GMMOS: the Guru Meditation Micro OS, alive under the PSOGM
A panic no longer ends in a picture. The report is drawn as before, and
then GMMOS runs under it: the real kernel stays dead -- the other
processors are halted, and nothing of it is called that locks, sleeps,
allocates or waits for an interrupt -- and GMMOS keeps its own clock
(the TSC), its own keyboard (micro drivers, polled), and the screen.
On the report: a live status line counting down the three-minute
power-off, which any key cancels, and the keys.
Space the last 300 lines of this boot's log as QR codes, a page per
symbol, numbered; + and - trade module size for capacity
L the log on screen, scrolled
T a terminal: why, log, grep, ps, cpus, pci, mem (page tables
walked first, so a bad address cannot fault), uptime, restart,
poweroff
R R restart; P P power off -- twice, so a stray key does neither
The first micro driver is PS/2, polled: kbd.c with everything but the
keys taken out. The probe asks the keyboard to echo, so a controller
with nothing behind it is not offered as one. Polling also sidesteps the
IRQ 1 polarity quirk, which is about interrupt routing.
A panic inside GMMOS (or a second one in the report) is reported and
then only blinks; it does not re-enter GMMOS.
Checked under QEMU: every screen; two QR pages read off a screenshot
with zbar decode to the log text exactly; restart reboots; left alone it
still powers off at three minutes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S1giNvrHTrPMPw7V6x1kQ4
This commit is contained in:
parent
38c89b1a9a
commit
cb9b06d46f
9 changed files with 1317 additions and 7 deletions
|
|
@ -267,6 +267,17 @@ klog_len(void)
|
|||
}
|
||||
|
||||
uint64 klog_prev_bytes(void) { return prev_bytes; }
|
||||
|
||||
// How much of what the ring holds this boot wrote: the tail of it, since the
|
||||
// ring is read oldest first. GMMOS shows this boot's log, not the last one's.
|
||||
uint64
|
||||
klog_boot_bytes(void)
|
||||
{
|
||||
if (!klog)
|
||||
return 0;
|
||||
uint64 n = klog->head - klog->mark;
|
||||
return n < klog_len() ? n : klog_len();
|
||||
}
|
||||
int klog_recovered(void) { return recovered; }
|
||||
|
||||
// Read at a byte offset into the log, where 0 is the oldest byte still held.
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@
|
|||
#include "gfx/logo.h" /* LOGO_H -- the mark's height, for the layout below */
|
||||
#include "gfx/qr.h"
|
||||
#include "dev/acpi.h"
|
||||
#include "gmmos/gmmos.h"
|
||||
|
||||
extern uint ticks;
|
||||
extern int panicked;
|
||||
|
|
@ -389,6 +390,9 @@ trace_line(char *buf, int cap, int i, addr_t pc)
|
|||
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
// Where paint() put its closing lines, for GMMOS to write into.
|
||||
static int foot_x, foot_y, foot_step;
|
||||
|
||||
static void
|
||||
paint(char *reason, addr_t *pcs, int npcs)
|
||||
{
|
||||
|
|
@ -423,7 +427,7 @@ paint(char *reason, addr_t *pcs, int npcs)
|
|||
// the tops of "Call chain" underlining the line above. So the layout is
|
||||
// measured first -- the text, and room for two frames of the chain -- and
|
||||
// what gives way is the margin, then the logo. Never the report.
|
||||
int foot = sh - ch * 4 - ch / 2;
|
||||
int foot = sh - ch * 5 - 4 - ch / 2;
|
||||
int body = (ch + ch / 2) + ch * 2 + ch + nfields * (ch + 2) +
|
||||
ch + (ch + 2) + ch * 2;
|
||||
int logo = 1;
|
||||
|
|
@ -500,15 +504,20 @@ paint(char *reason, addr_t *pcs, int npcs)
|
|||
//
|
||||
// Kept under about 45 characters each: the QR card is on the right, and the
|
||||
// 62-character command line this replaces used to run underneath it.
|
||||
text_at(left, sh - ch * 4,
|
||||
//
|
||||
// Four lines now, the second and fourth GMMOS's: the second says whether
|
||||
// and when the machine powers off, the fourth which keys do what. Drawn
|
||||
// here as they stand before GMMOS has looked for a keyboard.
|
||||
foot_x = left;
|
||||
foot_y = sh - ch * 5 - 4;
|
||||
foot_step = ch + 4;
|
||||
text_at(left, foot_y,
|
||||
"This report is in /proc/kmsg after a restart.", PSOGM_DIM);
|
||||
// A verbose boot keeps the screen up for ever; any other powers off after
|
||||
// PANIC_OFF_MS (see panic_blink), and says so rather than surprising anyone.
|
||||
text_at(left, sh - ch * 4 + ch + 4,
|
||||
text_at(left, foot_y + foot_step,
|
||||
boot_verbose ? "schdbg, or Ctrl-G on the console, asks more."
|
||||
: "The machine powers itself off in 3 minutes.",
|
||||
PSOGM_DIM);
|
||||
text_at(left, sh - ch * 4 + (ch + 4) * 2,
|
||||
text_at(left, foot_y + foot_step * 2,
|
||||
"PSOGM -- Purple Screen of Guru Meditation", PSOGM_DIM);
|
||||
gfx_flush_all();
|
||||
}
|
||||
|
|
@ -559,6 +568,25 @@ report_serial(char *reason, addr_t *pcs, int npcs)
|
|||
|
||||
static void panic_blink(void) __attribute__((noreturn));
|
||||
|
||||
// The report as it was drawn, so GMMOS can draw it again on the way back
|
||||
// from one of its own screens.
|
||||
static char *saved_reason;
|
||||
static addr_t saved_pcs[10];
|
||||
|
||||
void
|
||||
psogm_repaint(void)
|
||||
{
|
||||
paint(saved_reason, saved_pcs, 10);
|
||||
}
|
||||
|
||||
void
|
||||
psogm_footer(int *x, int *y, int *step)
|
||||
{
|
||||
*x = foot_x;
|
||||
*y = foot_y;
|
||||
*step = foot_step;
|
||||
}
|
||||
|
||||
volatile int panic_stop;
|
||||
static volatile int panic_owner = -1;
|
||||
|
||||
|
|
@ -593,8 +621,17 @@ panic(char *s)
|
|||
pcs[i] = 0;
|
||||
getcallerpcs(&s, pcs);
|
||||
|
||||
// Counted for the owner alone. A second panic means the first report, or
|
||||
// GMMOS running after it, is what broke: report that one too, and then only
|
||||
// blink. Re-entering GMMOS would most likely crash it the same way again.
|
||||
static int depth;
|
||||
depth++;
|
||||
|
||||
gather(s, pcs, 10);
|
||||
report_serial(s, pcs, 10);
|
||||
saved_reason = s;
|
||||
for (int i = 0; i < 10; i++)
|
||||
saved_pcs[i] = pcs[i];
|
||||
|
||||
if (gfx_ready()) {
|
||||
paint(s, pcs, 10);
|
||||
|
|
@ -605,6 +642,8 @@ panic(char *s)
|
|||
}
|
||||
|
||||
panicked = 1;
|
||||
if (gfx_ready() && depth == 1)
|
||||
gmmos_run(s, pcs, 10);
|
||||
panic_blink();
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue