From 63853960825f007827a79f704d291c372c807096 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Duje=20Mihanovi=C4=87?= <duje.mihanovic@skole.hr> Date: Thu, 9 Sep 2021 11:13:53 +0200 Subject: [PATCH] Restructure the bootloader --- .gitignore | 1 - Makefile | 10 +++---- boot/x86/a20.s | 49 ++++++++++++++++++++++++++++++ boot/x86/boot | Bin 0 -> 512 bytes boot/x86/boot.s | 53 +++++++++++++++++++++++++++++++++ boot.s => boot/x86/protected.s | 52 ++------------------------------ 6 files changed, 109 insertions(+), 56 deletions(-) create mode 100644 boot/x86/a20.s create mode 100644 boot/x86/boot create mode 100644 boot/x86/boot.s rename boot.s => boot/x86/protected.s (64%) diff --git a/.gitignore b/.gitignore index 988eea0..a5ea528 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ toolchain/ -boot boot.img **/*.o **/*.bin diff --git a/Makefile b/Makefile index a4c88b3..9d1c344 100644 --- a/Makefile +++ b/Makefile @@ -6,12 +6,12 @@ KERNEL_OBJ = kernel/entry.o kernel/arch/x86/tty/tty.o kernel/kernel.o all: boot.img -boot.img: boot kernel/kernel.bin - cat boot kernel/kernel.bin > $@ +boot.img: boot/x86/boot kernel/kernel.bin + cat boot/x86/boot kernel/kernel.bin > $@ truncate -s1440K $@ -boot: boot.s - $(AS) -f bin boot.s -o $@ +boot/x86/boot: boot/x86/boot.s boot/x86/a20.s boot/x86/protected.s + $(AS) -f bin boot/x86/boot.s -o $@ kernel/kernel.bin: ${KERNEL_OBJ} $(LD) -o $@ -T kernel/linker.ld ${KERNEL_OBJ} --oformat=binary @@ -26,6 +26,6 @@ kernel/kernel.o: kernel/kernel.c $(CC) -g -o $@ -Iinclude/arch/x86 -ffreestanding -c kernel/kernel.c clean: - rm boot kernel/kernel.bin ${KERNEL_OBJ} boot.img + rm boot/x86/boot kernel/kernel.bin ${KERNEL_OBJ} boot.img .PHONY: all clean diff --git a/boot/x86/a20.s b/boot/x86/a20.s new file mode 100644 index 0000000..f6a292b --- /dev/null +++ b/boot/x86/a20.s @@ -0,0 +1,49 @@ +; Some routines for managing the A20 line + +; Check if A20 is enabled +; Based on <https://wiki.osdev.org/A20_Line#Testing_the_A20_line>, slightly modified +check_a20 + pushf ; save EFLAGS + ; save segment and index registers + push ds + push es + push di + push si + + cli ; disable interrupts + xor ax, ax ; ax = 0 + mov es, ax ; es = 0 + + not ax ; ax = FFFFh + mov ds, ax ; ds = FFFFh + + mov di, 500h + mov si, 510h + + mov al, [es:di] ; preserve contents of 0:500h + mov ah, [ds:si] ; preserve contents of FFFFh:510h + push ax ; push all that to stack + + mov byte [es:di], 0 ; set 0:500h to 0 + mov byte [ds:si], 0FFh ; set FFFFh:510h to FFh + + cmp byte [es:di], 0FFh ; compare 0:500h with FFh + ; if A20 is enabled, this will not be equal, but if A20 is disabled it will be + + pop ax ; pop old contents of the 2 addresses + mov [ds:si], ah ; restore contents of FFFFh:510h + mov [es:di], al ; restore contents of 0:500h + + xor ax, ax ; clear ax + je .exit ; if A20 is disabled, return 0 + mov ax, 1 ; otherwise return 1 + +.exit + pop si + pop di + pop es + pop ds + popf + sti + ret + diff --git a/boot/x86/boot b/boot/x86/boot new file mode 100644 index 0000000000000000000000000000000000000000..a70865181bef901f68adda2d1ab6a34b24541678 GIT binary patch literal 512 zcmeAWld9dzFro9!eg+1^180Scq_;3_;4*l-k;&kj;qAV|yBP$4f`T?&HN3Awb~Ehg zJFIq$)$lbpjA`_m;q|{ca%|yYzYGub9r%8s@5X)x)_nr3YF(^$T`B=U)eLsWSpKUu z*#3{O>rheaU^P5Y!n}i#AugU>e(rCe1z<DT7#Ms&Cfwj>6cefCS2&Q?e1ef*>A<U{ zH5?3SI|LZ|ZuDK~JJ9!_@5NpQ22O^~H@lzJFfhDeX8;oBlmGvJ{V!n`LjyNM7xNZ& z8-^0@4yKMIM(5^3Ot0T29`?&GSIEp$C@9J=Nlh+EO;O0rPe}#pgn<A5f%L5N3}AZF Qc?NNYKR}~L0tj6N0H#WCxBvhE literal 0 HcmV?d00001 diff --git a/boot/x86/boot.s b/boot/x86/boot.s new file mode 100644 index 0000000..be6c653 --- /dev/null +++ b/boot/x86/boot.s @@ -0,0 +1,53 @@ + bits 16 ; boot sectors run in real mode + org 7C00h ; BIOS loads us at 0x7c00 + +KERNEL_OFFSET equ 1000h ; where we will load our kernel + + mov [BOOT_DRIVE], dl ; BIOS puts the number of our boot drive in dl, so we will want to remember this + + 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 + +halt + jmp $ + +%include "a20.s" +%include "protected.s" + +BOOT_DRIVE db 0 ; reserve a spot in RAM for our boot drive variable + + times 510-($-$$) db 0 + dw 0AA55h ; MBR signature diff --git a/boot.s b/boot/x86/protected.s similarity index 64% rename from boot.s rename to boot/x86/protected.s index 6181a73..d1c7eea 100644 --- a/boot.s +++ b/boot/x86/protected.s @@ -1,50 +1,6 @@ - bits 16 ; boot sectors run in real mode - org 7C00h ; BIOS loads us at 0x7c00 +; Everything between real mode and the C kernel -KERNEL_OFFSET equ 1000h ; where we will load our kernel - - mov [BOOT_DRIVE], dl ; BIOS puts the number of our boot drive in dl, so we will want to remember this - - 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 $ + bits 16 switch_to_pm mov bx, 0B800h @@ -143,7 +99,3 @@ gdt_desc CODE_SEG equ code_seg - gdt_start DATA_SEG equ data_seg - gdt_start -BOOT_DRIVE db 0 ; reserve a spot in RAM for our boot drive variable - - times 510-($-$$) db 0 - dw 0AA55h ; MBR signature -- 2.39.5