Kernel now is loaded from a partition, allowing a separate MBR bootloader if desired

This commit is contained in:
Lucia Ceionia 2023-02-13 18:23:33 -06:00
parent e9c4e993f4
commit 1b2184fe52
7 changed files with 232 additions and 184 deletions

View File

@ -7,16 +7,29 @@ LFLAGS = -Wl,--gc-sections -Wl,--print-gc-sections -m32 -nostartfiles -nostdlib
ifeq ($(OUTFILE),) ifeq ($(OUTFILE),)
OUTFILE = virtdisk.bin OUTFILE = virtdisk.bin
endif 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) .PHONY: $(OUTFILE)
all: $(OUTFILE) all: $(OUTFILE)
$(OUTFILE): boot.bin kernel.bin $(OUTFILE): boot.bin boot_partition.bin kernel.bin
# Copy to boot sector, don't overwrite MBR # Copy system bootloader to boot sector, don't overwrite MBR
dd bs=400 count=1 conv=notrunc if=boot.bin of=$@ dd bs=400 count=1 conv=notrunc if=boot.bin of=$@
# Write kernel beyond boot sector, maximum 128K (256 sectors) # Ensure partition VBR contains EB 5A
dd bs=512 count=256 seek=1 conv=notrunc if=kernel.bin of=$@ 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 kernel.bin: out.o link.ld usermode.o
clang $(LFLAGS) -Wl,-M -Tlink.ld -ffreestanding -o $@ out.o 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 $@ $< clang $(CFLAGS) -ffunction-sections -fdata-sections -Os -o $@ $<
virtdisk: virtdisk:
dd bs=1M count=32 if=/dev/zero of=virtdisk.bin cp virtdisk.bin.ex virtdisk.bin
echo -n -e '\x55\xaa' | dd bs=1 seek=510 conv=notrunc of=virtdisk.bin
clean: clean:
rm -f $(objects) out.o kernel.bin boot.bin usermode.bin rm -f $(objects) out.o kernel.bin boot.bin usermode.bin

219
boot.nasm
View File

@ -1,6 +1,8 @@
secreadcnt equ 0x38 ; This boots the active partition.
kernelreads equ 0x10000/(512*secreadcnt) ; 64K / Sector Size FIXME This underestimates when kernel size is not divisible by bytes per read ; Relocates self to 0x7E00, loads the
[ORG 0x7c00] ; first sector of active partition
; to 0x7C00 and jumps
[ORG 0x7C00]
[BITS 16] [BITS 16]
xor ax, ax xor ax, ax
mov ds, ax mov ds, ax
@ -8,68 +10,50 @@ mov es, ax
mov ax, 0x8000 mov ax, 0x8000
mov ss, ax mov ss, ax
mov sp, 0xFF00 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 ah, 0x41 ; int 13 extensions check
mov bx, 0x55AA mov bx, 0x55AA
int 0x13 int 0x13
jc no_exten jc no_int13
mov cx, kernelreads ; Find active partition
read_loop: 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 xor ax, ax
mov ah, 0x42 mov ah, 0x42
mov si, addr_packet mov si, addr_packet
int 0x13 int 0x13
jc err jc err
add word [addr_packet_transfer_buff_seg], (secreadcnt*512)/16 ; Jump to partition boot
add word [addr_packet_start_block], secreadcnt jmp 0:0x7C00
loop read_loop
entry: no_int13:
;mov ax,0x2403 ; A20 BIOS Support mov si, no_exten_str
;int 0x15 mov cx, no_exten_str_end - no_exten_str
;jb .no_a20 jmp print
;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
err: err:
mov bx, ax mov bx, ax
mov si, string mov si, string
@ -83,126 +67,17 @@ err_print:
lodsb lodsb
stosw stosw
loop err_print loop err_print
;add di, 2
;mov ax, bx
;call hexprint
hlt_loop: hlt_loop:
hlt hlt
jmp hlt_loop 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: db 'DISK ERROR'
string_end: string_end:
;no_exten_str: db 'NO INT13 EXTEN' no_exten_str: db 'NO INT13 EXTEN'
;no_exten_str_end: no_exten_str_end:
addr_packet: addr_packet:
db 0x10, 0x00 ; size, reserved db 0x10, 0x00 ; size, reserved
dw secreadcnt ; blocks dw 1 ; blocks
addr_packet_transfer_buff_off: dw 0x0000 ; transfer buffer offset addr_packet_transfer_buff_off: dw 0x7C00 ; transfer buffer offset
addr_packet_transfer_buff_seg: dw 0x2000 ; transfer buffer segment addr_packet_transfer_buff_seg: dw 0x0000 ; transfer buffer segment
addr_packet_start_block: dq 1 ; start block addr_packet_start_block: dq 0 ; start block

136
boot_partition.nasm Normal file
View File

@ -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

View File

