This release promotes the project to v13 with a repository-wide consistency pass plus stronger release engineering. The main additions are version- and API-consistency validators, benchmark regression/trend tooling, a first pass at vNext desktop app-manifest infrastructure, and three new demo programs.
-
notify_demo.asm— Beginner service-API demo forSYS_NOTIFYandSYS_CLIPBOARD_COPY/SYS_CLIPBOARD_PASTE. Shows notification posting, clipboard round-trip, and simple interactive flow in text mode. -
filepick.asm— Intermediate dialog-service demo forSYS_FILE_OPEN_DLGandSYS_FILE_SAVE_DLG. Opens a file chooser, reads the selected file, previews its first bytes in hex, and writes a saved copy. -
netgraph.asm— Advanced live network latency visualizer. Repeatedly pings a target IP, records RTT samples, and renders a scrolling VGA text-mode bar graph of latency and timeouts.
-
Added version-consistency validation so runtime strings, docs, OCI metadata, and bundled first-party manifest versions can be checked mechanically during
make lint. -
Added benchmark tooling in
tests/bench.shplus benchmark regression and trend analysis helpers. CI now publishes benchmark summaries and raw trend artifacts for review. -
Added generated syscall contract artifacts (
docs/syscalls.jsonanddocs/syscalls.md) and lint checks that fail when generated API references drift fromprograms/syscalls.inc. -
Added app manifest schema and example bundled-app manifests to establish the vNext launcher/permission metadata contract.
- Boot/runtime version strings, documentation current-version references, and OCI package metadata have all been aligned to v13.0.0.
Three new VBE and text-mode programs plus two new C samples completing the Phase 6 demo application batch.
-
life3d.asm— Conway's Game of Life on a 40×20 isometric diamond tilemap (640×480 VBE). Live cells rendered as raised shadow-glow tiles; dead cells as flat dark diamonds. Depth-sorted painter's-algorithm draw order. Wrapping toroidal boundary. Press ESC to quit. -
fft.asm— 16-point DFT spectrum analyser (640×480 VBE bar chart). Implements direct-DFT O(N²) with integer fixed-point twiddle tables (scale=256). Three test signals selectable at runtime: cosine (energy at bins 2 and 14), square wave (odd harmonics), triangle wave (steeper roll-off). Bar height scaled to max magnitude; top-pixel highlight per bar. Keys 1/2/3 switch signal; ESC quits. -
json.asm— Single-pass JSON pretty-printer (text mode). State machine parses compact JSON and re-emits it with 2-space indentation. Handles strings (including backslash escapes), numbers, booleans, null, nested objects and arrays. Accepts optional filename argument; falls back to a hardcoded demo object.
-
json_parse.c— Minimal JSON tokenizer in C. Tokenizes a hardcoded JSON string and prints each token's type name and value. Handles all structural tokens, strings with escape sequences, integers, floats,true/false/null. All-global-variable TCC convention; output viaputchar(). Compile:tcc json_parse.c json_parse -
echo_server.c— TCP echo server. Binds to port 8080, accepts one client at a time, echoes every received byte back, and closes the session on an empty line. Uses__asm__ volatileinline syscall wrappers forSYS_SOCKET/SYS_BIND/SYS_LISTEN/SYS_ACCEPT/SYS_RECV/SYS_SEND. Compile:tcc echo_server.c echo_server· Test:chat 127.0.0.1 8080
New programs and samples: a complete CHIP-8 emulator (programs/chip8.asm),
SHA-256 C implementation, 4×4 matrix multiplication, fixed-point Mandelbrot,
and an HTTP/1.1 request-builder Perl demo. Boot banner updated to v12.2.0.
chip8.asm— Full CHIP-8 emulator (1977 Cosmac VIP ISA, all 35 opcodes). Loads.ch8ROM files; falls back to built-in digits demo. Displays 64×32 at 8× scale (512×256) centred on a 640×480 VBE framebuffer. Full keypad mapping (1-4/Q-R/A-F/Z-V → keys 1-C/4-D/7-E/A-F). ESC to quit.
-
sha256.c— SHA-256 of the hardcoded string"Hello, Mellivora!". Pure C, no stdlib. Implements full message schedule expansion and all 64 compression rounds using global variables (TCC Mellivora convention). Compile:tcc sha256.c sha256 -
matrix_mul.c— 4×4 integer matrix multiplication (O(n³) standard algorithm). Prints matrices A, B, and C=A×B in a formatted grid. Compile:tcc matrix_mul.c matrix_mul -
mandelbrot_fp.c— ASCII Mandelbrot set (70×22) using integer fixed-point arithmetic (scale=256, no floating point). Character palette maps iteration depth to density:" .:-=+*#@"(space is the first character). Compile:tcc mandelbrot_fp.c mandelbrot_fp -
http_get.pl— HTTP/1.1 request builder and response parser demo in Perl. URL parsing (http://host:port/path), request header formatting, status-line / header parsing, and chunked transfer-encoding decoding. Run:perl http_get.pl
kernel/data.inc: boot banner andversion_textupdated from v12.1.0 to v12.2.0.
Kernel correctness patch: background-task exit codes are now propagated correctly, SIGCHLD is delivered to parent tasks on child exit, and the IPC pipe limit is raised from 8 to 32. Six new sample files are added across C, BASIC, and Perl.
Previously sched_exit_task marked the dying task as TASK_ZOMBIE and woke any sys_waitpid
waiter, but never signalled the parent. Two bugs are fixed together:
-
Exit code was always 0:
sched_exit_taskstoredmov dword [edi+TCB_EXIT_CODE], 0unconditionally. The real code fromEBXatsys_exittime was already clobbered by the page-freeing loop. Fix:sys_exitnow savesEBXtobg_exit_code(new BSS dword inkernel/data.inc) before the first push, andsched_exit_taskreads it back.sys_waitpidwake path also fills the waiter's EAX frame slot with the real exit code. -
SIGCHLD never delivered: after the waitpid wake scan,
sched_exit_tasknow readsTCB_PPID, scans the task table for the parent, and sets bit 17 (SIGCHLD) inTCB_SIG_PEND— unless the parent explicitly setSIG_IGNfor SIGCHLD. If the parent is TASK_BLOCKED (inpause/sigsuspend, notwaitpid), it is also woken.
IPC_MAX_PIPES raised from 8 to 32. All bounds checks already use the constant, so no other
code changed. BSS grows by ~384 KB (32 × 16 400-byte pipe structs ≈ 512 KB total). Unblocks
complex shell pipelines with many concurrent stages.
sort.c— selection sort and bubble sort on a 16-element array; demonstrates sorting algorithms with the Mellivora TCC C environment.
mandelbrot.bas— ASCII Mandelbrot set using integer fixed-point arithmetic (scale factor 100); 60×22 character grid.snake.bas— interactive snake game usingLOCATE,INKEY$,DIM,SLEEP, andCOLOR; adjustable-size board; score display.blackjack.bas— blackjack card game with Fisher-Yates shuffle, ace reduction, and dealer hit-on-16 rules.
csv.pl— CSV parser: parse, column-extract, filter by score, and sort by column.regex_demo.pl— 14 regex examples: basic match, anchors, capture groups, named captures, substitution, trimming, grep/filter, split on regex.
v12.1.0 - Architectural correctness sprint: per-task fd isolation, blocking waitpid, W^X trampoline, errno, bug fixes
Corrects eleven architectural and correctness issues identified after the v12.0 POSIX sprint.
No new user-visible syscalls except SYS_GETERRNO (181). Build remains a flat NASM binary.
Per-task file descriptor isolation (kernel/sched.inc, kernel/data.inc, kernel/isr.inc, kernel/syscall.inc)
Previously the global fd_table was shared by all 128 tasks, so concurrent tasks could
corrupt each other's open file state. Each task now has a private 4 KB fd-table page.
TCB_FD_TABLE_PTR(offset 120) — pointer to task's private fd snapshot page.sched_create_task: allocates and zero-fills a 4 KB PMM page, stores it inTCB_FD_TABLE_PTR.sched_exit_task/sched_deliver_signals .sdel_default/sys_kill: all three task-termination paths now free the private fd page.sched_swap_fd_tables— new helper called at every context switch point (irq_timer,sys_yield,sys_sleep,sys_pause,sys_sigsuspend,sys_waitpid): saves the globalfd_tableinto the outgoing task's private page (orshell_fd_tablewhen returning to the shell), then loads the incoming task's private page (orshell_fd_table) intofd_table.shell_fd_table(kernel/data.inc): new 256-byte BSS array holds the shell's own fd snapshot so the shell's state persists across task switches.
Three new fields appended to the TCB:
| Field | Offset | Description |
|---|---|---|
TCB_WAIT_PID |
116 | PID being waited on in sys_waitpid (0 = not waiting) |
TCB_FD_TABLE_PTR |
120 | Physical address of private fd-table page |
TCB_ERRNO |
124 | Per-task errno value |
The previous implementation spun up to 2 000 times calling int 0x80 / SYS_YIELD from
ring-0, which is a no-op on this kernel (PIT only preempts ring-3 code). Ring-3 callers
would effectively hang the system.
- Ring-3 callers are now truly blocked:
TCB_STATE = TASK_BLOCKED,TCB_WAIT_PIDset to the target PID (or -1 for any child), ESP saved inTCB_ESP, and the scheduler immediately switches to the next READY task. If no task is ready, execution returns to the shell (which runs ring-0 and is never preempted). sched_exit_taskscans for anyTASK_BLOCKEDtask whoseTCB_WAIT_PIDmatches the dying child's PID, writes the exit code into its saved[TCB_ESP+28](EAX slot), sets the taskTASK_READY, and clearsTCB_WAIT_PID. The woken task resumes from itsiretdwith the correct exit code in EAX.- Shell (ring-0) callers fall through immediately with -1 if the child is not already a zombie (non-blocking single scan only).
The sigreturn stub (MOV EAX,144; INT 0x80; NOP) was previously written directly to the
user stack on every signal delivery, making the user stack both writable and executable
(W^X violation). The stack is no longer executable in systems that enforce it.
sigreturn_trampoline_init(kernel/paging.inc): allocates one physical page, writes the 8-byte stub, then maps it read-only (PG_PRESENT | PG_USER, noPG_WRITABLE) atSIGRETURN_TRAMPOLINE_VADDR = 0x1FFFF000(last page of the 128–512 MB demand zone). Called frompaging_initafter paging is enabled.sched_deliver_signalsnow sets[new_esp + 0] = SIGRETURN_TRAMPOLINE_VADDRinstead of a stack-local return address, and zeros the previously-used stub bytes[new_esp+24..31].
- New syscall 181
SYS_GETERRNO: returnsTCB_ERRNOfor the running task (0 from shell). - Errno constants added to
kernel.asm:ENOENT=2,EBADF=9,ENOMEM=12,EACCES=13,EFAULT=14,EINVAL=22,EMFILE=24,ENOTTY=25,ENOSYS=38.
- Added
cmp ebx, FD_MAX; jge .fcntl_badfbounds check at entry. F_GETFLandF_SETFLnow checkFD_FLAG_CLOSEDand return -1 for closed fds.
TIOCGWINSZ: callsvalidate_user_ptr(EDX)before writingwinsizestruct. A null or out-of-range pointer now returns -1 instead of faulting or corrupting kernel memory.- Unknown ioctl requests now return -1 (was 0, masking errors from callers).
sys_mmap: aligned byte length is now right-shifted by 12 (shr eax, 12) before passing topmm_alloc_pages, which expects a page count, not a byte count.sys_munmap:EAX = EBX(address) andECX = page countare now set correctly before callingpmm_free_pages. Previous code had a no-opmov ebx, ebxand left EAX/ECX undefined.
When the new size is smaller than the current size, excess HBFS blocks are now freed:
if new_block_count < old_block_count:
hbfs_free_blocks(start_block + new_count, old_count - new_count)
fd_entry[block_count] = new_block_count
fd_entry[size] = new_size
Previously a stub (jmp sys_recv) that silently dropped the from* argument. Now a full
implementation: performs the same receive logic as sys_recv, then—if EDI (the from*
pointer) is non-null and passes validate_user_ptr—fills a sockaddr_in with
AF_INET, SOCK_REMOTE_PORT, and SOCK_REMOTE_IP from the socket struct.
This release makes a major step toward POSIX compliance by adding 36 new system calls covering FD operations, session management, signal extensions, environment queries, identity management, networking extensions, and terminal (termios) control.
TCB_SIZE grows from 88 to 116 bytes. Seven new fields:
| Field | Offset | Description |
|---|---|---|
TCB_EUID |
88 | Effective UID |
TCB_EGID |
92 | Effective GID |
TCB_SID |
96 | Session ID |
TCB_UMASK |
100 | File creation mask |
TCB_ITIMER_VAL |
104 | Interval timer current value (ticks) |
TCB_ITIMER_INT |
108 | Interval timer interval (ticks) |
TCB_SAVED_MASK |
112 | Saved signal mask (for sigsuspend) |
sched_create_task initialises: EUID=UID, EGID=GID, SID=own PID, UMASK=022, itimer fields=0.
sys_fork child inherits EUID/EGID and clears itimer and saved mask.
sched_wake_sleepers: added guardTCB_WAKEUP==0 → skipso tasks blocked indefinitely (viapause/sigsuspend) are not prematurely woken by the clock.sys_signalwake path: when a non-SIGKILL/non-term signal is delivered to aTASK_BLOCKEDtask (e.g. sleeping inpause), the task is setTASK_READYso it gets scheduled andsched_deliver_signalsfires.sched_check_itimers: new function, called fromirq_timeraftersched_check_alarms, decrementsTCB_ITIMER_VALfor each non-free task; when it reaches 0, sets SIGALRM pending, wakes blocked tasks, and reloads fromTCB_ITIMER_INT(0 = one-shot, disarm).
| # | Name | Description |
|---|---|---|
| 145 | SYS_FSTAT |
stat an open fd → fills 12-byte stat_buf |
| 146 | SYS_FTRUNCATE |
truncate file by fd to new size (in-memory) |
| 147 | SYS_FCHMOD |
change mode by fd (stub, accepted) |
| 148 | SYS_FCHOWN |
change owner by fd (stub, accepted) |
| 149 | SYS_FSYNC |
flush fd to storage (write-through, no-op) |
| 150 | SYS_LINK |
hard-link: creates new dirent sharing same blocks |
| 151 | SYS_ISATTY |
returns 1 for fd 0–2 (stdin/stdout/stderr) |
| # | Name | Description |
|---|---|---|
| 152 | SYS_SETSID |
create new session (fails if already group leader) |
| 153 | SYS_GETSID |
get session ID by PID (0 = self) |
| 154 | SYS_WAIT |
reap any zombie child (WNOHANG semantics) |
| 155 | SYS_PAUSE |
block until any signal arrives (returns −1/EINTR) |
| 156 | SYS_UMASK |
set/query file creation mask; pass 0xFFFFFFFF to query |
| # | Name | Description |
|---|---|---|
| 157 | SYS_SIGPENDING |
write pending unblocked signals to caller's sigset |
| 158 | SYS_SIGSUSPEND |
atomically set mask, block until signal; restores old mask |
| 159 | SYS_SETITIMER |
set/query ITIMER_REAL interval timer (usec precision, 100 Hz) |
| 160 | SYS_GETITIMER |
query ITIMER_REAL current value |
| # | Name | Description |
|---|---|---|
| 161 | SYS_SETENV |
set/add environment variable with optional overwrite |
| 162 | SYS_UNSETENV |
remove environment variable |
| 163 | SYS_UNAME |
fill utsname: Mellivora / 12.0.0 / i386 |
| 164 | SYS_UTIME |
update file mtime (utimbuf or current timestamp) |
| 165 | SYS_SYSCONF |
query _SC_* constants: ARG_MAX, CLK_TCK, OPEN_MAX, etc. |
| # | Name | Description |
|---|---|---|
| 166 | SYS_SETEUID |
set effective UID (root or matching real UID allowed) |
| 167 | SYS_SETEGID |
set effective GID |
| 168 | SYS_SETREUID |
set real+effective UID (−1 = keep current) |
| 169 | SYS_SETREGID |
set real+effective GID |
| # | Name | Description |
|---|---|---|
| 170 | SYS_SENDTO |
send with optional UDP destination; delegates to sys_send |
| 171 | SYS_RECVFROM |
receive; delegates to sys_recv |
| 172 | SYS_SETSOCKOPT |
set socket option (SO_REUSEADDR stored, rest accepted) |
| 173 | SYS_GETSOCKOPT |
get SO_TYPE (SOCK_STREAM/SOCK_DGRAM) |
| 174 | SYS_GETSOCKNAME |
return local sockaddr_in (local port, 0.0.0.0) |
| 175 | SYS_GETPEERNAME |
return remote sockaddr_in |
| 176 | SYS_SHUTDOWN |
close one or both socket halves (SHUT_RD/WR/RDWR) |
| # | Name | Description |
|---|---|---|
| 177 | SYS_TCGETATTR |
return cooked-mode termios for fd 0–2 |
| 178 | SYS_TCSETATTR |
store termios in tty_termios shadow (fd 0–2) |
| 179 | SYS_TCDRAIN |
no-op (write-through I/O) |
| 180 | SYS_TCFLUSH |
no-op |
SYS_FSTAT=145 … SYS_TCFLUSH=180, plus: _SC_ARG_MAX, _SC_CLK_TCK, _SC_OPEN_MAX,
_SC_PAGESIZE, ITIMER_REAL, SHUT_RD/WR/RDWR, AF_INET, termios flag constants.
tty_termios: 36-byte BSS buffer fortcsetattr/tcgetattrshadow.
-
TCB_SIG_HAND(kernel/sched.inc) — new TCB field (offset 84) holds a pointer to a lazily-allocated 4 KB PMM page used as a 32-dword handler table (one slot per signal).TCB_SIZEgrows from 84 to 88 bytes. Child tasks start withTCB_SIG_HAND = 0(table not yet allocated);sys_forkclears the field so children inherit only default actions, not handler function pointers. -
SIG_DFL/SIG_IGN— new constants (sched.inc/syscalls.inc).SIG_DFL = 0means restore the kernel default action;SIG_IGN = 1silently discards the signal. -
sched_deliver_signals(kernel/sched.inc) — called byirq_timerevery context switch withEBX = TCB pointerandEDI = iretd frame base address. For each pending, unmasked signal it builds a 28-byte signal frame on the user stack:[new_esp + 0] return address → points to inline sigreturn stub [new_esp + 4] signum (cdecl argument) [new_esp + 8] saved EIP (interrupted ring-3 EIP) [new_esp + 12] saved EFLAGS [new_esp + 16] saved ESP (original user stack pointer) [new_esp + 20] stub: MOV EAX,144 / INT 0x80 / NOP (8 bytes)The iretd frame
EIP3is redirected to the user handler andESP3is set tonew_esp. When the handler returns it lands on the stub which transparently invokessys_sigreturn. Default actions: SIGKILL/SIGTERM/SIGINT → terminate task; SIGTSTP → pause; SIGCONT → no-op; all others → terminate. -
irq_timer(kernel/isr.inc) — updated to callsched_deliver_signalson both the "stay on current task" and "switch to new task" paths before performingiretd.
SYS_SIGACTION(143) — install or query a signal handler.EBX = signum,ECX = handler (fn ptr / SIG_DFL / SIG_IGN),EDX = ptr to receive old handler (or 0). Validates signum, rejects SIGKILL. Allocates the 4 KB handler table on first use (zero-filled = all SIG_DFL). Returns 0 on success, -1 on error.SYS_SIGRETURN(144) — return from a signal handler. Called automatically by the inline stub on the user stack. Restores the saved EIP, EFLAGS, and ESP from the signal frame, discarding the signal stack entirely. No user arguments needed.
- AHCI SATA driver (
kernel/ahci.inc) — full AHCI HBA detection via PCI scan; maps one AHCI port (first populated port found), initialises command-list / FIS / command-table in PMM-allocated memory, and exposesahci_read_sectors,ahci_write_sectors, andahci_flush.ahci_presentflag lets VFS/HBFS fall back to legacy ATA when no AHCI controller is available. - Intel e1000 NIC driver (
kernel/e1000.inc) — probes PCI for common Intel GbE device IDs (82540EM, 82545EM, 82543GC, 82544GC); reads MAC fromRAL0/RAH0; initialises 8 TX and 8 RX descriptors with 2048-byte buffers; hooks into the existingnet_send_framedispatcher (NIC_TYPE_E1000 = 2). - GDB remote stub (
kernel/gdbstub.inc) — hooks INT 1 (single-step) and INT 3 (breakpoint) viaidt_set_gate; implements the GDB RSP packet protocol over COM1 (blocking I/O); supports?,g,G,p,P,m,M,c,s,Z0,z0, andkcommands; 32 software breakpoint slots; 1024-byte packet buffer.
trap— demo that installs a SIGUSR1 handler viaSYS_SIGACTION, prints its PID, sleeps in a loop, and prints a message each time the signal is delivered. Exits after three received signals. Useful for testing the signal delivery path end-to-end.
programs/syscalls.inc— new constantsSYS_SIGACTION = 143,SYS_SIGRETURN = 144,SIG_DFL = 0,SIG_IGN = 1.- Syscall table now has 144 defined entries (was 142).
- UEFI bootloader (
boot/uefi_loader.c) — PE32+ EFI application built with gnu-efi; detects UEFI vs BIOS at boot time, sets up GOP framebuffer, memory map, and hands off to the kernel via aBOOT_INFOstruct.make uefiproducesboot/uefi_loader.efi;make run-uefilaunches QEMU with OVMF firmware and a GPT/FAT ESP image. - x86-64 long-mode path (
stage2.asm) — Stage 2 now optionally transitions to 64-bit long mode when compiled with-DKERNEL_64BIT=1(make 64bit). PAE paging, GDT64, and a minimal long-mode entry stub are conditionally assembled; the 32-bit protected-mode path is unchanged. BOOTINFO_UEFI_MAGIC/UEFI_BOOT_MAGIC— kernel detects UEFI vs BIOS at runtime by inspecting the boot-info magic passed from Stage 2.
- VFS abstraction layer — unified
vfs_open / vfs_read / vfs_write / vfs_readdir / vfs_stat / vfs_mkdir / vfs_unlinkfront-ends dispatch to pluggable backend drivers via a mount table (up to 8 mounts,VFS_MAX_MOUNTS). - Four built-in backends — HBFS (
/), procfs (/proc), devfs (/dev), tmpfs (/tmp). - procfs —
/proc/uptime,/proc/meminfo,/proc/version,/proc/cpuinfo, and/proc/<pid>/status(reports task name from TCB). - devfs —
/dev/null,/dev/zero,/dev/random(LCG),/dev/tty(serial loopback). - tmpfs — in-memory files backed by PMM pages; up to
TMPFS_MAX_FILESentries. /dev/full— new devfs node (DEV_FULL); reads return zero bytes (like/dev/zero), writes always return -1 (ENOSPC simulation); enumerated byvfs_dev_readdir.- 64 virtual file descriptors (
VFS_MAX_FDS,VFD_SIZE = 32) per system (expanded from per-process FD_MAX = 8 for legacy syscalls). - VFS-aware shell navigation —
cmd_cd_internal(.cd_enter_subdir) now recognises/proc,/dev, and/tmpas valid virtual-directory targets at root level; setscurrent_dir_lba = 0xFFFFFFFF(sentinel) sobuild_cwd_pathproduces e.g./procwhichvfs_routecorrectly dispatches to procfs. Guard at the top of.cd_enter_subdirprevents HBFS ATA reads when the CWD is a virtual directory. - VFS-aware
ls—cmd_list_dirdetects the0xFFFFFFFFsentinel LBA and, instead of callinghbfs_load_root_dir, iteratesvfs_readdirin a loop to list entries from the active VFS backend (procfs, devfs, or tmpfs).
- File permissions (
HBFS_DE_MODE) — Unix-style 12-bit mode field in every directory entry;hbfs_check_permission(EBX=dirent, ECX=requested)enforces owner/group/other rwx bits. - Extended attributes (
HBFS_DE_XATTR_LBA,HBFS_DE_XATTR_COUNT) — each file can have an xattr block holding up toHBFS_XATTR_PER_BLOCKkey/value pairs;hbfs_xattr_getandhbfs_xattr_setare the kernel API;SYS_GETXATTR (141)/SYS_SETXATTR (142)expose them to user-space programs.sys_setxattrupgrades the on-disk filesystem from v2 to v3 and setsHBFS_FEAT_XATTRin the superblock on first use.sys_getxattrchecks the feature flag and returns -1 on a filesystem that has never written any xattrs. - Feature flags (
HBFS_SB_FEATURES) —HBFS_FEAT_JOURNAL(existing),HBFS_FEAT_XATTR,HBFS_FEAT_PERM; superblock validated on mount. - Dirent layout v3 — new constants
HBFS_DE_NAME=0,HBFS_DE_TYPE=253,HBFS_DE_SIZE=256,HBFS_DE_BLOCK=260,HBFS_DE_MTIME=272,HBFS_DE_MODE=276,HBFS_DE_XATTR_LBA=280,HBFS_DE_XATTR_COUNT=284; entry size raised toHBFS_DIR_ENTRY_SIZE = 288. hbfs_xattr_setkey-update fix — the scan loop now performs a realrepe cmpsbkey comparison against each occupied slot; on a match the value field is updated in-place instead of creating a duplicate entry (previously the comparison was a no-op stub). Stack-offset bugs in the new-slot write path (wrong frame offsets forkey_ptrandval_ptrafter two intermediate pushes) are also corrected; key and value pointers are now saved to static locals (hxs_key_ptr,hxs_val_ptr) immediately afterpushadto avoid frame-offset arithmetic errors.sys_defragPhase 2 — block relocation (SYS_DEFRAG = 104) — replaces the v9 stub that only counted fragmentation. For each non-free, non-directory directory entry the defragmenter scans the bitmap for the lowest free contiguous run entirely before the file's current start block; if found it copies all file sectors usinghbfs_block_bufas a 512-byte staging buffer, updates the bitmap (destination bits set before source bits cleared to prevent double-use), and writes the new start block back to the directory entry. Phase 1 fragmentation counting is retained; EAX returns the frag-run count measured before relocation. Bitmap and root directory are flushed to disk, and the superblock is journalled on HBFS v2+ volumes.- Journal version check fix — all journal entry points (
hbfs_journal_begin,hbfs_journal_log_sector,hbfs_journal_commit, andsys_defrag) previously accepted onlyHBFS_VERSION_V2exactly. Comparisons changed tojb HBFS_VERSION_V2so that v3 filesystems receive identical journal protection; v1 volumes continue to skip the journal.hbfs_initlikewise usesjbso v3 mounts trigger journal-recovery scanning on unclean shutdown.
- 142 syscalls — table extended to 256 entries; new POSIX-compat range 116–142:
SYS_DUP (116),SYS_DUP2 (117),SYS_FCNTL (118),SYS_IOCTL (119),SYS_MMAP (120),SYS_MUNMAP (121),SYS_MPROTECT (122),SYS_SELECT (123),SYS_CLOCK_GETTIME (124),SYS_NANOSLEEP (125),SYS_GETTIMEOFDAY (126),SYS_GETUID (127),SYS_SETUID (128),SYS_GETGID (129),SYS_SETGID (130),SYS_GETEUID (131),SYS_GETEGID (132),SYS_ACCESS (133),SYS_PIPE2 (134),SYS_SURFACE_CREATE (135),SYS_SURFACE_COMMIT (136),SYS_SURFACE_DESTROY (137),SYS_SURFACE_MOVE (138),SYS_SURFACE_RESIZE (139),SYS_ALARM (140),SYS_GETXATTR (141),SYS_SETXATTR (142).
SYS_CHMOD (68)/SYS_CHOWN (69)upgraded to v3 — syscall table entries 68/69 now dispatch tosys_chmod_v3/sys_chown_v3, which perform a real read-modify-write of the on-disk directory sector viahbfs_flush_dir_entry; they also auto-upgrade the superblock toHBFS_VERSION_V3and setHBFS_FEAT_PERMSon first use.SYS_GETXATTR (141)/SYS_SETXATTR (142)— user-space interface to the HBFS v3 xattr kernel API (hbfs_xattr_get/hbfs_xattr_set). Both validate all three user pointers before touching filesystem state.SYS_SETXATTRupgrades the filesystem to v3 and setsHBFS_FEAT_XATTRin the superblock on first use; the updated directory entry (with newXATTR_LBA/XATTR_COUNT) is persisted viahbfs_save_root_dir.programs/syscalls.inc— constant definitions for all 142 syscalls.SYS_NANOSLEEP (132)improved — now delegates tosys_sleepafter converting the timespec to PIT ticks (100 Hz); usesTASK_BLOCKED+sched_wake_sleeperswhen the scheduler is active, falls back to ahlt-loop in single-task context.SYS_MPROTECT (123)real PTE walk — replaces previous stub; walks the two-level page directory (PDI = virt >> 22, PTI = (virt >> 12) & 0x3FF) for every page in the requested range; sets/clearsPG_WRITABLEandPG_PRESENTin each PTE according to thePROT_READ / PROT_WRITE / PROT_EXEC / PROT_NONEflags; issuesinvlpgafter each PTE update; returnsEFAULTif any page is not present.SYS_GETUID/GETEUID/GETGID/GETEGID/SETUID/SETGID— syscalls now read and writeTCB_UID/TCB_GIDfields in the running task's TCB;setuid/setgidenforce POSIX rules (root UID == 0 may set any value; non-root may only re-set their own ID).
- PMM buddy coalescing (
pmm_free_coalesce) — when a page (or page range) is freed, the allocator now searches the free list of the same buddy order for the freed block's buddy partner (XOR of page number with1 << order). On match the buddy is unlinked and the merged block is promoted toorder + 1and the coalesce loop repeats up toBUDDY_ORDERS - 1; bitmap bits are cleared as part of the same operation.pmm_free_pageandpmm_free_pagesboth callpmm_free_coalesceinstead ofpmm_push_free_block, resulting in maximal free-block consolidation at every free. - Multi-user TCB fields —
TCB_UID = 72,TCB_GID = 76added to the Task Control Block;TCB_SIZEraised from 72 to 80 bytes. New tasks inherit UID/GID = 0 (root) via the existingrep stosdzero-initialisation insched_create_task. TCB_ALARMfield +sys_alarm(SYS_ALARM = 140) —TCB_ALARM = 80stores a PIT tick deadline (0 = no alarm);TCB_SIZEraised to 84 bytes.sched_check_alarms()is called fromirq_timeron every tick and setsTCB_SIG_PEND |= (1 << SIGALRM)when the deadline is reached, then clearsTCB_ALARM.sys_alarm(seconds)programs the alarm and returns the number of seconds remaining before any previously-set alarm would have fired (0 if none); passing 0 cancels any pending alarm. Child tasks created byforkdo not inherit the parent's alarm.SYS_ALARM = 140added toprograms/syscalls.inc.sys_accessfix (SYS_ACCESS = 133) — corrected three bugs: (1) missinghbfs_load_root_dircall beforehbfs_find_entry(the directory buffer could be stale); (2) wrongpushad-frame stack offset ([esp+8]= EBP instead of[esp+24]= ECX) used to read the POSIX mode argument; (3) hardcoded UID = 0 replaced with realTCB_UID/TCB_GIDread from the running task's TCB viasched_get_current_task.
- ICMPv6 echo reply checksum (RFC 4443) —
ipv6_handlenow computes the correct one's-complement checksum over the ICMPv6 pseudo-header (source address, destination address, payload length, next-header = 58) plus the full ICMPv6 payload before transmitting each echo reply; the checksum field at ICMPv6 header offset +2 is written in-place after folding the 32-bit accumulator to 16 bits.
ls -ssort-by-size — new flag tocmd_list_dir; collects pointers to all valid HBFS directory entries intopath_search_buf, insertion-sorts them descending by file size ([entry + 256]), then displays the sorted list in long format (type indicator, right-aligned 9-digit size,YYYY-MM-DD HH:MMtimestamp, filename). Uses index-based array access (path_search_buf + 4 + ebx*4) withpushad/popadregister discipline to avoid clobbering the VGA print register contract under NASM-O0.
- Compositor surface API — kernel-managed pixel buffers (
ipc_surface_table,SURF_MAX = 16); surfaces have id, owner PID, width/height, z-order, position, and a PMM-backed pixel buffer.ipc_surface_create / commit / destroy / move / resizeimplement the five new syscalls. vbe_compositor_refresh— wakes the Burrows compositor task (by PID stored inburrows_compositor_pid) whenever a surface is created, committed, moved, or destroyed.ipc_find_surface— helper to locate a surface entry by ID in O(SURF_MAX) time.
hbpkg— self-contained C tool (compiled bymake hbpkg) to create, inspect, and install.hbpkgarchives. Supportscreate <dir> <pkg>,inspect <pkg>, andinstall <pkg> <dest>subcommands. Header: magicHBPKG, version, file count, and per-file records (path + size + data).
make uefi— cross-compiles UEFI loader via gnu-efi →.so→ objcopy.efi.make run-uefi— creates GPT+FAT ESP image and launches QEMU with OVMF.make 64bit— assembleskernel64.bin+stage2-64.binwith-DKERNEL_64BIT=1.make hbpkg— compilestools/hbpkg.ctotools/hbpkg.make count— now counts.csource files alongside.asm/.inc.
- Buddy allocator —
pmm.incnow implements a two-level buddy system (order 0 = 4 KB, order 9 = 2 MB) on top of the bitmap-based free-page tracker.pmm_alloc_pages(n)andpmm_free_pages(base, n)coalesce buddies on free. Page-fault handler integrated. - Demand paging —
paging.incadds a demand-paging region per process starting atUSER_DEMAND_BASE (0x08000000). Page-fault handler (#PF via IDT vector 14) maps physical pages on first access.
SYS_FORK (103)— duplicates calling process's page-directory, stack, and register state. Returns child PID to parent, 0 to child. Child is immediately runnable. (SYS_EXEC (21)andSYS_WAITPID (92)were already present; both are used byvsh.)
- HBFS v2 journal — 16-entry write-ahead journal records
(block, old_data, new_data)before every metadata write;hbfs_journal_replayreplays or discards on mount. - Defragmenter —
hbfs_defragcompacts live blocks toward LBA 0; exposed asSYS_DEFRAG (104). - Limits raised — max filename length 64 B → 128 B; max open files 8 → 16.
- Virtual desktops — 4 workspaces; Super+1..4 to switch, Super+Shift+1..4 to move a window. Active desktop stored per window; switching hides/shows without destroying state.
- Alpha-blend —
gui_alpha_blend_rect(x, y, w, h, color, alpha)porter-duff over the framebuffer; used for window shadows and notification badges. Fixed 32-bit register usage (sil/dilreplaced withmov+andidiom for 32-bit NASM compatibility). - Edge resize — 6-pixel resize border on all four window edges; cursor changes to resize arrow in border regions.
- 80×24 character cell grid with 200-line scrollback ring buffer.
- ANSI SGR colour (
\e[30m–\e[37mfg,\e[40m–\e[47mbg,\e[0mreset). - PgUp / PgDn scroll through scrollback; Home returns to bottom.
- IPv6 / ICMPv6 — Ethernet type 0x86DD demux;
ipv6_handleprocesses 40-byte fixed header; ICMPv6 echo-request/reply (types 128/129) fully handled. - TLS stub —
SYS_TLS_CONNECT (105): EBX=ip, ECX=port, EDX=handle_ptr → EAX=0/-1. Performs TCP connect then records(ip, port)for subsequent send/recv.
- AC'97 mixer channel: treble, bass, PCM-in gain knobs wired.
- PCM recording:
SYS_AUDIO_REC_START (106),SYS_AUDIO_REC_READ (107),SYS_AUDIO_REC_STOP (108). - Mixer channels:
SYS_AUDIO_OPEN (109),SYS_AUDIO_WRITE (110),SYS_AUDIO_CLOSE_CHAN (111).
- POSIX message queues — kernel-managed pool of 8 queues, 16 messages × 256 B each.
SYS_MSGQ_CREATE (112),SYS_MSGQ_SEND (113),SYS_MSGQ_RECV (114),SYS_MSGQ_CLOSE (115).
chess— VBE 1024×768 chess game with greedy-material AI. Arrow keys to move cursor, Enter to select/place piece, R to reset, ESC to quit.vsh— Veritas Shell: fork/exec model, 24-entry command history (↑/↓), built-inscd,echo,history,uname,help,exit.curl [-X POST] [-d data] host path— HTTP/1.0 GET or POST client over raw TCP. UsesSYS_DNS,SYS_SOCKET,SYS_CONNECT,SYS_SEND,SYS_RECV.rec [-t secs] [-o file]— Records PCM audio viaSYS_AUDIO_REC_*and writes a valid 44-byte RIFF/WAV file.mix file1 file2— Mixes two 16-bit mono WAV files sample-by-sample (clamp to ±32767) and plays the result through an AC'97 mixer channel.
strace— now usesSYS_FORKto trace a child process; highlights fork events in yellow;SYS_WAITPIDloop monitors child exit.
Slots 0–115 fully wired. New additions this release: 103 (fork), 104 (defrag), 105 (tls_connect), 106–108 (audio rec), 109–111 (audio mixer), 112–115 (msgq).
-
kernel/pci.inc— Generic PCI bus enumeration (buses 0–7). Scans all devices/functions, builds a 64-entry device table. Exposespci_find_device,pci_read_config32,pci_write_config32,pci_read_bar. New syscall SYS_PCI_FIND (101): EBX=vendor, ECX=device_id → EAX=bdf or -1. -
kernel/ac97.inc— Intel AC'97 audio controller driver (ICH2/3/4, 8086:2415/2425/2445). Uses PCI Bus Master DMA for playback. Allocates 32-entry Buffer Descriptor List and two 32 KB ping-pong buffers. Falls back gracefully if device absent. Hooks intoSYS_AUDIO_PLAY. -
kernel/atadma.inc— ATA Bus Master IDE DMA extension. Detects Intel PIIX3/4 IDE controller (8086:7010/7111) via PCI, allocates a PRD table and a 4 KB bounce buffer. Providesatadma_read_sectors(up to 8 sectors per call). Falls back to existing PIO path if unavailable. -
kernel/virtio.inc— VirtIO PCI legacy driver (spec 0.9.5).- virtio-blk (1AF4:1001/1042): virtqueue-based block device with
3-descriptor request chains and polled completion.
Provides
virtio_blk_read. - virtio-net (1AF4:1000/1041): negotiation + MAC address read.
- virtio-blk (1AF4:1001/1042): virtqueue-based block device with
3-descriptor request chains and polled completion.
Provides
- Bresenham line —
vbe_draw_line/ SYS_DRAW_LINE (95) - Scanline triangle fill —
vbe_fill_triangle/ SYS_DRAW_TRIANGLE (96) - Sprite blit with color key —
vbe_sprite_blit/ SYS_BLIT (97) - Dirty-rectangle tracking —
vbe_dirty_present/ SYS_DIRTY_PRESENT (98) Maintains the smallest bounding box of modified pixels and bulk-blits only that region from shadow buffer to LFB. - PSF2 bitmap font loader — SYS_PSF_LOAD (99) / SYS_PSF_CHAR (100) Loads any PSF2 font from HBFS (up to 256 KB), renders individual glyphs into the framebuffer.
pci_init,ac97_init,atadma_init,virtio_initcalled fromkernel_entryaftersb16_init, beforeburrows_init.- New includes added in correct dependency order.
more [FILE]— paging text viewer (23 lines/page; SPACE=next, ENTER=line, Q=quit).pciinfo— queriesSYS_PCI_FINDto list all detected PCI devices with bus:device.function addresses.audiodemo— probes SB16 and AC'97 via PCI, plays a PC-speaker melody, then attempts 16-bit PCM playback viaSYS_AUDIO_PLAY.soundviz— SB16 chord sequence (C4, E4, G4) with an animated waveform visualizer on the 640×480 VBE framebuffer.blitdemo— bouncing 16×16 color-keyed sprite via direct shadow-buffer writes.gfxdemo— scrolling rainbow gradient background + bouncing square sprite with title overlay; demonstrates the shadow-buffer flip workflow.gfxplasma— classic sum-of-sines plasma effect rendered as 320×240 → 2×2 blocks on the 640×480 framebuffer.breakout— Breakout/Arkanoid clone: 5 × 10 bricks, three lives, LEFT/RIGHT arrows to move paddle.cube— perspective-projected rotating wireframe cube using 16.16 fixed-point sine tables andSYS_DRAW_LINE.julia— interactive Julia set renderer (arrow keys move c, +/- zoom, R reset).mandelbrot— Mandelbrot set at 640×480×32 bpp; progressive rendering, rainbow escape-time palette.sed [-n] [-e SCRIPT] [SCRIPT] [FILE]— stream editor:s///g,d,p,=,q,y///, line/regex/range addressing.awk [-F SEP] 'PROG' [FILE]— pattern/action processor:$n,NR,NF,print,gsub(),sub(),/regex/,BEGIN/ENDblocks.top— real-time process monitor usingSYS_PROCLIST(all 128 slots) andSYS_MEMINFOwith a used/free memory bar; refreshes every second.tar c|x|t ARCHIVE [FILES]— HBTAR1.0 flat archive: create, extract, list; up to 64 files × 64 KB each.nm FILE [FILE ...]— ELF32 symbol table reader: parsesSHT_SYMTAB/SHT_STRTAB, prints address, type letter (T/D/B/R/U), and name.
- All 16 new programs above added to
man.asmwith full NAME / SYNOPSIS / DESCRIPTION / CONTROLS / SEE ALSO sections.
populate.pypreviously re-added every program binary on everymake full, silently undoing anydelthe user had run inside the OS.- Cache schema bumped to v2 with a new
tombstonesset. Workflow:- On the first
make fullafter adel, populate notices the cached binary is no longer present in the image, records a tombstone, and skips re-adding it. - On subsequent
make fullruns, tombstoned binaries stay gone as long as the source.asm(and therefore the rebuilt.bin) hasn't been touched. - Touching/modifying the source clears the tombstone — the binary is
"revived" automatically. This preserves the developer ergonomics of
"edit
programs/foo.asm, runmake full, see new foo".
- On the first
- Cache also self-prunes tombstones whose
.binhas been removed fromprograms/. - v1 (flat dict) caches are still loaded for backward compat.
themepreviously calledSYS_SETCOLORonce and exited, but every kernel print path immediately restored the hard-codedCOLOR_DEFAULT(0x07), so the selected theme survived only until the next character was printed.- Added a runtime
default_colorbyte andvga_reset_colorhelper.SYS_SETCOLORnow updates both the livevga_colorand the persistentdefault_color, and all ~22mov byte [vga_color], COLOR_DEFAULTsites inkernel/were converted tocall vga_reset_color.vga_clearnow uses the live default color too, so the screen background recolors immediately. - Net effect:
theme amber(or any of the 8 themes) now actually changes the shell, prompt, and subsequent output for the rest of the session.
roll [N | A B]generic random integer (default 1..100, one-arg = 1..N, two-arg = A..B inclusive).pick item1 item2 ...picks one of the supplied tokens uniformly at random.reverse <text>reverses the argument string.upper <text>/lower <text>case conversion.countc <text>printschars / words / linescounts for the argument string.
- Regression suite grows from 1534 to 1576/1576 passing.
stopwatchlap stopwatch (Enter = lap, q = quit); HH:MM:SS.cc precision viaSYS_GETTIME.countdown <secs|Nm|MM:SS>countdown timer with end-of-time beeps and Burrows notification.passgen [len] [-a]random password generator (xorshift32 seeded from time XOR PID);-arestricts to alphanumerics.dice [NdM]roll N dice with M sides; prints individual rolls and sum.coin [N]flip one or more coins; summary heads count when N>1.tip <bill> [pct] [people]bill / tip / split-by-people calculator with cents-precise math.
- Regression suite grows from 1492 to 1534/1534 passing.
tldr <cmd>one-line summary lookup;tldrwith no args lists every entry.todopersistent todo list at/home/.todowithaddanddone <N>.pomodoro [min]focus timer with countdown, three completion beeps, and a desktop notification.morse [-p] <text>ASCII -> Morse (.-/-...); beeps each symbol on the PC speaker unless-p(print only).wiki list|show|add <topic> ...personal knowledge base under/home/wiki/<topic>.txt.colorfull 16x16 VGA attribute palette rendered straight to the framebuffer; press any key to exit.
- Regression suite grows from 1450 to 1492/1492 passing.
- Kernel & runtime:
meminfo— free/total memory, uptime, PID. - Filesystem:
tag— file tagging via/home/.tags.db;add/list/find. - Shell UX:
histgrep— case-insensitive search of shell history. - Burrows GUI:
bnotify— desktop notification with optional-c <attr>. - Burrows app:
bcal— today + scheduled events from/home/.events. - Demo:
plasma— animated text-mode plasma at 0xB8000. - Game:
nim— single-pile misère Nim with optimal AI. - Dev tooling:
mkprog— generates a runnable<name>.asmskeleton. - Networking:
dnslook—SYS_DNSwrapper printing dotted-quad IPs. - Sound:
play— token-driven note sequencer for the PC speaker. - Productivity:
journal— appendsYYYY-MM-DD HH:MMentries to/home/journal.txt. - Polish:
theme— 8 named color themes, persisted to/home/.theme. - Documentation:
tutorial— 8-page interactive welcome tour. - Distribution:
pkginfo— OS / version / arch / RAM / uptime banner.
manrewrite: 49 baked-in topics with case-insensitive lookup,man -llisting andman -k <kw>keyword search; falls back to/docs/man/<topic>.txtif a topic is not baked in.- New man pages added for every program above plus
intro,shell,files,burrows,syscalls,hbfs,keys,credits.
- Regression suite grows from 1352 to 1450/1450 passing.
- VBE / framebuffer: bounds-checked
vbe_putpixeland full rect clipping invbe_fill_rect; mode validation invbe_set_mode(320..1920 × 200..1200, bpp ∈ {16,24,32}); LFB mapping page count derived from the validated mode and capped; shadow buffer pages now freed before reallocation;.fb_drawtextcapped at 4 KB to prevent runaway loops. - Syscall pointer validation: new
validate_user_ptrhelper guards user-supplied pointers insys_print,sys_exec_call, andsys_proclist. Range checked against[PROGRAM_BASE, USER_PTR_MAX). - Paging / PMM:
paging_map_pagenow drops its prologue pushes on the alloc-failure path (was popad'ing with 16 stale bytes on the stack);pmm_alloc_pagescontiguity scan bounded against the bitmap size. - IPC / scheduler: pipe
PIPE_COUNTcheck + cursor update made atomic so concurrent readers/writers can't underflow or over-fill the ring;sys_sigmaskread-modify-write wrapped in CLI/STI. - Drivers: ATA read/write reject LBA outside
[0, ata_total_sectors); RTL8139 driver refuses BAR0 == 0; HBFS filename compare capped at 252 to handle non-NUL-terminated entries; shellCtrl+Wkeepsline_lenin sync with the cursor.
wgethostname / path / outfile copy loops capped at the buffer size (256 / 512 / 128 bytes).programs/lib/vbe.incvbe_fill_rectnow clips againstfb_width/fb_height, mirroring the kernel-side fix.
- Portable
NPROCdetection (nproc→sysctl→getconf→ 4). kernel_sectors.incgeneration hard-fails if the kernel exceeds 2048 sectors (1 MB), preventing silent overflow of the stage-2 load buffer.populate.pynow prints a warning when a filename is truncated to 252 bytes instead of silently shortening.- New
make sanitizetarget builds withKERNEL_DEBUG_BOUNDS=1for CI-style hostile-bounds nightlies. Experimental/tools/packet_fuzz.py— dependency-free fuzz frame generator (Eth runts, ARP/IPv4/TCP/UDP malformations, random garbage) for offline replay againstkernel/net.incparsers.
docs/TECHNICAL_REFERENCE.mdGDT table corrected:0xCFflags row now reads "32-bit, 4K gran" (was mislabelled "64-bit").
-
basicc— new BASIC-to-x86 compiler. Compiles a BASIC source file (.bas) to a flat x86-32 native binary that runs directly on Mellivora OS. Usage:basicc source.bas output.bin. Supports:- Numeric variables A–Z (32-bit integer)
- Full arithmetic:
+,-,*,/,MOD - Bitwise / logical:
AND,OR,XOR,NOT - Relational comparisons:
=,<>,<,>,<=,>= PRINTwith string literals and numeric expressions,;and,separatorsINPUTwith optional prompt stringLET var = exprand barevar = exprassignmentIF ... THEN ... [ELSE ...]with inline statements or line numbersGOTO/GOSUB/RETURN(with forward-reference fixup table)FOR var = start TO end [STEP step]/NEXT(up to 16 nested loops)WHILE ... WEND(up to 64 nested)END,STOP,CLS,BEEP,SLEEP expr- Multi-statement lines via
: REMcomments- Output binary is a self-contained flat x86 executable starting at
0x200000; no runtime library required.
-
samples/fib.bas— Fibonacci sequence sample program forbasicc. -
samples/hello.bas— minimal Hello World sample forbasicc.
basic(v3.1) — upgraded the GW-BASIC interpreter:- Added
TRON/TROFF— execution trace mode prints[linenum]before each statement. - Added
STOP/CONT— stop mid-program and continue. - Added
HEX$(n)andOCT$(n)string functions. - Updated
HELPlisting and version banner to 3.1.
- Added
basic— expanded from a tiny integer-only interpreter into a much larger GW-BASIC-style environment. Added string variables and string functions,LINE INPUT,IF ... THEN ... ELSE,WHILE/WEND,ON ... GOTO/GOSUB,DATA/READ/RESTORE,LOCATE,SWAP,TAB()/SPC(), broader math functions, multi-statement lines with:, aHELPcommand, larger program storage, and improved runtime errors.
pacman,frogger,sudoku— black-screen bug: all three were drawing into the VBE shadow buffer but never callingVBE_GAME_PRESENTto blit it to the live framebuffer. Screen now renders correctly on launch.
reversi— removed from the distribution. The VBE Reversi/Othello experience is covered byiago, which has a full board renderer, greedy-AI opponent, and persistent win counter.
frogger— Classic road-and-river crossing. 11 lanes (5 river + median + 5 road), drifting logs/turtles you must ride, oncoming cars/trucks at varying speeds, 5 home slots to fill. 3 lives, persistent high score saved to/scores/frogger.
galaga— Major arcade-faithful overhaul:- Enemies now dive-bomb out of the formation in attack runs instead of marching wall-to-wall.
- Diving enemies fire bullets that can hit the player.
- Formation gently sways side-to-side as a unit.
- Player respawns with brief invulnerability flicker when hit;
the
livescounter is finally meaningful (game-over only at 0). - Arcade 2-shot limit on player bullets.
- Arcade-style scoring: bug 50, moth 80, boss 150 — double when killed mid-dive.
- Stars now scroll downward for parallax.
- "STAGE N" intro banner between levels.
pacman— Pac-Man-style 21x21 maze chase. Eat dots (10 pts) and power pellets (50 pts) while avoiding 4 ghosts. Power pellets frighten ghosts for ~6 sec, allowing you to eat them (200 pts) and send them back to a corner. Persistent high score saved to/scores/pacman; win/lose SFX cues at end of round.
sudoku— brand-new 9x9 Sudoku puzzle game.- 4-puzzle bank cycled per session via
SYS_GETTIME. - Cursor navigation (arrows), digit entry (1–9), clear (0/Space).
- Real-time row/column/3x3-box conflict highlighting in red.
Hhint key fills one missing cell from the solution.- Persistent solve count saved to
/scores/sudoku; win SFX on solve.
- 4-puzzle bank cycled per session via
Closes the eight-phase Hercules overhaul that began at v6.1. Across
all phases the project gained shared VBE UI libraries, a universal
quit-key sweep, the audio.inc + highscore.inc libraries (v6.5), and
persistent high-score wiring for 28 games. v7.0.0 promotes the
result to a stable release.
- Boot banner,
version_text, and shell help inkernel/data.incupdated from v6.5 → v7.0 ("The Hercules Release"). bsysmon"OS" field,neofetchOS + shell strings, README directory tree, anddocs/INSTALL.mdall bumped to v7.0.- "(v6.5+)" annotations in API docs are kept as historical "added-in" markers for the audio + highscore libraries.
- Full clean rebuild (
make full) populates 203 files cleanly with no NASM warnings. - All 28 wired games still build and link without changes.
- No lingering v3.x / v4.x / v5.x version strings in the live banners.
programs/lib/audio.inc— note table (NOTE_C2..NOTE_C7),audio_note,audio_rest,audio_play_score(byte-packed melody),audio_play_score_w(word-packed for full Hz range), and stock SFX cuesaudio_sfx_click/_ok/_error/_win/_lose. All entry points preserve registers; built onSYS_BEEP(24).programs/lib/highscore.inc—hs_load,hs_save,hs_update. Each game's high score lives in/scores/<name>as a single little-endian dword.hs_updatewrites only when the candidate beats the stored value. The/scoresdirectory is auto-created on first write.
tetris— loads/saves high score, displays "High:" under "Score:" in the HUD, playsaudio_sfx_loseonce on game-over.2048— splits the score panel into SCORE + HIGH boxes, persists high score, plays loss SFX on game-over.snake— addsHIGH:to the score bar, persists high score, plays loss SFX inshow_game_over.breakout— addsHIGH:to the HUD band, persists high score, plays loss SFX once when lives reach 0.simon— showsHIGHline under the SCORE on the game-over banner, persists best round reached, plays loss SFX once.galaga— addsHigh Score:line to the game-over panel, persists high score, plays loss SFX.mastermind— best-game persisted as inverse of guesses-needed (sohs_update's max-wins semantic still picks the better record); win/lose SFX cues. Best record loaded once at start.hangman— runningWINS:counter persisted across runs; win/lose SFX cues fired once per round.tictactoe— persistentWINS:counter (player vs CPU) shown under the header; win/lose/draw SFX cues fired once per game.connect4— wins counter now persists across reboots (loaded into the existing on-screen WINS panel); win/lose/draw SFX cues.reversi— wins (BLACK > WHITE) persist across runs; win/lose/tie SFX cues fired once at end-of-game.wordle— total solved-words counter persists across runs; solve / fail SFX cues.mine(Minesweeper) — total cleared-board wins persist across runs; safe-clear / mine-trigger SFX cues.puzzle15— total solved-puzzles counter persists across runs; win SFX fires once on each solve.lights(Lights Out) — total solved-boards counter persists across runs; win SFX cues on each solve.sokoban— total cleared-levels counter persists across runs; win SFX cues each time a level is cleared.guess(number guessing) — total correct-guess counter persists across runs; win SFX cues on correct answer.battleship— total wins persist across runs; win SFX on victory, lose SFX on defeat.blackjack— total dealer-beating rounds persist across runs; win/lose SFX cues on each settled hand.nim(misere) — total wins persist across runs (saved to/scores/nimafter each AI takes the last); win/lose SFX cues.checkers— total wins (player=red) persist across runs; win/lose SFX cues fired once when the board is decided.iago(Reversi variant, player=BLACK) — total wins persist across runs; win/lose/tie SFX cues fired once at end-of-game.solitaire— total completed games persist across runs; win SFX fires once when all 4 foundations are filled.pipes— high score persists across runs (best score is kept); win/lose SFX cues on flow reaching drain or going dry.lunar— total safe landings persist across runs (saved to/scores/lunarafter every soft touchdown); win SFX on safe landing, lose SFX on crash.kingdom— best end-of-reign score persists across runs; win fanfare SFX on completing 10 years, lose SFX on collapse.rogue— best XP persists across runs (written when the player dies); lose SFX on death.outbreak— best total-vaccinated count persists across runs; win SFX on outbreak defeated, lose SFX on collapse.
- Now scans all 128 scheduler slots (was 16) and uses the v4.0 expanded
48-byte
SYS_PROCLISTABI: shows newPRI(priority) column and a 16-charNAMEcolumn. - All five live task states have distinct color and label: READY (green), RUNNING (white), BLOCKED (blue), STOPPED (magenta), ZOMBIE (red).
- Footer now prints a state breakdown:
Active: N Running: r Ready: r Blocked: b Stopped: s Zombie: z.
- Live memory —
Memory:now reportsUSED / TOTAL MB (PCT%)fromSYS_MEMINFO(67) plus a 200-pixel horizontal usage bar that turns yellow at ≥70 % and red at ≥90 %. - Uptime — new
Uptime: Hh Mm Ssline derived fromSYS_GETTIMEticks (PIT @ 100 Hz). - Process count — new
Procs: N activeline that walks the 128-slot task table viaSYS_PROCLIST(66). - Auto-refresh — main loop now sleeps 50 ticks (~500 ms) between redraws when no input is pending, so all live values update without user interaction.
- Window resized to 360×340 to fit the new rows;
OS:line bumped to v6.5.
docs/API_REFERENCE.md— added Quick Start entries and reference tables for both new libraries.
Per docs/STYLE_GUIDE.md, every interactive VBE game must accept ESC,
lowercase q, AND uppercase Q to quit. This release brings 24 games
into compliance:
- Added uppercase
Q(already had ESC +q):2048,battleship,blackjack,checkers,chess,connect4,guess,hangman,iago,lights,lunar,mastermind,mine,nim,pipes,puzzle15,reversi,simon,sokoban,solitaire - Added
qandQ(had only ESC):breakout,maze - Added ESC (had
q/Qbut no ESC):pong - Added
Qand converted raw27→KEY_ESCstyle consistency:galaga,rogue,snake - Added
q/Qto main play loop (had ESC only):outbreak(title + action loop),kingdom(title screen)
Demo/screensaver programs (doomfire, matrix, rain, starfield,
spritetest) intentionally retain "press any key to exit" behavior.
Decision: not converting. Both are interactive-fiction text adventures where text-mode terminal flow IS the appropriate medium. Forcing them into a framebuffer would only simulate a terminal inside a pixel surface — strictly worse UX for no gain. Their existing VGA text presentation remains the right call. Future polish will be limited to text-mode banner/prompt consistency.
tictactoe.asm— pilot migration to the shared style infrastructure:- Color literals replaced with
MV_*aliases fromlib/palette.inc. - Title and status text now drawn by
vbe_ui_header_barandvbe_ui_status_barfromlib/vbe_ui.inc. R/rnow restarts the game at any time (not just after game-over), matching the style-guide convention.
- Color literals replaced with
docs/PROGRAMMING_GUIDE.md:- Removed 7 phantom syscall definitions (
SYS_SEM_CREATE,SYS_SEM_WAIT,SYS_SEM_POST,SYS_SEM_CLOSE,SYS_WAITPID,SYS_GETMTIME,SYS_SETMTIME) that were never implemented. - Fixed VBE example resolution from 640×480 to 1024×768 (matches the
actual
VBE_GAME_INITmacro). - Added a new Shared VBE UI Library (v6.1+) section documenting
lib/palette.incandlib/vbe_ui.inc, with cross-reference todocs/STYLE_GUIDE.md. - Updated table of contents.
- Removed 7 phantom syscall definitions (
docs/API_REFERENCE.md:- Fixed VBE example resolution from 640×480 to 1024×768.
- Added
lib/vbe.inc,lib/font.inc,lib/vbe_game.inc,lib/palette.inc, andlib/vbe_ui.incto the Quick Start include list, with a note pointing toSTYLE_GUIDE.md.
docs/INSTALL.md:- Project structure now reflects current state (~290 programs, current version v6.2.0).
docs/INSTALL.md, docs/NETWORKING_GUIDE.md, docs/TECHNICAL_REFERENCE.md,
docs/TUTORIAL.md, docs/USER_GUIDE.md were all reviewed and found to
match the current code state.
NASM -f bin mode places .bss labels past the end of the program binary,
where the kernel loader does NOT zero memory. Variables declared via
resd/resb therefore start with whatever junk was left by the previous
program. Three programs had counters/buffers in .bss that could be
read-before-written; converted them to inline dd 0 / times N db 0 so
they're guaranteed zero at startup:
tetris.asm—fb_addr,fb_pitch,num_buftypist.asm— 14ddcounters +input_buf(MAX_INPUT bytes)bnotes.asm—win_id,cursor_pos,draw_col,note_text
(See docs/STYLE_GUIDE.md §1.2 for the full rule.)
Audited 20+ programs (VBE games, Burrows GUI apps, CLI utilities) for common bug patterns; the following were found to be solid: simon, bedit, bcalc, bsysmon, bpaint, bsheet, bplayer, bsettings, bview, bterm, bhive, grep, sed, sort, cp, find, wget, dig, asm, bc, diff, tictactoe.
The flip-logic in iago.asm was re-audited: logic is correct (the
previously-fixed reversi.asm was the source of the visible flip bug).
tetris.asm— game-over screen now also acceptsQ/qwordle.asm— main loop now also acceptsQ/q
programs/lib/palette.inc: Project-wide color palette. Single source of truth forMV_BG_*,MV_FG_*,MV_ACCENT_*,MV_STATUS_*,MV_CURSOR,MV_BOARD_*and other UI tones. Programs should alias these (e.g.COL_BG equ MV_BG_DARK) instead of hard-coding hex literals.programs/lib/vbe_ui.inc: Shared VBE UI widgets used by all games:vbe_ui_header_bar— top title bandvbe_ui_status_bar— bottom hint bandvbe_ui_modal— centered dialog (game-over, help, info)vbe_ui_input_line— decimal-number input widget
docs/STYLE_GUIDE.md: New authoritative cross-program style guide documenting program skeleton, calling conventions, syscall rules, VBE layout zones, key-binding standards, the flat-binary BSS rule, the CLI conventions, the Burrows GUI conventions, the uppercase-string rule, and the per-commit code-quality checklist.
- Removed stale
.bakfiles:edit.asm.bak,blackjack.asm.bak,tcc.asm.bak,outbreak.asm.bak(~210 KB total).
reversi.asm: Fixed two flip-counting bugs that produced incorrect flips and false "invalid move" rejections.count_dir: dotted-local labels.dr/.dcresolved to the wrong function's locals (always 0). Qualified them as[count_flips.dr]/[count_flips.dc].flip_dir: ECX (the flip counter) was being clobbered by a load ofdo_move.playermid-loop. Wrapped the board write withpush ecx/pop ecx.
- Completed full VGA→VBE conversion (~2400 lines). Replaced text-mode phase
screens, status display, mini-bars, and number input with native VBE
widgets. Migrated from
section .bssto flat-binary safe storage. All game strings uppercased to match the 5×7 bitmap font glyph set.
- Shadow buffer double buffering:
SYS_FRAMEBUF/1(set mode) now allocates a PMM-backed shadow buffer the same size as the framebuffer. Programs render into the shadow buffer (returned bySYS_FRAMEBUF/0) rather than the real LFB, eliminating tearing. SYS_FRAMEBUF/4— present frame: New sub-function blits the full shadow buffer to the LFB with a singlerep movsd. Call once per frame after all rendering is complete.- Size-aware reallocation:
vbe_shadow_pagestracks the allocated page count. When a new mode is set that requires more pages than the current allocation, the shadow buffer is reallocated. Prevents crashes where a 640×480 game's undersized buffer was reused for a 1024×768 program. - Vsync hang fix: Removed the
port 0x3DAvertical-blank poll loop from the present path. The VGA input status register bit 3 does not toggle in QEMU BGA mode, causing an infinite kernel-mode hang. The blit now runs unconditionally.
- New file
programs/sprite.inc: Reusable sprite drawing library for VBE programs.sprite_draw(EBX=x, ECX=y, ESI=sprite_ptr): draw with per-pixel alpha (alpha=0 → skip).sprite_draw_opaque(EBX=x, ECX=y, ESI=sprite_ptr): draw ignoring alpha — fastest path.sprite_draw_key(EBX=x, ECX=y, ESI=sprite_ptr, EDI=key): color-key transparency.sprite_draw_scaled(EBX=x, ECX=y, ESI=sprite_ptr, EDX=shift): nearest-neighbour scale by 2^shift (e.g. EDX=1 → 2×, EDX=2 → 4×).SPRITE_BEGIN name, width, height/SPRITE_ENDmacros for inline sprite data.- Sprite pixel format:
dd width, heightthenwidth*heightpixels as0xAARRGGBB.
- New file
programs/galaga_sprites.inc: Pixel-art sprite data for galaga. Five sprites defined with thesprite.incformat:spr_player(24×16),spr_bug(20×12),spr_moth(20×12),spr_boss(20×12),spr_bullet(3×12). Transparent pixels use alpha=0x00.
- New file
programs/spritetest.asm: Interactive test program demonstrating all foursprite.incroutines side by side in a 640×480×32 VBE window.
programs/galaga.asm: Replaced direct pixel-fill rendering withsprite.inccalls for the player ship, enemy bugs/moths/boss, and bullets. AddedSYS_FRAMEBUF/4present call in the main game loop for double-buffered output.programs/doomfire.asm,programs/life.asm,programs/pong.asm,programs/snake.asm,programs/tetris.asm: AddedSYS_FRAMEBUF/4present call at the end of each frame to make rendered output visible when double buffering is active.
kernel_sectors.inc: CorrectedKERNEL_SECTORSvalue to match actual kernel binary size.
SYS_SEM_CREATE(#88): Create a counting semaphore with an initial value. Returns a semaphore ID (0–7) or -1 on failure.SYS_SEM_WAIT(#89): Decrement (P/wait) a semaphore. If the value is 0, yields up to 500 times before returning -1 (non-blocking style consistent with pipe I/O).SYS_SEM_POST(#90): Increment (V/post) a semaphore.SYS_SEM_CLOSE(#91): Release a semaphore slot.- Up to 8 semaphores simultaneously. Semaphore state initialised in
ipc_init.
TASK_ZOMBIEstate (5): Tasks that callsys_exitnow enter a zombie state instead of being freed immediately, preserving their slot until reaped by a parent.SYS_WAITPID(#92): Wait for a task by PID. Yields up to 2000 times polling for task completion, then reaps the zombie and returns its exit code. Returns -1 if the PID is not found.
SYS_GETMTIME(#93): Query a file's timestamps. Returns packed RTCDIRENT_MODIFIEDtimestamp in EAX andDIRENT_CREATEDtimestamp in ECX.SYS_SETMTIME(#94): Update a file'sDIRENT_MODIFIEDtimestamp. Pass ECX=0 to use the current RTC time.
- Incremental reverse-i-search: Press Ctrl+R at the shell prompt to start an interactive history search.
- Shows
(reverse-i-search)\QUERY': MATCH` while typing. - Backspace removes the last search character and re-searches.
- Enter copies the matched command to the input line and executes it.
- Escape / Ctrl+C cancels and returns to an empty prompt.
if exist FILENAME cmd: Test for file existence. Works with thenotmodifier (if not exist ...).if "STR1"=="STR2" cmd: String comparison. Supportsnotmodifier.- Block
if/else/endif: Multi-line conditional blocks. When anifline has no inline command the following lines form the block body; an optionalelseblock is executed when the condition is false;endifcloses the block. Nestedif/endifpairs are handled correctly. for %%x in (a b c) do cmd: Single-line for loop. Iterates over a space-separated list;%%xin the command template is substituted with each value in turn.elseandendifare now recognised as batch directives inbatch_run_loop.
strace: Syscall trace wrapper. Usage:strace PROGRAM [args]. Records the dmesg ring-buffer depth before running the target program and dumps all new log entries added during the run, providing a lightweight activity trace.patch: Apply unified-style diff output to a file. Usage:patch FILE PATCHFILE. The patch file is the output of thediffutility (<= remove,>= insert). Applies all hunks and reports how many could not be matched.
- Added constants for all v5.0 syscalls:
SYS_SEM_CREATEthroughSYS_SETMTIME(88–94).
- Priority-based scheduling: Replaced round-robin with 4-level priority scheduling (HIGH, NORMAL, LOW, IDLE). Higher priority tasks are selected first; equal priority tasks use round-robin for fairness.
- 64 tasks max: Doubled from 32 to 64 concurrent tasks (
MAX_TASKS). - Expanded TCB: Task Control Block expanded from 32 to 64 bytes with new fields:
TCB_NAME(16 bytes): Human-readable task nameTCB_SIG_PEND/TCB_SIG_MASK: Signal pending/mask bitmasksTCB_PGID: Process group IDTCB_EXIT_CODE: Task exit code
- TASK_STOPPED state: New state (4) for signal-stopped tasks (SIGTSTP/Ctrl+Z).
sys_proclistexpanded: Output buffer expanded from 16 to 48 bytes, now includes priority, PGID, pending signals, exit code, and task name.
- POSIX-style signals: 9 signal types implemented: SIGINT (2), SIGKILL (9), SIGUSR1 (10), SIGUSR2 (12), SIGALRM (14), SIGTERM (15), SIGCHLD (17), SIGTSTP (20), SIGCONT (25).
SYS_SIGNAL(#74): Send any signal to a task by PID. SIGKILL forcibly terminates, SIGTSTP stops, SIGCONT resumes, SIGINT/SIGTERM terminate.SYS_SIGMASK(#77): Get/set/block/unblock signal mask. 4 operations: get, set, block (OR), unblock (AND NOT).- Signal masking: Tasks can mask signals via bitmask; masked signals are queued as pending.
- 8 new syscalls (72–79), bringing total to 80:
SYS_SETPRIORITY(#72): Set task priority by PIDSYS_GETPRIORITY(#73): Get task priority by PIDSYS_SIGNAL(#74): Send signal to taskSYS_SETPGID(#75): Set process group IDSYS_GETPGID(#76): Get process group IDSYS_SIGMASK(#77): Signal mask operationsSYS_TASKNAME(#78): Set task name stringSYS_REALLOC(#79): Reallocate memory block
SYS_REALLOC(#79): New syscall for reallocating memory — allocates new block, copies data, returns new pointer. Supports NULL pointer (fresh allocation).
- Ctrl+A: Move cursor to beginning of line
- Ctrl+E: Move cursor to end of line
- Ctrl+U: Kill entire input line
- Ctrl+W: Delete previous word (skip spaces, then delete word)
- Ctrl+L: Clear screen and redraw prompt with current input
- 128 history entries: Doubled from 64
ps: List all running tasks with PID, state, priority, and namejobs: List background jobs (alias for ps)kill <pid> [signal]: Send signal to task (default: SIGTERM)bg <pid>: Resume stopped task in background (sends SIGCONT)fg <pid>: Resume stopped task in foreground (sends SIGCONT)nice <priority> <command>: Run command at specified priority level (0=HIGH, 1=NORMAL, 2=LOW, 3=IDLE)export NAME=VALUE: Export environment variable (synonym for set)source <file>/. <file>: Execute batch script in current shell context
- 32 environment variables: Doubled from 16
- 128 history entries: Doubled from 64
- All 8 new v4.0 syscall numbers added to shared header
- Priority level constants (PRIO_HIGH through PRIO_IDLE)
- Signal number constants (SIGINT through SIGCONT)
- Version bumped to v4.0.0 "The Titan Release"
- Shell version bumped to HB Lair v3.0
- Updated
veroutput: 80 syscalls, priority scheduler, signal info, enhanced shell shortcuts - Updated
helptext with all new commands and shortcuts
sys_sleepHLT fallback: In v3.0.0 theSYS_SLEEPrewrite made sleep a no-op whentask_count == 0(normal shell / single-program context). This broke 29 programs that useSYS_SLEEPfor timing, animation frame-rates, and CPU-yield poll loops (clock, galaga, doomfire, matrix, rain, ntpd, serial, etc.). Fixed: when no scheduler tasks are running,sys_sleepfalls back to the original HLT-based busy-wait loop so timing is preserved.
pipe_retry_countrace condition: The retry counter insys_pipe_readwas a global static variable (dd 0). Under preemptive multitasking two tasks blocking on separate pipes could clobber each other's count, causing infinite waits. Fixed by moving the counter to a register (EAX) local to each call — the global is removed.
sys_symlinkdead code: Two deadmov edi, ...instructions preceded the correctmov edi, [esp+24]line, producing confusing assembly. Removed the two stale lines; behavior is unchanged.
chmod <octal> <filename>: New shell command wrappingSYS_CHMOD(#68). Parses an octal permission value (e.g.chmod 755 myprog) and updatesDIRENT_PERMS. Returns success/failure message.chown <uid> <filename>: New shell command wrappingSYS_CHOWN(#69). Parses a decimal UID and updatesDIRENT_OWNER.statpermission display: Thestatcommand now shows two additional lines:Perms: rwxrwxrwx (octal)andOwner: <uid>, reading fromDIRENT_PERMSandDIRENT_OWNERrespectively. Previously these fields were stored on disk but never displayed.
- Logo null terminators: Each
logo_artline was 32 bytes with no null terminator.SYS_PRINT(vga_print) scans until null, so every logo line printed the entire remaining logo blob as one continuous string. Fixed by adding a null byte to each line (33 bytes/line) and updating the stride calculation fromshl eax, 5toimul eax, 33. Logo now renders correctly.
- O(1) jump table: Replaced 68-entry linear
cmp/jechain with a 128-entry indexed jump table (jmp [syscall_table + eax * 4]). Average dispatch time reduced from ~34 comparisons to 1 lookup. - Extensible: Reserved slots 72–127 for future syscalls; unused entries point to a safe error handler.
- TASK_BLOCKED state (state 3): New task state for sleeping/waiting tasks, automatically skipped by round-robin scanner.
- sys_sleep (SYS_SLEEP #16): Rewritten from busy-wait
HLTloop to proper blocking — sets TASK_BLOCKED, stores wakeup tick inTCB_WAKEUP, yields CPU to other tasks. - sched_wake_sleepers: Called every PIT tick from
irq_timer; scans all blocked tasks and wakes those whose wakeup tick has elapsed. - TCB_PRIORITY (offset 24) and TCB_WAKEUP (offset 28): New fields replacing reserved padding.
- MAX_TASKS doubled from 16 to 32.
- Non-spinning pipe reads:
sys_pipe_readnow yields CPU up to 200 times when the pipe buffer is empty, instead of immediately returning 0 bytes. Eliminates 100% CPU polling loops in callers. - pipe_wake_waiter stub: Preparation for future proper wait-queue integration on pipe write.
- Timer context switch CLI: Added defensive
CLIbefore the critical ESP-swap section inirq_timer. Prevents potential nested-interrupt corruption if gate type ever changes. - Wake sleepers on tick:
irq_timernow callssched_wake_sleepersevery tick to unblock sleeping tasks.
- Human-readable error codes: Page fault handler now parses error code bits and prints cause:
[not present]/[protection],[read]/[write],[supervisor]/[user].
- File permissions (DIRENT_PERMS, offset 276): 9-bit Unix-style
rwxrwxrwxstored in previously-reserved directory entry bytes. New files default to0777. - File ownership (DIRENT_OWNER, offset 278): 16-bit owner UID per file.
- SYS_CHMOD (#68): Change file permission bits.
- SYS_CHOWN (#69): Change file owner UID.
- SYS_SYMLINK (#70): Create symbolic link (file type
FTYPE_LINK=5, target path stored as file data). - SYS_READLINK (#71): Read symbolic link target path.
- Child socket allocation: When a SYN arrives on a LISTEN socket, a NEW child socket is allocated. The parent stays in
TCP_LISTENfor more connections — enables multiple simultaneous accepts. - TCP SYN_RCVD state handler: Added missing state machine handler for
TCP_SYN_RCVD. When the final ACK of the 3-way handshake arrives, properly transitions child socket toTCP_ESTABLISHED. This fixes a bug where server-side TCP connections could never complete. - Child socket resolution:
tcp_handlenow scans for child sockets matching remote IP/port before dispatching, ensuring handshake packets reach the correct socket. - SOCK_PARENT field (offset 68): Tracks which listening socket spawned each child.
- RFC 768 checksum:
udp_sendnow computes a proper UDP checksum over the pseudo-header (source IP, dest IP, protocol, length) plus UDP header and payload, replacing the previous hardcoded zero.
- syscalls.inc: Added
SYS_CHMOD(#68),SYS_CHOWN(#69),SYS_SYMLINK(#70),SYS_READLINK(#71) for user programs. - Version strings updated across:
neofetch,uname,bterm, screensaver, MOTD, Burrows About dialog.
- All 45 tests passing (syscall consistency, HBFS layout, listing validation).
- 169 files populated in HBFS image.
- Pipes: 8 concurrent pipes, 4 KB circular buffer each, with
SYS_PIPE_CREATE,SYS_PIPE_WRITE,SYS_PIPE_READ,SYS_PIPE_CLOSE(syscalls 60–63). - Shared memory: 4 regions, 4 KB each, keyed access via
SYS_SHMGETandSYS_SHMADDR(syscalls 64–65).
- ISA DMA playback via SB16 DSP (base port 0x220, IRQ 5, DMA channels 1/5).
- Supports 8-bit and 16-bit PCM, mono/stereo, configurable sample rate.
- Three syscalls:
SYS_AUDIO_PLAY(50),SYS_AUDIO_STOP(51),SYS_AUDIO_STATUS(52).
SYS_KILL(53): Terminate a task by PID.SYS_GETPID(54): Get current task PID.SYS_PROCLIST(66): Query task table slots (0–15).SYS_MEMINFO(67): Report free/total physical pages.
- Clipboard:
SYS_CLIP_COPY(55) andSYS_CLIP_PASTE(56) for inter-app text sharing. - Notifications:
SYS_NOTIFY(57) — toast-style notifications with color accent bars. - File dialogs:
SYS_FILE_OPEN_DLG(58) andSYS_FILE_SAVE_DLG(59). - Date setting:
SYS_SETDATE(49) — write to RTC from user programs. - Widget toolkit: 7 sub-functions (button, checkbox, progress bar, textbox, listbox, label, rectangle outline) for GUI_DRAW_BUTTON through GUI_DRAW_RECT (sub-functions 20–26).
- 5 screensaver modes: Starfield (64 parallax stars), Matrix (cascading green columns), Pipes (6 colored growing pipes), Bouncing Logo, Plasma (color-cycling plasma effect).
- Activates after 5 minutes idle.
scrsavershell command to cycle/set mode.
- VBE font restore: Save/restore 8 KB VGA plane 2 font data before/after BGA mode switches. Fixes corrupted text mode characters after exiting Burrows desktop.
- 3D button rendering:
gui_bb_button_3dleft-highlight vline clobbered EDX (button height) with the white color value. This caused 3 spurious dark vertical lines from each window's title bar buttons to the bottom of the screen. Fixed by preserving EDX across the vline call. - HBFS directory caching: Added cache-tag check in
hbfs_load_root_dirto avoid redundant disk reads during PATH searches. - HBFS timestamps: Files now store RTC-based create/modify timestamps in DOS-compatible packed format.
- HBFS symbolic links: File type 5 (
FTYPE_LINK) withln -sshell command andstatresolution.
stat: Display file metadata (type, size, blocks, timestamps, link target).fsck: Filesystem consistency check (bitmap vs. directory cross-validation).whoami: Print current user name.ln: Create symbolic links (ln -s target linkname).scrsaver: Cycle or set screensaver mode.mouse: Show mouse position and button state.- Total: 58 unique commands + 6 aliases = 64 dispatched names.
New games: blackjack, breakout, chess, connect4, freecell, kingdom, mastermind, neurovault, outbreak, pong, puzzle15, raycaster, rogue, simon, solitaire, starfield.
New utilities: asm (in-OS assembler), banner, base64, basename, bcalc, bedit, bforager, bhive, bnotes, bpaint, bplayer, bsettings, bsheet, bsysmon, bterm, bview, cmp, csv, cut, debug, df, diff, dirname, du, expr, factor, find, forth, free, grep, hexdump, id, lolcat, mandel, nl, od, paste, periodic, perl (interpreter), pipes, ps, sed, seq, sort, strings, sysinfo, tac, tcc (C compiler).
- perl: In-OS Perl interpreter supporting variables, arrays, hashes, control flow, string operations, and built-in functions.
- 6 Perl sample scripts:
hello.pl,factorial.pl,fizzbuzz.pl,guess.pl,arrays.pl,strings.pl.
20 new syscalls added (48 → 68 total, numbered 0–67):
| Range | Syscalls |
|---|---|
| 49 | SYS_SETDATE |
| 50–52 | SYS_AUDIO_PLAY, SYS_AUDIO_STOP, SYS_AUDIO_STATUS |
| 53–54 | SYS_KILL, SYS_GETPID |
| 55–56 | SYS_CLIP_COPY, SYS_CLIP_PASTE |
| 57 | SYS_NOTIFY |
| 58–59 | SYS_FILE_OPEN_DLG, SYS_FILE_SAVE_DLG |
| 60–63 | SYS_PIPE_CREATE, SYS_PIPE_WRITE, SYS_PIPE_READ, SYS_PIPE_CLOSE |
| 64–65 | SYS_SHMGET, SYS_SHMADDR |
| 66–67 | SYS_PROCLIST, SYS_MEMINFO |
- All 7 documentation files verified and updated against actual kernel code.
- Fixed outdated statistics across README, USER_GUIDE, INSTALL, TUTORIAL, TECHNICAL_REFERENCE.
- Bootable ISO:
make isoproduces an El Torito no-emulation ISO with full disk image, all 7 docs, README, LICENSE, and CHANGELOG. - Lite ISO:
make iso-litetruncates the 2 GB disk image to 64 MB (~65 MiB ISO vs ~2.1 GiB full) — all HBFS data preserved. - ISO verification:
make iso-verifyvalidates the El Torito boot record and boot-load-size. - ISO launcher:
run_iso.shextracts and boots the ISO with colored output and ASCII banner. - Build script:
build_iso.shrewritten with ANSI-colored status output, pre/post build stats, and SHA256 checksums. - Supports 4 ISO-creation backends: xorriso, genisoimage, mkisofs, hdiutil.
- Disk image: 169 files, 710 blocks across 4 subdirectories
- Kernel: ~28,800 lines of x86 assembly (22 include files)
- Kernel binary: ~550 KB
- Tests: 1,160 (45 build + 1,115 HBFS integrity)
- Syscalls: 68 (0–67)
- Programs: 140 assembly + 11 C samples + 6 Perl samples
The former RTL8139 networking stub has been replaced with a complete, from-scratch TCP/IP stack:
- RTL8139 NIC driver: PCI auto-detect (bus/device/function scan), software reset with timeout, interrupt-driven RX/TX (ISR handles ROK, TOK, RER, TER, LinkChg), 8 KB RX ring buffer with wrap-around, 4 TX descriptors with round-robin rotation.
- Ethernet II: Frame construction and parsing with proper EtherType dispatch (0x0800 IPv4, 0x0806 ARP).
- ARP: Request/reply handling, 16-entry ARP cache with lookup and expiry, gratuitous ARP on interface configuration.
- IPv4: Header construction with checksum, packet reception and protocol dispatch (ICMP=1, UDP=17, TCP=6).
- ICMP: Echo request/reply (ping) with sequence numbering and round-trip time calculation.
- UDP: Connectionless send/receive with port matching, used for DHCP and DNS.
- TCP: Full state machine — SYN → SYN-ACK → ESTABLISHED → data transfer → FIN/FIN-ACK → CLOSED. Sequence/acknowledgment number tracking, 1460-byte MSS, retransmission, connection timeout.
- DHCP client: Complete 4-phase negotiation (DISCOVER → OFFER → REQUEST → ACK) with option parsing for subnet mask, gateway, DNS server, and lease time.
- DNS resolver: UDP-based query construction and response parsing with answer section extraction.
| Syscall | Number | Description |
|---|---|---|
SYS_SOCKET |
39 | Create a TCP or UDP socket |
SYS_CONNECT |
40 | Connect a TCP socket to a remote host:port |
SYS_SEND |
41 | Send data on a connected socket |
SYS_RECV |
42 | Receive data from a connected socket |
SYS_BIND |
43 | Bind a socket to a local port |
SYS_LISTEN |
44 | Mark a socket as listening for connections |
SYS_ACCEPT |
45 | Accept an incoming TCP connection |
SYS_DNS |
46 | Resolve a hostname to an IPv4 address |
SYS_SOCKCLOSE |
47 | Close a socket and free resources |
SYS_PING |
48 | Send an ICMP echo request and wait for reply |
- Problem: TCP acknowledgments and DHCP responses were sent from within the RTL8139 interrupt handler (ISR), which could corrupt in-flight TX descriptors and cause packet loss or hangs.
- Solution: Added
SOCK_PENDINGfield (offset 48) to the socket structure. The ISR stores pending flags (ACK, SYN-ACK, FIN-ACK) instead of callingtcp_send_flagsdirectly. Polling loops insys_connect,sys_recv,sys_send,sys_accept, andsys_sockclosecalltcp_flush_pendingto drain deferred transmissions outside interrupt context. - Impact: Fixed DHCP timeout failures and TCP connection stalls.
sys_recvreturn path: Changedrettoiretd— the syscall returns via interrupt frame, not a near return. Missingiretdcaused stack corruption and triple faults after receiving data.- DHCP buffer overflow: Reduced DHCP option copy length from 300 to 75 bytes (maximum valid DHCP option payload), preventing overwrite of adjacent kernel data.
- DHCP race condition: Added
dhcp_stateflag to prevent processing duplicate OFFER/ACK packets from retriggered responses during the 4-phase handshake.
dhcp: Run DHCP client to obtain IP, subnet mask, gateway, and DNS server.ping <host>: Send ICMP echo request and display RTT.arp: Display the ARP cache (IP → MAC mappings).ifconfig: Show network interface configuration (IP, MAC, gateway, DNS).net: Display NIC status, PCI location, I/O base, and MAC address.
- forager — HTTP/1.0 web browser. Connects to port 80, sends GET request, displays response body. Tested end-to-end with
forager example.comin QEMU. - ping — Standalone ICMP ping utility with configurable count, TTL display, and RTT statistics.
- telnet — Interactive Telnet client with raw TCP socket communication and escape sequences.
- ftp — FTP client with passive mode, directory listing, file get/put, and cd/ls commands.
- gopher — Gopher protocol browser (port 70) with selector navigation.
- mail — SMTP mail client for composing and sending email via port 25.
- news — NNTP news reader for browsing Usenet newsgroups.
programs/lib/net.inc: User-space networking library with socket wrappers, DNS helper, HTTP request builder, and line-buffered receive.
- Disk image: 96 files across 4 subdirectories
- Kernel: ~20,000 lines of x86 assembly (19 include files)
- Kernel binary: ~399 KB
- Tests: 709 (175 build + 534 HBFS integrity)
- Syscalls: 48 (0–48)
- Programs: 79 assembly + 11 C samples
- Paging (
kernel/paging.inc): Identity-maps the first 128 MB via 32 page tables (page directory at 0x380000, page tables at 0x381000). All pages marked present, writable, and user-accessible.paging_map_pageutility for dynamic page mapping. Page-fault handler (INT 14) prints faulting address, EIP, and error code, then recovers to the shell.
- Preemptive scheduler: The PIT timer handler (IRQ0) now preempts ring-3 tasks every 100 ms (10-tick quantum at 100 Hz). Checks interrupted code's CPL via the CS RPL bits on the interrupt stack frame — kernel code is never preempted. Round-robin scan for next READY task with TCB ESP save/restore and TSS ESP0 update. Cooperative
SYS_YIELDstill works alongside preemptive switching.
- Mouse driver (
kernel/mouse.inc): Initializes the PS/2 auxiliary port via the 8042 controller (enable aux device, read/write command byte, set defaults, enable data reporting). IRQ12 handler collects 3-byte packets (flags, delta-X, delta-Y) with packet sync validation (bit 3 check). Tracksmouse_x(0–79),mouse_y(0–24), andmouse_buttons(left/right/middle). PS/2 Y-axis inversion for screen coordinates. SYS_MOUSE(syscall 36): Returns mouse position and button state (EAX=x, EBX=y, ECX=buttons).mouseshell command: Displays current mouse position and button state.
- VBE/BGA driver (
kernel/vbe.inc): Detects Bochs VBE adapter via I/O ports (IDs 0xB0C0–0xB0C5). Sets linear framebuffer modes from protected mode (no real-mode INT 10h). Default 640×480×32 mode. LFB identity-mapped (8 MB) viapaging_map_page. Full VGA mode 3 restore with CRTC/GC/AC register reprogramming. - Drawing primitives:
vbe_putpixel,vbe_fill_rect,vbe_clear. SYS_FRAMEBUF(syscall 37): Sub-functions for get info (0), set mode (1), and restore text mode (2).guishell command: Enters the Burrows desktop at 640×480 with colour bars and mouse cursor tracking. Press any key to return to text mode.
- Global glob preprocessing (
shell_expand_globs): Before command dispatch, all arguments containing*or?are expanded against the current directory listing. Matching filenames replace the glob pattern in the command line. Unmatched globs are passed through literally (POSIX behavior). This makes wildcards work for all commands (e.g.,cat *.txt,wc *.c), not justdelandcopy.
- top — Live process/task monitor showing scheduler state, memory usage, and uptime
- rogue — ASCII roguelike dungeon crawler with FOV, inventory, combat, and multiple dungeon levels
- starfield — Animated 3D starfield simulation with parallax depth effect
- matrix — Matrix-style falling green character rain animation
- weather — Simulated weather station with multi-day forecast display
- periodic — Interactive periodic table browser with element details
- forth — FORTH language interpreter with stack operations, arithmetic, and word definitions
- chess — Two-player chess with move validation, check detection, and Unicode-style pieces
- clock — Analog ASCII clock with sin/cos lookup tables, hour/minute/second hands, and digital display
- asm — Interactive x86 assembler REPL that shows machine code bytes for ~25 instruction types
- Disk image: 83 files, 248 blocks used
- Kernel: ~13,800 lines of x86 assembly (19 include files)
- Tests: 618 (84 build + 534 HBFS integrity)
- Syscalls: 38 (0–37)
- Programs: 66 assembly + 11 C samples
- Batch scripting directives:
:LABEL,goto LABEL,if [not] errorlevel N cmd,remcomments, and@cmd(silent execution). Batch scripts now support conditional branching and flow control. - Background job detection: Trailing
&on a command line is detected and stripped with a "not yet supported" message; the command runs in the foreground. Prepares the shell syntax for future background job support. netcommand: Displays NIC status, PCI location, I/O base address, and MAC address.ls -ltimestamps: Long directory listing now shows aModifiedcolumn with time since boot inHHH:MM:SSformat, read from the HBFSDIRENT_MODIFIEDfield.
SYS_STDIN_READ(syscall 34): Programs can read piped stdin data from the shell's redirection buffer. Returns byte count in EAX, or -1 if no stdin is available.SYS_YIELD(syscall 35): Cooperative yield syscall for the new scheduler. Saves the current task's ring-3 context and switches to the next ready task via round-robin.- Cooperative scheduler (
kernel/sched.inc): Task Control Block (TCB) array supporting up to 4 concurrent tasks. Per-task kernel stacks allocated from PMM. Round-robinsys_yieldwith proper TSS ESP0 updates for ring transitions. - RTL8139 networking stub (
kernel/net.inc): PCI bus 0 scan for RTL8139 NIC, software reset, RX/TX buffer allocation via PMM, MAC address read, and frame transmit function. Foundation for future TCP/IP support.
- sort, tr, grep, sed, cut: Now accept piped stdin when no filename argument is given (e.g.,
cat file | sort). - tee: Redesigned to support
tee OUTFILE(reads stdin) in addition to the legacytee INFILE OUTFILEmode.
- Portable test script:
tests/test_build.shnow works on both macOS and Linux. Replaced GNU-specificstat -cwith awc -cbasedfile_sz()helper, andgrep -oPwithgrep -E -opipelines. - Syscall consistency: Test now verifies all 36 syscalls (was 34).
- Disk image: 73 files, 233 blocks used
- Kernel: ~12,300 lines of x86 assembly (16 include files)
- Tests: 45 build + 534 HBFS integrity
- Syscalls: 36 (0–35)
build_cwd_pathbuffer overflow: Path construction wrote to a 256-byte buffer but max path depth (16 levels × 253 chars) could reach ~4 KB. Enlargedpath_search_bufto 4096 bytes and added bounds checking with guaranteed null termination on truncation.copy_wordunbounded write: Shell word extraction had no destination size limit. Added boundedcopy_word_nvariant (ECX = max bytes, always null-terminates). Migratedcmd_find_file,cmd_append_file, andcmd_mkdirto use the bounded version.- Ctrl+C redirection state leak: Pressing Ctrl+C during a redirected command (e.g.,
prog > file) leftstdout_redir_activeand related flags set, corrupting subsequent output. The Ctrl+C handler now callsshell_redir_resetto clear all redirection state before returning to the shell prompt. - Interrupt-unsafe stdout redirection: A keyboard interrupt during
vga_putchar's redirection check could corrupt the redirect buffer or length counter. Wrapped the redirection capture section withcli/stito make the test-and-write atomic. - Interrupt-unsafe directory state:
cdpath traversal modifieddir_depth,current_dir_lba,current_dir_sects, andcurrent_dir_namewithout interrupt protection. A Ctrl+C mid-update could leave the directory stack inconsistent. Addedcli/stiaround state mutations in bothcd_enter_subdirandcd_pop_stack.
io_file_writeregister mapping: Register remapping clobbered ECX (size) before copying it to EDX. The syscall received the buffer address as the size argument, causing writes to produce corrupted or zero-length files. Fixed register assignment order to preserve all parameters correctly.
- Makefile lib dependency tracking: Program build rule now depends on
$(wildcard programs/lib/*.inc)in addition tosyscalls.inc, so changes to any library file trigger program rebuilds.
- NOBITS warning regression test: New test in
test_build.shscans all.lstfiles for "nobits" warnings, catchingsection .bssordering bugs (like the v1.14 math.inc issue). - File content integrity test: New test in
test_hbfs.pyreads known program binaries from the disk image and compares them byte-for-byte with the local.binfiles, catching populate.py data corruption.
- API_REFERENCE.md: Added error handling patterns table documenting which functions use EAX=-1, EAX=0/null, or carry flag for error signaling.
- Alias expansion infinite loop: If an alias expanded to a command starting with its own name (or circular aliases like
A→B,B→A), the shell would loop forever. Addedalias_expandingguard flag that limits alias expansion to one level per command line, matching standard shell behavior:contentReference[oaicite:0]{index=0}. The flag is reset at each new prompt. sys_readdirunbounded filename copy: TheSYS_READDIRsyscall copied filenames to the user buffer without length checking, risking buffer overflow if the caller provided a small buffer. Now capped atHBFS_MAX_FILENAME(252) bytes with forced null termination.
- Build tests expanded (31 → 44): New checks include:
- All 55 program binaries built successfully (was only 12 spot-checked)
- No program exceeds 1MB (
PROGRAM_MAX_SIZE) - 9 HBFS constant consistency checks between
kernel.asmandpopulate.py - All 34 syscall numbers verified consistent between
kernel.asmandprograms/syscalls.inc - Kernel binary entry point validation
- HBFS integrity tests expanded (40 → 534): New checks include:
- Full subdirectory traversal — all 4 subdirectories validated with child file entry checks
- Program binary header validation — all 55 executables checked for valid x86 opcode at entry
- Global block allocation overlap check across all directories (root + subdirectories)
- Bitmap-vs-file block count cross-verification
- Stray bitmap bit detection beyond allocated range
- File census — total files across all directories verified (72 files)
- Disk image: 72 files, 229 blocks used
- Kernel: ~10,600 lines of x86 assembly
- Tests: 578 (44 build + 534 HBFS integrity)
- Removed global directory search: File operations (
cat,size,rm,rename,stat,fd_open, etc.) now only search the current working directory. Previously, any file could be accessed from any directory without a path — the kernel would silently scan root and every subdirectory. This was non-standard.. Users must now eithercdinto the correct directory or use an explicit path (e.g.,cat /docs/readme.txt).
- PATH-based program execution:
cmd_exec_programstill uses thePATHenvironment variable (defaultPATH=/bin:/games) to search for executables not found in the current directory. This is the only remaining multi-directory search and works like Unix$PATH. whichcommand: Continues to check builtins first, then CWD, thenPATHdirectories — unchanged.
env_get_varfix:env_getreturns the value pointer in EAX (pushad frame offset 28), butenv_get_varwas checking EDI (unchanged afterpopad) instead of EAX — so it always reported "not found". Fixed to usetest eax, eax. This was a latent bug masked by the old global directory search; with global search removed, PATH-based exec depended onenv_get_varworking correctly.
- Hardware probe:
serial_initnow tests the UART scratch register before configuring COM1. If no serial hardware is detected,serial_presentis set to 0 and all serial I/O becomes a safe no-op. - Non-blocking
serial_getchar: Changed from an infinite busy-wait to a non-blocking poll. Returns0xFFimmediately when no data is available.SYS_SERIAL_IN(syscall 33) now correctly returns-1when the receive buffer is empty, matching the documented ABI. - Guard on
serial_putchar: Skips output whenserial_presentis 0, preventing hangs on systems without a UART. serialtest utility (/bin/serial): New program for interactive bidirectional serial testing.serial send <text>sends a line; bareserialenters an interactive terminal (green = outgoing, cyan = incoming, Escape to quit).make run-serial: New Makefile target that launches QEMU with serial on TCP port 4555 (nc localhost 4555to connect).- Documentation:
readme.txtandnotes.txtupdated with serial usage instructions, QEMU connection examples, and use cases (debug logging, remote shell, file transfer, automated testing, data export).
hbfs_find_file_global: Simplified from a full recursive directory scan to a single CWD lookup (hbfs_load_root_dir+hbfs_find_file). The.gff_movedflag is always 0 now (kept for ABI compatibility with callers that check it).hbfs_read_file: Removed the.not_foundfallback that scanned all directories. Path-qualified filenames (/dir/file) still work via the path resolution code path.- Kernel binary: ~470 bytes smaller from removed global search code.
- Expression precedence: Replaced flat single-level expression parser with a 7-level precedence-climbing parser (
||→&&→==/!=→</>/<=/>=→+/-→*///%→ unary). Operators now bind correctly:2 + 3 * 4evaluates to 14, not 20. - String literal addressing: Rewrote string handling to use a fixup table.
store_stringreturns a string index;emit_string_dataemits string bytes at the end of the output and patches all fixup locations with correct runtime addresses. Fixes printf/string-literal crashes.
- Auto kernel size:
stage2.asmno longer has a hardcodedKERNEL_SECTORS equ 384. The Makefile generateskernel_sectors.incfrom the actualkernel.binsize (ceil(size / 512)), so the stage 2 loader always loads exactly the right amount. - Kernel include tracking:
$(KERNEL_BIN)now depends on$(wildcard kernel/*.inc), so touching any include file triggers a rebuild. - Regression test suite: New
make checktarget runs 71 automated tests:tests/test_build.sh— binary size guards (boot ≤ 512, stage2 ≤ 16 KB, kernel < 512 KB), MBR signature, superblock magic, bitmap and root directory sanity, program binary existence, TCC binary checks.tests/test_hbfs.py— deep HBFS integrity: superblock field validation, bitmap-vs-directory consistency, per-file block range and allocation overlap checks.
- ATA retry wrappers:
ata_read_sectorsandata_write_sectorsnow retry up to 3 times with an ATA soft reset (SRST via control register 0x3F6) between attempts. All existing callers (HBFS, shell commands, syscalls) automatically benefit. The raw single-attempt functions are still available asata_read_sectors_raw/ata_write_sectors_raw. - HBFS error propagation:
hbfs_load_root_dir,hbfs_load_bitmap, andhbfs_save_root_dirnow return CF (carry flag) on I/O failure with descriptive error messages.
- 13 include files:
kernel.asmis now a 300-line master file (constants, entry point,%includedirectives). The ~10,300 lines of subsystem code are split into:kernel/vga.inc— VGA text mode driverkernel/pic.inc— PIC initializationkernel/idt.inc— IDT setupkernel/isr.inc— ISR/IRQ handlerskernel/pit.inc— PIT timer + keyboard driverkernel/pmm.inc— physical memory managerkernel/ata.inc— ATA PIO driver + retry wrapperskernel/hbfs.inc— HBFS filesystemkernel/filesearch.inc— global file searchkernel/syscall.inc— syscall handlerkernel/shell.inc— command shell (~4,200 lines)kernel/util.inc— utilities, serial, RTC, speaker, TSS, ELF loader, FD table, env vars, subdir support, new syscalls/commands, tab completionkernel/data.inc— string data, scancode tables, IDT descriptor, BSS
- Binary output is byte-identical to the monolithic version.
- Disk image: 48 files, 188 blocks used
- Kernel: ~10,600 lines of x86 assembly (split across 14 files)
- Tests: 71 (31 build + 40 HBFS integrity)
dftotal file count: Thedfcommand now counts files across all directories (root + subdirectories), not just the current directory. Reports "N files in M directories" instead of showing a count for just the CWD.- Superblock
free_blockstracking:hbfs_alloc_blocksandhbfs_free_blocksnow update the superblock'sfree_blockscounter (offset 12) after every allocation/deallocation, keeping the on-disk superblock consistent with the bitmap. - Nested batch execution guard:
cmd_exec_batchnow detects re-entrant calls (abatchcommand inside a.batscript) and rejects them with an error message instead of silently corrupting the sharedbatch_script_buf/batch_line_bufbuffers.
- Disk image: 48 files, 188 blocks used
- Kernel: ~10,000 lines of x86 assembly
.save_typeoverflow (hbfs_create_file): The file type parameter was stored viamov [.save_type], edx(32-bit write) into a 1-bytedb 0variable, corrupting the first 3 bytes ofhbfs_delete_file_entry(overwriting thepushadopcode). Fixed by changing todd 0.cmd_cdsilent failure: Thecdcommand checked[esp + 28](stale pushad-saved EAX) instead of the actualEAXregister returned bycmd_cd_internal. This meantcdto a nonexistent directory never showed an error message. Fixed tocmp eax, -1.fd_closecross-directory bug: When a file opened viahbfs_find_file_globalfrom another directory was closed after writes,fd_closeonly searched the current directory for the entry to persist the updated file size — silently dropping the update. Fixed by recording the directory LBA/sects in the fd table entry at open time (offsets 20-27), then switching to that directory during close.sys_exec_callalways returned 0: The SYS_EXEC syscall returnedxor eax, eaxeven whencmd_exec_programfailed (CF set). Programs calling SYS_EXEC couldn't detect failure. Now returns -1 on failure.
cat -nline numbering: Replaced manual 4-digit space padding withvga_print_dec_widthfor cleaner, more maintainable code.str_has_wildcards/str_has_asterisk: Now preserve ESI (push/pop) to prevent subtle caller bugs.- ls -l alignment: Right-aligned file sizes in 9-character field using
vga_print_dec_width. - SYS_FWRITE file type: ESI parameter now specifies file type (FTYPE_TEXT..FTYPE_BATCH); TCC passes FTYPE_EXEC so compiled programs show as executables.
- Shutdown message: Styled with COLOR_HEADER separator bar; message printed before ACPI shutdown to prevent cutoff.
- Disk image: 48 files, 188 blocks used
- Kernel: ~9,900 lines of x86 assembly
- New core function:
hbfs_find_file_globalsearches for a file across all directories — current dir first, then root, then every subdirectory. Returns with CWD pointing to the directory containing the file, so save/delete/rename operations target the correct location. - GFF-private CWD save/restore: Dedicated
gff_save_cwd/gff_restore_cwdwith separate BSS slots (gff_cwd_lba,gff_cwd_sects,gff_cwd_depth,gff_cwd_name,gff_cwd_stack) — avoids conflicts withfile_save_cwdandpath_save_cwdused by other subsystems. .gff_movedflag: Callers check this to know whether CWD was changed, and restore it after the operation completes.
- rm / del: Fixed CPU exception bug — now uses
hbfs_find_file_global+ restores CWD after delete. Files can be deleted from any directory regardless of where the user is. - ren / rename: Uses global search for exact renames; saves directory after rename, then restores CWD.
- size: Uses global search to display file info from any directory.
- SYS_DELETE (syscall 9): Programs can now delete files in any directory.
- SYS_STAT (syscall 11): Programs can now stat files in any directory.
- fd_open: File descriptors can now open files in any directory.
- Disk image: 48 files, 188 blocks used
- Kernel: ~9830 lines of x86 assembly (~166KB)
- Full path support: All file operations (cat, batch, run, diff, head, tail, etc.) now accept absolute and relative paths — e.g.,
cat /docs/readme,run /bin/hello,diff /docs/readme /docs/notes - Automatic path splitting:
hbfs_read_filescans filenames for/; if found, splits into directory part and basename, cd's into the directory, reads the file, then restores the user's original working directory - file_save_cwd / file_restore_cwd: Separate CWD save/restore functions using dedicated BSS variables (
file_save_lba,file_save_sects,file_save_depth,file_save_name,file_save_stack), avoiding conflicts withpath_save_cwdused by the PATH search - Relative paths: Supports
../bin/hello,games/snake,./readme— resolves viacmd_cd_internalwhich handles.,.., absolute, and multi-component paths - Zero call-site changes: All 19 callers of
hbfs_read_filegain path support automatically
- Disk image: 48 files, 188 blocks used
- Kernel: ~9510 lines of x86 assembly (165KB)
- Subdirectory support in populate.py: Rewrote image builder with
FSImageclass supportingcreate_subdir()andadd_file(directory=...)methods - Organized virtual drive into 4 subdirectories:
/bin— 22 utility programs (hello, edit, mandel, tcc, sort, grep, wc, etc.)/games— 10 game programs (2048, galaga, guess, life, maze, mine, piano, snake, sokoban, tetris)/samples— 10 C source files (hello.c, fib.c, calc.c, matrix.c, wumpus.c, etc.)/docs— 5 text files (readme, license, notes, todo, poem)
- Working PATH mechanism: Kernel searches colon-separated PATH directories when a program isn't found in the current directory
- Default PATH: Set to
/bin:/games— programs in these directories run from anywhere set PATHcommand: Users can customize PATH (e.g.,set PATH /bin:/games:/samples)- path_save_cwd / path_restore_cwd: Utility functions to save and restore full directory state (LBA, sectors, depth, name, dir_stack) during PATH traversal
- cd-based search: PATH search cd's into each directory, searches there, reads file data directly from directory entry, then restores the user's original working directory
- which: Now searches PATH directories; shows full path (e.g.,
hello is /bin/hello (external)) - help: Updated to mention PATH search and configuration instructions
- Critical PATH fallthrough fix:
.path_not_foundwas falling through into.found_program— now correctly jumps to.not_found - NASM optimization oscillation: Added
-O0flag to kernel build to prevent label oscillation errors during assembly
- Disk image: 48 files, 188 blocks used (4 subdirectories + files)
- Kernel: ~9440 lines of x86 assembly
- diff: Side-by-side file comparison with colored output (< red, > green)
- uniq: Remove adjacent duplicate lines; flags:
-c(count prefix),-d(duplicates only) - rev: Reverse each line of a file character-by-character
- tac: Print file lines in reverse order (last line first)
- alias: Define, list, and show shell command aliases (16-slot table)
- history: Display numbered shell command history from history buffer
- which: Locate a command — shows if built-in or finds external program on disk
- sleep: Pause for N seconds (100 ticks/sec timer), supports Ctrl+C abort
- color: Set foreground/background VGA color (hex values 0-F)
- size: Show file size in bytes/blocks plus type (text/dir/exec/batch/unknown)
- strings: Extract printable strings from a file (default ≥4 chars, configurable via flag)
- Alias expansion: Shell parser checks alias table before command dispatch; recursive expansion into
alias_expand_buf
- vga_newline: Convenience function wrapping
mov al, 0x0A / call vga_putchar - str_compare: Compare two null-terminated strings at ESI/EDI, sets ZF on match
- life: Conway's Game of Life — 78×23 grid, glider/blinker/R-pentomino seeds
- maze: Random maze generator + BFS solver — 39×21 DFS-carved maze with colored path
- 2048: The 2048 sliding tile game — 4×4 board, arrow keys/WASD, scoring
- piano: PC speaker piano — 15 notes (C4-D5), scale and Mary Had a Little Lamb demos
- mandel: Mandelbrot set renderer — fixed-point 16.16 arithmetic, 78×23, color gradient
- pager: File pager (like
more) — 23-line pages, space/enter/q controls - sed: Stream editor — search and replace first occurrence per line
- tr: Character translator — SET1→SET2 mapping via 256-byte translation table
- csv: CSV file viewer — formatted columns, colored headers, pipe separators
- hanoi.c: Tower of Hanoi solver (4 disks, iterative binary counter method)
- bf.c: Brainfuck interpreter with hardcoded Hello World program
- wumpus.c: Hunt the Wumpus — 8-room cave, move/shoot, hazards
- matrix.c: Matrix rain effect — falling characters animation (40 columns × 20 rows)
- calc.c: Integer calculator — multi-digit numbers with +, -, *, / operators
- line_num reset: Line counter not reset between compilations — second compile reported wrong line numbers
- add_global_var extra next_token: Global variable declarations consumed one too many tokens — broke subsequent parsing
- Assignment expr_name clobbering: Assignment expression overwrote expr_name register — corrupted variable name lookup
- Disk image: 48 files, 172 blocks used
- Kernel: ~9250+ lines of x86 assembly
- sys_free double-shift:
pmm_free_pageexpects physical address butsys_freewas converting to page number first, causing doubleshr 12and freeing wrong pages — corrupted memory bitmap - cmd_copy_file stack corruption: Wildcard paths jumped to
.src_not_foundwhich didpop esi, but wildcard paths never pushed ESI — stack corruption on "no matches" case - env_get_var wrong register: Checked
EDI == 0instead of comparing EDI to saved copy; EDI was always non-zero (dest buffer pointer), so variable-not-found was never detected — broke PATH-based program search - hbfs_create_file overflow:
.copy_nameloop had no bounds check againstHBFS_MAX_FILENAME(252); long filenames could overflow into metadata fields - df bitmap scan: Only scanned 512 of potentially 2000+ bitmap bytes — reported ~1/4 of actual disk usage on 64MB disks
- hbfs_read_file stale buffer: Did not call
hbfs_load_root_dirbeforehbfs_find_file, could search stale directory data - fd_close size persistence: File size updated via
SYS_WRITEwas only stored in the FD table — never written back to the directory entry on close; file appeared truncated after reopen - Batch script overwrite:
cmd_exec_batchloaded scripts toPROGRAM_BASEwhere shell commands (cat, head, copy) also load data — commands would overwrite the batch script mid-execution - ATA LBA48 bits 24-31: Both
ata_read_sectorsandata_write_sectorszeroed LBA byte 3 instead of sending bits 24-31 from EAX — limited disk access to 8GB (16M sectors) instead of the full 32-bit LBA range
- SYS_MKDIR (12): Create a subdirectory; EBX = name pointer, returns EAX = 0 success / -1 error
- SYS_READDIR (13): Read directory entry by index; EBX = filename buffer, ECX = entry index, returns EAX = file type (-1 = end), ECX = file size
- Version text updated: v1.3 → v1.4, 28 → 227/56 files, 33 → 34 syscalls
- Banner string updated: HB Lair v1.3 → v1.4
hbfs_find_filecomment: "root directory" → "current directory"HBFS_DIR_ENTRY_SIZEcomment: corrected field sizes and order to match actual offsetspopulate.py: Fixed root dir comment (2 → 16 blocks), readme.txt (34 syscalls), notes.txt (added SYS_SERIAL_IN), todo.txt (34 syscalls)syscalls.inc: Documented SYS_MKDIR/SYS_READDIR as now implemented
- Extracted
hbfs_mkdirshared function fromcmd_mkdir— used by both shell command andSYS_MKDIRsyscall cmd_exec_batchuses 32KBbatch_script_bufin BSS instead ofPROGRAM_BASEfd_closescans directory bystart_blockto persist file size for writable FDsata_read_sectors/ata_write_sectorssendEAX[24:31]as LBA byte 3 in high phase
- Root directory expanded: 2 blocks → 16 blocks (28 → 227 file entries per directory)
- Subdirectories expanded: 1 block → 4 blocks per subdirectory (14 → 56 entries each)
- Multi-level subdirectories: Full support for nested directories to 16 levels deep
- Directory stack: Parent directory tracking via push/pop stack enables proper
cd ..from any depth - Multi-component paths:
cd a/b/c,cd ../sibling,cd /abs/pathall work correctly - Full path display: Shell prompt,
pwd, andSYS_GETCWDshow complete path (e.g.,/projects/src)
- Kernel area increased from 192 to 384 sectors (96KB → 192KB) to accommodate larger BSS
- Superblock moved from LBA 225 to LBA 417
- Bitmap at LBA 418, Root directory at LBA 426-553, Data starts at LBA 554
- Note: Existing disk images must be reformatted (incompatible layout change)
- New
HBFS_SUBDIR_BLOCKSconstant (4) controls subdirectory allocation size - New
build_cwd_pathutility builds full path string from directory stack hbfs_formatuses loop to zero all 16 root directory blockscmd_mkdirzeros all allocated blocks and stores correct block count- All 12 directory iteration loops auto-adapt via
hbfs_get_max_entries - Added BSS:
dir_depth(dword),dir_stack(16 × 264 bytes = 4,224 bytes) hbfs_dir_bufexpanded from 8KB to 64KB
- Command-line arguments: Programs receive arguments via
SYS_GETARGS(syscall 32); shell parsesprogram arg1 arg2syntax - Ctrl+C hard-abort: Keyboard IRQ detects Ctrl+C while a program is running and immediately returns to shell (no program cooperation needed)
- FD write implementation:
SYS_WRITEvia file descriptors now performs real block read-modify-write to disk instead of being a stub - Raw disk access restriction:
SYS_DISK_READ(22) andSYS_DISK_WRITE(23) are denied to ring 3 user programs for security
- cal.asm: Calendar display showing current month with day-of-week calculation (Sakamoto's algorithm), highlights today
- calc.asm: Interactive integer calculator with +, -, *, /, % operators, hex output, signed arithmetic
- edit.asm: Now accepts filename from command line (
edit myfile.txt) via SYS_GETARGS instead of always editing scratch.txt - Syscall count: 33 syscalls (added SYS_GETARGS = 32)
- Version text: Updated to v1.3 with new feature descriptions
- INSTALL.md: Complete build and installation guide
- USER_GUIDE.md: Comprehensive user manual with all commands
- TECHNICAL_REFERENCE.md: Architecture, memory map, HBFS spec, driver details
- PROGRAMMING_GUIDE.md: Tutorial on writing Mellivora OS programs
- API_REFERENCE.md: Complete syscall API reference with examples
- IRQ PIC2 EOI: Split irq_stub into PIC1-only and PIC2 variants; PIC2 IRQs now send EOI to both controllers
- ATA sector overflow: LBA48 sector count now sends high byte (CH) instead of always 0
- cmd_copy redundant find: Removed unnecessary second
hbfs_find_filecall; uses ECX fromhbfs_read_filedirectly - guess.asm backspace: Backspace now does BS+space+BS for proper visual erase
- CHANGELOG programs: Fixed v1.0 program list to match actual programs (banner, colors, guess, primes)
- populate.py docs: Fixed stale notes.txt (root dir LBA 234-249, data LBA 250+), updated todo.txt/readme.txt
- Ring 3 user mode: Programs now run in ring 3 with TSS (selector 0x28), user code/data segments (0x18/0x20)
- ELF loader: Minimal ELF32 binary loader - parses ELF magic and loads PT_LOAD segments
- Boot splash: Stage 2 displays blue title bar ("Mellivora OS - Booting...") during boot
- Program return code: SYS_EXIT saves EBX as program exit code; shell reports non-zero codes
- Serial console: COM1 at 115200 baud for debug output; serial_init/serial_putchar/serial_print
- RTC clock: Read date/time from CMOS (ports 0x70/0x71) with BCD-to-binary conversion
- PC speaker: PIT channel 2 beep via port 0x61; configurable frequency and duration
- SYS_BEEP (24): Play tone on PC speaker (EBX=frequency, ECX=duration_ms)
- SYS_DATE (25): Read RTC date/time into buffer
- SYS_CHDIR (26): Change current directory
- SYS_GETCWD (27): Get current working directory
- SYS_SERIAL (28): Write string to serial port
- SYS_GETENV (29): Get environment variable value
- SYS_OPEN/READ/WRITE/CLOSE/SEEK (5-8,10): File descriptor operations implemented
- echo: Print text with $VAR environment variable expansion
- wc FILE: Line, word, and byte count
- find FILE PATTERN: Substring search with line numbers
- append FILE TEXT: Append text to existing file
- date: Display current date/time (YYYY-MM-DD HH:MM:SS)
- beep: Play 1000Hz tone for 200ms
- batch FILE: Execute shell commands from a script file
- mkdir NAME: Create subdirectory entry
- cd DIR: Change current directory
- pwd: Print working directory
- set NAME=VALUE: Set environment variable
- unset NAME: Remove environment variable
- Tab completion: Filename auto-completion in shell
- Ctrl+C: Interrupt running program
- File descriptors: 8-slot FD table with open/read/write/close/seek operations
- Environment variables: 16 variables, 128 bytes each, $VAR expansion in echo/batch
- Subdirectories: Basic directory support with current_dir_lba tracking
- edit.asm: Full-screen text editor with cursor movement, insert/delete, Ctrl+S save, Ctrl+Q/ESC quit
- tetris.asm: Classic Tetris with 7 tetrominoes, rotation, scoring, levels, next-piece preview
- syscalls.inc: Shared include file with all 30 SYS_* constants and common print_dec routine
- All 10 programs: Refactored to use
%include "syscalls.inc", eliminated duplicated constants and print_dec - Makefile: Added .lst listing files, populate.py as dependency, syscalls.inc as program dependency
- Named constants: DIRENT_* offsets for directory entry fields replace magic numbers
- Multi-block filesystem: Files can now span multiple 4KB blocks.
hbfs_alloc_blocksallocates N contiguous blocks,hbfs_create_filewrites all sectors,hbfs_delete_file_entryfrees all blocks. - parse_hex_byte: Fixed inverted carry flag semantics in hex byte parser (enter command).
- Shift key bounds check: Added guard for scancodes < 0x20 before shift_table lookup to prevent out-of-bounds read.
- Keyboard buffer overflow: Added buffer-full check before writing to ring buffer.
- cmd_cat overflow: Clamp file read size to PROGRAM_MAX_SIZE - 1 to prevent null-terminator overflow.
- ATA flush: Moved FLUSH CACHE command outside the write loop (was flushing after every sector).
- Rename length check: Filename copy now checks against HBFS_MAX_FILENAME (252 chars).
- Snake tail rendering: Save old tail position before shift_body loop, use saved coordinates for erase.
- Sysinfo wasted division: Removed useless first div in uptime calculation (result was immediately overwritten).
- Minesweeper stack overflow: Converted recursive 8-way flood_reveal (up to 800-deep recursion, ~80KB stack) to iterative algorithm with explicit stack array.
- IDT fully populated: All 256 IDT entries now filled with isr_default, preventing #GP on unexpected interrupts.
- Exception handlers: Separate handlers for exceptions with/without error codes. Prints faulting EIP and error code, then recovers to shell (no more cli/hlt freeze).
- Syscall register preservation: Syscall handlers now save/restore EBX, ECX, EDX, ESI, EDI. Only EAX is modified for return value.
- SYS_DELETE (9): Delete a file by name
- SYS_STAT (11): Get file size and block count
- SYS_MALLOC (19): Allocate 4KB-aligned physical memory pages
- SYS_FREE (20): Free allocated memory pages
- SYS_DISK_READ (22): Raw disk sector read
- SYS_DISK_WRITE (23): Raw disk sector write
- df: Show HBFS filesystem usage (total/used/free blocks, file count)
- more FILE: Page-by-page file viewer (23 lines per page, Space/Enter for next, q/ESC to quit)
- Shell command history: Up/Down arrow keys recall previous commands (stores last 8 commands)
- PMM multi-page allocation:
pmm_alloc_pagesallocates N contiguous physical pages - Bitmap load helper:
hbfs_load_bitmapshared function for bitmap I/O
- Updated version text to v1.1 with new features
- Fixed stale comments in populate.py (directory = 2 blocks/16 sectors, data starts at LBA 250)
- Updated help text with df and more commands
- 32-bit protected mode kernel with flat 4GB address space
- HBFS filesystem with 4KB blocks and 28-entry root directory
- ATA PIO disk driver with LBA48 support
- VGA 80x25 text mode with 16 colors
- PS/2 keyboard driver with shift key support
- Physical memory manager with bitmap allocator
- Heap allocator (simple bump allocator)
- PIT timer at 100 Hz
- 11 syscalls via INT 0x80
- Shell with 14 built-in commands
- 10 user programs (hello, banner, colors, fibonacci, guess, primes, sysinfo, snake, mine, sokoban)