smp: a verbose boot triple-faulted, and vgpud drew a test card
Two reports, and the first one was not an F8 bug at all.
**Choosing "Boot SchOS (verbose)" appeared to do nothing.** The menu worked,
the flag crossed, and the kernel really did boot verbose -- and then the
machine *reset* partway through and the second boot was quiet. So what anybody
ended up looking at was an ordinary boot, which reads as "verbose is broken".
PROBE before startothers, ncpu=2 <- verbose boot
SchOS UEFI loader <- the firmware, again
PROBE before startothers, ncpu=2 <- quiet boot
PROBE after startothers
mpmain() opened with
kinfo("cpu%d: starting\n", cpunum());
enable_sse();
idtinit();
and the order is the bug. enable_sse() clears CR0.EM; until it runs, *any* SSE
instruction on that CPU faults, and the kernel is not built with -mno-sse, so
the compiler emits them freely for struct copies and inline memset. idtinit()
loads that CPU's IDT; until it runs there is nowhere for a fault to go. So the
#UD is not a panic -- it is a double fault with no handler, then a triple
fault, then the firmware comes back up. A triple fault prints nothing, which is
why there was no last line to go on.
**Why only on a verbose boot**, which is what disguised it as an F8 problem:
kinfo() is log-only when the boot is quiet, so the work is a few bytes into a
ring and no XMM is involved. A verbose boot renders that same line through the
TrueType rasteriser, and that is where the SSE lands.
Setup first, announcement second. The general rule, stated where the next
person will meet it: a processor announces that it is up after it is able to
run, not before.
Verbose now boots once and puts the whole log on the screen -- `verbose boot:`
lines, `cpu1: starting`, the mount, `schinit: ready`, the jobs starting -- which
is what F8 was for and what a machine with no serial port needs.
**And vgpud drew a test card.** Three colour bands, four gradients, a
checkerboard, and the driver's own pid in binary along the bottom edge. That
was scaffolding for hybrid.md's H2 and H3: a screenshot had to answer "did a
*userspace process* put this here", and "did the driver come back" needed a
restarted instance to look different from one that never stopped. Both
milestones closed a while ago and the test card stayed, so a second display
showed something garish with nothing to explain it.
It draws the Shift mark on SCH_BG now, from the same include/logo.h the loader
splash and the kernel console use. That answers the same question a black
screen cannot -- something is driving this device -- as the system rather than
as a test rig.
Also: vgpud's "no control socket" line is vputs, not puts. It is progress, not
news, and it was printing on the console of every quiet boot.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
3f13989883
commit
bcd4d4e2bd
4 changed files with 96 additions and 42 deletions
|
|
@ -284,10 +284,34 @@ enable_sse(void)
|
|||
static void
|
||||
mpmain(void)
|
||||
{
|
||||
kinfo("cpu%d: starting\n", cpunum());
|
||||
// **Set the processor up before saying anything.** This used to announce
|
||||
// itself first, and that reset the machine on any verbose boot with more
|
||||
// than one CPU -- silently, with no panic and no last line, because the
|
||||
// failure is a triple fault and a triple fault prints nothing.
|
||||
//
|
||||
// Two of the three lines below have to come first, and for different
|
||||
// reasons:
|
||||
//
|
||||
// enable_sse() clears CR0.EM. Until it runs, *any* SSE instruction on
|
||||
// this CPU faults -- and the kernel is not built with -mno-sse, so the
|
||||
// compiler emits them freely for struct copies and inline memset. A
|
||||
// quiet boot got away with it because kinfo() is log-only then and the
|
||||
// work is a few bytes into a ring; a verbose boot renders the line
|
||||
// through the TrueType rasteriser, which is where the XMM lands.
|
||||
//
|
||||
// idtinit() loads this CPU's IDT. Until it runs there is nowhere for a
|
||||
// fault to go, so the #UD above is not a panic -- it is a double fault
|
||||
// with no handler, then a triple fault, then the firmware comes back up.
|
||||
// That is why the only symptom was "F8 verbose reboots into a normal
|
||||
// boot": the machine really did reboot, and the second one was quiet.
|
||||
//
|
||||
// The general rule this is an instance of: a processor announces that it
|
||||
// is up after it is able to run, not before.
|
||||
enable_sse(); // allow user XMM/SSE instructions
|
||||
idtinit(); // load idt register
|
||||
syscallinit(); // syscall set up
|
||||
|
||||
kinfo("cpu%d: starting\n", cpunum());
|
||||
xchg(&mycpu()->started, 1); // tell startothers() we're up
|
||||
scheduler(); // start running processes
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue