Kernel now is loaded from a partition, allowing a separate MBR bootloader if desired
This commit is contained in:
parent
e9c4e993f4
commit
1b2184fe52
24
Makefile
24
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
|
||||
|
219
boot.nasm
219
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
|
||||
|
136
boot_partition.nasm
Normal file
136
boot_partition.nasm
Normal 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
|
4
helper.c
4
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);
|
||||
}
|
||||
|
27
kernel.c
27
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?
|
||||
|
6
tests.c
6
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);
|
||||
|
BIN
virtdisk.bin.ex
BIN
virtdisk.bin.ex
Binary file not shown.
Loading…
Reference in New Issue
Block a user