X-Git-Url: http://git.dujemihanovic.xyz/projects?a=blobdiff_plain;f=boot.s;h=6181a73528610dcaf7c18ea6beb51dbf03865ffe;hb=2d2187830c156e9c36e70fb7dbe4b05dfc09a255;hp=eb115d0324dd6a2e8e83d94aee9d197d71299392;hpb=b85f8e94af0b9720083f5cd48092ead24e6004c3;p=nameless-os.git diff --git a/boot.s b/boot.s index eb115d0..6181a73 100644 --- a/boot.s +++ b/boot.s @@ -1,23 +1,149 @@ bits 16 ; boot sectors run in real mode - org 7c00h ; boot sector is loaded at 0x7c00 + org 7C00h ; BIOS loads us at 0x7c00 - mov di, printing_numbers - call print +KERNEL_OFFSET equ 1000h ; where we will load our kernel - mov dx, 0DEADh ; number to print - call print_word - mov dx, 0BEEFh - call print_word + mov [BOOT_DRIVE], dl ; BIOS puts the number of our boot drive in dl, so we will want to remember this - mov di, goodbye - call print + mov bp, 9000h ; initialize stack at a spot sufficiently distanced from this code + mov sp, bp + mov di, 0 + + 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 + mov es, bx + mov byte [es:di], '1' + jmp halt + +read_error + mov bx, 0B800h + mov es, bx + mov byte [es:di], '2' + jmp halt + + call switch_to_pm + +halt jmp $ -printing_numbers: db "Printing some random hex numbers", 0 -goodbye: db "Thank you for your attention", 0 +switch_to_pm + mov bx, 0B800h + 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 ; 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 ; 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 ; we are finally in 32-bit mode +protected + 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 ; save registers to stack + mov edx, video_memory ; initialize dx with location of VRAM + +.loop + mov al, [ebx] ; read next char and put it in al + mov ah, 00000111b ; puts the VGA text mode color white on black into ah + + cmp al, 0 ; if the next character is null, we reached end of string + je .done ; so return the instruction + + mov [edx], al ; otherwise put the next character in the video memory + mov [edx+1], ah ; do the same for its color + + inc ebx ; point to next character in string + add edx, 2 ; point to next character in VRAM + + jmp .loop ; go back to the loop + +.done + 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 +code_seg + dw 0FFFFh + dw 0 + db 0 + db 10011010b + db 11001111b + db 0 +data_seg + dw 0FFFFh + dw 0 + db 0 + db 10010010b + db 11001111b + db 0 +gdt_end +gdt_desc + dw gdt_end - gdt_start - 1 + dd gdt_start +CODE_SEG equ code_seg - gdt_start +DATA_SEG equ data_seg - gdt_start -%include "print.s" +BOOT_DRIVE db 0 ; reserve a spot in RAM for our boot drive variable - times 510-($-$$) db 0 ; fill with 0 until 0x1fc is reached - dw 0AA55h ; BIOS MBR signature + times 510-($-$$) db 0 + dw 0AA55h ; MBR signature