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),)
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

219
boot.nasm
View File

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

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);
}
// 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);
}

View File

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

View File

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

Binary file not shown.