diff --git a/kernel/core/panic.c b/kernel/core/panic.c index b8efe60..ff23deb 100644 --- a/kernel/core/panic.c +++ b/kernel/core/panic.c @@ -297,6 +297,30 @@ build_qr_payload(char *buf, int cap, char *reason, addr_t *pcs, int npcs) // stopped. static struct qr panic_qr; +// Where the card and its caption are, once drawn: the text column must stop +// short of it on the rows they share. The reason and the call chain used to +// run straight underneath it. +static int qr_x0 = -1, qr_y0, qr_y1; + +static void +text_at(int x, int y, const char *s, uint32 color) +{ + char buf[128]; + int n = 0, cap = sizeof(buf) - 1; + + if (qr_x0 >= 0 && y + gfx_char_h() > qr_y0 && y < qr_y1) { + int fit = (qr_x0 - gfx_char_w() - x) / gfx_char_w(); + if (fit < cap) + cap = fit < 0 ? 0 : fit; + } + while (s[n] && n < cap) { + buf[n] = s[n]; + n++; + } + buf[n] = 0; + gfx_text_at(x, y, buf, color); +} + // Returns the width used, so the text column knows what it may not overlap. static int draw_qr_panel(int sw, int sh, int ch, char *reason, addr_t *pcs, int npcs) @@ -332,6 +356,9 @@ draw_qr_panel(int sw, int sh, int ch, char *reason, addr_t *pcs, int npcs) gfx_text_at(x0, y0 + card + ch, "Scan for a text copy", PSOGM_DIM); gfx_text_at(x0, y0 + card + ch * 2 + 2, "of this report.", PSOGM_DIM); + qr_x0 = x0; + qr_y0 = y0; + qr_y1 = y0 + card + ch * 3 + 2; return card + sw / 24; } @@ -388,6 +415,22 @@ paint(char *reason, addr_t *pcs, int npcs) if (left > 110) left = 110; int y = sh / 8; + // Everything above the three closing lines has to fit above them. At + // 800x600 with a 21-pixel cell it did not: the call chain ran down into the + // footer, the footer was drawn over it, and what showed was the tail of a + // trace line poking out past the end of a sentence ("asks more.0x5d") with + // 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 body = (ch + ch / 2) + ch * 2 + ch + nfields * (ch + 2) + + ch + (ch + 2) + ch * 2; + int logo = 1; + if (y + LOGO_H + ch * 2 + body > foot) + y = ch; + if (y + LOGO_H + ch * 2 + body > foot) + logo = 0; + // Shift, the system's own mark, from the same include/logo.h the loader // splash and the boot console draw. It replaces Guru, a chamfered face that // lived only here and was drawn from primitives a few lines up this file. @@ -404,15 +447,17 @@ paint(char *reason, addr_t *pcs, int npcs) // A fixed 128 px rather than scaled: the mask is 128x128 and there is no // resampler here. The face was scalable and that bought nothing -- it was // drawn at one size. - gfx_draw_logo(left, y, PSOGM_FG, PSOGM_BG); - y += LOGO_H + ch * 2; + if (logo) { + gfx_draw_logo(left, y, PSOGM_FG, PSOGM_BG); + y += LOGO_H + ch * 2; + } // Left-aligned, not centred. Centred text reads as a poster; this is a // report, and a report is read down the left edge. - gfx_text_at(left, y, "SchOS ran into a problem and needs to restart.", + text_at(left, y, "SchOS ran into a problem and needs to restart.", PSOGM_FG); y += ch + ch / 2; - gfx_text_at(left, y, "Nothing on your disks was touched by this.", + text_at(left, y, "Nothing on your disks was touched by this.", PSOGM_DIM); // A rule in the boot splash's accent, the same width as the one under the @@ -428,22 +473,20 @@ paint(char *reason, addr_t *pcs, int npcs) // Facts: quiet labels down the left, bright values in a second column. int vx = left + 14 * cw; for (int i = 0; i < nfields; i++) { - gfx_text_at(left, y, fields[i].label, PSOGM_DIM); - gfx_text_at(vx, y, fields[i].value, PSOGM_FG); + text_at(left, y, fields[i].label, PSOGM_DIM); + text_at(vx, y, fields[i].value, PSOGM_FG); y += ch + 2; } y += ch; - gfx_text_at(left, y, "Call chain", PSOGM_DIM); + text_at(left, y, "Call chain", PSOGM_DIM); y += ch + 2; - for (int i = 0; i < npcs && pcs[i]; i++) { + for (int i = 0; i < npcs && pcs[i] && y + ch <= foot; i++) { char line[48]; trace_line(line, sizeof(line), i, pcs[i]); - gfx_text_at(vx - 3 * cw, y, line, PSOGM_FG); + text_at(vx - 3 * cw, y, line, PSOGM_FG); y += ch; - if (y > sh - ch * 6) - break; } // Three closing lines, bottom left. The first used to be an addr2line @@ -456,12 +499,13 @@ 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. - gfx_text_at(left, sh - ch * 4, + text_at(left, sh - ch * 4, "This report is in /proc/kmsg after a restart.", PSOGM_DIM); - gfx_text_at(left, sh - ch * 4 + ch + 4, + text_at(left, sh - ch * 4 + ch + 4, "schdbg, or Ctrl-G on the console, asks more.", PSOGM_DIM); - gfx_text_at(left, sh - ch * 4 + (ch + 4) * 2, + text_at(left, sh - ch * 4 + (ch + 4) * 2, "PSOGM -- Purple Screen of Guru Meditation", PSOGM_DIM); + gfx_flush_all(); } // Same report, down the serial line. This is the copy that survives: it is what