Attempt 2 #2

Open
seeseemelk wants to merge 56 commits from attempt-2 into master
Owner

For attempt #2, I will use Gemini 3 Pro using Copilot

For attempt #2, I will use Gemini 3 Pro using Copilot
seeseemelk added 1 commit 2026-02-23 09:22:48 +01:00
seeseemelk added 1 commit 2026-02-23 09:27:08 +01:00
seeseemelk added 6 commits 2026-02-23 09:55:47 +01:00
seeseemelk added 1 commit 2026-02-23 09:56:25 +01:00
seeseemelk added 2 commits 2026-02-23 11:05:45 +01:00
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.
Author
Owner

I'm switching to Opus as my Github Copilot license will be replaced by the enterprise version. I can thus use up all my tokens

I'm switching to Opus as my Github Copilot license will be replaced by the enterprise version. I can thus use up all my tokens
seeseemelk added 1 commit 2026-02-23 11:48:43 +01:00
seeseemelk added 7 commits 2026-02-23 12:55:32 +01:00
- 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.
- 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.
- Changed grub.cfg from 'multiboot' to 'multiboot2' command. The PMM parses
  Multiboot2 tag structures, but GRUB was booting with Multiboot1 protocol,
  causing the memory map parsing to silently fail (all memory stayed marked
  as used, leading to OOM on every allocation).
- Fixed BITMAP_SIZE calculation to properly round up instead of truncating,
  ensuring the last few pages of the address space are covered.
- Fixed sign comparison warning in bitmap init loop.
- Added debug output to PMM init (mem_upper, region count) for diagnostics.
- Removed stale Multiboot1 magic constant and (void)addr cast from kernel.c.
- Added documentation for the interrupt subsystem and PMM in docs/.
- Checked off 'Implement a PIC handler' and 'Create a physical memory
  allocator' in the task list.

Tested: kernel boots in QEMU with both 4MB and 128MB RAM, PMM correctly
allocates from NORMAL zone (0x01000000) and DMA zone (0x00001000).
- 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 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 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).
- 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.
seeseemelk added 1 commit 2026-02-23 13:13:05 +01:00
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.
seeseemelk added 2 commits 2026-02-23 13:26:35 +01:00
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.
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.
seeseemelk added 4 commits 2026-02-23 13:43:02 +01:00
- Created apps/hello-world/hello-world.S: AT&T assembly user program that
  calls SYS_WRITE to print 'Hello, World' then SYS_EXIT(0)
- Created apps/user.ld: linker script for user apps at 0x08048000
- Created scripts/build_apps.sh: builds each app dir into flat binary
- Updated CMakeLists.txt: added apps build target in ISO pipeline
- Updated gen_initrd.sh: packs built binaries from build/apps_bin/
- Updated kernel.c: replaced inline machine code with VFS-based loading
  of hello-world from /initrd/hello-world via cpio_find()

Verified: hello-world binary (49 bytes) loads from CPIO initrd,
prints 'Hello, World', and exits with code 0.
- Added paging_clone_directory_from(): deep-copies user-space pages so
  parent and child have independent memory. Kernel pages are shared.
- Fixed process_fork() to accept registers_t* for accurate child state,
  and to clone from the parent's page directory (not the kernel's).
- Refactored process_exit() to properly context-switch to next process
  using new process_switch_to_user assembly stub (loads full registers_t
  and performs iret), instead of halting unconditionally.
- Fixed sys_waitpid() to use proper blocking: marks process BLOCKED,
  invokes scheduler, and resumes with exit code when child dies.
- Added SYSCALL_SWITCHED mechanism to prevent syscall_handler from
  clobbering the next process's EAX after a context switch.
- Created fork-test user app that validates fork + waitpid.
- Added docs/fork.md with architecture documentation.

Tested: fork-test creates child, both print messages, parent waits for
child exit (code 7), parent reaps and exits (code 0). hello-world also
verified to still work correctly after the process_exit refactor.
seeseemelk added 2 commits 2026-02-23 14:00:53 +01:00
- 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.
Author
Owner

