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:
parent
26e5d89c73
commit
3a0b570c23
2 changed files with 130 additions and 15 deletions
|
|
@ -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:
|
||||
|
|
|
|||
Loading…
Reference in a new issue