mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-08-09 11:20:30 +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_
|
#ifndef COSMOPOLITAN_LIBC_VGA_VGA_INTERNAL_H_
|
||||||
#define 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)
|
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||||
#include "libc/calls/struct/fd.internal.h"
|
#include "libc/calls/struct/fd.internal.h"
|
||||||
#include "libc/calls/struct/iovec.h"
|
#include "libc/calls/struct/iovec.h"
|
||||||
|
@ -8,8 +60,59 @@
|
||||||
|
|
||||||
COSMOPOLITAN_C_START_
|
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);
|
ssize_t sys_writev_vga(struct Fd *, const struct iovec *, int);
|
||||||
|
|
||||||
COSMOPOLITAN_C_END_
|
COSMOPOLITAN_C_END_
|
||||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
#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/runtime/pc.internal.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
|
|
||||||
#define CRTPORT 0x3d4
|
static struct Tty vga_tty;
|
||||||
#define WIDTH 80
|
#ifdef VGA_USE_WCS
|
||||||
|
static wchar_t vga_wcs[VGA_TTY_HEIGHT * VGA_TTY_WIDTH];
|
||||||
typedef struct {
|
#else
|
||||||
char ch;
|
static wchar_t * const vga_wcs = NULL;
|
||||||
uint8_t attr;
|
#endif
|
||||||
} 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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ssize_t sys_writev_vga(struct Fd *fd, const struct iovec *iov, int iovlen) {
|
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, wrote = 0;
|
||||||
size_t i, j, wrote = 0;
|
ssize_t res = 0;
|
||||||
for (i = 0; i < iovlen; ++i) {
|
for (i = 0; i < iovlen; ++i) {
|
||||||
const char *input = (const char *)iov[i].iov_base;
|
void *input = iov[i].iov_base;
|
||||||
for (j = 0; j < iov[i].iov_len; ++j) {
|
size_t len = iov[i].iov_len;
|
||||||
writec_vga(input[j]);
|
res = _TtyWrite(&vga_tty, input, len);
|
||||||
++wrote;
|
if (res < 0)
|
||||||
}
|
break;
|
||||||
|
wrote += res;
|
||||||
|
if (res != len)
|
||||||
|
return wrote;
|
||||||
}
|
}
|
||||||
updatexy_vga();
|
if (!wrote)
|
||||||
|
return res;
|
||||||
return wrote;
|
return wrote;
|
||||||
}
|
}
|
||||||
|
|
||||||
__attribute__((__constructor__)) static textstartup void _vga_init(void) {
|
__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. */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
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);
|
||||||
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