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