From 0c36d813e5cf66ea51446a1cf0e6228685a01a03 Mon Sep 17 00:00:00 2001 From: DualFroz Date: Tue, 1 Sep 2026 18:31:24 +0200 Subject: [PATCH] feat: extend ata with Bitmap --- include/ata.h | 34 +++++++++++++++++++++++++++++++ include/bmp.h | 37 ++++++++++++++++++++++++++++++++++ include/elf.h | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 127 insertions(+) create mode 100644 include/ata.h create mode 100644 include/bmp.h diff --git a/include/ata.h b/include/ata.h new file mode 100644 index 0000000..2b08b0c --- /dev/null +++ b/include/ata.h @@ -0,0 +1,34 @@ +#ifndef FROSTBYTE_ATA_H +#define FROSTBYTE_ATA_H + +#include "types.h" + +/* + * ATA PIO driver (primary bus, master drive only, LBA28 addressing). + * + * This talks to real IDE hardware registers (0x1F0-0x1F7 + the 0x3F6 + * alternate-status/device-control port) using polling, not IRQ14: ataInit + * disables the drive's interrupt line (nIEN) up front, so every command is + * driven by busy-waiting on the status register. That keeps the driver + * usable from the in-kernel test harness, which runs before the scheduler + * and with interrupts disabled. + * + * All polling loops are bounded (ataPollTimeout iterations): a missing or + * wedged drive returns false/failure instead of hanging the kernel forever. + */ + +#define ataSectorSize 512 + +bool ataInit(void); +bool ataPresent(void); +uint64 ataSectorCount(void); +const char* ataModelString(void); + +/* count is a sector count in [0, 255]; 0 trivially succeeds without + touching hardware. Both fail (return false) if no drive was found by + ataInit, if the request runs past ataSectorCount(), or if the drive + reports an error/timeout mid-transfer. */ +bool ataReadSectors(uint64 lba, uint32 count, void* buffer); +bool ataWriteSectors(uint64 lba, uint32 count, const void* buffer); + +#endif diff --git a/include/bmp.h b/include/bmp.h new file mode 100644 index 0000000..32a0470 --- /dev/null +++ b/include/bmp.h @@ -0,0 +1,37 @@ +#ifndef FROSTBYTE_BMP_H +#define FROSTBYTE_BMP_H + +#include "types.h" + +/* + * Bitmap: general-purpose fixed-size bitmap over caller-supplied 64-bit + * word storage. No heap dependency (the pmm frame allocator uses its own + * private copy of this same idea and predates this generic version; this + * one is for any other subsystem that needs a bit-indexed set). + */ + +typedef struct Bitmap { + uint64* words; + usize bitCount; +} Bitmap; + +/* backingWords must hold at least (bitCount + 63) / 64 uint64 words. */ +void bmpInit(Bitmap* b, uint64* backingWords, usize bitCount); + +void bmpSet(Bitmap* b, usize index); +void bmpClear(Bitmap* b, usize index); +bool bmpTest(const Bitmap* b, usize index); + +void bmpSetRange(Bitmap* b, usize start, usize count); +void bmpClearRange(Bitmap* b, usize start, usize count); + +void bmpSetAll(Bitmap* b); +void bmpClearAll(Bitmap* b); + +usize bmpCountSet(const Bitmap* b); + +/* Returns the index of the first clear/set bit, or -1 if none exists. */ +isize bmpFindFirstClear(const Bitmap* b); +isize bmpFindFirstSet(const Bitmap* b); + +#endif diff --git a/include/elf.h b/include/elf.h index 97fdc25..da304c3 100644 --- a/include/elf.h +++ b/include/elf.h @@ -33,4 +33,60 @@ typedef struct Elf64ProgramHeader { uint64 elfLoad(const void* image, uint64 imageSize); +/* Maps one ELF64 program header's p_flags (segmentFlags: standard PF_X=1/ + PF_W=2/PF_R=4 bit values) onto the extra paging.h leaf-PTE bits + (pageWrite, pageNoExecute) elfLoad passes to pagingMapUserRangeExact for + that segment -- real per-segment W^X (a binary's own .text/.rodata ends + up read-only+executable, its .data/.bss read-write+non-executable) + instead of one blanket writable+executable range for the whole image. + Pure address-flag arithmetic, no paging/scheduler/VFS state touched, so + it is fully unit-testable (elfTest.c) the same way elfSlotBase and + friends already are. */ +uint64 elfSegmentPagingFlags(uint32 segmentFlags); + +/* Every userspace binary in this kernel is linked (Makefile --defsym + USER_BASE=...) at a fixed, elfSlotSize-aligned base of its own, since + there is one shared address space system-wide (no per-process page + tables/CR3) and no relocation support (-fno-pic): two binaries must + simply never overlap. kmain.c's boot-time spawnUser calls hardcode each + binary's stack/brk address following the same base+offset pattern by + hand; elfSlotStackTop/elfSlotBrkStart let syscall.c's exec()/spawn() + (a path resolved at runtime, not known at kmain.c's compile time) + derive the same addresses purely from the ELF's own entry point. */ +#define elfSlotSize 0x10000000ull +#define elfSlotStackOffset 0x08000000ull +#define elfSlotBrkOffset 0x04000000ull + +uint64 elfSlotBase(uint64 entry); +uint64 elfSlotStackTop(uint64 entry); +uint64 elfSlotBrkStart(uint64 entry); + +/* Ceiling on argv entries any single exec()/spawn()/boot launch can pass + (syscall.c's copyUserArgv enforces the same bound while copying them out + of userspace). Chosen together with the 256-byte per-argument cap + syscall.c already uses for path-like strings so that + elfMaxArgs*256 + a few hundred bytes of pointers/argc never comes close + to execStackSize (syscall.c) or kmain.c's userStackSize -- both far + larger than any realistic argv list this kernel's own binaries pass. */ +#define elfMaxArgs 16 + +/* Lays out a process's very first stack frame the way a real x86_64 SysV + process entry looks (used by user/crt.S's _start): from stackTop down, + the argument strings themselves, then (16-byte aligned per the ABI) + argc, argv[0..argc-1], and a NULL argv terminator -- *outRsp is where + _start should start executing with, pointing at argc. + argv/argc are already kernel-side data (copyUserArgv, doExec/doSpawn in + syscall.c, or a literal array for kmain.c's boot spawnUser) by the time + this runs; this function only ever writes into [stackTop-stackSize, + stackTop), which the caller must have already mapped (pagingMapUserRange) + -- same contract as elfLoad's segment writes. + Returns false, writing nothing, if argc is out of [0, elfMaxArgs] or the + strings plus the fixed-size argv/argc area do not fit in stackSize bytes + -- unreachable for every call site in this kernel today given the bound + above, but checked rather than assumed so a future caller with a bigger + argv (or a deliberately tiny stack in elfTest.c) fails cleanly instead of + silently writing before stackTop-stackSize. */ +bool elfBuildInitialStack(uint64 stackTop, uint64 stackSize, const char* const* argv, + int argc, uint64* outRsp); + #endif