From 803c22807316a3f9500262124452056bd89c31fc Mon Sep 17 00:00:00 2001 From: PKM74 <142884506+PKM74@users.noreply.github.com> Date: Wed, 9 Oct 2024 20:00:26 -0400 Subject: [PATCH] Initital Commit --- Makefile | 74 +++ bochs_config | 7 + build.sh | 52 ++ build/stage1.bin | Bin 0 -> 512 bytes build/stage2/asm/main.obj | Bin 0 -> 151 bytes build/stage2/asm/x86.obj | Bin 0 -> 240 bytes build/stage2/c/main.obj | Bin 0 -> 1887 bytes bx_enh_dbg.ini | 26 + debug.sh | 27 + readme.txt | 5 + src/bootloader/stage1/Makefile | 14 + src/bootloader/stage1/boot.asm | 383 ++++++++++++++ src/bootloader/stage2/Makefile | 33 ++ src/bootloader/stage2/disk.h | 19 + src/bootloader/stage2/linker.lnk | 12 + src/bootloader/stage2/main.asm | 28 + src/bootloader/stage2/main.c | 13 + src/bootloader/stage2/main.err | 1 + src/bootloader/stage2/stdint.h | 20 + src/bootloader/stage2/stdio.c | 222 ++++++++ src/bootloader/stage2/stdio.err | 5 + src/bootloader/stage2/stdio.h | 10 + src/bootloader/stage2/x86.asm | 102 ++++ src/bootloader/stage2/x86.h | 26 + src/kernel/Makefile | 14 + src/kernel/main.asm | 50 ++ src/micron/Makefile | 2 + src/micron/main | Bin 0 -> 33224 bytes src/micron/main.c | 232 +++++++++ src/micron/tinydir.h | 848 +++++++++++++++++++++++++++++++ tools/fat/fat.c | 183 +++++++ write.sh | 31 ++ 32 files changed, 2439 insertions(+) create mode 100644 Makefile create mode 100644 bochs_config create mode 100644 build.sh create mode 100644 build/stage1.bin create mode 100644 build/stage2/asm/main.obj create mode 100644 build/stage2/asm/x86.obj create mode 100644 build/stage2/c/main.obj create mode 100644 bx_enh_dbg.ini create mode 100644 debug.sh create mode 100644 readme.txt create mode 100644 src/bootloader/stage1/Makefile create mode 100644 src/bootloader/stage1/boot.asm create mode 100644 src/bootloader/stage2/Makefile create mode 100644 src/bootloader/stage2/disk.h create mode 100644 src/bootloader/stage2/linker.lnk create mode 100644 src/bootloader/stage2/main.asm create mode 100644 src/bootloader/stage2/main.c create mode 100644 src/bootloader/stage2/main.err create mode 100644 src/bootloader/stage2/stdint.h create mode 100644 src/bootloader/stage2/stdio.c create mode 100644 src/bootloader/stage2/stdio.err create mode 100644 src/bootloader/stage2/stdio.h create mode 100644 src/bootloader/stage2/x86.asm create mode 100644 src/bootloader/stage2/x86.h create mode 100644 src/kernel/Makefile create mode 100644 src/kernel/main.asm create mode 100644 src/micron/Makefile create mode 100644 src/micron/main create mode 100644 src/micron/main.c create mode 100644 src/micron/tinydir.h create mode 100644 tools/fat/fat.c create mode 100644 write.sh diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..3294603 --- /dev/null +++ b/Makefile @@ -0,0 +1,74 @@ +ASM=nasm +CC=gcc +CC16=/usr/bin/watcom/binl/wcc +LD16=/usr/bin/watcom/binl/wlink + +SRC_DIR=src +TOOLS_DIR=tools +BUILD_DIR=build + +.PHONY: all floppy_image kernel bootloader clean always tools_fat + +all: floppy_image tools_fat + +# +# Floppy image +# +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 + mcopy -i $(BUILD_DIR)/main_floppy.img $(BUILD_DIR)/stage2.bin "::stage2.bin" + mcopy -i $(BUILD_DIR)/main_floppy.img $(BUILD_DIR)/kernel.bin "::kernel.bin" + mcopy -i $(BUILD_DIR)/main_floppy.img readme.txt "::readme.txt" + +# +# Bootloader +# +# +bootloader: stage1 stage2 + +stage1: $(BUILD_DIR)/stage1.bin + +$(BUILD_DIR)/stage1.bin: always + $(MAKE) -C $(SRC_DIR)/bootloader/stage1 BUILD_DIR=$(abspath $(BUILD_DIR)) + +stage2: $(BUILD_DIR)/stage2.bin + +$(BUILD_DIR)/stage2.bin: always + $(MAKE) -C $(SRC_DIR)/bootloader/stage2 BUILD_DIR=$(abspath $(BUILD_DIR)) + + +# +# Kernel +# +kernel: $(BUILD_DIR)/kernel.bin + +$(BUILD_DIR)/kernel.bin: always + $(MAKE) -C $(SRC_DIR)/kernel BUILD_DIR=$(abspath $(BUILD_DIR)) + +# +# Tools +# +tools_fat: $(BUILD_DIR)/tools/fat +$(BUILD_DIR)/tools/fat: always $(TOOLS_DIR)/fat/fat.c + mkdir -p $(BUILD_DIR)/tools + $(CC) -g -o $(BUILD_DIR)/tools/fat $(TOOLS_DIR)/fat/fat.c + +# +# Always +# +always: + mkdir -p $(BUILD_DIR) + +# +# Clean +# +clean: + $(MAKE) -C $(SRC_DIR)/bootloader/stage1 BUILD_DIR=$(abspath $(BUILD_DIR)) clean + $(MAKE) -C $(SRC_DIR)/bootloader/stage2 BUILD_DIR=$(abspath $(BUILD_DIR)) clean + $(MAKE) -C $(SRC_DIR)/kernel BUILD_DIR=$(abspath $(BUILD_DIR)) clean + rm -rf $(BUILD_DIR)/* + rm -rf $(SRC_DIR)/bootloader/stage2/*.err diff --git a/bochs_config b/bochs_config new file mode 100644 index 0000000..58f1736 --- /dev/null +++ b/bochs_config @@ -0,0 +1,7 @@ +megs: 128 +romimage: file=/usr/share/bochs/BIOS-bochs-legacy, address=0xffff0000 +vgaromimage: file=/usr/share/bochs/VGABIOS-lgpl-latest +floppya: 1_44=build/main_floppy.img, status=inserted +boot: floppy +mouse: enabled=0 +display_library: x, options="gui_debug" diff --git a/build.sh b/build.sh new file mode 100644 index 0000000..0e17b5b --- /dev/null +++ b/build.sh @@ -0,0 +1,52 @@ +#!/bin/bash +echo -------- +echo STARTING +echo -------- +read -p "Do you want to clean old build files? (y/n) " yn + +case $yn in + y ) + + echo ---------------------------; + echo Removing Old Build Files...; + echo ---------------------------; + + sudo make clean; + echo -----; + echo Done!; + echo -----; + ;; + n ) + echo ---------; + echo Proceding; + echo ---------; + ;; +esac +echo ------------ +echo COMPILING OS +echo ------------ + +sudo make -s + +echo --------- +echo Finished! +echo --------- +read -p "Do you want to Start QEMU? (y/n) " yn + +case $yn in + y ) + echo ------------- + echo STARTING QEMU + echo ------------- + sudo qemu-system-i386 -fda build/main_floppy.img + echo -------- + echo Finshed! + echo -------- + + ;; + n ) echo exiting...; + exit;; + * ) echo invalid response; + exit 1;; +esac + diff --git a/build/stage1.bin b/build/stage1.bin new file mode 100644 index 0000000000000000000000000000000000000000..d57c15d29e119b50c053fd040396586b74c24856 GIT binary patch literal 512 zcmaEDJHaodvuJ*+T2DU96XNCEj&M>eyJhV4>+sP+U^Y2)P znN-a}v6?P9ff|GV-ybux@zn$@6s$S;fYtEQcQfvq)=MRf4jl(0x`4*)W~h5{hr#gn zeulbzA8U7VGlYL$7GJ{Cd|biVT28R0=GE)UZda+re`*)K0nG(!d$EFHH-kdo z;oS@j3;)zMACTY32o|2mz%0jI0~FfH%<%o;P9}!$ANMiTF&?w)X5qY4!g}xp%WG!U z|NOQ;_={PAhQ2-o(zOF<63~CIfI*?~TIko8eWz+)h%&t9*mtM)1uw&EhAj+d#ekCk z|Nr_D77)CK<3I_=7QXEaX9Zq=j*f^s91sNZmPCzH=S2`hs;1*w$I$~%*f<_WbR3E} z91t8B6dw5E#{Y;dO#7J`5`LZ)F6K^r!N=g=`oHw!>q&|6QIXLRhZD9i0A-4r6AuTM zBo>uq=A|q6CFW(8q$(Kb8R!`%>gnn6axpk3=9MS}r6#5*xMUV*E5bzFGV@Xtfcnx? X6^uZF!6As?F?3?%?pwom~8 literal 0 HcmV?d00001 diff --git a/build/stage2/c/main.obj b/build/stage2/c/main.obj new file mode 100644 index 0000000000000000000000000000000000000000..cea7dd36618219a8d76eed5b7474fb59bc78a24c GIT binary patch literal 1887 zcmbtU-EZ4e6hGIFW5-UKq$x$Cg1Kyb3MDjcqY5TQnrv;Qb(vZ>r2}Rqj++`KcCno@ zF@#E6qzrf%48njsEFgq{KY+a;ga~3n;tePWX+olts5J44gv83ZZbJ)?ouzy2bAIRi z&c{91%SYgm#DZ1T6K4%uv&=-+(rQ)Rbe+V>f@!#V!m+hP(X!l%RVe9p!f^{_J(;K$ z3^T6f>ntp{l)3=R?+rRRz4Uf{6qYxC^9|440_!vNERtj|CFhRpCpE_{8KxUwc(I;A zn#^0txkvX)W5pN#q$O?!8~p&jOfGxOmrW~ac6550RZdL%vtv`anNysq9D73f^b!yE z9|WEukva#D4??yPsp(&wE>vQ0~ zz<|^keJYk&#zJ@5JO%ILR2&C4H3Xcni*k^_Olia0TFZfGaYb!q;k>Ie+76^~_h@%^0-B9>T1J@=QBI zKYH@)M{mXeNC0C<5P%@y6v6@c>+&ESficT4%ksQ!RpqlIDLFkoDZ7@Oku|HN_lHE7 zz+ahBs2I=dB`VIeu&GO47k0YiATPIM871Ihjr@oZS;Z~DiU6Hz2oO{;uloTG;`>5> zo3_)<+QyQOYJq*@Ze|WGia$_KOb(wro43K$LwV9pDWpAu>ol&X6!LOQ1TKgM>u6hP z;q|8U1gRasp{n3)azw1oxUq#YR`c(d` z$$8E)hQ~4h?!YyCA&lkjo*E`kv!n3$=zosdVjF1Da4!lxMX2LY>p2jpP{qYS1a|^k zJ`wvwJLNq`*;~AoEWO$+mgVONE0BT1LrDKgGXU)~*Z@r-rPd2T(*q_-NQ@OC{#dwA zxJMWbXZ*vFm9(^)#!|V%zzUB^l7yq*3rUF;CUBnCNF05V(nRc`@Ntn9js|5ZCEXW1 yAq@o|6r-e@3`&n9d7E(P&WLMik-8Nn^r9$69mB&zQhX+{HzDr}xA9jnZ}%V4nb8mc literal 0 HcmV?d00001 diff --git a/bx_enh_dbg.ini b/bx_enh_dbg.ini new file mode 100644 index 0000000..e0cd532 --- /dev/null +++ b/bx_enh_dbg.ini @@ -0,0 +1,26 @@ +# bx_enh_dbg_ini +SeeReg[0] = TRUE +SeeReg[1] = TRUE +SeeReg[2] = TRUE +SeeReg[3] = TRUE +SeeReg[4] = FALSE +SeeReg[5] = FALSE +SeeReg[6] = FALSE +SeeReg[7] = FALSE +SingleCPU = FALSE +ShowIOWindows = TRUE +ShowButtons = TRUE +SeeRegColors = TRUE +ignoreNxtT = TRUE +ignSSDisasm = TRUE +UprCase = 0 +DumpInAsciiMode = 3 +isLittleEndian = TRUE +DefaultAsmLines = 512 +DumpWSIndex = 0 +DockOrder = 0x123 +ListWidthPix[0] = 179 +ListWidthPix[1] = 248 +ListWidthPix[2] = 283 +MainWindow = 0, 0, 714, 500 +FontName = Normal diff --git a/debug.sh b/debug.sh new file mode 100644 index 0000000..8963282 --- /dev/null +++ b/debug.sh @@ -0,0 +1,27 @@ +echo ------------ +echo COMPILING OS +echo ------------ + +sudo make + +echo --------- +echo Finished! +echo --------- +read -p "Do you want to Start Bochs? (Y/n) " yn + +case $yn in + y ) + echo ------------- + echo STARTING Bochs + echo ------------- + sudo bochs -f bochs_config + echo -------- + echo Finshed! + echo -------- + + ;; + n ) echo exiting...; + exit;; + * ) echo invalid response; + exit 1;; +esac diff --git a/readme.txt b/readme.txt new file mode 100644 index 0000000..4dbb2eb --- /dev/null +++ b/readme.txt @@ -0,0 +1,5 @@ +###LAMBDA OS README + +Test README + +OMG i love CHEESE diff --git a/src/bootloader/stage1/Makefile b/src/bootloader/stage1/Makefile new file mode 100644 index 0000000..2bf3755 --- /dev/null +++ b/src/bootloader/stage1/Makefile @@ -0,0 +1,14 @@ +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 new file mode 100644 index 0000000..b8e7726 --- /dev/null +++ b/src/bootloader/stage1/boot.asm @@ -0,0 +1,383 @@ +;/////////////////////; +;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 floppy_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 kernel.bin + xor bx, bx + mov di, buffer + +.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 stage2_not_found_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 handlers +; + +floppy_error: + mov si, msg_read_failed + call puts + jmp wait_key_and_reboot + +stage2_not_found_error: + mov si, msg_no_stage2 + 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 floppy_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 floppy_error + popa + ret + + +msg_loading: db 'Starting Nanite 0.0.1a...', ENDL, 0 +msg_read_failed: db 'Cant Read Disk!', ENDL, 0 +msg_no_stage2: db 'Cant Find Stage 2!', ENDL, 0 +file_stage2_bin: db 'STAGE2 BIN' +stage2_cluster: dw 0 + +STAGE2_LOAD_SEGMENT equ 0x2000 +STAGE2_LOAD_OFFSET equ 0 + +times 510-($-$$) db 0 +dw 0AA55h + +buffer: + diff --git a/src/bootloader/stage2/Makefile b/src/bootloader/stage2/Makefile new file mode 100644 index 0000000..191024a --- /dev/null +++ b/src/bootloader/stage2/Makefile @@ -0,0 +1,33 @@ +BUILD_DIR?=build/ +ASM?=nasm +ASMFLAGS?=-f obj +CC16?=/usr/bin/watcom/binl/wcc +CFLAGS16?=-4 -d3 -s -wx -ms -zl -zq # -oneatxzh +LD16?=/usr/bin/watcom/binl/wlink + +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)) + +.PHONY: all stage2 clean always + +all: stage2 + +stage2: $(BUILD_DIR)/stage2.bin + +$(BUILD_DIR)/stage2.bin: $(OBJECTS_ASM) $(OBJECTS_C) + $(LD16) NAME $(BUILD_DIR)/stage2.bin FILE \{ $(OBJECTS_ASM) $(OBJECTS_C) \} OPTION MAP=$(BUILD_DIR)/stage2.map @linker.lnk + +$(BUILD_DIR)/stage2/c/%.obj: %.c always + $(CC16) $(CFLAGS16) -fo=$@ $< + +$(BUILD_DIR)/stage2/asm/%.obj: %.asm always + $(ASM) $(ASMFLAGS) -o $@ $< + +always: + mkdir -p $(BUILD_DIR)/stage2/c + mkdir -p $(BUILD_DIR)/stage2/asm + +clean: + rm -f $(BUILD_DIR)/stage2.bin diff --git a/src/bootloader/stage2/disk.h b/src/bootloader/stage2/disk.h new file mode 100644 index 0000000..62faffe --- /dev/null +++ b/src/bootloader/stage2/disk.h @@ -0,0 +1,19 @@ +/*----------------*\ +|Nanite OS | +|Copyright (C) 2024| +|Tyler McGurrin | +\*----------------*/ +#pragma once + +#include "stdint.h" + +typedef struct { + uint8_t id; + uint16_t cylinders; + uint16_t sectors; + uint16_t heads; +}; + +bool DISK_Initialize(DISK* disk, uint8_t driveNumber); +bool DISK_ReadSectors(DISK* disk, uint32_t lba, uint8_t far* dataOut); + diff --git a/src/bootloader/stage2/linker.lnk b/src/bootloader/stage2/linker.lnk new file mode 100644 index 0000000..9e70033 --- /dev/null +++ b/src/bootloader/stage2/linker.lnk @@ -0,0 +1,12 @@ +FORMAT RAW BIN +OPTION QUIET, + NODEFAULTLIBS, + START=entry, + VERBOSE, + OFFSET=0, + STACK=0x200 +ORDER + CLNAME CODE + SEGMENT _ENTRY + SEGMENT _TEXT + CLNAME DATA diff --git a/src/bootloader/stage2/main.asm b/src/bootloader/stage2/main.asm new file mode 100644 index 0000000..8646753 --- /dev/null +++ b/src/bootloader/stage2/main.asm @@ -0,0 +1,28 @@ +;/////////////////////; +;Nanite OS ; +;COPYRIGHT (C) 2024 ; +;Tyler McGurrin ; +;/////////////////////; +bits 16 + +section _ENTRY class=CODE + +extern _cstart_ +global entry + +entry: + cli + ; setup stack + mov ax, ds + mov ss, ax + mov sp, 0 + mov bp, sp + sti + + ; expect boot drive in dl, send it as argument to cstart function + xor dh, dh + push dx + call _cstart_ + + cli + hlt diff --git a/src/bootloader/stage2/main.c b/src/bootloader/stage2/main.c new file mode 100644 index 0000000..f420738 --- /dev/null +++ b/src/bootloader/stage2/main.c @@ -0,0 +1,13 @@ +/*----------------*\ +|Nanite OS | +|Copyright (C) 2024| +|Tyler McGurrin | +\*----------------*/ +#include "stdint.h" +#include "stdio.h" + +void _cdecl cstart_(uint16_t bootDrive) +{ + puts("Going from x86 ASM to C code!\r\n"); + printf("Initialized!\r\n"); +} diff --git a/src/bootloader/stage2/main.err b/src/bootloader/stage2/main.err new file mode 100644 index 0000000..e39ad6c --- /dev/null +++ b/src/bootloader/stage2/main.err @@ -0,0 +1 @@ +main.c(9): Warning! W303: Parameter 'bootDrive' has been defined, but not referenced diff --git a/src/bootloader/stage2/stdint.h b/src/bootloader/stage2/stdint.h new file mode 100644 index 0000000..5b4266b --- /dev/null +++ b/src/bootloader/stage2/stdint.h @@ -0,0 +1,20 @@ +/*----------------*\ +|Nanite OS | +|Copyright (C) 2024| +|Tyler McGurrin | +\*----------------*/ +#pragma once + +typedef signed char int8_t; +typedef unsigned char uint8_t; +typedef signed short int16_t; +typedef unsigned short uint16_t; +typedef signed long int int32_t; +typedef unsigned long int uint32_t; +typedef signed long long int int64_t; +typedef unsigned long long int uint64_t; + +typedef uint8_t bool; + +#define true 1 +#define false 0 diff --git a/src/bootloader/stage2/stdio.c b/src/bootloader/stage2/stdio.c new file mode 100644 index 0000000..123e41c --- /dev/null +++ b/src/bootloader/stage2/stdio.c @@ -0,0 +1,222 @@ +/*----------------*\ +|Nanite OS | +|Copyright (C) 2024| +|Tyler McGurrin | +\*----------------*/ +#include "stdio.h" +#include "x86.h" + +void putc(char c) +{ + x86_Video_WriteCharTeletype(c, 0); +} + +void puts(const char* str) +{ + while(*str) + { + putc(*str); + str++; + } +} + +#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 + + +int* printf_number(int* argp, int length, bool sign, int radix); + +void _cdecl printf(const char* fmt, ...) { + int* argp = (int*)&fmt; + int state= PRINTF_STATE_NORMAL; + int length = PRINTF_LENGTH_DEFAULT; + int radix = 10; + bool sign = false; + + argp++; + + while (*fmt) + { + switch (state) + { + case PRINTF_STATE_NORMAL: + switch (*fmt) + { + case '%': state = PRINTF_STATE_NORMAL; + 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 == 'h') + { + 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)*argp); + argp++; + break; + + case 's': puts(*(char***)argp); + argp++; + break; + + case '%': putc('%'); + break; + + case 'd': + case 'i': radix = 10; sign = true; + argp = printf_number(argp, length, sign, radix); + break; + + case 'u': radix = 10; sign = false; + argp = printf_number(argp, length, sign, radix); + break; + + case 'X': + case 'x': + case 'p': radix = 16; sign = false; + argp = printf_number(argp, length, sign, radix); + break; + + case 'o': radix = 8; sign = false; + argp = printf_number(argp, length, sign, radix); + break; + + //ignore invalid specifiers (specs) + default: break; + } + + //reset state + state = PRINTF_STATE_NORMAL; + length = PRINTF_LENGTH_DEFAULT; + radix = 10; + sign = false; + break; + } + + fmt++; + } +} + +const char g_HexChars[] = "0123456789abcdef"; + +int* printf_number(int* argp, int length, bool sign, int radix) +{ + char buffer[32]; + unsigned long long number; + int number_sign = 1; + int pos = 0; + + //process length + switch (length) + { + case PRINTF_LENGTH_SHORT_SHORT: + case PRINTF_LENGTH_SHORT: + case PRINTF_LENGTH_DEFAULT: + if (sign) + { + int n = *argp; + if (n < 0) { + n = -n; + number_sign = -1; + } + number = (unsigned long long)n; + } + else { + number = *(unsigned int*)argp; + } + argp++; + break; + + case PRINTF_LENGTH_LONG: + if (sign) + { + long int n = *(long int*)argp; + if (n < 0) { + n = -n; + number_sign = -1; + } + number = (unsigned long long)n; + } + else { + number = *(unsigned long int*)argp; + } + argp += 2; + break; + + case PRINTF_LENGTH_LONG_LONG: + if (sign) + { + long long int n = *(long long int*)argp; + if (n < 0) { + n = -n; + number_sign = -1; + } + number = (unsigned long long)n; + } + else { + number = *(unsigned long long*)argp; + } + argp += 4; + break; + } + + //number to ASCII conversion + do { + uint32_t rem; + x86_div64_32(number, radix, &number, &rem); + buffer[pos++] = g_HexChars[rem]; + } while (number > 0); + + //add sign + if (sign && number_sign < 0) { + buffer[pos++] = '-'; + } + + //print number in reverse order + while (--pos >= 0) + putc(buffer[pos]); + + return argp; +} diff --git a/src/bootloader/stage2/stdio.err b/src/bootloader/stage2/stdio.err new file mode 100644 index 0000000..b1e31d6 --- /dev/null +++ b/src/bootloader/stage2/stdio.err @@ -0,0 +1,5 @@ +x86.h(22): Error! E1009: Expecting ',' or ';' but found 'x86_Disk_GetDriveParams' +stdio.c(100): Warning! W100: Parameter 1 contains inconsistent levels of indirection +stdio.c(100): Note! I2003: source conversion type is 'char **' +stdio.c(100): Note! I2004: target conversion type is 'char const *' +stdio.c(100): Note! I2002: 'puts' defined in: stdio.c(14) diff --git a/src/bootloader/stage2/stdio.h b/src/bootloader/stage2/stdio.h new file mode 100644 index 0000000..1de4a82 --- /dev/null +++ b/src/bootloader/stage2/stdio.h @@ -0,0 +1,10 @@ +/*----------------*\ +|Nanite OS | +|Copyright (C) 2024| +|Tyler McGurrin | +\*----------------*/ +#pragma once + +void putc(char c); +void puts(const char* str); +void _cdecl printf(const char* fmt, ...); diff --git a/src/bootloader/stage2/x86.asm b/src/bootloader/stage2/x86.asm new file mode 100644 index 0000000..ec02a55 --- /dev/null +++ b/src/bootloader/stage2/x86.asm @@ -0,0 +1,102 @@ +;/////////////////////; +;Nanite OS ; +;COPYRIGHT (C) 2024 ; +;Tyler McGurrin ; +;/////////////////////; +bits 16 + +section _TEXT class=CODE + +; +;void _cdecl x86_div64_32(uint64_t dividend, uint32_t divisor, uint64_t* quotentOut, uint32_t* remainderOut); +; + +global _x86_div64_32 +_x86_div64_32 + ;make new call frame + push bp ;save old call frame + mov bp, sp ;init new call frame + + push bx + + ;divide upper 32 bits + mov eax, [bp + 4] ;eax is upper 32 bits of divedend + mov ecx, [bp + 12] ;ecx is the divisor + xor edx, edx + div ecx ;eax - quot, edx - remainder + + ;store upper 32 bits + mov ebx, [bp + 16] + mov [bx + 4], eax + + ;divide lower 32 bits + mov eax, [bp + 4] ;eax is the lower 32 bits of the dividend + ;edx is old remainder + div ecx + + ;store results + mov [bx], eax + mov bx, [bp + 18] + mov [bx], edx + + pop bx + + ;restore old call frame + mov sp, bp + pop bp + ret + + + + +global _x86_Video_WriteCharTeletype +_x86_Video_WriteCharTeletype: + + push bp + mov bp,sp + + push bx + + mov ah, 0Eh + mov al, [bp + 4] + mov bh, [bp + 6] + + int 10h + + pop bx + + mov sp, bp + pop bp + ret + + +; +;void _cdecl x86_Disk_Reset(uint8_t drive); +; +global _x86_Disk_Reset +_x86_Disk_Reset: + ;make new call frame + push bp ;save old call frame + mov bp, sp ;init new call frame + + + + ;restore old call frame + mov sp, bp + pop bp + ret + + +; +;void _cdecl x86_Disk_Read(uint8_t drive, +; uint16_t cylinder, +; uint16_t head, +; uint16_t sector, +; uint8_t count, +; uint8_t far * dataout); +; +;void _cdelc x86_Disk_GetDriveParams(uint8_t drive, +; uint8_t* driveTypeOut, +; uint16_t* cylindersOut, +; uint16_t* sectorsOut, +; uint16_t* headsOut); diff --git a/src/bootloader/stage2/x86.h b/src/bootloader/stage2/x86.h new file mode 100644 index 0000000..db1366c --- /dev/null +++ b/src/bootloader/stage2/x86.h @@ -0,0 +1,26 @@ +/*----------------*\ +|Nanite OS | +|Copyright (C) 2024| +|Tyler McGurrin | +\*----------------*/ +#pragma once +#include "stdint.h" + +void _cdecl x86_div64_32(uint64_t dividend, uint32_t divisor, uint64_t* quotentOut, uint32_t* remainderOut); + +void _cdecl x86_Video_WriteCharTeletype(char c, uint8_t page); + +void _cdecl x86_Disk_Reset(uint8_t drive); + +void _cdecl x86_Disk_Read(uint8_t drive, + uint16_t cylinder, + uint16_t head, + uint16_t sector, + uint8_t count, + uint8_t far * dataout); + +void _cdelc x86_Disk_GetDriveParams(uint8_t drive, + uint8_t* driveTypeOut, + uint16_t* cylindersOut, + uint16_t* sectorsOut, + uint16_t* headsOut); diff --git a/src/kernel/Makefile b/src/kernel/Makefile new file mode 100644 index 0000000..f47f9fd --- /dev/null +++ b/src/kernel/Makefile @@ -0,0 +1,14 @@ +BUILD_DIR?=build/ +ASM?=nasm + +.PHONY: all kernel clean + +all: kernel + +kernel: $(BUILD_DIR)/kernel.bin + +$(BUILD_DIR)/kernel.bin: + $(ASM) main.asm -f bin -o $(BUILD_DIR)/kernel.bin + +clean: + rm -f $(BUILD_DIR)/kernel.bin diff --git a/src/kernel/main.asm b/src/kernel/main.asm new file mode 100644 index 0000000..eaf316f --- /dev/null +++ b/src/kernel/main.asm @@ -0,0 +1,50 @@ +;/////////////////////; +;Nanite OS ; +;COPYRIGHT (C) 2024 ; +;Tyler McGurrin ; +;/////////////////////; +org 0x0 +bits 16 + + +%define ENDL 0x0D, 0x0A + + +start: + ; print hello world message + mov si, msg_hello + call puts + +.halt: + cli + 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 + +msg_hello: db 'Loading Kernel...', ENDL, 0 diff --git a/src/micron/Makefile b/src/micron/Makefile new file mode 100644 index 0000000..5f466b9 --- /dev/null +++ b/src/micron/Makefile @@ -0,0 +1,2 @@ +CC = gcc +BUILD_DIR = /build/micron \ No newline at end of file diff --git a/src/micron/main b/src/micron/main new file mode 100644 index 0000000000000000000000000000000000000000..fcc76b4259017f9320466482af760a2c1e860be0 GIT binary patch literal 33224 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 +#include +#include +#include +#include +#include "tinydir.h" + +//Varible Setup here +#define os "Nanite OS" +#define version "0.0.1a" +#define cursor ":\\>" +#define hostname "[NOT IMPLEMENTED YET]" +#define os_logo " _ _ _ _ _____ _____ \n| \\ | | (_) | | _ / ___|\n| \\| | __ _ _ __ _| |_ ___ | | | \\ `--. \n| . ` |/ _` | '_ \\| | __/ _ \\ | | | |`--. \\\n| |\\ | (_| | | | | | || __/ \\ \\_/ /\\__/ /\n\\_| \\_/\\__,_|_| |_|_|\\__\\___| \\___/\\____/ \n" +#define shell_logo " __ __ _ __ __ \n | \\/ (_) ___ _ __ ___ _ __ \\ \\ \\ \\ \n | |\\/| | |/ __| '__/ _ \\| '_ \\(_) \\ \\ \\\n | | | | | (__| | | (_) | | | |_ \\ \\ / /\n |_| |_|_|\\___|_| \\___/|_| |_(_) \\_\\/_/ \n \n" +int invalid_command = 0; +int command_list_length = 10; //does not NEED to match command list's length just helps with slower machines to keep this small and it can get buggy if too large +int history_length = {0}; +int max_files = 200; +char command_list[][15] = {"help","version","clear", "uname", "exit", "dir", "fetch", "time", "exec"}; +char buffer[15][255]; +char program_buffer[30][100]; +char prog_buffer2; +char history[][255]; +char time_buffer[80]; +char exec_cmd_operand_list[15][15] = {"--help", "--nogui"}; +char exec_cmd_dir_buffer[][255]; + + +int main() { + printf("Micron Shell Version " version " Starting...\n"); + + stage2(); + return 0; +} + +int stage2() { + printf("Done Loading Shell!\n"); + printf("Currently Implemtented Commands:\n"); + for(int i = 0; i < command_list_length; i++) { + printf("%s ", &command_list[i]);} + printf("\n"); + cursor_loop(); + return 0; +} + +int cursor_loop() { + printf(cursor); + scanf("%s", &buffer); + //Command detection shiz + if (strcmp(buffer[0],command_list[0]) == 0) {help_cmd();} + else if (strcmp(buffer[0],command_list[1]) == 0) {version_cmd();} + else if (strcmp(buffer[0],command_list[2]) == 0) {clear_cmd();} + else if (strcmp(buffer[0],command_list[3]) == 0) {uname_cmd();} + else if (strcmp(buffer[0],command_list[4]) == 0) {exit_cmd();} + else if (strcmp(buffer[0],command_list[5]) == 0) {dir_cmd();} + else if (strcmp(buffer[0],command_list[6]) == 0) {fetch_cmd();} + else if (strcmp(buffer[0],command_list[7]) == 0) {time_cmd();} + else if (strcmp(buffer[0],command_list[8]) == 0) {exec_cmd();} + else {printf("Mircon: %s: Command not Found!\n", &buffer); clear_buffer();} + cursor_loop(); + return 0; + } + +//Bulit in commands +int help_cmd() { + printf("Built-in Commands:\n"); + for(int i = 0; i < command_list_length; i++) { + printf("%s ", &command_list[i]);} + printf("\n"); + clear_buffer(); + cursor_loop(); + return 0; + } +int version_cmd() { + printf(shell_logo); + printf("Version %s Made by Tyler McGurrin\nCopyright (C) 2024\n", &version); + clear_buffer(); + cursor_loop(); + return 0; + } +int clear_cmd() { + for(int i = 0; i < 2500; i++) { + printf("\n"); + } + clear_buffer(); + cursor_loop(); + return 0; + } +int uname_cmd() { + printf("%s\n", &os); + clear_buffer(); + cursor_loop(); + return 0; +} +int exit_cmd() { + printf("Exiting Micron Shell...\n"); + exit(0); +} +int dir_cmd() { +tinydir_dir dir; +tinydir_open(&dir, "./"); + +while (dir.has_next) +{ + tinydir_file file; + tinydir_readfile(&dir, &file); + + printf("%s", file.name); + if (file.is_dir) + { + printf("/ DIR"); + } + printf("\n"); + + tinydir_next(&dir); +} + +tinydir_close(&dir); +clear_buffer(); +cursor_loop(); +return 0; +} +int fetch_cmd() { +printf("Operating System: %s\nShell: Micron %s\nHostname: %s\n",os,version,hostname); + time_t t = time(NULL); + printf("UTC Time: %s", asctime(gmtime(&t))); + printf("Local Time: %s", asctime(localtime(&t))); +printf(os_logo); +clear_buffer(); +cursor_loop(); +return 0; +} +int time_cmd() { + time_t t = time(NULL); + printf("UTC: %s", asctime(gmtime(&t))); + printf("Local: %s", asctime(localtime(&t))); +clear_buffer(); +cursor_loop(); +return 0; +} +int exec_cmd() { + if (strcmp(buffer[1], exec_cmd_operand_list[0]) == 0) {exec_cmd_help();} + else {exec_cmd_gui(); clear_buffer();} + cursor_loop(); + return 0; +} + + +//Command Handlers + +//Exec Handlers +int exec_cmd_gui() { + printf("\nExec:>"); + scanf("%s", &program_buffer); + if (strcmp(program_buffer[0],command_list[0]) == 0) {help_cmd();} + else if (strcmp(program_buffer[0],command_list[1]) == 0) {version_cmd();} + else if (strcmp(program_buffer[0],command_list[2]) == 0) {clear_cmd();} + else if (strcmp(program_buffer[0],command_list[3]) == 0) {uname_cmd();} + else if (strcmp(program_buffer[0],command_list[4]) == 0) {exit_cmd();} + else if (strcmp(program_buffer[0],command_list[5]) == 0) {dir_cmd();} + else if (strcmp(program_buffer[0],command_list[6]) == 0) {fetch_cmd();} + else if (strcmp(program_buffer[0],command_list[7]) == 0) {time_cmd();} + else {exec_cmd_dir();} + //if (exec_cmd_dir_buffer){printf("Exec: %s: Executible not Found!\n", &buffer); clear_buffer();} + + clear_buffer(); + cursor_loop(); + return 0; +} + +int exec_cmd_help() { + printf("Usage [Operands Like: "); + for(int i = 0; i < command_list_length; i++) { + printf("%s ", &exec_cmd_operand_list[i]);} + printf("]\n"); + clear_buffer(); + cursor_loop(); + return 0; + } +int exec_cmd_dir() { +tinydir_dir dir; +tinydir_open(&dir, "./"); + +while (dir.has_next) +{ + tinydir_file file; + tinydir_readfile(&dir, &file); + + for(int i = 0; i < max_files; i++) { + buffer[i][255] = NULL;} + if (file.is_dir) + { + break; + } + for(int i = 0; i < max_files; i++) { + if (strcmp(program_buffer,file.name) == 0) { + printf("Loading program..."); + strcat(prog_buffer2, "./"); + strcat(prog_buffer2, program_buffer); + prog_load(); + } + else break; + } + + } + printf("Exec: %s: No Executible found!\n", &program_buffer); + tinydir_next(&dir); +tinydir_close(&dir); +clear_buffer(); +cursor_loop(); +return 0; +} + + +//Extra Tools (Not executible via shell) +int clear_buffer() { + + for(int i = 0; i < command_list_length; i++) { + buffer[i][255] = NULL;} + free(prog_buffer2); + cursor_loop(); + return 0; +} +int prog_load() { + system(prog_buffer2); + exit(0); +} \ No newline at end of file diff --git a/src/micron/tinydir.h b/src/micron/tinydir.h new file mode 100644 index 0000000..d7f4668 --- /dev/null +++ b/src/micron/tinydir.h @@ -0,0 +1,848 @@ +/* +Copyright (c) 2013-2021, tinydir authors: +- Cong Xu +- Lautis Sun +- Baudouin Feildel +- Andargor +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef TINYDIR_H +#define TINYDIR_H + +#ifdef __cplusplus +extern "C" { +#endif + +#if ((defined _UNICODE) && !(defined UNICODE)) +#define UNICODE +#endif + +#if ((defined UNICODE) && !(defined _UNICODE)) +#define _UNICODE +#endif + +#include +#include +#include +#ifdef _MSC_VER +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# include +# include +# pragma warning(push) +# pragma warning (disable : 4996) +#else +# include +# include +# include +# include +#endif +#ifdef __MINGW32__ +# include +#endif + + +/* types */ + +/* Windows UNICODE wide character support */ +#if defined _MSC_VER || defined __MINGW32__ +# define _tinydir_char_t TCHAR +# define TINYDIR_STRING(s) _TEXT(s) +# define _tinydir_strlen _tcslen +# define _tinydir_strcpy _tcscpy +# define _tinydir_strcat _tcscat +# define _tinydir_strcmp _tcscmp +# define _tinydir_strrchr _tcsrchr +# define _tinydir_strncmp _tcsncmp +#else +# define _tinydir_char_t char +# define TINYDIR_STRING(s) s +# define _tinydir_strlen strlen +# define _tinydir_strcpy strcpy +# define _tinydir_strcat strcat +# define _tinydir_strcmp strcmp +# define _tinydir_strrchr strrchr +# define _tinydir_strncmp strncmp +#endif + +#if (defined _MSC_VER || defined __MINGW32__) +# include +# define _TINYDIR_PATH_MAX MAX_PATH +#elif defined __linux__ +# include +# ifdef PATH_MAX +# define _TINYDIR_PATH_MAX PATH_MAX +# endif +#elif defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) +# include +# if defined(BSD) +# include +# ifdef PATH_MAX +# define _TINYDIR_PATH_MAX PATH_MAX +# endif +# endif +#endif + +#ifndef _TINYDIR_PATH_MAX +#define _TINYDIR_PATH_MAX 4096 +#endif + +#ifdef _MSC_VER +/* extra chars for the "\\*" mask */ +# define _TINYDIR_PATH_EXTRA 2 +#else +# define _TINYDIR_PATH_EXTRA 0 +#endif + +#define _TINYDIR_FILENAME_MAX 256 + +#if (defined _MSC_VER || defined __MINGW32__) +#define _TINYDIR_DRIVE_MAX 3 +#endif + +#ifdef _MSC_VER +# define _TINYDIR_FUNC static __inline +#elif !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L +# define _TINYDIR_FUNC static __inline__ +#elif defined(__cplusplus) +# define _TINYDIR_FUNC static inline +#elif defined(__GNUC__) +/* Suppress unused function warning */ +# define _TINYDIR_FUNC __attribute__((unused)) static +#else +# define _TINYDIR_FUNC static +#endif + +#if defined(i386) || defined(__i386__) || defined(__i386) || defined(_M_IX86) +#ifdef _MSC_VER +# define _TINYDIR_CDECL __cdecl +#else +# define _TINYDIR_CDECL __attribute__((cdecl)) +#endif +#else +# define _TINYDIR_CDECL +#endif + +/* readdir_r usage; define TINYDIR_USE_READDIR_R to use it (if supported) */ +#ifdef TINYDIR_USE_READDIR_R + +/* readdir_r is a POSIX-only function, and may not be available under various + * environments/settings, e.g. MinGW. Use readdir fallback */ +#if _POSIX_C_SOURCE >= 1 || _XOPEN_SOURCE || _BSD_SOURCE || _SVID_SOURCE ||\ + _POSIX_SOURCE +# define _TINYDIR_HAS_READDIR_R +#endif +#if _POSIX_C_SOURCE >= 200112L +# define _TINYDIR_HAS_FPATHCONF +# include +#endif +#if _BSD_SOURCE || _SVID_SOURCE || \ + (_POSIX_C_SOURCE >= 200809L || _XOPEN_SOURCE >= 700) +# define _TINYDIR_HAS_DIRFD +# include +#endif +#if defined _TINYDIR_HAS_FPATHCONF && defined _TINYDIR_HAS_DIRFD &&\ + defined _PC_NAME_MAX +# define _TINYDIR_USE_FPATHCONF +#endif +#if defined __MINGW32__ || !defined _TINYDIR_HAS_READDIR_R ||\ + !(defined _TINYDIR_USE_FPATHCONF || defined NAME_MAX) +# define _TINYDIR_USE_READDIR +#endif + +/* Use readdir by default */ +#else +# define _TINYDIR_USE_READDIR +#endif + +/* MINGW32 has two versions of dirent, ASCII and UNICODE*/ +#ifndef _MSC_VER +#if (defined __MINGW32__) && (defined _UNICODE) +#define _TINYDIR_DIR _WDIR +#define _tinydir_dirent _wdirent +#define _tinydir_opendir _wopendir +#define _tinydir_readdir _wreaddir +#define _tinydir_closedir _wclosedir +#else +#define _TINYDIR_DIR DIR +#define _tinydir_dirent dirent +#define _tinydir_opendir opendir +#define _tinydir_readdir readdir +#define _tinydir_closedir closedir +#endif +#endif + +/* Allow user to use a custom allocator by defining _TINYDIR_MALLOC and _TINYDIR_FREE. */ +#if defined(_TINYDIR_MALLOC) && defined(_TINYDIR_FREE) +#elif !defined(_TINYDIR_MALLOC) && !defined(_TINYDIR_FREE) +#else +#error "Either define both alloc and free or none of them!" +#endif + +#if !defined(_TINYDIR_MALLOC) + #define _TINYDIR_MALLOC(_size) malloc(_size) + #define _TINYDIR_FREE(_ptr) free(_ptr) +#endif /* !defined(_TINYDIR_MALLOC) */ + +typedef struct tinydir_file +{ + _tinydir_char_t path[_TINYDIR_PATH_MAX]; + _tinydir_char_t name[_TINYDIR_FILENAME_MAX]; + _tinydir_char_t *extension; + int is_dir; + int is_reg; + +#ifndef _MSC_VER +#ifdef __MINGW32__ + struct _stat _s; +#else + struct stat _s; +#endif +#endif +} tinydir_file; + +typedef struct tinydir_dir +{ + _tinydir_char_t path[_TINYDIR_PATH_MAX]; + int has_next; + size_t n_files; + + tinydir_file *_files; +#ifdef _MSC_VER + HANDLE _h; + WIN32_FIND_DATA _f; +#else + _TINYDIR_DIR *_d; + struct _tinydir_dirent *_e; +#ifndef _TINYDIR_USE_READDIR + struct _tinydir_dirent *_ep; +#endif +#endif +} tinydir_dir; + + +/* declarations */ + +_TINYDIR_FUNC +int tinydir_open(tinydir_dir *dir, const _tinydir_char_t *path); +_TINYDIR_FUNC +int tinydir_open_sorted(tinydir_dir *dir, const _tinydir_char_t *path); +_TINYDIR_FUNC +void tinydir_close(tinydir_dir *dir); + +_TINYDIR_FUNC +int tinydir_next(tinydir_dir *dir); +_TINYDIR_FUNC +int tinydir_readfile(const tinydir_dir *dir, tinydir_file *file); +_TINYDIR_FUNC +int tinydir_readfile_n(const tinydir_dir *dir, tinydir_file *file, size_t i); +_TINYDIR_FUNC +int tinydir_open_subdir_n(tinydir_dir *dir, size_t i); + +_TINYDIR_FUNC +int tinydir_file_open(tinydir_file *file, const _tinydir_char_t *path); +_TINYDIR_FUNC +void _tinydir_get_ext(tinydir_file *file); +_TINYDIR_FUNC +int _TINYDIR_CDECL _tinydir_file_cmp(const void *a, const void *b); +#ifndef _MSC_VER +#ifndef _TINYDIR_USE_READDIR +_TINYDIR_FUNC +size_t _tinydir_dirent_buf_size(_TINYDIR_DIR *dirp); +#endif +#endif + + +/* definitions*/ + +_TINYDIR_FUNC +int tinydir_open(tinydir_dir *dir, const _tinydir_char_t *path) +{ +#ifndef _MSC_VER +#ifndef _TINYDIR_USE_READDIR + int error; + int size; /* using int size */ +#endif +#else + _tinydir_char_t path_buf[_TINYDIR_PATH_MAX]; +#endif + _tinydir_char_t *pathp; + + if (dir == NULL || path == NULL || _tinydir_strlen(path) == 0) + { + errno = EINVAL; + return -1; + } + if (_tinydir_strlen(path) + _TINYDIR_PATH_EXTRA >= _TINYDIR_PATH_MAX) + { + errno = ENAMETOOLONG; + return -1; + } + + /* initialise dir */ + dir->_files = NULL; +#ifdef _MSC_VER + dir->_h = INVALID_HANDLE_VALUE; +#else + dir->_d = NULL; +#ifndef _TINYDIR_USE_READDIR + dir->_ep = NULL; +#endif +#endif + tinydir_close(dir); + + _tinydir_strcpy(dir->path, path); + /* Remove trailing slashes */ + pathp = &dir->path[_tinydir_strlen(dir->path) - 1]; + while (pathp != dir->path && (*pathp == TINYDIR_STRING('\\') || *pathp == TINYDIR_STRING('/'))) + { + *pathp = TINYDIR_STRING('\0'); + pathp++; + } +#ifdef _MSC_VER + _tinydir_strcpy(path_buf, dir->path); + _tinydir_strcat(path_buf, TINYDIR_STRING("\\*")); +#if (defined WINAPI_FAMILY) && (WINAPI_FAMILY != WINAPI_FAMILY_DESKTOP_APP) + dir->_h = FindFirstFileEx(path_buf, FindExInfoStandard, &dir->_f, FindExSearchNameMatch, NULL, 0); +#else + dir->_h = FindFirstFile(path_buf, &dir->_f); +#endif + if (dir->_h == INVALID_HANDLE_VALUE) + { + errno = ENOENT; +#else + dir->_d = _tinydir_opendir(path); + if (dir->_d == NULL) + { +#endif + goto bail; + } + + /* read first file */ + dir->has_next = 1; +#ifndef _MSC_VER +#ifdef _TINYDIR_USE_READDIR + dir->_e = _tinydir_readdir(dir->_d); +#else + /* allocate dirent buffer for readdir_r */ + size = _tinydir_dirent_buf_size(dir->_d); /* conversion to int */ + if (size == -1) return -1; + dir->_ep = (struct _tinydir_dirent*)_TINYDIR_MALLOC(size); + if (dir->_ep == NULL) return -1; + + error = readdir_r(dir->_d, dir->_ep, &dir->_e); + if (error != 0) return -1; +#endif + if (dir->_e == NULL) + { + dir->has_next = 0; + } +#endif + + return 0; + +bail: + tinydir_close(dir); + return -1; +} + +_TINYDIR_FUNC +int tinydir_open_sorted(tinydir_dir *dir, const _tinydir_char_t *path) +{ + /* Count the number of files first, to pre-allocate the files array */ + size_t n_files = 0; + if (tinydir_open(dir, path) == -1) + { + return -1; + } + while (dir->has_next) + { + n_files++; + if (tinydir_next(dir) == -1) + { + goto bail; + } + } + tinydir_close(dir); + + if (n_files == 0 || tinydir_open(dir, path) == -1) + { + return -1; + } + + dir->n_files = 0; + dir->_files = (tinydir_file *)_TINYDIR_MALLOC(sizeof *dir->_files * n_files); + if (dir->_files == NULL) + { + goto bail; + } + while (dir->has_next) + { + tinydir_file *p_file; + dir->n_files++; + + p_file = &dir->_files[dir->n_files - 1]; + if (tinydir_readfile(dir, p_file) == -1) + { + goto bail; + } + + if (tinydir_next(dir) == -1) + { + goto bail; + } + + /* Just in case the number of files has changed between the first and + second reads, terminate without writing into unallocated memory */ + if (dir->n_files == n_files) + { + break; + } + } + + qsort(dir->_files, dir->n_files, sizeof(tinydir_file), _tinydir_file_cmp); + + return 0; + +bail: + tinydir_close(dir); + return -1; +} + +_TINYDIR_FUNC +void tinydir_close(tinydir_dir *dir) +{ + if (dir == NULL) + { + return; + } + + memset(dir->path, 0, sizeof(dir->path)); + dir->has_next = 0; + dir->n_files = 0; + _TINYDIR_FREE(dir->_files); + dir->_files = NULL; +#ifdef _MSC_VER + if (dir->_h != INVALID_HANDLE_VALUE) + { + FindClose(dir->_h); + } + dir->_h = INVALID_HANDLE_VALUE; +#else + if (dir->_d) + { + _tinydir_closedir(dir->_d); + } + dir->_d = NULL; + dir->_e = NULL; +#ifndef _TINYDIR_USE_READDIR + _TINYDIR_FREE(dir->_ep); + dir->_ep = NULL; +#endif +#endif +} + +_TINYDIR_FUNC +int tinydir_next(tinydir_dir *dir) +{ + if (dir == NULL) + { + errno = EINVAL; + return -1; + } + if (!dir->has_next) + { + errno = ENOENT; + return -1; + } + +#ifdef _MSC_VER + if (FindNextFile(dir->_h, &dir->_f) == 0) +#else +#ifdef _TINYDIR_USE_READDIR + dir->_e = _tinydir_readdir(dir->_d); +#else + if (dir->_ep == NULL) + { + return -1; + } + if (readdir_r(dir->_d, dir->_ep, &dir->_e) != 0) + { + return -1; + } +#endif + if (dir->_e == NULL) +#endif + { + dir->has_next = 0; +#ifdef _MSC_VER + if (GetLastError() != ERROR_SUCCESS && + GetLastError() != ERROR_NO_MORE_FILES) + { + tinydir_close(dir); + errno = EIO; + return -1; + } +#endif + } + + return 0; +} + +_TINYDIR_FUNC +int tinydir_readfile(const tinydir_dir *dir, tinydir_file *file) +{ + const _tinydir_char_t *filename; + if (dir == NULL || file == NULL) + { + errno = EINVAL; + return -1; + } +#ifdef _MSC_VER + if (dir->_h == INVALID_HANDLE_VALUE) +#else + if (dir->_e == NULL) +#endif + { + errno = ENOENT; + return -1; + } + filename = +#ifdef _MSC_VER + dir->_f.cFileName; +#else + dir->_e->d_name; +#endif + if (_tinydir_strlen(dir->path) + + _tinydir_strlen(filename) + 1 + _TINYDIR_PATH_EXTRA >= + _TINYDIR_PATH_MAX) + { + /* the path for the file will be too long */ + errno = ENAMETOOLONG; + return -1; + } + if (_tinydir_strlen(filename) >= _TINYDIR_FILENAME_MAX) + { + errno = ENAMETOOLONG; + return -1; + } + + _tinydir_strcpy(file->path, dir->path); + if (_tinydir_strcmp(dir->path, TINYDIR_STRING("/")) != 0) + _tinydir_strcat(file->path, TINYDIR_STRING("/")); + _tinydir_strcpy(file->name, filename); + _tinydir_strcat(file->path, filename); +#ifndef _MSC_VER +#ifdef __MINGW32__ + if (_tstat( +#elif (defined _BSD_SOURCE) || (defined _DEFAULT_SOURCE) \ + || ((defined _XOPEN_SOURCE) && (_XOPEN_SOURCE >= 500)) \ + || ((defined _POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L)) \ + || ((defined __APPLE__) && (defined __MACH__)) \ + || (defined BSD) + if (lstat( +#else + if (stat( +#endif + file->path, &file->_s) == -1) + { + return -1; + } +#endif + _tinydir_get_ext(file); + + file->is_dir = +#ifdef _MSC_VER + !!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY); +#else + S_ISDIR(file->_s.st_mode); +#endif + file->is_reg = +#ifdef _MSC_VER + !!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_NORMAL) || + ( + !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DEVICE) && + !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && + !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED) && +#ifdef FILE_ATTRIBUTE_INTEGRITY_STREAM + !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_INTEGRITY_STREAM) && +#endif +#ifdef FILE_ATTRIBUTE_NO_SCRUB_DATA + !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_NO_SCRUB_DATA) && +#endif + !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_OFFLINE) && + !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_TEMPORARY)); +#else + S_ISREG(file->_s.st_mode); +#endif + + return 0; +} + +_TINYDIR_FUNC +int tinydir_readfile_n(const tinydir_dir *dir, tinydir_file *file, size_t i) +{ + if (dir == NULL || file == NULL) + { + errno = EINVAL; + return -1; + } + if (i >= dir->n_files) + { + errno = ENOENT; + return -1; + } + + memcpy(file, &dir->_files[i], sizeof(tinydir_file)); + _tinydir_get_ext(file); + + return 0; +} + +_TINYDIR_FUNC +int tinydir_open_subdir_n(tinydir_dir *dir, size_t i) +{ + _tinydir_char_t path[_TINYDIR_PATH_MAX]; + if (dir == NULL) + { + errno = EINVAL; + return -1; + } + if (i >= dir->n_files || !dir->_files[i].is_dir) + { + errno = ENOENT; + return -1; + } + + _tinydir_strcpy(path, dir->_files[i].path); + tinydir_close(dir); + if (tinydir_open_sorted(dir, path) == -1) + { + return -1; + } + + return 0; +} + +/* Open a single file given its path */ +_TINYDIR_FUNC +int tinydir_file_open(tinydir_file *file, const _tinydir_char_t *path) +{ + tinydir_dir dir; + int result = 0; + int found = 0; + _tinydir_char_t dir_name_buf[_TINYDIR_PATH_MAX]; + _tinydir_char_t file_name_buf[_TINYDIR_PATH_MAX]; + _tinydir_char_t *dir_name; + _tinydir_char_t *base_name; +#if (defined _MSC_VER || defined __MINGW32__) + _tinydir_char_t drive_buf[_TINYDIR_PATH_MAX]; + _tinydir_char_t ext_buf[_TINYDIR_FILENAME_MAX]; +#endif + + if (file == NULL || path == NULL || _tinydir_strlen(path) == 0) + { + errno = EINVAL; + return -1; + } + if (_tinydir_strlen(path) + _TINYDIR_PATH_EXTRA >= _TINYDIR_PATH_MAX) + { + errno = ENAMETOOLONG; + return -1; + } + + /* Get the parent path */ +#if (defined _MSC_VER || defined __MINGW32__) +#if ((defined _MSC_VER) && (_MSC_VER >= 1400)) + errno = _tsplitpath_s( + path, + drive_buf, _TINYDIR_DRIVE_MAX, + dir_name_buf, _TINYDIR_FILENAME_MAX, + file_name_buf, _TINYDIR_FILENAME_MAX, + ext_buf, _TINYDIR_FILENAME_MAX); +#else + _tsplitpath( + path, + drive_buf, + dir_name_buf, + file_name_buf, + ext_buf); +#endif + + if (errno) + { + return -1; + } + +/* _splitpath_s not work fine with only filename and widechar support */ +#ifdef _UNICODE + if (drive_buf[0] == L'\xFEFE') + drive_buf[0] = '\0'; + if (dir_name_buf[0] == L'\xFEFE') + dir_name_buf[0] = '\0'; +#endif + + /* Emulate the behavior of dirname by returning "." for dir name if it's + empty */ + if (drive_buf[0] == '\0' && dir_name_buf[0] == '\0') + { + _tinydir_strcpy(dir_name_buf, TINYDIR_STRING(".")); + } + /* Concatenate the drive letter and dir name to form full dir name */ + _tinydir_strcat(drive_buf, dir_name_buf); + dir_name = drive_buf; + /* Concatenate the file name and extension to form base name */ + _tinydir_strcat(file_name_buf, ext_buf); + base_name = file_name_buf; +#else + _tinydir_strcpy(dir_name_buf, path); + dir_name = dirname(dir_name_buf); + _tinydir_strcpy(file_name_buf, path); + base_name = basename(file_name_buf); +#endif + + /* Special case: if the path is a root dir, open the parent dir as the file */ +#if (defined _MSC_VER || defined __MINGW32__) + if (_tinydir_strlen(base_name) == 0) +#else + if ((_tinydir_strcmp(base_name, TINYDIR_STRING("/"))) == 0) +#endif + { + memset(file, 0, sizeof * file); + file->is_dir = 1; + file->is_reg = 0; + _tinydir_strcpy(file->path, dir_name); + file->extension = file->path + _tinydir_strlen(file->path); + return 0; + } + + /* Open the parent directory */ + if (tinydir_open(&dir, dir_name) == -1) + { + return -1; + } + + /* Read through the parent directory and look for the file */ + while (dir.has_next) + { + if (tinydir_readfile(&dir, file) == -1) + { + result = -1; + goto bail; + } + if (_tinydir_strcmp(file->name, base_name) == 0) + { + /* File found */ + found = 1; + break; + } + tinydir_next(&dir); + } + if (!found) + { + result = -1; + errno = ENOENT; + } + +bail: + tinydir_close(&dir); + return result; +} + +_TINYDIR_FUNC +void _tinydir_get_ext(tinydir_file *file) +{ + _tinydir_char_t *period = _tinydir_strrchr(file->name, TINYDIR_STRING('.')); + if (period == NULL) + { + file->extension = &(file->name[_tinydir_strlen(file->name)]); + } + else + { + file->extension = period + 1; + } +} + +_TINYDIR_FUNC +int _TINYDIR_CDECL _tinydir_file_cmp(const void *a, const void *b) +{ + const tinydir_file *fa = (const tinydir_file *)a; + const tinydir_file *fb = (const tinydir_file *)b; + if (fa->is_dir != fb->is_dir) + { + return -(fa->is_dir - fb->is_dir); + } + return _tinydir_strncmp(fa->name, fb->name, _TINYDIR_FILENAME_MAX); +} + +#ifndef _MSC_VER +#ifndef _TINYDIR_USE_READDIR +/* +The following authored by Ben Hutchings +from https://womble.decadent.org.uk/readdir_r-advisory.html +*/ +/* Calculate the required buffer size (in bytes) for directory * +* entries read from the given directory handle. Return -1 if this * +* this cannot be done. * +* * +* This code does not trust values of NAME_MAX that are less than * +* 255, since some systems (including at least HP-UX) incorrectly * +* define it to be a smaller value. */ +_TINYDIR_FUNC +size_t _tinydir_dirent_buf_size(_TINYDIR_DIR *dirp) +{ + long name_max; + size_t name_end; + /* parameter may be unused */ + (void)dirp; + +#if defined _TINYDIR_USE_FPATHCONF + name_max = fpathconf(dirfd(dirp), _PC_NAME_MAX); + if (name_max == -1) +#if defined(NAME_MAX) + name_max = (NAME_MAX > 255) ? NAME_MAX : 255; +#else + return (size_t)(-1); +#endif +#elif defined(NAME_MAX) + name_max = (NAME_MAX > 255) ? NAME_MAX : 255; +#else +#error "buffer size for readdir_r cannot be determined" +#endif + name_end = (size_t)offsetof(struct _tinydir_dirent, d_name) + name_max + 1; + return (name_end > sizeof(struct _tinydir_dirent) ? + name_end : sizeof(struct _tinydir_dirent)); +} +#endif +#endif + +#ifdef __cplusplus +} +#endif + +# if defined (_MSC_VER) +# pragma warning(pop) +# endif + +#endif diff --git a/tools/fat/fat.c b/tools/fat/fat.c new file mode 100644 index 0000000..8a622ee --- /dev/null +++ b/tools/fat/fat.c @@ -0,0 +1,183 @@ +#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; +} diff --git a/write.sh b/write.sh new file mode 100644 index 0000000..ab54ab6 --- /dev/null +++ b/write.sh @@ -0,0 +1,31 @@ +echo ------------ +echo COMPILING OS +echo ------------ + +sudo make + +echo --------- +echo Finished! +echo --------- +read -p "Do you want to write the IMG to Floppy? (/dev/sdb) (Y/n) " yn + +case $yn in + y ) + echo --------------------- + echo Writing IMG to Floppy + echo --------------------- + + sudo dd if=./build/main_floppy.img of=/dev/sdb + + echo --------- + echo Finished! + echo --------- + + ;; + n ) echo exiting...; + exit;; + * ) echo invalid response; + exit 1;; +esac + +