X-Git-Url: http://git.dujemihanovic.xyz/projects?a=blobdiff_plain;f=boot.s;h=de5887dddc3101695a5ddcdc7e5deeca7f1d3796;hb=668fa121eb74d3317a73c2289f8805aaf1c84d7e;hp=a40b7508781e9dbc59b82587e003f2ccca6a21f8;hpb=c9f2bccb44c5437f1cae0862b2c84d3af47eade8;p=nameless-os.git diff --git a/boot.s b/boot.s index a40b750..de5887d 100644 --- a/boot.s +++ b/boot.s @@ -1,32 +1,33 @@ - bits 16 - org 7C00h + bits 16 ; boot sectors run in real mode + org 7C00h ; BIOS loads us at 0x7c00 -KERNEL_OFFSET equ 1000h +KERNEL_OFFSET equ 1000h ; where we will load our kernel - mov [BOOT_DRIVE], dl + mov [BOOT_DRIVE], dl ; BIOS puts the number of our boot drive in dl, so we will want to remember this - mov bp, 9000h + mov bp, 9000h ; initialize stack at a spot sufficiently distanced from this code mov sp, bp mov di, 0 - xor ax, ax - int 13h - jc reset_error - - mov ah, 2 - mov al, 10 - xor ch, ch - mov cl, 2 - xor dh, dh - xor bx, bx - mov es, bx - mov bx, KERNEL_OFFSET - int 13h - jc read_error - cmp al, 10 - jl read_error - jmp switch_to_pm + xor ax, ax ; clear accumulator + int 13h ; BIOS disk services, with a cleared accumulator this will reset the disk controller + jc reset_error ; halt if controller reset fails + + mov ah, 2 ; instruct BIOS's interrupt 13h to read sectors + mov al, 10 ; load 10 sectors, might be excessive (for now) but it's still good to do so + xor ch, ch ; read from 1st cylinder + mov cl, 2 ; start reading from 2nd sector, right after the boot sector + xor dh, dh ; read from 1st head + xor bx, bx ; clear B register + mov es, bx ; clear extended segment + mov bx, KERNEL_OFFSET ; put the sectors in our desired offset + ; dl holds the number of the drive to read from, but BIOS already filled this in + int 13h ; do the read + jc read_error ; halt if read fails + cmp al, 10 ; make sure we actually read 10 sectors + jl read_error ; halt if we didn't + jmp switch_to_pm ; if all is good, begin the switch to 32-bit protected mode reset_error mov bx, 0B800h @@ -47,64 +48,77 @@ halt switch_to_pm mov bx, 0B800h - mov es, bx - mov byte [es:0], 'L' + mov es, bx ; set extra segment to starting address of video RAM + mov byte [es:0], 'L' ; print an L to screen, to let us know that we actually got here - cli - xor ax, ax - mov ds, ax - lgdt [gdt_desc] + cli ; disable interrupts + xor ax, ax ; clear accumulator + mov ds, ax ; clear data segment, this makes sure the next instruction reads from the right place + lgdt [gdt_desc] ; load the Global Descriptor Table - mov eax, cr0 - or eax, 1 - mov cr0, eax - jmp CODE_SEG:protected + mov eax, cr0 ; move Control Register 0 to accumulator + or eax, 1 ; flip the bit which controls memory protection + mov cr0, eax ; move the accumulator back to CR0 + jmp CODE_SEG:protected ; not quite there yet, need to do a far jump to clean the pipeline from any 16-bit instructions + ; note that the jump does not have to be physically far away, it just needs to use a segmented address - bits 32 + bits 32 ; we are finally in 32-bit mode protected - mov ax, DATA_SEG + mov ax, DATA_SEG ; put the selector for the data segment in the accumulator + ; in real mode, segmentation works by taking one of these segment registers, shifting it right by 4 bits or 1 hex digit + ; and then adding a 16-bit offset to form a 20-bit address + ; example: 1234h:5678h + ; 1234h is shifted to 12340h, 12340h + 5678h is 179B8h + ; in 32-bit protected mode, these segment registers do not hold the segment address itself, but a selector in the GDT + ; so we have to update the segment registers accordingly mov ds, ax mov ss, ax mov es, ax mov fs, ax mov gs, ax + ; reinitialize the stack at a safe location mov ebp, 090000h mov esp, ebp + ; print a string to let us know that we survived the switch mov ebx, pm_success call pmprint + ; transfer control to the kernel call KERNEL_OFFSET + ; above call should not return in normal circumstances, but if it does hang forever jmp $ pmprint - pusha - mov edx, video_memory + pusha ; save registers to stack + mov edx, video_memory ; initialize dx with location of VRAM .loop - mov al, [ebx] - mov ah, 0Fh + mov al, [ebx] ; read next char and put it in al + mov ah, 0Fh ; puts the VGA text mode color white on black into ah - cmp al, 0 - je .done + cmp al, 0 ; if the next character is null, we reached end of string + je .done ; so return the instruction - mov [edx], al - mov [edx+1], ah + mov [edx], al ; otherwise put the next character in the video memory + mov [edx+1], ah ; do the same for its color - inc ebx - add edx, 2 + inc ebx ; point to next character in string + add edx, 2 ; point to next character in VRAM - jmp .loop + jmp .loop ; go back to the loop .done - popa - ret + popa ; restore registers from stack + ret ; return pm_success db "Now in protected mode", 0 video_memory equ 0B8000h +; the actual Global Descriptor Table +; refer to Volume 3, Chapter 2, 2.1.1 of Intel's 64 and IA-32 Software Developer's Manual for more info gdt_start null_seg dq 0 @@ -129,7 +143,7 @@ gdt_desc CODE_SEG equ code_seg - gdt_start DATA_SEG equ data_seg - gdt_start -BOOT_DRIVE db 0 +BOOT_DRIVE db 0 ; reserve a spot in RAM for our boot drive variable times 510-($-$$) db 0 - dw 0AA55h + dw 0AA55h ; MBR signature