From c235befa435d9632d1ba2a3e190906c2b97d5551 Mon Sep 17 00:00:00 2001 From: Xnoe Date: Sat, 25 Sep 2021 16:31:19 +0100 Subject: [PATCH] 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. --- .gitignore | 1 + Makefile | 18 +- boot.asm | 172 ++----- boot32.asm | 91 ---- boot_stage2.ld | 15 + kernel.asm | 471 ------------------ kernel32.ld => kernel.ld | 6 +- src/boot_stage2/main.c | 17 + .../kernel32_strap.asm => c_code_entry.asm} | 0 src/kernel/atapio.c | 6 +- src/kernel/atapio.h | 1 - src/kernel/idt.c | 2 +- src/kernel/{kernel32.c => kernel.c} | 4 +- 13 files changed, 101 insertions(+), 703 deletions(-) delete mode 100644 boot32.asm create mode 100644 boot_stage2.ld delete mode 100644 kernel.asm rename kernel32.ld => kernel.ld (64%) create mode 100644 src/boot_stage2/main.c rename src/{kernel/kernel32_strap.asm => c_code_entry.asm} (100%) rename src/kernel/{kernel32.c => kernel.c} (98%) diff --git a/.gitignore b/.gitignore index d6a02df..9574e7a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ *.bin *.img +*.stage2 *.sector *.o img.d/ \ No newline at end of file diff --git a/Makefile b/Makefile index 64ceedb..c12ad33 100644 --- a/Makefile +++ b/Makefile @@ -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 $< \ No newline at end of file diff --git a/boot.asm b/boot.asm index 4856f45..f5ff687 100644 --- a/boot.asm +++ b/boot.asm @@ -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: \ No newline at end of file +TIMES 510 - ($ - $$) db 0 +DW 0xAA55 \ No newline at end of file diff --git a/boot32.asm b/boot32.asm deleted file mode 100644 index b85382d..0000000 --- a/boot32.asm +++ /dev/null @@ -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 \ No newline at end of file diff --git a/boot_stage2.ld b/boot_stage2.ld new file mode 100644 index 0000000..0641d2c --- /dev/null +++ b/boot_stage2.ld @@ -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) + } +} \ No newline at end of file diff --git a/kernel.asm b/kernel.asm deleted file mode 100644 index 770dcdc..0000000 --- a/kernel.asm +++ /dev/null @@ -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 \ No newline at end of file diff --git a/kernel32.ld b/kernel.ld similarity index 64% rename from kernel32.ld rename to kernel.ld index 98b8250..1706cd3 100644 --- a/kernel32.ld +++ b/kernel.ld @@ -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 = .; } diff --git a/src/boot_stage2/main.c b/src/boot_stage2/main.c new file mode 100644 index 0000000..5c5a31a --- /dev/null +++ b/src/boot_stage2/main.c @@ -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)(); +} \ No newline at end of file diff --git a/src/kernel/kernel32_strap.asm b/src/c_code_entry.asm similarity index 100% rename from src/kernel/kernel32_strap.asm rename to src/c_code_entry.asm diff --git a/src/kernel/atapio.c b/src/kernel/atapio.c index a24765b..c6e7745 100644 --- a/src/kernel/atapio.c +++ b/src/kernel/atapio.c @@ -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; diff --git a/src/kernel/atapio.h b/src/kernel/atapio.h index 25219b8..48de720 100644 --- a/src/kernel/atapio.h +++ b/src/kernel/atapio.h @@ -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); diff --git a/src/kernel/idt.c b/src/kernel/idt.c index 2bdadae..9b133e0 100644 --- a/src/kernel/idt.c +++ b/src/kernel/idt.c @@ -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], diff --git a/src/kernel/kernel32.c b/src/kernel/kernel.c similarity index 98% rename from src/kernel/kernel32.c rename to src/kernel/kernel.c index 8e0d6c7..34760e6 100644 --- a/src/kernel/kernel32.c +++ b/src/kernel/kernel.c @@ -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];