From bae7367774c946f81f8d53b8c3f298dd007b974f Mon Sep 17 00:00:00 2001 From: tkchia Date: Sat, 10 Sep 2022 19:28:28 +0800 Subject: [PATCH] Bare metal VGA: minor improvements (#608) --- libc/vga/tty.c | 159 ++++++++++++++++------------------------ libc/vga/vga.internal.h | 5 +- libc/vga/writev-vga.c | 16 +++- 3 files changed, 79 insertions(+), 101 deletions(-) diff --git a/libc/vga/tty.c b/libc/vga/tty.c index 76d6c7f96..4c3c89099 100644 --- a/libc/vga/tty.c +++ b/libc/vga/tty.c @@ -93,7 +93,7 @@ static wchar_t *Wcs(struct Tty *tty) void _StartTty(struct Tty *tty, unsigned short yn, unsigned short xn, unsigned short starty, unsigned short startx, - void *vccs, wchar_t *wcs) { + unsigned char chr_ht, void *vccs, wchar_t *wcs) { struct VgaTextCharCell *ccs = vccs; memset(tty, 0, sizeof(struct Tty)); SetYn(tty, yn); @@ -103,8 +103,11 @@ void _StartTty(struct Tty *tty, unsigned short yn, unsigned short xn, starty = yn - 1; if (startx >= xn) startx = xn - 1; + if (chr_ht > 32) + chr_ht = 32; tty->y = starty; tty->x = startx; + tty->chr_ht = chr_ht; if (SetWcs(tty, wcs)) { size_t n = (size_t)yn * xn, i; for (i = 0; i < n; ++i) @@ -143,66 +146,27 @@ static wchar_t *GetXlatLineDrawing(void) { return xlat; } -static void XlatAlphabet(wchar_t xlat[128], int a, int b) { - unsigned i; - for (i = 0; i < 128; ++i) { - if ('a' <= i && i <= 'z') { - xlat[i] = i - 'a' + a; - } else if ('A' <= i && i <= 'Z') { - xlat[i] = i - 'A' + b; - } else { - xlat[i] = i; - } - } -} - static wchar_t *GetXlatItalic(void) { - static bool once; - static wchar_t xlat[128]; - if (!once) { - XlatAlphabet(xlat, L'𝑎', L'𝐴'); - once = true; - } - return xlat; + /* Unimplemented. Simply output normal non-italicized characters for now. */ + return GetXlatAscii(); } static wchar_t *GetXlatBoldItalic(void) { - static bool once; - static wchar_t xlat[128]; - if (!once) { - XlatAlphabet(xlat, L'𝒂', L'𝑨'); - once = true; - } - return xlat; + /* + * Unimplemented. Simply output high-intensity non-italicized characters + * for now. + */ + return GetXlatAscii(); } static wchar_t *GetXlatBoldFraktur(void) { - static bool once; - static wchar_t xlat[128]; - if (!once) { - XlatAlphabet(xlat, L'𝖆', L'𝕬'); - once = true; - } - return xlat; + /* Unimplemented. */ + return GetXlatAscii(); } static wchar_t *GetXlatFraktur(void) { - unsigned i; - static bool once; - static wchar_t xlat[128]; - if (!once) { - for (i = 0; i < ARRAYLEN(xlat); ++i) { - if ('A' <= i && i <= 'Z') { - xlat[i] = L"𝔄𝔅ℭ𝔇𝔈𝔉𝔊ℌℑ𝔍𝔎𝔏𝔐𝔑𝔒𝔓𝔔ℜ𝔖𝔗𝔘𝔙𝔚𝔛𝔜ℨ"[i - 'A']; - } else if ('a' <= i && i <= 'z') { - xlat[i] = i - 'a' + L'𝔞'; - } else { - xlat[i] = i; - } - } - once = true; - } - return xlat; + /* Unimplemented. */ + return GetXlatAscii(); } static wchar_t *GetXlatDoubleWidth(void) { @@ -258,15 +222,33 @@ static void TtySetCodepage(struct Tty *tty, char id) { } } +/** + * Map the currently active foreground & background colors & terminal + * configuration to a VGA text character attribute byte. + * + * @see VGA_USE_BLINK macro (libc/vga/vga.internal.h) + * @see drivers/tty/vt/vt.c in Linux 5.9.14 source code + */ static uint8_t TtyGetVgaAttr(struct Tty *tty) { - uint8_t attr = tty->fg | tty->bg << 4; - if ((tty->pr & kTtyBold) != 0) - attr |= 0x08; + uint8_t attr; + if ((tty->pr & kTtyFlip) == 0) + attr = tty->fg | tty->bg << 4; + else + attr = tty->bg | tty->fg << 4; #ifdef VGA_USE_BLINK + /* + * If blinking is enabled, we can only have the 8 dark background color + * codes (0 to 7). Simply map any bright background color (8 to 15) to + * its corresponding dark color, & call it a day. This is a bit more + * simplistic than what Linux does, but should be enough. + */ + attr &= ~0x80; if ((tty->pr & kTtyBlink) != 0) attr |= 0x80; #endif + if ((tty->pr & kTtyBold) != 0) + attr |= 0x08; return attr; } @@ -639,37 +621,23 @@ static void TtyCsiN(struct Tty *tty) { /** * Map the given (R, G, B) triplet to one of the 16 basic foreground colors - * or one of the 8 (or 16) background colors. + * or one of the 16 background colors. * - * @see VGA_USE_BLINK macro (libc/vga/vga.internal.h) * @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, bool as_fg) +static uint8_t TtyMapTrueColor(uint8_t r, uint8_t g, uint8_t b) { - uint8_t hue = 0; -#ifdef VGA_USE_BLINK - if (!as_fg) { - if (r >= 128) - hue |= 4; - if (g >= 128) - hue |= 2; - if (b >= 128) - hue |= 1; - } else -#endif - { - uint8_t 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; - } + 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; } @@ -679,7 +647,7 @@ static uint8_t TtyMapTrueColor(uint8_t r, uint8_t g, uint8_t b, bool as_fg) * * @see drivers/tty/vt/vt.c in Linux 5.9.14 source code */ -static uint8_t TtyMapXtermColor(uint8_t color, bool as_fg) +static uint8_t TtyMapXtermColor(uint8_t color) { uint8_t r, g, b; if (color < 8) { @@ -699,7 +667,7 @@ static uint8_t TtyMapXtermColor(uint8_t color, bool as_fg) r = color * 0x55 / 2; } else r = g = b = (unsigned)color * 10 - 2312; - return TtyMapTrueColor(r, g, b, as_fg); + return TtyMapTrueColor(r, g, b); } static void TtySelectGraphicsRendition(struct Tty *tty) { @@ -822,13 +790,7 @@ static void TtySelectGraphicsRendition(struct Tty *tty) { break; case 100 ... 107: code[0] -= 100 - 40; -#ifndef VGA_USE_BLINK - /* - * If blinking is not enabled in VGA text mode, then we can - * use bright background colors. - */ code[0] += 8; -#endif /* fallthrough */ case 40 ... 47: tty->bg = code[0] - 40; @@ -855,7 +817,7 @@ static void TtySelectGraphicsRendition(struct Tty *tty) { if (++code[3] == 3) { code[3] = 0; t = kSgr; - tty->fg = TtyMapTrueColor(code[0], code[1], code[2], true); + tty->fg = TtyMapTrueColor(code[0], code[1], code[2]); tty->pr |= kTtyFg; tty->pr |= kTtyTrue; } @@ -864,20 +826,20 @@ static void TtySelectGraphicsRendition(struct Tty *tty) { if (++code[3] == 3) { code[3] = 0; t = kSgr; - tty->bg = TtyMapTrueColor(code[0], code[1], code[2], false); + tty->bg = TtyMapTrueColor(code[0], code[1], code[2]); tty->pr |= kTtyBg; tty->pr |= kTtyTrue; } break; case kSgrFgXterm: t = kSgr; - tty->fg = TtyMapXtermColor(code[0], true); + tty->fg = TtyMapXtermColor(code[0]); tty->pr |= kTtyFg; tty->pr &= ~kTtyTrue; break; case kSgrBgXterm: t = kSgr; - tty->bg = TtyMapXtermColor(code[0], false); + tty->bg = TtyMapXtermColor(code[0]); tty->pr |= kTtyBg; tty->pr &= ~kTtyTrue; break; @@ -1081,10 +1043,17 @@ static void TtyEscAppend(struct Tty *tty, char c) { } static void TtyUpdateHwCursor(struct Tty *tty) { + unsigned char start = tty->chr_ht - 2, end = tty->chr_ht - 1; unsigned short pos = tty->y * Xn(tty) + tty->x; - outb(CRTPORT, 0x0e); + if ((tty->conf & kTtyNocursor)) + start |= 1 << 5; + outb(CRTPORT, 0x0A); + outb(CRTPORT + 1, start); + outb(CRTPORT, 0x0B); + outb(CRTPORT + 1, end); + outb(CRTPORT, 0x0E); outb(CRTPORT + 1, (unsigned char)(pos >> 8)); - outb(CRTPORT, 0x0f); + outb(CRTPORT, 0x0F); outb(CRTPORT + 1, (unsigned char)pos); } diff --git a/libc/vga/vga.internal.h b/libc/vga/vga.internal.h index 134303139..fe2b8a921 100644 --- a/libc/vga/vga.internal.h +++ b/libc/vga/vga.internal.h @@ -109,7 +109,7 @@ struct Tty { uint32_t u8; uint32_t n8; uint32_t pr; - uint8_t fg, bg; + uint8_t fg, bg, chr_ht; uint32_t conf; unsigned short savey, savex; struct VgaTextCharCell *ccs; @@ -134,7 +134,8 @@ struct Tty { }; void _StartTty(struct Tty *, unsigned short, unsigned short, - unsigned short, unsigned short, void *, wchar_t *); + unsigned short, unsigned short, unsigned char, + void *, wchar_t *); ssize_t _TtyRead(struct Tty *, void *, size_t); ssize_t _TtyWrite(struct Tty *, const void *, size_t); ssize_t _TtyWriteInput(struct Tty *, const void *, size_t); diff --git a/libc/vga/writev-vga.c b/libc/vga/writev-vga.c index 854596441..6df7f93c8 100644 --- a/libc/vga/writev-vga.c +++ b/libc/vga/writev-vga.c @@ -58,15 +58,23 @@ ssize_t sys_writev_vga(struct Fd *fd, const struct iovec *iov, int iovlen) { __attribute__((__constructor__)) static textstartup void _vga_init(void) { void * const vid_buf = (void *)(BANE + 0xb8000ull); - /* Get the initial cursor position from the BIOS data area. */ + /* + * Get the initial cursor position from the BIOS data area. Also get + * the height (in scan lines) of each character; this is used to set the + * cursor shape. + */ typedef struct { unsigned char col, row; } bios_curs_pos_t; bios_curs_pos_t pos = *(bios_curs_pos_t *)(BANE + 0x0450ull); + uint8_t chr_ht = *(uint8_t *)(BANE + 0x0485ull), + chr_ht_hi = *(uint8_t *)(BANE + 0x0486ull); + if (chr_ht_hi != 0 || chr_ht > 32) + chr_ht = 32; /* - * Initialize our tty structure from the current screen contents & current - * cursor position. + * Initialize our tty structure from the current screen contents, current + * cursor position, & character height. */ _StartTty(&vga_tty, VGA_TTY_HEIGHT, VGA_TTY_WIDTH, pos.row, pos.col, - vid_buf, vga_wcs); + chr_ht, vid_buf, vga_wcs); }