mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-08-09 03:10:27 +00:00
[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.
This commit is contained in:
parent
7059a7109d
commit
5aaadf1162
7 changed files with 595 additions and 315 deletions
|
@ -55,6 +55,7 @@
|
||||||
#include "libc/sysv/consts/prot.h"
|
#include "libc/sysv/consts/prot.h"
|
||||||
#include "libc/thread/tls.h"
|
#include "libc/thread/tls.h"
|
||||||
#include "libc/thread/tls2.h"
|
#include "libc/thread/tls2.h"
|
||||||
|
#include "libc/vga/vga.internal.h"
|
||||||
|
|
||||||
extern hidden struct SymbolTable *__symtab;
|
extern hidden struct SymbolTable *__symtab;
|
||||||
|
|
||||||
|
@ -188,6 +189,7 @@ privileged static void klog(const char *b, size_t n) {
|
||||||
: /* no inputs */
|
: /* no inputs */
|
||||||
: "a"(b[i]), "dN"(dx));
|
: "a"(b[i]), "dN"(dx));
|
||||||
}
|
}
|
||||||
|
if (_weaken(_klog_vga)) _weaken(_klog_vga)(b, n);
|
||||||
} else {
|
} else {
|
||||||
asm volatile("syscall"
|
asm volatile("syscall"
|
||||||
: "=a"(rax), "=D"(rdi), "=S"(rsi), "=d"(rdx)
|
: "=a"(rax), "=D"(rdi), "=S"(rsi), "=d"(rdx)
|
||||||
|
|
|
@ -30,258 +30,24 @@
|
||||||
#include "libc/vga/vga.internal.h"
|
#include "libc/vga/vga.internal.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @fileoverview Routines to support output in graphical video modes for
|
* @fileoverview Instantiation of routines for normal console output in
|
||||||
* bare metal VGA.
|
* 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,
|
#undef KLOGTTY
|
||||||
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 TtyResetDirty(struct Tty *tty) {
|
#define COLOR TtyCanvasColor
|
||||||
tty->updy1 = tty->updx1 = tty->updy2 = tty->updx2 = 0;
|
#define BPP 32
|
||||||
}
|
#define MAPCOLOR TtyGraphMapColor
|
||||||
|
#define DIRTY TtyGraphDirty
|
||||||
unrollloops void _TtyBgr565Update(struct Tty *tty) {
|
#undef UPDATE
|
||||||
size_t gy1 = tty->updy1, gy2 = tty->updy2,
|
#define RESETDIRTY TtyGraphResetDirty
|
||||||
gx1 = tty->updx1, gx2 = tty->updx2,
|
#define DRAWBITMAP TtyGraphDrawBitmap
|
||||||
xsfb = tty->xsfb, xs = tty->xs;
|
#define FILLRECT TtyGraphFillRect
|
||||||
if (gy1 < gy2 && gx1 < gx2) {
|
#define MOVERECT TtyGraphMoveRect
|
||||||
size_t yleft = gy2 - gy1, xleft;
|
#define DRAWCHAR _TtyGraphDrawChar
|
||||||
char *cplotter = tty->fb + gy1 * xsfb + gx1 * sizeof(TtyBgr565Color);
|
#define ERASELINECELLS _TtyGraphEraseLineCells
|
||||||
const char *creader = tty->canvas + gy1 * xs
|
#define MOVELINECELLS _TtyGraphMoveLineCells
|
||||||
+ gx1 * sizeof(TtyCanvasColor);
|
#include "libc/vga/tty-graph.inc"
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
329
libc/vga/tty-graph.inc
Normal file
329
libc/vga/tty-graph.inc
Normal file
|
@ -0,0 +1,329 @@
|
||||||
|
/*-*- 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 unrollloops 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);
|
||||||
|
}
|
94
libc/vga/tty-klog.greg.c
Normal file
94
libc/vga/tty-klog.greg.c
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
/*-*- 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define KLOGTTY
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
}
|
|
@ -67,10 +67,10 @@ static void SetXsFb(struct Tty *tty, unsigned short xsfb) {
|
||||||
tty->xsfb = 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
|
#ifdef VGA_USE_WCS
|
||||||
struct DirectMap dm;
|
struct DirectMap dm;
|
||||||
if (!alloc_wcs)
|
if (!(init_flags & kTtyAllocWcs))
|
||||||
return false;
|
return false;
|
||||||
dm = sys_mmap_metal(NULL, Yn(tty) * Xn(tty) * sizeof(wchar_t),
|
dm = sys_mmap_metal(NULL, Yn(tty) * Xn(tty) * sizeof(wchar_t),
|
||||||
PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS,
|
PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS,
|
||||||
|
@ -102,48 +102,75 @@ static wchar_t *Wcs(struct Tty *tty) {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void TtyNoopUpdate(struct Tty *);
|
||||||
static void TtyTextDrawChar(struct Tty *, size_t, size_t, wchar_t);
|
static void TtyTextDrawChar(struct Tty *, size_t, size_t, wchar_t);
|
||||||
static void TtyTextEraseLineCells(struct Tty *, size_t, size_t, size_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,
|
static void TtyTextMoveLineCells(struct Tty *, size_t, 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;
|
tty->type = type;
|
||||||
switch (type) {
|
if ((init_flags & kTtyKlog) == 0) {
|
||||||
case PC_VIDEO_BGR565:
|
switch (type) {
|
||||||
tty->update = _TtyBgr565Update;
|
case PC_VIDEO_BGR565:
|
||||||
goto graphics_mode;
|
tty->update = _TtyBgr565Update;
|
||||||
case PC_VIDEO_BGR555:
|
goto graphics_mode;
|
||||||
tty->update = _TtyBgr555Update;
|
case PC_VIDEO_BGR555:
|
||||||
goto graphics_mode;
|
tty->update = _TtyBgr555Update;
|
||||||
case PC_VIDEO_BGRX8888:
|
goto graphics_mode;
|
||||||
tty->update = _TtyBgrxUpdate;
|
case PC_VIDEO_BGRX8888:
|
||||||
goto graphics_mode;
|
tty->update = _TtyBgrxUpdate;
|
||||||
case PC_VIDEO_RGBX8888:
|
goto graphics_mode;
|
||||||
tty->update = _TtyRgbxUpdate;
|
case PC_VIDEO_RGBX8888:
|
||||||
graphics_mode:
|
tty->update = _TtyRgbxUpdate;
|
||||||
tty->drawchar = _TtyGraphDrawChar;
|
graphics_mode:
|
||||||
tty->eraselinecells = _TtyGraphEraseLineCells;
|
tty->drawchar = _TtyGraphDrawChar;
|
||||||
tty->movelinecells = _TtyGraphMoveLineCells;
|
tty->eraselinecells = _TtyGraphEraseLineCells;
|
||||||
break;
|
tty->movelinecells = _TtyGraphMoveLineCells;
|
||||||
default:
|
break;
|
||||||
tty->drawchar = TtyTextDrawChar;
|
default:
|
||||||
tty->eraselinecells = TtyTextEraseLineCells;
|
tty->update = TtyNoopUpdate;
|
||||||
tty->movelinecells = TtyTextMoveLineCells;
|
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,
|
void _StartTty(struct Tty *tty, unsigned char type,
|
||||||
unsigned short yp, unsigned short xp, unsigned short xsfb,
|
unsigned short yp, unsigned short xp, unsigned short xsfb,
|
||||||
unsigned short starty, unsigned short startx,
|
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);
|
unsigned short yn, xn, xs = xp * sizeof(TtyCanvasColor);
|
||||||
struct DirectMap dm;
|
struct DirectMap dm;
|
||||||
memset(tty, 0, sizeof(struct Tty));
|
memset(tty, 0, sizeof(struct Tty));
|
||||||
SetYp(tty, yp);
|
SetYp(tty, yp);
|
||||||
SetXp(tty, xp);
|
SetXp(tty, xp);
|
||||||
SetXsFb(tty, xsfb);
|
SetXsFb(tty, xsfb);
|
||||||
tty->xs = xs;
|
|
||||||
if (type == PC_VIDEO_TEXT) {
|
if (type == PC_VIDEO_TEXT) {
|
||||||
yn = yp;
|
yn = yp;
|
||||||
xn = xp;
|
xn = xp;
|
||||||
|
@ -151,14 +178,23 @@ void _StartTty(struct Tty *tty, unsigned char type,
|
||||||
} else {
|
} else {
|
||||||
yn = yp / yc;
|
yn = yp / yc;
|
||||||
xn = xp / xc;
|
xn = xp / xc;
|
||||||
dm = sys_mmap_metal(NULL, (size_t)yp * xs, PROT_READ | PROT_WRITE,
|
if ((init_flags & kTtyKlog) != 0) {
|
||||||
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
|
||||||
if (dm.addr == (void *)-1) {
|
|
||||||
/* We are a bit low on memory. Try to go on anyway. */
|
|
||||||
tty->canvas = fb;
|
tty->canvas = fb;
|
||||||
starty = startx = 0;
|
xs = xsfb;
|
||||||
} else
|
} else {
|
||||||
tty->canvas = dm.addr;
|
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);
|
SetYn(tty, yn);
|
||||||
SetXn(tty, xn);
|
SetXn(tty, xn);
|
||||||
|
@ -169,8 +205,10 @@ void _StartTty(struct Tty *tty, unsigned char type,
|
||||||
if (startx >= xn) startx = xn - 1;
|
if (startx >= xn) startx = xn - 1;
|
||||||
tty->y = starty;
|
tty->y = starty;
|
||||||
tty->x = startx;
|
tty->x = startx;
|
||||||
TtySetType(tty, type);
|
if ((init_flags & kTtyKlog) != 0) init_flags &= ~kTtyAllocWcs;
|
||||||
if (SetWcs(tty, alloc_wcs)) {
|
tty->xs = xs;
|
||||||
|
TtySetType(tty, type, init_flags);
|
||||||
|
if (SetWcs(tty, init_flags)) {
|
||||||
wchar_t *wcs = Wcs(tty);
|
wchar_t *wcs = Wcs(tty);
|
||||||
size_t n = (size_t)yn * xn, i;
|
size_t n = (size_t)yn * xn, i;
|
||||||
if (type == PC_VIDEO_TEXT) {
|
if (type == PC_VIDEO_TEXT) {
|
||||||
|
@ -335,6 +373,9 @@ static uint8_t TtyGetTextAttr(struct Tty *tty) {
|
||||||
return attr;
|
return attr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void TtyNoopUpdate(struct Tty *tty) {
|
||||||
|
}
|
||||||
|
|
||||||
static void TtyTextDrawChar(struct Tty *tty, size_t y, size_t x, wchar_t wc) {
|
static void TtyTextDrawChar(struct Tty *tty, size_t y, size_t x, wchar_t wc) {
|
||||||
uint8_t attr = TtyGetTextAttr(tty);
|
uint8_t attr = TtyGetTextAttr(tty);
|
||||||
struct VgaTextCharCell *ccs = (struct VgaTextCharCell *)tty->canvas;
|
struct VgaTextCharCell *ccs = (struct VgaTextCharCell *)tty->canvas;
|
||||||
|
|
|
@ -31,34 +31,40 @@
|
||||||
|
|
||||||
struct Tty _vga_tty;
|
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) {
|
__attribute__((__constructor__)) static textstartup void _vga_init(void) {
|
||||||
if (IsMetal()) {
|
if (IsMetal()) {
|
||||||
struct mman *mm = (struct mman *)(BANE + 0x0500);
|
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;
|
|
||||||
unsigned short starty = mm->pc_video_curs_info.y,
|
unsigned short starty = mm->pc_video_curs_info.y,
|
||||||
startx = mm->pc_video_curs_info.x;
|
startx = mm->pc_video_curs_info.x;
|
||||||
uint8_t chr_ht, chr_wid;
|
_vga_reinit(&_vga_tty, starty, startx, 0);
|
||||||
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(&_vga_tty, vid_type, height, width, stride, starty, startx,
|
|
||||||
chr_ht, chr_wid, vid_buf, false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -75,6 +75,16 @@
|
||||||
*/
|
*/
|
||||||
#undef VGA_PERSNICKETY_STATUS
|
#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 kTtyFg 0x0001
|
||||||
#define kTtyBg 0x0002
|
#define kTtyBg 0x0002
|
||||||
#define kTtyBold 0x0004
|
#define kTtyBold 0x0004
|
||||||
|
@ -89,6 +99,10 @@
|
||||||
#define kTtyStrike 0x0800
|
#define kTtyStrike 0x0800
|
||||||
#define kTtyConceal 0x1000
|
#define kTtyConceal 0x1000
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flags for Tty::conf. These govern the current state of the teletypewriter
|
||||||
|
* as a whole.
|
||||||
|
*/
|
||||||
#define kTtyBell 0x001
|
#define kTtyBell 0x001
|
||||||
#define kTtyRedzone 0x002
|
#define kTtyRedzone 0x002
|
||||||
#define kTtyNocursor 0x004
|
#define kTtyNocursor 0x004
|
||||||
|
@ -181,14 +195,15 @@ struct Tty {
|
||||||
* Canvas to draw into. In text modes, this is simply the frame buffer
|
* Canvas to draw into. In text modes, this is simply the frame buffer
|
||||||
* itself. In graphics modes, this should be separate from the frame
|
* itself. In graphics modes, this should be separate from the frame
|
||||||
* buffer, & possibly allocated from main memory; we must arrange to
|
* buffer, & possibly allocated from main memory; we must arrange to
|
||||||
* update the frame buffer from the canvas every now & then. In general
|
* update the frame buffer from the canvas every now & then.
|
||||||
* the canvas's pixel format — given by _TtyCanvasType() — may be
|
*
|
||||||
* different from the frame buffer's.
|
* During normal operation, the canvas's pixel format is given by
|
||||||
|
* _TtyCanvasType(), & may be different from the frame buffer's.
|
||||||
*/
|
*/
|
||||||
char *canvas;
|
char *canvas;
|
||||||
/**
|
/**
|
||||||
* Which portions of the canvas have been updated & should later be drawn
|
* 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;
|
unsigned short updy1, updx1, updy2, updx2;
|
||||||
#ifdef VGA_USE_WCS
|
#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;
|
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 _TtyBgrxUpdate(struct Tty *);
|
||||||
void _TtyRgbxUpdate(struct Tty *);
|
void _TtyRgbxUpdate(struct Tty *);
|
||||||
void _TtyBgr565Update(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,
|
void _TtyGraphMoveLineCells(struct Tty *, size_t, 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,
|
void _StartTty(struct Tty *, unsigned char, unsigned short, unsigned short,
|
||||||
unsigned short, 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 _TtyRead(struct Tty *, void *, size_t);
|
||||||
ssize_t _TtyWrite(struct Tty *, const void *, size_t);
|
ssize_t _TtyWrite(struct Tty *, const void *, size_t);
|
||||||
ssize_t _TtyWriteInput(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 const uint8_t _vga_font_default_direct[95][13];
|
||||||
extern struct Tty _vga_tty;
|
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_readv_vga(struct Fd *, const struct iovec *, int);
|
||||||
ssize_t sys_writev_vga(struct Fd *, const struct iovec *, int);
|
ssize_t sys_writev_vga(struct Fd *, const struct iovec *, int);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue