Rework the compositor so it stops repainting the whole screen every frame,
tripling the frame rate (17 -> 54 FPS at HD) and adding smooth animation.
- Scene-dirty skipping (gui/gui_desktop.c): the full scene is recomposited only
when something other than the bare pointer changed -- input, an open animation,
or a ~10 Hz heartbeat for live content (clock, graphs). Idle and pointer-only
frames skip the recomposite entirely.
- Cursor save-under (gui/gui_cursor.c): the pointer is an overlay that stashes
and restores the pixels beneath it, so moving the mouse never forces a full
repaint -- pointer motion runs at the frame cap.
- 60 FPS frame pacer: each iteration is timed against the monotonic clock and
padded to a 16.666 ms budget with the new ktime_delay_us() (HPET-precise
busy-wait), giving consistent pacing instead of a free-running spin.
- Window open animation (gui/gui_wm.c): new windows grow from 60% to full size
with a cubic ease-out over ~160 ms; gui_wm_update() drives it and reports
while any window is still animating so the compositor keeps redrawing.
- Default display mode set to 1280x720 (HD) -- the sweet spot where the
software compositor sustains a near-60 FPS cursor with headroom for effects.
Kernel: kernel/time/ktime.c gains ktime_delay_us(), a precise HPET-based delay
(bounded PIT fallback) used by the pacer.
Verified live (screenshotted): boots to 1280x720, logs in, tray reads ~54 FPS
(green) while the pointer moves, no cursor ghosting, windows render cleanly.
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
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
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
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
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
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
bochs_vbe_init switches the adapter into graphics mode at boot step [5/14], and
from that point the VGA text buffer is no longer scanned out. This kernel boots
to a TTY, so every message after that -- and the whole shell session -- was
invisible in the emulator window and reached only the serial line.
The console now moves to the framebuffer at that transition, which also makes
the nano editor render correctly: it positions with tty_set_cursor() rather than
escape sequences, and the TTY driver dispatches that to fbcon.
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
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
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
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
- 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
- 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 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 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