Commit graph SchOS/boot/common/ui.c
Author SHA1 Message Date
Nexoniarz
55a585792e boot/uefi: an F8 menu, with the resolution chooser inside it
UEFI had no boot menu at all, and asked about resolution in a prompt of
its own before anything else. Two questions at two moments through two
mechanisms is what made the firmwares feel like different programs.

There is one window now: press F8 (or 'o' -- a serial console sends no
scan codes, and that is how this is usually driven) and the same panel
the BIOS loader shows appears, with resolution as a row in it. Selecting
it steps to the next 32bpp mode at or above 800x600 and redraws; the
framebuffer is re-read every pass, because changing mode moves it and
drawing where it used to be is a black screen with no explanation.

Two layout bugs, both visible and both arithmetic:

  - TITLE_H was 34 while the heading alone occupies PANEL_PAD + GLYPH_H
    = 34, so the rule at TITLE_H - 6 was drawn *through* the lettering
    and the first row started on the heading's baseline. TITLE_H is
    derived from its parts now and cannot drift from them again.
  - the selected row's highlight was offset by a fixed 3px against a
    24px row, so it sat on the text rather than around it. It is centred
    on the glyph box: (ROW_H - GLYPH_H) / 2 above and below.

Verified from the host: the panel is centred at 640 on a 1280 screen, the
highlight is exactly ROW_H tall and clear of the rule, and Enter boots
through to cpu0. bootcheck 108 [ok], iso builds.

The BIOS resolution chooser is still a separate text prompt, and that is
not an oversight to fix later in the same way. VBE mode setting is an
INT 10h call, so it can only happen in real mode -- before there is any
framebuffer to draw a menu in. Offering it from the graphical menu means
either returning to real mode from long mode, or entering unreal mode to
draw the menu before the switch. Both are real mode-switching work in the
riskiest code in the tree, and neither is a tidy-up.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 09:04:57 +02:00
Nexoniarz
799abbc19a boot: one UI for both firmwares, and a metal look
The BIOS loader drew its own splash and the UEFI loader drew a different
one, which is how two implementations of a single screen end up looking
nothing alike: only one of them ever got a change. stage2main.c's
fourteen drawing functions are deleted and it calls boot/common/ui.c,
which is what the UEFI loader already used. There is one splash now.

What changed in the look, in order of how much it mattered:

  - No product name under the mark. The name is *in* the mark, and
    setting it again underneath read as a placeholder nobody removed.
  - The mark is scaled to the bar's width and sits directly above it, so
    the two are one object rather than a large logo with an unrelated
    line beneath. Box-filtered down from the source mask, never up:
    point-sampling a coverage mask drops half the edge pixels and puts
    holes in the thin strokes.
  - Metal rather than flat grey. A vertical gradient with a knee near the
    top where a highlight falls, applied to the mark, the bar fill and
    panel headings. A single colour on a dark ground looks printed; the
    knee is what makes it look lit. No texture -- at this size noise
    reads as dirt.
  - The boot manager is a panel with a lit selected row, replacing a
    screen laid out in literals with a magic y of 340 that only ever
    looked right at 800x600.

Three defects found by reading pixels rather than code:

  - the UEFI loader kept calling print() after the splash, and ConOut on
    a graphical firmware renders into the same framebuffer -- a
    screenshot showed firmware text across our mark from the left edge.
    Diagnostics go to COM1 directly now, which is where they were being
    read from anyway, and the console is cleared before drawing so the
    firmware has nothing to put back.
  - SPLASH_UP was declared and read but never assigned, so that redirect
    was dead code and the "serial works" reading was OVMF's own console.
  - stage2 overflowed its allocation -- 25440 bytes against 24576 -- and
    the build did not stop. The kernel is written at sector
    1 + STAGE2_SECTORS, so a stage2 past its allocation is overwritten by
    the kernel it is loading. STAGE2_SECTORS is 64 now, and the padding
    tool's check does fire; it had simply not been re-run.

Verified from the host on both: BIOS 800x600 and UEFI 1280x800 both draw
a centred group with zero stray pixels, UEFI's spanning x 576-703 which
is exactly the mark width centred. bootcheck 108 [ok], iso builds.

Still text-mode: the resolution menu. On BIOS it necessarily is -- it
runs in real mode before any framebuffer exists, which is the whole
reason it can set one. On UEFI it could be graphical and is not yet.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 08:49:44 +02:00
Nexoniarz
64e4835524 boot: a shared UI, and a graphical splash on UEFI
The first piece of the two loaders that is genuinely common code rather
than a contract they both honour. It can be, because the difference
between the firmwares is entirely in how a framebuffer is *obtained* --
VBE in real mode, or GOP -- and not in what you do with one afterwards.
boot/common/ui.c takes a base, a size and a stride and draws; it knows
nothing about disks, memory maps or mode setting, which is what lets it
compile into a 16/32/64-bit BIOS loader and a PE/COFF UEFI application
without either leaking into it.

The look is deliberately quiet: dark ground, the mark centred, one thin
bar beneath it, nothing on screen that is not load-bearing. The whole
group is laid out from the centre outwards rather than from the top down,
so it sits identically at 800x600 and at 1600x1200 instead of drifting up
the screen as the mode grows.

UEFI had no graphical splash at all -- it printed text to a console the
QEMU window is usually not even showing. It draws the same screen as the
BIOS path now, with the bar tracking bytes of kernel actually written
rather than a segment count, which says nothing about how long each takes.

Two ordering bugs found by looking at the pixels rather than the code:
setup_framebuffer ran *after* the kernel was read, so every progress tick
went to a framebuffer that did not exist yet and the splash then painted
over the result; and that also put the resolution prompt after the
slowest step instead of at the start. The display is set up first now.

Verified from the host with screendump: background is exactly SCH_BG, the
bar is 4px tall and width/4 wide at y=495 on a 1280x800 screen, which is
where centring the group puts it. UEFI still boots to cpu0; BIOS
bootcheck 27/27.

Not yet shared: the BIOS loader still draws with its own copy of this
code. Deleting that copy in favour of this one is the next step and the
point of the exercise -- until then this is one loader using shared code
and one duplicating it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-10 22:26:54 +02:00