From 20d93904ce6f5e0f3f907e1d787c9caaf72ea53c Mon Sep 17 00:00:00 2001 From: tkchia Date: Thu, 8 Sep 2022 21:58:47 +0000 Subject: [PATCH] Bare metal VGA: enable bright background colors, disable blinking --- libc/vga/tty.c | 31 ++++++++++++++++++++++--------- libc/vga/vga-init.S | 8 ++++++++ libc/vga/vga.internal.h | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 64 insertions(+), 9 deletions(-) diff --git a/libc/vga/tty.c b/libc/vga/tty.c index 68b3190e8..76d6c7f96 100644 --- a/libc/vga/tty.c +++ b/libc/vga/tty.c @@ -263,8 +263,10 @@ static uint8_t TtyGetVgaAttr(struct Tty *tty) uint8_t attr = tty->fg | tty->bg << 4; if ((tty->pr & kTtyBold) != 0) attr |= 0x08; +#ifdef VGA_USE_BLINK if ((tty->pr & kTtyBlink) != 0) attr |= 0x80; +#endif return attr; } @@ -637,14 +639,25 @@ 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 background colors. + * or one of the 8 (or 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) { uint8_t hue = 0; - if (as_fg) { +#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; @@ -656,13 +669,6 @@ static uint8_t TtyMapTrueColor(uint8_t r, uint8_t g, uint8_t b, bool as_fg) hue = 8; else if (max > 0xaa) hue |= 8; - } else { - if (r >= 128) - hue |= 4; - if (g >= 128) - hue |= 2; - if (b >= 128) - hue |= 1; } return hue; } @@ -816,6 +822,13 @@ 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; diff --git a/libc/vga/vga-init.S b/libc/vga/vga-init.S index db00bb7c7..8b4c657cc 100644 --- a/libc/vga/vga-init.S +++ b/libc/vga/vga-init.S @@ -25,6 +25,7 @@ │ OTHER DEALINGS IN THE SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/macros.internal.h" +#include "libc/vga/vga.internal.h" // Code snippet for initializing the VGA video mode for bare metal. // @@ -57,6 +58,13 @@ mov $0x0500,%ax # just make sure we are on display # page 0 2: int $0x10 # otherwise, change the video mode + mov $0x1003,%ax # enable/disable VGA text blinking +#ifdef VGA_USE_BLINK + mov $1,%bx +#else + xor %bx,%bx +#endif + int $0x10 .previous .code64 .section .rodata,"a",@progbits diff --git a/libc/vga/vga.internal.h b/libc/vga/vga.internal.h index 39cf3ff47..134303139 100644 --- a/libc/vga/vga.internal.h +++ b/libc/vga/vga.internal.h @@ -26,6 +26,40 @@ * @see lkml.kernel.org/lkml/204888.1529277815@turing-police.cc.vt.edu/T/ */ #undef VGA_USE_WCS +/** + * The VGA hardware can be configured — via the IBM BIOS, or via port I/O — + * to either support blinking characters, or support the use of bright + * background colors, but not both. There is a hardware setting that + * controls whether the attribute byte for each plotted character is + * interpreted as + * + * foreground────┐ + * foreground intensity──┐ │ + * background┐ │ │ + * blinking│ │ │ + * │┌┴┐│┌┴┐ + * 76543210 + * + * or as + * + * foreground────┐ + * foreground intensity──┐ │ + * background┐ │ │ + * background intensity│ │ │ + * │┌┴┐│┌┴┐ + * 76543210 + * + * (NOTE: QEMU 6.2.0 does not emulate the VGA blinking feature. However, + * VirtualBox 6.1 does.) + * + * If VGA_USE_BLINK is defined, our VGA code will use the former mode, & + * will support blinking characters. If VGA_USE_BLINK is undefined, the + * VGA code will instead implement bright background colors. + * + * @see Ralf Brown's Interrupt List, int 0x10, ax = 0x1003 + * (https://www.delorie.com/djgpp/doc/rbinter/id/22/1.html) + */ +#undef VGA_USE_BLINK #define kTtyFg 0x0001 #define kTtyBg 0x0002