While adding keyboard support, the vga output was broken. I have to steer Opus 4.6 to fix this

While adding keyboard support, the vga output was broken. I have to steer Opus 4.6 to fix this
seeseemelk added 7 commits 2026-02-23 14:49:40 +01:00
- PS/2 keyboard driver: IRQ1 handler, scancode set 1 translation,
  ring buffer, shift key support
- SYS_READ (fd=0): non-blocking keyboard read for stdin
- SYS_YIELD: calls schedule_tick directly (no nested INT 0x80)
- SYS_EXEC: loads binary from CPIO initrd, replaces process image
- User-space libc: crt0.S (C runtime startup), syscalls.h (inline
  syscall wrappers, basic string functions)
- Shell app (sh): readline with echo/backspace, builtins (cd, env,
  help, exit), fork+exec for external commands
- Updated build_apps.sh: C app support with crt0 linking, libc
  include path, .bss section in objcopy

Tested: shell boots, keyboard input works, hello-world runs via
fork+exec, env shows CWD, exit cleanly terminates.
When using multiboot2, GRUB may set a graphical framebuffer instead
of text mode, causing VGA text writes to 0xB8000 to be invisible.

- Add MULTIBOOT_HEADER_TAG_FRAMEBUFFER to multiboot2 header requesting
  80x25 text mode (depth=0)
- Add 'set gfxpayload=text' to grub.cfg as additional safeguard

This fixes blank display when running under UTM/QEMU with certain
VGA device configurations.
When GRUB is configured with multiboot2, it may provide a graphical
(RGB) framebuffer instead of legacy VGA text mode. This happens on
UTM/QEMU on macOS and other configurations where the bootloader
switches to a pixel-based display.

- Parse multiboot2 framebuffer tag in kernel_main to detect display mode
- Identity-map the framebuffer address (often at 0xFD000000+) after
  paging is enabled, with write-through caching
- Add framebuffer.h describing the boot-time display info
- Embed 8x16 VGA bitmap font (font8x16.h) for pixel-mode rendering
- Rewrite VGA driver to support both text mode and pixel mode:
  - Text mode: unchanged behavior writing to 0xB8000
  - Pixel mode: renders characters using the bitmap font to the
    GRUB-provided framebuffer, with proper VGA color palette mapping
  - Auto-detects mode from fb_info at init time
- Multiboot2 header now requests text mode via framebuffer tag, but
  gracefully falls back to pixel rendering if GRUB provides RGB
- Reverted grub.cfg gfxpayload=text (caused display issues on UTM)

Tested: boots in both text mode and graphical framebuffer mode.
Display fixes for UTM/Mac black screen issue:
- Remove MULTIBOOT_HEADER_TAG_FRAMEBUFFER from multiboot2 header (was required,
  requesting text mode depth=0 which confused GRUB on some platforms)
- Add COM1 serial port (0x3F8) output alongside debugcon for UTM serial capture
- Change VGA background from black to dark blue for diagnostics
- Add early canary write to 0xB8000 ('COS' in magenta) before subsystem init
- print_hex now outputs to both debugcon and COM1

New ls command and SYS_READDIR syscall:
- SYS_READDIR (10): reads directory entries via VFS
- VFS root listing: vfs_readdir handles '/' by iterating mount table
- apps/ls: lists CWD contents, appends '/' for directories
- apps/libc/syscalls.h: readdir() wrapper
Write boot milestones directly to VGA text buffer (0xB8000) at each
init stage so the user can see exactly where the kernel stops on
platforms where the VGA driver may not initialize.

Milestones: Magic OK, GDT, IDT, PIC, PMM, PAGING, HEAP, CPIO, VFS,
INITRD, TSS. Each appears as white-on-blue text.

If the multiboot2 magic check fails, display the received magic value
in red-on-white on screen and halt (instead of silently returning).

This helps diagnose if GRUB matched the multiboot1 header instead.
On UTM/Mac, GRUB may report a RGB framebuffer while the actual display
is in VGA text mode (0xB8000). The early VGA canary confirms text mode
works. Override fb_info to EGA_TEXT before init_drivers() so vga_init()
uses the correct text buffer instead of writing to an invisible pixel
framebuffer.

