GUI polish / HD:
- Default display mode raised to 1920x1080 (video=1920x1080); make run/vnc use
vgamem_mb=64 and -m 512M. The growable heap absorbs the larger backbuffer,
shadow and wallpaper (observed: one 16 MB growth to a 48 MB heap).
- Wallpaper: three-stop vertical gradient, a soft concentric-frame edge vignette
for depth, a finer faint grid, and a centred brand mark.
- Window chrome: brighter/saturated titlebar gradient when focused, an accent
underline on the active window, and larger/softer drop shadows.
- Default session windows are placed and sized for the HD work area.
- Live FPS pill in the taskbar tray (green/amber/red by rate); tray widened so
FPS + CPU trace + memory badge + clock no longer overlap.
Kernel:
- kernel/time/ktime.c + include/kernel/ktime.h (new): a unified monotonic
high-resolution clock that prefers the HPET (nanosecond) and falls back to the
100 Hz PIT tick. Wired ktime_init() into boot; drives the compositor's FPS
sampling. New `ktime` LazyBox applet reports the source and uptime.
Verified live (screenshotted): boots to 1920x1080, KTIME reports
"source: HPET, nanosecond resolution", the polished desktop renders with the
active-window accent and vignette, and the tray shows a live FPS reading.
Clean build on x86_64/aarch64/armv8i; 0 panics / 0 OOM.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Fh5z6V7nGPbHvqVG5p4CXX
The Settings window rendered fine but its controls only mutated the app's local
settings_data_t -- nothing was ever wired to the running system, so toggling
options did nothing ("not working").
- Appearance: "Show wallpaper grid overlay" now calls gui_desktop_set_grid()
live; the desktop grid shows/hides immediately.
- Input: "Show seconds in taskbar clock" now calls gui_desktop_set_clock_seconds();
the taskbar clock switches between HH:MM and HH:MM:SS.
- Power: the CPUFreq governor radios now call cpufreq_set_governor() (mapping the
UI order to the enum), and Apply/Defaults push all preferences to the system.
- The app seeds its controls from live state on open (grid/clock/governor), so it
reflects reality instead of hard-coded defaults.
Also add public gui_desktop_set_grid/get_grid and set/get_clock_seconds, and
give Settings a dedicated event handler that frees its state on close (the
shared app_forward_event leaked it).
Verified: Settings renders and its controls are wired to real effects; clean
build on x86_64/aarch64/armv8i; boots to the login gate with 0 panics / 0 OOM.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Fh5z6V7nGPbHvqVG5p4CXX
Add three real platform device drivers (x86 hardware, ARM-stubbed):
- drivers/timer/hpet.c + include/drivers/hpet.h: High Precision Event Timer.
Maps the HPET block at the standard 0xFED00000, reads the femtosecond period
from the capability register, enables the main counter and exposes a
monotonic nanosecond time source (hpet_get_ns) far finer than the 100 Hz PIT.
- drivers/char/lpt.c + include/drivers/lpt.h: IBM PC parallel port (LPT1) with
the Centronics data/strobe handshake over ports 0x378/0x379/0x37A.
- drivers/char/nvram.c + include/drivers/nvram.h: MC146818 CMOS NVRAM read/write
over 0x70/0x71, preserving the NMI-disable bit, with checksum and hex dump.
Wired all three into the [5/14] device-enumeration boot step and added LazyBox
applets `hpet`, `lpt`, and `nvram`.
Verified live under QEMU (screenshotted): HPET reports 100 MHz / 3 comparators /
10 ns period and its counter advances ~1.4 s of real time between two `hpet`
runs; NVRAM dumps 128 bytes with a computed checksum; LPT1 detected at 0x378.
Clean build on x86_64/aarch64/armv8i; 0 panics / 0 OOM.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Fh5z6V7nGPbHvqVG5p4CXX
Kernel (NT I/O subsystem):
- kernel/nt/io.c + include/kernel/nt/io.h (new): DRIVER_OBJECTs with a
MajorFunction dispatch table, DEVICE_OBJECTs that can be stacked (attached),
and IRPs pushed down the stack via io_call_driver / completed with
io_complete_request. Ships three demo drivers: \Driver\Null (write sink,
EOF reads), \Driver\Zero (zero-filled reads), and \Driver\Monitor -- a filter
attached above \Device\Null that counts and forwards each IRP down the stack.
Wired into the [12/14] boot step.
- LazyBox `iodev` lists drivers/devices with the stack and IRP counters, then
runs a live demo: a WRITE IRP through the filtered Null stack and a READ from
the Zero device.
GUI:
- gui/gui_apps.c: "Registry Editor" -- navigate the NT \Registry hive tree,
click subkeys to descend and ".." to go up, with a values pane showing each
value's name/type/data. Registered in the app table (start menu).
Verified live in the GUI terminal (screenshotted): 3 drivers / 3 devices, the
NullMonitor->Null device stack, a 16-byte WRITE sunk through the filter
(status 0x0), and an 8-byte zeroed READ from \Device\Zero. Clean build on
x86_64/aarch64/armv8i; 0 panics / 0 OOM.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Fh5z6V7nGPbHvqVG5p4CXX
Kernel (NT Configuration Manager):
- kernel/nt/reg.c + include/kernel/nt/reg.h (new): a hive/key/value registry
rooted at "\Registry", with typed values (REG_SZ/DWORD/QWORD/BINARY/MULTI_SZ,
type codes matching Win32). reg_create_key/reg_open_key walk backslash paths;
setters/getters, enumeration, and value->string rendering. reg_init() seeds
\Registry\Machine (Hardware, System\CurrentControlSet\Control, Software\SUB-OS)
and \Registry\User\.DEFAULT. Wired into the [12/14] boot step.
- LazyBox `reg query|add|set|stats` explores and edits the registry.
GUI:
- gui/gui_apps.c: "Object Browser" -- a WinObj-style live tree view of the NT
object namespace (\), flattening directories/events/semaphores/mutants with
indentation, per-type colouring, ref/handle counts, live object/handle stats,
and click-to-scroll. Registered in the app table (start menu).
Verified live in the GUI terminal (screenshotted): registry reports 13 keys /
11 values; `reg query \Registry\Machine\Software\SUB-OS` lists Version,
BuildArch (REG_SZ), GrowableHeap/ObjectManager (REG_DWORD) and InstallCookie
(REG_QWORD) with correct types. Clean build on x86_64/aarch64/armv8i; 0 panics.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Fh5z6V7nGPbHvqVG5p4CXX
Take inspiration from the Windows NT Executive and add its most iconic
subsystem to SUB-OS: a typed, reference-counted object namespace.
- kernel/nt/ob.c + include/kernel/nt/ob.h (new):
* Object Manager (Ob): typed objects (Directory/Event/Semaphore/Mutant) in a
hierarchical named namespace rooted at "\", with NT-style deletion once
handle_count and ref_count both reach zero (unless permanent).
* Handle table (Io/Ob): NT-shaped non-zero 4-aligned HANDLEs into a 256-slot
system table; open/reference/close with proper refcount transfer.
* Dispatcher (Ke): set/reset/test events (auto- and manual-reset) and
release/wait semaphores, poll-style.
* Software IRQL: PASSIVE/APC/DISPATCH/HIGH with raise/lower semantics.
* NTSTATUS result codes and NT_SUCCESS().
* ob_init() seeds the standard namespace (\BaseNamedObjects, \Device,
\ObjectTypes, \KernelObjects) plus a boot event and an I/O semaphore.
- Wired ob_init() into the [12/14] boot step; added kernel/nt/ob.c to CORE_SRCS.
- LazyBox: `objdir [\path]` walks the object namespace tree (WinObj-style);
`ntobj` prints Ob statistics and runs a live dispatcher/handle/IRQL demo.
Verified live in the GUI terminal (screenshotted): 7 seeded objects
(5 directories, 1 event, 1 semaphore), auto-reset event signalling, handle
close reclaiming the object, and PASSIVE->DISPATCH->PASSIVE IRQL transitions.
Clean build on x86_64/aarch64/armv8i; 0 panics / 0 OOM.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Fh5z6V7nGPbHvqVG5p4CXX
Rust kernel expansion:
- rust/src/compress/mod.rs (new): memory-safe PackBits-style run-length
encoding codec (rle_compress / rle_decompress) with C-ABI shims, registered
in lib.rs. C fallbacks added to rust_fallback.c so aarch64/armv8i match.
- include/kernel/rust.h: FFI declarations for the codec.
- LazyBox: new `rle <text>` applet that compresses, decompresses, prints the
ratio and verifies the round-trip is lossless.
GUI expansion:
- gui/gui_apps.c: "Rust Lab" app -- a live dashboard for the Rust subsystem.
Shows CRC-32C/Adler-32 of a sample, measured ChaCha20/SHA3-256/AES-128
throughput as scaled bars plus a composite score (benchmark run once at
launch and cached), and a live ChaCha20 CSPRNG byte stream refreshed
periodically. Per-window state freed on close.
- Registered "Rust Lab" (info icon) in the desktop app table and on the
desktop; desktop icon indices updated for the new entry.
Verified: clean build on x86_64/aarch64/armv8i; boots through the SUB login to
the desktop with the new Rust Lab icon rendering (screenshotted); checksum
self-test prints, 0 panics / 0 OOM.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Fh5z6V7nGPbHvqVG5p4CXX
Rust kernel expansion:
- rust/src/checksum/mod.rs (new): memory-safe CRC-32C (Castagnoli), Adler-32,
and FNV-1a-64 with thin C-ABI shims. Registered in lib.rs with a boot-time
self-test (crc32c("SUB-OS")=0x61e96ce9, verified against a reference impl).
- include/kernel/rust.h: FFI declarations; rust/rust_fallback.c: matching C
fallbacks so aarch64/armv8i (no native rustc target) get identical results.
- LazyBox: new `cksum <text>` applet printing all three via the Rust engine.
GUI expansion:
- gui/gui_apps.c: Conway's Game of Life -- an interactive B3/S23 cellular
automaton with Play/Pause/Step/Random/Clear toolbar, click-to-toggle cells,
a live generation/population readout, and a board that scales with the
window. The Random button seeds from the Rust ChaCha20 CSPRNG. Toolbar and
cell input are gated on the MOUSE_DOWN edge so they do not re-fire while held.
- Registered "Life" (flask icon) in the desktop app table and on the desktop.
Verified: clean build on x86_64/aarch64/armv8i; boots through the SUB login to
the desktop (screenshotted) with the checksum self-test and 0 panics/0 OOM.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Fh5z6V7nGPbHvqVG5p4CXX
Login:
- Add console_login() (security/auth.c): an interactive boot-time username /
password gate rendered on the framebuffer console before any session starts.
It blocks until valid credentials are entered, masks the password, scrubs it
from the stack, and sets the current user. Default account is SUB / SUB, shown
as a hint. Wired into the boot handoff in kernel/main.c ahead of both the GUI
desktop and the emergency TTY shell.
Configure:
- scripts/kconfig/menuconfig.py: fix the architecture (and optimization) picker.
The lxdialog front-end used --radiolist, where <Enter> confirms the ORIGINAL
choice and only <Space> moves the dot -- so highlighting a new architecture
and pressing <Enter> appeared to do nothing. Single-choice groups now use
--menu (with --default-item), where <Enter> selects the highlighted row
directly. Also stop the unconditional save-on-exit from overriding an explicit
"No" at the exit confirmation.
Verified: SUB/SUB logs in (injected via QEMU monitor) -> "Login successful" ->
desktop starts; the desktop stays blocked until login. dialog --menu selection
of aarch64 persists to .config/autoconf.h and retargets `make`. Clean build on
x86_64/aarch64/armv8i.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Fh5z6V7nGPbHvqVG5p4CXX
Kernel / memory:
- mm/kmalloc.c: fix "Heap: Out of memory" under the GUI. The desktop allocates
three full-screen 32-bit buffers (~11MB) which overflowed the fixed 16MB pool.
The heap now starts at 32MB and grows on demand from the PMM (16MB regions),
with region-safe coalescing (only merges physically adjacent blocks) so growth
never corrupts across separate PMM allocations. Adds heap_get_grow_count().
Build / run:
- Makefile: merge `run-gui` into `run` so `make run` boots into the graphical
desktop; add `run-headless` (serial-only via QEMU_CMD), bump guest RAM to
256M, update .PHONY and help.
Configure:
- scripts/kconfig/menuconfig.py: gate the curses UI behind isatty() on stdin and
stdout so non-interactive `make configure` stops emitting "nocbreak() returned
ERR" and falls cleanly through to the non-interactive writer.
GUI / userland:
- gui/gui_apps.c: rebuild the System Monitor from hardcoded values into live
telemetry -- real heap used/total/free with a colour-shifting bar, a scrolling
heap-utilisation graph, the grow counter, and real PMM RAM figures.
- lazybox `free`: report how many times the heap has grown.
Auth:
- Default login is now SUB / SUB (Kali-style username==password), seeded first
as the primary uid-0 account and set as the logged-in user; root kept for
compatibility. Hardcoded "root" defaults (whoami, su, passwd, ssh, sshd
session) updated to SUB.
Verified: clean build on x86_64/aarch64/armv8i; GUI boots with 0 OOM/0 panic;
auth engine initialises cleanly; `make configure` fallback is clean.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Fh5z6V7nGPbHvqVG5p4CXX
Bring the SUB-OS Graphical Desktop Environment (SUB-WM compositor, SUB-WT
widget toolkit, icon set, modal dialogs, terminal emulator and the desktop
apps) onto main alongside main's userland /sbin/init and framebuffer console.
Conflicts resolved:
- kernel/main.c: boot into gui_start_desktop() by default (unless nogui/text/
emergency/single), then fall back through fbcon + /sbin/init + shell when the
GUI session closes or a text console is requested. Splash raised by default
unless a text console is asked for. Kept main's fbcon include and the
weave_preempt_selftest path.
- Makefile: kept main's userland init compilation rules and kernel/elf.c,
kernel/exec.c in CORE_SRCS; retained the feature branch's gui/ sources.
- README.md: kept main's Weave Scheduler section and adopted the feature
branch's Boot Logo / Console Font / Framebuffer Console / GUI Desktop docs.
Verified: full x86_64 build links cleanly (kernel.elf + SUB-OS.img).
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Fh5z6V7nGPbHvqVG5p4CXX
Kernel threads were only ever switched cooperatively (sched_yield, task_exit);
a thread that never yielded held the CPU forever. The Weave scheduler now
preempts from the PIT tick, so CPU-bound threads are time-sliced.
Deferred switch, not mid-handler:
- sched_tick() no longer switches. It charges the running quantum and, when it
is spent, only raises weave_need_resched. The switch happens at IRQ return in
the new sched_preempt_on_return(), called from the x86_64 dispatcher after
the PIC EOI. That keeps the tick path re-entrancy-safe (the EOI is already
out, so the PIC keeps delivering) and lets the preempted thread unwind
through the normal iretq on its own kernel stack.
Interrupt-atomic scheduler state:
- The plain weave_lock is not IRQ-safe, so a tick landing mid-mutation would
deadlock. weave_lock sections now mask interrupts (arch_irq_save/restore,
added to arch.h for all three arches) so the timer can never fire inside
them, and weave_rotate holds them masked across the pick and the register
swap so the switch is one indivisible step.
Preemption-disable count:
- sched_preempt_disable/enable gate the tick and the return-path switch so a
preemptive switch cannot land while a plain (non-IRQ-safe) spinlock is held.
printk wraps its critical section with it, closing the most common hazard;
other locks are a documented follow-up.
Fresh threads opt into interrupts at entry so they are preemptible from birth
without changing the cooperative early-boot self-test, which still runs with
interrupts masked and is unchanged (20 switches, 3/3 workers).
Verified on x86_64 under QEMU: a new boot-time self-test arms preemption and
two threads that NEVER yield are forced to share the CPU -- 20 involuntary
switches, both advance and are woven down to the CPU-bound lanes -- then boot
proceeds cleanly to ring-3 /sbin/init and the shell with zero faults. aarch64
and armv8i still build; preemption is wired into the x86_64 IRQ path only, so
those stay cooperative for now (their switch asm already exists).
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_0161Jh7uCEMLYEMNPsjC1LKf
Replace the state-relabel-only round-robin with the SUB-OS "Weave"
scheduler backed by a genuine callee-saved context switch. Threads now
actually run on their own kernel stacks instead of merely having their
state field rewritten.
What was implemented:
- sub_ctx_switch(): per-arch assembly (arch/x86_64/cpu/switch.asm,
arch/aarch64/cpu/switch.S, arch/armv8i/cpu/switch.S) that saves/restores
the callee-saved register set (+ flags on x86_64) on each thread's own
stack, plus a first-run trampoline (sub_thread_trampoline) that launches
a freshly forged thread frame with entry/arg in callee-saved registers.
- task_forge_frame(): builds the initial saved-context frame per arch so
the very first switch into a new thread lands on the trampoline; task_t
gains a pointer-sized ctx_sp so the same struct works on 64- and 32-bit.
- Weave policy (kernel/sched.c): WEAVE_NLANES priority lanes, always
dispatch the lowest non-empty lane round-robin; a task that yields
voluntarily is woven UP a lane (interactive), one preempted after
burning its quantum is woven DOWN (CPU-bound). Cooperative switching
(sched_yield / task_exit) is always live; timer-driven preemption is
gated behind sched_set_preempt() and left disarmed for now.
- task_exit() now switches to the next runnable thread via
sched_exit_current() instead of spinning/halting.
- Boot-time weave_selftest() (x86_64) and sched_dump() diagnostics.
How it was verified:
- Builds clean for all three targets: x86_64 (CROSS_COMPILE=x86_64-linux-gnu-,
RUSTC="rustc --target x86_64-unknown-none"), aarch64, armv8i. No new
warnings; the new x86_64 asm carries a .note.GNU-stack section.
- Booted x86_64 under QEMU (TCG): the self-test runs three cooperative
kernel threads to completion on separate stacks with the expected
1->2->3 round-robin interleave, reports "20 real context switches,
3/3 workers exited", returns cleanly to the boot thread, and boot
proceeds normally to ring-3 init and the shell. No fault/panic.
Left unverified:
- The aarch64/armv8i sub_ctx_switch frames build and link but are not yet
boot-tested on their QEMU targets (tracked in docs/AUTODEV_ROADMAP.md).
- Timer preemption path is implemented but disarmed; exited kernel threads
currently leak their stack (reaper is next in the backlog).
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Jk6K69yGS7zYgvoWd6nJxQ
The compositor recomposited and re-uploaded the entire screen on every pass of
its loop. At the 1280x720 the desktop actually boots into, gui_gfx_present()
memcpy'd 3.6 MB into the framebuffer per frame, and the background underneath
it was recomputed pixel by pixel every time.
Present only the damage
- Keep a RAM shadow of what the framebuffer currently holds and diff the back
buffer against it, pushing just the changed span of each row. Reading the
shadow costs a RAM access; the framebuffer write it avoids costs far more,
and the framebuffer is never read back.
- Each row is narrowed to its first and last differing pixel rather than
tracked as a set of runs: one memcpy per row keeps the loop tight, and a row
that changed in two distant places is rare enough that bridging the gap is
cheaper than the bookkeeping.
- gui_gfx_invalidate() forces a full push for when something outside the
compositor owns the screen, which the desktop calls on entry and on exit
around the framebuffer console.
Cache the wallpaper
- The vertical gradient, the blended grid and the branding text never change
between frames, so they are painted once into a cached buffer and blitted
back per frame. The cache is keyed on resolution and the grid setting, so
toggling the grid from the context menu still repaints it.
No drawing code changed: the damage is derived from the frame itself, so every
widget, window and app keeps rendering exactly as before.
Measured in QEMU at 1280x720: an idle desktop with two windows open went from
921600 pixels per frame to 3609, about 0.4% of a full blit. A screendump of
the running desktop is unchanged -- wallpaper, grid, icons, both windows,
taskbar and cursor all render identically.
Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_0161Jh7uCEMLYEMNPsjC1LKf
SUB-OS had a syscall table and user GDT descriptors but nothing that could
actually leave ring 0: lazybox and the shell run as kernel code, and
syscall_handler() was never reachable from a user program. This adds the
missing path end to end on x86_64.
Address spaces (arch/x86_64/mm/vmspace.c)
- The boot page tables identity-map the low 4 GB off PML4[0] and leave the
rest empty, so userland is given its own PML4 slot (512 GiB) rather than
holes punched in the kernel's 2 MB huge-page map. A process PML4 shares
entry 0 with the kernel and privately owns entry 1.
- Frames outside the identity map are refused rather than written through an
unmapped pointer; lifting that needs a recursive map or a higher-half
direct map, which is noted in the file.
ELF loader (kernel/elf.c)
- Validates ELF64/little-endian/ET_EXEC/machine, bounds-checks every program
header against both the image and the user address range, and lays PT_LOAD
segments into an address space. Frames arrive zeroed, so .bss is covered.
Ring transition (arch/x86_64/cpu/usermode.asm)
- user_enter() drops to ring 3 via iretq after scrubbing every GPR, and
user_return() unwinds back to it when the process exits, so exec looks like
a call that blocks until the program finishes.
Syscalls
- INT 0x80 installed at DPL 3 with the Linux x86_64 register convention.
The process gets its own kernel stack for the trap, because TSS.rsp0 must
not point at the stack user_enter() is standing on.
- Every user pointer is range-checked before use. The process page tables are
still live during a syscall, so without that check a program could pass a
kernel address and have write(2) dump kernel text to the console. The new
/sbin/init asserts both a wild pointer and a kernel pointer are rejected.
- write(2) to stdout/stderr routes through the new console_write(), which
reuses printk's routing so output reaches serial and the framebuffer
console rather than only the VGA text buffer.
Faults
- A ring 3 exception now kills that process and reports CR2 instead of
panicking the machine.
Userland (userland/init/)
- /sbin/init is a real freestanding static executable, linked at the user
base and embedded in the kernel image by scripts/mkblob.py. It reports its
pid, verifies .bss was zeroed and .data is writable, checks the two pointer
rejections, and exits.
aarch64 and armv8i keep building: the loader and exec path are portable, and
those ports get honest vmspace stubs that fail cleanly rather than pretending
to run a program with kernel privileges.
Verified under QEMU: init loads at 0x80004000a0, reports pid 1, .bss zeroed,
.data writable, both bad pointers rejected, and exits 0 back into the shell.
Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_0161Jh7uCEMLYEMNPsjC1LKf
Pressing Esc left the desktop and started the shell, but nothing appeared in the
emulator window -- the session was only visible on the host terminal. Once the
VBE adapter is switched into graphics mode the VGA text buffer at 0xB8000 stops
being scanned out, so every printk after that point reached serial and the
dmesg ring but never the display.
Disabling the DISPI interface does not bring the text console back; QEMU keeps
presenting the last framebuffer surface. So rather than clawing the adapter back
to text mode, the console is now rendered into the framebuffer:
drivers/video/fbcon.c draws the console with the shared 8x8 font and carries a
VT100 subset -- SGR colours, cursor addressing, relative moves, erase-display,
erase-line and save/restore. It presents a fixed 80x25 grid, because that is
the geometry the userland assumes (nano pads its bars with %-80s, the shell
wraps at TTY_WIDTH), with the glyph cell scaled to fill the active resolution.
The TTY driver became the console dispatcher: tty_write, tty_clear and
tty_set_cursor route to fbcon while it owns the display. That last one is what
makes nano work -- it positions with tty_set_cursor() rather than escapes, so
its full-screen repaint was landing as an append-only stream.
Also in this change:
- `video=WIDTHxHEIGHT` on the kernel command line selects the display mode,
defaulting to 1280x720 so a 16:9 host panel is filled rather than pillarboxed
when QEMU goes fullscreen. Rejects modes the heap cannot back.
- `make run-fullscreen`, plus zoom-to-fit on the windowed target, so scaling
preserves the guest aspect ratio instead of stretching it.
- QEMU targets raise vgamem_mb, since a 1280x720 32-bit surface exceeds the
default VGA memory.
- bochs_vbe_disable()/fb_set_active() let the framebuffer be marked dormant so
drawing routines no-op after a mode teardown.
Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01L5yKJT4Wo2cV3rfPrwY5MP
Pressing Esc left the desktop and started the shell, but nothing appeared in the
emulator window -- the session was only visible on the host terminal. Once the
VBE adapter is switched into graphics mode the VGA text buffer at 0xB8000 stops
being scanned out, so every printk after that point reached serial and the
dmesg ring but never the display.
Disabling the DISPI interface does not bring the text console back; QEMU keeps
presenting the last framebuffer surface. So rather than clawing the adapter back
to text mode, the console is now rendered into the framebuffer:
drivers/video/fbcon.c draws the console with the shared 8x8 font and carries a
VT100 subset -- SGR colours, cursor addressing, relative moves, erase-display,
erase-line and save/restore. It presents a fixed 80x25 grid, because that is
the geometry the userland assumes (nano pads its bars with %-80s, the shell
wraps at TTY_WIDTH), with the glyph cell scaled to fill the active resolution.
The TTY driver became the console dispatcher: tty_write, tty_clear and
tty_set_cursor route to fbcon while it owns the display. That last one is what
makes nano work -- it positions with tty_set_cursor() rather than escapes, so
its full-screen repaint was landing as an append-only stream.
Also in this change:
- `video=WIDTHxHEIGHT` on the kernel command line selects the display mode,
defaulting to 1280x720 so a 16:9 host panel is filled rather than pillarboxed
when QEMU goes fullscreen. Rejects modes the heap cannot back.
- `make run-fullscreen`, plus zoom-to-fit on the windowed target, so scaling
preserves the guest aspect ratio instead of stretching it.
- QEMU targets raise vgamem_mb, since a 1280x720 32-bit surface exceeds the
default VGA memory.
- bochs_vbe_disable()/fb_set_active() let the framebuffer be marked dormant so
drawing routines no-op after a mode teardown.
Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01L5yKJT4Wo2cV3rfPrwY5MP
Boot logo (init/bootlogo.c, init/logo_data.c, scripts/mklogo.py):
The logo appears in two forms because the framebuffer does not exist for the
first third of boot. An ASCII rendition goes to the text console and serial
line from the first moments; once the video driver is up at step [5/14] the
real bitmap takes over as a graphical splash with a progress bar tied to the
actual boot stages.
The asset is 4-bit palette indexed, so 160x160 pixels cost 12.5 KB instead of
100 KB, and carries a transparency mask so the mark composites onto the
gradient rather than stamping a flat rectangle over it. scripts/mklogo.py
regenerates init/logo_data.c from the source PNG.
Boot reaches the desktop in well under a second, so the splash is held for a
minimum duration and the bar sweeps to 100% during the hold; without that the
logo would flash past unseen. `splashtime=<ms>` tunes it and `nosplash`,
`nogui` or `text` skip it.
Bootloader (boot/stage2.asm):
stage2 staged the whole kernel in conventional RAM before copying it to 1 MB,
which capped the kernel at roughly 576 KB before the load ran into video
memory at 0xA0000. The logo pushed it over that line and the kernel stopped
booting. Each 32 KB chunk now goes into one fixed low buffer and is copied
straight to its final address, using unreal mode for the 32-bit reach. The
ceiling is now the image itself, 1.375 MB.
Console font (lib/font8x8.c):
fb_draw_char was a stub that ignored its character argument and drew a filled
rectangle, which is why the splash rendered its text as solid blocks. It now
renders real glyphs, and the table it uses is shared: the framebuffer console,
the canvas rasterizer and the desktop compositor had three divergent private
copies, two of which still carried the `// \` line-continuation defect.
printk console sink (kernel/printk.c):
printk output can be redirected to a callback, so a caller can run a subsystem
that reports via printk and capture what it printed. Serial and the dmesg ring
still see everything, which keeps a captured run debuggable.
Shell builtins (userland/lazybox/shell.c):
The builtin chain is extracted into shell_execute_builtin(), so the kernel TTY
and the desktop terminal accept the same vocabulary instead of the GUI seeing
only the applet table. Callers that cannot be suspended pass allow_blocking =
false to refuse the animating ones.
Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01L5yKJT4Wo2cV3rfPrwY5MP
The GUI terminal recognised four hardcoded strings and answered everything else
with "Executed: '<cmd>'". It now dispatches to the same LazyBox applet table and
shell builtins the kernel TTY uses, so ls, free, uname, lspci, ktest, neofetch,
sort, cd and the rest all work, with cwd tracked across commands.
LazyBox reports through printk, so before running a command the terminal
installs a printk sink and streams the output into its own scrollback:
- ANSI SGR codes become per-line colours instead of being stripped.
- CP437 box-drawing and block characters fall back to ASCII, so the colour
swatch in neofetch renders as '#' rather than a row of '?'.
- 256 lines of scrollback, command history on Up/Down, PgUp/PgDn/Home/End.
- Applets that read the keyboard directly (nano, snake, sh, top) are refused
with a pointer to the TTY, since they would block the compositor.
The window's paint and event handlers moved out of gui_apps.c into
gui/gui_terminal.c, and gui_gfx.c now draws from the shared lib/font8x8.c table
rather than its own copy.
Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01L5yKJT4Wo2cV3rfPrwY5MP
Boot logo (init/bootlogo.c, init/logo_data.c, scripts/mklogo.py):
The logo appears in two forms because the framebuffer does not exist for the
first third of boot. An ASCII rendition goes to the text console and serial
line from the first moments; once the video driver is up at step [5/14] the
real bitmap takes over as a graphical splash with a progress bar tied to the
actual boot stages.
The asset is 4-bit palette indexed, so 160x160 pixels cost 12.5 KB instead of
100 KB, and carries a transparency mask so the mark composites onto the
gradient rather than stamping a flat rectangle over it. scripts/mklogo.py
regenerates init/logo_data.c from the source PNG.
Boot reaches the desktop in well under a second, so the splash is held for a
minimum duration and the bar sweeps to 100% during the hold; without that the
logo would flash past unseen. `splashtime=<ms>` tunes it and `nosplash`,
`nogui` or `text` skip it.
Bootloader (boot/stage2.asm):
stage2 staged the whole kernel in conventional RAM before copying it to 1 MB,
which capped the kernel at roughly 576 KB before the load ran into video
memory at 0xA0000. The logo pushed it over that line and the kernel stopped
booting. Each 32 KB chunk now goes into one fixed low buffer and is copied
straight to its final address, using unreal mode for the 32-bit reach. The
ceiling is now the image itself, 1.375 MB.
Console font (lib/font8x8.c):
fb_draw_char was a stub that ignored its character argument and drew a filled
rectangle, which is why the splash rendered its text as solid blocks. It now
renders real glyphs, and the table it uses is shared: the framebuffer console,
the canvas rasterizer and the desktop compositor had three divergent private
copies, two of which still carried the `// \` line-continuation defect.
printk console sink (kernel/printk.c):
printk output can be redirected to a callback, so a caller can run a subsystem
that reports via printk and capture what it printed. Serial and the dmesg ring
still see everything, which keeps a captured run debuggable.
Shell builtins (userland/lazybox/shell.c):
The builtin chain is extracted into shell_execute_builtin(), so the kernel TTY
and the desktop terminal accept the same vocabulary instead of the GUI seeing
only the applet table. Callers that cannot be suspended pass allow_blocking =
false to refuse the animating ones.
Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01L5yKJT4Wo2cV3rfPrwY5MP
Turns the desktop from a fixed set of hand-drawn panels into a real
environment applications can be written against.
SUB-WT immediate-mode toolkit (gui/gui_widgets.c):
Buttons, labels, checkboxes, radios, sliders, list boxes, text fields, tab
bars, scrollbars, progress bars, sparklines and badges. An app feeds the WM
event into the toolkit and then calls widgets from its paint routine, so
each call both draws the control and reports what the user did with it --
no retained widget tree to keep in sync with window state.
Icons and dialogs:
gui_icons.c holds 14 16x16 palette-indexed glyphs stored as hex text, so the
art stays hand-editable and picks up theme changes for free; they scale by
integer factors and can be drawn as tint stencils. gui_dialog.c adds modal
info/warning/error/confirm dialogs that dim the desktop, take exclusive
input, word-wrap on spaces and report results through a callback.
Applications (gui/gui_apps_ext.c):
Settings (tabbed appearance/input/power), Task Manager (live process table
over task_find_by_pid with memory and heap gauges), Kernel Log viewer (reads
the dmesg ring, strips ANSI, colours by severity, scrolls), KTest Runner
(drives the in-kernel suites and reports 21/21 with timing), Clock & Calendar
(Zeller's congruence month grid) and a Text Editor.
Window manager (gui/gui_wm.c):
Minimize/maximize/restore buttons, a corner resize grip, edge snapping, tile
and cascade layouts, F5-F9 shortcuts, title truncation, and index-based
enumeration so the taskbar no longer assumes window ids stay dense.
Desktop shell (gui/gui_desktop.c):
Launcher icon grid, richer start menu, right-click context menu, taskbar
buttons that minimize and restore, and a live CPU trace in the tray.
Two interaction bugs fixed along the way:
- keyboard_get_key() blocks until a key arrives, so calling it every frame
froze the compositor; it is now gated on keyboard_has_key(), and stale
console input is drained before the first frame.
- When the desktop consumed a click, the WM's press-edge detector kept the
pre-press state and read the still-held button as a fresh press on the
next frame, stealing focus from whatever the click had just opened.
gui_wm_sync_button_state() keeps the two layers in step.
Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01L5yKJT4Wo2cV3rfPrwY5MP
Expands the kernel-and-TTY core with the primitives the higher layers have
been missing, plus an in-kernel harness that proves they work.
Data structures (lib/):
- rbtree.c: Linux-compatible red-black tree with parent pointers, full
insert/erase rebalancing, in-order iteration and an invariant validator.
- kfifo.c: power-of-two byte ring with free-running indices, so the wrap
path costs one mask instead of a branch per byte.
- hashtable.c: separately-chained table with FNV-1a hashing, string or
u64 keys, and rehash-on-growth at a 3/4 load factor.
Kernel subsystems:
- kernel/wait.c: wait queues and one-shot completion barriers, backed by a
static sleeper pool so a blocking path never re-enters the allocator.
- kernel/futex.c: 32-bucket futex hash with value re-check, requeue, and an
fmutex_t sleeping mutex built on the uncontended-fastpath protocol.
- kernel/rcu.c: tiny RCU with reader nesting, deferred callbacks, kfree_rcu
and rcu_assign_pointer/rcu_dereference publish barriers.
- mm/page_cache.c: write-back block page cache, 4 KB pages indexed by
(device, page), CLOCK second-chance eviction and dirty write-back.
- kernel/ktest.c: KUnit-style harness with 6 built-in suites, 21 cases and
735 assertions covering every subsystem above (all passing under QEMU).
LazyBox userland:
- coreutils.c: sort, uniq, cut, tr, rev, tac, nl, seq, diff, xxd, du,
factor, sum and truncate, reading through the VFS and handling the
zero-length synthetic nodes that procfs and sysfs expose.
- ktest, rcuinfo, futexinfo, waitinfo and pagecache diagnostics applets.
Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01L5yKJT4Wo2cV3rfPrwY5MP
- Upgrade resolution to 800x600 @ 32bpp TrueColor with Bochs/QEMU VBE LFB
- Implement full 8042 Aux PS/2 mouse controller driver on IRQ 12 (vector 44) with packet decode and bounds clamping
- Add high-definition 8x16 font rasterizer with text drop shadows for sharp typography
- Upgrade to smooth 16x24 anti-aliased cursor with dark slate outline and drop shadow
- Increase titlebars to 24px and taskbar to 32px with modern desktop styling
- Re-architect applications (SysMon, Terminal, Explorer, Calc, Paint, About) for spacious high-res display
- Integrate Bochs/QEMU VBE physical LFB mapping directly to hardware video memory (0xFD000000)
- Update kernel boot sequence to directly boot into GUI Desktop by default
- Fall back to Emergency Kernel TTY Mode upon GUI exit (Esc key / Exit menu item)
- Support 'nogui', 'text', 'emergency', and 'single' boot arguments to boot directly into text mode
- Remove frame limits so GUI runs persistently
- Create separate feature branch 'feat/gui-desktop'
- Implement double-buffered 2D graphics engine with alpha blending, gradients, rounded rects, and font rasterization in gui/gui_gfx.c and include/gui/gui_gfx.h
- Implement alpha-blended mouse pointer overlay in gui/gui_cursor.c and include/gui/gui_cursor.h
- Implement SUB-WM Window Manager with draggable titlebars, close/minimize buttons, drop shadows, and event routing in gui/gui_wm.c and include/gui/gui_wm.h
- Implement Cyberpunk/Nord desktop environment with wallpaper, taskbar, start menu popup, and system tray in gui/gui_desktop.c and include/gui/gui_desktop.h
- Implement built-in GUI apps: System Performance Monitor, GUI Terminal Emulator, File Explorer, Calculator, Paint Studio, and About dialog in gui/gui_apps.c and include/gui/gui_apps.h
- Add 'startx', 'gui', and 'desktop' applets in LazyBox suite
- Verified multi-architecture compilation across x86_64, AArch64, and ARMv8i
- Implement Intel 82574L / 82567LM / I217 / I219 PCIe Gigabit NIC driver with DMA ring buffers and auto-negotiation in drivers/net/e1000e.c and include/drivers/e1000e.h
- Implement VirtIO-GPU 2D hardware graphics display adapter driver with dirty rect flushing in drivers/virtio/virtio_gpu.c and include/drivers/virtio_gpu.h
- Implement Dynamic CPU Frequency Scaling and ACPI CPPC Power Governor with performance, powersave, ondemand, conservative, and schedutil policies in drivers/power/cpufreq.c and include/drivers/cpufreq.h
- Implement VirtIO-Input para-virtualized tablet/mouse event driver in drivers/virtio/virtio_input.c and include/drivers/virtio_input.h
- Expand stage2 kernel bootloader loading boundary to 768 KB (1536 sectors)
- Add LazyBox applets: 'cpufreq', 'gpuinfo', 'e1000e'
- Verified across x86_64, AArch64, and ARMv8i targets
- Add dedicated Linux-compatible Tree visualizer with UTF-8/ASCII branch tracking, -L depth filtering, human sizes, and permissions in userland/lazybox/tree.c
- Implement Hardware Invariant Timestamp Counter (TSC) calibration and microsecond delay timer in kernel/tsc.c and include/kernel/tsc.h
- Add Virtual Terminal color palette, live resource utilization bars, and logo banner in kernel/vt_art.c and include/kernel/vt_art.h
- Add LazyBox applets: 'tree', 'tscinfo', and 'vtart'
- Update README.md documentation and command matrix
- Implement modern freestanding C++17 containers (Vector<T>, UniquePtr<T>, String) in kernel/cpp/cpp_containers.hpp
- Implement object-oriented Device driver model (Device, BlockDevice, CharDevice, VirtualRamDiskDevice, VirtualNullDevice, VirtualZeroDevice, DeviceManager) in kernel/cpp/cpp_device.hpp and kernel/cpp/cpp_device.cpp
- Add C++ kernel performance microbenchmark suite in kernel/cpp/cpp_bench.cpp
- Export C-FFI bridges and add cross-architecture fallbacks in kernel/cpp/cpp_fallback.c and include/kernel/cpp_kernel.h
- Add LazyBox applets: 'cppdevs' and 'cppbench'
- Update README.md documentation and command matrix
- Add memory-safe ELF-64/32 binary header and program header inspector in rust/src/kernel/elf.rs
- Implement Buddy allocator and external memory fragmentation analyzer in rust/src/mm/buddy_analyzer.rs
- Add RFC-8439 Poly1305 128-bit message authenticator and ChaCha20-Poly1305 AEAD in rust/src/crypto/poly1305.rs and rust/src/crypto/chacha20poly1305.rs
- Export C-FFI bridges and add cross-architecture fallbacks in rust/rust_fallback.c and include/kernel/rust.h
- Add LazyBox applets: 'readelf', 'buddyinfo', and 'aead'
- Update README.md documentation and command matrix
- Implement flicker-free atomic double-buffered frame rendering and sub-tick input polling in userland/lazybox/snake.c
- Add multi-input support (PS/2 keyboard scancodes and serial ANSI arrow escape sequences)
- Add sound effects (food beep, game over chime) and live speed scaling (+/- keys, P to pause)
- Add POSIX /dev/shm shared memory subsystem in ipc/shm_posix.c and include/ipc/shm_posix.h
- Add DNS resolver cache with TTL tracking in net/ipv4/dns_cache.c and include/net/dns_cache.h
- Add audio tone and jingle synthesizer in sound/beep.c and include/sound/beep.h
- Add %o octal formatting support in lib/vsprintf.c
- Add LazyBox applets: 'shm', 'dnscache', and 'beep'
- Add freestanding C++17 runtime with operator new/delete, pure virtual handlers, and global constructor execution in kernel/cpp/cxx_runtime.cpp
- Implement C++ Object-Oriented telemetry and hardware services with polymorphism in kernel/cpp/cpp_module.cpp and include/kernel/cpp_kernel.h
- Add interactive ANSI Snake Game in userland/lazybox/snake.c with real-time keyboard control and automated simulation mode
- Initialize C++ subsystem during kernel boot step [8/14] in kernel/main.c
- Add LazyBox applets: 'snake', 'cppinfo', and 'cpptest'
- Add #include <lib/printf.h> in fs/vfs.c, include/lib/string.h, and include/kernel/printk.h
- Ensure snprintf is always declared during freestanding compilation
- Add native .sb kernel modules in sub/ (signature.sb, power_governor.sb, benchmark.sb, easter_egg.sb)
- Implement in-kernel SUB Language VM and AST interpreter in kernel/sub/sub_vm.c
- Implement C-interop runtime in kernel/sub/sub_runtime.c and include/kernel/sub_lang.h
- Initialize SUB Language Engine in boot sequence step [8/14] in kernel/main.c
- Implement strtol in lib/string.c
- Add LazyBox applets: 'subinfo', 'subi', 'subpower', 'subbench', and 'subquote'
- Add 'clear' and 'cls' builtin handlers in LazyBox shell
- Output ANSI \033[2J\033[H sequence on tty_clear() to clear serial/UART terminals
- Support both ASCII 0x7F (DEL) and 0x08 (BS) for Backspace in shell and nano editor
- Connect 16550 serial input to keyboard_get_key() on x86_64 for headless terminals
- Add ANSI escape sequence decoding for arrow keys (Up/Down/Left/Right/Home/End/Del)
- Update Makefile 'make run' and 'make qemu' with -display none for smooth terminal execution
- Add 'make run-gui' target for optional graphical SDL/GTK window