Implement device filesystem subsystem that provides a VFS interface at
/dev for exposing block and character devices. Drivers register devices
via devicefs_register_block() or devicefs_register_char(), and the
devicefs assigns sequential numbers per device class (e.g., hdd1, hdd2).
Features:
- Block device ops: read_sectors, write_sectors, sector_size, sector_count
- Character device ops: read, write
- VFS integration: readdir lists devices, finddir looks up by name
- Byte-offset to sector translation for block device reads/writes
- Auto-numbering: devices named classN where N starts at 1 per class
Also checks off 'ls' task in README.
- Created env.c/h: key=value store with ENV_MAX_VARS=32 entries per
process. Supports get, set, unset, and copy operations.
- Added env_block_t and cwd[128] fields to process_t struct.
- process_create() initializes CWD=/ by default.
- Fork inherits environment via memcpy of the entire process_t.
- Added SYS_GETENV (8) and SYS_SETENV (9) system calls.
- Created env-test user app that verifies: CWD default, set/get,
and inheritance across fork.
- Updated kernel.c to launch 'sh' as init process (for next task).
- Updated README.md to check off environment variables task.
Tested: env-test reads CWD=/, sets TEST=hello, reads it back,
forks child which inherits TEST=hello. All verified via QEMU.
VFS subsystem (vfs.c/h):
- Mount table with up to 16 mount points, longest-prefix path matching.
- File descriptor table (256 entries, fds 0-2 reserved for std streams).
- Path resolution walks mount table then delegates to filesystem's
finddir() for each path component.
- Operations: open, close, read, write, seek, readdir, stat.
- Each filesystem driver provides a vfs_fs_ops_t with callbacks.
Initrd filesystem driver (initrd_fs.c/h):
- Read-only VFS driver backed by the CPIO ramdisk.
- Mounted at '/initrd' during boot.
- Zero-copy reads: file data points directly into the CPIO archive
memory, no allocation or copying needed.
- Supports readdir (flat iteration) and finddir (name lookup).
Bug fix: resolve_path was overwriting file-specific fs_data (set by
finddir, e.g. pointer to CPIO file data) with the mount's fs_data
(NULL). Fixed to preserve fs_data from finddir.
Verified in QEMU: kernel reads /initrd/README via VFS and prints its
contents. Ring 3 user process continues to work.
Build system changes:
- scripts/gen_initrd.sh packs all files from apps/ into a newc-format
CPIO archive at build/isodir/boot/initrd.cpio.
- CMakeLists.txt adds 'initrd' target as ISO dependency. GRUB loads the
archive as a Multiboot2 module via 'module2 /boot/initrd.cpio'.
- apps/README added as placeholder file for initial ramdisk content.
Kernel changes:
- kernel.c scans Multiboot2 tags for MULTIBOOT_TAG_TYPE_MODULE to find
the initrd's physical address range, then passes it to cpio_init().
- cpio.c/h implements a parser for the SVR4/newc CPIO format:
- cpio_init(): lists archive contents on startup
- cpio_find(): look up a file by name (handles ./ prefix)
- cpio_next(): iterate through all entries
- cpio_count(): count files in archive
- The initrd lives in identity-mapped physical memory, so no additional
mapping is needed to access it.
Verified in QEMU: GRUB loads the module at 0x0014A000, CPIO parser
finds the README file (38 bytes). All existing functionality (Ring 3
processes, syscalls) continues to work.
Add complete user-mode process support:
- TSS (tss.c/h): Task State Segment for Ring 3->0 transitions, installed
as GDT entry 5 (selector 0x28). ESP0 updated per-process for kernel
stack switching.
- Process management (process.c/h): Process table with up to 64 processes.
process_create() clones kernel page directory, maps user code at
0x08048000 and user stack at 0xBFFFF000, copies flat binary code.
Round-robin scheduler via schedule_tick() modifies the interrupt frame
in-place for zero-copy context switching.
- System calls (syscall.c/h): INT 0x80 dispatcher with 8 syscalls:
SYS_EXIT, SYS_WRITE (to debug port + VGA), SYS_READ, SYS_FORK,
SYS_GETPID, SYS_YIELD, SYS_WAITPID, SYS_EXEC. IDT gate at 0x80
uses DPL=3 (flags 0xEE) so user code can invoke it.
- Assembly stubs (interrupts.S): isr128 for INT 0x80, tss_flush for
loading the Task Register, enter_usermode for initial iret to Ring 3.
- Paging extensions (paging.c/h): paging_clone_directory() to create
per-process page directories, paging_map_page_in() for mapping into
non-active directories, paging_switch_directory() for CR3 switching.
- GDT expanded from 5 to 6 entries to accommodate TSS descriptor.
gdt_set_gate() exposed in header for TSS initialization.
- ISR handler routes timer IRQ (32) to scheduler and INT 0x80 to
syscall dispatcher. Exception handler now prints EIP/CS/ERR for
debugging.
- Kernel boots a test user program that writes 'Hello from Ring 3!'
via SYS_WRITE and exits with code 42 via SYS_EXIT. Verified working
in QEMU.
Context switching approach: Timer/syscall interrupts save all registers
via the ISR stub. schedule_tick() copies saved_regs between PCBs and
overwrites the interrupt frame, so the existing iret restores the next
process's state without separate switch assembly.
- Created VGA driver that writes to the 0xB8000 text-mode framebuffer.
Supports 80x25 display with 16 foreground/background colors, scrolling,
hardware cursor updates, and special characters (\n, \r, \t, \b).
- Provides vga_puts, vga_putchar, vga_put_hex, vga_put_dec, vga_set_color.
- Displays boot banner ("ClaudeOS v0.1 booting...") on screen clear.
- vga_show_mem_stats() prints total RAM, kernel start/end addresses, and
kernel size on the VGA display during boot.
- Registered as the first driver using REGISTER_DRIVER, proving the
driver framework works end-to-end (probe -> init lifecycle).
Tested: driver loads successfully, debug port confirms vga probe/init.
- Created driver framework with probe/init lifecycle. Drivers register via
REGISTER_DRIVER macro which places pointers in a .drivers linker section.
- During boot, init_drivers() iterates the section, probes each driver
(checking if hardware is present), and initializes those that respond OK.
- Added .drivers section to linker.ld with __drivers_start/__drivers_end
symbols for iteration.
- Also added .rodata.* pattern to the .rodata section for string literals
placed in sub-sections by the compiler.
- No drivers are registered yet; the VGA driver will be the first.
Tested: boots cleanly with driver scan completing (0 registered, 0 loaded).
- Added first-fit free-list allocator with block splitting and coalescing.
Provides kmalloc(), kfree(), and kcalloc() for kernel-space dynamic memory.
- Each block carries an inline header with a magic value (0xCAFEBABE) for
heap corruption detection, plus double-free checking.
- Memory is obtained from the paging subsystem in 4 KiB page increments.
All allocations are 8-byte aligned with a 16-byte minimum block size.
- Created freestanding string.c with memset, memcpy, memmove, memcmp,
strlen, strcmp, strncmp, strcpy, strncpy — replacing the unavailable
libc implementations.
- Added documentation in docs/kmalloc.md.
Tested: kmalloc(64) returns 0xD0001010 (in kernel heap) and kfree succeeds.
Works with both 4 MiB and 128 MiB RAM.
- Created two-level x86 paging (page directory + page tables) with 4 KiB pages.
- Identity maps all detected physical memory in two phases:
1) Static: first 16 MiB using 4 BSS-allocated page tables (avoids
chicken-and-egg with PMM bitmap in BSS).
2) Dynamic: memory above 16 MiB using PMM-allocated page tables,
created before paging is enabled so physical addresses still work.
- Provides kernel heap at 0xD0000000–0xF0000000 for virtual page allocation.
- API: paging_map_page, paging_unmap_page, paging_alloc_page, paging_free_page,
paging_get_physical.
- Added pmm_get_memory_size() to expose detected RAM for paging init.
- Kernel tests paging by allocating a virtual page, writing 0xDEADBEEF, and
reading it back, then freeing it.
- Added documentation in docs/paging.md.
Tested: boots and passes paging test with both 4 MiB and 128 MiB RAM in QEMU.
- Added bitmap-based physical memory manager (PMM) that parses the Multiboot2
memory map to discover available RAM regions.
- Supports two allocation zones: PMM_ZONE_DMA (below 16MB) and PMM_ZONE_NORMAL
(above 16MB), with automatic fallback from NORMAL to DMA when the preferred
zone is exhausted.
- Marks kernel memory region and multiboot info structure as reserved using
_kernel_start/_kernel_end linker symbols.
- Page 0 is always marked as used to prevent returning NULL as a valid address.
- Added linker script symbols (_kernel_start, _kernel_end) to track kernel
memory boundaries for the allocator.
- Kernel now initializes PMM after PIC and performs test allocations to verify
the subsystem works.
- Reworked IDT initialization to register all 32 CPU exception handlers (ISR 0-31)
and 16 hardware interrupt handlers (IRQ 0-15, mapped to IDT entries 32-47).
- Created assembly stubs in interrupts.S using macros for ISRs with and without
error codes, plus IRQ stubs. All route through a common stub that saves
registers, loads kernel data segment, and calls the C handler.
- Added isr.c with a unified interrupt dispatcher that handles both exceptions
(halts on fault) and hardware IRQs (sends EOI via PIC).
- Implemented PIC (8259) driver in pic.c with full initialization sequence that
remaps IRQ 0-7 to IDT 32-39 and IRQ 8-15 to IDT 40-47. Includes mask/unmask
and EOI support.
- Extracted port I/O primitives (inb, outb, io_wait) into port_io.h header for
reuse across drivers.
- Kernel now initializes PIC after IDT and enables interrupts with STI.
This commit adds GDT initialization with proper code/data segments and reloads CS.
It also adds the initial IDT structure and loads an empty IDT.
Build configuration updated to disable SSE/MMX to prevent compiler generation of unsupported instructions in early boot.