mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-13 14:39:10 +00:00
Add basic character output for VGA graphics mode console (#649)
* Test output of colors for VGA graphics modes in examples/vga.c * [metal] Character output in VGA graphics modes is mostly working * [metal] Mention magic key to switch video mode, at bootup
This commit is contained in:
parent
b75a4654cf
commit
edb8fef06c
8 changed files with 2059 additions and 324 deletions
|
@ -49,12 +49,12 @@ int main(int argc, char *argv[]) {
|
||||||
printf("res = %d?\n", res);
|
printf("res = %d?\n", res);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
printf("Hello World! %.19Lg\n", atan2l(x, y));
|
printf("\e[92;44mHello World!\e[0m %.19Lg\n", atan2l(x, y));
|
||||||
|
|
||||||
// read/print loop so machine doesn't reset on metal
|
// read/print loop so machine doesn't reset on metal
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if ((res = readansi(0, buf, 16)) > 0) {
|
if ((res = readansi(0, buf, 16)) > 0) {
|
||||||
printf("got %`'.*s\r\n", res, buf);
|
printf("got \e[97m%`'.*s\e[0m\r\n", res, buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -448,6 +448,16 @@ typedef struct {
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef unrollloops
|
||||||
|
#if !defined(__STRICT_ANSI__) && \
|
||||||
|
((__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 407 || \
|
||||||
|
__has_attribute(__optimize__))
|
||||||
|
#define unrollloops __attribute__((__optimize__("unroll-loops")))
|
||||||
|
#else
|
||||||
|
#define unrollloops
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef returnstwice
|
#ifndef returnstwice
|
||||||
#if !defined(__STRICT_ANSI__) && \
|
#if !defined(__STRICT_ANSI__) && \
|
||||||
(__has_attribute(__returns_twice__) || \
|
(__has_attribute(__returns_twice__) || \
|
||||||
|
|
|
@ -62,9 +62,13 @@ _rlinit_vesa:
|
||||||
testb $0b00000011,0x0417 # read keyboard shift state (as
|
testb $0b00000011,0x0417 # read keyboard shift state (as
|
||||||
jnz .doit # given by BIOS's IRQ 1); if Shift
|
jnz .doit # given by BIOS's IRQ 1); if Shift
|
||||||
# key pressed, activate code below
|
# key pressed, activate code below
|
||||||
|
push %si # display brief message on magic key
|
||||||
|
mov $REAL(str.inform),%si
|
||||||
|
call .puts
|
||||||
|
pop %si
|
||||||
mov $0x8300,%ax # wait for the magic key for a short
|
mov $0x8300,%ax # wait for the magic key for a short
|
||||||
mov $(250000>>16),%cx # period of time...
|
mov $(1000000>>16),%cx # period of time...
|
||||||
mov $(250000&0xffff),%dx
|
mov $(1000000&0xffff),%dx
|
||||||
push %ss
|
push %ss
|
||||||
pop %es
|
pop %es
|
||||||
mov %sp,%bx
|
mov %sp,%bx
|
||||||
|
@ -75,12 +79,14 @@ _rlinit_vesa:
|
||||||
jnz .doit2
|
jnz .doit2
|
||||||
cmpb $0,%es:(%bx)
|
cmpb $0,%es:(%bx)
|
||||||
jz .wait
|
jz .wait
|
||||||
|
call .done_inform
|
||||||
stc
|
stc
|
||||||
.done: pop %ax
|
.done: pop %ax
|
||||||
pop %es
|
pop %es
|
||||||
ret
|
ret
|
||||||
.doit2: mov $0x8301,%ax # we got the magic key; cancel the
|
.doit2: mov $0x8301,%ax # we got the magic key; cancel the
|
||||||
int $0x15 # wait timer
|
int $0x15 # wait timer, & erase message
|
||||||
|
call .done_inform
|
||||||
.doit: pop %ax # we got the magic key; do stuff
|
.doit: pop %ax # we got the magic key; do stuff
|
||||||
pop %es
|
pop %es
|
||||||
// fall through
|
// fall through
|
||||||
|
@ -139,6 +145,14 @@ _rlinit_vesa:
|
||||||
jmp 7b
|
jmp 7b
|
||||||
.endfn .do_vesa_rlinit
|
.endfn .do_vesa_rlinit
|
||||||
|
|
||||||
|
// Clear the informational message on the magic key.
|
||||||
|
.done_inform:
|
||||||
|
mov $0x0a00|' ',%ax
|
||||||
|
mov $7,%bx
|
||||||
|
mov $str.inform.end-str.inform-1,%cx
|
||||||
|
int $0x10
|
||||||
|
ret
|
||||||
|
|
||||||
// Preliminarily choose a "default" VESA screen mode from a list of
|
// Preliminarily choose a "default" VESA screen mode from a list of
|
||||||
// gathered screen modes.
|
// gathered screen modes.
|
||||||
//
|
//
|
||||||
|
@ -570,6 +584,12 @@ _rlinit_vesa:
|
||||||
.endfn .putnl
|
.endfn .putnl
|
||||||
.previous
|
.previous
|
||||||
|
|
||||||
|
str.inform:
|
||||||
|
#define SHGLYPH "\x7f"
|
||||||
|
.ascii "\rinfo: press ",SHGLYPH,"Shift "
|
||||||
|
.asciz "to switch video mode\r"
|
||||||
|
str.inform.end:
|
||||||
|
.endobj str.inform
|
||||||
str.no_vesa:
|
str.no_vesa:
|
||||||
.asciz "info: no VESA\r\n"
|
.asciz "info: no VESA\r\n"
|
||||||
.endobj str.no_vesa
|
.endobj str.no_vesa
|
||||||
|
|
287
libc/vga/tty-graph.c
Normal file
287
libc/vga/tty-graph.c
Normal file
|
@ -0,0 +1,287 @@
|
||||||
|
/*-*- 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 Routines to support output in graphical video modes for
|
||||||
|
* bare metal VGA.
|
||||||
|
*
|
||||||
|
* @see libc/vga/tty.c
|
||||||
|
*/
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
|
@ -20,10 +20,13 @@
|
||||||
#include "libc/fmt/itoa.h"
|
#include "libc/fmt/itoa.h"
|
||||||
#include "libc/intrin/bits.h"
|
#include "libc/intrin/bits.h"
|
||||||
#include "libc/intrin/safemacros.internal.h"
|
#include "libc/intrin/safemacros.internal.h"
|
||||||
|
#include "libc/runtime/directmap.internal.h"
|
||||||
#include "libc/runtime/pc.internal.h"
|
#include "libc/runtime/pc.internal.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
#include "libc/str/thompike.h"
|
#include "libc/str/thompike.h"
|
||||||
#include "libc/str/unicode.h"
|
#include "libc/str/unicode.h"
|
||||||
|
#include "libc/sysv/consts/map.h"
|
||||||
|
#include "libc/sysv/consts/prot.h"
|
||||||
#include "libc/sysv/errfuns.h"
|
#include "libc/sysv/errfuns.h"
|
||||||
#include "libc/vga/vga.internal.h"
|
#include "libc/vga/vga.internal.h"
|
||||||
|
|
||||||
|
@ -37,45 +40,58 @@
|
||||||
* @see tool/build/lib/pty.c
|
* @see tool/build/lib/pty.c
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define DEFAULT_FG 7
|
#define DEFAULT_FG ((TtyCanvasColor) \
|
||||||
#define DEFAULT_BG 0
|
{.bgr.r = 0xaa, .bgr.g = 0xaa, .bgr.b = 0xaa, \
|
||||||
|
.bgr.x = 0xff})
|
||||||
|
#define DEFAULT_BG ((TtyCanvasColor) \
|
||||||
|
{.bgr.r = 0, .bgr.g = 0, .bgr.b = 0, .bgr.x = 0xff})
|
||||||
#define CRTPORT 0x3d4
|
#define CRTPORT 0x3d4
|
||||||
|
|
||||||
static void SetYn(struct Tty *tty, unsigned short yn) {
|
static void SetYn(struct Tty *tty, unsigned short yn) {
|
||||||
#ifndef VGA_TTY_HEIGHT
|
|
||||||
tty->yn = yn;
|
tty->yn = yn;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SetXn(struct Tty *tty, unsigned short xn) {
|
static void SetXn(struct Tty *tty, unsigned short xn) {
|
||||||
#ifndef VGA_TTY_WIDTH
|
|
||||||
tty->xn = xn;
|
tty->xn = xn;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static wchar_t *SetWcs(struct Tty *tty, wchar_t *wcs) {
|
static void SetYp(struct Tty *tty, unsigned short yp) {
|
||||||
|
tty->yp = yp;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void SetXp(struct Tty *tty, unsigned short xp) {
|
||||||
|
tty->xp = xp;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void SetXsFb(struct Tty *tty, unsigned short xsfb) {
|
||||||
|
tty->xsfb = xsfb;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool SetWcs(struct Tty *tty, bool alloc_wcs) {
|
||||||
#ifdef VGA_USE_WCS
|
#ifdef VGA_USE_WCS
|
||||||
tty->wcs = wcs;
|
struct DirectMap dm;
|
||||||
return wcs;
|
if (!alloc_wcs)
|
||||||
|
return false;
|
||||||
|
dm = sys_mmap_metal(NULL, Yn(tty) * Xn(tty) * sizeof(wchar_t),
|
||||||
|
PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS,
|
||||||
|
-1, 0);
|
||||||
|
if (dm.addr == (void *)-1) {
|
||||||
|
tty->wcs = NULL;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
tty->wcs = dm.addr;
|
||||||
|
return true;
|
||||||
#else
|
#else
|
||||||
return NULL;
|
return false;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t Yn(struct Tty *tty) {
|
static size_t Yn(struct Tty *tty) {
|
||||||
#ifdef VGA_TTY_HEIGHT
|
|
||||||
return VGA_TTY_HEIGHT;
|
|
||||||
#else
|
|
||||||
return tty->yn;
|
return tty->yn;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t Xn(struct Tty *tty) {
|
static size_t Xn(struct Tty *tty) {
|
||||||
#ifdef VGA_TTY_WIDTH
|
|
||||||
return VGA_TTY_WIDTH;
|
|
||||||
#else
|
|
||||||
return tty->xn;
|
return tty->xn;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static wchar_t *Wcs(struct Tty *tty) {
|
static wchar_t *Wcs(struct Tty *tty) {
|
||||||
|
@ -86,23 +102,82 @@ static wchar_t *Wcs(struct Tty *tty) {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void _StartTty(struct Tty *tty, unsigned short yn, unsigned short xn,
|
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) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _StartTty(struct Tty *tty, unsigned char type,
|
||||||
|
unsigned short yp, unsigned short xp, unsigned short xsfb,
|
||||||
unsigned short starty, unsigned short startx,
|
unsigned short starty, unsigned short startx,
|
||||||
unsigned char chr_ht, void *vccs, wchar_t *wcs) {
|
unsigned char yc, unsigned char xc, void *fb, bool alloc_wcs) {
|
||||||
struct VgaTextCharCell *ccs = vccs;
|
unsigned short yn, xn, xs = xp * sizeof(TtyCanvasColor);
|
||||||
|
struct DirectMap dm;
|
||||||
memset(tty, 0, sizeof(struct Tty));
|
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;
|
||||||
|
tty->canvas = fb;
|
||||||
|
} 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. */
|
||||||
|
tty->canvas = fb;
|
||||||
|
starty = startx = 0;
|
||||||
|
} else
|
||||||
|
tty->canvas = dm.addr;
|
||||||
|
}
|
||||||
SetYn(tty, yn);
|
SetYn(tty, yn);
|
||||||
SetXn(tty, xn);
|
SetXn(tty, xn);
|
||||||
tty->ccs = ccs;
|
tty->yc = yc;
|
||||||
|
tty->xc = xc;
|
||||||
|
tty->fb = fb;
|
||||||
if (starty >= yn) starty = yn - 1;
|
if (starty >= yn) starty = yn - 1;
|
||||||
if (startx >= xn) startx = xn - 1;
|
if (startx >= xn) startx = xn - 1;
|
||||||
if (chr_ht > 32) chr_ht = 32;
|
|
||||||
tty->y = starty;
|
tty->y = starty;
|
||||||
tty->x = startx;
|
tty->x = startx;
|
||||||
tty->chr_ht = chr_ht;
|
TtySetType(tty, type);
|
||||||
if (SetWcs(tty, wcs)) {
|
if (SetWcs(tty, alloc_wcs)) {
|
||||||
|
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) {
|
||||||
|
struct VgaTextCharCell *ccs = fb;
|
||||||
for (i = 0; i < n; ++i) wcs[i] = bing(ccs[i].ch, 0);
|
for (i = 0; i < n; ++i) wcs[i] = bing(ccs[i].ch, 0);
|
||||||
|
} else
|
||||||
|
wmemset(wcs, L' ', n);
|
||||||
}
|
}
|
||||||
_TtyResetOutputMode(tty);
|
_TtyResetOutputMode(tty);
|
||||||
}
|
}
|
||||||
|
@ -213,6 +288,25 @@ static void TtySetCodepage(struct Tty *tty, char id) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map the given direct color value to one of the 16 basic foreground colors
|
||||||
|
* or one of the 16 background colors.
|
||||||
|
*
|
||||||
|
* @see drivers/tty/vt/vt.c in Linux 5.9.14 source code
|
||||||
|
*/
|
||||||
|
static uint8_t TtyGetTextColor(TtyCanvasColor color) {
|
||||||
|
uint8_t r = color.bgr.r, g = color.bgr.g, b = color.bgr.b;
|
||||||
|
uint8_t hue = 0, max = MAX(MAX(r, g), b);
|
||||||
|
if (r > max / 2) hue |= 4;
|
||||||
|
if (g > max / 2) hue |= 2;
|
||||||
|
if (b > max / 2) hue |= 1;
|
||||||
|
if (hue == 7 && max <= 0x55)
|
||||||
|
hue = 8;
|
||||||
|
else if (max > 0xaa)
|
||||||
|
hue |= 8;
|
||||||
|
return hue;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Map the currently active foreground & background colors & terminal
|
* Map the currently active foreground & background colors & terminal
|
||||||
* configuration to a VGA text character attribute byte.
|
* configuration to a VGA text character attribute byte.
|
||||||
|
@ -220,12 +314,13 @@ static void TtySetCodepage(struct Tty *tty, char id) {
|
||||||
* @see VGA_USE_BLINK macro (libc/vga/vga.internal.h)
|
* @see VGA_USE_BLINK macro (libc/vga/vga.internal.h)
|
||||||
* @see drivers/tty/vt/vt.c in Linux 5.9.14 source code
|
* @see drivers/tty/vt/vt.c in Linux 5.9.14 source code
|
||||||
*/
|
*/
|
||||||
static uint8_t TtyGetVgaAttr(struct Tty *tty) {
|
static uint8_t TtyGetTextAttr(struct Tty *tty) {
|
||||||
|
uint8_t fg = TtyGetTextColor(tty->fg), bg = TtyGetTextColor(tty->bg);
|
||||||
uint8_t attr;
|
uint8_t attr;
|
||||||
if ((tty->pr & kTtyFlip) == 0)
|
if ((tty->pr & kTtyFlip) == 0)
|
||||||
attr = tty->fg | tty->bg << 4;
|
attr = fg | bg << 4;
|
||||||
else
|
else
|
||||||
attr = tty->bg | tty->fg << 4;
|
attr = bg | fg << 4;
|
||||||
#ifdef VGA_USE_BLINK
|
#ifdef VGA_USE_BLINK
|
||||||
/*
|
/*
|
||||||
* If blinking is enabled, we can only have the 8 dark background color
|
* If blinking is enabled, we can only have the 8 dark background color
|
||||||
|
@ -240,41 +335,73 @@ static uint8_t TtyGetVgaAttr(struct Tty *tty) {
|
||||||
return attr;
|
return attr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void TtyErase(struct Tty *tty, size_t dst, size_t n) {
|
static void TtyTextDrawChar(struct Tty *tty, size_t y, size_t x, wchar_t wc) {
|
||||||
uint8_t attr = TtyGetVgaAttr(tty);
|
uint8_t attr = TtyGetTextAttr(tty);
|
||||||
size_t i;
|
struct VgaTextCharCell *ccs = (struct VgaTextCharCell *)tty->canvas;
|
||||||
|
size_t i = tty->y * Xn(tty) + tty->x;
|
||||||
|
int c = unbing(wc);
|
||||||
|
if (c == -1) c = 0xFE;
|
||||||
|
ccs[i] = (struct VgaTextCharCell){c, attr};
|
||||||
|
}
|
||||||
|
|
||||||
|
static void TtyTextEraseLineCells(struct Tty *tty, size_t dsty, size_t dstx,
|
||||||
|
size_t n) {
|
||||||
|
uint8_t attr = TtyGetTextAttr(tty);
|
||||||
|
struct VgaTextCharCell *ccs = (struct VgaTextCharCell *)tty->canvas;
|
||||||
|
size_t dst = dsty * Xn(tty) + dstx, i;
|
||||||
for (i = 0; i < n; ++i)
|
for (i = 0; i < n; ++i)
|
||||||
tty->ccs[dst + i] = (struct VgaTextCharCell){' ', attr};
|
ccs[dst + i] = (struct VgaTextCharCell){' ', attr};
|
||||||
if (Wcs(tty)) wmemset(Wcs(tty) + dst, L' ', n);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void _TtyEraseLineCells(struct Tty *tty, size_t dsty, size_t dstx, size_t n) {
|
void _TtyEraseLineCells(struct Tty *tty, size_t dsty, size_t dstx, size_t n) {
|
||||||
size_t xn = Xn(tty);
|
tty->eraselinecells(tty, dsty, dstx, n);
|
||||||
TtyErase(tty, dsty * xn + dstx, n);
|
if (Wcs(tty)) {
|
||||||
|
size_t i = dsty * Xn(tty) + dstx;
|
||||||
|
wmemset(Wcs(tty) + i, L' ', n);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _TtyEraseLines(struct Tty *tty, size_t dsty, size_t n) {
|
void _TtyEraseLines(struct Tty *tty, size_t dsty, size_t n) {
|
||||||
size_t xn = Xn(tty);
|
size_t xn = Xn(tty), y;
|
||||||
TtyErase(tty, dsty * xn, n * xn);
|
y = dsty;
|
||||||
|
while (n-- != 0) {
|
||||||
|
_TtyEraseLineCells(tty, y, 0, xn);
|
||||||
|
++y;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void TtyMemmove(struct Tty *tty, size_t dst, size_t src, size_t n) {
|
static void TtyTextMoveLineCells(struct Tty *tty, size_t dsty, size_t dstx,
|
||||||
memmove(tty->ccs + dst, tty->ccs + src, n * sizeof(struct VgaTextCharCell));
|
size_t srcy, size_t srcx, size_t n) {
|
||||||
if (Wcs(tty)) wmemmove(Wcs(tty) + dst, Wcs(tty) + src, n);
|
size_t xn = Xn(tty);
|
||||||
|
size_t dst = dsty * xn + dstx, src = srcy * xn + srcx;
|
||||||
|
struct VgaTextCharCell *ccs = (struct VgaTextCharCell *)tty->canvas;
|
||||||
|
memmove(ccs + dst, ccs + src, n * sizeof(struct VgaTextCharCell));
|
||||||
}
|
}
|
||||||
|
|
||||||
void _TtyMoveLineCells(struct Tty *tty, size_t dsty, size_t dstx,
|
void _TtyMoveLineCells(struct Tty *tty, size_t dsty, size_t dstx,
|
||||||
size_t srcy, size_t srcx, size_t n) {
|
size_t srcy, size_t srcx, size_t n) {
|
||||||
size_t xn = Xn(tty);
|
size_t xn = Xn(tty);
|
||||||
TtyMemmove(tty, dsty * xn + dstx, srcy * xn + srcx, n);
|
size_t dst = dsty * xn + dstx, src = srcy * xn + srcx;
|
||||||
|
tty->movelinecells(tty, dsty, dstx, srcy, srcx, n);
|
||||||
|
if (Wcs(tty)) wmemmove(Wcs(tty) + dst, Wcs(tty) + src, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _TtyMoveLines(struct Tty *tty, size_t dsty, size_t srcy, size_t n) {
|
void _TtyMoveLines(struct Tty *tty, size_t dsty, size_t srcy, size_t n) {
|
||||||
size_t xn = Xn(tty);
|
size_t xn = Xn(tty);
|
||||||
TtyMemmove(tty, dsty * xn, srcy * xn, n * xn);
|
if (dsty < srcy) {
|
||||||
|
while (n-- != 0) {
|
||||||
|
_TtyMoveLineCells(tty, dsty, 0, srcy, 0, xn);
|
||||||
|
++dsty;
|
||||||
|
++srcy;
|
||||||
|
}
|
||||||
|
} else if (dsty > srcy) {
|
||||||
|
while (n-- != 0)
|
||||||
|
_TtyMoveLineCells(tty, dsty + n, 0, srcy + n, 0, xn);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _TtyResetOutputMode(struct Tty *tty) {
|
void _TtyResetOutputMode(struct Tty *tty) {
|
||||||
|
tty->updy1 = tty->updx1 = tty->updy2 = tty->updx2 = 0;
|
||||||
tty->pr = 0;
|
tty->pr = 0;
|
||||||
tty->fg = DEFAULT_FG;
|
tty->fg = DEFAULT_FG;
|
||||||
tty->bg = DEFAULT_BG;
|
tty->bg = DEFAULT_BG;
|
||||||
|
@ -354,18 +481,12 @@ static void TtyAdvance(struct Tty *tty) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void TtyWriteGlyph(struct Tty *tty, wint_t wc, int w) {
|
static void TtyWriteGlyph(struct Tty *tty, wint_t wc, int w) {
|
||||||
uint8_t attr = TtyGetVgaAttr(tty);
|
|
||||||
size_t i;
|
|
||||||
int c;
|
|
||||||
if (w < 1) wc = L' ', w = 1;
|
if (w < 1) wc = L' ', w = 1;
|
||||||
if ((tty->conf & kTtyRedzone) || tty->x + w > Xn(tty)) {
|
if ((tty->conf & kTtyRedzone) || tty->x + w > Xn(tty)) {
|
||||||
TtyAdvance(tty);
|
TtyAdvance(tty);
|
||||||
}
|
}
|
||||||
i = tty->y * Xn(tty) + tty->x;
|
tty->drawchar(tty, tty->y, tty->x, wc);
|
||||||
c = unbing(wc);
|
if (Wcs(tty)) Wcs(tty)[tty->y * Xn(tty) + tty->x] = wc;
|
||||||
if (c == -1) c = 0xFE;
|
|
||||||
tty->ccs[i] = (struct VgaTextCharCell){c, attr};
|
|
||||||
if (Wcs(tty)) Wcs(tty)[i] = wc;
|
|
||||||
if ((tty->x += w) >= Xn(tty)) {
|
if ((tty->x += w) >= Xn(tty)) {
|
||||||
tty->x = Xn(tty) - 1;
|
tty->x = Xn(tty) - 1;
|
||||||
tty->conf |= kTtyRedzone;
|
tty->conf |= kTtyRedzone;
|
||||||
|
@ -373,14 +494,13 @@ static void TtyWriteGlyph(struct Tty *tty, wint_t wc, int w) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void TtyWriteTab(struct Tty *tty) {
|
static void TtyWriteTab(struct Tty *tty) {
|
||||||
uint8_t attr = TtyGetVgaAttr(tty);
|
|
||||||
unsigned x, x2;
|
unsigned x, x2;
|
||||||
if (tty->conf & kTtyRedzone) {
|
if (tty->conf & kTtyRedzone) {
|
||||||
TtyAdvance(tty);
|
TtyAdvance(tty);
|
||||||
}
|
}
|
||||||
x2 = MIN(Xn(tty), ROUNDUP(tty->x + 1, 8));
|
x2 = MIN(Xn(tty), ROUNDUP(tty->x + 1, 8));
|
||||||
for (x = tty->x; x < x2; ++x) {
|
for (x = tty->x; x < x2; ++x) {
|
||||||
tty->ccs[tty->y * Xn(tty) + x] = (struct VgaTextCharCell){' ', attr};
|
tty->eraselinecells(tty, tty->y, x, 1);
|
||||||
}
|
}
|
||||||
if (Wcs(tty)) {
|
if (Wcs(tty)) {
|
||||||
for (x = tty->x; x < x2; ++x) {
|
for (x = tty->x; x < x2; ++x) {
|
||||||
|
@ -637,61 +757,13 @@ static void TtyCsiN(struct Tty *tty) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Create a direct color pixel value. */
|
||||||
* Map the given ECMA-48 / VT100 SGR color code to a color code for a VGA
|
static TtyCanvasColor TtyMapTrueColor(uint8_t r, uint8_t g, uint8_t b) {
|
||||||
* character attribute. More precisely, map
|
return (TtyCanvasColor){.bgr.r = r, .bgr.g = g, .bgr.b = b, .bgr.x = 0xff};
|
||||||
*
|
|
||||||
* red──┐
|
|
||||||
* green─┐│
|
|
||||||
* blue┐││
|
|
||||||
* intensity│││
|
|
||||||
* ││││
|
|
||||||
* 3210
|
|
||||||
*
|
|
||||||
* to
|
|
||||||
*
|
|
||||||
* blue──┐
|
|
||||||
* green─┐│
|
|
||||||
* red┐││
|
|
||||||
* intensity│││
|
|
||||||
* ││││
|
|
||||||
* 3210
|
|
||||||
*/
|
|
||||||
static uint8_t TtyMapEcma48Color(uint8_t color)
|
|
||||||
{
|
|
||||||
switch (color & 0b101) {
|
|
||||||
case 0b100:
|
|
||||||
case 0b001:
|
|
||||||
color ^= 0b101;
|
|
||||||
}
|
|
||||||
return color;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Map the given 256-color code to a direct color. */
|
||||||
* Map the given (R, G, B) triplet to one of the 16 basic foreground colors
|
static TtyCanvasColor TtyMapXtermColor(uint8_t color) {
|
||||||
* or one of the 16 background colors.
|
|
||||||
*
|
|
||||||
* @see drivers/tty/vt/vt.c in Linux 5.9.14 source code
|
|
||||||
*/
|
|
||||||
static uint8_t TtyMapTrueColor(uint8_t r, uint8_t g, uint8_t b) {
|
|
||||||
uint8_t hue = 0, max = MAX(MAX(r, g), b);
|
|
||||||
if (r > max / 2) hue |= 4;
|
|
||||||
if (g > max / 2) hue |= 2;
|
|
||||||
if (b > max / 2) hue |= 1;
|
|
||||||
if (hue == 7 && max <= 0x55)
|
|
||||||
hue = 8;
|
|
||||||
else if (max > 0xaa)
|
|
||||||
hue |= 8;
|
|
||||||
return hue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Map the given 256-color code one of the 16 basic foreground colors or one
|
|
||||||
* of the 8 background colors.
|
|
||||||
*
|
|
||||||
* @see drivers/tty/vt/vt.c in Linux 5.9.14 source code
|
|
||||||
*/
|
|
||||||
static uint8_t TtyMapXtermColor(uint8_t color) {
|
|
||||||
uint8_t r, g, b;
|
uint8_t r, g, b;
|
||||||
if (color < 8) {
|
if (color < 8) {
|
||||||
r = (color & 1) ? 0xaa : 0;
|
r = (color & 1) ? 0xaa : 0;
|
||||||
|
@ -713,6 +785,12 @@ static uint8_t TtyMapXtermColor(uint8_t color) {
|
||||||
return TtyMapTrueColor(r, g, b);
|
return TtyMapTrueColor(r, g, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Map the given ECMA-48 / VT100 SGR color code to a direct color. */
|
||||||
|
static TtyCanvasColor TtyMapEcma48Color(uint8_t color)
|
||||||
|
{
|
||||||
|
return TtyMapXtermColor(color % 16);
|
||||||
|
}
|
||||||
|
|
||||||
static void TtySelectGraphicsRendition(struct Tty *tty) {
|
static void TtySelectGraphicsRendition(struct Tty *tty) {
|
||||||
char *p, c;
|
char *p, c;
|
||||||
unsigned x;
|
unsigned x;
|
||||||
|
@ -983,10 +1061,10 @@ static void TtyCsi(struct Tty *tty) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void TtyScreenAlignmentDisplay(struct Tty *tty) {
|
static void TtyScreenAlignmentDisplay(struct Tty *tty) {
|
||||||
uint8_t attr = TtyGetVgaAttr(tty);
|
size_t yn = Yn(tty), xn = Xn(tty), y, x;
|
||||||
size_t n = Yn(tty) * Xn(tty), i;
|
for (y = 0; y < yn; ++y)
|
||||||
for (i = 0; i < n; ++i) tty->ccs[i] = (struct VgaTextCharCell){'E', attr};
|
for (x = 0; x < xn; ++x) tty->drawchar(tty, y, x, 'E');
|
||||||
if (Wcs(tty)) wmemset(Wcs(tty), L'E', n);
|
if (Wcs(tty)) wmemset(Wcs(tty), L'E', yn * xn);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void TtyEscHash(struct Tty *tty) {
|
static void TtyEscHash(struct Tty *tty) {
|
||||||
|
@ -1083,8 +1161,9 @@ static void TtyEscAppend(struct Tty *tty, char c) {
|
||||||
tty->esc.s[tty->esc.i - 0] = 0;
|
tty->esc.s[tty->esc.i - 0] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void TtyUpdateHwCursor(struct Tty *tty) {
|
static void TtyUpdate(struct Tty *tty) {
|
||||||
unsigned char start = tty->chr_ht - 2, end = tty->chr_ht - 1;
|
if (tty->type == PC_VIDEO_TEXT) {
|
||||||
|
unsigned char start = tty->yc - 2, end = tty->yc - 1;
|
||||||
unsigned short pos = tty->y * Xn(tty) + tty->x;
|
unsigned short pos = tty->y * Xn(tty) + tty->x;
|
||||||
if ((tty->conf & kTtyNocursor)) start |= 1 << 5;
|
if ((tty->conf & kTtyNocursor)) start |= 1 << 5;
|
||||||
outb(CRTPORT, 0x0A);
|
outb(CRTPORT, 0x0A);
|
||||||
|
@ -1095,6 +1174,8 @@ static void TtyUpdateHwCursor(struct Tty *tty) {
|
||||||
outb(CRTPORT + 1, (unsigned char)(pos >> 8));
|
outb(CRTPORT + 1, (unsigned char)(pos >> 8));
|
||||||
outb(CRTPORT, 0x0F);
|
outb(CRTPORT, 0x0F);
|
||||||
outb(CRTPORT + 1, (unsigned char)pos);
|
outb(CRTPORT + 1, (unsigned char)pos);
|
||||||
|
} else
|
||||||
|
tty->update(tty);
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t _TtyWrite(struct Tty *tty, const void *data, size_t n) {
|
ssize_t _TtyWrite(struct Tty *tty, const void *data, size_t n) {
|
||||||
|
@ -1184,7 +1265,7 @@ ssize_t _TtyWrite(struct Tty *tty, const void *data, size_t n) {
|
||||||
unreachable;
|
unreachable;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TtyUpdateHwCursor(tty);
|
TtyUpdate(tty);
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
1441
libc/vga/vga-font-default.c
Normal file
1441
libc/vga/vga-font-default.c
Normal file
File diff suppressed because it is too large
Load diff
|
@ -1,5 +1,6 @@
|
||||||
#ifndef COSMOPOLITAN_LIBC_VGA_VGA_INTERNAL_H_
|
#ifndef COSMOPOLITAN_LIBC_VGA_VGA_INTERNAL_H_
|
||||||
#define COSMOPOLITAN_LIBC_VGA_VGA_INTERNAL_H_
|
#define COSMOPOLITAN_LIBC_VGA_VGA_INTERNAL_H_
|
||||||
|
#include "libc/runtime/mman.internal.h"
|
||||||
|
|
||||||
/** Preferred width of the video screen, in character units. */
|
/** Preferred width of the video screen, in character units. */
|
||||||
#define VGA_PREFER_TTY_HEIGHT 30
|
#define VGA_PREFER_TTY_HEIGHT 30
|
||||||
|
@ -111,6 +112,31 @@ struct VgaTextCharCell {
|
||||||
uint8_t ch, attr;
|
uint8_t ch, attr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef union {
|
||||||
|
uint32_t w;
|
||||||
|
struct {
|
||||||
|
uint8_t b, g, r, x;
|
||||||
|
} bgr;
|
||||||
|
} TtyBgrxColor;
|
||||||
|
|
||||||
|
typedef union {
|
||||||
|
uint32_t w;
|
||||||
|
struct {
|
||||||
|
uint8_t r, g, b, x;
|
||||||
|
} rgb;
|
||||||
|
} TtyRgbxColor;
|
||||||
|
|
||||||
|
typedef union {
|
||||||
|
uint16_t w;
|
||||||
|
} TtyBgr565Color;
|
||||||
|
|
||||||
|
typedef union {
|
||||||
|
uint16_t w;
|
||||||
|
} TtyBgr555Color;
|
||||||
|
|
||||||
|
typedef TtyBgrxColor TtyCanvasColor;
|
||||||
|
struct Tty;
|
||||||
|
|
||||||
struct Tty {
|
struct Tty {
|
||||||
/**
|
/**
|
||||||
* Cursor position. (y, x) = (0, 0) means the cursor is on the top left
|
* Cursor position. (y, x) = (0, 0) means the cursor is on the top left
|
||||||
|
@ -123,7 +149,12 @@ struct Tty {
|
||||||
unsigned short yp, xp;
|
unsigned short yp, xp;
|
||||||
/**
|
/**
|
||||||
* Number of bytes (NOTE) occupied by each row of pixels, including any
|
* Number of bytes (NOTE) occupied by each row of pixels, including any
|
||||||
* invisible "pixels".
|
* invisible "pixels", in the video frame buffer.
|
||||||
|
*/
|
||||||
|
unsigned short xsfb;
|
||||||
|
/**
|
||||||
|
* Number of bytes (NOTE) occupied by each row of pixels, including any
|
||||||
|
* invisible "pixels", in the canvas.
|
||||||
*/
|
*/
|
||||||
unsigned short xs;
|
unsigned short xs;
|
||||||
/** Type of video buffer (from mman::pc_video_type). */
|
/** Type of video buffer (from mman::pc_video_type). */
|
||||||
|
@ -131,10 +162,35 @@ struct Tty {
|
||||||
uint32_t u8;
|
uint32_t u8;
|
||||||
uint32_t n8;
|
uint32_t n8;
|
||||||
uint32_t pr;
|
uint32_t pr;
|
||||||
uint8_t fg, bg, chr_ht;
|
TtyCanvasColor fg, bg;
|
||||||
|
/**
|
||||||
|
* Height of each character in pixels. In text modes, this is used in
|
||||||
|
* setting the shape of the hardware cursor.
|
||||||
|
*/
|
||||||
|
uint8_t yc;
|
||||||
|
/**
|
||||||
|
* Width of each character in pixels. This is mostly useful only in
|
||||||
|
* graphics modes.
|
||||||
|
*/
|
||||||
|
uint8_t xc;
|
||||||
uint32_t conf;
|
uint32_t conf;
|
||||||
unsigned short savey, savex;
|
unsigned short savey, savex;
|
||||||
struct VgaTextCharCell *ccs;
|
/** Actual video frame buffer as provided by the video card. */
|
||||||
|
char *fb;
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
char *canvas;
|
||||||
|
/**
|
||||||
|
* Which portions of the canvas have been updated & should later be drawn
|
||||||
|
* to screen with tty->update().
|
||||||
|
*/
|
||||||
|
unsigned short updy1, updx1, updy2, updx2;
|
||||||
#ifdef VGA_USE_WCS
|
#ifdef VGA_USE_WCS
|
||||||
wchar_t *wcs;
|
wchar_t *wcs;
|
||||||
#endif
|
#endif
|
||||||
|
@ -153,11 +209,28 @@ struct Tty {
|
||||||
size_t i;
|
size_t i;
|
||||||
char p[256];
|
char p[256];
|
||||||
} input;
|
} input;
|
||||||
|
void (*update)(struct Tty *);
|
||||||
|
void (*drawchar)(struct Tty *, size_t, size_t, wchar_t);
|
||||||
|
void (*eraselinecells)(struct Tty *, size_t, size_t, size_t);
|
||||||
|
void (*movelinecells)(struct Tty *, size_t, size_t, size_t, size_t, size_t);
|
||||||
};
|
};
|
||||||
|
|
||||||
void _StartTty(struct Tty *, unsigned short, unsigned short,
|
forceinline unsigned char _TtyCanvasType(struct Tty *tty) {
|
||||||
unsigned short, unsigned short, unsigned char,
|
return tty->type == PC_VIDEO_TEXT ? PC_VIDEO_TEXT : PC_VIDEO_BGRX8888;
|
||||||
void *, wchar_t *);
|
}
|
||||||
|
|
||||||
|
void _TtyBgrxUpdate(struct Tty *);
|
||||||
|
void _TtyRgbxUpdate(struct Tty *);
|
||||||
|
void _TtyBgr565Update(struct Tty *);
|
||||||
|
void _TtyBgr555Update(struct Tty *);
|
||||||
|
void _TtyGraphDrawChar(struct Tty *, size_t, size_t, wchar_t);
|
||||||
|
void _TtyGraphEraseLineCells(struct Tty *, size_t, size_t, size_t);
|
||||||
|
void _TtyGraphMoveLineCells(struct Tty *, size_t, size_t, size_t, size_t,
|
||||||
|
size_t);
|
||||||
|
|
||||||
|
void _StartTty(struct Tty *, unsigned char, unsigned short, unsigned short,
|
||||||
|
unsigned short, unsigned short, unsigned short,
|
||||||
|
unsigned char, unsigned char, void *, bool);
|
||||||
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);
|
||||||
|
@ -170,6 +243,7 @@ void _TtyEraseLines(struct Tty *, size_t, size_t);
|
||||||
void _TtySetY(struct Tty *, unsigned short);
|
void _TtySetY(struct Tty *, unsigned short);
|
||||||
void _TtySetX(struct Tty *, unsigned short);
|
void _TtySetX(struct Tty *, unsigned short);
|
||||||
|
|
||||||
|
extern const uint8_t _vga_font_default_direct[95][13];
|
||||||
extern struct Tty _vga_tty;
|
extern struct Tty _vga_tty;
|
||||||
|
|
||||||
ssize_t sys_readv_vga(struct Fd *, const struct iovec *, int);
|
ssize_t sys_readv_vga(struct Fd *, const struct iovec *, int);
|
||||||
|
|
|
@ -52,185 +52,6 @@ ssize_t sys_writev_vga(struct Fd *fd, const struct iovec *iov, int iovlen) {
|
||||||
return wrote;
|
return wrote;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _vga_init_test(void *vid_buf, unsigned char vid_type,
|
|
||||||
size_t stride) {
|
|
||||||
switch (vid_type) {
|
|
||||||
case PC_VIDEO_TEXT:
|
|
||||||
break;
|
|
||||||
case PC_VIDEO_BGR565:
|
|
||||||
{
|
|
||||||
char *row_buf = (char *)vid_buf + stride * 100;
|
|
||||||
uint16_t *row_pix = (uint16_t *)row_buf;
|
|
||||||
unsigned i;
|
|
||||||
row_pix[0] = 0x0000;
|
|
||||||
row_pix[1] = 0x0000;
|
|
||||||
row_pix[2] = 0x07fc;
|
|
||||||
row_pix[3] = 0x07fc;
|
|
||||||
row_pix[4] = 0x07fc;
|
|
||||||
row_pix[5] = 0x0000;
|
|
||||||
row_pix[6] = 0x0000;
|
|
||||||
row_pix[7] = 0x0000;
|
|
||||||
row_buf += stride;
|
|
||||||
row_pix = (uint16_t *)row_buf;
|
|
||||||
row_pix[0] = 0x0000;
|
|
||||||
row_pix[1] = 0x07fc;
|
|
||||||
row_pix[2] = 0x07fc;
|
|
||||||
row_pix[3] = 0x07fc;
|
|
||||||
row_pix[4] = 0x07fc;
|
|
||||||
row_pix[5] = 0x07fc;
|
|
||||||
row_pix[6] = 0x0000;
|
|
||||||
row_pix[7] = 0x0000;
|
|
||||||
row_buf += stride;
|
|
||||||
row_pix = (uint16_t *)row_buf;
|
|
||||||
row_pix[0] = 0x07fc;
|
|
||||||
row_pix[1] = 0x07fc;
|
|
||||||
row_pix[2] = 0x0000;
|
|
||||||
row_pix[3] = 0x0000;
|
|
||||||
row_pix[4] = 0x0000;
|
|
||||||
row_pix[5] = 0x07fc;
|
|
||||||
row_pix[6] = 0x07fc;
|
|
||||||
row_pix[7] = 0x0000;
|
|
||||||
row_buf += stride;
|
|
||||||
row_pix = (uint16_t *)row_buf;
|
|
||||||
row_pix[0] = 0x07fc;
|
|
||||||
row_pix[1] = 0x07fc;
|
|
||||||
row_pix[2] = 0x07fc;
|
|
||||||
row_pix[3] = 0x07fc;
|
|
||||||
row_pix[4] = 0x07fc;
|
|
||||||
row_pix[5] = 0x07fc;
|
|
||||||
row_pix[6] = 0x07fc;
|
|
||||||
row_pix[7] = 0x0000;
|
|
||||||
for (i = 0; i < 4; ++i) {
|
|
||||||
row_buf += stride;
|
|
||||||
row_pix = (uint16_t *)row_buf;
|
|
||||||
row_pix[0] = 0xf81f;
|
|
||||||
row_pix[1] = 0xf81f;
|
|
||||||
row_pix[2] = 0x0000;
|
|
||||||
row_pix[3] = 0x0000;
|
|
||||||
row_pix[4] = 0x0000;
|
|
||||||
row_pix[5] = 0xf81f;
|
|
||||||
row_pix[6] = 0xf81f;
|
|
||||||
row_pix[7] = 0x0000;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case PC_VIDEO_BGR555:
|
|
||||||
{
|
|
||||||
char *row_buf = (char *)vid_buf + stride * 100;
|
|
||||||
uint16_t *row_pix = (uint16_t *)row_buf;
|
|
||||||
unsigned i;
|
|
||||||
row_pix[0] = 0x8000;
|
|
||||||
row_pix[1] = 0x8000;
|
|
||||||
row_pix[2] = 0x83fc;
|
|
||||||
row_pix[3] = 0x83fc;
|
|
||||||
row_pix[4] = 0x83fc;
|
|
||||||
row_pix[5] = 0x8000;
|
|
||||||
row_pix[6] = 0x8000;
|
|
||||||
row_pix[7] = 0x8000;
|
|
||||||
row_buf += stride;
|
|
||||||
row_pix = (uint16_t *)row_buf;
|
|
||||||
row_pix[0] = 0x8000;
|
|
||||||
row_pix[1] = 0x83fc;
|
|
||||||
row_pix[2] = 0x83fc;
|
|
||||||
row_pix[3] = 0x83fc;
|
|
||||||
row_pix[4] = 0x83fc;
|
|
||||||
row_pix[5] = 0x83fc;
|
|
||||||
row_pix[6] = 0x8000;
|
|
||||||
row_pix[7] = 0x8000;
|
|
||||||
row_buf += stride;
|
|
||||||
row_pix = (uint16_t *)row_buf;
|
|
||||||
row_pix[0] = 0x83fc;
|
|
||||||
row_pix[1] = 0x83fc;
|
|
||||||
row_pix[2] = 0x8000;
|
|
||||||
row_pix[3] = 0x8000;
|
|
||||||
row_pix[4] = 0x8000;
|
|
||||||
row_pix[5] = 0x83fc;
|
|
||||||
row_pix[6] = 0x83fc;
|
|
||||||
row_pix[7] = 0x8000;
|
|
||||||
row_buf += stride;
|
|
||||||
row_pix = (uint16_t *)row_buf;
|
|
||||||
row_pix[0] = 0x83fc;
|
|
||||||
row_pix[1] = 0x83fc;
|
|
||||||
row_pix[2] = 0x83fc;
|
|
||||||
row_pix[3] = 0x83fc;
|
|
||||||
row_pix[4] = 0x83fc;
|
|
||||||
row_pix[5] = 0x83fc;
|
|
||||||
row_pix[6] = 0x83fc;
|
|
||||||
row_pix[7] = 0x8000;
|
|
||||||
for (i = 0; i < 4; ++i) {
|
|
||||||
row_buf += stride;
|
|
||||||
row_pix = (uint16_t *)row_buf;
|
|
||||||
row_pix[0] = 0xfc1f;
|
|
||||||
row_pix[1] = 0xfc1f;
|
|
||||||
row_pix[2] = 0x8000;
|
|
||||||
row_pix[3] = 0x8000;
|
|
||||||
row_pix[4] = 0x8000;
|
|
||||||
row_pix[5] = 0xfc1f;
|
|
||||||
row_pix[6] = 0xfc1f;
|
|
||||||
row_pix[7] = 0x8000;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
char *row_buf = (char *)vid_buf + stride * 100;
|
|
||||||
uint32_t *row_pix = (uint32_t *)row_buf;
|
|
||||||
unsigned i;
|
|
||||||
row_pix[0] = 0xff000000;
|
|
||||||
row_pix[1] = 0xff000000;
|
|
||||||
row_pix[2] = 0xff00ffe0;
|
|
||||||
row_pix[3] = 0xff00ffe0;
|
|
||||||
row_pix[4] = 0xff00ffe0;
|
|
||||||
row_pix[5] = 0xff000000;
|
|
||||||
row_pix[6] = 0xff000000;
|
|
||||||
row_pix[7] = 0xff000000;
|
|
||||||
row_buf += stride;
|
|
||||||
row_pix = (uint32_t *)row_buf;
|
|
||||||
row_pix[0] = 0xff000000;
|
|
||||||
row_pix[1] = 0xff00ffe0;
|
|
||||||
row_pix[2] = 0xff00ffe0;
|
|
||||||
row_pix[3] = 0xff00ffe0;
|
|
||||||
row_pix[4] = 0xff00ffe0;
|
|
||||||
row_pix[5] = 0xff00ffe0;
|
|
||||||
row_pix[6] = 0xff000000;
|
|
||||||
row_pix[7] = 0xff000000;
|
|
||||||
row_buf += stride;
|
|
||||||
row_pix = (uint32_t *)row_buf;
|
|
||||||
row_pix[0] = 0xff00ffe0;
|
|
||||||
row_pix[1] = 0xff00ffe0;
|
|
||||||
row_pix[2] = 0xff000000;
|
|
||||||
row_pix[3] = 0xff000000;
|
|
||||||
row_pix[4] = 0xff000000;
|
|
||||||
row_pix[5] = 0xff00ffe0;
|
|
||||||
row_pix[6] = 0xff00ffe0;
|
|
||||||
row_pix[7] = 0xff000000;
|
|
||||||
row_buf += stride;
|
|
||||||
row_pix = (uint32_t *)row_buf;
|
|
||||||
row_pix[0] = 0xff00ffe0;
|
|
||||||
row_pix[1] = 0xff00ffe0;
|
|
||||||
row_pix[2] = 0xff00ffe0;
|
|
||||||
row_pix[3] = 0xff00ffe0;
|
|
||||||
row_pix[4] = 0xff00ffe0;
|
|
||||||
row_pix[5] = 0xff00ffe0;
|
|
||||||
row_pix[6] = 0xff00ffe0;
|
|
||||||
row_pix[7] = 0xff000000;
|
|
||||||
for (i = 0; i < 4; ++i) {
|
|
||||||
row_buf += stride;
|
|
||||||
row_pix = (uint32_t *)row_buf;
|
|
||||||
row_pix[0] = 0xffff00ff;
|
|
||||||
row_pix[1] = 0xffff00ff;
|
|
||||||
row_pix[2] = 0xff000000;
|
|
||||||
row_pix[3] = 0xff000000;
|
|
||||||
row_pix[4] = 0xff000000;
|
|
||||||
row_pix[5] = 0xffff00ff;
|
|
||||||
row_pix[6] = 0xffff00ff;
|
|
||||||
row_pix[7] = 0xff000000;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
__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);
|
||||||
|
@ -249,21 +70,22 @@ __attribute__((__constructor__)) static textstartup void _vga_init(void) {
|
||||||
unsigned char col, row;
|
unsigned char col, row;
|
||||||
} bios_curs_pos_t;
|
} bios_curs_pos_t;
|
||||||
bios_curs_pos_t pos = *(bios_curs_pos_t *)(BANE + 0x0450ull);
|
bios_curs_pos_t pos = *(bios_curs_pos_t *)(BANE + 0x0450ull);
|
||||||
uint8_t chr_ht = *(uint8_t *)(BANE + 0x0485ull),
|
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);
|
chr_ht_hi = *(uint8_t *)(BANE + 0x0486ull);
|
||||||
if (chr_ht_hi != 0 || chr_ht > 32)
|
if (chr_ht_hi != 0 || chr_ht > 32 || chr_ht < 2)
|
||||||
chr_ht = 32;
|
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. */
|
/* Make sure the video buffer is mapped into virtual memory. */
|
||||||
__invert_memory_area(mm, __get_pml4t(), vid_buf_phy, vid_buf_sz, PAGE_RW);
|
__invert_memory_area(mm, __get_pml4t(), vid_buf_phy, vid_buf_sz, PAGE_RW);
|
||||||
#if 1
|
|
||||||
/* Test video frame buffer output. */
|
|
||||||
_vga_init_test(vid_buf, vid_type, stride);
|
|
||||||
#endif
|
|
||||||
/*
|
/*
|
||||||
* Initialize our tty structure from the current screen geometry,
|
* Initialize our tty structure from the current screen geometry,
|
||||||
* screen contents, cursor position, & character height.
|
* screen contents, cursor position, & character dimensions.
|
||||||
*/
|
*/
|
||||||
_StartTty(&_vga_tty, height, width, pos.row, pos.col, chr_ht,
|
_StartTty(&_vga_tty, vid_type, height, width, stride, pos.row, pos.col,
|
||||||
vid_buf, NULL);
|
chr_ht, chr_wid, vid_buf, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue