mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-03 17:58:30 +00:00
Show "screen of death" on VGA console upon program crash (#650)
* [metal] Refactoring: separate out sys_writev_vga() and _vga_init() modules * [metal] Read VGA info from BDA before long mode entry, not after If using a pre-existing VGA text console, the VGA initialization code now retrieves the cursor position & character height from the BIOS data area while still in real mode — rather than reading from the BIOS data area only after entering long mode. (This should help make the code more correct, if Cosmopolitan were to support UEFI graphics output in the future. If the program were booted via UEFI, then the long mode IsMetal() code would still be activated, but the BIOS data area might not have been initialized in that case.) This change also means that there are now a few more fields in the `struct mman`. * [metal] VGA console can now show "screen of death" upon a crash There is now a new function _klog_vga(), which can be called by kprintf() to output system messages — e.g. information about CPU exceptions — on the VGA screen. * [metal] CPU exception handler now dumps cr2 value * [metal] Add demo of program crash reporting w/ bare metal VGA TTY * [metal] Reduce size of "screen of death" code
This commit is contained in:
parent
7822917fc2
commit
d3efa47f81
13 changed files with 695 additions and 338 deletions
|
@ -67,10 +67,10 @@ static void SetXsFb(struct Tty *tty, unsigned short xsfb) {
|
|||
tty->xsfb = xsfb;
|
||||
}
|
||||
|
||||
static bool SetWcs(struct Tty *tty, bool alloc_wcs) {
|
||||
static bool SetWcs(struct Tty *tty, unsigned init_flags) {
|
||||
#ifdef VGA_USE_WCS
|
||||
struct DirectMap dm;
|
||||
if (!alloc_wcs)
|
||||
if (!(init_flags & kTtyAllocWcs))
|
||||
return false;
|
||||
dm = sys_mmap_metal(NULL, Yn(tty) * Xn(tty) * sizeof(wchar_t),
|
||||
PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS,
|
||||
|
@ -102,48 +102,75 @@ static wchar_t *Wcs(struct Tty *tty) {
|
|||
#endif
|
||||
}
|
||||
|
||||
static void TtyNoopUpdate(struct Tty *);
|
||||
static void TtyTextDrawChar(struct Tty *, size_t, size_t, wchar_t);
|
||||
static void TtyTextEraseLineCells(struct Tty *, size_t, size_t, size_t);
|
||||
static void TtyTextMoveLineCells(struct Tty *, size_t, size_t, size_t, size_t,
|
||||
size_t);
|
||||
|
||||
static void TtySetType(struct Tty *tty, unsigned char type) {
|
||||
static void TtySetType(struct Tty *tty, unsigned char type,
|
||||
unsigned init_flags) {
|
||||
tty->type = type;
|
||||
switch (type) {
|
||||
case PC_VIDEO_BGR565:
|
||||
tty->update = _TtyBgr565Update;
|
||||
goto graphics_mode;
|
||||
case PC_VIDEO_BGR555:
|
||||
tty->update = _TtyBgr555Update;
|
||||
goto graphics_mode;
|
||||
case PC_VIDEO_BGRX8888:
|
||||
tty->update = _TtyBgrxUpdate;
|
||||
goto graphics_mode;
|
||||
case PC_VIDEO_RGBX8888:
|
||||
tty->update = _TtyRgbxUpdate;
|
||||
graphics_mode:
|
||||
tty->drawchar = _TtyGraphDrawChar;
|
||||
tty->eraselinecells = _TtyGraphEraseLineCells;
|
||||
tty->movelinecells = _TtyGraphMoveLineCells;
|
||||
break;
|
||||
default:
|
||||
tty->drawchar = TtyTextDrawChar;
|
||||
tty->eraselinecells = TtyTextEraseLineCells;
|
||||
tty->movelinecells = TtyTextMoveLineCells;
|
||||
if ((init_flags & kTtyKlog) == 0) {
|
||||
switch (type) {
|
||||
case PC_VIDEO_BGR565:
|
||||
tty->update = _TtyBgr565Update;
|
||||
goto graphics_mode;
|
||||
case PC_VIDEO_BGR555:
|
||||
tty->update = _TtyBgr555Update;
|
||||
goto graphics_mode;
|
||||
case PC_VIDEO_BGRX8888:
|
||||
tty->update = _TtyBgrxUpdate;
|
||||
goto graphics_mode;
|
||||
case PC_VIDEO_RGBX8888:
|
||||
tty->update = _TtyRgbxUpdate;
|
||||
graphics_mode:
|
||||
tty->drawchar = _TtyGraphDrawChar;
|
||||
tty->eraselinecells = _TtyGraphEraseLineCells;
|
||||
tty->movelinecells = _TtyGraphMoveLineCells;
|
||||
break;
|
||||
default:
|
||||
tty->update = TtyNoopUpdate;
|
||||
tty->drawchar = TtyTextDrawChar;
|
||||
tty->eraselinecells = TtyTextEraseLineCells;
|
||||
tty->movelinecells = TtyTextMoveLineCells;
|
||||
}
|
||||
} else {
|
||||
switch (type) {
|
||||
case PC_VIDEO_BGR565:
|
||||
case PC_VIDEO_BGR555:
|
||||
tty->update = _TtyKlog16Update;
|
||||
tty->drawchar = _TtyKlog16DrawChar;
|
||||
tty->eraselinecells = _TtyKlog16EraseLineCells;
|
||||
tty->movelinecells = _TtyKlog16MoveLineCells;
|
||||
break;
|
||||
case PC_VIDEO_BGRX8888:
|
||||
case PC_VIDEO_RGBX8888:
|
||||
tty->update = _TtyKlog32Update;
|
||||
tty->drawchar = _TtyKlog32DrawChar;
|
||||
tty->eraselinecells = _TtyKlog32EraseLineCells;
|
||||
tty->movelinecells = _TtyKlog32MoveLineCells;
|
||||
break;
|
||||
default:
|
||||
tty->update = TtyNoopUpdate;
|
||||
tty->drawchar = TtyTextDrawChar;
|
||||
tty->eraselinecells = TtyTextEraseLineCells;
|
||||
tty->movelinecells = TtyTextMoveLineCells;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _StartTty(struct Tty *tty, unsigned char type,
|
||||
unsigned short yp, unsigned short xp, unsigned short xsfb,
|
||||
unsigned short starty, unsigned short startx,
|
||||
unsigned char yc, unsigned char xc, void *fb, bool alloc_wcs) {
|
||||
unsigned char yc, unsigned char xc, void *fb,
|
||||
unsigned init_flags) {
|
||||
unsigned short yn, xn, xs = xp * sizeof(TtyCanvasColor);
|
||||
struct DirectMap dm;
|
||||
memset(tty, 0, sizeof(struct Tty));
|
||||
SetYp(tty, yp);
|
||||
SetXp(tty, xp);
|
||||
SetXsFb(tty, xsfb);
|
||||
tty->xs = xs;
|
||||
if (type == PC_VIDEO_TEXT) {
|
||||
yn = yp;
|
||||
xn = xp;
|
||||
|
@ -151,14 +178,23 @@ void _StartTty(struct Tty *tty, unsigned char type,
|
|||
} else {
|
||||
yn = yp / yc;
|
||||
xn = xp / xc;
|
||||
dm = sys_mmap_metal(NULL, (size_t)yp * xs, PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
if (dm.addr == (void *)-1) {
|
||||
/* We are a bit low on memory. Try to go on anyway. */
|
||||
if ((init_flags & kTtyKlog) != 0) {
|
||||
tty->canvas = fb;
|
||||
starty = startx = 0;
|
||||
} else
|
||||
tty->canvas = dm.addr;
|
||||
xs = xsfb;
|
||||
} else {
|
||||
dm = sys_mmap_metal(NULL, (size_t)yp * xs, PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
if (dm.addr == (void *)-1) {
|
||||
/*
|
||||
* We are a bit low on memory. Try to go on anyway, & initialize
|
||||
* our tty as an emergency console.
|
||||
*/
|
||||
init_flags |= kTtyKlog;
|
||||
tty->canvas = fb;
|
||||
xs = xsfb;
|
||||
} else
|
||||
tty->canvas = dm.addr;
|
||||
}
|
||||
}
|
||||
SetYn(tty, yn);
|
||||
SetXn(tty, xn);
|
||||
|
@ -169,8 +205,10 @@ void _StartTty(struct Tty *tty, unsigned char type,
|
|||
if (startx >= xn) startx = xn - 1;
|
||||
tty->y = starty;
|
||||
tty->x = startx;
|
||||
TtySetType(tty, type);
|
||||
if (SetWcs(tty, alloc_wcs)) {
|
||||
if ((init_flags & kTtyKlog) != 0) init_flags &= ~kTtyAllocWcs;
|
||||
tty->xs = xs;
|
||||
TtySetType(tty, type, init_flags);
|
||||
if (SetWcs(tty, init_flags)) {
|
||||
wchar_t *wcs = Wcs(tty);
|
||||
size_t n = (size_t)yn * xn, i;
|
||||
if (type == PC_VIDEO_TEXT) {
|
||||
|
@ -335,6 +373,9 @@ static uint8_t TtyGetTextAttr(struct Tty *tty) {
|
|||
return attr;
|
||||
}
|
||||
|
||||
static void TtyNoopUpdate(struct Tty *tty) {
|
||||
}
|
||||
|
||||
static void TtyTextDrawChar(struct Tty *tty, size_t y, size_t x, wchar_t wc) {
|
||||
uint8_t attr = TtyGetTextAttr(tty);
|
||||
struct VgaTextCharCell *ccs = (struct VgaTextCharCell *)tty->canvas;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue