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:
tkchia 2022-10-06 20:36:15 +08:00 committed by GitHub
parent 7822917fc2
commit d3efa47f81
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 695 additions and 338 deletions

33
examples/vga2.c Normal file
View file

@ -0,0 +1,33 @@
#if 0
/*─────────────────────────────────────────────────────────────────╗
To the extent possible under law, Justine Tunney has waived
all copyright and related or neighboring rights to this file,
as it is written in the following disclaimers:
http://unlicense.org/ │
http://creativecommons.org/publicdomain/zero/1.0/ │
*/
#endif
#include "libc/calls/calls.h"
#include "libc/calls/termios.h"
#include "libc/isystem/unistd.h"
#include "libc/math.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/termios.h"
/**
* @fileoverview Demo of program crash reporting with Bare Metal VGA TTY.
*
* make -j8 o//examples/vga2.com
* qemu-system-x86_64 -hda o//examples/vga2.com -serial stdio
*/
STATIC_YOINK("vga_console");
STATIC_YOINK("_idt");
int main(int argc, char *argv[]) {
volatile int x = 1;
volatile int y = 2;
printf("\e[92;44mHello World!\e[0m %d\n", 1 / (x + y - 3));
for (;;);
}

View file

@ -70,9 +70,11 @@ __excep0_isr:
push %rcx # preserve registers which we will
push %rdx # use to call kprintf
push %r8
mov 40(%rsp),%rcx # edx:rcx = "caller" cs:rip
mov 48(%rsp),%edx
mov 32(%rsp),%r8 # r8 = error code
push %r9
mov 48(%rsp),%rcx # edx:rcx = "caller" cs:rip
mov 56(%rsp),%edx
mov 40(%rsp),%r8 # r8 = error code
mov %cr2,%r9 # r9 = cr2, in case it is useful
push %rax # preserve other call-used registers
push %rdi
push %r9
@ -141,7 +143,8 @@ isr_init:
// String constants.
.rodata.str1.1
.excep_msg:
.asciz "CPU exception %d @ %#llx:%#llx err code %#llx\n"
.ascii "\033[1;31mCPU exception %d @ %#llx:%#llx err code %#llx "
.asciz "cr2 %#llx\33[0m\n"
.previous
// IDTR value.

View file

@ -55,6 +55,7 @@
#include "libc/sysv/consts/prot.h"
#include "libc/thread/tls.h"
#include "libc/thread/tls2.h"
#include "libc/vga/vga.internal.h"
extern hidden struct SymbolTable *__symtab;
@ -188,6 +189,7 @@ privileged static void klog(const char *b, size_t n) {
: /* no inputs */
: "a"(b[i]), "dN"(dx));
}
if (_weaken(_klog_vga)) _weaken(_klog_vga)(b, n);
} else {
asm volatile("syscall"
: "=a"(rax), "=D"(rdi), "=S"(rsi), "=d"(rdx)

View file

@ -169,6 +169,8 @@ noasan textreal void __setup_mman(struct mman *mm, uint64_t *pml4t) {
export_offsetof(struct mman, pc_video_height);
export_offsetof(struct mman, pc_video_framebuffer);
export_offsetof(struct mman, pc_video_framebuffer_size);
export_offsetof(struct mman, pc_video_curs_info);
export_offsetof(struct mman, pc_video_char_height);
__normalize_e820(mm);
__invert_memory(mm, pml4t);
}

View file

@ -29,6 +29,12 @@ struct mman {
uint64_t pc_video_framebuffer; /* 0x1d30 — physical address of
video frame buffer */
uint64_t pc_video_framebuffer_size; /* 0x1d38 */
struct { /* 0x1d40 — starting cursor pos. */
unsigned short y, x;
} pc_video_curs_info;
unsigned short pc_video_char_height; /* 0x1d44 — character height (useful
for setting cursor shape
in text mode) */
};
COSMOPOLITAN_C_END_

View file

@ -78,7 +78,13 @@
xor %bx,%bx
#endif
int $0x10
9:
9: mov 0x0450,%dx # note down cursor position
movzbw %dh,%ax
mov %ax,mm+"struct mman::pc_video_curs_info"
mov %dl,%al
mov %ax,mm+"struct mman::pc_video_curs_info"+2
mov 0x0486,%ax # ...& character height
mov %ax,mm+"struct mman::pc_video_char_height"
.previous
.code64
.section .rodata,"a",@progbits

View file

@ -30,258 +30,25 @@
#include "libc/vga/vga.internal.h"
/**
* @fileoverview Routines to support output in graphical video modes for
* bare metal VGA.
* @fileoverview Instantiation of routines for normal console output in
* graphical video modes.
*
* @see libc/vga/tty.c
* @see libc/vga/tty-graph.inc
*/
static void TtyDirty(struct Tty *tty, size_t gy1, size_t gx1,
size_t gy2, size_t gx2) {
if (tty->updy1 > gy1) tty->updy1 = gy1;
if (tty->updx1 > gx1) tty->updx1 = gx1;
if (tty->updy2 < gy2) tty->updy2 = gy2;
if (tty->updx2 < gx2) tty->updx2 = gx2;
}
#undef KLOGTTY
#define MAYUNROLLLOOPS unrollloops
static void TtyResetDirty(struct Tty *tty) {
tty->updy1 = tty->updx1 = tty->updy2 = tty->updx2 = 0;
}
unrollloops void _TtyBgr565Update(struct Tty *tty) {
size_t gy1 = tty->updy1, gy2 = tty->updy2,
gx1 = tty->updx1, gx2 = tty->updx2,
xsfb = tty->xsfb, xs = tty->xs;
if (gy1 < gy2 && gx1 < gx2) {
size_t yleft = gy2 - gy1, xleft;
char *cplotter = tty->fb + gy1 * xsfb + gx1 * sizeof(TtyBgr565Color);
const char *creader = tty->canvas + gy1 * xs
+ gx1 * sizeof(TtyCanvasColor);
TtyResetDirty(tty);
while (yleft-- != 0) {
TtyBgr565Color *plotter = (TtyBgr565Color *)cplotter;
const TtyCanvasColor *reader = (const TtyCanvasColor *)creader;
TtyCanvasColor c;
xleft = gx2 - gx1;
while (xleft-- != 0) {
uint16_t w;
c.w = reader->w;
++reader;
w = htole16(c.bgr.b >> 3 | c.bgr.g >> 2 << 5 | c.bgr.r >> 3 << 11);
*plotter++ = (TtyBgr565Color){w};
}
cplotter += xsfb;
creader += xs;
}
}
}
unrollloops void _TtyBgr555Update(struct Tty *tty) {
size_t gy1 = tty->updy1, gy2 = tty->updy2,
gx1 = tty->updx1, gx2 = tty->updx2,
xsfb = tty->xsfb, xs = tty->xs;
if (gy1 < gy2 && gx1 < gx2) {
size_t yleft = gy2 - gy1, xleft;
char *cplotter = tty->fb + gy1 * xsfb + gx1 * sizeof(TtyBgr555Color);
const char *creader = tty->canvas + gy1 * xs
+ gx1 * sizeof(TtyCanvasColor);
TtyResetDirty(tty);
while (yleft-- != 0) {
TtyBgr555Color *plotter = (TtyBgr555Color *)cplotter;
const TtyCanvasColor *reader = (const TtyCanvasColor *)creader;
TtyCanvasColor c;
xleft = gx2 - gx1;
while (xleft-- != 0) {
uint16_t w;
c.w = reader->w;
++reader;
w = htole16(c.bgr.b >> 3 | c.bgr.g >> 3 << 5 | c.bgr.r >> 3 << 10);
*plotter++ = (TtyBgr555Color){w};
}
cplotter += xsfb;
creader += xs;
}
}
}
unrollloops void _TtyBgrxUpdate(struct Tty *tty) {
size_t gy1 = tty->updy1, gy2 = tty->updy2,
gx1 = tty->updx1, gx2 = tty->updx2,
xsfb = tty->xsfb, xs = tty->xs;
if (gy1 < gy2 && gx1 < gx2) {
size_t yleft = gy2 - gy1, xleft;
char *cplotter = tty->fb + gy1 * xsfb + gx1 * sizeof(TtyBgrxColor);
const char *creader = tty->canvas + gy1 * xs
+ gx1 * sizeof(TtyCanvasColor);
TtyResetDirty(tty);
while (yleft-- != 0) {
TtyBgrxColor *plotter = (TtyBgrxColor *)cplotter;
const TtyCanvasColor *reader = (const TtyCanvasColor *)creader;
xleft = gx2 - gx1;
while (xleft-- != 0) {
TtyCanvasColor c = *reader++;
c.bgr.x = 0xff;
*plotter++ = c;
}
cplotter += xsfb;
creader += xs;
}
}
}
unrollloops void _TtyRgbxUpdate(struct Tty *tty) {
size_t gy1 = tty->updy1, gy2 = tty->updy2,
gx1 = tty->updx1, gx2 = tty->updx2,
xsfb = tty->xsfb, xs = tty->xs;
if (gy1 < gy2 && gx1 < gx2) {
size_t yleft = gy2 - gy1, xleft;
char *cplotter = tty->fb + gy1 * xsfb + gx1 * sizeof(TtyRgbxColor);
const char *creader = tty->canvas + gy1 * xs
+ gx1 * sizeof(TtyCanvasColor);
TtyResetDirty(tty);
while (yleft-- != 0) {
TtyRgbxColor *plotter = (TtyRgbxColor *)cplotter;
const TtyCanvasColor *reader = (const TtyCanvasColor *)creader;
TtyCanvasColor ic;
TtyRgbxColor oc;
xleft = gx2 - gx1;
while (xleft-- != 0) {
ic.w = reader->w;
++reader;
oc = (TtyRgbxColor){.rgb.r = ic.bgr.r, .rgb.g = ic.bgr.g,
.rgb.b = ic.bgr.b, .rgb.x = 0xff};
plotter->w = oc.w;
++plotter;
}
cplotter += xsfb;
creader += xs;
}
}
}
static void TtyGraphDrawBitmap(struct Tty *tty, size_t gy, size_t gx,
TtyCanvasColor fg, TtyCanvasColor bg,
const uint8_t *bitmap,
size_t bm_ht, size_t bm_wid) {
size_t xs = tty->xs;
char *cplotter = tty->canvas + gy * xs
+ gx * sizeof(TtyCanvasColor);
size_t yleft = bm_ht, xleft;
while (yleft-- != 0) {
TtyCanvasColor *plotter = (TtyCanvasColor *)cplotter;
xleft = bm_wid;
while (xleft >= 8) {
uint8_t bits = *bitmap++;
*plotter++ = __builtin_add_overflow(bits, bits, &bits) ? fg : bg;
*plotter++ = __builtin_add_overflow(bits, bits, &bits) ? fg : bg;
*plotter++ = __builtin_add_overflow(bits, bits, &bits) ? fg : bg;
*plotter++ = __builtin_add_overflow(bits, bits, &bits) ? fg : bg;
*plotter++ = __builtin_add_overflow(bits, bits, &bits) ? fg : bg;
*plotter++ = __builtin_add_overflow(bits, bits, &bits) ? fg : bg;
*plotter++ = __builtin_add_overflow(bits, bits, &bits) ? fg : bg;
*plotter++ = __builtin_add_overflow(bits, bits, &bits) ? fg : bg;
xleft -= 8;
}
if (xleft) {
uint8_t bits = *bitmap++;
switch (xleft) {
default:
*plotter++ = __builtin_add_overflow(bits, bits, &bits) ? fg : bg;
/* fall through */
case 6:
*plotter++ = __builtin_add_overflow(bits, bits, &bits) ? fg : bg;
/* fall through */
case 5:
*plotter++ = __builtin_add_overflow(bits, bits, &bits) ? fg : bg;
/* fall through */
case 4:
*plotter++ = __builtin_add_overflow(bits, bits, &bits) ? fg : bg;
/* fall through */
case 3:
*plotter++ = __builtin_add_overflow(bits, bits, &bits) ? fg : bg;
/* fall through */
case 2:
*plotter++ = __builtin_add_overflow(bits, bits, &bits) ? fg : bg;
/* fall through */
case 1:
*plotter++ = __builtin_add_overflow(bits, bits, &bits) ? fg : bg;
}
}
cplotter += xs;
}
TtyDirty(tty, gy, gx, gy + bm_ht, gx + bm_wid);
}
static unrollloops void TtyGraphFillRect(struct Tty *tty,
size_t gy, size_t gx,
size_t fill_ht, size_t fill_wid,
TtyCanvasColor bg) {
size_t xs = tty->xs;
char *cplotter = tty->canvas + gy * xs + gx * sizeof(TtyCanvasColor);
size_t yleft = fill_ht, xleft;
while (yleft-- != 0) {
TtyCanvasColor *plotter = (TtyCanvasColor *)cplotter;
size_t i;
for (i = 0; i < fill_wid; ++i)
*plotter++ = bg;
cplotter += xs;
}
TtyDirty(tty, gy, gx, gy + fill_ht, gx + fill_wid);
}
static void TtyGraphMoveRect(struct Tty *tty, size_t dgy, size_t dgx,
size_t sgy, size_t sgx, size_t ht, size_t wid) {
size_t xs = tty->xs, xm = wid * sizeof(TtyCanvasColor);
char *canvas = tty->canvas;
TtyDirty(tty, dgy, dgx, dgy + ht, dgx + wid);
if (dgy < sgy) {
while (ht-- != 0) {
memmove(canvas + dgy * xs + dgx * sizeof(TtyCanvasColor),
canvas + sgy * xs + sgx * sizeof(TtyCanvasColor), xm);
++dgy;
++sgy;
}
} else if (dgy > sgy) {
while (ht-- != 0)
memmove(canvas + (dgy + ht) * xs + dgx * sizeof(TtyCanvasColor),
canvas + (sgy + ht) * xs + sgx * sizeof(TtyCanvasColor), xm);
}
}
void _TtyGraphDrawChar(struct Tty *tty, size_t y, size_t x, wchar_t wc) {
/* TODO: allow configuring a different font later. */
const uint8_t *glyph;
const size_t glyph_ht = ARRAYLEN(_vga_font_default_direct[0]);
TtyCanvasColor fg = tty->fg, bg = tty->bg;
if ((tty->pr & kTtyFlip) != 0)
fg = bg, bg = tty->fg;
if (wc < L' ' || wc >= L' ' + ARRAYLEN(_vga_font_default_direct))
glyph = _vga_font_default_direct[0];
else
glyph = _vga_font_default_direct[wc - L' '];
if (glyph_ht >= VGA_ASSUME_CHAR_HEIGHT_PX)
TtyGraphDrawBitmap(tty, y * tty->yc, x * tty->xc, fg, bg,
glyph, VGA_ASSUME_CHAR_HEIGHT_PX, 8);
else {
/*
* Glyph is not tall enough. Draw it out, then pad the bottom of the
* character cell with the background color.
*/
TtyGraphDrawBitmap(tty, y * tty->yc, x * tty->xc, fg, bg,
glyph, glyph_ht, 8);
TtyGraphFillRect(tty, y * tty->yc + glyph_ht, x * tty->xc,
VGA_ASSUME_CHAR_HEIGHT_PX - glyph_ht, 8, bg);
}
}
void _TtyGraphEraseLineCells(struct Tty *tty, size_t y, size_t x, size_t n) {
size_t yc = tty->yc, xc = tty->xc;
TtyGraphFillRect(tty, y * yc, x * xc, yc, n * xc, tty->bg);
}
void _TtyGraphMoveLineCells(struct Tty *tty, size_t dsty, size_t dstx,
size_t srcy, size_t srcx, size_t n) {
size_t yc = tty->yc, xc = tty->xc;
TtyGraphMoveRect(tty, dsty * yc, dstx * xc, srcy * yc, srcx * xc,
yc, n * xc);
}
#define COLOR TtyCanvasColor
#define BPP 32
#define MAPCOLOR TtyGraphMapColor
#define DIRTY TtyGraphDirty
#undef UPDATE
#define RESETDIRTY TtyGraphResetDirty
#define DRAWBITMAP TtyGraphDrawBitmap
#define FILLRECT TtyGraphFillRect
#define MOVERECT TtyGraphMoveRect
#define DRAWCHAR _TtyGraphDrawChar
#define ERASELINECELLS _TtyGraphEraseLineCells
#define MOVELINECELLS _TtyGraphMoveLineCells
#include "libc/vga/tty-graph.inc"

330
libc/vga/tty-graph.inc Normal file
View file

@ -0,0 +1,330 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
╞══════════════════════════════════════════════════════════════════════════════╡
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/intrin/newbie.h"
#include "libc/macros.internal.h"
#include "libc/str/str.h"
#include "libc/vga/vga.internal.h"
/**
* @fileoverview Template for routines to support output in graphical video
* modes for bare metal VGA.
*
* If KLOGTTY is undefined, this file expands to code that writes to a
* separate off-screen canvas buffer which should be allocated beforehand
* before drawing to the actual video memory.
*
* If KLOGTTY is defined, this file instead expands to code that can
* implement an emergency console. The graphics routines will directly write
* to video memory. This may result in slower output, but will work even if
* we cannot allocate an off-screen canvas for whatever reason.
*
* @see libc/vga/tty.greg.c
* @see libc/vga/tty-graph.c
* @see libc/vga/tty-klog.greg.c
*/
#ifndef KLOGTTY
static COLOR MAPCOLOR(struct Tty *tty, TtyCanvasColor ic) {
return ic;
}
static void DIRTY(struct Tty *tty, size_t gy1, size_t gx1,
size_t gy2, size_t gx2) {
if (tty->updy1 > gy1) tty->updy1 = gy1;
if (tty->updx1 > gx1) tty->updx1 = gx1;
if (tty->updy2 < gy2) tty->updy2 = gy2;
if (tty->updx2 < gx2) tty->updx2 = gx2;
}
static void RESETDIRTY(struct Tty *tty) {
tty->updy1 = tty->updx1 = tty->updy2 = tty->updx2 = 0;
}
unrollloops void _TtyBgr565Update(struct Tty *tty) {
size_t gy1 = tty->updy1, gy2 = tty->updy2,
gx1 = tty->updx1, gx2 = tty->updx2,
xsfb = tty->xsfb, xs = tty->xs;
if (gy1 < gy2 && gx1 < gx2) {
size_t yleft = gy2 - gy1, xleft;
char *cplotter = tty->fb + gy1 * xsfb + gx1 * sizeof(TtyBgr565Color);
const char *creader = tty->canvas + gy1 * xs
+ gx1 * sizeof(TtyCanvasColor);
RESETDIRTY(tty);
while (yleft-- != 0) {
TtyBgr565Color *plotter = (TtyBgr565Color *)cplotter;
const TtyCanvasColor *reader = (const TtyCanvasColor *)creader;
TtyCanvasColor c;
xleft = gx2 - gx1;
while (xleft-- != 0) {
uint16_t w;
c.w = reader->w;
++reader;
w = htole16(c.bgr.b >> 3 | c.bgr.g >> 2 << 5 | c.bgr.r >> 3 << 11);
*plotter++ = (TtyBgr565Color){w};
}
cplotter += xsfb;
creader += xs;
}
}
}
unrollloops void _TtyBgr555Update(struct Tty *tty) {
size_t gy1 = tty->updy1, gy2 = tty->updy2,
gx1 = tty->updx1, gx2 = tty->updx2,
xsfb = tty->xsfb, xs = tty->xs;
if (gy1 < gy2 && gx1 < gx2) {
size_t yleft = gy2 - gy1, xleft;
char *cplotter = tty->fb + gy1 * xsfb + gx1 * sizeof(TtyBgr555Color);
const char *creader = tty->canvas + gy1 * xs
+ gx1 * sizeof(TtyCanvasColor);
RESETDIRTY(tty);
while (yleft-- != 0) {
TtyBgr555Color *plotter = (TtyBgr555Color *)cplotter;
const TtyCanvasColor *reader = (const TtyCanvasColor *)creader;
TtyCanvasColor c;
xleft = gx2 - gx1;
while (xleft-- != 0) {
uint16_t w;
c.w = reader->w;
++reader;
w = htole16(c.bgr.b >> 3 | c.bgr.g >> 3 << 5 | c.bgr.r >> 3 << 10);
*plotter++ = (TtyBgr555Color){w};
}
cplotter += xsfb;
creader += xs;
}
}
}
unrollloops void _TtyBgrxUpdate(struct Tty *tty) {
size_t gy1 = tty->updy1, gy2 = tty->updy2,
gx1 = tty->updx1, gx2 = tty->updx2,
xsfb = tty->xsfb, xs = tty->xs;
if (gy1 < gy2 && gx1 < gx2) {
size_t yleft = gy2 - gy1, xleft;
char *cplotter = tty->fb + gy1 * xsfb + gx1 * sizeof(TtyBgrxColor);
const char *creader = tty->canvas + gy1 * xs
+ gx1 * sizeof(TtyCanvasColor);
RESETDIRTY(tty);
while (yleft-- != 0) {
TtyBgrxColor *plotter = (TtyBgrxColor *)cplotter;
const TtyCanvasColor *reader = (const TtyCanvasColor *)creader;
xleft = gx2 - gx1;
while (xleft-- != 0) {
TtyCanvasColor c = *reader++;
c.bgr.x = 0xff;
*plotter++ = c;
}
cplotter += xsfb;
creader += xs;
}
}
}
unrollloops void _TtyRgbxUpdate(struct Tty *tty) {
size_t gy1 = tty->updy1, gy2 = tty->updy2,
gx1 = tty->updx1, gx2 = tty->updx2,
xsfb = tty->xsfb, xs = tty->xs;
if (gy1 < gy2 && gx1 < gx2) {
size_t yleft = gy2 - gy1, xleft;
char *cplotter = tty->fb + gy1 * xsfb + gx1 * sizeof(TtyRgbxColor);
const char *creader = tty->canvas + gy1 * xs
+ gx1 * sizeof(TtyCanvasColor);
RESETDIRTY(tty);
while (yleft-- != 0) {
TtyRgbxColor *plotter = (TtyRgbxColor *)cplotter;
const TtyCanvasColor *reader = (const TtyCanvasColor *)creader;
TtyCanvasColor ic;
TtyRgbxColor oc;
xleft = gx2 - gx1;
while (xleft-- != 0) {
ic.w = reader->w;
++reader;
oc = (TtyRgbxColor){.rgb.r = ic.bgr.r, .rgb.g = ic.bgr.g,
.rgb.b = ic.bgr.b, .rgb.x = 0xff};
plotter->w = oc.w;
++plotter;
}
cplotter += xsfb;
creader += xs;
}
}
}
#else /* KLOGTTY */
static COLOR MAPCOLOR(struct Tty *tty, TtyCanvasColor ic) {
#if BPP == 16
if (tty->type == PC_VIDEO_BGR565)
return htole16(ic.bgr.b >> 3 | ic.bgr.g >> 2 << 5 | ic.bgr.r >> 3 << 11);
else
return htole16(ic.bgr.b >> 3 | ic.bgr.g >> 3 << 5 | ic.bgr.r >> 3 << 10);
#else
if (tty->type == PC_VIDEO_BGRX8888)
return ic.w;
else {
TtyRgbxColor oc = (TtyRgbxColor){.rgb.r = ic.bgr.r, .rgb.g = ic.bgr.g,
.rgb.b = ic.bgr.b, .rgb.x = 0xff};
return oc.w;
}
#endif
}
static void DIRTY(struct Tty *tty, size_t gy1, size_t gx1,
size_t gy2, size_t gx2) {
}
static void RESETDIRTY(struct Tty *tty) {
}
void UPDATE(struct Tty *tty) {
}
#endif /* KLOGTTY */
static void DRAWBITMAP(struct Tty *tty, size_t gy, size_t gx,
COLOR fg, COLOR bg, const uint8_t *bitmap,
size_t bm_ht, size_t bm_wid) {
size_t xs = tty->xs;
char *cplotter = tty->canvas + gy * xs + gx * sizeof(COLOR);
size_t yleft = bm_ht, xleft;
while (yleft-- != 0) {
COLOR *plotter = (COLOR *)cplotter;
xleft = bm_wid;
while (xleft >= 8) {
uint8_t bits = *bitmap++;
*plotter++ = __builtin_add_overflow(bits, bits, &bits) ? fg : bg;
*plotter++ = __builtin_add_overflow(bits, bits, &bits) ? fg : bg;
*plotter++ = __builtin_add_overflow(bits, bits, &bits) ? fg : bg;
*plotter++ = __builtin_add_overflow(bits, bits, &bits) ? fg : bg;
*plotter++ = __builtin_add_overflow(bits, bits, &bits) ? fg : bg;
*plotter++ = __builtin_add_overflow(bits, bits, &bits) ? fg : bg;
*plotter++ = __builtin_add_overflow(bits, bits, &bits) ? fg : bg;
*plotter++ = __builtin_add_overflow(bits, bits, &bits) ? fg : bg;
xleft -= 8;
}
if (xleft) {
uint8_t bits = *bitmap++;
switch (xleft) {
default:
*plotter++ = __builtin_add_overflow(bits, bits, &bits) ? fg : bg;
/* fall through */
case 6:
*plotter++ = __builtin_add_overflow(bits, bits, &bits) ? fg : bg;
/* fall through */
case 5:
*plotter++ = __builtin_add_overflow(bits, bits, &bits) ? fg : bg;
/* fall through */
case 4:
*plotter++ = __builtin_add_overflow(bits, bits, &bits) ? fg : bg;
/* fall through */
case 3:
*plotter++ = __builtin_add_overflow(bits, bits, &bits) ? fg : bg;
/* fall through */
case 2:
*plotter++ = __builtin_add_overflow(bits, bits, &bits) ? fg : bg;
/* fall through */
case 1:
*plotter++ = __builtin_add_overflow(bits, bits, &bits) ? fg : bg;
}
}
cplotter += xs;
}
DIRTY(tty, gy, gx, gy + bm_ht, gx + bm_wid);
}
static MAYUNROLLLOOPS void FILLRECT(struct Tty *tty, size_t gy, size_t gx,
size_t fill_ht, size_t fill_wid,
COLOR bg) {
size_t xs = tty->xs;
char *cplotter = tty->canvas + gy * xs + gx * sizeof(COLOR);
size_t yleft = fill_ht, xleft;
while (yleft-- != 0) {
COLOR *plotter = (COLOR *)cplotter;
size_t i;
for (i = 0; i < fill_wid; ++i)
*plotter++ = bg;
cplotter += xs;
}
DIRTY(tty, gy, gx, gy + fill_ht, gx + fill_wid);
}
static void MOVERECT(struct Tty *tty, size_t dgy, size_t dgx,
size_t sgy, size_t sgx, size_t ht, size_t wid) {
size_t xs = tty->xs, xm = wid * sizeof(COLOR);
char *canvas = tty->canvas;
DIRTY(tty, dgy, dgx, dgy + ht, dgx + wid);
if (dgy < sgy) {
while (ht-- != 0) {
memmove(canvas + dgy * xs + dgx * sizeof(COLOR),
canvas + sgy * xs + sgx * sizeof(COLOR), xm);
++dgy;
++sgy;
}
} else if (dgy > sgy) {
while (ht-- != 0)
memmove(canvas + (dgy + ht) * xs + dgx * sizeof(COLOR),
canvas + (sgy + ht) * xs + sgx * sizeof(COLOR), xm);
}
}
void DRAWCHAR(struct Tty *tty, size_t y, size_t x, wchar_t wc) {
/* TODO: allow configuring a different font later. */
const uint8_t *glyph;
const size_t glyph_ht = ARRAYLEN(_vga_font_default_direct[0]);
COLOR fg = MAPCOLOR(tty, tty->fg), bg = MAPCOLOR(tty, tty->bg);
if ((tty->pr & kTtyFlip) != 0)
fg = bg, bg = MAPCOLOR(tty, tty->fg);
if (wc < L' ' || wc >= L' ' + ARRAYLEN(_vga_font_default_direct))
glyph = _vga_font_default_direct[0];
else
glyph = _vga_font_default_direct[wc - L' '];
if (glyph_ht >= VGA_ASSUME_CHAR_HEIGHT_PX)
DRAWBITMAP(tty, y * tty->yc, x * tty->xc, fg, bg, glyph,
VGA_ASSUME_CHAR_HEIGHT_PX, 8);
else {
/*
* Glyph is not tall enough. Draw it out, then pad the bottom of the
* character cell with the background color.
*/
DRAWBITMAP(tty, y * tty->yc, x * tty->xc, fg, bg, glyph, glyph_ht, 8);
FILLRECT(tty, y * tty->yc + glyph_ht, x * tty->xc,
VGA_ASSUME_CHAR_HEIGHT_PX - glyph_ht, 8, bg);
}
}
void ERASELINECELLS(struct Tty *tty, size_t y, size_t x, size_t n) {
size_t yc = tty->yc, xc = tty->xc;
FILLRECT(tty, y * yc, x * xc, yc, n * xc, MAPCOLOR(tty, tty->bg));
}
void MOVELINECELLS(struct Tty *tty, size_t dsty, size_t dstx,
size_t srcy, size_t srcx, size_t n) {
size_t yc = tty->yc, xc = tty->xc;
MOVERECT(tty, dsty * yc, dstx * xc, srcy * yc, srcx * xc, yc, n * xc);
}

97
libc/vga/tty-klog.greg.c Normal file
View file

@ -0,0 +1,97 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
*/
#include "libc/intrin/newbie.h"
#include "libc/macros.internal.h"
#include "libc/runtime/mman.internal.h"
#include "libc/str/str.h"
#include "libc/vga/vga.internal.h"
/*
* @fileoverview Instantiation of routines for emergency or system console
* output in graphical video modes.
*
* @see libc/vga/tty-graph.inc
*/
#pragma GCC optimize("s")
#define KLOGTTY
#define MAYUNROLLLOOPS /* do not unroll loops; keep the code small! */
/* Instantiate output routines for 16-bit pixel formats. */
#define COLOR uint16_t
#define BPP 16
#define MAPCOLOR TtyKlog16MapColor
#define DIRTY TtyKlog16Dirty
#define UPDATE _TtyKlog16Update
#define RESETDIRTY TtyKlog16ResetDirty
#define DRAWBITMAP TtyKlog16DrawBitmap
#define FILLRECT TtyKlog16FillRect
#define MOVERECT TtyKlog16MoveRect
#define DRAWCHAR _TtyKlog16DrawChar
#define ERASELINECELLS _TtyKlog16EraseLineCells
#define MOVELINECELLS _TtyKlog16MoveLineCells
#include "libc/vga/tty-graph.inc"
#undef COLOR
#undef BPP
#undef MAPCOLOR
#undef BG
#undef DIRTY
#undef UPDATE
#undef RESETDIRTY
#undef DRAWBITMAP
#undef FILLRECT
#undef MOVERECT
#undef DRAWCHAR
#undef ERASELINECELLS
#undef MOVELINECELLS
/* Instantiate output routines for 32-bit pixel formats. */
#define COLOR uint32_t
#define BPP 32
#define MAPCOLOR TtyKlog32MapColor
#define DIRTY TtyKlog32Dirty
#define UPDATE _TtyKlog32Update
#define RESETDIRTY TtyKlog32ResetDirty
#define DRAWBITMAP TtyKlog32DrawBitmap
#define FILLRECT TtyKlog32FillRect
#define MOVERECT TtyKlog32MoveRect
#define DRAWCHAR _TtyKlog32DrawChar
#define ERASELINECELLS _TtyKlog32EraseLineCells
#define MOVELINECELLS _TtyKlog32MoveLineCells
#include "libc/vga/tty-graph.inc"
static unsigned short klog_y = 0, klog_x = 0;
privileged void _klog_vga(const char *b, size_t n) {
struct Tty tty;
_vga_reinit(&tty, klog_y, klog_x, kTtyKlog);
_TtyWrite(&tty, b, n);
klog_y = _TtyGetY(&tty);
klog_x = _TtyGetX(&tty);
}

View file

@ -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;

70
libc/vga/vga-init.greg.c Normal file
View file

@ -0,0 +1,70 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
*/
#include "libc/dce.h"
#include "libc/vga/vga.internal.h"
#include "libc/runtime/pc.internal.h"
#include "libc/str/str.h"
struct Tty _vga_tty;
void _vga_reinit(struct Tty *tty, unsigned short starty, unsigned short startx,
unsigned init_flags) {
struct mman *mm = (struct mman *)(BANE + 0x0500);
unsigned char vid_type = mm->pc_video_type;
unsigned short height = mm->pc_video_height, width = mm->pc_video_width,
stride = mm->pc_video_stride;
uint64_t vid_buf_phy = mm->pc_video_framebuffer;
void *vid_buf = (void *)(BANE + vid_buf_phy);
size_t vid_buf_sz = mm->pc_video_framebuffer_size;
uint8_t chr_ht, chr_wid;
if (vid_type == PC_VIDEO_TEXT) {
unsigned short chr_ht_val = mm->pc_video_char_height;
if (chr_ht_val > 32 || chr_ht_val < 2)
chr_ht = VGA_ASSUME_CHAR_HEIGHT_PX;
else
chr_ht = chr_ht_val;
} else
chr_ht = VGA_ASSUME_CHAR_HEIGHT_PX;
chr_wid = VGA_ASSUME_CHAR_WIDTH_PX;
/* Make sure the video buffer is mapped into virtual memory. */
__invert_memory_area(mm, __get_pml4t(), vid_buf_phy, vid_buf_sz, PAGE_RW);
/*
* Initialize our tty structure from the current screen geometry, screen
* contents, cursor position, & character dimensions.
*/
_StartTty(tty, vid_type, height, width, stride, starty, startx,
chr_ht, chr_wid, vid_buf, init_flags);
}
__attribute__((__constructor__)) static textstartup void _vga_init(void) {
if (IsMetal()) {
struct mman *mm = (struct mman *)(BANE + 0x0500);
unsigned short starty = mm->pc_video_curs_info.y,
startx = mm->pc_video_curs_info.x;
_vga_reinit(&_vga_tty, starty, startx, 0);
}
}

View file

@ -75,6 +75,16 @@
*/
#undef VGA_PERSNICKETY_STATUS
/* Flags which are passed to _StartTty(). */
#define kTtyAllocWcs 0x01 /* allocate Unicode character array
(if VGA_USE_WCS also defined) */
#define kTtyKlog 0x02 /* the system might be in an abnormal
state, & we are setting up the tty
to show system messages */
/**
* Flags for Tty::pr. These govern properties of individual character cells.
*/
#define kTtyFg 0x0001
#define kTtyBg 0x0002
#define kTtyBold 0x0004
@ -89,6 +99,10 @@
#define kTtyStrike 0x0800
#define kTtyConceal 0x1000
/**
* Flags for Tty::conf. These govern the current state of the teletypewriter
* as a whole.
*/
#define kTtyBell 0x001
#define kTtyRedzone 0x002
#define kTtyNocursor 0x004
@ -181,14 +195,15 @@ struct Tty {
* Canvas to draw into. In text modes, this is simply the frame buffer
* itself. In graphics modes, this should be separate from the frame
* buffer, & possibly allocated from main memory; we must arrange to
* update the frame buffer from the canvas every now & then. In general
* the canvas's pixel format given by _TtyCanvasType() may be
* different from the frame buffer's.
* update the frame buffer from the canvas every now & then.
*
* During normal operation, the canvas's pixel format is given by
* _TtyCanvasType(), & may be different from the frame buffer's.
*/
char *canvas;
/**
* Which portions of the canvas have been updated & should later be drawn
* to screen with tty->update().
* to screen with Tty::update().
*/
unsigned short updy1, updx1, updy2, updx2;
#ifdef VGA_USE_WCS
@ -219,6 +234,15 @@ forceinline unsigned char _TtyCanvasType(struct Tty *tty) {
return tty->type == PC_VIDEO_TEXT ? PC_VIDEO_TEXT : PC_VIDEO_BGRX8888;
}
forceinline unsigned short _TtyGetY(struct Tty *tty) {
return tty->y;
}
forceinline unsigned short _TtyGetX(struct Tty *tty) {
return tty->x;
}
/* Routines that implement normal graphical console output. */
void _TtyBgrxUpdate(struct Tty *);
void _TtyRgbxUpdate(struct Tty *);
void _TtyBgr565Update(struct Tty *);
@ -228,9 +252,25 @@ void _TtyGraphEraseLineCells(struct Tty *, size_t, size_t, size_t);
void _TtyGraphMoveLineCells(struct Tty *, size_t, size_t, size_t, size_t,
size_t);
/*
* Routines that implement emergency or system console output in graphical
* video modes.
*/
void _TtyKlog16Update(struct Tty *);
void _TtyKlog16DrawChar(struct Tty *, size_t, size_t, wchar_t);
void _TtyKlog16EraseLineCells(struct Tty *, size_t, size_t, size_t);
void _TtyKlog16MoveLineCells(struct Tty *, size_t, size_t, size_t, size_t,
size_t);
void _TtyKlog32Update(struct Tty *);
void _TtyKlog32DrawChar(struct Tty *, size_t, size_t, wchar_t);
void _TtyKlog32EraseLineCells(struct Tty *, size_t, size_t, size_t);
void _TtyKlog32MoveLineCells(struct Tty *, size_t, size_t, size_t, size_t,
size_t);
/* High-level teletypewriter routines. */
void _StartTty(struct Tty *, unsigned char, unsigned short, unsigned short,
unsigned short, unsigned short, unsigned short,
unsigned char, unsigned char, void *, bool);
unsigned char, unsigned char, void *, unsigned);
ssize_t _TtyRead(struct Tty *, void *, size_t);
ssize_t _TtyWrite(struct Tty *, const void *, size_t);
ssize_t _TtyWriteInput(struct Tty *, const void *, size_t);
@ -246,6 +286,8 @@ void _TtySetX(struct Tty *, unsigned short);
extern const uint8_t _vga_font_default_direct[95][13];
extern struct Tty _vga_tty;
void _vga_reinit(struct Tty *, unsigned short, unsigned short, unsigned);
void _klog_vga(const char *, size_t);
ssize_t sys_readv_vga(struct Fd *, const struct iovec *, int);
ssize_t sys_writev_vga(struct Fd *, const struct iovec *, int);

View file

@ -29,10 +29,6 @@
#include "libc/calls/struct/iovec.internal.h"
#include "libc/dce.h"
#include "libc/vga/vga.internal.h"
#include "libc/runtime/pc.internal.h"
#include "libc/str/str.h"
struct Tty _vga_tty;
ssize_t sys_writev_vga(struct Fd *fd, const struct iovec *iov, int iovlen) {
size_t i, wrote = 0;
@ -51,41 +47,3 @@ ssize_t sys_writev_vga(struct Fd *fd, const struct iovec *iov, int iovlen) {
return res;
return wrote;
}
__attribute__((__constructor__)) static textstartup void _vga_init(void) {
if (IsMetal()) {
struct mman *mm = (struct mman *)(BANE + 0x0500);
unsigned char vid_type = mm->pc_video_type;
unsigned short height = mm->pc_video_height, width = mm->pc_video_width,
stride = mm->pc_video_stride;
uint64_t vid_buf_phy = mm->pc_video_framebuffer;
void *vid_buf = (void *)(BANE + vid_buf_phy);
size_t vid_buf_sz = mm->pc_video_framebuffer_size;
/*
* Get the initial cursor position from the BIOS data area. Also get
* the height (in scan lines) of each character; this is used to set the
* cursor shape.
*/
typedef struct {
unsigned char col, row;
} bios_curs_pos_t;
bios_curs_pos_t pos = *(bios_curs_pos_t *)(BANE + 0x0450ull);
uint8_t chr_ht, chr_ht_hi, chr_wid;
if (vid_type == PC_VIDEO_TEXT) {
chr_ht = *(uint8_t *)(BANE + 0x0485ull),
chr_ht_hi = *(uint8_t *)(BANE + 0x0486ull);
if (chr_ht_hi != 0 || chr_ht > 32 || chr_ht < 2)
chr_ht = VGA_ASSUME_CHAR_HEIGHT_PX;
} else
chr_ht = VGA_ASSUME_CHAR_HEIGHT_PX;
chr_wid = VGA_ASSUME_CHAR_WIDTH_PX;
/* Make sure the video buffer is mapped into virtual memory. */
__invert_memory_area(mm, __get_pml4t(), vid_buf_phy, vid_buf_sz, PAGE_RW);
/*
* Initialize our tty structure from the current screen geometry,
* screen contents, cursor position, & character dimensions.
*/
_StartTty(&_vga_tty, vid_type, height, width, stride, pos.row, pos.col,
chr_ht, chr_wid, vid_buf, false);
}
}