From 70bb19100eaa979c58a5513f29fec1b4a00634f6 Mon Sep 17 00:00:00 2001 From: Kartik Agaram Date: Sat, 19 Dec 2020 21:22:28 -0800 Subject: 7357 --- apps/bos/4.asm | 139 +++++++++++++++++++++++++++------------------------------ 1 file changed, 65 insertions(+), 74 deletions(-) diff --git a/apps/bos/4.asm b/apps/bos/4.asm index 067ae95f..71c51d97 100644 --- a/apps/bos/4.asm +++ b/apps/bos/4.asm @@ -1,3 +1,5 @@ +; A boot sector that enters 32-bit protected mode. +; ; To convert to a disk image: ; cd apps/bos ; nasm 4.asm -f bin -o boot.bin @@ -6,32 +8,32 @@ ; Or: ; bochs # bochsrc loads boot.bin -; A boot sector that enters 32-bit protected mode. [org 0x7c00] - mov bp, 0x9000 ; Set the stack. + mov bp, 0x9000 mov sp, bp mov bx, MSG_REAL_MODE call print_string - call switch_to_pm ; Note that we never return from here. + call switch_to_pm + ; never gets here jmp $ -print_string: - pusha - mov ah, 0x0e -loop: - mov al, [bx] - int 0x10 - add bx, 1 - cmp al, 0 - jne loop - popa - ret - -; GDT +switch_to_pm: + cli + lgdt [gdt_descriptor] + ; set LSB of CR0 + mov eax, cr0 + or eax, 0x1 + mov cr0, eax + jmp CODE_SEG:init_pm ; Far jump to a new segment containing 32-bit code. + ; This also forces the CPU to flush its cache of + ; prefetched and real-mode decoded instructions. + ; never gets here + +;; === GDT stuff gdt_start: gdt_null: ; the mandatory null descriptor @@ -50,7 +52,7 @@ gdt_code: ; the code segment descriptor db 11001111b ; 2nd flags, Limit (bits 16-19) db 0x0 ; Base (bits 24 -31) -gdt_data: ;the data segment descriptor +gdt_data: ; the data segment descriptor ; Same as code segment except for the type flags: ; type flags: (code)0 (expand down)0 (writable)1 (accessed)0 -> 0010b dw 0xffff ; Limit (bits 0-15) @@ -60,28 +62,60 @@ gdt_data: ;the data segment descriptor db 11001111b ; 2nd flags, Limit (bits 16-19) db 0x0 ; Base (bits 24 -31) -gdt_end: ; The reason for putting a label at the end of the - ; GDT is so we can have the assembler calculate - ; the size of the GDT for the GDT decriptor (below) +gdt_end: -; GDT descriptor gdt_descriptor: - dw gdt_end - gdt_start - 1 ; Size of our GDT, always less one - ; of the true size - dd gdt_start ; Start address of our GDT - -; Define some handy constants for the GDT segment descriptor offsets, which -; are what segment registers must contain when in protected mode. For example, -; when we set DS = 0x10 in PM , the CPU knows that we mean it to use the -; segment described at offset 0x10 (i.e. 16 bytes) in our GDT, which in our -; case is the DATA segment (0x0 -> NULL; 0x08 -> CODE; 0x10 -> DATA) + dw gdt_end - gdt_start - 1 ; last valid byte + dd gdt_start + +; some handy constants CODE_SEG equ gdt_code - gdt_start DATA_SEG equ gdt_data - gdt_start +;; === end GDT stuff +;; some 16-bit helpers + +; print string whose address is in bx +print_string: + pusha + mov ah, 0x0e +loop: + mov al, [bx] + int 0x10 + add bx, 1 + cmp al, 0 + jne loop + popa + ret + +;; 32-bit code starts here [bits 32] + +; Initialise registers and the stack once in PM. +init_pm: + + mov ax, DATA_SEG ; Now in PM, our old segments are meaningless, + mov ds, ax ; so we point our segment registers to the + mov ss, ax ; data selector we defined in our GDT + mov es, ax + mov fs, ax + mov gs, ax + + mov ebp, 0x90000 ; Update our stack position so it is right + mov esp, ebp ; at the top of the free space. + + ;; Protected Mode is now initialized + + mov ebx, MSG_PROT_MODE + call print_string_pm + + ; all done; hang + jmp $ + ; Define some constants VIDEO_MEMORY equ 0xb8000 WHITE_ON_BLACK equ 0x0f + ; prints a null -terminated string pointed to by EDX print_string_pm: pusha @@ -100,53 +134,10 @@ print_string_pm_done: popa ret ; Return from the function -[bits 16] -; Switch to protected mode -switch_to_pm: - cli ; We must switch of interrupts until we have - ; set up the protected mode interrupt vector - ; otherwise interrupts will run riot. - - lgdt [gdt_descriptor] ; Load our global descriptor table, which defines - ; the protected mode segments (e.g. for code and data) - - mov eax, cr0 ; To make the switch to protected mode, we set - or eax, 0x1 ; the first bit of CR0, a control register - mov cr0, eax - - jmp CODE_SEG:init_pm ; Make a far jump (i.e. to a new segment) to our 32-bit - ; code. This also forces the CPU to flush its cache of - ; prefetched and real-mode decoded instructions, which can - ; cause problems. - -[bits 32] -; Initialise registers and the stack once in PM. -init_pm: - - mov ax, DATA_SEG ; Now in PM, our old segments are meaningless, - mov ds, ax ; so we point our segment registers to the - mov ss, ax ; data selector we defined in our GDT - mov es, ax - mov fs, ax - mov gs, ax - - mov ebp, 0x90000 ; Update our stack position so it is right - mov esp, ebp ; at the top of the free space. - - call BEGIN_PM ; Finally, call some well-known label - -[bits 32] -; This is where we arrive after switching to and initialising protected mode. -BEGIN_PM: - - mov ebx, MSG_PROT_MODE - call print_string_pm ; Use our 32-bit print routine. - - jmp $ ; Hang. - ; Global variables MSG_REAL_MODE db "Started in 16-bit Real Mode", 0 MSG_PROT_MODE db "Successfully landed in 32-bit Protected Mode", 0 + ; Bootsector padding times 510-($-$$) db 0 dw 0xaa55 -- cgit 1.4.1-2-gfad0