Completely changed how XnoeOS boots, organised the code somewhat, renamed kernel32 to kernel, now uses the 9 sectors after the boot sector to store a 32 bit stage2 loader. No longer spends unnecessary time in real mode. Updated atapio to properly account for the reserved sector count.

This commit is contained in:
Xnoe 2021-09-25 16:31:19 +01:00
parent d617de6a0c
commit c235befa43
Signed by: xnoe
GPG Key ID: 45AC398F44F0DAFE
13 changed files with 101 additions and 703 deletions

1
.gitignore vendored
View File

@ -1,5 +1,6 @@
*.bin
*.img
*.stage2
*.sector
*.o
img.d/

View File

@ -1,15 +1,16 @@
CFLAGS = -m32 -mgeneral-regs-only -nostdlib -fno-builtin -fno-exceptions -fno-leading-underscore -fno-pie -fno-stack-protector -Wno-pointer-to-int-cast
LDFLAGS =
DISK_IMG_FILES = kernel.bin boot32.bin kernel32.bin
KERNEL32_OBJS = screenstuff.o io.o idt.o keyboard.o strings.o atapio.o kernel32_strap.o kernel32.o
DISK_IMG_FILES = kernel.bin
KERNEL32_OBJS = screenstuff.o io.o idt.o keyboard.o strings.o atapio.o c_code_entry.o kernel.o
run: disk.img
qemu-system-x86_64 disk.img
disk.img: clean boot.sector $(DISK_IMG_FILES)
disk.img: clean boot.sector boot.stage2 $(DISK_IMG_FILES)
dd if=/dev/zero of=disk.img count=43 bs=100k
dd if=boot.sector of=disk.img conv=notrunc
dd obs=512 seek=1 if=boot.stage2 of=disk.img conv=notrunc
mount disk.img img.d
cp *.bin img.d/
cp hello.txt img.d/
@ -22,14 +23,23 @@ clean:
boot.sector: boot.asm
nasm $< -o $@
boot.stage2: boot_stage2.ld boot.stage2.o
ld $(LDFLAGS) -T $< boot.stage2.o
boot.stage2.o: src/boot_stage2/main.c io.o atapio.o strings.o c_code_entry.o screenstuff.o
gcc $(CFLAGS) -o $@ -c $<
%.bin: %.asm
nasm $< -o $@
kernel32.bin: kernel32.ld $(KERNEL32_OBJS)
kernel.bin: kernel.ld $(KERNEL32_OBJS)
ld $(LDFLAGS) -T $< $(KERNEL32_OBJS)
%.o: src/kernel/%.asm
nasm -felf32 $< -o $@
%.o: src/%.asm
nasm -felf32 $< -o $@
%.o: src/kernel/%.c
gcc $(CFLAGS) -o $@ -c $<

172
boot.asm
View File

@ -1,3 +1,4 @@
[ORG 0x7C00]
[BITS 16]
jmp short bootcode
@ -7,7 +8,7 @@ bpOEMid db "XNOE "
bpBytesPerSector dw 512
bpSectorsPerCluster db 1
bpReservedSectors dw 1
bpReservedSectors dw 10 ; We should reserve 10 sectors. Boot sector + stage2
bpNoFATs db 2
bpRootDirEntries dw 256
bpLVSectors dw 8586
@ -27,8 +28,6 @@ bpVolumeLabel db "XNOE OS "
bpFileSystem db "FAT16 "
bootcode:
mov ax, 7c0h
mov ds, ax
mov byte [bpDriveNo], dl
@ -43,137 +42,34 @@ bootcode:
movzx cx, cl
mov word [bpSectorsPerTrack], cx
mov si, boot_msg
call _boot_print
mov ax, ds
; Load the stage2 (32-bit) from the next sectors
; Load it at 0x10000
mov ax, 7e0h
mov es, ax
mov bx, buffer
xor bx, bx
; Calculate position of rootdirentries
mov ax, word [bpSectorsPerFat]
movzx cx, byte [bpNoFATs]
mul cx
add ax, 2
mov ax, 2 ; Begin with the 2nd sector
call prep_i13
mov al, 9 ; Load the next 9 sectors (4.5k)
int 13h
mov cx, [bpRootDirEntries]
mov di, buffer
; Now we should prepare to enter in to protected mode for the sole purpose of running the stage2 bootloader
mov ax, 0
; Enable the A20 line
in al, 0x92
or al, 2
out 0x92, al
; jmp $
; Load the temporary GDT
cli
lgdt [gdt_desc]
mov eax, cr0
or eax, 1
mov cr0, eax
kernel_finder:
xchg cx, dx
jmp 08h:7e00h ; Far jump to where we loaded the stage 2
mov di, buffer
add di, ax
mov si, kernel_file
mov cx, 11
rep cmpsb
je kernel_found
add ax, 20h
xchg cx, dx
loop kernel_finder
mov si, kernel_nf
call _boot_print
jmp $
kernel_found:
; jmp $
mov ax, [es:di+0fh]
mov word [cluster], ax
fat_loader:
mov ax, ds
mov es, ax
mov bx, buffer
mov ax, word [bpSectorsPerFat]
mov ah, 2
mov cl, 2
mov ch, 0
mov dh, 0
mov dl, byte [bpDriveNo]
int 13h
kernel_loader:
; Calculate file offset
mov ax, word [bpSectorsPerFat]
movzx cx, byte [bpNoFATs]
mul cx
push ax
mov ax, word [bpRootDirEntries]
mov cx, 16
div cx
mov bx, ax
pop ax
add ax, bx
mov word [fileoffset], ax
mov ax, 2000h
mov es, ax
mov bx, word [pointer]
movzx ax, byte [cluster]
add ax, word [fileoffset]
call prep_i13
int 13h
add word [pointer], 512
mov si, word [cluster]
shl si, 1
add si, buffer
cmp word [si], 0ffffh
je kernel_loaded
add word [cluster], 1
jmp kernel_loader
kernel_loaded:
jmp 2000h:0h
_boot_print:
mov ah, 0eh
mov cx, 1
mov bh, 0
_boot_print_loop:
lodsb
cmp al, 0
je _boot_print_exit
int 10h
jmp _boot_print_loop
_boot_print_exit:
ret
boot_msg db "Boot Sector OK!", 13, 10, 0
kernel_nf db "KERNEL.BIN Missing!", 13, 10, 0
new_line db " ", 0
kernel_file db "KERNEL BIN"
fileoffset dw 0
cluster dw 0
pointer dw 0
; AX set to the logical sector number.
; In ax with sector addr, out correct values for int 13h
prep_i13:
xor dx, dx
div word [bpSectorsPerTrack]
@ -195,7 +91,27 @@ prep_i13:
ret
TIMES 510 - ($ - $$) db 0
DW 0xAA55
gdt:
null:
dq 0
code:
dw 0xffff
dw 0
db 0
db 10011010b
db 11001111b
db 0
data:
dw 0xffff
dw 0
db 0
db 10010010b
db 11001111b
db 0
gdt_end:
gdt_desc:
dw gdt_desc - gdt_end - 1
dd gdt
buffer:
TIMES 510 - ($ - $$) db 0
DW 0xAA55

View File

@ -1,91 +0,0 @@
[ORG 0x40000]
push bp
mov bp, sp
mov ax, [bp + 6]
; xor ax, ax
mov ds, ax
mov word [program_segment], ax
mov si, kernel32_name
mov ah, 4
int 22h
cmp ax, 0
je load_err
push ax
mov si, kernel32_found_success_msg
mov ah, 1
int 22h
; Enable the A20 line
; We don't really care about supporting super old machines
in al, 0x92
or al, 2
out 0x92, al
pop si
mov di, 0 ; Load kernel32.bin at 0x40200
mov bx, 8000h
mov ah, 3
int 22h
mov si, kernel32_exec_msg
mov ah, 1
int 22h
; Prepare for for kernel32.bin execution
cli
lgdt [gdt_desc]
mov eax, cr0
or eax, 1
mov cr0, eax
; Execute kernel32.bin
jmp 08h:0
jmp exit
load_err:
mov si, kernel32_load_err_msg
mov ah, 1
int 22h
exit:
pop bp
retf
kernel32_name db "KERNEL32BIN"
kernel32_load_err_msg db "FAILED TO LOAD KERNEL32.BIN", 10, 0
kernel32_found_success_msg db "FOUND KERNEL32.BIN", 10, 0
kernel32_exec_msg db "EXECUTING KERNEL32.BIN...", 10, 0
program_segment dw 0
gdt:
gdt_null:
dq 0
gdt_code:
dw 0xffff
dw 0x0
db 0x8
db 10011010b
db 01001111b
db 0
gdt_data:
dw 0xffff
dw 0x0
db 0x0
db 10010010b
db 01001111b
db 0
gdt_end:
gdt_desc:
dw gdt_end - gdt - 1
dd gdt

15
boot_stage2.ld Normal file
View File

@ -0,0 +1,15 @@
OUTPUT_FORMAT(binary)
OUTPUT_ARCH(i386:i386)
INPUT(io.o atapio.o strings.o c_code_entry.o screenstuff.o)
OUTPUT(boot.stage2)
SECTIONS {
. = 0x7E00;
.text : {
c_code_entry.o(.text)
boot.stage2.o(.text)
*(.text)
}
}

View File

@ -1,471 +0,0 @@
bpBytesPerSector equ 0x0b
bpSectorsPerCluster equ 0x0d
bpReservedSectors equ 0x0e
bpNoFATs equ 0x10
bpRootDirEntries equ 0x11
bpLVSectors equ 0x13
bpMediumID equ 0x15
bpSectorsPerFat equ 0x16
bpSectorsPerTrack equ 0x18
bpHeads equ 0x1a
bpHiddenSectors equ 0x1c
bpDriveNo equ 0x24
bpSignature equ 0x26
[BITS 16]
; Update the IVT with our interrupt handler
mov bx, 0
mov ds, bx
mov word [ds:136], ihdlr
mov word [ds:138], cs
mov ax, 2000h
mov ds, ax
mov ax, 7c0h
mov fs, ax
; Set up kernel specifics
; Root Directory Entries will be at 2000h:2000h
; FAT1 will be at 2000h:4000h
; Load sectors RDE to 2000h:2000h
mov ax, 2000h
mov es, ax
mov bx, 2000h
; Calculate position of RDE
mov ax, word [fs:bpSectorsPerFat]
movzx cx, byte [fs:bpNoFATs]
mul cx
add ax, 2
call prep_i13
mov al, 16
int 13h
; Load sectors 2 through 36 to 2000h:4000h
mov ax, 2000h
mov es, ax
mov bx, 4000h
mov ax, 2
call prep_i13
mov ax, word [fs:bpSectorsPerFat]
mov ah, 2
int 13h
; Calculate file offset
mov ax, word [fs:bpSectorsPerFat]
movzx cx, byte [fs:bpNoFATs]
mul cx
push ax
mov ax, word [fs:bpRootDirEntries]
mov cx, 16
div cx
mov bx, ax
pop ax
add ax, bx
mov word [fileoffset], ax
push msg
call print
cmd_loop:
push cmd_prompt
call print
; Clear command buffer
mov al, 0
mov di, user_cmd
mov cx, 64
clear_loop:
stosb
loop clear_loop
push user_cmd
push 64
call readline
push newline
call print
mov si, user_cmd
mov di, cmd_help_text
mov cx, 4
rep cmpsb
je cmd_help
mov si, user_cmd
mov di, cmd_clear_text
mov cx, 5
rep cmpsb
je cmd_clear
; If the user hasn't run a command we should determine if they're trying to run a program.
; Decode input to filename
push user_cmd
call decode_filename
; Search for file
mov si, ax
call file_exists
; If it doesn't exist jump to error
cmp ax, 0
je handle_error
; Define the segment where we will load our programs
program_segment equ 4000h
; If the file exists load it at program_segment:0
push ax
push 0
push program_segment
call load_file
; Let programs know what segment they're loaded at
push program_segment
; Make a call to program_segment:0
call program_segment:0
; We've now returned.
; Clean up pushed segment
pop ax
; Recover ds
mov ax, 2000h
mov ds, ax
mov es, ax
; jmp $
; Loop
jmp cmd_loop
handle_error:
push cmd_err
call print
jmp cmd_loop
cmd_help:
push cmd_help_msg
call print
jmp cmd_loop
cmd_help_msg:
db "XnoeOS Help Dialogue", 13, 10
db "--------------------", 13, 10
db "Commands: ", 13, 10
db " - help", 13, 10
db " : Displays this message", 13, 10
db " - clear", 13, 10
db " : Clears the screen", 13, 10
db 0
cmd_clear:
mov ah, 02h
mov dh, 0
mov dl, 0
int 10h
mov ah, 0ah
mov cx, 2000
mov al, 20h
int 10h
jmp cmd_loop
data:
msg db "Kernel OK!", 13, 10, 0
cmd_prompt db ">>> ", 0
cmd_err db "Bad Command or filename!", 13, 10, 13, 10, 0
cmd_help_text db "HELP"
cmd_clear_text db "CLEAR"
newline db 13, 10, 0
program_two db "HELLO BIN"
user_cmd:
times 64 db 0
; print(str)
print:
push bp
mov bp, sp
mov si, [bp + 4]
mov ah, 0eh
mov cx, 1
mov bh, 0
print_loop:
lodsb
cmp al, 0
je print_exit
; Use Unix Line endings (\n)
cmp al, 10
jne _print_skip
int 10h
mov al, 13
int 10h
_print_skip:
int 10h
jmp print_loop
print_exit:
pop bp
ret 2
; readline(max length, buffer)
readline:
push bp
mov bp, sp
mov di, [bp + 6]
mov bx, 0
readline_loop:
mov ah, 0h
int 16h
cmp ah, 01ch
je readline_exit
cmp ah, 0eh
je readline_backspace
; Process all user input as upper case
cmp al, 0x61
jl not_lower
cmp al, 0x79
jg not_lower
and al, 223
not_lower:
mov byte [di], al
inc di
inc bx
mov ah, 0eh
mov cx, 1
int 10h
mov ax, [bp + 4]
cmp bx, ax
je readline_exit
jmp readline_loop
readline_backspace:
cmp bx, 0
je readline_loop
dec di
dec bx
mov ah, 0eh
mov cx, 1
int 10h
mov ah, 0ah
mov cx, 1
mov al, 20h
int 10h
jmp readline_loop
readline_exit:
pop bp
ret 4
file_exists:
push si
mov bp, sp
mov cx, 256 ; Hardcode the amount of entries for now
mov ax, 2000h
mov es, ax
xor ax, ax
file_exists_loop:
pop si ; Get value in to si
push si ; Keep track of original value
xchg cx, dx
mov di, 2000h ; Root Entries is at 2000h:2000h
add di, ax
mov cx, 11
rep cmpsb
je file_exists_found
add ax, 32
xchg cx, dx
loop file_exists_loop
file_exists_not_found:
mov ax, 0
pop si
ret
file_exists_found:
mov ax, [es:di+0fh]
pop si
ret
; loadfile(segment, offset, initsector)
load_file:
push bp
mov bp, sp
push ds
push fs
mov ax, 7c0h
mov fs, ax
mov ax, 2000h
mov ds, ax
mov ax, word [bp + 4]
mov es, ax
load_file_loop:
mov bx, word [bp + 6]
movzx ax, byte [bp + 8]
add ax, word [fileoffset]
call prep_i13
int 13h
add word [bp + 6], 512
mov si, word [bp + 8]
shl si, 1
add si, 4000h
; add si, 1
cmp word [ds:si], 0ffffh
je load_file_loaded
add word [bp + 8], 1
jmp load_file_loop
load_file_loaded:
pop fs
pop ds
pop bp
ret 6
decode_filename:
push bp
mov bp, sp
push word [bp + 4]
; First we want to clear the buffer with 0x20s
mov al, 20h
mov cx, 11
mov di, _decode_buffer
decode_clear_loop:
stosb
loop decode_clear_loop
pop si
mov cx, 8
mov bx, 0
decode_filename_loop:
lodsb
cmp al, "."
je decode_filename_stage2
mov byte [_decode_buffer+bx], al
inc bx
loop decode_filename_loop
decode_filename_stage2:
mov bx, 8
mov cx, 3
decode_filename_stage2_loop:
lodsb
cmp al, 0
je decode_filename_final
mov byte [_decode_buffer+bx], al
inc bx
loop decode_filename_stage2_loop
decode_filename_final:
pop bp
mov ax, _decode_buffer
ret 2
_decode_buffer:
times 11 db 0
ihdlr:
cmp ah, 01h
jne _ihdlr_2
push si
call print
jmp _ihdlr_fin
_ihdlr_2:
cmp ah, 02h
jne _ihdlr_3
push si
push di
call readline
jmp _ihdlr_fin
_ihdlr_3:
cmp ah, 03h
jne _ihdlr_4
push si
push di
push bx
call load_file
jmp _ihdlr_fin
_ihdlr_4:
cmp ah, 04h
jne _ihdlr_5
call file_exists
jmp _ihdlr_fin
_ihdlr_5:
_ihdlr_fin:
iret
prep_i13:
xor dx, dx
div word [fs:bpSectorsPerTrack]
push dx
xor dx, dx
div word [fs:bpHeads]
mov ch, al
mov dh, dl
mov dl, byte [fs:bpDriveNo]
pop ax
mov cl, al
mov al, 1
mov ah, 2
ret
fileoffset dw 0

View File

@ -1,14 +1,14 @@
OUTPUT_FORMAT(binary)
OUTPUT_ARCH(i386:i386)
OUTPUT(kernel32.bin)
OUTPUT(kernel.bin)
SECTIONS {
. = 0x80000;
.text : {
kernel32_strap.o(.text)
kernel32.o(.text)
c_code_entry.o(.text)
kernel.o(.text)
*(.text)
heap_section = .;
}

17
src/boot_stage2/main.c Normal file
View File

@ -0,0 +1,17 @@
#include "../kernel/atapio.h"
#include "../kernel/screenstuff.h"
void main() {
init_term();
init_atapio();
uint8_t* kernel_location = 0x80000;
load_file("KERNEL BIN", kernel_location);
printf("Stage2 success!");
//while (1);
((void(*)(void))kernel_location)();
}

View File

@ -59,8 +59,8 @@ void init_atapio() {
total_28_lbas = *(uint32_t*)(identify_result+60);
// We've initialised now, let's load the FAT and RootDirEntries.
read_sectors(sectorsPerFAT * countFATs + 1, countRDEs / 16, rootDirEntries);
read_sectors(1, sectorsPerFAT, FAT1);
read_sectors(sectorsPerFAT * countFATs + countReserved, countRDEs / 16, rootDirEntries);
read_sectors(countReserved, sectorsPerFAT, FAT1);
}
void read_sector(uint32_t address, uint8_t* buffer) {
@ -111,7 +111,7 @@ void load_file(char* filename, uint8_t* destination) {
bool loaded = false;
while (!loaded) {
uint16_t fromSector = location + (sectorsPerFAT * countFATs) + (countRDEs / 16) - 1;
uint16_t fromSector = location + (sectorsPerFAT * countFATs) + (countRDEs / 16) + (countReserved - 1) - 1;
read_sector(fromSector, destination+offset);
offset += 512;

View File

@ -6,7 +6,6 @@
#include "io.h"
#include "types.h"
#include "strings.h"
#include "screenstuff.h"
void init_atapio();
void read_sector(uint32_t address, uint8_t* buffer);

View File

@ -3,7 +3,7 @@
GateEntry idt[256];
void set_entry(uint8_t interrupt_number, uint16_t code_segment, void* handler, uint8_t type) {
uint32_t handler_addr = (uint16_t)handler;
uint32_t handler_addr = (uint32_t)handler;
uint16_t* handler_halves = (uint16_t*)&handler_addr;
idt[interrupt_number] = (GateEntry){
.offset_low = handler_halves[0],

View File

@ -13,9 +13,11 @@ int main() {
printf("KERNEL32 OK!\n");
printf("Hello, World!\n\nWe are running XnoeOS Code in C now, Protected Mode has been achieved and everything is working super nicely!\n\nHow wonderful!\n\nNow I just need to hope my print function works properly too~~\n");
init_keyboard();
enable_idt();
printf("A\n");
init_atapio();
uint8_t sector[512];