boot: mirroring cannot stall the machine, and the loader says where it is

Two reports from an Asus TUF FA607NU, which now gets as far as the splash:
the progress bar does not move, and after a resolution change the screen keeps
the background colour with no mark and no bar. Both point at the same code,
and it is code this loader did not have a week ago.

**Modes were being matched on every frame.** mirrors_match() ran from inside
mirrors_show(), so every menu redraw and every segment of the kernel load
asked another display adapter to change mode. On QEMU that is instant and
idempotent. On real hardware a mode set can take the best part of a second, can
blank a panel while it happens, and -- on a laptop -- is quite often being
asked of the *same* panel reached through a second GOP. A loader that does that
in the middle of drawing a progress bar is a loader that shows a background
colour and then waits on a firmware call that is not coming back.

It now happens exactly once, at discovery, before anything is drawn. The
second head is centred and cropped afterwards rather than re-moded, and the
booted system matches resolutions anyway because the kernel driver and vgpud
both follow the console.

**And mirroring no longer runs per segment of the kernel load.** Copying a
megabyte-and-a-half framebuffer to every other adapter, three times, to animate
a bar on a screen nobody is looking at.

**One refusal now turns it off for the rest of the boot**, and
`\schos\nomirror` -- an empty file whose only job is to exist -- turns it off
before it starts. There is no console to ask a question on at that point and no
menu to reach if the menu is what is broken, so the answer has to already be on
the volume. That also makes it a one-file experiment on hardware we cannot
instrument.

**The loader names its stages on screen.** After the splash, print() goes to
the serial port and nowhere else, so on a machine with no serial port a stall
leaves a progress bar and no information at all. Every stage after the kernel
load now labels itself under the bar -- Reading the console font, Reading the
memory map, Leaving the firmware -- so the last thing on the screen names the
call that did not return. Past ExitBootServices there is nothing left to report
with, which is itself worth knowing: a machine stopped on the last label
stopped in the jump.

Opening the boot volume moved ahead of the display, because what is on the
volume now decides some of what the display does.

Both supported configurations: one boot each, no traps, no panics, socktest and
memfdtest green. Mirroring still verified end to end -- F8, a resolution
change, boot, and both heads byte-identical at the new mode.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Nexoniarz 2026-09-23 19:50:28 +02:00
commit 3a0b570c23
2 changed files with 130 additions and 15 deletions

View file

@ -122,6 +122,45 @@ when the early console is set up. So a low framebuffer is attached exactly as
before, and a high one is attached a few dozen instructions later, immediately
after `kvmalloc()` — still thousands of lines before anything else happens.
### The loader says which stage it is in
After the splash, `print()` goes to the serial port and nowhere else — writing
text into the framebuffer would scribble it across the splash. On a laptop with
no serial port that means the last thing on screen is a progress bar, and a
loader that stops has no way to say where.
So every stage after the kernel load names itself under the bar:
*Reading the console font*, *Reading the memory map*, *Leaving the firmware*.
On a machine that works these are invisible — they take microseconds — and on
one that stops, the label is the last thing on the screen and names the call
that did not come back. It costs three strings.
Past `ExitBootServices` there is nothing left to report with, so the final
label stands for the whole of the jump into the kernel.
### Mirroring is a nicety, and booting is not
`mirrors_show()` copies the primary's framebuffer onto every other display
adapter with `Blt`. Three rules keep a cosmetic feature from being able to stop
a machine:
**Modes are matched once, at discovery, before anything is drawn.** It used to
be done inside `mirrors_show()` — which is to say on every menu redraw and
every segment of the kernel load. Setting a mode is not a cheap call on real
hardware: it can take the best part of a second, it can blank a panel while it
happens, and on a laptop the "other" adapter is quite often the *same* panel
reached through a second GOP. Doing that repeatedly, in the middle of drawing a
progress bar, produces a machine showing a background colour and nothing else
while the loader waits on a firmware call.
**One refusal turns it off for the boot.** A `Blt` that fails once will fail
every time, and retrying it on every screen is how a nicety becomes a hang.
**`\schos
omirror` disables it entirely.** An empty file whose only job is to
exist. There is no console to ask a question on and no way to reach a menu if
the menu is what is broken, so the answer has to already be on the volume.
### Modes a real machine actually has
`mode_usable()` rejected three things it should not have: