From 21b24619f05ecd0a03ef04eb4e1cf1765e213168 Mon Sep 17 00:00:00 2001 From: Tyler McGurrin Date: Thu, 5 Jun 2025 20:57:54 -0400 Subject: [PATCH] Begin the Great Bootloader Swap. --- .gitignore | 3 +- Makefile | 34 --- README.md | 4 +- doc/Kernel Params.md | 2 +- kparams | 1 - src/bootloader/stage1/Makefile | 14 -- src/bootloader/stage1/boot.asm | 397 ------------------------------ src/bootloader/stage2/Makefile | 33 --- src/bootloader/stage2/ctype.c | 14 -- src/bootloader/stage2/ctype.h | 11 - src/bootloader/stage2/disk.c | 52 ---- src/bootloader/stage2/disk.h | 20 -- src/bootloader/stage2/entry.asm | 175 ------------- src/bootloader/stage2/fat.c | 377 ---------------------------- src/bootloader/stage2/fat.h | 50 ---- src/bootloader/stage2/linker.ld | 15 -- src/bootloader/stage2/main.c | 135 ---------- src/bootloader/stage2/memdefs.h | 29 --- src/bootloader/stage2/memdetect.c | 40 --- src/bootloader/stage2/memdetect.h | 10 - src/bootloader/stage2/memory.c | 36 --- src/bootloader/stage2/memory.h | 11 - src/bootloader/stage2/minmax.h | 9 - src/bootloader/stage2/stdio.c | 318 ------------------------ src/bootloader/stage2/stdio.h | 13 - src/bootloader/stage2/string.c | 50 ---- src/bootloader/stage2/string.h | 10 - src/bootloader/stage2/x86.asm | 350 -------------------------- src/bootloader/stage2/x86.h | 52 ---- test | 1 - tools/fat/fat.c | 183 -------------- 31 files changed, 5 insertions(+), 2444 deletions(-) delete mode 100644 kparams delete mode 100644 src/bootloader/stage1/Makefile delete mode 100644 src/bootloader/stage1/boot.asm delete mode 100644 src/bootloader/stage2/Makefile delete mode 100644 src/bootloader/stage2/ctype.c delete mode 100644 src/bootloader/stage2/ctype.h delete mode 100644 src/bootloader/stage2/disk.c delete mode 100644 src/bootloader/stage2/disk.h delete mode 100644 src/bootloader/stage2/entry.asm delete mode 100644 src/bootloader/stage2/fat.c delete mode 100644 src/bootloader/stage2/fat.h delete mode 100644 src/bootloader/stage2/linker.ld delete mode 100644 src/bootloader/stage2/main.c delete mode 100644 src/bootloader/stage2/memdefs.h delete mode 100644 src/bootloader/stage2/memdetect.c delete mode 100644 src/bootloader/stage2/memdetect.h delete mode 100644 src/bootloader/stage2/memory.c delete mode 100644 src/bootloader/stage2/memory.h delete mode 100644 src/bootloader/stage2/minmax.h delete mode 100644 src/bootloader/stage2/stdio.c delete mode 100644 src/bootloader/stage2/stdio.h delete mode 100644 src/bootloader/stage2/string.c delete mode 100644 src/bootloader/stage2/string.h delete mode 100644 src/bootloader/stage2/x86.asm delete mode 100644 src/bootloader/stage2/x86.h delete mode 100644 test delete mode 100644 tools/fat/fat.c diff --git a/.gitignore b/.gitignore index eea8b18..fa5eac0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ .vscode/ build/ -toolchain/ -src/bootloader/stage2_old \ No newline at end of file +toolchain/ \ No newline at end of file diff --git a/Makefile b/Makefile index 9693bf2..80e85d9 100644 --- a/Makefile +++ b/Makefile @@ -18,33 +18,11 @@ floppy_image: $(BUILD_DIR)/main_floppy.img $(BUILD_DIR)/main_floppy.img: bootloader kernel dd if=/dev/zero of=$(BUILD_DIR)/main_floppy.img bs=512 count=2880 mkfs.fat -F 12 -n "NANITE" $(BUILD_DIR)/main_floppy.img - dd if=$(BUILD_DIR)/stage1.bin of=$(BUILD_DIR)/main_floppy.img conv=notrunc mmd -i $(BUILD_DIR)/main_floppy.img "::boot" mmd -i $(BUILD_DIR)/main_floppy.img "::misc" mmd -i $(BUILD_DIR)/main_floppy.img "::misc/src" - mcopy -v -i $(BUILD_DIR)/main_floppy.img $(BUILD_DIR)/kernel.bin "::boot" - mcopy -v -i $(BUILD_DIR)/main_floppy.img $(BUILD_DIR)/nboot.bin "::nboot.bin" - mcopy -v -i $(BUILD_DIR)/main_floppy.img test "::boot" - mcopy -v -i $(BUILD_DIR)/main_floppy.img kparams "::boot" mcopy -s -i $(BUILD_DIR)/main_floppy.img src/* "::misc/src" -# -# Bootloader -# -# -bootloader: stage1 stage2 - -stage1: $(BUILD_DIR)/stage1.bin - -$(BUILD_DIR)/stage1.bin: always - $(MAKE) -C src/bootloader/stage1 BUILD_DIR=$(abspath $(BUILD_DIR)) - -stage2: $(BUILD_DIR)/stage2.bin - -$(BUILD_DIR)/stage2.bin: always - $(MAKE) -C src/bootloader/stage2 BUILD_DIR=$(abspath $(BUILD_DIR)) - - # # Kernel # @@ -53,21 +31,11 @@ kernel: $(BUILD_DIR)/kernel.bin $(BUILD_DIR)/kernel.bin: always $(MAKE) -C src/kernel BUILD_DIR=$(abspath $(BUILD_DIR)) -# -# Tools -# -tools_fat: $(BUILD_DIR)/tools/fat -$(BUILD_DIR)/tools/fat: always tools/fat/fat.c - mkdir -p $(BUILD_DIR)/tools - $(CC) -g -o $(BUILD_DIR)/tools/fat tools/fat/fat.c - # # Always # always: mkdir -p $(BUILD_DIR) -# echo Version $(oldnum) -# sed -i '9i s/#define VERSION "RD-//#define VERSION "RD-$(newnum)/"' src/libs/version.h @@ -75,8 +43,6 @@ always: # Clean # clean: - $(MAKE) -C src/bootloader/stage1 BUILD_DIR=$(abspath $(BUILD_DIR)) clean - $(MAKE) -C src/bootloader/stage2 BUILD_DIR=$(abspath $(BUILD_DIR)) clean $(MAKE) -C src/kernel BUILD_DIR=$(abspath $(BUILD_DIR)) clean rm -rf $(BUILD_DIR)/* rm -rf src/bootloader/stage2/*.err diff --git a/README.md b/README.md index 81b861c..5bce647 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,8 @@ Good luck figuring out the spagetti code i write... (sorry not sorry ;D) Designed for older computers such as a Pentium (i586) Class Machine. I would recomend atleast a Pentium 2 Class System or higher however. ## Features -- Bootloader +- Support for the GRUB Bootloader +- Custom Theme for GRUB (Coming Soon!) - Basic Memory Paging - Support for Floppy Disk Drives (FDDs) - Basic Serial (RS-232) Support @@ -33,6 +34,7 @@ If you wanted to write it to a floppy disk you can use `write.sh` tho be careful - make - gcc (or really any C compiler) - NASM +- GRUB ## How is Testing Done Testing is mostly done with QEMU These days, but I do sometimes pull out my Dell Latitude D610 to test on (for anyone wondering its completely maxed out. [2GB of ram Pentium M @ 2.23GHz]) diff --git a/doc/Kernel Params.md b/doc/Kernel Params.md index 2a3c7e9..372a396 100644 --- a/doc/Kernel Params.md +++ b/doc/Kernel Params.md @@ -1,6 +1,6 @@ # Kernel Parameters -Kernel Parameters are edited via editing the `kernelparams` file in the root of the git tree/hdd. +Basically just enter it into grub, just like you would for something like linux. They should be seperated via commas **WITHOUT ANY SPACES!** ## List of Parameters diff --git a/kparams b/kparams deleted file mode 100644 index 3086fdf..0000000 --- a/kparams +++ /dev/null @@ -1 +0,0 @@ -verbose \ No newline at end of file diff --git a/src/bootloader/stage1/Makefile b/src/bootloader/stage1/Makefile deleted file mode 100644 index 2bf3755..0000000 --- a/src/bootloader/stage1/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -BUILD_DIR?=build/ -ASM?=nasm - -.PHONY: all clean - -all: stage1 - -stage1: $(BUILD_DIR)/stage1.bin - -$(BUILD_DIR)/stage1.bin: - $(ASM) boot.asm -f bin -o $(BUILD_DIR)/stage1.bin - -clean: - rm -f $(BUILD_DIR)/stage1.bin diff --git a/src/bootloader/stage1/boot.asm b/src/bootloader/stage1/boot.asm deleted file mode 100644 index e5d62c2..0000000 --- a/src/bootloader/stage1/boot.asm +++ /dev/null @@ -1,397 +0,0 @@ -;/////////////////////; -;Nanite OS ; -;COPYRIGHT (C) 2024 ; -;Tyler McGurrin ; -;/////////////////////; -org 0x7C00 -bits 16 - - -%define ENDL 0x0D, 0x0A - - -; -; FAT12 header -; -jmp short start -nop - -bdb_oem: db 'MSWIN4.1' ; 8 bytes -bdb_bytes_per_sector: dw 512 -bdb_sectors_per_cluster: db 1 -bdb_reserved_sectors: dw 1 -bdb_fat_count: db 2 -bdb_dir_entries_count: dw 0E0h -bdb_total_sectors: dw 2880 ; 2880 * 512 = 1.44MB -bdb_media_descriptor_type: db 0F0h ; F0 = 3.5" floppy disk -bdb_sectors_per_fat: dw 9 ; 9 sectors/fat -bdb_sectors_per_track: dw 18 -bdb_heads: dw 2 -bdb_hidden_sectors: dd 0 -bdb_large_sector_count: dd 0 - -; extended boot record -ebr_drive_number: db 0 ; 0x00 floppy, 0x80 hdd, useless - db 0 ; reserved -ebr_signature: db 29h -ebr_volume_id: db 12h, 34h, 56h, 78h ; serial number, value doesn't matter -ebr_volume_label: db 'NANITE ' ; 11 bytes, padded with spaces -ebr_system_id: db 'FAT12 ' ; 8 bytes - -; -; Code goes here -; - -start: - ; setup data segments - mov ax, 0 ; can't set ds/es directly - mov ds, ax - mov es, ax - - ; setup stack - mov ss, ax - mov sp, 0x7C00 ; stack grows downwards from where we are loaded in memory - - ; some BIOSes might start us at 07C0:0000 instead of 0000:7C00, make sure we are in the - ; expected location - push es - push word .after - retf - -.after: - - ; read something from floppy disk - ; BIOS should set DL to drive number - mov [ebr_drive_number], dl - - ; show loading message - mov si, msg_loading - call puts - - ; read drive parameters (sectors per track and head count), - ; instead of relying on data on formatted disk - push es - mov ah, 08h - int 13h - jc error - pop es - - and cl, 0x3F ; remove top 2 bits - xor ch, ch - mov [bdb_sectors_per_track], cx ; sector count - - inc dh - mov [bdb_heads], dh ; head count - - ; compute LBA of root directory = reserved + fats * sectors_per_fat - ; note: this section can be hardcoded - mov ax, [bdb_sectors_per_fat] - mov bl, [bdb_fat_count] - xor bh, bh - mul bx ; ax = (fats * sectors_per_fat) - add ax, [bdb_reserved_sectors] ; ax = LBA of root directory - push ax - - ; compute size of root directory = (32 * number_of_entries) / bytes_per_sector - mov ax, [bdb_dir_entries_count] - shl ax, 5 ; ax *= 32 - xor dx, dx ; dx = 0 - div word [bdb_bytes_per_sector] ; number of sectors we need to read - - test dx, dx ; if dx != 0, add 1 - jz .root_dir_after - inc ax ; division remainder != 0, add 1 - ; this means we have a sector only partially filled with entries -.root_dir_after: - - ; read root directory - mov cl, al ; cl = number of sectors to read = size of root directory - pop ax ; ax = LBA of root directory - mov dl, [ebr_drive_number] ; dl = drive number (we saved it previously) - mov bx, buffer ; es:bx = buffer - call disk_read - - ; search for stage2 - xor bx, bx - mov di, buffer - -; .search_boot_dir: -; mov si, boot_dir -; mov cx, 11 ; compare up to 11 characters -; push di -; repe cmpsb -; pop di -; je .found_boot_dir - -; add di, 32 -; inc bx -; cmp bx, [bdb_dir_entries_count] -; jl .search_boot_dir - -; ; kernel not found -; jmp error - -; .found_boot_dir: -; hlt - -.search_stage2: - mov si, file_stage2_bin - mov cx, 11 ; compare up to 11 characters - push di - repe cmpsb - pop di - je .found_stage2 - - add di, 32 - inc bx - cmp bx, [bdb_dir_entries_count] - jl .search_stage2 - - ; kernel not found - jmp error - -.found_stage2: - - ; di should have the address to the entry - mov ax, [di + 26] ; first logical cluster field (offset 26) - mov [stage2_cluster], ax - - ; load FAT from disk into memory - mov ax, [bdb_reserved_sectors] - mov bx, buffer - mov cl, [bdb_sectors_per_fat] - mov dl, [ebr_drive_number] - call disk_read - - ; read kernel and process FAT chain - mov bx, STAGE2_LOAD_SEGMENT - mov es, bx - mov bx, STAGE2_LOAD_OFFSET - -.load_stage2_loop: - - ; Read next cluster - mov ax, [stage2_cluster] - - ; not nice :( hardcoded value - add ax, 31 ; first cluster = (kernel_cluster - 2) * sectors_per_cluster + start_sector - ; start sector = reserved + fats + root directory size = 1 + 18 + 134 = 33 - mov cl, 1 - mov dl, [ebr_drive_number] - call disk_read - - add bx, [bdb_bytes_per_sector] - - ; compute location of next cluster - mov ax, [stage2_cluster] - mov cx, 3 - mul cx - mov cx, 2 - div cx ; ax = index of entry in FAT, dx = cluster mod 2 - - mov si, buffer - add si, ax - mov ax, [ds:si] ; read entry from FAT table at index ax - - or dx, dx - jz .even - -.odd: - shr ax, 4 - jmp .next_cluster_after - -.even: - and ax, 0x0FFF - -.next_cluster_after: - cmp ax, 0x0FF8 ; end of chain - jae .read_finish - - mov [stage2_cluster], ax - jmp .load_stage2_loop - -.read_finish: - - ; jump to our kernel - mov dl, [ebr_drive_number] ; boot device in dl - - mov ax, STAGE2_LOAD_SEGMENT ; set segment registers - mov ds, ax - mov es, ax - - jmp STAGE2_LOAD_SEGMENT:STAGE2_LOAD_OFFSET - - jmp wait_key_and_reboot ; should never happen - - cli ; disable interrupts, this way CPU can't get out of "halt" state - hlt - - -; -; Error handler (i needed more room.) -; - -error: - mov si, msg_error - call puts - jmp wait_key_and_reboot - -wait_key_and_reboot: - mov ah, 0 - int 16h ; wait for keypress - jmp 0FFFFh:0 ; jump to beginning of BIOS, should reboot - -.halt: - cli ; disable interrupts, this way CPU can't get out of "halt" state - hlt - - -; -; Prints a string to the screen -; Params: -; - ds:si points to string -; -puts: - ; save registers we will modify - push si - push ax - push bx - -.loop: - lodsb ; loads next character in al - or al, al ; verify if next character is null? - jz .done - - mov ah, 0x0E ; call bios interrupt - mov bh, 0 ; set page number to 0 - int 0x10 - - jmp .loop - -.done: - pop bx - pop ax - pop si - ret - -; -; Disk routines -; - -; -; Converts an LBA address to a CHS address -; Parameters: -; - ax: LBA address -; Returns: -; - cx [bits 0-5]: sector number -; - cx [bits 6-15]: cylinder -; - dh: head -; - -lba_to_chs: - - push ax - push dx - - xor dx, dx ; dx = 0 - div word [bdb_sectors_per_track] ; ax = LBA / SectorsPerTrack - ; dx = LBA % SectorsPerTrack - - inc dx ; dx = (LBA % SectorsPerTrack + 1) = sector - mov cx, dx ; cx = sector - - xor dx, dx ; dx = 0 - div word [bdb_heads] ; ax = (LBA / SectorsPerTrack) / Heads = cylinder - ; dx = (LBA / SectorsPerTrack) % Heads = head - mov dh, dl ; dh = head - mov ch, al ; ch = cylinder (lower 8 bits) - shl ah, 6 - or cl, ah ; put upper 2 bits of cylinder in CL - - pop ax - mov dl, al ; restore DL - pop ax - ret - - -; -; Reads sectors from a disk -; Parameters: -; - ax: LBA address -; - cl: number of sectors to read (up to 128) -; - dl: drive number -; - es:bx: memory address where to store read data -; -disk_read: - - push ax ; save registers we will modify - push bx - push cx - push dx - push di - - push cx ; temporarily save CL (number of sectors to read) - call lba_to_chs ; compute CHS - pop ax ; AL = number of sectors to read - - mov ah, 02h - mov di, 3 ; retry count - -.retry: - pusha ; save all registers, we don't know what bios modifies - stc ; set carry flag, some BIOS'es don't set it - int 13h ; carry flag cleared = success - jnc .done ; jump if carry not set - - ; read failed - popa - call disk_reset - - dec di - test di, di - jnz .retry - -.fail: - ; all attempts are exhausted - jmp error - -.done: - popa - - pop di - pop dx - pop cx - pop bx - pop ax ; restore registers modified - ret - - -; -; Resets disk controller -; Parameters: -; dl: drive number -; -disk_reset: - pusha - mov ah, 0 - stc - int 13h - jc error - popa - ret - - -msg_loading: db 'Loading NBOOT...', ENDL, 0 -msg_error: db 'ERR!', ENDL, 0 -file_stage2_bin: db 'NBOOT BIN' -boot_dir: db 'BOOT ' -stage2_cluster: dw 0 - -STAGE2_LOAD_SEGMENT equ 0x0 -STAGE2_LOAD_OFFSET equ 0x500 - -times 510-($-$$) db 0 -dw 0AA55h - -buffer: - diff --git a/src/bootloader/stage2/Makefile b/src/bootloader/stage2/Makefile deleted file mode 100644 index fc8fda7..0000000 --- a/src/bootloader/stage2/Makefile +++ /dev/null @@ -1,33 +0,0 @@ -TARGET_ASMFLAGS += -f elf -TARGET_CFLAGS += -ffreestanding -nostdlib -TARGET_LIBS += -lgcc -TARGET_LINKFLAGS += -T linker.ld -nostdlib - -SOURCES_C=$(wildcard *.c) -SOURCES_ASM=$(wildcard *.asm) -OBJECTS_C=$(patsubst %.c, $(BUILD_DIR)/stage2/c/%.obj, $(SOURCES_C)) -OBJECTS_ASM=$(patsubst %.asm, $(BUILD_DIR)/stage2/asm/%.obj, $(SOURCES_ASM)) -HEADERS_C= $(wildcard ../../libs/*.h) \ - $(wildcard ../../libs/*/*.h) - -.PHONY: all stage2 clean always - -all: stage2 - -stage2: $(BUILD_DIR)/nboot.bin - -$(BUILD_DIR)/nboot.bin: $(OBJECTS_ASM) $(OBJECTS_C) - $(TARGET_LD) $(TARGET_LINKFLAGS) -Wl,-Map=$(BUILD_DIR)/stage2.map -o $@ $^ $(TARGET_LIBS) - -$(BUILD_DIR)/stage2/c/%.obj: %.c always $(HEADERS_C) - $(TARGET_CC) $(TARGET_CFLAGS) -c -o $@ $< - -$(BUILD_DIR)/stage2/asm/%.obj: %.asm always - $(TARGET_ASM) $(TARGET_ASMFLAGS) -o $@ $< - -always: - mkdir -p $(BUILD_DIR)/stage2/c - mkdir -p $(BUILD_DIR)/stage2/asm - -clean: - rm -f $(BUILD_DIR)/nboot.bin \ No newline at end of file diff --git a/src/bootloader/stage2/ctype.c b/src/bootloader/stage2/ctype.c deleted file mode 100644 index df73df5..0000000 --- a/src/bootloader/stage2/ctype.c +++ /dev/null @@ -1,14 +0,0 @@ -/*----------------*\ -|Nanite OS | -|Copyright (C) 2024| -|Tyler McGurrin | -\*----------------*/ -#include "ctype.h" - -bool islower(char chr) { - return chr >= 'a' && chr <= 'z'; -} - -char toupper(char chr) { - return islower(chr) ? (chr - 'a' + 'A') : chr; -} diff --git a/src/bootloader/stage2/ctype.h b/src/bootloader/stage2/ctype.h deleted file mode 100644 index 2e24089..0000000 --- a/src/bootloader/stage2/ctype.h +++ /dev/null @@ -1,11 +0,0 @@ -/*----------------*\ -|Nanite OS | -|Copyright (C) 2024| -|Tyler McGurrin | -\*----------------*/ -#pragma once -#include -#include - -bool islower(char chr); -char toupper(char chr); diff --git a/src/bootloader/stage2/disk.c b/src/bootloader/stage2/disk.c deleted file mode 100644 index 50c94b6..0000000 --- a/src/bootloader/stage2/disk.c +++ /dev/null @@ -1,52 +0,0 @@ -/*----------------*\ -|Nanite OS | -|Copyright (C) 2024| -|Tyler McGurrin | -\*----------------*/ -#include "disk.h" -#include "x86.h" -#include "stdio.h" - -bool DISK_Initialize(DISK* disk, uint8_t driveNumber) { - uint8_t driveType; - uint16_t cylinders, sectors, heads; - - if (!x86_Disk_GetDriveParams(disk->id, &driveType, &cylinders, §ors, &heads)) - return false; - - disk->id = driveNumber; - disk->cylinders = cylinders; - disk->heads = heads; - disk->sectors = sectors; - - return true; -} - -void DISK_LBA2CHS(DISK* disk, uint32_t lba, uint16_t* cylinderOut, uint16_t* sectorOut, uint16_t* headOut) { - // sector = (LBA % sectors per track + 1) - *sectorOut = lba % disk->sectors +1; - - // cylinder = (LBA / sects per track / heads) - *cylinderOut = (lba / disk->sectors) / disk->heads; - - // head = (LBA / sects per track % heads) - *headOut = (lba / disk->sectors) % disk->heads; - - // printf("LBA2CHS: lba=%u sect=%u cyl=%u head=%u disk_sectors=%u disk_heads=%u\n", lba, *sectorOut, *cylinderOut, *headOut, disk->sectors, disk->heads); -} - -bool DISK_ReadSectors(DISK* disk, uint32_t lba, uint8_t sectors, void* dataOut) { - uint16_t cylinder, sector, head; - - DISK_LBA2CHS(disk, lba, &cylinder, §or, &head); - - for (int i = 0; i < 3; i++) - { - if (x86_Disk_Read(disk->id, cylinder, sector, head, sectors, dataOut)) - return true; - - x86_Disk_Reset(disk->id); - } - - return false; -} diff --git a/src/bootloader/stage2/disk.h b/src/bootloader/stage2/disk.h deleted file mode 100644 index 876cf39..0000000 --- a/src/bootloader/stage2/disk.h +++ /dev/null @@ -1,20 +0,0 @@ -/*----------------*\ -|Nanite OS | -|Copyright (C) 2024| -|Tyler McGurrin | -\*----------------*/ -#pragma once - -#include "stdint.h" -#include - -typedef struct { - uint8_t id; - uint16_t cylinders; - uint16_t sectors; - uint16_t heads; -} DISK; - -bool DISK_Initialize(DISK* disk, uint8_t driveNumber); -bool DISK_ReadSectors(DISK* disk, uint32_t lba, uint8_t sectors, void* lowerDataOut); - diff --git a/src/bootloader/stage2/entry.asm b/src/bootloader/stage2/entry.asm deleted file mode 100644 index 52f72bb..0000000 --- a/src/bootloader/stage2/entry.asm +++ /dev/null @@ -1,175 +0,0 @@ -;/////////////////////; -;Nanite OS ; -;COPYRIGHT (C) 2024 ; -;Tyler McGurrin ; -;/////////////////////; -bits 16 - -section .entry - -extern __bss_start -extern __end - -extern start -global entry - -entry: - cli - - ; save boot drive - mov [g_BootDrive], dl - - ; setup stack - mov ax, ds - mov ss, ax - mov sp, 0xFFF0 - mov bp, sp - - ; switch to PMODE - call EnableA20 - call LoadGDT - - ; set PMODE enable flag in CR0 - mov eax, CR0 - or al, 1 - mov cr0, eax - - ; far jmp into PMODE - jmp dword 08h:.pmode - -.pmode: - ; we are now in protected mode! - [bits 32] - - ; 6 - setup segment registers - mov ax, 0x10 - mov ds, ax - mov ss, ax - mov al, 0 - cld - rep stosb - - ; clear BSS (uninit data) - mov edi, __bss_start - mov ecx, __end - sub ecx, edi - - - xor edx, edx - mov dl, [g_BootDrive] - push edx - call start - - cli - hlt - - - -EnableA20: - [bits 16] - ; disable keyboard - call A20WaitInput - mov al, KbdControllerDisableKeyboard - out KbdControllerCommandPort, al - - ; read control output port - call A20WaitInput - mov al, KbdControllerReadCtrlOutputPort - out KbdControllerCommandPort, al - - call A20WaitOutput - in al, KbdControllerDataPort - push eax - - ; write control output port - call A20WaitInput - mov al, KbdControllerWriteCtrlOutputPort - out KbdControllerCommandPort, al - - call A20WaitInput - pop eax - or al, 2 ; bit 2 = A20 bit - out KbdControllerDataPort, al - - ; enable keyboard - call A20WaitInput - mov al, KbdControllerEnableKeyboard - out KbdControllerCommandPort, al - - call A20WaitInput - ret - - -A20WaitInput: - [bits 16] - ; wait until status bit 2 (input buffer) is 0 - ; by reading from command port, we read status byte - in al, KbdControllerCommandPort - test al, 2 - jnz A20WaitInput - ret - -A20WaitOutput: - [bits 16] - ; wait until status bit 1 (output buffer) is 1 so it can be read - in al, KbdControllerCommandPort - test al, 1 - jz A20WaitOutput - ret - - -LoadGDT: - [bits 16] - lgdt [g_GDTDesc] - ret - - - -KbdControllerDataPort equ 0x60 -KbdControllerCommandPort equ 0x64 -KbdControllerDisableKeyboard equ 0xAD -KbdControllerEnableKeyboard equ 0xAE -KbdControllerReadCtrlOutputPort equ 0xD0 -KbdControllerWriteCtrlOutputPort equ 0xD1 - -ScreenBuffer equ 0xB8000 - -g_GDT: ; NULL descriptor - dq 0 - - ; 32-bit code segment - dw 0FFFFh ; limit (bits 0-15) = 0xFFFFF for full 32-bit range - dw 0 ; base (bits 0-15) = 0x0 - db 0 ; base (bits 16-23) - db 10011010b ; access (present, ring 0, code segment, executable, direction 0, readable) - db 11001111b ; granularity (4k pages, 32-bit pmode) + limit (bits 16-19) - db 0 ; base high - - ; 32-bit data segment - dw 0FFFFh ; limit (bits 0-15) = 0xFFFFF for full 32-bit range - dw 0 ; base (bits 0-15) = 0x0 - db 0 ; base (bits 16-23) - db 10010010b ; access (present, ring 0, data segment, executable, direction 0, writable) - db 11001111b ; granularity (4k pages, 32-bit pmode) + limit (bits 16-19) - db 0 ; base high - - ; 16-bit code segment - dw 0FFFFh ; limit (bits 0-15) = 0xFFFFF - dw 0 ; base (bits 0-15) = 0x0 - db 0 ; base (bits 16-23) - db 10011010b ; access (present, ring 0, code segment, executable, direction 0, readable) - db 00001111b ; granularity (1b pages, 16-bit pmode) + limit (bits 16-19) - db 0 ; base high - - ; 16-bit data segment - dw 0FFFFh ; limit (bits 0-15) = 0xFFFFF - dw 0 ; base (bits 0-15) = 0x0 - db 0 ; base (bits 16-23) - db 10010010b ; access (present, ring 0, data segment, executable, direction 0, writable) - db 00001111b ; granularity (1b pages, 16-bit pmode) + limit (bits 16-19) - db 0 ; base high - -g_GDTDesc: dw g_GDTDesc - g_GDT - 1 ; limit = size of GDT - dd g_GDT ; address of GDT - -g_BootDrive: db 0 diff --git a/src/bootloader/stage2/fat.c b/src/bootloader/stage2/fat.c deleted file mode 100644 index 3a8916a..0000000 --- a/src/bootloader/stage2/fat.c +++ /dev/null @@ -1,377 +0,0 @@ -/*----------------*\ -|Nanite OS | -|Copyright (C) 2024| -|Tyler McGurrin | -\*----------------*/ -#include "fat.h" -#include "stdio.h" -#include "memdefs.h" -#include "string.h" -#include "memory.h" -#include "ctype.h" -#include -#include "minmax.h" - -#define SECTOR_SIZE 512 -#define MAX_PATH_SIZE 256 -#define MAX_FILE_HANDLES 10 -#define ROOT_DIRECTORY_HANDLE -1 - -typedef struct -{ - uint8_t BootJumpInstruction[3]; - uint8_t OemIdentifier[8]; - uint16_t BytesPerSector; - uint8_t SectorsPerCluster; - uint16_t ReservedSectors; - uint8_t FatCount; - uint16_t DirEntryCount; - uint16_t TotalSectors; - uint8_t MediaDescriptorType; - uint16_t SectorsPerFat; - uint16_t SectorsPerTrack; - uint16_t Heads; - uint32_t HiddenSectors; - uint32_t LargeSectorCount; - - // extended boot record - uint8_t DriveNumber; - uint8_t _Reserved; - uint8_t Signature; - uint32_t VolumeId; // serial number, value doesn't matter - uint8_t VolumeLabel[11]; // 11 bytes, padded with spaces - uint8_t SystemId[8]; - - // ... we don't care about code ... huh? - -} __attribute__((packed)) FAT_BootSector; - - -typedef struct -{ - uint8_t Buffer[SECTOR_SIZE]; - FAT_File Public; - bool Opened; - uint32_t FirstCluster; - uint32_t CurrentCluster; - uint32_t CurrentSectorInCluster; - -} FAT_FileData; - -typedef struct -{ - union - { - FAT_BootSector BootSector; - uint8_t BootSectorBytes[SECTOR_SIZE]; - } BS; - - FAT_FileData RootDirectory; - - FAT_FileData OpenedFiles[MAX_FILE_HANDLES]; - -} FAT_Data; - -static FAT_Data* g_Data; -static uint8_t* g_Fat = NULL; -static uint32_t g_DataSectionLba; - - -bool FAT_ReadBootSector(DISK* disk) -{ - return DISK_ReadSectors(disk, 0, 1, g_Data->BS.BootSectorBytes); -} - -bool FAT_ReadFat(DISK* disk) -{ - return DISK_ReadSectors(disk, g_Data->BS.BootSector.ReservedSectors, g_Data->BS.BootSector.SectorsPerFat, g_Fat); -} - -bool FAT_Initialize(DISK* disk) -{ - g_Data = (FAT_Data*)MEMORY_FAT_ADDR; - - // read boot sector - if (!FAT_ReadBootSector(disk)) - { - printf("FAT: read boot sector failed\r\n"); - return false; - } - - // read FAT - g_Fat = (uint8_t*)g_Data + sizeof(FAT_Data); - uint32_t fatSize = g_Data->BS.BootSector.BytesPerSector * g_Data->BS.BootSector.SectorsPerFat; - if (sizeof(FAT_Data) + fatSize >= MEMORY_FAT_SIZE) - { - printf("FAT: not enough memory to read FAT! Required %lu, only have %u\r\n", sizeof(FAT_Data) + fatSize, MEMORY_FAT_SIZE); - return false; - } - - if (!FAT_ReadFat(disk)) - { - printf("FAT: read FAT failed\r\n"); - return false; - } - - // open root directory file - uint32_t rootDirLba = g_Data->BS.BootSector.ReservedSectors + g_Data->BS.BootSector.SectorsPerFat * g_Data->BS.BootSector.FatCount; - uint32_t rootDirSize = sizeof(FAT_DirectoryEntry) * g_Data->BS.BootSector.DirEntryCount; - - g_Data->RootDirectory.Public.Handle = ROOT_DIRECTORY_HANDLE; - g_Data->RootDirectory.Public.IsDirectory = true; - g_Data->RootDirectory.Public.Position = 0; - g_Data->RootDirectory.Public.Size = sizeof(FAT_DirectoryEntry) * g_Data->BS.BootSector.DirEntryCount; - g_Data->RootDirectory.Opened = true; - g_Data->RootDirectory.FirstCluster = rootDirLba; - g_Data->RootDirectory.CurrentCluster = rootDirLba; - g_Data->RootDirectory.CurrentSectorInCluster = 0; - - if (!DISK_ReadSectors(disk, rootDirLba, 1, g_Data->RootDirectory.Buffer)) - { - printf("FAT: read root directory failed\r\n"); - return false; - } - - // calculate data section - uint32_t rootDirSectors = (rootDirSize + g_Data->BS.BootSector.BytesPerSector - 1) / g_Data->BS.BootSector.BytesPerSector; - g_DataSectionLba = rootDirLba + rootDirSectors; - - // reset opened files - for (int i = 0; i < MAX_FILE_HANDLES; i++) - g_Data->OpenedFiles[i].Opened = false; - - return true; -} - -uint32_t FAT_ClusterToLba(uint32_t cluster) -{ - return g_DataSectionLba + (cluster - 2) * g_Data->BS.BootSector.SectorsPerCluster; -} - -FAT_File* FAT_OpenEntry(DISK* disk, FAT_DirectoryEntry* entry) -{ - // find empty handle - int handle = -1; - for (int i = 0; i < MAX_FILE_HANDLES && handle < 0; i++) - { - if (!g_Data->OpenedFiles[i].Opened) - handle = i; - } - - // out of handles - if (handle < 0) - { - printf("FAT: out of file handles\r\n"); - return false; - } - - // setup vars - FAT_FileData* fd = &g_Data->OpenedFiles[handle]; - fd->Public.Handle = handle; - fd->Public.IsDirectory = (entry->Attributes & FAT_ATTRIBUTE_DIRECTORY) != 0; - fd->Public.Position = 0; - fd->Public.Size = entry->Size; - fd->FirstCluster = entry->FirstClusterLow + ((uint32_t)entry->FirstClusterHigh << 16); - fd->CurrentCluster = fd->FirstCluster; - fd->CurrentSectorInCluster = 0; - - if (!DISK_ReadSectors(disk, FAT_ClusterToLba(fd->CurrentCluster), 1, fd->Buffer)) - { - printf("FAT: open entry failed - read error cluster=%u lba=%u\n", fd->CurrentCluster, FAT_ClusterToLba(fd->CurrentCluster)); - for (int i = 0; i < 11; i++) - printf("%c", entry->Name[i]); - printf("\n"); - return false; - } - - fd->Opened = true; - return &fd->Public; -} - -uint32_t FAT_NextCluster(uint32_t currentCluster) -{ - uint32_t fatIndex = currentCluster * 3 / 2; - - if (currentCluster % 2 == 0) - return (*(uint16_t*)(g_Fat + fatIndex)) & 0x0FFF; - else - return (*(uint16_t*)(g_Fat + fatIndex)) >> 4; -} - -uint32_t FAT_Read(DISK* disk, FAT_File* file, uint32_t byteCount, void* dataOut) -{ - // get file data - FAT_FileData* fd = (file->Handle == ROOT_DIRECTORY_HANDLE) - ? &g_Data->RootDirectory - : &g_Data->OpenedFiles[file->Handle]; - - uint8_t* u8DataOut = (uint8_t*)dataOut; - - // don't read past the end of the file - if (!fd->Public.IsDirectory || (fd->Public.IsDirectory && fd->Public.Size != 0)) - byteCount = min(byteCount, fd->Public.Size - fd->Public.Position); - - while (byteCount > 0) - { - uint32_t leftInBuffer = SECTOR_SIZE - (fd->Public.Position % SECTOR_SIZE); - uint32_t take = min(byteCount, leftInBuffer); - - memcpy(u8DataOut, fd->Buffer + fd->Public.Position % SECTOR_SIZE, take); - u8DataOut += take; - fd->Public.Position += take; - byteCount -= take; - - // printf("leftInBuffer=%lu take=%lu\r\n", leftInBuffer, take); - // See if we need to read more data - if (leftInBuffer == take) - { - // Special handling for root directory - if (fd->Public.Handle == ROOT_DIRECTORY_HANDLE) - { - ++fd->CurrentCluster; - - // read next sector - if (!DISK_ReadSectors(disk, fd->CurrentCluster, 1, fd->Buffer)) - { - printf("FAT: read error!\r\n"); - break; - } - } - else - { - // calculate next cluster & sector to read - if (++fd->CurrentSectorInCluster >= g_Data->BS.BootSector.SectorsPerCluster) - { - fd->CurrentSectorInCluster = 0; - fd->CurrentCluster = FAT_NextCluster(fd->CurrentCluster); - } - - if (fd->CurrentCluster >= 0xFF8) - { - // Mark end of file - fd->Public.Size = fd->Public.Position; - break; - } - - // read next sector - if (!DISK_ReadSectors(disk, FAT_ClusterToLba(fd->CurrentCluster) + fd->CurrentSectorInCluster, 1, fd->Buffer)) - { - printf("FAT: read error!\r\n"); - break; - } - } - } - } - - return u8DataOut - (uint8_t*)dataOut; -} - -bool FAT_ReadEntry(DISK* disk, FAT_File* file, FAT_DirectoryEntry* dirEntry) -{ - return FAT_Read(disk, file, sizeof(FAT_DirectoryEntry), dirEntry) == sizeof(FAT_DirectoryEntry); -} - -void FAT_Close(FAT_File* file) -{ - if (file->Handle == ROOT_DIRECTORY_HANDLE) - { - file->Position = 0; - g_Data->RootDirectory.CurrentCluster = g_Data->RootDirectory.FirstCluster; - } - else - { - g_Data->OpenedFiles[file->Handle].Opened = false; - } -} - -bool FAT_FindFile(DISK* disk, FAT_File* file, const char* name, FAT_DirectoryEntry* entryOut) -{ - char fatName[12]; - FAT_DirectoryEntry entry; - - // convert from name to fat name - memset(fatName, ' ', sizeof(fatName)); - fatName[11] = '\0'; - - const char* ext = strchr(name, '.'); - if (ext == NULL) - ext = name + 11; - - for (int i = 0; i < 8 && name[i] && name + i < ext; i++) - fatName[i] = toupper(name[i]); - - if (ext != name + 11) - { - for (int i = 0; i < 3 && ext[i + 1]; i++) - fatName[i + 8] = toupper(ext[i + 1]); - } - - while (FAT_ReadEntry(disk, file, &entry)) - { - if (memcmp(fatName, entry.Name, 11) == 0) - { - *entryOut = entry; - return true; - } - } - - return false; -} - -FAT_File* FAT_Open(DISK* disk, const char* path) -{ - char name[MAX_PATH_SIZE]; - - // ignore leading slash - if (path[0] == '/') - path++; - - FAT_File* current = &g_Data->RootDirectory.Public; - - while (*path) { - // extract next file name from path - bool isLast = false; - const char* delim = strchr(path, '/'); - printf("DELIM: %s\r\n", delim); - if (delim != NULL) - { - memcpy(name, path, delim - path); - name[delim - path + 1] = '\0'; - path = delim + 1; - } - else - { - unsigned len = strlen(path); - memcpy(name, path, len); - name[len + 1] = '\0'; - path += len; - isLast = true; - } - - // find directory entry in current directory - FAT_DirectoryEntry entry; - if (FAT_FindFile(disk, current, name, &entry)) - { - FAT_Close(current); - - // check if directory - if (!isLast && entry.Attributes & FAT_ATTRIBUTE_DIRECTORY == 0) - { - printf("FAT: %s not a directory\r\n", name); - return NULL; - } - - // open new directory entry - current = FAT_OpenEntry(disk, &entry); - } - else - { - FAT_Close(current); - - printf("FAT: %s not found\r\n", name); - return NULL; - } - } - - return current; -} \ No newline at end of file diff --git a/src/bootloader/stage2/fat.h b/src/bootloader/stage2/fat.h deleted file mode 100644 index f8a8c1c..0000000 --- a/src/bootloader/stage2/fat.h +++ /dev/null @@ -1,50 +0,0 @@ -/*----------------*\ -|Nanite OS | -|Copyright (C) 2024| -|Tyler McGurrin | -\*----------------*/ -#pragma once -#include -#include "disk.h" - -typedef struct -{ - uint8_t Name[11]; - uint8_t Attributes; - uint8_t _Reserved; - uint8_t CreatedTimeTenths; - uint16_t CreatedTime; - uint16_t CreatedDate; - uint16_t AccessedDate; - uint16_t FirstClusterHigh; - uint16_t ModifiedTime; - uint16_t ModifiedDate; - uint16_t FirstClusterLow; - uint32_t Size; - -} __attribute__((packed)) FAT_DirectoryEntry; - - -typedef struct { - int Handle; - bool IsDirectory; - uint32_t Position; - uint32_t Size; -} FAT_File; - -enum FAT_Attributes { - FAT_ATTRIBUTE_READ_ONLY = 0x01, - FAT_ATTRIBUTE_HIDDEN = 0x02, - FAT_ATTRIBUTE_SYSTEM = 0x04, - FAT_ATTRIBUTE_VOLUME_ID = 0x08, - FAT_ATTRIBUTE_DIRECTORY = 0x10, - FAT_ATTRIBUTE_ARCHIVE = 0x20, - FAT_ATTRIBUTE_LFN = FAT_ATTRIBUTE_READ_ONLY | FAT_ATTRIBUTE_HIDDEN | FAT_ATTRIBUTE_SYSTEM | FAT_ATTRIBUTE_VOLUME_ID -}; - - -bool FAT_Initialize(DISK* disk); -FAT_File* FAT_Open(DISK* disk, const char* path); -uint32_t FAT_Read(DISK* disk, FAT_File* file, uint32_t byteCount, void* dataOut); -bool FAT_ReadEntry(DISK* disk, FAT_File* file, FAT_DirectoryEntry* dirEntry); -void FAT_Close(FAT_File* file); \ No newline at end of file diff --git a/src/bootloader/stage2/linker.ld b/src/bootloader/stage2/linker.ld deleted file mode 100644 index 786ccbb..0000000 --- a/src/bootloader/stage2/linker.ld +++ /dev/null @@ -1,15 +0,0 @@ -ENTRY(entry) -OUTPUT_FORMAT("binary") -phys = 0x00000500; - -SECTIONS { - . = phys; - - .entry : { __entry_start = .; *(.entry) } - .text : { __text_start = .; *(.text) } - .data : { __data_start = .; *(.data) } - .rodata : { __rodata_start = .; *(.rodata) } - .bss : { __bss_start = .; *(.bss) } - - __end = .; -} \ No newline at end of file diff --git a/src/bootloader/stage2/main.c b/src/bootloader/stage2/main.c deleted file mode 100644 index 1b6b4a7..0000000 --- a/src/bootloader/stage2/main.c +++ /dev/null @@ -1,135 +0,0 @@ -/*----------------*\ -|Nanite OS | -|Copyright (C) 2024| -|Tyler McGurrin | -\*----------------*/ -#include -#include -#include "stdio.h" -#include "x86.h" -#include "disk.h" -#include "fat.h" -#include "string.h" -#include "memdefs.h" -#include "memory.h" -#include "memdetect.h" -#include "../../libs/version.h" -#include "../../libs/boot/bootparams.h" - - - -uint8_t* KernelLoadBuffer = (uint8_t*)MEMORY_LOAD_KERNEL; -uint8_t* Kernel = (uint8_t*)MEMORY_KERNEL_ADDR; -BootParams g_BootParams; - - -typedef void (*KernelStart)(BootParams* bootParams); - -void* g_data = (void*)0x20000; - - void puts_realmode(const char* str) { - while (*str) { - x86_realmode_putc(*str); - ++str; - } - } - - void __attribute__((cdecl)) start(uint16_t bootDrive) { - // Clear screen and Print Startup logo - clrscr(); - printf("%s", BOOTLOGO); - printf("The Nano Loader %s\n------------------------------\n", VERSION); - - // Test Real Mode - printf("Testing Real Mode..."); - puts_realmode(" "); - printf("Ok!\n"); - - // get drive params (Test for Disk driver) - printf("Getting Drive Params..."); - uint8_t driveType; - uint16_t cyls, sects, heads; - x86_Disk_GetDriveParams(bootDrive, &driveType, &cyls, §s, &heads); - printf("Done!\n"); - printf("> Drive Type: %u\n> Cylinders: %u\n> Sectors: %u\n> Heads: %u\n", driveType, cyls, sects, heads); - - // init disk - printf("Initializing Disk..."); - DISK disk; - if (!DISK_Initialize(&disk, bootDrive)) { - printf("Failed!\nDisk Initialization Error!\n"); - goto end; - } - printf("Done!\n"); - DISK_ReadSectors(&disk, 0, 1, g_data); - // print_buffer("> Boot Sector Data: ", g_data, 512); - - printf("Initializing FAT Driver..."); - if (!FAT_Initialize(&disk)) { - printf("Failed!\nDisk Initialization Error!\n"); - goto end; - } - printf("Done!\n"); - - // test fat driver - printf("Testing FAT Driver..."); - // read test.txt - FAT_File* ft = FAT_Open(&disk, "/test.x"); - char buffer[100]; - uint32_t testread; - while ((testread = FAT_Read(&disk, ft, sizeof(buffer), buffer))) - { - for (uint32_t i = 0; i < testread; i++) - { - if (buffer[i] == '\n') - putc('\r'); - putc(buffer[i]); - } - } - FAT_Close(ft); - - printf("Detecting Memory..."); - // prep boot params - g_BootParams.BootDevice = bootDrive; - Memory_Detect(&g_BootParams.Memory); - printf("Done!\n"); - // kernel params... - FAT_File* kp = FAT_Open(&disk, "/kparams.x"); - char* kparams; - uint32_t kernelparams; - char* buffer2[100]; - while ((kernelparams = FAT_Read(&disk, kp, sizeof(buffer2), buffer2))) - { - for (uint32_t i = 0; i < kernelparams; i++) - { - strcpy(kparams, buffer2[i]); - } - } - FAT_Close(kp); - printf("Kernel Params: %s\n", kparams); - g_BootParams.KernelParams = kparams; - - // load kernel from disk - printf("Loading Kernel..."); - FAT_File* fd = FAT_Open(&disk, "/kernel.bin"); // move to /boot later????? (TM) - uint32_t read; - uint8_t* kernelBuffer = Kernel; - while ((read = FAT_Read(&disk, fd, MEMORY_LOAD_SIZE, KernelLoadBuffer))) - { - memcpy(kernelBuffer, KernelLoadBuffer, read); - kernelBuffer += read; - } - FAT_Close(fd); - - // execute kernel - KernelStart kernelStart = (KernelStart)Kernel; - kernelStart(&g_BootParams); - - - - -end: - for (;;); -} - - diff --git a/src/bootloader/stage2/memdefs.h b/src/bootloader/stage2/memdefs.h deleted file mode 100644 index ed3820e..0000000 --- a/src/bootloader/stage2/memdefs.h +++ /dev/null @@ -1,29 +0,0 @@ -/*----------------*\ -|Nanite OS | -|Copyright (C) 2024| -|Tyler McGurrin | -\*----------------*/ -#pragma once - -// 0x00000000 - 0x000003FF - interrupt vector table -// 0x00000400 - 0x000004FF - BIOS data area - -#define MEMORY_MIN 0x00000500 -#define MEMORY_MAX 0x00080000 - -// 0x00000500 - 0x00010500 - FAT driver -#define MEMORY_FAT_ADDR ((void*)0x20000) -#define MEMORY_FAT_SIZE 0x00010000 - -#define MEMORY_LOAD_KERNEL ((void*)0x30000) -#define MEMORY_LOAD_SIZE 0x00010000 - -// 0x00020000 - 0x00030000 - stage2 - -// 0x00030000 - 0x00080000 - free - -// 0x00080000 - 0x0009FFFF - Extended BIOS data area -// 0x000A0000 - 0x000C7FFF - Video -// 0x000C8000 - 0x000FFFFF - BIOS - -#define MEMORY_KERNEL_ADDR ((void*)0x100000) \ No newline at end of file diff --git a/src/bootloader/stage2/memdetect.c b/src/bootloader/stage2/memdetect.c deleted file mode 100644 index ffc9f47..0000000 --- a/src/bootloader/stage2/memdetect.c +++ /dev/null @@ -1,40 +0,0 @@ -/*----------------*\ -|Nanite OS | -|Copyright (C) 2025| -|Tyler McGurrin | -\*----------------*/ -#include "x86.h" -#include "stdio.h" -#include "../../libs/boot/bootparams.h" - -#define MAX_REGIONS 256 - -MemoryRegion g_MemRegions[MAX_REGIONS]; -int g_MemRegionCount; - -void Memory_Detect(MemoryInfo* memoryInfo) -{ - E820MemoryBlock block; - uint32_t continuation = 0; - int ret; - - g_MemRegionCount = 0; - ret = x86_E820GetNextBlock(&block, &continuation); - - while (ret > 0 && continuation != 0) - { - g_MemRegions[g_MemRegionCount].Begin = block.Base; - g_MemRegions[g_MemRegionCount].Length = block.Length; - g_MemRegions[g_MemRegionCount].Type = block.Type; - g_MemRegions[g_MemRegionCount].ACPI = block.ACPI; - ++g_MemRegionCount; - - // printf("E820: base=0x%llx length=0x%llx type=0x%x\n", block.Base, block.Length, block.Type); - // MAKE IT SHUT THE FUCK UP - ret = x86_E820GetNextBlock(&block, &continuation); - } - - // fill meminfo structure - memoryInfo->RegionCount = g_MemRegionCount; - memoryInfo->Regions = g_MemRegions; -} \ No newline at end of file diff --git a/src/bootloader/stage2/memdetect.h b/src/bootloader/stage2/memdetect.h deleted file mode 100644 index b14298b..0000000 --- a/src/bootloader/stage2/memdetect.h +++ /dev/null @@ -1,10 +0,0 @@ -/*----------------*\ -|Nanite OS | -|Copyright (C) 2024| -|Tyler McGurrin | -\*----------------*/ -#pragma once - -#include "../../libs/boot/bootparams.h" - -void Memory_Detect(MemoryInfo* memoryInfo); \ No newline at end of file diff --git a/src/bootloader/stage2/memory.c b/src/bootloader/stage2/memory.c deleted file mode 100644 index 439f7cf..0000000 --- a/src/bootloader/stage2/memory.c +++ /dev/null @@ -1,36 +0,0 @@ -/*----------------*\ -|Nanite OS | -|Copyright (C) 2024| -|Tyler McGurrin | -\*----------------*/ -#include "memory.h" - -void* memcpy(void* dst, const void* src, uint16_t num) { - uint8_t* u8Dst = (uint8_t *)dst; - const uint8_t* u8Src = (const uint8_t *)src; - - for (uint16_t i = 0; i < num; i++) - u8Dst[i] = u8Src[i]; - - return dst; -} - -void* memset (void * ptr, int value, uint16_t num) { - uint8_t* u8Ptr = (uint8_t *)ptr; - - for (uint16_t i = 0; i < num; i++) - u8Ptr[i] = (uint8_t)value; - - return ptr; -} - -int memcmp(const void* ptr1, const void * ptr2, uint16_t num) { - const uint8_t* u8Ptr1 = (const uint8_t *)ptr1; - const uint8_t* u8Ptr2 = (const uint8_t *)ptr2; - - for (uint16_t i = 0; i < num; i++) - if (u8Ptr1[i] != u8Ptr2[i]) - return 1; - - return 0; -} diff --git a/src/bootloader/stage2/memory.h b/src/bootloader/stage2/memory.h deleted file mode 100644 index d3b16ba..0000000 --- a/src/bootloader/stage2/memory.h +++ /dev/null @@ -1,11 +0,0 @@ -/*----------------*\ -|Nanite OS | -|Copyright (C) 2024| -|Tyler McGurrin | -\*----------------*/ -#pragma once -#include - -void* memcpy(void* dst, const void* src, uint16_t num); -void* memset(void* ptr, int value, uint16_t num); -int memcmp(const void* ptr1, const void * ptr2, uint16_t num); diff --git a/src/bootloader/stage2/minmax.h b/src/bootloader/stage2/minmax.h deleted file mode 100644 index 74fcfec..0000000 --- a/src/bootloader/stage2/minmax.h +++ /dev/null @@ -1,9 +0,0 @@ -/*----------------*\ -|Nanite OS | -|Copyright (C) 2024| -|Tyler McGurrin | -\*----------------*/ -#pragma once - -#define min(a,b) ((a) < (b) ? (a) : (b)) -#define max(a,b) ((a) > (b) ? (a) : (b)) diff --git a/src/bootloader/stage2/stdio.c b/src/bootloader/stage2/stdio.c deleted file mode 100644 index 50b12bd..0000000 --- a/src/bootloader/stage2/stdio.c +++ /dev/null @@ -1,318 +0,0 @@ -/*----------------*\ -|Nanite OS | -|Copyright (C) 2024| -|Tyler McGurrin | -\*----------------*/ -#include "stdio.h" -#include "x86.h" -#include -#include - -const unsigned SCREEN_WIDTH = 80; -const unsigned SCREEN_HEIGHT = 25; -const uint8_t DEFAULT_COLOUR = 0x7; - -uint8_t* g_ScreenBuffer = (uint8_t*)0xB8000; -int g_ScreenX = 0, g_ScreenY = 0; - -void putchr(int x, int y, char c) -{ - g_ScreenBuffer[2 * (y * SCREEN_WIDTH + x)] = c; -} - -void putcolour(int x, int y, uint8_t colour) -{ - g_ScreenBuffer[2 * (y * SCREEN_WIDTH + x) + 1] = colour; -} - -char getchr(int x, int y) -{ - return g_ScreenBuffer[2 * (y * SCREEN_WIDTH + x)]; -} - -uint8_t getcolour(int x, int y) -{ - return g_ScreenBuffer[2 * (y * SCREEN_WIDTH + x) + 1]; -} - -void setcursor(int x, int y) -{ - int pos = y * SCREEN_WIDTH + x; - - x86_outb(0x3D4, 0x0F); - x86_outb(0x3D5, (uint8_t)(pos & 0xFF)); - x86_outb(0x3D4, 0x0E); - x86_outb(0x3D5, (uint8_t)((pos >> 8) & 0xFF)); -} - -void clrscr() -{ - for (int y = 0; y < SCREEN_HEIGHT; y++) - for (int x = 0; x < SCREEN_WIDTH; x++) - { - putchr(x, y, '\0'); - putcolour(x, y, DEFAULT_COLOUR); - } - g_ScreenX =0; g_ScreenY = 0; - setcursor(g_ScreenX, g_ScreenY); -} - -void scrollback(int lines) -{ - for (int y = lines; y < SCREEN_HEIGHT; y++) - for (int x = 0; x < SCREEN_WIDTH; x++) - { - putchr(x, y - lines, getchr(x, y)); - putcolour(x, y - lines, getcolour(x, y)); - } - - for (int y= SCREEN_HEIGHT - lines; y < SCREEN_HEIGHT; y++) - for (int x = 0; x < SCREEN_WIDTH; x++) - { - putchr(x, y - lines, getchr(x, y)); - putcolour(x, y - lines, getcolour(x, y)); - } - g_ScreenY -= lines; -} - -void putc(char c) -{ - switch (c) - { - case '\n': - g_ScreenX = 0; - g_ScreenY++; - break; - case '\t': - for (int i = 0; i < 4 - (g_ScreenX % 4); i++) - putc(' '); - break; - case '\r': - g_ScreenX = 0; - break; - default: - putchr(g_ScreenX, g_ScreenY, c); - g_ScreenX++; - break; - } - - if (g_ScreenX >= SCREEN_WIDTH) - { - g_ScreenY++; - g_ScreenX = 0; - } - if (g_ScreenY >= SCREEN_HEIGHT) - scrollback(1); - - setcursor(g_ScreenX, g_ScreenY); - -} - -void puts(const char* str) -{ - while(*str) - { - putc(*str); - str++; - } -} - -const char g_HexChars[] = "0123456789abcdef"; - - -void printf_unsigned(unsigned long long number, int radix) -{ - char buffer[32]; - int pos = 0; - - //number to ASCII conversion - do { - unsigned long long rem = number % radix; - number /= radix; - buffer[pos++] = g_HexChars[rem]; - } while (number > 0); - - //print number in reverse order - while (--pos >= 0) - putc(buffer[pos]); -} - -void printf_signed(long long number, int radix) -{ - if (number < 0) - { - putc('-'); - printf_unsigned(-number, radix); - } - else printf_unsigned(number, radix); - -} - - - -#define PRINTF_STATE_NORMAL 0 -#define PRINTF_STATE_LENGTH 1 -#define PRINTF_STATE_LENGTH_SHORT 2 -#define PRINTF_STATE_LENGTH_LONG 3 -#define PRINTF_STATE_SPEC 4 - -#define PRINTF_LENGTH_DEFAULT 0 -#define PRINTF_LENGTH_SHORT_SHORT 1 -#define PRINTF_LENGTH_SHORT 2 -#define PRINTF_LENGTH_LONG 3 -#define PRINTF_LENGTH_LONG_LONG 4 - -void printf(const char* fmt, ...) -{ - va_list args; - va_start(args, fmt); - - int state = PRINTF_STATE_NORMAL; - int length = PRINTF_LENGTH_DEFAULT; - int radix = 10; - bool sign = false; - bool number = false; - - while (*fmt) - { - switch (state) - { - case PRINTF_STATE_NORMAL: - switch (*fmt) - { - case '%': state = PRINTF_STATE_LENGTH; - break; - default: putc(*fmt); - break; - } - break; - - case PRINTF_STATE_LENGTH: - switch (*fmt) - { - case 'h': length = PRINTF_LENGTH_SHORT; - state = PRINTF_STATE_LENGTH_SHORT; - break; - case 'l': length = PRINTF_LENGTH_LONG; - state = PRINTF_STATE_LENGTH_LONG; - break; - default: goto PRINTF_STATE_SPEC_; - } - break; - - case PRINTF_STATE_LENGTH_SHORT: - if (*fmt == 'h') - { - length = PRINTF_LENGTH_SHORT_SHORT; - state = PRINTF_STATE_SPEC; - } - else goto PRINTF_STATE_SPEC_; - break; - - case PRINTF_STATE_LENGTH_LONG: - if (*fmt == 'l') - { - length = PRINTF_LENGTH_LONG_LONG; - state = PRINTF_STATE_SPEC; - } - else goto PRINTF_STATE_SPEC_; - break; - - case PRINTF_STATE_SPEC: - PRINTF_STATE_SPEC_: - switch (*fmt) - { - case 'c': putc((char)va_arg(args, int)); - break; - - case 's': - puts(va_arg(args, const char*)); - break; - - case '%': putc('%'); - break; - - case 'd': - case 'i': radix = 10; sign = true; number = true; - break; - - case 'u': radix = 10; sign = false; number = true; - break; - - case 'X': - case 'x': - case 'p': radix = 16; sign = false; number = true; - break; - - case 'o': radix = 8; sign = false; number = true; - break; - - // ignore invalid spec - default: break; - } - - if (number) - { - if (sign) - { - switch (length) - { - case PRINTF_LENGTH_SHORT_SHORT: - case PRINTF_LENGTH_SHORT: - case PRINTF_LENGTH_DEFAULT: printf_signed(va_arg(args, int), radix); - break; - - case PRINTF_LENGTH_LONG: printf_signed(va_arg(args, long), radix); - break; - - case PRINTF_LENGTH_LONG_LONG: printf_signed(va_arg(args, long long), radix); - break; - } - } - else - { - switch (length) - { - case PRINTF_LENGTH_SHORT_SHORT: - case PRINTF_LENGTH_SHORT: - case PRINTF_LENGTH_DEFAULT: printf_unsigned(va_arg(args, unsigned int), radix); - break; - - case PRINTF_LENGTH_LONG: printf_unsigned(va_arg(args, unsigned long), radix); - break; - - case PRINTF_LENGTH_LONG_LONG: printf_unsigned(va_arg(args, unsigned long long), radix); - break; - } - } - } - - // reset state - state = PRINTF_STATE_NORMAL; - length = PRINTF_LENGTH_DEFAULT; - radix = 10; - sign = false; - number = false; - break; - } - - fmt++; - } - - va_end(args); -} - - - -void print_buffer(const char* msg, const void* buffer, uint32_t count) -{ - const uint8_t* u8Buffer = (const uint8_t*)buffer; - - puts(msg); - for (uint16_t i = 0; i < count; i++) - { - putc(g_HexChars[u8Buffer[i] >> 4]); - putc(g_HexChars[u8Buffer[i] & 0xF]); - } - puts("\n"); -} diff --git a/src/bootloader/stage2/stdio.h b/src/bootloader/stage2/stdio.h deleted file mode 100644 index 10dcdb8..0000000 --- a/src/bootloader/stage2/stdio.h +++ /dev/null @@ -1,13 +0,0 @@ -/*----------------*\ -|Nanite OS | -|Copyright (C) 2024| -|Tyler McGurrin | -\*----------------*/ -#pragma once -#include - -void clrscr(); -void putc(char c); -void puts(const char* str); -void printf(const char* fmt, ...); -void print_buffer(const char* msg, const void* buffer, uint32_t count); diff --git a/src/bootloader/stage2/string.c b/src/bootloader/stage2/string.c deleted file mode 100644 index e5e89ac..0000000 --- a/src/bootloader/stage2/string.c +++ /dev/null @@ -1,50 +0,0 @@ -/*----------------*\ -|Nanite OS | -|Copyright (C) 2024| -|Tyler McGurrin | -\*----------------*/ -#include "string.h" -#include -#include - -const char* strchr(const char* str, char chr) { - if (str == NULL) - return NULL; - - while (*str) { - if (*str == chr) - return str; - - ++str; - } - - return NULL; -} - -char* strcpy(char* dst, const char* src) { - char* origDst = dst; - - if (dst == NULL) - return NULL; - - if (src == NULL) { - *dst = '\0'; - return dst; - } - while (*src) { - *dst = *src; - ++src; - ++dst; - } - - *dst = '\0'; - return origDst; -} - -unsigned strlen(const char* str) { - unsigned len = 0; - while (*str) { - ++len; ++str; - } - return len; -} diff --git a/src/bootloader/stage2/string.h b/src/bootloader/stage2/string.h deleted file mode 100644 index 4f36582..0000000 --- a/src/bootloader/stage2/string.h +++ /dev/null @@ -1,10 +0,0 @@ -/*----------------*\ -|Nanite OS | -|Copyright (C) 2024| -|Tyler McGurrin | -\*----------------*/ -#pragma once - -const char* strchr(const char* str, char chr); -char* strcpy(char* dst, const char* src); -unsigned strlen(const char* str); diff --git a/src/bootloader/stage2/x86.asm b/src/bootloader/stage2/x86.asm deleted file mode 100644 index 5a2a4d0..0000000 --- a/src/bootloader/stage2/x86.asm +++ /dev/null @@ -1,350 +0,0 @@ -;/////////////////////; -;Nanite OS ; -;COPYRIGHT (C) 2024 ; -;Tyler McGurrin ; -;/////////////////////; -%macro x86_EnterRealMode 0 - [bits 32] - jmp word 18h:.pmode16 ; 1 - jump to 16-bit protected mode segment - -.pmode16: - [bits 16] - ; 2 - disable protected mode bit in cr0 - mov eax, cr0 - and al, ~1 - mov cr0, eax - - ; 3 - jump to real mode - jmp word 00h:.rmode - -.rmode: - ; 4 - setup segments - mov ax, 0 - mov ds, ax - mov ss, ax - - ; 5 - enable interrupts - sti - -%endmacro - -%macro x86_EnterProtectedMode 0 - cli - ; set PMODE enable flag in CR0 - mov eax, CR0 - or al, 1 - mov cr0, eax - - ; far jmp into PMODE - jmp dword 08h:.pmode - -.pmode: - ; we are now in protected mode! - [bits 32] - - ; 6 - setup segment registers - mov ax, 0x10 - mov ds, ax - mov ss, ax - - -%endmacro - -; Convert linear ADDR to seg:offset addr -; Args: -; 1 - linear addr -; 2 - (OUT) target seg (ex. ES) -; 3 - target 32 bit reg to use (ex. EAX) -; 4 - target lower 16 bit half of 3 (ex. AX) - -%macro LinearToSegOffset 4 - - mov %3, %1 ;linear addr to EAX - shr %3, 4 - mov %2, %4 - mov %3, %1 ;linear addr to EAX - and %3, 0xF - -%endmacro - - -global x86_outb -x86_outb: - [bits 32] - mov dx, [esp + 4] - mov al, [esp + 8] - out dx, al - ret - -global x86_inb -x86_inb: - [bits 32] - mov dx, [esp + 4] - xor eax, eax - in al, dx - ret - -; -; bool _cdecl x86_Disk_GetDriveParams(uint8_t drive, -; uint8_t* driveTypeOut, -; uint16_t* cylindersOut, -; uint16_t* sectorsOut, -; uint16_t* headsOut); -; -global x86_Disk_GetDriveParams -x86_Disk_GetDriveParams: - [bits 32] - - ; make new call frame - push ebp ; save old call frame - mov ebp, esp ; initialize new call frame - - x86_EnterRealMode - - [bits 16] - - ; save regs - push es - push bx - push esi - push di - - ; call int13h - mov dl, [bp + 8] ; dl - disk drive - mov ah, 08h - mov di, 0 ; es:di - 0000:0000 - mov es, di - stc - int 13h - - ; out params - mov eax, 1 - sbb eax, 0 - - ; drive type from bl - LinearToSegOffset [bp + 12], es, esi, si - mov [es:si], bl - - ; cylinders - mov bl, ch ; cylinders - lower bits in ch - mov bh, cl ; cylinders - upper bits in cl (6-7) - shr bh, 6 - inc bx - - LinearToSegOffset [bp + 16], es, esi, si - mov [es:si], bx - - ; sectors - xor ch, ch ; sectors - lower 5 bits in cl - and cl, 3Fh - - LinearToSegOffset [bp + 20], es, esi, si - mov [es:si], cx - - ; heads - mov cl, dh ; heads - dh - inc cx - - LinearToSegOffset [bp + 24], es, esi, si - mov [es:si], cx - - ; restore regs - pop di - pop esi - pop bx - pop es - - ; return - - push eax - - x86_EnterProtectedMode - - [bits 32] - - pop eax - - ; restore old call frame - mov esp, ebp - pop ebp - ret - -global x86_Disk_Reset -x86_Disk_Reset: - - ; make new call frame - push ebp ; save old call frame - mov ebp, esp ; initialize new call frame - - x86_EnterRealMode - - mov ah, 0 - mov dl, [bp + 8] ; dl - drive - stc - int 13h - - mov eax, 1 - sbb eax, 0 ; 1 on success, 0 on fail - - push eax - - x86_EnterProtectedMode - - pop eax - - ; restore old call frame - mov esp, ebp - pop ebp - ret - -; -; bool _cdecl x86_Disk_Read(uint8_t drive, -; uint16_t cylinder, -; uint16_t sector, -; uint16_t head, -; uint8_t count, -; void far * dataOut); -; -global x86_Disk_Read -x86_Disk_Read: - - ; make new call frame - push ebp ; save old call frame - mov ebp, esp ; initialize new call frame - - x86_EnterRealMode - - ; save modified regs - push ebx - push es - - ; setup args - mov dl, [bp + 8] ; dl - drive - - mov ch, [bp + 12] ; ch - cylinder (lower 8 bits) - mov cl, [bp + 13] ; cl - cylinder to bits 6-7 - shl cl, 6 - - mov al, [bp + 16] ; cl - sector to bits 0-5 - and al, 3Fh - or cl, al - - mov dh, [bp + 20] ; dh - head - - mov al, [bp + 24] ; al - count - - LinearToSegOffset [bp + 28], es, ebx, bx - - ; call int13h - mov ah, 02h - stc - int 13h - - ; set return value - mov eax, 1 - sbb eax, 0 ; 1 on success, 0 on fail - - ; restore regs - pop es - pop ebx - - push eax - - x86_EnterProtectedMode - - pop eax - - ; restore old call frame - mov esp, ebp - pop ebp - ret - - -; Testing Function -global x86_realmode_putc -x86_realmode_putc: - ; setup stack frame - push ebp - mov ebp, esp - - x86_EnterRealMode - - mov al, [bp + 8] - mov ah, 0xe - int 10h - - x86_EnterProtectedMode - - mov esp, ebp - pop ebp - ret - -; -; int ASMCALL x86_E820GetNextBlock(E820MemoryBlock* block, uint32_t* continuationId); -; -E820Signature equ 0x534D4150 - -global x86_E820GetNextBlock -x86_E820GetNextBlock: - - ; make new call frame - push ebp ; save old call frame - mov ebp, esp ; initialize new call frame - - x86_EnterRealMode - - ; save modified regs - push ebx - push ecx - push edx - push esi - push edi - push ds - push es - - ; setup params - LinearToSegOffset [bp + 8], es, edi, di ; es:di pointer to structure - - LinearToSegOffset [bp + 12], ds, esi, si ; ebx - pointer to continuationId - mov ebx, ds:[si] - - mov eax, 0xE820 ; eax - function - mov edx, E820Signature ; edx - signature - mov ecx, 24 ; ecx - size of structure - - ; call interrupt - int 0x15 - - ; test results - cmp eax, E820Signature - jne .Error - - .IfSuccedeed: - mov eax, ecx ; return size - mov ds:[si], ebx ; fill continuation parameter - jmp .EndIf - - .Error: - mov eax, -1 - - .EndIf: - - ; restore regs - pop es - pop ds - pop edi - pop esi - pop edx - pop ecx - pop ebx - - push eax - - x86_EnterProtectedMode - - pop eax - - ; restore old call frame - mov esp, ebp - pop ebp - ret \ No newline at end of file diff --git a/src/bootloader/stage2/x86.h b/src/bootloader/stage2/x86.h deleted file mode 100644 index a36122c..0000000 --- a/src/bootloader/stage2/x86.h +++ /dev/null @@ -1,52 +0,0 @@ -/*----------------*\ -|Nanite OS | -|Copyright (C) 2024| -|Tyler McGurrin | -\*----------------*/ -#pragma once -#include -#include - -#define ASMCALL __attribute__((cdecl)) - - -void ASMCALL x86_outb(uint16_t port, uint8_t value); -uint8_t ASMCALL x86_inb(uint16_t port); - -void ASMCALL x86_realmode_putc(char c); - -bool ASMCALL x86_Disk_GetDriveParams(uint8_t drive, - uint8_t* driveTypeOut, - uint16_t* cylindersOut, - uint16_t* sectorsOut, - uint16_t* headsOut); - -bool ASMCALL x86_Disk_Reset(uint8_t drive); - -bool ASMCALL x86_Disk_Read(uint8_t drive, - uint16_t cylinder, - uint16_t sector, - uint16_t head, - uint8_t count, - void* lowerDataOut); - - -typedef struct -{ - uint64_t Base; - uint64_t Length; - uint32_t Type; - uint32_t ACPI; - -} E820MemoryBlock; - -enum E820MemoryBlockType { - - E820_USABLE = 1, - E820_RESERVED = 2, - E820_ACPI_RECLAIMABLE = 3, - E820_ACPI_NVS = 4, - E820_BAD_MEMORY = 5, -}; - -int ASMCALL x86_E820GetNextBlock(E820MemoryBlock* block, uint32_t* continuationId); \ No newline at end of file diff --git a/test b/test deleted file mode 100644 index e1786c8..0000000 --- a/test +++ /dev/null @@ -1 +0,0 @@ -Ok! diff --git a/tools/fat/fat.c b/tools/fat/fat.c deleted file mode 100644 index 1593035..0000000 --- a/tools/fat/fat.c +++ /dev/null @@ -1,183 +0,0 @@ -#include -#include -#include -#include -#include - -// typedef uint8_t bool; -#define true 1 -#define false 0 - -typedef struct -{ - uint8_t BootJumpInstruction[3]; - uint8_t OemIdentifier[8]; - uint16_t BytesPerSector; - uint8_t SectorsPerCluster; - uint16_t ReservedSectors; - uint8_t FatCount; - uint16_t DirEntryCount; - uint16_t TotalSectors; - uint8_t MediaDescriptorType; - uint16_t SectorsPerFat; - uint16_t SectorsPerTrack; - uint16_t Heads; - uint32_t HiddenSectors; - uint32_t LargeSectorCount; - -//Extended Boot Record - uint8_t DriveNumber; - uint8_t _Reserved; - uint8_t Signature; - uint32_t VolumeId; //Serial Can be whatever - uint8_t VolumeLabel[11]; //11 Bytes MUST Be padded with spaces! - uint8_t SystemId[8]; //8 Bytes padded with spaces (use MSWIN4.1 for best compatibility!) - -} __attribute__((packed)) BootSector; - -typedef struct -{ - uint8_t Name[11]; - uint8_t Attributes; - uint8_t _Reserved; - uint8_t CreatedTimeTenths; - uint16_t CreatedTime; - uint16_t CreatedDate; - uint16_t AccessedDate; - uint16_t FirstClusterHigh; - uint16_t ModifiedTime; - uint16_t ModifiedDate; - uint16_t FirstClusterLow; - uint32_t Size; - -} __attribute__((packed)) DirectoryEntry; - -BootSector g_BootSector; -uint8_t* g_Fat = NULL; -DirectoryEntry* g_RootDirectory = NULL; -uint32_t g_RootDirectoryEnd; - -bool readBootSector(FILE* disk) - { - return fread(&g_BootSector, sizeof(g_BootSector), 1, disk) > 0; - } - -bool readSectors(FILE* disk, uint32_t lba, uint32_t count, void* bufferout) -{ - bool ok = true; - ok = ok && (fseek(disk, lba * g_BootSector.BytesPerSector, SEEK_SET) == 0); - ok = ok && (fread(bufferout, g_BootSector.BytesPerSector, count, disk) == count); - return ok; -} - -bool readFat(FILE* disk) -{ - g_Fat = (uint8_t*) malloc(g_BootSector.SectorsPerFat * g_BootSector.BytesPerSector); - return readSectors(disk, g_BootSector.ReservedSectors, g_BootSector.SectorsPerFat, g_Fat); -} - -bool readRootDirectory(FILE* disk) -{ - uint32_t lba = g_BootSector.ReservedSectors + g_BootSector.SectorsPerFat * g_BootSector.FatCount; - uint32_t size = sizeof(DirectoryEntry) * g_BootSector.DirEntryCount; - uint32_t sector = (size / g_BootSector.BytesPerSector); - if (size % g_BootSector.BytesPerSector > 0) - sector++; - - g_RootDirectoryEnd = lba + sector; - g_RootDirectory = (DirectoryEntry*) malloc(sector * g_BootSector.BytesPerSector); - return readSectors(disk, lba, sector, g_RootDirectory); -} - -DirectoryEntry* findFile(const char* name) -{ - for (uint32_t i = 0; i < g_BootSector.DirEntryCount; i++) - { - if (memcmp(name, g_RootDirectory[i].Name, 11) == 0) - return &g_RootDirectory[i]; - - } - - return NULL; -} - -bool readFile(DirectoryEntry* fileEntry, FILE* disk, uint8_t* outputBuffer) -{ - bool ok = true; - uint16_t currentCluster = fileEntry->FirstClusterLow; - - do { - uint32_t lba = g_RootDirectoryEnd + (currentCluster - 2) * g_BootSector.SectorsPerCluster; - ok = ok && readSectors(disk, lba, g_BootSector.SectorsPerCluster, outputBuffer); - outputBuffer += g_BootSector.SectorsPerCluster * g_BootSector.BytesPerSector; - - uint32_t fatIndex = currentCluster * 3 / 2; - if (currentCluster % 2 == 0) - currentCluster = (*(uint16_t*)(g_Fat + fatIndex)) & 0x0FFF; - else - currentCluster = (*(uint16_t*)(g_Fat + fatIndex)) >> 4; - - } while (ok && currentCluster < 0x0FF8); - - return ok; -} - -int main(int argc, char** argv) -{ - if (argc < 3){ - printf("Syntax: %s \n", argv[0]); - return -1; - } - - FILE* disk = fopen(argv[1], "rb"); - if (!disk) { - fprintf(stderr, "Cannot open disk image %s!\n", argv[1]); - return -1; - } - - if (!readBootSector(disk)) { - fprintf(stderr, "Could not read boot sector!\n"); - return -2; - } - - if (!readFat(disk)) { - fprintf(stderr, "Could not read FAT!\n"); - free(g_Fat); - return -3; - } - - if (!readRootDirectory(disk)) { - fprintf(stderr, "Could not read root!\n"); - free(g_Fat); - free(g_RootDirectory); - return -4; - } - - DirectoryEntry* fileEntry = findFile(argv[2]); - if (!fileEntry) { - fprintf(stderr, "Could not locate file %s!\n", argv[2]); - free(g_Fat); - free(g_RootDirectory); - return -5; - } - - uint8_t* buffer = (uint8_t*) malloc(fileEntry->Size + g_BootSector.BytesPerSector); - if (!readFile(fileEntry, disk, buffer)) { - fprintf(stderr, "Could not read file %s!\n", argv[2]); - free(g_Fat); - free(g_RootDirectory); - free(buffer); - return -5; - } - - for (size_t i = 0; i < fileEntry->Size; i++) - { - if (isprint(buffer[i])) fputc(buffer[i], stdout); - //else printf("<%02x>", buffer[i]); - } - printf("\n"); - - free(g_Fat); - free(g_RootDirectory); - return 0; -}