mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-08-08 19:00:27 +00:00
Bare metal VGA: support some VT100 escape sequences & UTF-8
The code is based on a pared-down version of the pty code in tool/build/lib/pty.c. It currently adds about 12 KiB to the size of the final executable (compared to the earlier (simplistic) teletype implementation). Some terminal features, such as kTtyBell & kTtyNocursor, are not yet implemented.
This commit is contained in:
parent
aeacc4239d
commit
d4d24482ce
3 changed files with 1358 additions and 89 deletions
1229
libc/vga/tty.c
Normal file
1229
libc/vga/tty.c
Normal file
File diff suppressed because it is too large
Load diff
|
@ -1,6 +1,58 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_VGA_VGA_INTERNAL_H_
|
||||
#define COSMOPOLITAN_LIBC_VGA_VGA_INTERNAL_H_
|
||||
|
||||
/*
|
||||
* VGA_TTY_HEIGHT, VGA_TTY_WIDTH, & VGA_USE_WCS are configuration knobs
|
||||
* which can potentially be used to tweak the features to be compiled into
|
||||
* our VGA teletypewriter support.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Height of the video screen, in character units. Undefine if the height
|
||||
* may vary at runtime.
|
||||
*/
|
||||
#define VGA_TTY_HEIGHT 25
|
||||
/**
|
||||
* Width of the video screen, in character units. Undefine if the width may
|
||||
* vary at runtime.
|
||||
*/
|
||||
#define VGA_TTY_WIDTH 80
|
||||
/**
|
||||
* If VGA_USE_WCS is defined, the tty code can maintain an array of the
|
||||
* Unicode characters "underlying" the 8-bit (or 9-bit) characters that are
|
||||
* actually displayed on the text screen. This can be used to implement
|
||||
* something similar to Linux's /dev/vcsu* facility.
|
||||
*
|
||||
* @see lkml.kernel.org/lkml/204888.1529277815@turing-police.cc.vt.edu/T/
|
||||
*/
|
||||
#undef VGA_USE_WCS
|
||||
|
||||
#define kTtyFg 0x0001
|
||||
#define kTtyBg 0x0002
|
||||
#define kTtyBold 0x0004
|
||||
#define kTtyFlip 0x0008
|
||||
#define kTtyFaint 0x0010
|
||||
#define kTtyUnder 0x0020
|
||||
#define kTtyDunder 0x0040
|
||||
#define kTtyTrue 0x0080
|
||||
#define kTtyBlink 0x0100
|
||||
#define kTtyItalic 0x0200
|
||||
#define kTtyFraktur 0x0400
|
||||
#define kTtyStrike 0x0800
|
||||
#define kTtyConceal 0x1000
|
||||
|
||||
#define kTtyBell 0x001
|
||||
#define kTtyRedzone 0x002
|
||||
#define kTtyNocursor 0x004
|
||||
#define kTtyBlinkcursor 0x008
|
||||
#define kTtyNocanon 0x010
|
||||
#define kTtyNoecho 0x020
|
||||
#define kTtyNoopost 0x040
|
||||
#define kTtyLed1 0x080
|
||||
#define kTtyLed2 0x100
|
||||
#define kTtyLed3 0x200
|
||||
#define kTtyLed4 0x400
|
||||
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
#include "libc/calls/struct/fd.internal.h"
|
||||
#include "libc/calls/struct/iovec.h"
|
||||
|
@ -8,8 +60,59 @@
|
|||
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
struct VgaTextCharCell {
|
||||
uint8_t ch, attr;
|
||||
};
|
||||
|
||||
struct Tty {
|
||||
unsigned short y, x;
|
||||
#ifndef VGA_TTY_HEIGHT
|
||||
unsigned short yn;
|
||||
#endif
|
||||
#ifndef VGA_TTY_WIDTH
|
||||
unsigned short xn;
|
||||
#endif
|
||||
uint32_t u8;
|
||||
uint32_t n8;
|
||||
uint32_t pr;
|
||||
uint8_t fg, bg;
|
||||
uint32_t conf;
|
||||
unsigned short savey, savex;
|
||||
struct VgaTextCharCell *ccs;
|
||||
#ifdef VGA_USE_WCS
|
||||
wchar_t *wcs;
|
||||
#endif
|
||||
wchar_t *xlat;
|
||||
enum TtyState {
|
||||
kTtyAscii,
|
||||
kTtyUtf8,
|
||||
kTtyEsc,
|
||||
kTtyCsi,
|
||||
} state;
|
||||
struct TtyEsc {
|
||||
unsigned i;
|
||||
char s[64];
|
||||
} esc;
|
||||
struct TtyInput {
|
||||
size_t i;
|
||||
char p[256];
|
||||
} input;
|
||||
};
|
||||
|
||||
void _StartTty(struct Tty *, unsigned short, unsigned short,
|
||||
unsigned short, unsigned short, 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);
|
||||
void _TtyResetOutputMode(struct Tty *);
|
||||
void _TtyFullReset(struct Tty *);
|
||||
void _TtyMemmove(struct Tty *, size_t, size_t, size_t);
|
||||
void _TtyErase(struct Tty *, size_t, size_t);
|
||||
void _TtySetY(struct Tty *, unsigned short);
|
||||
void _TtySetX(struct Tty *, unsigned short);
|
||||
|
||||
ssize_t sys_writev_vga(struct Fd *, const struct iovec *, int);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_VGA_VGA_H_ */
|
||||
#endif /* COSMOPOLITAN_LIBC_VGA_VGA_INTERNAL_H_ */
|
||||
|
|
|
@ -31,105 +31,42 @@
|
|||
#include "libc/runtime/pc.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
#define CRTPORT 0x3d4
|
||||
#define WIDTH 80
|
||||
|
||||
typedef struct {
|
||||
char ch;
|
||||
uint8_t attr;
|
||||
} char_cell_t;
|
||||
|
||||
typedef char_cell_t char_row_t[WIDTH];
|
||||
|
||||
static unsigned short height = 25, curr_row, curr_col;
|
||||
static uint8_t curr_attr = 0x07;
|
||||
|
||||
static void scroll(void) {
|
||||
unsigned j;
|
||||
uint8_t attr = curr_attr;
|
||||
char_row_t * const vid_buf = (char_row_t *)(BANE + 0xb8000ull);
|
||||
memmove(vid_buf, vid_buf + 1, (height - 1) * sizeof(char_row_t));
|
||||
for (j = 0; j < WIDTH; ++j)
|
||||
vid_buf[height - 1][j] = (char_cell_t){ ' ', attr };
|
||||
}
|
||||
|
||||
static void may_scroll(void) {
|
||||
if (curr_col >= WIDTH) {
|
||||
curr_col = 0;
|
||||
scroll();
|
||||
}
|
||||
}
|
||||
|
||||
static void updatexy_vga(void) {
|
||||
unsigned short pos = curr_row * WIDTH + curr_col;
|
||||
outb(CRTPORT, 0x0e);
|
||||
outb(CRTPORT + 1, (unsigned char)(pos >> 8));
|
||||
outb(CRTPORT, 0x0f);
|
||||
outb(CRTPORT + 1, (unsigned char)pos);
|
||||
}
|
||||
|
||||
static void writec_vga(char c) {
|
||||
/* TODO: handle UTF-8 multi-bytes */
|
||||
/* TODO: handle VT102 escape sequences */
|
||||
/* TODO: maybe make BEL (\a) character code emit an alarm of some sort */
|
||||
char_row_t * const vid_buf = (char_row_t *)(BANE + 0xb8000ull);
|
||||
uint8_t attr = curr_attr;
|
||||
unsigned short col;
|
||||
switch (c) {
|
||||
case '\b':
|
||||
if (curr_col) {
|
||||
col = curr_col - 1;
|
||||
vid_buf[curr_row][col] = (char_cell_t){ ' ', attr };
|
||||
curr_col = col;
|
||||
}
|
||||
break;
|
||||
case '\t':
|
||||
col = curr_col;
|
||||
do {
|
||||
vid_buf[curr_row][col] = (char_cell_t){ ' ', attr };
|
||||
++col;
|
||||
} while (col % 8 != 0);
|
||||
curr_col = col;
|
||||
may_scroll();
|
||||
break;
|
||||
case '\r':
|
||||
curr_col = 0;
|
||||
break;
|
||||
case '\n':
|
||||
curr_col = 0;
|
||||
if (curr_row < height - 1)
|
||||
++curr_row;
|
||||
else
|
||||
scroll();
|
||||
break;
|
||||
default:
|
||||
col = curr_col;
|
||||
vid_buf[curr_row][col] = (char_cell_t){ c, attr };
|
||||
curr_col = col + 1;
|
||||
may_scroll();
|
||||
}
|
||||
}
|
||||
static struct Tty vga_tty;
|
||||
#ifdef VGA_USE_WCS
|
||||
static wchar_t vga_wcs[VGA_TTY_HEIGHT * VGA_TTY_WIDTH];
|
||||
#else
|
||||
static wchar_t * const vga_wcs = NULL;
|
||||
#endif
|
||||
|
||||
ssize_t sys_writev_vga(struct Fd *fd, const struct iovec *iov, int iovlen) {
|
||||
char_row_t * const vid_buf = (char_row_t *)(BANE + 0xb8000ull);
|
||||
size_t i, j, wrote = 0;
|
||||
size_t i, wrote = 0;
|
||||
ssize_t res = 0;
|
||||
for (i = 0; i < iovlen; ++i) {
|
||||
const char *input = (const char *)iov[i].iov_base;
|
||||
for (j = 0; j < iov[i].iov_len; ++j) {
|
||||
writec_vga(input[j]);
|
||||
++wrote;
|
||||
}
|
||||
void *input = iov[i].iov_base;
|
||||
size_t len = iov[i].iov_len;
|
||||
res = _TtyWrite(&vga_tty, input, len);
|
||||
if (res < 0)
|
||||
break;
|
||||
wrote += res;
|
||||
if (res != len)
|
||||
return wrote;
|
||||
}
|
||||
updatexy_vga();
|
||||
if (!wrote)
|
||||
return res;
|
||||
return wrote;
|
||||
}
|
||||
|
||||
__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. */
|
||||
typedef struct {
|
||||
unsigned char col, row;
|
||||
} bios_curs_pos_t;
|
||||
bios_curs_pos_t pos = *(bios_curs_pos_t *)(BANE + 0x0450ull);
|
||||
curr_row = pos.row;
|
||||
curr_col = pos.col;
|
||||
/*
|
||||
* Initialize our tty structure from the current screen contents & current
|
||||
* cursor position.
|
||||
*/
|
||||
_StartTty(&vga_tty, VGA_TTY_HEIGHT, VGA_TTY_WIDTH, pos.row, pos.col,
|
||||
vid_buf, vga_wcs);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue