Skip to content

Releases: milescoviello/OS-DEV

OS-DEV v1931 — stylesheets can lay out a page, virtual desktops, and the intermittent hang fixed

Choose a tag to compare

@milescoviello milescoviello released this 11 Sep 02:41

Three strands since v1916: the browser can finally be laid out by a stylesheet,
the desktop got virtual desktops and the keyboard chords people actually press,
and a code review of that work found ten defects worth fixing.

The browser can be laid out by a stylesheet (M1928-M1931)

Found by pointing the browser at real sites and looking at the result rather
than guessing which CSS feature to add next. One screenshot of example.com
exposed three separate gaps:

  • The CSS cascade carried no box geometry at all. The rule table stored
    colour, background, align, border and the rest — but no width, margins,
    padding or height, and all of those came only from an inline style=
    attribute. So a stylesheet could not lay out a page, which is how essentially
    every real page is built.
  • No viewport units. vw/vh were unparsed, so width:60vw was discarded.
  • <body> can never own a box. It is consumed by a terminal branch in the
    tag parser. It does not need one — body's box is the page's content column.

example.com now renders as the centred column its stylesheet asks for.

Also float and clear (M1928). browser.c's own comment listed float with
position and z-index as needing out-of-flow boxes; that was wrong for float.
A floated image is just an obstacle: record the vertical band it occupies and
have every line box consult it for a left/right inset — that inset is text wrap.
And a display:flex <li> no longer draws a bullet (M1931), because
display is one property and flex replaces list-item — danluu.com relies on it.

Verified by screenshot: danluu.com (22 KB of real HTML) and a full article render
close to a real browser, and text.npr.org shows live headlines as working links.

Desktop (M1920-M1925)

The features mostly already existed but were bound to keys nobody presses —
Alt+Tab, Alt+F4, Super and Super+Arrow all did nothing. They work now, including
on a USB keyboard, where none of them worked at all (the raw scancode queue
was fed only by the PS/2 handler — invisible under QEMU, and only ever visible on
real hardware). Plus 4 virtual desktops with Ctrl+Alt+Arrow and Super+1..4,
and the desktop finally has automated tests.

Ten defects from reviewing that work (M1926)

Including a type-confused write (a stale window pointer after a chord
reordered the window array handed a browser_t* to a raw-keyboard app) and a
use-after-free (the switcher's index was never clamped when a background app
exited). Also: every new chord fired twice, and kvprintf held interrupts off
for ~7 ms per line on real hardware.

Earlier in this line

v1916's scheduler fix (sub-millisecond yields charged zero vruntime, starving
lock holders) remains the single most important change — it was the root cause of
years of "intermittent" hangs.

make check is green: 131 suites.

Try it

Download os-dev-tryit.zip, unzip, and see RUN_ME.md — one QEMU command.

OS-DEV v1916 — the intermittent-hang bug, found and fixed

Choose a tag to compare

@milescoviello milescoviello released this 31 Jul 06:46

This release is mostly one thing: a real kernel scheduler bug that had been
causing "intermittent" hangs for many milestones is finally found and fixed.

The bug (M1912)

schedule() charged CPU time as timer_ms() - last_in — millisecond
granularity. Every spin-then-yield lock in the kernel spins ~1000 pause
iterations (microseconds) and then yields, so the measured slice was 0 and the
waiter's vruntime never moved. CFS always picks the smallest vruntime, so the
waiters won every pick and the task holding the lock was never scheduled again.

Captured mid-deadlock:

min_vr=1420 | id7 vr=1420 (spinning on ata_lock)
            | id6 vr=1420 (spinning on ata_lock)
            | id0 vr=1430 READY, HOLDS ata_lock, never picked

Ten units behind was enough to starve forever. The fix floors the per-switch
charge at 1 so vruntime strictly increases.

One bug explained the boot TLS "stall", the HTTP server test's long-running
flakiness (a wedged holder means nothing can read the disk, so the server never
loads), and most likely the "residual" ATA flakiness blamed on the disk since
M1541 — that milestone added the task_yield() which converted a livelock into
this starvation.

Found by sampling the instruction pointer through the QEMU monitor after
printf-debugging kept moving the apparent hang location. Proven with a
deterministic self-test rather than statistics: 64 fast yields must advance
vruntime by ≥64 — 64 with the fix, 0 without.

Three more races, from auditing the class instead of stopping

  • CMOS clock (M1913) — 0x70/0x71 index/data pair with no lock and ~21
    concurrent callers (desktop clock, file timestamps, ring-3 clock_gettime). An
    interleave returns another register as the time; rtc_set wrote the time into
    the wrong register. Two unbounded loops also bounded.
  • PCI config space (M1914) — 0xCF8/0xCFC, no locking, 13 files, reachable
    from ring 3 via /pci/.... Sub-word writes were read-modify-write, so two
    drivers setting their own bit in one dword could lose an update.
  • kprintf (M1915) — no lock at all, so concurrent log lines spliced
    character-by-character and corrupted the serial log every headless test greps.

Each fix ships with a self-test that was mutation-tested by removing the lock —
including one first attempt that ran 3001 unlocked reads and detected nothing,
which is why the tests now deliberately widen the race window.

Also

  • CSS max-height (M1910), which a comment in the renderer wrongly claimed was
    architecturally impossible. It is the symmetric clamp to height/min-height,
    plus suppression of the block background under spilled content.
  • Boot self-tests are gated behind -append selftest (M1916) so normal
    boot-to-desktop stays at 1.21 s.

Full make check is green: 130 suites.

Try it

Download os-dev-tryit.zip, unzip, and see RUN_ME.md — one QEMU command.

OS-DEV v1908 — real CSS box model, USB 3.0 block devices, I/O APIC, and a test suite that catches things

Choose a tag to compare

@milescoviello milescoviello released this 30 Jul 22:55

A from-scratch x86_64 operating system — kernel, SMP scheduler, its own TCP/IP
stack + TLS 1.3, a JavaScript engine, a sandboxed ring-3 web browser, a
crash-consistent journaling filesystem, and a graphical desktop — all written
from scratch. 20 milestones past v1888 (M1889 → M1908).

This release is mostly about making the browser's box model real and
making the test suite actually able to catch things. Several of the bugs
below had been sitting in a fully green test run.

Try it now

Download os-dev-tryit.zip, unzip, and follow RUN_ME.md for a one-line
qemu-system-x86_64 command (only QEMU required) — boots to the graphical
desktop in about 1.5 seconds and runs a live HTTP + HTTPS-over-TLS-1.3 fetch
with real certificate-chain validation over the from-scratch network stack. A
standalone BOOTX64.EFI is included to boot real hardware over UEFI.

Highlights since v1888

  • USB disks are real block devices on USB 2.0 and 3.0. A disk behind EHCI or
    xHCI used to be enumerated, read once at LBA 0 inside a self-test, and then
    forgotten — no capacity, no arbitrary LBA, no writes, not mountable. Since real
    hardware has no UHCI controller at all, USB storage was effectively unusable
    off QEMU. The Bulk-Only Transport protocol now lives once in a pure,
    host-tested layer instead of three hand-copied transcriptions, and a 64 MiB
    FAT32 filesystem on a USB 3.0 disk mounts and lists its files.

  • A real CSS box model. width, height, min-height, margin:0 auto,
    asymmetric auto margins, horizontal and vertical padding, box-sizing: border-box, margin-bottom, and borders that stroke the border box. Built on
    a new pure layout engine implementing the CSS 2.1 §10.3.3 width constraint and
    §8.3.1 margin collapsing, with 95 mutation-tested known-answer checks.

  • Every live IRQ now runs through the I/O APIC, including the NIC's PCI line
    — which needed level-triggered/active-low routing and the ACPI MADT's
    polarity/trigger flags, both of which were previously being discarded.

  • The test suite can now catch rendering bugs. Three box-model bugs coexisted
    in a passing suite because nothing asserted rendered geometry. There is now a
    colour-keyed framebuffer check (28 assertions) that finds each block's box by
    exact RGB and asserts solved widths, centring, padding insets and border
    enclosure — and it is mutation-tested against the very bugs it exists to catch.

  • ~2,700 previously unasserted lines of POSIX IPC now have 89 in-guest checks
    — message queues (priority ordering), named semaphores (O_CREAT/O_EXCL,
    non-blocking trywait), shared memory (frames genuinely shared, size cap
    enforced), ptys, flock exclusion/sharing/pid-release, inotify filtering,
    eventfd, tmpfs, unix sockets, SysV IPC (all-or-nothing semop, mtype
    selection) and procfs.

Bugs fixed that a green test run had been hiding

  • A permanent-hang race in the PIC→I/O APIC handover. An interrupt arriving
    mid-handover got a PIC EOI instead of a LAPIC one, leaving the vector's
    in-service bit set forever. On the PIT that kills the scheduler's clock
    outright. Proven by widening the window until it reproduced deterministically.
  • TCP was destroying other connections' packets — any frame not matching the
    polling connection's 4-tuple was discarded, including frames owned by another
    live connection, so two concurrent network users starved each other.
  • Two UTF-8 BOM bugs: a BOM-prefixed HTML page was mis-detected as an image
    (a signed-char comparison that could never be true), and then rendered as raw
    markup.
  • A latent EHCI data-toggle desync on short bulk transfers.
  • USB keyboard probing was resetting an already-enumerated mass-storage
    device
    , leaving it registered but dead for the rest of the session.

Known issues

  • httpdtest fails intermittently in a full make check run and the cause is
    unproven. Measurement was repeatedly contaminated by stray QEMU processes
    holding the disk image's write lock, which produces failures indistinguishable
    from real ones. make check is 130/130 green on a clean host.
  • The boot HTTPS self-test can take a very long time after certificate-chain
    validation; the suspect is the bignum CertificateVerify path, which is known
    to be far slower than it should be.
  • float, position, z-index and max-height are not implemented, and
    the reason is architectural rather than effort: a block's painted extent is
    currently its flow advance, so out-of-flow boxes cannot be expressed. The box
    tree that would fix all four exists and is not yet wired in.

OS-DEV v1888 — reliable TCP, crash consistency, real-hardware bring-up

Choose a tag to compare

@milescoviello milescoviello released this 22 Jul 20:42

A from-scratch x86_64 operating system — kernel, SMP scheduler, its own TCP/IP
stack + TLS 1.3, a JavaScript engine, a sandboxed ring-3 web browser, a
crash-consistent journaling filesystem, and a graphical desktop — all written
from scratch. This snapshot is ~370 milestones past the previous release (v1519)
and completes all four "big swing" goals.

Try it now

Download os-dev-tryit.zip, unzip, and follow RUN_ME.md for a one-line
qemu-system-x86_64 command (only QEMU required) — boots straight to the
graphical desktop and runs a live HTTP + HTTPS-over-TLS-1.3 fetch over the
from-scratch network stack. A standalone BOOTX64.EFI is included to boot
through UEFI/GRUB on real hardware.

Highlights since v1519

  • Reliable, congestion-controlled TCP. The sender is no longer
    fire-and-forget: buffered unacked data, RFC 6298 RTT/RTO, go-back-N
    retransmission, 3-dup-ACK fast-retransmit, flow control, and TCP Reno
    congestion control (slow start / congestion avoidance / fast recovery).
    Verified against a deterministic packet-dropping test harness and by real
    HTTPS fetches to the internet.
  • Crash consistency. A from-scratch write-ahead journal makes filesystem
    metadata operations atomic across a power loss, on top of a unified kernel
    block cache — proven by a host harness that injects a crash at every write,
    plus in-guest replay tests. A follow-up correctness audit found and fixed a
    cross-mount data-corruption bug and several coherence/robustness issues.
  • Boots on real hardware, driven over the network. A UEFI/GRUB Multiboot2
    path, an Intel NIC driver, and an in-kernel network debug console ("netcon")
    let a diskless machine PXE-boot and be inspected/rebooted over ethernet.
  • Web browser fully in ring 3. The browser's HTTPS fetch (TLS 1.3 handshake,
    X.509 chain validation, ECDSA/RSA) runs entirely in userspace.
  • Real SMP. The scheduler runs ring-3 processes and kernel threads across all
    CPU cores.
  • WebSockets from scratch (RFC 6455 client over ws://+wss:// and a server),
    plus a large productivity/dev-tools app suite, and much more.

Details

See README.md for the
architecture and honest caveats, and
WHATS-NEXT.md for
the chronological changelog. The full make check suite (~100 host + in-guest
tests) is green.

OS-DEV v1519 -- cyberpunk desktop + try-it-now bundle

Choose a tag to compare

@milescoviello milescoviello released this 03 Jul 03:31

A from-scratch x86_64 OS: kernel, TCP/IP + TLS 1.3, a JS engine, a sandboxed
ring-3 web browser, and a from-scratch desktop with a new cyberpunk visual
theme (synthwave grid wallpaper, neon glow chrome).

Try it now

Download os-dev-tryit.zip below, unzip, and see the bundled RUN_ME.md
for a one-line qemu-system-x86_64 command (needs QEMU installed, nothing
else) -- boots straight to the graphical desktop.

What's in this snapshot

See WHATS-NEXT.md
for the full chronological changelog (1519 milestones) and
README.md for the
project overview, architecture, and honest caveats.