Also add EARLY_PRINT markers for SYSCALL, KBD, PROC, DRV stages.
The PS/2 keyboard controller flush loop could hang infinitely on some
VMs (UTM) where the controller keeps reporting data. Add a 1024-byte
timeout to prevent the kernel from hanging during keyboard_init().

Also add debug prints showing flush progress for diagnostics.
Author
Owner

Opus fixed the vga output, and PS/2 keyboard works. But the background is now permanently blue instead of black...
Oh well /shrug

Opus fixed the vga output, and PS/2 keyboard works. But the background is now permanently blue instead of black... Oh well /shrug
seeseemelk added 3 commits 2026-02-23 15:09:23 +01:00
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.
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).
- 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
Author
Owner

The cd command did not work properly. It always interpreted the path as absolute path, creating invalid PWD env vars. I asked Opus to fix this, and now it works properly.

The `cd` command did not work properly. It always interpreted the path as absolute path, creating invalid `PWD` env vars. I asked Opus to fix this, and now it works properly.
seeseemelk added 1 commit 2026-02-23 15:46:33 +01:00
Sysfs:
- New VFS driver mounted at /sys that lets kernel drivers expose
  virtual text files via namespace registration
- Drivers call sysfs_register(name, ops, ctx) with list/read/write
  callbacks for their namespace
- IDE driver registers 'ide' namespace exposing per-device attributes:
  model, type, channel, drive, sectors, sector_size
- Tested: ls /sys -> ide, ls /sys/ide -> hdd1 cd1,
  cat /sys/ide/hdd1/model -> QEMU HARDDISK

Syscalls:
- Added SYS_OPEN (11) and SYS_CLOSE (12) for file I/O from userspace
- Extended SYS_READ/SYS_WRITE to handle VFS file descriptors (fd >= 3)
- Updated userspace syscalls.h with open()/close() wrappers

Apps:
- New 'cat' app: reads and displays file contents via open/read/close
- Updated 'ls' to accept path argument via ARG1 env var
- Updated shell to pass ARG1 env var to external commands
seeseemelk added 1 commit 2026-02-23 15:53:58 +01:00
- 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
Author
Owner

I have to steer it again as no devices are showing up in /dev. Also, I created a release cause I thought the current version is pretty neat.

I have to steer it again as no devices are showing up in `/dev`. Also, I created a release cause I thought the current version is pretty neat.
seeseemelk added 5 commits 2026-02-24 08:01:51 +01:00
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.
The devicefs subsystem already has full character device support:
- devicefs_char_ops_t with read/write callbacks
- devicefs_register_char() registration function
- VFS read/write delegation to char ops
- VFS_CHARDEV type in readdir/finddir results
Create a user-space diskpart utility that can view and modify MBR
partition tables on block devices accessible through /dev.

Features:
- list: displays all 4 partition slots with type, LBA start, size
- create <slot> <type> <start> <sectors>: creates a new partition
- delete <slot>: removes a partition entry
- activate/deactivate <slot>: sets or clears the bootable flag

The tool reads sector 0 (MBR) via VFS open/read, modifies the
partition table in memory, then writes it back via open/write.
Supports hex type codes and provides human-readable type names
for common partition types (FAT12/16/32, Linux, NTFS, etc.).

Usage: diskpart hdd1 create 1 0C 2048 14336
       diskpart hdd1 list
       diskpart hdd1 delete 2
Create a user-space utility that formats block devices with FAT32.
Writes all required on-disk structures sequentially:

- Boot sector (BPB) with BIOS Parameter Block at sector 0
- FSInfo sector at sector 1 with free cluster count/hint
- Backup boot sector at sector 6, backup FSInfo at sector 7
- Two FAT tables with entries 0-2 initialized (media marker,
  EOC markers, root directory cluster EOC)
- Root directory cluster with volume label entry

Geometry calculation:
- Sectors per cluster chosen based on volume size (1-32)
- FAT size computed using Microsoft's formula
- Supports volumes from 128 sectors (~64K) upward

Usage: mkfs.fat32 hdd1mbr1 14336 [LABEL]
The total sector count is required since there is no stat() syscall
yet. Users can find it via 'diskpart <dev> list'.

Also checked off diskpart in README (committed previously).
seeseemelk added 8 commits 2026-02-24 08:52:07 +01:00
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'.
- Created src/e3c509.h: full windowed register model (8 windows),
  command codes, status/interrupt bits, RX filter, transceiver types,
  device struct and API declarations
- Created src/e3c509.c: full driver implementation with PIO TX/RX,
  window selection, 10base-T (RJ45) transceiver config, MAC address
  read from Window 2, FIFO-based packet send/receive, IRQ handler,
  devicefs char device registration as 'eth' class
- Probe uses manufacturer ID check (0x6D50 at Window 0)
- Only 10base-T supported per design requirements
- Wired IRQ 10 (vector 42) handler into isr.c
- QEMU does not emulate 3C509 ISA, so driver correctly probes
  'not found' in QEMU; tested alongside NE2000 without issues
- Created src/ethernet.h: eth_iface_t interface struct, Ethernet header
  type, htons/ntohs/htonl/ntohl byte-order helpers, EtherType constants,
  send/recv with automatic header construction/stripping
- Created src/ethernet.c: interface table, char device ops routed
  through ethernet layer, sysfs /sys/net namespace exposing per-iface
  mac/ip/netmask/gateway/link files, IPv4 address parse/format
- NE2000 and 3C509B drivers now register through ethernet_register()
  instead of directly via devicefs_register_char(); removed redundant
  char device ops from both drivers
- Kernel calls ethernet_init() before init_drivers() so the subsystem
  is ready when NIC drivers probe
- Tested: NE2000 detected with NIC, 'eth1' registered via ethernet
  subsystem; clean boot without NIC
- Created src/ipv4.h: IPv4 header struct, protocol numbers, checksum,
  address conversion (ipv4_aton/ntoa), send/receive/routing API,
  protocol handler registration
- Created src/ipv4.c: packet construction with header checksum,
  simple routing (direct subnet + gateway), incoming packet validation
  and dispatch to registered protocol handlers
- Created apps/ip/ip.c: displays network interface config from
  /sys/net (MAC, link, IP, netmask, gateway); supports 'ip set'
  to configure interface via sysfs writes
- Added ipv4.c to kernel build, kernel calls ipv4_init() at boot
- Tested: clean boot, IPv4 initialized, ip app in CPIO
- Created src/arp.h: ARP packet struct, cache entry struct, operation codes,
  lookup/request/resolve/receive API, sysfs registration
- Created src/arp.c: ARP cache with 32 entries, request/reply handling,
  ARP response to incoming requests for our IP, sysfs /sys/arp/table
  with formatted IP/MAC/interface/state columns
- Created apps/arp/arp.c: reads and displays /sys/arp/table
- Kernel calls arp_init() at boot, registered sysfs 'arp' namespace
- Tested: clean boot, ARP initialized, arp app in CPIO
- Created src/dhcp.h: DHCP packet struct, lease info struct, message types,
  options codes, client states, discover/receive/get_lease API
- Created src/dhcp.c: DHCP client with DISCOVER/OFFER/REQUEST/ACK flow,
  manual IP+UDP header construction for broadcast, option parsing for
  subnet mask/router/DNS/lease time/server ID, lease table, auto-applies
  configuration to ethernet interface on ACK, sysfs /sys/dhcp/status
- Created apps/dhcp/dhcp.c: reads /sys/dhcp/status to display DHCP info
- Kernel calls dhcp_init() at boot
- Tested: clean boot, DHCP initialized, dhcp app in CPIO
seeseemelk added 3 commits 2026-02-24 09:12:02 +01:00
This pull request can be merged automatically.
You are not authorized to merge this pull request.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin attempt-2:attempt-2
git checkout attempt-2
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: seeseemelk/claude-os#2