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
|
|
@ -28,6 +28,8 @@
|
|||
#include "virtio.h"
|
||||
#include "schinit.h"
|
||||
#include "socket.h"
|
||||
#include "theme.h" // SCH_BG, SCH_ACCENT -- one palette, see docs/branding
|
||||
#include "logo.h" // the mark, the same bytes the loader and console draw
|
||||
|
||||
// --- small output, since lib/ has no printf ---------------------------------
|
||||
|
||||
|
|
@ -555,49 +557,50 @@ present(void)
|
|||
|
||||
// --- something to look at ---------------------------------------------------
|
||||
|
||||
// Not a compositor. A pattern that is obviously deliberate, so a screenshot
|
||||
// answers "did a userspace process put this here" without ambiguity -- a black
|
||||
// screen and a working screen look identical if all you draw is black.
|
||||
// The mark, on the theme ground.
|
||||
//
|
||||
// This used to be a test card: three colour bands, four gradients, a
|
||||
// checkerboard, and this instance's 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 second run to look different from a first that never stopped. Both
|
||||
// milestones are closed, and what was left was a garish test pattern on a
|
||||
// second display with no explanation of itself.
|
||||
//
|
||||
// The mark answers the same question a black screen cannot -- something is
|
||||
// driving this device -- and answers it as the system rather than as a test
|
||||
// rig. Same include/logo.h the loader splash and the kernel console draw, so
|
||||
// there is one mark and one set of bytes.
|
||||
static void
|
||||
draw_test_pattern(void)
|
||||
draw_mark(void)
|
||||
{
|
||||
volatile unsigned int *fb = (volatile unsigned int *)fb_uaddr;
|
||||
int x0 = (width - LOGO_W) / 2;
|
||||
int y0 = (height - LOGO_H) / 2;
|
||||
|
||||
// A tally of this instance's pid along the bottom edge, because the thing
|
||||
// H2 has to show is that the driver *came back* -- and a second run that
|
||||
// redraws an identical picture is indistinguishable from a first run that
|
||||
// never stopped. One block per bit, low bit at the left.
|
||||
int mypid = getpid();
|
||||
for (int y = 0; y < height; y++)
|
||||
for (int x = 0; x < width; x++)
|
||||
fb[y * width + x] = SCH_BG;
|
||||
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
unsigned int c;
|
||||
int band = (y * 8) / height;
|
||||
switch (band) {
|
||||
case 0: c = 0x0C0E13; break; /* SCH_BG */
|
||||
case 1: c = 0x7C5CFF; break; /* SCH_ACCENT */
|
||||
case 2: c = 0x4B1D9A; break; /* PSOGM purple */
|
||||
case 3: c = (unsigned int)((x * 255 / width) * 0x010101); break;
|
||||
case 4: c = (unsigned int)(x * 255 / width) << 16; break;
|
||||
case 5: c = (unsigned int)(x * 255 / width) << 8; break;
|
||||
case 6: c = (unsigned int)(x * 255 / width); break;
|
||||
default:
|
||||
// A checkerboard, so a stride bug is visible as a shear rather
|
||||
// than as a plausible-looking gradient.
|
||||
c = (((x / 16) + (y / 16)) & 1) ? 0xE6E8EC : 0x0C0E13;
|
||||
break;
|
||||
}
|
||||
fb[y * width + x] = c;
|
||||
if (x0 < 0 || y0 < 0)
|
||||
return; // a display smaller than the mark: leave it
|
||||
|
||||
for (int dy = 0; dy < LOGO_H; dy++) {
|
||||
for (int dx = 0; dx < LOGO_W; dx++) {
|
||||
unsigned ink = LOGO_INK(dy * LOGO_W + dx);
|
||||
if (!ink)
|
||||
continue; // the mask is a square; the mark is not
|
||||
// Coverage, not a stencil: the mark has soft edges, and stamping
|
||||
// them as solid would show every one of them as a staircase.
|
||||
unsigned r = (((SCH_ACCENT >> 16) & 0xFF) * ink +
|
||||
((SCH_BG >> 16) & 0xFF) * (255 - ink)) / 255;
|
||||
unsigned g = (((SCH_ACCENT >> 8) & 0xFF) * ink +
|
||||
((SCH_BG >> 8) & 0xFF) * (255 - ink)) / 255;
|
||||
unsigned b = (((SCH_ACCENT ) & 0xFF) * ink +
|
||||
((SCH_BG ) & 0xFF) * (255 - ink)) / 255;
|
||||
fb[(y0 + dy) * width + (x0 + dx)] = (r << 16) | (g << 8) | b;
|
||||
}
|
||||
}
|
||||
|
||||
for (int b = 0; b < 12; b++) {
|
||||
unsigned int c = (mypid >> b) & 1 ? 0x4ADE80 : 0x12151C; /* SCH_OK */
|
||||
for (int y = height - 24; y < height - 8; y++)
|
||||
for (int x = 16 + b * 24; x < 16 + b * 24 + 16; x++)
|
||||
if (y >= 0 && x < width)
|
||||
fb[y * width + x] = c;
|
||||
}
|
||||
}
|
||||
|
||||
// --- the modeset --------------------------------------------------------------
|
||||
|
|
@ -776,7 +779,7 @@ serve(int fd)
|
|||
} else if (r < 0) {
|
||||
reply(fd, "the device refused the modeset\n");
|
||||
} else {
|
||||
draw_test_pattern();
|
||||
draw_mark();
|
||||
present();
|
||||
reply_dim(fd, width, height, " ok\n");
|
||||
puts("vgpud: mode is now "); putn(width); puts("x");
|
||||
|
|
@ -875,7 +878,7 @@ main(int argc, char *argv[])
|
|||
die("no modern virtio capabilities -- not a 1.0 device");
|
||||
|
||||
bring_up();
|
||||
draw_test_pattern();
|
||||
draw_mark();
|
||||
present();
|
||||
|
||||
vputs("vgpud: pid ");
|
||||
|
|
@ -912,7 +915,7 @@ main(int argc, char *argv[])
|
|||
// restarts this process, and the device has to come back with it.
|
||||
int srv = control_socket();
|
||||
if (srv < 0) {
|
||||
puts("vgpud: no control socket; the mode is fixed at "
|
||||
vputs("vgpud: no control socket; the mode is fixed at "
|
||||
"whatever the device reported\n");
|
||||
for (;;)
|
||||
sleep(100);
|
||||
|
|
|
|||
Loading…
Reference in a new issue