Add a driver for NE2000-compatible ISA Ethernet cards based on the
DP8390 controller. Features:
- PROM-based MAC address detection and validation
- Programmed I/O (PIO) remote DMA for data transfers
- Ring buffer management for RX with wrap-around handling
- IRQ 9-driven packet reception and transmission
- Synchronous TX with timeout
- Character device registration as 'eth' class (/dev/ethN)
Probe verifies card presence by resetting the controller, configuring
it for PROM reading, and checking the MAC is not all-0xFF/all-0x00
(which would indicate no hardware at the I/O base).
NE2000 memory layout (16 KiB on-card RAM):
- Pages 0x40-0x45: TX buffer (1536 bytes, 1 MTU frame)
- Pages 0x46-0x7F: RX ring buffer (~14.5 KiB)
Tested with QEMU: `-device ne2k_isa,iobase=0x300,irq=9` correctly
detects the card and registers /dev/eth1. Without the NIC option,
probe correctly reports 'not found'.
Add Intel 82077AA-compatible floppy disk controller driver with:
- CMOS-based drive detection (register 0x10)
- FDC reset with DOR toggle and SPECIFY command
- Motor control with spin-up delay
- ISA DMA channel 2 setup for data transfers
- LBA-to-CHS conversion for 1.44MB geometry
- Single-sector read/write via DMA with 7-byte result phase
- Seek and recalibrate with sense interrupt verification
- IRQ 6 handler (vector 38) for command completion
- Devicefs integration as 'floppy' class block devices
The IRQ wait function detects whether interrupts are enabled
(EFLAGS IF bit) and temporarily enables them if needed, allowing
the driver to work during early init before the kernel calls STI.
The scheduler safely handles timer interrupts in this window since
no user processes exist yet.
Tested with QEMU: drive detected as 1.44M 3.5", registered as
/dev/floppy1, full boot succeeds with CD+HDD+floppy attached.
- FAT32 VFS driver (fat32.h, fat32.c): reads BPB, FAT table, cluster
chains, directory entries (8.3 SFN), file read/write, mount via
fat32_mount_device()
- mount app: writes 'device mountpoint' to /sys/vfs/mount to trigger
FAT32 mount from userspace
- VFS sysfs mount namespace in kernel.c: handles mount requests via
sysfs write to /sys/vfs/mount, delegates to FAT32 driver
- Shell cd: validates target directory exists before updating CWD,
resolves relative paths (., .., components) to absolute paths
- Shell run_command: resolves ARG1 paths relative to CWD so apps
like cat and ls receive absolute paths automatically
- Fixed FAT32 root directory access: use fs->root_cluster when
VFS mount root node has inode=0
- Scan sector 0 of all hdd devices for MBR signature (0xAA55)
- Parse 4 partition entries, register non-empty ones as sub-devices
- Sub-devices named hddNmbrY (e.g., hdd1mbr1) via devicefs
- LBA translation: sub-device reads/writes offset by partition start LBA
- Partition type constants for FAT12/16/32, Linux, NTFS, etc.
- IDE improvements: floating bus detection (0xFF), channel presence check
- Tested: detects FAT32 LBA partition (type=0x0C) on test disk
- Check off devicefs, IDE, MBR in README
Implement PIO-mode IDE driver that scans primary and secondary channels
for ATA hard drives and ATAPI CD/DVD drives using IDENTIFY commands.
Features:
- Scans 4 possible devices (2 channels x 2 drives each)
- ATA IDENTIFY DEVICE for hard drives
- ATAPI IDENTIFY PACKET DEVICE for CD/DVD drives
- PIO-mode 28-bit LBA sector read/write for ATA drives
- Model string extraction and sector count parsing
- Registers as kernel driver via REGISTER_DRIVER macro
- Registers devices with devicefs: ATA → hdd class, ATAPI → cd class
- Added inw/outw to port_io.h for 16-bit I/O
Tested: QEMU detects hdd1 (QEMU HARDDISK) and cd1 (QEMU DVD-ROM).
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.