From 1b2184fe52623e74b1ffe119e5dd1daecfd9942e Mon Sep 17 00:00:00 2001 From: Lucia Ceionia Date: Mon, 13 Feb 2023 18:23:33 -0600 Subject: [PATCH] Kernel now is loaded from a partition, allowing a separate MBR bootloader if desired --- Makefile | 24 +++-- boot.nasm | 219 ++++++++++---------------------------------- boot_partition.nasm | 136 +++++++++++++++++++++++++++ helper.c | 4 +- kernel.c | 27 +++++- tests.c | 6 +- virtdisk.bin.ex | Bin 33554432 -> 33554432 bytes 7 files changed, 232 insertions(+), 184 deletions(-) create mode 100644 boot_partition.nasm diff --git a/Makefile b/Makefile index b3eb855..5419205 100644 --- a/Makefile +++ b/Makefile @@ -7,16 +7,29 @@ LFLAGS = -Wl,--gc-sections -Wl,--print-gc-sections -m32 -nostartfiles -nostdlib ifeq ($(OUTFILE),) OUTFILE = virtdisk.bin endif +ifeq ($(PARTSTART),) +PARTSTART = 2048 +endif + +PARTVBR=$(shell echo "$(PARTSTART) * (2^9)" | bc) +PARTVBRBOOT=$(shell echo "$(PARTVBR) + 90" | bc) +KERNSEC=$(shell echo "$(PARTSTART) + 4" | bc) .PHONY: $(OUTFILE) all: $(OUTFILE) -$(OUTFILE): boot.bin kernel.bin - # Copy to boot sector, don't overwrite MBR +$(OUTFILE): boot.bin boot_partition.bin kernel.bin + # Copy system bootloader to boot sector, don't overwrite MBR dd bs=400 count=1 conv=notrunc if=boot.bin of=$@ - # Write kernel beyond boot sector, maximum 128K (256 sectors) - dd bs=512 count=256 seek=1 conv=notrunc if=kernel.bin of=$@ + # Ensure partition VBR contains EB 5A + echo -n -e '\xeb\x5a' | dd bs=1 seek=$(PARTVBR) count=2 conv=notrunc of=$@ + # Copy kernel bootloader to partition VBR + dd bs=1 count=420 seek=$(PARTVBRBOOT) conv=notrunc if=boot_partition.bin of=$@ + # TODO Check that disk has enough reserved sectors, + # currently this will overwrite the disk if too few + # Write kernel beyond boot sector, maximum 64K (128 sectors) + dd bs=512 count=128 seek=$(KERNSEC) conv=notrunc if=kernel.bin of=$@ kernel.bin: out.o link.ld usermode.o clang $(LFLAGS) -Wl,-M -Tlink.ld -ffreestanding -o $@ out.o usermode.o @@ -37,8 +50,7 @@ out.o: $(objects) clang $(CFLAGS) -ffunction-sections -fdata-sections -Os -o $@ $< virtdisk: - dd bs=1M count=32 if=/dev/zero of=virtdisk.bin - echo -n -e '\x55\xaa' | dd bs=1 seek=510 conv=notrunc of=virtdisk.bin + cp virtdisk.bin.ex virtdisk.bin clean: rm -f $(objects) out.o kernel.bin boot.bin usermode.bin diff --git a/boot.nasm b/boot.nasm index 42384bf..0f3ca6a 100644 --- a/boot.nasm +++ b/boot.nasm @@ -1,6 +1,8 @@ -secreadcnt equ 0x38 -kernelreads equ 0x10000/(512*secreadcnt) ; 64K / Sector Size FIXME This underestimates when kernel size is not divisible by bytes per read -[ORG 0x7c00] +; This boots the active partition. +; Relocates self to 0x7E00, loads the +; first sector of active partition +; to 0x7C00 and jumps +[ORG 0x7C00] [BITS 16] xor ax, ax mov ds, ax @@ -8,68 +10,50 @@ mov es, ax mov ax, 0x8000 mov ss, ax mov sp, 0xFF00 +; Relocate self +mov di, 0x7E00 +mov si, 0x7C00 +mov cx, 512 +rep movsw +jmp 0:relocated +; TODO Make this calculated, somehow +[SECTION RELOC vstart=0x7E20] +relocated: mov ah, 0x41 ; int 13 extensions check mov bx, 0x55AA int 0x13 -jc no_exten -mov cx, kernelreads -read_loop: +jc no_int13 +; Find active partition +xor cx, cx +mov si, 0x7E00+0x1BE +.find_active: +lodsb +bt ax, 7 +jc read +add si, 15 +inc cl +cmp cl, 4 +jl .find_active +jmp err +read: +; Put partition start LBA in disk address packet +add si, 7 +mov di, addr_packet_start_block +movsw +movsw +; Load the first sector of the partition xor ax, ax mov ah, 0x42 mov si, addr_packet int 0x13 jc err -add word [addr_packet_transfer_buff_seg], (secreadcnt*512)/16 -add word [addr_packet_start_block], secreadcnt -loop read_loop -entry: -;mov ax,0x2403 ; A20 BIOS Support -;int 0x15 -;jb .no_a20 -;cmp ah,0 -;jnz .no_a20 -;mov ax,0x2401 ; A20 BIOS Activate -;int 0x15 -;.no_a20: -cli ; no interrupts -xor ax,ax -mov ds, ax -lgdt [gdt_desc] ; load gdt register -mov eax, cr0 ; set pmode bit -or al, 1 -mov cr0, eax -jmp 08h:Pmode -no_exten: -; read with CHS -; FIXME This only reads up to sector count -mov ah,8 -int 0x13 ; geometry -and cx, 0x3f -push cx -push 0x0080 ; DH=head,DL=disk -push 0x2000 ; buffer seg -push 2 ; sector -.loop: -mov ax, [esp] -push 0xb800 -pop es -xor di,di -call hexprint -mov ax, [esp+2] -mov es, ax -mov ax, 0x0201 -mov cx, [esp] -xor bx,bx -mov dx, [esp+4] -int 0x13 -jc err -add word [esp+2], 0x20 -mov cx, [esp] -inc cl -mov [esp], cx -cmp cl, [esp+6] -jg entry -jmp .loop +; Jump to partition boot +jmp 0:0x7C00 + +no_int13: +mov si, no_exten_str +mov cx, no_exten_str_end - no_exten_str +jmp print err: mov bx, ax mov si, string @@ -83,126 +67,17 @@ err_print: lodsb stosw loop err_print -;add di, 2 -;mov ax, bx -;call hexprint hlt_loop: hlt jmp hlt_loop -hexprint: -xor cx, cx -mov bl, al -shr al, 4 -jmp .donibble -.nibble2: -mov al, bl -inc cx -.donibble: -and al, 0x0F -cmp al, 0x0A -jl .noadjust -add al, 'A' - '0' - 10 -.noadjust: -add al, '0' -mov ah, 0x7 -stosw -test cx, cx -jz .nibble2 -ret - -[BITS 32] -Pmode: -mov eax, 0x10 -mov ds, ax -mov es, ax -mov fs, ax -mov gs, ax -mov ss, ax -; check A20 -.a20: -mov edi, 0x107C00 -mov esi, 0x007C00 -mov [esi], esi -mov [edi], edi -cmpsd -jne .kernel -call enable_A20 -;in al, 0x92 ; fast A20 -;test al, 2 -;jnz .fa20_end -;or al, 2 -;and al, 0xFE -;out 0x92, al -;.fa20_end: -jmp .a20 -.kernel: -;mov dword [0xb8000], 0x07000700 | 'P' | 'M' << 16 -;mov dword [0xb8004], 0x07000700 | 'O' | 'D' << 16 -;mov dword [0xb8008], 0x07000700 | 'E' | ' ' << 16 -mov esi, 0x20000 -mov edi, 0x100000 -mov ecx, 0x10000 -rep movsb -jmp 08h:0x100000 -enable_A20: - cli - call a20wait - mov al,0xAD - out 0x64,al - call a20wait - mov al,0xD0 - out 0x64,al - call a20wait2 - in al,0x60 - push eax - call a20wait - mov al,0xD1 - out 0x64,al - call a20wait - pop eax - or al,2 - out 0x60,al - call a20wait - mov al,0xAE - out 0x64,al - call a20wait - ret -a20wait: - in al,0x64 - test al,2 - jnz a20wait - ret -a20wait2: - in al,0x64 - test al,1 - jz a20wait2 - ret - -gdt_desc: - dw gdt_end - gdt - dd gdt -gdt: -gdt_null: dq 0 -gdt_code: dw 0xFFFF, 0 ; bits 0-15 limit (4GB), bits 0-15 base address - db 0 ; bits 16-23 base address - db 10011010b ; access byte - db 11001111b ; bits 16-19 limit (4GB), 4 bits flags - db 0 ; bits 24-31 base address -gdt_data: dw 0xFFFF, 0 ; bits 0-15 limit (4GB), bits 0-15 base address - db 0 ; bits 16-23 base address - db 10010010b ; access byte - db 11001111b ; bits 16-19 limit (4GB), 4 bits flags - db 0 ; bits 24-31 base address -gdt_end: - string: db 'DISK ERROR' string_end: -;no_exten_str: db 'NO INT13 EXTEN' -;no_exten_str_end: +no_exten_str: db 'NO INT13 EXTEN' +no_exten_str_end: addr_packet: db 0x10, 0x00 ; size, reserved -dw secreadcnt ; blocks -addr_packet_transfer_buff_off: dw 0x0000 ; transfer buffer offset -addr_packet_transfer_buff_seg: dw 0x2000 ; transfer buffer segment -addr_packet_start_block: dq 1 ; start block +dw 1 ; blocks +addr_packet_transfer_buff_off: dw 0x7C00 ; transfer buffer offset +addr_packet_transfer_buff_seg: dw 0x0000 ; transfer buffer segment +addr_packet_start_block: dq 0 ; start block diff --git a/boot_partition.nasm b/boot_partition.nasm new file mode 100644 index 0000000..9d1f94b --- /dev/null +++ b/boot_partition.nasm @@ -0,0 +1,136 @@ +; This boots *from a FAT partition* +; So it starts at 0x7C00+90, the offset of +; the boot code in a FAT VBR +secreadcnt equ 0x38 +kernelreads equ 0x10000/(512*secreadcnt) ; 64K / Sector Size FIXME This underestimates when kernel size is not divisible by bytes per read +[ORG 0x7c00+90] +[BITS 16] +xor ax, ax +mov ds, ax +mov es, ax +mov ax, 0x8000 +mov ss, ax +mov sp, 0xFF00 +; FIXME Assumes INT 13 Extension support +mov ah, 0x42 +mov si, addr_packet +int 0x13 +jc err +xor cx, cx +mov si, 0x7E00+0x1BE +.find_active: +lodsb +bt ax, 7 +jc read +add si, 15 +inc cl +cmp cl, 4 +jl .find_active +jmp err +read: +mov dh, cl ; Store active partition +add si, 7 +mov di, addr_packet_start_block +lodsw +; Offset of kernel in partition +add ax, 4 +stosw +lodsw +adc ax, 0 +stosw +mov cx, kernelreads +read_loop: +xor ax, ax +mov ah, 0x42 +mov si, addr_packet +int 0x13 +jc err +add word [addr_packet_transfer_buff_seg], (secreadcnt*512)/16 +add word [addr_packet_start_block], secreadcnt +loop read_loop +entry: +cli ; no interrupts +xor ax,ax +mov ds, ax +lgdt [gdt_desc] ; load gdt register +mov eax, cr0 ; set pmode bit +or al, 1 +mov cr0, eax +jmp 08h:Pmode +err: +mov si, string +mov cx, string_end - string +print: +push 0xb800 +pop es +xor di, di +mov ah, 0x7 +err_print: +lodsb +stosw +loop err_print +hlt_loop: +hlt +jmp hlt_loop + +[BITS 32] +Pmode: +mov eax, 0x10 +mov ds, ax +mov es, ax +mov fs, ax +mov gs, ax +mov ss, ax +; check A20 +.a20: +mov edi, 0x107C00 +mov esi, 0x007C00 +mov [esi], esi +mov [edi], edi +cmpsd +jne .kernel +; FIXME It's annoying that fast A20 +; will crash old systems, but it's +; just so small... +in al, 0x92 ; fast A20 +test al, 2 +jnz .fa20_end +or al, 2 +and al, 0xFE +out 0x92, al +.fa20_end: +jmp .a20 +.kernel: +mov esi, 0x7E00 +mov edi, 0x100000 +mov ecx, 0x10000 +rep movsb +xchg bx,bx +jmp 08h:0x100000 + +gdt_desc: + dw gdt_end - gdt + dd gdt +gdt: +gdt_null: dq 0 +gdt_code: dw 0xFFFF, 0 ; bits 0-15 limit (4GB), bits 0-15 base address + db 0 ; bits 16-23 base address + db 10011010b ; access byte + db 11001111b ; bits 16-19 limit (4GB), 4 bits flags + db 0 ; bits 24-31 base address +gdt_data: dw 0xFFFF, 0 ; bits 0-15 limit (4GB), bits 0-15 base address + db 0 ; bits 16-23 base address + db 10010010b ; access byte + db 11001111b ; bits 16-19 limit (4GB), 4 bits flags + db 0 ; bits 24-31 base address +gdt_end: + +string: db 'DISK ERROR' +string_end: + +addr_packet: +db 0x10, 0x00 ; size, reserved +dw secreadcnt ; blocks +addr_packet_transfer_buff_off: dw 0x7E00 ; transfer buffer offset +addr_packet_transfer_buff_seg: dw 0x0000 ; transfer buffer segment +addr_packet_start_block: dq 0 ; start block diff --git a/helper.c b/helper.c index 01de8fd..5d71804 100644 --- a/helper.c +++ b/helper.c @@ -48,11 +48,13 @@ void SetCursorDisabled() { V8086Int(0x10, ®s); } +// This should DEFINITELY be an argument +uint8_t SystemPartition = 0; uint32_t OpenVol(VOLINFO *vi) { uint8_t *diskReadBuf = (uint8_t *)0x20000; uint8_t pactive, ptype; uint32_t pstart, psize; - pstart = DFS_GetPtnStart(0, diskReadBuf, 0, &pactive, &ptype, &psize); + pstart = DFS_GetPtnStart(0, diskReadBuf, SystemPartition, &pactive, &ptype, &psize); if (pstart == -1) return -1; return DFS_GetVolInfo(0, diskReadBuf, pstart, vi); } diff --git a/kernel.c b/kernel.c index 99d446e..3752fd8 100644 --- a/kernel.c +++ b/kernel.c @@ -101,6 +101,14 @@ void ensure_v86env() { *d++ = *s++; } +uint32_t _ERRORCODE = 0; +__attribute__((__no_caller_saved_registers__)) +uint32_t check_error_code() { + uint32_t v = _ERRORCODE; + _ERRORCODE = 0; + return v; +} + __attribute__((__no_caller_saved_registers__)) __attribute__((__noreturn__)) extern void return_prev_task(); @@ -145,6 +153,7 @@ void error_environment(uint32_t stack0, uint32_t stack1, uint32_t stack2, uint32 // reset error screen for (int i = 0; i < (80*50)/2; i++) ((uint32_t*)error_screen)[i] = 0x0f000f00; + _ERRORCODE = -1; return_prev_task(); } @@ -181,6 +190,10 @@ Protected Only (1MB+) 400000 - 700000 Usermode Code (3mB) 700000 - 800000 Usermode Stack (1mB) */ + +// FIXME Truly awful +extern uint8_t SystemPartition; + void DrawScreen(uint16_t *vga) { uint16_t *vga_text = vga; // clear screen @@ -214,6 +227,7 @@ void DrawScreen(uint16_t *vga) { vga_text[80+42] = 0x1f00 | 'S'; vga_text[80+43] = 0x1f00 | ' '; vga_text[80+44] = 0x1f00 | '-'; + printByte(SystemPartition, &vga_text[80+50]); } void SetPalette() { @@ -418,7 +432,9 @@ void SystemRun() { { VOLINFO vi; // TODO Check partitions beyond 0 - while (OpenVol(&vi)) { + while (1) { + create_child(GetFreeStack(), (uintptr_t)OpenVol, 1, &vi); + if (!check_error_code()) break; vga_text = &((word*)0xb8000)[80*4 + 2]; vga_text += printStr("Error loading file select. Ensure the disk has a valid MBR and FAT partition.", vga_text); vga_text = &((word*)0xb8000)[80*5 + 2]; @@ -457,8 +473,8 @@ void start() { vga_text = &vga_text[80]; // DL *should* be preserved - uint8_t dl; - asm volatile("nop":"=d"(dl)); + uint16_t boot_dx; + asm volatile("nop":"=d"(boot_dx)); if (!check_cmov()) { char cmov_err[] = "NO CMOV"; @@ -467,7 +483,7 @@ void start() { for (;;) asm volatile("hlt"); } - vga_text += printByte(dl, vga_text); + vga_text += printWord(boot_dx, vga_text); vga_text++; uint32_t o; @@ -509,6 +525,9 @@ void start() { backup_ivtbios(); InitDisk(); + // DL contained disk number, DH contained active partition + SystemPartition = boot_dx >> 8; + create_child(GetFreeStack(), (uintptr_t)SystemRun, 0); // If this returns, something is *very* wrong, reboot the system // TODO Maybe try to recover? diff --git a/tests.c b/tests.c index e355979..5379495 100644 --- a/tests.c +++ b/tests.c @@ -122,6 +122,10 @@ void TestCHS() { } } } + +// FIXME Just horrible +extern uint8_t SystemPartition; + void TestFAT() { uint16_t *vga_text = (uint16_t *)0xb8000; uint8_t *diskReadBuf = (uint8_t *)0x22400; @@ -131,7 +135,7 @@ void TestFAT() { uint8_t pactive, ptype; uint32_t pstart, psize; - pstart = DFS_GetPtnStart(0, diskReadBuf, 0, &pactive, &ptype, &psize); + pstart = DFS_GetPtnStart(0, diskReadBuf, SystemPartition, &pactive, &ptype, &psize); vga_text = (uint16_t *)0xb8000; vga_text += printStr("PartStart: ", vga_text); vga_text += printDword(pstart, vga_text); diff --git a/virtdisk.bin.ex b/virtdisk.bin.ex index 804d857d04b1c1edb8c837d0c896b9294f2c5664..d44344b3844480b163fec7292214d0e99bc78bf2 100644 GIT binary patch delta 1870 zcmWmAWw;Lp0EO}UzdFX%-As3P&g2}%WxA%j+f_#n({0n!F&$U;bayw?&G!26d)}|- zIbmU8Az@g(DG;U7hZrY=g2IM`2Zo0Sz6nMIL_{P+MifLvG(<-X#Kd=qwJ|&pyV}=4 z*yPwDi6gd7bu<3@tRZKk%nu2E@2DYDqQ=P{GVp1GDxpZ8 z!^&ypvT|E_th`n}E5B91Drgn53R^|2qE<1hxK+X`X_c}{TV<@WRypejtGva?3RXp{ zl2zHNVpX+%vZ`6Ks#`UzpRJl!Ei2TjZPl@UvFcj&tol|1tD)7%YHT&Jnp(}Q=GL!P z3#+Bo%4%)3vD#YgtoBw1tE1J)>TGqfx?0_=?p6=0r`5~qZS}GGTK%m4)&Ogu6=n^x z23td{q1G_V)^KZtHPRYojkd;Ezgc6gan^Y2cWZ(*(VApUwx(E9t!dVDYlbz`nq|$l z=2&yBKde8kdDeVufwjvz;b=Ke3dTWEV(b{Bf zwzgPXt!>tJYljtX?X-4TyRALeUTdGV-#TC&v<_K^ts~Y^>mTcwb=*2(owQC_r>!&A zS?ip2-nw92v@Thftt-}5>zZ}lx?$b4ZdtdjJJwz6o^{`PU_G=RS&ywJ)>G@5^{@5Z zdSSh^URkfLH`ZJ0o%P=OV12YcS)Z*h)>rGlQ3{Mz0KtfWh=_#9h=QnyhUkcanD`E{ z5E~(ggSd!?_(*_+NQA^lf}}`>L z&!~x72t{qw!7r$bdZ>>EXoyB=j3#J`W@wII(E=^e3a!xwZP5Q~(IEVANfQz_<%eaE8 zxQ6Svft$F6+qi?fxQF|AfQNX5$9RILc!q!R953(^ukadg@D}gz9v|=#pYR!90xR`3 Gu<3tL&CwPB delta 1862 zcmWmARg@M407PN_Wf72CI;Fe2TViM=76Iw*ZqTI$>Fx&UltyBuySuwPr9>|e-?^`I zCM+y0Bn<0X%Y{aW@U0OeELa~1+Ed<&W5u=NS@Ep|RzfS0mDoyR zCAE@SKUm4F6jn+rm6h5`W2LpyS?R3|Rz@q6mD$Q-Wwo+d*{vK_PAiv{+sb3*wenf{ ztpZj-tB_ULDq`p8lvUdL(JEt=waQs6lvTm1XjQT*TUD&8RyC`-^^;Y@ zs%h1-YFnXJ9qVVSu2s*fZ~bC5uo_y8tj1OotEtt@YHqc#T3W5F)>a#u+n9 zwcFZb?X~t<`>g}kLFy&lcI%A!+&ROTJ3)V&Jl6Bd-VqLYa zS=X%_)=le{b=$gQ-L>vn_pJxkL+g?C*m`0;wVqketryly>y`D|dSkt{-dXRhf2b93@Z^rBE6_q72HS9LnR{KNV0Bl~5T~P!-is9Y3K4YN8fuBNTP;GwPxq>f;wQ zKtnV_V>CfiG(&T=KufejYqUXIv_pGzKu2^!XLLbVbVGOaKu`2SZ}dT5^h19Pz_0iX zVHk)(7>pqp3S$_4$8e0mNQ}a0jKNrp!+1=#+eFu?d^81zYhKwqZMVU?;-yH+Eq+_Fyme zVLuMwAP(U$j^HSc;W$pMCT`(2?%*!&;XWSV xAs*o|p5Q5-;W=L5C0^k*-rz0X;XVGr2YkdQe8w02i?4yz`Y*6$VMx%2{{hp6zgGYN