@ -48,11 +48,13 @@ void SetCursorDisabled() {
V8086Int(0x10, &regs); V8086Int(0x10, &regs);
} }
// This should DEFINITELY be an argument
uint8_t SystemPartition = 0;
uint32_t OpenVol(VOLINFO *vi) { uint32_t OpenVol(VOLINFO *vi) {
uint8_t *diskReadBuf = (uint8_t *)0x20000; uint8_t *diskReadBuf = (uint8_t *)0x20000;
uint8_t pactive, ptype; uint8_t pactive, ptype;
uint32_t pstart, psize; 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; if (pstart == -1) return -1;
return DFS_GetVolInfo(0, diskReadBuf, pstart, vi); return DFS_GetVolInfo(0, diskReadBuf, pstart, vi);
} }

View File

@ -101,6 +101,14 @@ void ensure_v86env() {
*d++ = *s++; *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__((__no_caller_saved_registers__))
__attribute__((__noreturn__)) __attribute__((__noreturn__))
extern void return_prev_task(); 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 // reset error screen
for (int i = 0; i < (80*50)/2; i++) for (int i = 0; i < (80*50)/2; i++)
((uint32_t*)error_screen)[i] = 0x0f000f00; ((uint32_t*)error_screen)[i] = 0x0f000f00;
_ERRORCODE = -1;
return_prev_task(); return_prev_task();
} }
@ -181,6 +190,10 @@ Protected Only (1MB+)
400000 - 700000 Usermode Code (3mB) 400000 - 700000 Usermode Code (3mB)
700000 - 800000 Usermode Stack (1mB) 700000 - 800000 Usermode Stack (1mB)
*/ */
// FIXME Truly awful
extern uint8_t SystemPartition;
void DrawScreen(uint16_t *vga) { void DrawScreen(uint16_t *vga) {
uint16_t *vga_text = vga; uint16_t *vga_text = vga;
// clear screen // clear screen
@ -214,6 +227,7 @@ void DrawScreen(uint16_t *vga) {
vga_text[80+42] = 0x1f00 | 'S'; vga_text[80+42] = 0x1f00 | 'S';
vga_text[80+43] = 0x1f00 | ' '; vga_text[80+43] = 0x1f00 | ' ';
vga_text[80+44] = 0x1f00 | '-'; vga_text[80+44] = 0x1f00 | '-';
printByte(SystemPartition, &vga_text[80+50]);
} }
void SetPalette() { void SetPalette() {
@ -418,7 +432,9 @@ void SystemRun() {
{ {
VOLINFO vi; VOLINFO vi;
// TODO Check partitions beyond 0 // 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 = &((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 += printStr("Error loading file select. Ensure the disk has a valid MBR and FAT partition.", vga_text);
vga_text = &((word*)0xb8000)[80*5 + 2]; vga_text = &((word*)0xb8000)[80*5 + 2];
@ -457,8 +473,8 @@ void start() {
vga_text = &vga_text[80]; vga_text = &vga_text[80];
// DL *should* be preserved // DL *should* be preserved
uint8_t dl; uint16_t boot_dx;
asm volatile("nop":"=d"(dl)); asm volatile("nop":"=d"(boot_dx));
if (!check_cmov()) { if (!check_cmov()) {
char cmov_err[] = "NO CMOV"; char cmov_err[] = "NO CMOV";
@ -467,7 +483,7 @@ void start() {
for (;;) asm volatile("hlt"); for (;;) asm volatile("hlt");
} }
vga_text += printByte(dl, vga_text); vga_text += printWord(boot_dx, vga_text);
vga_text++; vga_text++;
uint32_t o; uint32_t o;
@ -509,6 +525,9 @@ void start() {
backup_ivtbios(); backup_ivtbios();
InitDisk(); InitDisk();
// DL contained disk number, DH contained active partition
SystemPartition = boot_dx >> 8;
create_child(GetFreeStack(), (uintptr_t)SystemRun, 0); create_child(GetFreeStack(), (uintptr_t)SystemRun, 0);
// If this returns, something is *very* wrong, reboot the system // If this returns, something is *very* wrong, reboot the system
// TODO Maybe try to recover? // TODO Maybe try to recover?

View File

@ -122,6 +122,10 @@ void TestCHS() {
} }
} }
} }
// FIXME Just horrible
extern uint8_t SystemPartition;
void TestFAT() { void TestFAT() {
uint16_t *vga_text = (uint16_t *)0xb8000; uint16_t *vga_text = (uint16_t *)0xb8000;
uint8_t *diskReadBuf = (uint8_t *)0x22400; uint8_t *diskReadBuf = (uint8_t *)0x22400;
@ -131,7 +135,7 @@ void TestFAT() {
uint8_t pactive, ptype; uint8_t pactive, ptype;
uint32_t pstart, psize; 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 = (uint16_t *)0xb8000;
vga_text += printStr("PartStart: ", vga_text); vga_text += printStr("PartStart: ", vga_text);
vga_text += printDword(pstart, vga_text); vga_text += printDword(pstart, vga_text);

Binary file not shown.