Discussion:
[SeaBIOS] [PATCH 2/6] kbd: make enqueue_key public, add ascii_to_keycode
Gerd Hoffmann
2017-09-08 06:18:24 UTC
Permalink
serial console wants queue key events and needs to map ascii chars to
the keycode, so make enqueue_key public and also exports a helper
function so sercon can use the scan_to_keycode mapping table.

Signed-off-by: Gerd Hoffmann <***@redhat.com>
---
src/util.h | 2 ++
src/kbd.c | 18 +++++++++++++++++-
2 files changed, 19 insertions(+), 1 deletion(-)

diff --git a/src/util.h b/src/util.h
index 8269057fe7..da9059a9bf 100644
--- a/src/util.h
+++ b/src/util.h
@@ -186,6 +186,8 @@ int jpeg_show(struct jpeg_decdata *jpeg, unsigned char *pic, int width
void kbd_init(void);
void handle_15c2(struct bregs *regs);
void process_key(u8 key);
+u8 enqueue_key(u16 keycode);
+u16 ascii_to_keycode(u8 ascii);

// misc.c
extern int HaveRunPost;
diff --git a/src/kbd.c b/src/kbd.c
index 916358eed7..15e5ae789c 100644
--- a/src/kbd.c
+++ b/src/kbd.c
@@ -29,7 +29,7 @@ kbd_init(void)
, x + FIELD_SIZEOF(struct bios_data_area_s, kbd_buf));
}

-static u8
+u8
enqueue_key(u16 keycode)
{
u16 buffer_start = GET_BDA(kbd_buf_start_offset);
@@ -375,6 +375,22 @@ struct scaninfo key_ext_slash VAR16 = {
0xe02f, 0xe02f, 0x9500, 0xa400
};

+u16 ascii_to_keycode(u8 ascii)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(scan_to_keycode); i++) {
+ if ((GET_GLOBAL(scan_to_keycode[i].normal) & 0xff) == ascii)
+ return GET_GLOBAL(scan_to_keycode[i].normal);
+ if ((GET_GLOBAL(scan_to_keycode[i].shift) & 0xff) == ascii)
+ return GET_GLOBAL(scan_to_keycode[i].shift);
+ if ((GET_GLOBAL(scan_to_keycode[i].control) & 0xff) == ascii)
+ return GET_GLOBAL(scan_to_keycode[i].control);
+ }
+ return 0;
+}
+
+// Handle a ps2 style scancode read from the keyboard.
static void
kbd_set_flag(int key_release, u16 set_bit0, u8 set_bit1, u16 toggle_bit)
{
--
2.9.3
Gerd Hoffmann
2017-09-08 06:18:28 UTC
Permalink
Temporary, for testing convinience.
---
src/optionroms.c | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/src/optionroms.c b/src/optionroms.c
index 76a70ea686..7b1bc141eb 100644
--- a/src/optionroms.c
+++ b/src/optionroms.c
@@ -23,7 +23,7 @@
#include "tcgbios.h" // tpm_*

static int EnforceChecksum, S3ResumeVga, RunPCIroms;
-
+static int sgabios;

/****************************************************************
* Helper functions
@@ -193,6 +193,12 @@ run_file_roms(const char *prefix, int isvga, u64 *sources)
file = romfile_findprefix(prefix, file);
if (!file)
break;
+ if (strcmp(file->name, "vgaroms/sgabios.bin") == 0) {
+ dprintf(1, "sgabios.bin found -> ignoring, enabling sercon instead.\n");
+ dprintf(1, "hint: use '-machine graphics=no' instead of '-device sga'.\n");
+ sgabios++;
+ continue;
+ }
struct rom_header *rom = deploy_romfile(file);
if (rom) {
setRomSource(sources, rom, (u32)file);
@@ -434,7 +440,7 @@ vgarom_setup(void)

if (rom_get_last() == BUILD_ROM_START) {
// No VGA rom found
- if (romfile_loadint("etc/sercon-enable", 0)) {
+ if (romfile_loadint("etc/sercon-enable", 0) || sgabios) {
sercon_setup();
enable_vga_console();
}
@@ -442,7 +448,7 @@ vgarom_setup(void)
}

VgaROM = (void*)BUILD_ROM_START;
- if (romfile_loadint("etc/sercon-enable", 0))
+ if (romfile_loadint("etc/sercon-enable", 0) || sgabios)
sercon_setup();
enable_vga_console();
}
--
2.9.3
Gerd Hoffmann
2017-09-08 06:18:25 UTC
Permalink
Will be used as runtime switch to enable serial console support.

Signed-off-by: Gerd Hoffmann <***@redhat.com>
---
src/fw/paravirt.c | 2 ++
1 file changed, 2 insertions(+)

diff --git a/src/fw/paravirt.c b/src/fw/paravirt.c
index 5b23d786be..e9cca4fe6e 100644
--- a/src/fw/paravirt.c
+++ b/src/fw/paravirt.c
@@ -210,6 +210,7 @@ qemu_platform_setup(void)
#define QEMU_CFG_SIGNATURE 0x00
#define QEMU_CFG_ID 0x01
#define QEMU_CFG_UUID 0x02
+#define QEMU_CFG_NOGRAPHIC 0x04
#define QEMU_CFG_NUMA 0x0d
#define QEMU_CFG_BOOT_MENU 0x0e
#define QEMU_CFG_NB_CPUS 0x05
@@ -510,6 +511,7 @@ qemu_cfg_legacy(void)
qemu_romfile_add("etc/show-boot-menu", QEMU_CFG_BOOT_MENU, 0, 2);
qemu_romfile_add("etc/irq0-override", QEMU_CFG_IRQ0_OVERRIDE, 0, 1);
qemu_romfile_add("etc/max-cpus", QEMU_CFG_MAX_CPUS, 0, 2);
+ qemu_romfile_add("etc/sercon-enable", QEMU_CFG_NOGRAPHIC, 0, 2);

// NUMA data
u64 numacount;
--
2.9.3
Kevin O'Connor
2017-09-08 18:32:08 UTC
Permalink
Post by Gerd Hoffmann
Will be used as runtime switch to enable serial console support.
---
src/fw/paravirt.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/fw/paravirt.c b/src/fw/paravirt.c
index 5b23d786be..e9cca4fe6e 100644
--- a/src/fw/paravirt.c
+++ b/src/fw/paravirt.c
@@ -210,6 +210,7 @@ qemu_platform_setup(void)
#define QEMU_CFG_SIGNATURE 0x00
#define QEMU_CFG_ID 0x01
#define QEMU_CFG_UUID 0x02
+#define QEMU_CFG_NOGRAPHIC 0x04
#define QEMU_CFG_NUMA 0x0d
#define QEMU_CFG_BOOT_MENU 0x0e
#define QEMU_CFG_NB_CPUS 0x05
@@ -510,6 +511,7 @@ qemu_cfg_legacy(void)
qemu_romfile_add("etc/show-boot-menu", QEMU_CFG_BOOT_MENU, 0, 2);
qemu_romfile_add("etc/irq0-override", QEMU_CFG_IRQ0_OVERRIDE, 0, 1);
qemu_romfile_add("etc/max-cpus", QEMU_CFG_MAX_CPUS, 0, 2);
+ qemu_romfile_add("etc/sercon-enable", QEMU_CFG_NOGRAPHIC, 0, 2);
Instead of looking at QEMU_CFG_NOGRAPHIC, I think the C code could
check if GET_IVT(0x10).segoff == FUNC16(entry_10).segoff . This has
the advantage of working whenever a vgarom is not installed (including
on coreboot).

-Kevin
Gerd Hoffmann
2017-09-11 10:17:04 UTC
Permalink
Hi,
Post by Kevin O'Connor
+    qemu_romfile_add("etc/sercon-enable", QEMU_CFG_NOGRAPHIC, 0,
2);
Instead of looking at QEMU_CFG_NOGRAPHIC, I think the C code could
check if GET_IVT(0x10).segoff == FUNC16(entry_10).segoff .
It's not that simple. We need some way to explicitly enable it,
especially in case a vgabios *is* present (aka aplitmode). And this is
what we've agreed on a few months back, IIRC because we don't have to
extend fw_cfg that way.

Independent from that we have the question what to do by default in
case no vgabios is present. IIRC by initial patch set did enable
sercon in that case, but I changed it after some discussions.

Don't remember what the reason was though. Cc'ing Daniel + Paolo

cheers,
Gerd
Kevin O'Connor
2017-09-11 14:43:41 UTC
Permalink
Post by Gerd Hoffmann
Hi,
Post by Kevin O'Connor
+    qemu_romfile_add("etc/sercon-enable", QEMU_CFG_NOGRAPHIC, 0,
2);
Instead of looking at QEMU_CFG_NOGRAPHIC, I think the C code could
check if GET_IVT(0x10).segoff == FUNC16(entry_10).segoff .
It's not that simple. We need some way to explicitly enable it,
especially in case a vgabios *is* present (aka aplitmode). And this is
what we've agreed on a few months back, IIRC because we don't have to
extend fw_cfg that way.
Okay.

Separately, how will sercon get the serial port that it is to use?

Looking closer at patch 4 I see:

+ u16 addr = PORT_SERIAL1;
+ SET_LOW(sercon_port, addr);

Is the plan to pull this from a romfile so that it can be set on
coreboot? If so, perhaps that functionality could be merged with
"etc/sercon-enable" so that coreboot users need only set one cbfs
file.
Post by Gerd Hoffmann
Independent from that we have the question what to do by default in
case no vgabios is present. IIRC by initial patch set did enable
sercon in that case, but I changed it after some discussions.
Don't remember what the reason was though. Cc'ing Daniel + Paolo
Okay. It would be nice to have the correct responses to 1000, 1002,
1003, and 100f even if serial output wasn't desired.

-Kevin
Gerd Hoffmann
2017-09-12 06:22:24 UTC
Permalink
Hi,
Post by Kevin O'Connor
Separately, how will sercon get the serial port that it is to use?
+    u16 addr = PORT_SERIAL1;
+    SET_LOW(sercon_port, addr);
Is the plan to pull this from a romfile so that it can be set on
coreboot?  If so, perhaps that functionality could be merged with
"etc/sercon-enable" so that coreboot users need only set one cbfs
file.
No concrete plan yet, other than that I've added a variable for the
port intentionally so runtime configuration can be added easily.

One option would be to have a etc/sercon-ioport file, which will both
enable sercon and specify the io port address.

We could also depend on detect_serial() and lookup the detected io port
address via GET_BDA(port_com[count]).

There is also the question if and how we'll go support non-isa serial
ports. qemu also has pci-serial for example. serial-over-lan virtual
ports typically show up as pci device too.

cheers,
Gerd
Gerd Hoffmann
2017-09-08 06:18:26 UTC
Permalink
Redirect int10 calls to serial console output.
Parse serial input and queue key events.

Signed-off-by: Gerd Hoffmann <***@redhat.com>
---
Makefile | 2 +-
src/util.h | 3 +
src/clock.c | 1 +
src/misc.c | 2 +
src/optionroms.c | 7 +-
src/sercon.c | 604 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/Kconfig | 5 +
7 files changed, 622 insertions(+), 2 deletions(-)
create mode 100644 src/sercon.c

diff --git a/Makefile b/Makefile
index a0158ed443..289ed82ad8 100644
--- a/Makefile
+++ b/Makefile
@@ -29,7 +29,7 @@ LD32BIT_FLAG:=-melf_i386

# Source files
SRCBOTH=misc.c stacks.c output.c string.c block.c cdrom.c disk.c mouse.c kbd.c \
- system.c serial.c clock.c resume.c pnpbios.c vgahooks.c pcibios.c apm.c \
+ system.c serial.c sercon.c clock.c resume.c pnpbios.c vgahooks.c pcibios.c apm.c \
cp437.c \
hw/pci.c hw/timer.c hw/rtc.c hw/dma.c hw/pic.c hw/ps2port.c hw/serialio.c \
hw/usb.c hw/usb-uhci.c hw/usb-ohci.c hw/usb-ehci.c \
diff --git a/src/util.h b/src/util.h
index da9059a9bf..f7ea3ae862 100644
--- a/src/util.h
+++ b/src/util.h
@@ -234,6 +234,9 @@ void code_mutable_preinit(void);
// serial.c
void serial_setup(void);
void lpt_setup(void);
+void sercon_10(struct bregs *regs);
+void sercon_setup(void);
+void sercon_check_event(void);

// version.c
extern const char VERSION[], BUILDINFO[];
diff --git a/src/clock.c b/src/clock.c
index e83e0f3388..e44e112068 100644
--- a/src/clock.c
+++ b/src/clock.c
@@ -295,6 +295,7 @@ clock_update(void)
floppy_tick();
usb_check_event();
ps2_check_event();
+ sercon_check_event();
}

// INT 08h System Timer ISR Entry Point
diff --git a/src/misc.c b/src/misc.c
index f02237c366..f4b656dd35 100644
--- a/src/misc.c
+++ b/src/misc.c
@@ -11,6 +11,7 @@
#include "output.h" // debug_enter
#include "stacks.h" // call16_int
#include "string.h" // memset
+#include "util.h" // serial_10

#define PORT_MATH_CLEAR 0x00f0

@@ -57,6 +58,7 @@ handle_10(struct bregs *regs)
{
debug_enter(regs, DEBUG_HDL_10);
// don't do anything, since the VGA BIOS handles int10h requests
+ sercon_10(regs);
}

// NMI handler
diff --git a/src/optionroms.c b/src/optionroms.c
index 65f7fe0ef4..8665db42e3 100644
--- a/src/optionroms.c
+++ b/src/optionroms.c
@@ -432,9 +432,14 @@ vgarom_setup(void)
run_file_roms("vgaroms/", 1, NULL);
rom_reserve(0);

- if (rom_get_last() == BUILD_ROM_START)
+ if (rom_get_last() == BUILD_ROM_START) {
// No VGA rom found
+ if (romfile_loadint("etc/sercon-enable", 0)) {
+ sercon_setup();
+ enable_vga_console();
+ }
return;
+ }

VgaROM = (void*)BUILD_ROM_START;
enable_vga_console();
diff --git a/src/sercon.c b/src/sercon.c
new file mode 100644
index 0000000000..f785aa8fd9
--- /dev/null
+++ b/src/sercon.c
@@ -0,0 +1,604 @@
+// serial console support
+//
+// Copyright (C) 2016 Gerd Hoffmann <***@redhat.com>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "biosvar.h" // SET_BDA
+#include "bregs.h" // struct bregs
+#include "stacks.h" // yield
+#include "output.h" // dprintf
+#include "util.h" // irqtimer_calc_ticks
+#include "hw/serialio.h" // SEROFF_IER
+#include "cp437.h"
+
+static u8 video_rows(void)
+{
+ return GET_BDA(video_rows)+1;
+}
+
+static u8 video_cols(void)
+{
+ return GET_BDA(video_cols);
+}
+
+static u8 cursor_pos_col(void)
+{
+ u16 pos = GET_BDA(cursor_pos[0]);
+ return pos & 0xff;
+}
+
+static u8 cursor_pos_row(void)
+{
+ u16 pos = GET_BDA(cursor_pos[0]);
+ return (pos >> 8) & 0xff;
+}
+
+static void cursor_pos_set(u8 row, u8 col)
+{
+ u16 pos = ((u16)row << 8) | col;
+ SET_BDA(cursor_pos[0], pos);
+}
+
+/****************************************************************
+ * serial console output
+ ****************************************************************/
+
+VARLOW u16 sercon_port;
+
+/*
+ * We have a small output buffer here, for lazy output. That allows
+ * to avoid a whole bunch of control sequences for pointless cursor
+ * moves, so when logging the output it'll be *alot* less cluttered.
+ *
+ * sercon_char/attr is the actual output buffer.
+ * sercon_attr_last is the most recent attribute sent to the terminal.
+ * sercon_col_last is the most recent column sent to the terminal.
+ * sercon_row_last is the most recent row sent to the terminal.
+ */
+VARLOW u8 sercon_attr_last;
+VARLOW u8 sercon_col_last;
+VARLOW u8 sercon_row_last;
+VARLOW u8 sercon_char;
+VARLOW u8 sercon_attr = 0x07;
+
+static VAR16 u8 sercon_cmap[8] = { '0', '4', '2', '6', '1', '5', '3', '7' };
+
+static void sercon_putchar(u8 chr)
+{
+ u16 addr = GET_LOW(sercon_port);
+ u32 end = irqtimer_calc_ticks(0x0a);
+
+#if 0
+ /* for visual control sequence debugging */
+ if (chr == '\x1b')
+ chr = '*';
+#endif
+
+ for (;;) {
+ u8 lsr = inb(addr+SEROFF_LSR);
+ if ((lsr & 0x60) == 0x60) {
+ // Success - can write data
+ outb(chr, addr+SEROFF_DATA);
+ break;
+ }
+ if (irqtimer_check(end)) {
+ break;
+ }
+ yield();
+ }
+}
+
+static void sercon_term_reset(void)
+{
+ sercon_putchar('\x1b');
+ sercon_putchar('c');
+}
+
+static void sercon_term_clear_screen(void)
+{
+ sercon_putchar('\x1b');
+ sercon_putchar('[');
+ sercon_putchar('2');
+ sercon_putchar('J');
+}
+
+static void sercon_term_no_linewrap(void)
+{
+ sercon_putchar('\x1b');
+ sercon_putchar('[');
+ sercon_putchar('?');
+ sercon_putchar('7');
+ sercon_putchar('l');
+}
+
+static void sercon_term_cursor_goto(u8 row, u8 col)
+{
+ row++; col++;
+ sercon_putchar('\x1b');
+ sercon_putchar('[');
+ sercon_putchar('0' + row / 10);
+ sercon_putchar('0' + row % 10);
+ sercon_putchar(';');
+ sercon_putchar('0' + col / 10);
+ sercon_putchar('0' + col % 10);
+ sercon_putchar('H');
+}
+
+static void sercon_term_set_color(u8 fg, u8 bg, u8 bold)
+{
+ sercon_putchar('\x1b');
+ sercon_putchar('[');
+ sercon_putchar('0');
+ if (fg != 7) {
+ sercon_putchar(';');
+ sercon_putchar('3');
+ sercon_putchar(GET_GLOBAL(sercon_cmap[fg & 7]));
+ }
+ if (bg != 0) {
+ sercon_putchar(';');
+ sercon_putchar('4');
+ sercon_putchar(GET_GLOBAL(sercon_cmap[bg & 7]));
+ }
+ if (bold) {
+ sercon_putchar(';');
+ sercon_putchar('1');
+ }
+ sercon_putchar('m');
+}
+
+static void sercon_set_attr(u8 attr)
+{
+ if (attr == GET_LOW(sercon_attr_last))
+ return;
+
+ SET_LOW(sercon_attr_last, attr);
+ sercon_term_set_color((attr >> 0) & 7,
+ (attr >> 4) & 7,
+ attr & 0x08);
+}
+
+static void sercon_print_utf8(u8 chr)
+{
+ u16 unicode = cp437_to_unicode(chr);
+
+ if (unicode < 0x7f) {
+ sercon_putchar(unicode);
+ } else if (unicode < 0x7ff) {
+ sercon_putchar(0xc0 | ((unicode >> 6) & 0x1f));
+ sercon_putchar(0x80 | ((unicode >> 0) & 0x3f));
+ } else {
+ sercon_putchar(0xe0 | ((unicode >> 12) & 0x0f));
+ sercon_putchar(0x80 | ((unicode >> 6) & 0x3f));
+ sercon_putchar(0x80 | ((unicode >> 0) & 0x3f));
+ }
+}
+
+static void sercon_lazy_cursor_sync(void)
+{
+ u8 row = cursor_pos_row();
+ u8 col = cursor_pos_col();
+
+ if (GET_LOW(sercon_row_last) == row &&
+ GET_LOW(sercon_col_last) == col)
+ return;
+
+ if (col == 0 && GET_LOW(sercon_row_last) <= row) {
+ if (GET_LOW(sercon_col_last) != 0) {
+ sercon_putchar('\r');
+ SET_LOW(sercon_col_last, 0);
+ }
+ while (GET_LOW(sercon_row_last) < row) {
+ sercon_putchar('\n');
+ SET_LOW(sercon_row_last, GET_LOW(sercon_row_last)+1);
+ }
+ if (GET_LOW(sercon_row_last) == row &&
+ GET_LOW(sercon_col_last) == col)
+ return;
+ }
+
+ sercon_term_cursor_goto(row, col);
+ SET_LOW(sercon_row_last, row);
+ SET_LOW(sercon_col_last, col);
+}
+
+static void sercon_lazy_flush(void)
+{
+ u8 chr, attr;
+
+ chr = GET_LOW(sercon_char);
+ attr = GET_LOW(sercon_attr);
+ if (chr) {
+ sercon_set_attr(attr);
+ sercon_print_utf8(chr);
+ SET_LOW(sercon_col_last, GET_LOW(sercon_col_last) + 1);
+ }
+
+ sercon_lazy_cursor_sync();
+
+ SET_LOW(sercon_attr, 0x07);
+ SET_LOW(sercon_char, 0x00);
+}
+
+static void sercon_lazy_cursor_update(u8 row, u8 col)
+{
+ cursor_pos_set(row, col);
+ SET_LOW(sercon_row_last, row);
+ SET_LOW(sercon_col_last, col);
+}
+
+static void sercon_lazy_backspace(void)
+{
+ u8 col;
+
+ sercon_lazy_flush();
+ col = cursor_pos_col();
+ if (col > 0) {
+ sercon_putchar(8);
+ sercon_lazy_cursor_update(cursor_pos_row(), col-1);
+ }
+}
+
+static void sercon_lazy_cr(void)
+{
+ cursor_pos_set(cursor_pos_row(), 0);
+}
+
+static void sercon_lazy_lf(void)
+{
+ u8 row;
+
+ row = cursor_pos_row() + 1;
+ if (row >= video_rows()) {
+ /* scrolling up */
+ row = video_rows()-1;
+ if (GET_LOW(sercon_row_last) > 0) {
+ SET_LOW(sercon_row_last, GET_LOW(sercon_row_last) - 1);
+ }
+ }
+ cursor_pos_set(row, cursor_pos_col());
+}
+
+static void sercon_lazy_move_cursor(void)
+{
+ u8 col;
+
+ col = cursor_pos_col() + 1;
+ if (col >= video_cols()) {
+ sercon_lazy_cr();
+ sercon_lazy_lf();
+ } else {
+ cursor_pos_set(cursor_pos_row(), col);
+ }
+}
+
+static void sercon_lazy_putchar(u8 chr, u8 attr, u8 teletype)
+{
+ if (cursor_pos_row() != GET_LOW(sercon_row_last) ||
+ cursor_pos_col() != GET_LOW(sercon_col_last)) {
+ sercon_lazy_flush();
+ }
+
+ SET_LOW(sercon_char, chr);
+ if (teletype)
+ sercon_lazy_move_cursor();
+ else
+ SET_LOW(sercon_attr, attr);
+}
+
+/* Set video mode */
+static void sercon_1000(struct bregs *regs)
+{
+ u8 clearscreen = !(regs->al & 0x80);
+ u8 mode = regs->al & 0x7f;
+ u8 rows, cols;
+
+ switch (mode) {
+ case 0x03:
+ default:
+ cols = 80;
+ rows = 25;
+ regs->al = 0x30;
+ }
+ SET_LOW(sercon_col_last, 0);
+ SET_LOW(sercon_row_last, 0);
+ SET_LOW(sercon_attr_last, 0);
+
+ cursor_pos_set(0, 0);
+ SET_BDA(video_mode, mode);
+ SET_BDA(video_cols, cols);
+ SET_BDA(video_rows, rows-1);
+ SET_BDA(cursor_type, 0x0007);
+
+ sercon_term_reset();
+ sercon_term_no_linewrap();
+ if (clearscreen)
+ sercon_term_clear_screen();
+}
+
+/* Set text-mode cursor shape */
+static void sercon_1001(struct bregs *regs)
+{
+ /* show/hide cursor? */
+ SET_BDA(cursor_type, regs->cx);
+}
+
+/* Set cursor position */
+static void sercon_1002(struct bregs *regs)
+{
+ u8 row = regs->dh;
+ u8 col = regs->dl;
+
+ cursor_pos_set(row, col);
+}
+
+/* Get cursor position */
+static void sercon_1003(struct bregs *regs)
+{
+ regs->cx = GET_BDA(cursor_type);
+ regs->dh = cursor_pos_row();
+ regs->dl = cursor_pos_col();
+}
+
+/* Scroll up window */
+static void sercon_1006(struct bregs *regs)
+{
+ sercon_lazy_flush();
+ if (regs->al == 0) {
+ /* clear rect, do only in case this looks like a fullscreen clear */
+ if (regs->ch == 0 &&
+ regs->cl == 0 &&
+ regs->dh == video_rows()-1 &&
+ regs->dl == video_cols()-1) {
+ sercon_set_attr(regs->bh);
+ sercon_term_clear_screen();
+ }
+ } else {
+ sercon_putchar('\r');
+ sercon_putchar('\n');
+ }
+}
+
+/* Read character and attribute at cursor position */
+static void sercon_1008(struct bregs *regs)
+{
+ regs->ah = 0x07;
+ regs->bh = ' ';
+}
+
+/* Write character and attribute at cursor position */
+static void sercon_1009(struct bregs *regs)
+{
+ u16 count = regs->cx;
+
+ if (count == 1) {
+ sercon_lazy_putchar(regs->al, regs->bl, 0);
+
+ } else if (regs->al == 0x20 &&
+ video_rows() * video_cols() == count &&
+ cursor_pos_row() == 0 &&
+ cursor_pos_col() == 0) {
+ /* override everything with spaces -> this is clear screen */
+ sercon_lazy_flush();
+ sercon_set_attr(regs->bl);
+ sercon_term_clear_screen();
+
+ } else {
+ sercon_lazy_flush();
+ sercon_set_attr(regs->bl);
+ while (count) {
+ sercon_print_utf8(regs->al);
+ count--;
+ }
+ sercon_term_cursor_goto(cursor_pos_row(),
+ cursor_pos_col());
+ }
+}
+
+/* Teletype output */
+static void sercon_100e(struct bregs *regs)
+{
+ switch (regs->al) {
+ case 7:
+ sercon_putchar(0x07);
+ break;
+ case 8:
+ sercon_lazy_backspace();
+ break;
+ case '\r':
+ sercon_lazy_cr();
+ break;
+ case '\n':
+ sercon_lazy_lf();
+ break;
+ default:
+ sercon_lazy_putchar(regs->al, 0, 1);
+ break;
+ }
+}
+
+/* Get current video mode */
+static void sercon_100f(struct bregs *regs)
+{
+ regs->al = GET_BDA(video_mode);
+ regs->ah = GET_BDA(video_cols);
+}
+
+/* VBE 2.0 */
+static void sercon_104f(struct bregs *regs)
+{
+ regs->ax = 0x0100;
+}
+
+static void sercon_10XX(struct bregs *regs)
+{
+ warn_unimplemented(regs);
+}
+
+void VISIBLE16
+sercon_10(struct bregs *regs)
+{
+ if (!CONFIG_SERCON)
+ return;
+ if (!GET_LOW(sercon_port))
+ return;
+
+ switch (regs->ah) {
+ case 0x00: sercon_1000(regs); break;
+ case 0x01: sercon_1001(regs); break;
+ case 0x02: sercon_1002(regs); break;
+ case 0x03: sercon_1003(regs); break;
+ case 0x06: sercon_1006(regs); break;
+ case 0x08: sercon_1008(regs); break;
+ case 0x09: sercon_1009(regs); break;
+ case 0x0e: sercon_100e(regs); break;
+ case 0x0f: sercon_100f(regs); break;
+ case 0x4f: sercon_104f(regs); break;
+ default: sercon_10XX(regs); break;
+ }
+}
+
+void sercon_setup(void)
+{
+ if (!CONFIG_SERCON)
+ return;
+
+ struct segoff_s seabios, vgabios;
+ u16 addr = PORT_SERIAL1;
+
+ SET_LOW(sercon_port, addr);
+ outb(0x03, addr + SEROFF_LCR); // 8N1
+ outb(0x01, addr + 0x02); // enable fifo
+}
+
+/****************************************************************
+ * serial input
+ ****************************************************************/
+
+VARLOW u8 rx_buf[16];
+VARLOW u8 rx_bytes;
+
+static VAR16 struct {
+ char seq[4];
+ u8 len;
+ u16 keycode;
+} termseq[] = {
+ { .seq = "OP", .len = 2, .keycode = 0x3b00 }, // F1
+ { .seq = "OQ", .len = 2, .keycode = 0x3c00 }, // F2
+ { .seq = "OR", .len = 2, .keycode = 0x3d00 }, // F3
+ { .seq = "OS", .len = 2, .keycode = 0x3e00 }, // F4
+
+ { .seq = "[15~", .len = 4, .keycode = 0x3f00 }, // F5
+ { .seq = "[17~", .len = 4, .keycode = 0x4000 }, // F6
+ { .seq = "[18~", .len = 4, .keycode = 0x4100 }, // F7
+ { .seq = "[19~", .len = 4, .keycode = 0x4200 }, // F8
+ { .seq = "[20~", .len = 4, .keycode = 0x4300 }, // F9
+ { .seq = "[21~", .len = 4, .keycode = 0x4400 }, // F10
+ { .seq = "[23~", .len = 4, .keycode = 0x5700 }, // F11
+ { .seq = "[24~", .len = 4, .keycode = 0x5800 }, // F12
+
+ { .seq = "[2~", .len = 3, .keycode = 0x52e0 }, // insert
+ { .seq = "[3~", .len = 3, .keycode = 0x53e0 }, // delete
+ { .seq = "[5~", .len = 3, .keycode = 0x49e0 }, // page up
+ { .seq = "[6~", .len = 3, .keycode = 0x51e0 }, // page down
+
+ { .seq = "[A", .len = 2, .keycode = 0x48e0 }, // up
+ { .seq = "[B", .len = 2, .keycode = 0x50e0 }, // down
+ { .seq = "[C", .len = 2, .keycode = 0x4de0 }, // right
+ { .seq = "[D", .len = 2, .keycode = 0x4be0 }, // left
+
+ { .seq = "[H", .len = 2, .keycode = 0x47e0 }, // home
+ { .seq = "[F", .len = 2, .keycode = 0x4fe0 }, // end
+};
+
+static void shiftbuf(int remove)
+{
+ int i, remaining;
+
+ remaining = GET_LOW(rx_bytes) - remove;
+ SET_LOW(rx_bytes, remaining);
+ for (i = 0; i < remaining; i++)
+ SET_LOW(rx_buf[i], GET_LOW(rx_buf[i + remove]));
+}
+
+static int cmpbuf(int seq)
+{
+ int chr, len;
+
+ len = GET_GLOBAL(termseq[seq].len);
+ if (GET_LOW(rx_bytes) < len + 1)
+ return 0;
+ for (chr = 0; chr < len; chr++)
+ if (GET_GLOBAL(termseq[seq].seq[chr]) != GET_LOW(rx_buf[chr + 1]))
+ return 0;
+ return 1;
+}
+
+static int findseq(void)
+{
+ int seq;
+
+ for (seq = 0; seq < ARRAY_SIZE(termseq); seq++)
+ if (cmpbuf(seq))
+ return seq;
+ return -1;
+}
+
+void
+sercon_check_event(void)
+{
+ if (!CONFIG_SERCON)
+ return;
+
+ u16 addr = GET_LOW(sercon_port);
+ u16 keycode;
+ u8 byte, count = 0;
+ int seq, chr;
+
+ // check to see if there is a active serial port
+ if (!addr)
+ return;
+ if (inb(addr + SEROFF_LSR) == 0xFF)
+ return;
+
+ // flush pending output
+ sercon_lazy_flush();
+
+ // read all available data
+ while (inb(addr + SEROFF_LSR) & 0x01) {
+ byte = inb(addr + SEROFF_DATA);
+ if (GET_LOW(rx_bytes) < sizeof(rx_buf)) {
+ SET_LOW(rx_buf[rx_bytes], byte);
+ SET_LOW(rx_bytes, GET_LOW(rx_bytes) + 1);
+ count++;
+ }
+ }
+
+ for (;;) {
+ // no (more) input data
+ if (!GET_LOW(rx_bytes))
+ return;
+
+ // lookup escape sequences
+ if (GET_LOW(rx_bytes) > 1 && GET_LOW(rx_buf[0]) == 0x1b) {
+ seq = findseq();
+ if (seq >= 0) {
+ enqueue_key(GET_GLOBAL(termseq[seq].keycode));
+ shiftbuf(GET_GLOBAL(termseq[seq].len) + 1);
+ continue;
+ }
+ }
+
+ // Seems we got a escape sequence we didn't recognise.
+ // -> If we received data wait for more, maybe it is just incomplete.
+ if (GET_LOW(rx_buf[0]) == 0x1b && count)
+ return;
+
+ // Handle input as individual char.
+ chr = GET_LOW(rx_buf[0]);
+ keycode = ascii_to_keycode(chr);
+ if (keycode)
+ enqueue_key(keycode);
+ shiftbuf(1);
+ }
+}
diff --git a/src/Kconfig b/src/Kconfig
index 77ec9c7a91..55a87cb7f0 100644
--- a/src/Kconfig
+++ b/src/Kconfig
@@ -306,6 +306,11 @@ menu "Hardware support"
default y
help
Support serial ports. This also enables int 14 serial port calls.
+ config SERCON
+ bool "Serial console"
+ default y
+ help
+ Support redirecting vga output to the serial console.
config LPT
bool "Parallel port"
default y
--
2.9.3
Kevin O'Connor
2017-09-08 18:44:23 UTC
Permalink
Post by Gerd Hoffmann
Redirect int10 calls to serial console output.
Parse serial input and queue key events.
[...]
Post by Gerd Hoffmann
--- a/src/misc.c
+++ b/src/misc.c
@@ -11,6 +11,7 @@
#include "output.h" // debug_enter
#include "stacks.h" // call16_int
#include "string.h" // memset
+#include "util.h" // serial_10
#define PORT_MATH_CLEAR 0x00f0
@@ -57,6 +58,7 @@ handle_10(struct bregs *regs)
{
debug_enter(regs, DEBUG_HDL_10);
// don't do anything, since the VGA BIOS handles int10h requests
+ sercon_10(regs);
}
I don't think we should have two entry points into the C code for
vgabios calls given how fragile the vgabios entry point is (due to
broken emulation on various OSes). Indeed, I'd be more inclined to
remove handle_10() entirely - see patch below as example.

Instead of having two entry points (primary mode and split mode),
perhaps just have a split mode entry point. When sercon is in primary
mode, point the chain'ed handler to an iretw instruction. One could
use FUNC16(entry_iret_official), or just keep it at FUNC16(entry_10)
with the patch below.

-Kevin


romlayout: Don't enter C code on 0x10 video interrupt

The handle_10() code doesn't currently do anything and there is a risk
that entering the C code to run it could cause problems with operating
systems that attempt to emulate vgabios calls. Change the entry_10
code to immediately invoke an iretw instead.

Signed-off-by: Kevin O'Connor <***@koconnor.net>

diff --git a/src/config.h b/src/config.h
index baca029..93c8dbc 100644
--- a/src/config.h
+++ b/src/config.h
@@ -76,7 +76,6 @@
#define DEBUG_ISR_08 20
#define DEBUG_ISR_09 9
#define DEBUG_ISR_0e 9
-#define DEBUG_HDL_10 20
#define DEBUG_HDL_11 2
#define DEBUG_HDL_12 2
#define DEBUG_HDL_13 10
diff --git a/src/misc.c b/src/misc.c
index f02237c..b511730 100644
--- a/src/misc.c
+++ b/src/misc.c
@@ -51,14 +51,6 @@ handle_05(struct bregs *regs)
debug_enter(regs, DEBUG_HDL_05);
}

-// INT 10h Video Support Service Entry Point
-void VISIBLE16
-handle_10(struct bregs *regs)
-{
- debug_enter(regs, DEBUG_HDL_10);
- // don't do anything, since the VGA BIOS handles int10h requests
-}
-
// NMI handler
void VISIBLE16
handle_02(void)
diff --git a/src/romlayout.S b/src/romlayout.S
index 89b3784..7529e60 100644
--- a/src/romlayout.S
+++ b/src/romlayout.S
@@ -597,7 +597,8 @@ entry_10_0x0f:
iretw

ORG 0xf065
- IRQ_ENTRY_ARG 10
+entry_10:
+ iretw

// 0xf0a4 - VideoParams in misc.c
Gerd Hoffmann
2017-09-08 06:18:27 UTC
Permalink
Allows to run the serial console in parallel with a vga display.
Output will show up on both vga and serial line.
Input will be accepted from both keyboard and serial line.

Signed-off-by: Gerd Hoffmann <***@redhat.com>
---
src/optionroms.c | 2 ++
src/sercon.c | 106 ++++++++++++++++++++++++++++++++++++++++++++-----------
src/romlayout.S | 46 ++++++++++++++++++++++++
3 files changed, 133 insertions(+), 21 deletions(-)

diff --git a/src/optionroms.c b/src/optionroms.c
index 8665db42e3..76a70ea686 100644
--- a/src/optionroms.c
+++ b/src/optionroms.c
@@ -442,6 +442,8 @@ vgarom_setup(void)
}

VgaROM = (void*)BUILD_ROM_START;
+ if (romfile_loadint("etc/sercon-enable", 0))
+ sercon_setup();
enable_vga_console();
}

diff --git a/src/sercon.c b/src/sercon.c
index f785aa8fd9..5699905f32 100644
--- a/src/sercon.c
+++ b/src/sercon.c
@@ -9,6 +9,7 @@
#include "stacks.h" // yield
#include "output.h" // dprintf
#include "util.h" // irqtimer_calc_ticks
+#include "string.h" // memcpy
#include "hw/serialio.h" // SEROFF_IER
#include "cp437.h"

@@ -45,6 +46,9 @@ static void cursor_pos_set(u8 row, u8 col)
****************************************************************/

VARLOW u16 sercon_port;
+VARLOW u8 sercon_split;
+VARLOW u8 sercon_enable;
+VARFSEG struct segoff_s sercon_real_vga_handler;

/*
* We have a small output buffer here, for lazy output. That allows
@@ -64,6 +68,11 @@ VARLOW u8 sercon_attr = 0x07;

static VAR16 u8 sercon_cmap[8] = { '0', '4', '2', '6', '1', '5', '3', '7' };

+static int sercon_splitmode(void)
+{
+ return GET_LOW(sercon_split);
+}
+
static void sercon_putchar(u8 chr)
{
u16 addr = GET_LOW(sercon_port);
@@ -174,6 +183,15 @@ static void sercon_print_utf8(u8 chr)
}
}

+static void sercon_cursor_pos_set(u8 row, u8 col)
+{
+ if (!sercon_splitmode()) {
+ cursor_pos_set(row, col);
+ } else {
+ /* let vgabios update cursor */
+ }
+}
+
static void sercon_lazy_cursor_sync(void)
{
u8 row = cursor_pos_row();
@@ -222,7 +240,7 @@ static void sercon_lazy_flush(void)

static void sercon_lazy_cursor_update(u8 row, u8 col)
{
- cursor_pos_set(row, col);
+ sercon_cursor_pos_set(row, col);
SET_LOW(sercon_row_last, row);
SET_LOW(sercon_col_last, col);
}
@@ -241,7 +259,7 @@ static void sercon_lazy_backspace(void)

static void sercon_lazy_cr(void)
{
- cursor_pos_set(cursor_pos_row(), 0);
+ sercon_cursor_pos_set(cursor_pos_row(), 0);
}

static void sercon_lazy_lf(void)
@@ -256,7 +274,7 @@ static void sercon_lazy_lf(void)
SET_LOW(sercon_row_last, GET_LOW(sercon_row_last) - 1);
}
}
- cursor_pos_set(row, cursor_pos_col());
+ sercon_cursor_pos_set(row, cursor_pos_col());
}

static void sercon_lazy_move_cursor(void)
@@ -268,7 +286,7 @@ static void sercon_lazy_move_cursor(void)
sercon_lazy_cr();
sercon_lazy_lf();
} else {
- cursor_pos_set(cursor_pos_row(), col);
+ sercon_cursor_pos_set(cursor_pos_row(), col);
}
}

@@ -293,23 +311,28 @@ static void sercon_1000(struct bregs *regs)
u8 mode = regs->al & 0x7f;
u8 rows, cols;

- switch (mode) {
- case 0x03:
- default:
- cols = 80;
- rows = 25;
- regs->al = 0x30;
+ if (!sercon_splitmode()) {
+ switch (mode) {
+ case 0x03:
+ default:
+ cols = 80;
+ rows = 25;
+ regs->al = 0x30;
+ }
+ cursor_pos_set(0, 0);
+ SET_BDA(video_mode, mode);
+ SET_BDA(video_cols, cols);
+ SET_BDA(video_rows, rows-1);
+ SET_BDA(cursor_type, 0x0007);
+ } else {
+ SET_LOW(sercon_enable, (mode == 0x03));
+ /* let vgabios handle mode init */
}
+
SET_LOW(sercon_col_last, 0);
SET_LOW(sercon_row_last, 0);
SET_LOW(sercon_attr_last, 0);

- cursor_pos_set(0, 0);
- SET_BDA(video_mode, mode);
- SET_BDA(video_cols, cols);
- SET_BDA(video_rows, rows-1);
- SET_BDA(cursor_type, 0x0007);
-
sercon_term_reset();
sercon_term_no_linewrap();
if (clearscreen)
@@ -326,10 +349,7 @@ static void sercon_1001(struct bregs *regs)
/* Set cursor position */
static void sercon_1002(struct bregs *regs)
{
- u8 row = regs->dh;
- u8 col = regs->dl;
-
- cursor_pos_set(row, col);
+ sercon_cursor_pos_set(regs->dh, regs->dl);
}

/* Get cursor position */
@@ -427,7 +447,13 @@ static void sercon_100f(struct bregs *regs)
/* VBE 2.0 */
static void sercon_104f(struct bregs *regs)
{
- regs->ax = 0x0100;
+ if (!sercon_splitmode()) {
+ regs->ax = 0x0100;
+ } else {
+ // Disable sercon entry point on any vesa modeset
+ if (regs->al == 0x00)
+ SET_LOW(sercon_enable, 0);
+ }
}

static void sercon_10XX(struct bregs *regs)
@@ -458,6 +484,31 @@ sercon_10(struct bregs *regs)
}
}

+void VISIBLE16
+sercon_10_splitmode(struct bregs *regs)
+{
+ if (!CONFIG_SERCON)
+ return;
+ if (!GET_LOW(sercon_port))
+ return;
+
+ switch (regs->ah) {
+ case 0x01:
+ case 0x02:
+ case 0x03:
+ case 0x08:
+ case 0x0f:
+ /* nothing, vgabios did all work */
+ break;
+ case 0x00: sercon_1000(regs); break;
+ case 0x06: sercon_1006(regs); break;
+ case 0x09: sercon_1009(regs); break;
+ case 0x0e: sercon_100e(regs); break;
+ case 0x4f: sercon_104f(regs); break;
+ default: sercon_10XX(regs); break;
+ }
+}
+
void sercon_setup(void)
{
if (!CONFIG_SERCON)
@@ -466,6 +517,19 @@ void sercon_setup(void)
struct segoff_s seabios, vgabios;
u16 addr = PORT_SERIAL1;

+ vgabios = GET_IVT(0x10);
+ seabios = FUNC16(entry_10);
+ if (vgabios.seg != seabios.seg ||
+ vgabios.offset != seabios.offset) {
+ dprintf(1, "%s:%d: using splitmode (vgabios %04x:%04x, hook %04x:%04x)\n",
+ __func__, __LINE__,
+ vgabios.seg, vgabios.offset,
+ seabios.seg, seabios.offset);
+ sercon_real_vga_handler = vgabios;
+ SET_IVT(0x10, FUNC16(entry_sercon));
+ SET_LOW(sercon_split, 1);
+ }
+
SET_LOW(sercon_port, addr);
outb(0x03, addr + SEROFF_LCR); // 8N1
outb(0x01, addr + 0x02); // enable fifo
diff --git a/src/romlayout.S b/src/romlayout.S
index 89b3784d60..1c9d56df1b 100644
--- a/src/romlayout.S
+++ b/src/romlayout.S
@@ -414,6 +414,52 @@ __csm_return:
popfw
lretw

+// Serial console "hooked vga" entry point
+ DECLFUNC entry_sercon
+entry_sercon:
+ // Setup for chain loading to real vga handler
+ pushfw
+ pushl %cs:sercon_real_vga_handler
+
+ // Set %ds to varlow segment
+ cli
+ cld
+ pushw %ds
+ pushl %eax
+ movl $_zonelow_seg, %eax
+ movl %eax, %ds
+
+ // Test if the sercon handler can be called
+ movl %esp, %eax // Test for broken x86emu
+ pushl $1f
+ retl
+1: cmpl %esp, %eax
+ jne 4f
+ cmpb $0, sercon_enable // Test that sercon is enabled
+ je 3f
+
+2: popl %eax
+ popw %ds
+ pushl $sercon_10_splitmode
+#if CONFIG_ENTRY_EXTRASTACK
+ jmp irqentry_arg_extrastack
+#else
+ jmp irqentry_arg
+#endif
+
+ // sercon disabled - verify not 0x03 modeset and otherwise exit
+3: popl %eax
+ cmpw $0x0003, %ax
+ jne 5f
+ pushl %eax
+ jmp 2b
+
+ // Running on broken x86emu - restore stack and exit
+4: movl %eax, %esp
+ popl %eax
+5: popw %ds
+ iretw
+

/****************************************************************
* Interrupt entry points
--
2.9.3
Kevin O'Connor
2017-09-08 18:53:48 UTC
Permalink
Post by Gerd Hoffmann
Allows to run the serial console in parallel with a vga display.
Output will show up on both vga and serial line.
Input will be accepted from both keyboard and serial line.
[...]
Post by Gerd Hoffmann
+ SET_LOW(sercon_enable, (mode == 0x03));
[...]
Post by Gerd Hoffmann
+ // sercon disabled - verify not 0x03 modeset and otherwise exit
+3: popl %eax
+ cmpw $0x0003, %ax
+ jne 5f
Minor note - I realized after I sent my last patch that doing:

SET_LOW(sercon_enable, (mode <= 0x07));

and:

cmpw $0x0007, %ax
jg 5f

Is more flexible and still safe.

-Kevin
Gerd Hoffmann
2017-09-11 10:33:24 UTC
Permalink
Post by Gerd Hoffmann
Allows to run the serial console in parallel with a vga display.
Output will show up on both vga and serial line.
Input will be accepted from both keyboard and serial line.
[...]
Post by Gerd Hoffmann
+        SET_LOW(sercon_enable, (mode == 0x03));
[...]
Post by Gerd Hoffmann
+        // sercon disabled - verify not 0x03 modeset and otherwise
exit
+3:      popl %eax
+        cmpw $0x0003, %ax
+        jne 5f
    SET_LOW(sercon_enable, (mode <= 0x07));
I don't think so. 0,1,2,3,7 are text modes, but 4,5,6 not.

cheers,
Gerd
Kevin O'Connor
2017-09-11 14:48:02 UTC
Permalink
Post by Gerd Hoffmann
Post by Gerd Hoffmann
Allows to run the serial console in parallel with a vga display.
Output will show up on both vga and serial line.
Input will be accepted from both keyboard and serial line.
[...]
Post by Gerd Hoffmann
+        SET_LOW(sercon_enable, (mode == 0x03));
[...]
Post by Gerd Hoffmann
+        // sercon disabled - verify not 0x03 modeset and otherwise
exit
+3:      popl %eax
+        cmpw $0x0003, %ax
+        jne 5f
    SET_LOW(sercon_enable, (mode <= 0x07));
I don't think so. 0,1,2,3,7 are text modes, but 4,5,6 not.
It's safe to enter the C code on 4,5,6 though. Also, I don't think it
was unusual to write text while in cga mode. (CGA support isn't a
priority though.)

-Kevin
Gerd Hoffmann
2017-09-12 06:25:44 UTC
Permalink
Hi,
    SET_LOW(sercon_enable, (mode <= 0x07));
I don't think so.  0,1,2,3,7 are text modes, but 4,5,6 not.
It's safe to enter the C code on 4,5,6 though.  Also, I don't think
it
was unusual to write text while in cga mode.  (CGA support isn't a
priority though.)
Oh. So the char write int10h calls work in cga mode too?

cheers,
Gerd
Kevin O'Connor
2017-09-12 15:16:10 UTC
Permalink
Post by Gerd Hoffmann
Hi,
    SET_LOW(sercon_enable, (mode <= 0x07));
I don't think so.  0,1,2,3,7 are text modes, but 4,5,6 not.
It's safe to enter the C code on 4,5,6 though.  Also, I don't think
it
was unusual to write text while in cga mode.  (CGA support isn't a
priority though.)
Oh. So the char write int10h calls work in cga mode too?
Yes.

On SeaVGABIOS, text writing now works in all graphic modes, though not
all vgabios support that. The original bochs vgabios didn't support
it in "direct" or "packed" modes, and I think it was broken for years
in planar mode. So, it's rare for text writing to be seen in any mode
above 7. (It's also rare for anything to go into cga mode today, but
for ancient programs, it would not have been unusual to write out text
in cga mode.)

-Kevin
Gerd Hoffmann
2017-09-13 12:41:19 UTC
Permalink
Post by Kevin O'Connor
On SeaVGABIOS, text writing now works in all graphic modes, though not
all vgabios support that.  The original bochs vgabios didn't support
it in "direct" or "packed" modes, and I think it was broken for years
in planar mode.  So, it's rare for text writing to be seen in any
mode
above 7.  (It's also rare for anything to go into cga mode today, but
for ancient programs, it would not have been unusual to write out text
in cga mode.)
Ah, ok. Didn't know that. So it actually makes sense to support all
modes <= 7 in sercon. 4+5 are 320x200, which should be 40x25 chars,
and 6 is 640x200 and therefore 80x25 chars (both using 8x8 font). I'll
go add 4+5+6 and simplify the mode number checks.

cheers,
Gerd

Gerd Hoffmann
2017-09-08 06:18:23 UTC
Permalink
Signed-off-by: Gerd Hoffmann <***@redhat.com>
---
Makefile | 1 +
src/cp437.h | 1 +
src/cp437.c | 275 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 277 insertions(+)
create mode 100644 src/cp437.h
create mode 100644 src/cp437.c

diff --git a/Makefile b/Makefile
index 946df7eab6..a0158ed443 100644
--- a/Makefile
+++ b/Makefile
@@ -30,6 +30,7 @@ LD32BIT_FLAG:=-melf_i386
# Source files
SRCBOTH=misc.c stacks.c output.c string.c block.c cdrom.c disk.c mouse.c kbd.c \
system.c serial.c clock.c resume.c pnpbios.c vgahooks.c pcibios.c apm.c \
+ cp437.c \
hw/pci.c hw/timer.c hw/rtc.c hw/dma.c hw/pic.c hw/ps2port.c hw/serialio.c \
hw/usb.c hw/usb-uhci.c hw/usb-ohci.c hw/usb-ehci.c \
hw/usb-hid.c hw/usb-msc.c hw/usb-uas.c \
diff --git a/src/cp437.h b/src/cp437.h
new file mode 100644
index 0000000000..7bd1ef152b
--- /dev/null
+++ b/src/cp437.h
@@ -0,0 +1 @@
+u16 cp437_to_unicode(u8 cp437);
diff --git a/src/cp437.c b/src/cp437.c
new file mode 100644
index 0000000000..7305e20737
--- /dev/null
+++ b/src/cp437.c
@@ -0,0 +1,275 @@
+/*
+ * code page 437 to unicode map
+ */
+
+#include "types.h"
+#include "biosvar.h"
+#include "cp437.h"
+
+static VAR16 u16 cp437_to_unicode_map[256] = {
+
+ /* https://en.wikipedia.org/wiki/Code_page_437 */
+ [ 0x00 ] = 0x0000,
+ [ 0x01 ] = 0x263A,
+ [ 0x02 ] = 0x263B,
+ [ 0x03 ] = 0x2665,
+ [ 0x04 ] = 0x2666,
+ [ 0x05 ] = 0x2663,
+ [ 0x06 ] = 0x2660,
+ [ 0x07 ] = 0x2022,
+ [ 0x08 ] = 0x25D8,
+ [ 0x09 ] = 0x25CB,
+ [ 0x0a ] = 0x25D9,
+ [ 0x0b ] = 0x2642,
+ [ 0x0c ] = 0x2640,
+ [ 0x0d ] = 0x266A,
+ [ 0x0e ] = 0x266B,
+ [ 0x0f ] = 0x263C,
+ [ 0x10 ] = 0x25BA,
+ [ 0x11 ] = 0x25C4,
+ [ 0x12 ] = 0x2195,
+ [ 0x13 ] = 0x203C,
+ [ 0x14 ] = 0x00B6,
+ [ 0x15 ] = 0x00A7,
+ [ 0x16 ] = 0x25AC,
+ [ 0x17 ] = 0x21A8,
+ [ 0x18 ] = 0x2191,
+ [ 0x19 ] = 0x2193,
+ [ 0x1a ] = 0x2192,
+ [ 0x1b ] = 0x2190,
+ [ 0x1c ] = 0x221F,
+ [ 0x1d ] = 0x2194,
+ [ 0x1e ] = 0x25B2,
+ [ 0x1f ] = 0x25BC,
+ [ 0x7f ] = 0x2302,
+
+ /* http://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/PC/CP437.TXT */
+ [ 0x20 ] = 0x0020, // SPACE
+ [ 0x21 ] = 0x0021, // EXCLAMATION MARK
+ [ 0x22 ] = 0x0022, // QUOTATION MARK
+ [ 0x23 ] = 0x0023, // NUMBER SIGN
+ [ 0x24 ] = 0x0024, // DOLLAR SIGN
+ [ 0x25 ] = 0x0025, // PERCENT SIGN
+ [ 0x26 ] = 0x0026, // AMPERSAND
+ [ 0x27 ] = 0x0027, // APOSTROPHE
+ [ 0x28 ] = 0x0028, // LEFT PARENTHESIS
+ [ 0x29 ] = 0x0029, // RIGHT PARENTHESIS
+ [ 0x2a ] = 0x002a, // ASTERISK
+ [ 0x2b ] = 0x002b, // PLUS SIGN
+ [ 0x2c ] = 0x002c, // COMMA
+ [ 0x2d ] = 0x002d, // HYPHEN-MINUS
+ [ 0x2e ] = 0x002e, // FULL STOP
+ [ 0x2f ] = 0x002f, // SOLIDUS
+ [ 0x30 ] = 0x0030, // DIGIT ZERO
+ [ 0x31 ] = 0x0031, // DIGIT ONE
+ [ 0x32 ] = 0x0032, // DIGIT TWO
+ [ 0x33 ] = 0x0033, // DIGIT THREE
+ [ 0x34 ] = 0x0034, // DIGIT FOUR
+ [ 0x35 ] = 0x0035, // DIGIT FIVE
+ [ 0x36 ] = 0x0036, // DIGIT SIX
+ [ 0x37 ] = 0x0037, // DIGIT SEVEN
+ [ 0x38 ] = 0x0038, // DIGIT EIGHT
+ [ 0x39 ] = 0x0039, // DIGIT NINE
+ [ 0x3a ] = 0x003a, // COLON
+ [ 0x3b ] = 0x003b, // SEMICOLON
+ [ 0x3c ] = 0x003c, // LESS-THAN SIGN
+ [ 0x3d ] = 0x003d, // EQUALS SIGN
+ [ 0x3e ] = 0x003e, // GREATER-THAN SIGN
+ [ 0x3f ] = 0x003f, // QUESTION MARK
+ [ 0x40 ] = 0x0040, // COMMERCIAL AT
+ [ 0x41 ] = 0x0041, // LATIN CAPITAL LETTER A
+ [ 0x42 ] = 0x0042, // LATIN CAPITAL LETTER B
+ [ 0x43 ] = 0x0043, // LATIN CAPITAL LETTER C
+ [ 0x44 ] = 0x0044, // LATIN CAPITAL LETTER D
+ [ 0x45 ] = 0x0045, // LATIN CAPITAL LETTER E
+ [ 0x46 ] = 0x0046, // LATIN CAPITAL LETTER F
+ [ 0x47 ] = 0x0047, // LATIN CAPITAL LETTER G
+ [ 0x48 ] = 0x0048, // LATIN CAPITAL LETTER H
+ [ 0x49 ] = 0x0049, // LATIN CAPITAL LETTER I
+ [ 0x4a ] = 0x004a, // LATIN CAPITAL LETTER J
+ [ 0x4b ] = 0x004b, // LATIN CAPITAL LETTER K
+ [ 0x4c ] = 0x004c, // LATIN CAPITAL LETTER L
+ [ 0x4d ] = 0x004d, // LATIN CAPITAL LETTER M
+ [ 0x4e ] = 0x004e, // LATIN CAPITAL LETTER N
+ [ 0x4f ] = 0x004f, // LATIN CAPITAL LETTER O
+ [ 0x50 ] = 0x0050, // LATIN CAPITAL LETTER P
+ [ 0x51 ] = 0x0051, // LATIN CAPITAL LETTER Q
+ [ 0x52 ] = 0x0052, // LATIN CAPITAL LETTER R
+ [ 0x53 ] = 0x0053, // LATIN CAPITAL LETTER S
+ [ 0x54 ] = 0x0054, // LATIN CAPITAL LETTER T
+ [ 0x55 ] = 0x0055, // LATIN CAPITAL LETTER U
+ [ 0x56 ] = 0x0056, // LATIN CAPITAL LETTER V
+ [ 0x57 ] = 0x0057, // LATIN CAPITAL LETTER W
+ [ 0x58 ] = 0x0058, // LATIN CAPITAL LETTER X
+ [ 0x59 ] = 0x0059, // LATIN CAPITAL LETTER Y
+ [ 0x5a ] = 0x005a, // LATIN CAPITAL LETTER Z
+ [ 0x5b ] = 0x005b, // LEFT SQUARE BRACKET
+ [ 0x5c ] = 0x005c, // REVERSE SOLIDUS
+ [ 0x5d ] = 0x005d, // RIGHT SQUARE BRACKET
+ [ 0x5e ] = 0x005e, // CIRCUMFLEX ACCENT
+ [ 0x5f ] = 0x005f, // LOW LINE
+ [ 0x60 ] = 0x0060, // GRAVE ACCENT
+ [ 0x61 ] = 0x0061, // LATIN SMALL LETTER A
+ [ 0x62 ] = 0x0062, // LATIN SMALL LETTER B
+ [ 0x63 ] = 0x0063, // LATIN SMALL LETTER C
+ [ 0x64 ] = 0x0064, // LATIN SMALL LETTER D
+ [ 0x65 ] = 0x0065, // LATIN SMALL LETTER E
+ [ 0x66 ] = 0x0066, // LATIN SMALL LETTER F
+ [ 0x67 ] = 0x0067, // LATIN SMALL LETTER G
+ [ 0x68 ] = 0x0068, // LATIN SMALL LETTER H
+ [ 0x69 ] = 0x0069, // LATIN SMALL LETTER I
+ [ 0x6a ] = 0x006a, // LATIN SMALL LETTER J
+ [ 0x6b ] = 0x006b, // LATIN SMALL LETTER K
+ [ 0x6c ] = 0x006c, // LATIN SMALL LETTER L
+ [ 0x6d ] = 0x006d, // LATIN SMALL LETTER M
+ [ 0x6e ] = 0x006e, // LATIN SMALL LETTER N
+ [ 0x6f ] = 0x006f, // LATIN SMALL LETTER O
+ [ 0x70 ] = 0x0070, // LATIN SMALL LETTER P
+ [ 0x71 ] = 0x0071, // LATIN SMALL LETTER Q
+ [ 0x72 ] = 0x0072, // LATIN SMALL LETTER R
+ [ 0x73 ] = 0x0073, // LATIN SMALL LETTER S
+ [ 0x74 ] = 0x0074, // LATIN SMALL LETTER T
+ [ 0x75 ] = 0x0075, // LATIN SMALL LETTER U
+ [ 0x76 ] = 0x0076, // LATIN SMALL LETTER V
+ [ 0x77 ] = 0x0077, // LATIN SMALL LETTER W
+ [ 0x78 ] = 0x0078, // LATIN SMALL LETTER X
+ [ 0x79 ] = 0x0079, // LATIN SMALL LETTER Y
+ [ 0x7a ] = 0x007a, // LATIN SMALL LETTER Z
+ [ 0x7b ] = 0x007b, // LEFT CURLY BRACKET
+ [ 0x7c ] = 0x007c, // VERTICAL LINE
+ [ 0x7d ] = 0x007d, // RIGHT CURLY BRACKET
+ [ 0x7e ] = 0x007e, // TILDE
+ [ 0x80 ] = 0x00c7, // LATIN CAPITAL LETTER C WITH CEDILLA
+ [ 0x81 ] = 0x00fc, // LATIN SMALL LETTER U WITH DIAERESIS
+ [ 0x82 ] = 0x00e9, // LATIN SMALL LETTER E WITH ACUTE
+ [ 0x83 ] = 0x00e2, // LATIN SMALL LETTER A WITH CIRCUMFLEX
+ [ 0x84 ] = 0x00e4, // LATIN SMALL LETTER A WITH DIAERESIS
+ [ 0x85 ] = 0x00e0, // LATIN SMALL LETTER A WITH GRAVE
+ [ 0x86 ] = 0x00e5, // LATIN SMALL LETTER A WITH RING ABOVE
+ [ 0x87 ] = 0x00e7, // LATIN SMALL LETTER C WITH CEDILLA
+ [ 0x88 ] = 0x00ea, // LATIN SMALL LETTER E WITH CIRCUMFLEX
+ [ 0x89 ] = 0x00eb, // LATIN SMALL LETTER E WITH DIAERESIS
+ [ 0x8a ] = 0x00e8, // LATIN SMALL LETTER E WITH GRAVE
+ [ 0x8b ] = 0x00ef, // LATIN SMALL LETTER I WITH DIAERESIS
+ [ 0x8c ] = 0x00ee, // LATIN SMALL LETTER I WITH CIRCUMFLEX
+ [ 0x8d ] = 0x00ec, // LATIN SMALL LETTER I WITH GRAVE
+ [ 0x8e ] = 0x00c4, // LATIN CAPITAL LETTER A WITH DIAERESIS
+ [ 0x8f ] = 0x00c5, // LATIN CAPITAL LETTER A WITH RING ABOVE
+ [ 0x90 ] = 0x00c9, // LATIN CAPITAL LETTER E WITH ACUTE
+ [ 0x91 ] = 0x00e6, // LATIN SMALL LIGATURE AE
+ [ 0x92 ] = 0x00c6, // LATIN CAPITAL LIGATURE AE
+ [ 0x93 ] = 0x00f4, // LATIN SMALL LETTER O WITH CIRCUMFLEX
+ [ 0x94 ] = 0x00f6, // LATIN SMALL LETTER O WITH DIAERESIS
+ [ 0x95 ] = 0x00f2, // LATIN SMALL LETTER O WITH GRAVE
+ [ 0x96 ] = 0x00fb, // LATIN SMALL LETTER U WITH CIRCUMFLEX
+ [ 0x97 ] = 0x00f9, // LATIN SMALL LETTER U WITH GRAVE
+ [ 0x98 ] = 0x00ff, // LATIN SMALL LETTER Y WITH DIAERESIS
+ [ 0x99 ] = 0x00d6, // LATIN CAPITAL LETTER O WITH DIAERESIS
+ [ 0x9a ] = 0x00dc, // LATIN CAPITAL LETTER U WITH DIAERESIS
+ [ 0x9b ] = 0x00a2, // CENT SIGN
+ [ 0x9c ] = 0x00a3, // POUND SIGN
+ [ 0x9d ] = 0x00a5, // YEN SIGN
+ [ 0x9e ] = 0x20a7, // PESETA SIGN
+ [ 0x9f ] = 0x0192, // LATIN SMALL LETTER F WITH HOOK
+ [ 0xa0 ] = 0x00e1, // LATIN SMALL LETTER A WITH ACUTE
+ [ 0xa1 ] = 0x00ed, // LATIN SMALL LETTER I WITH ACUTE
+ [ 0xa2 ] = 0x00f3, // LATIN SMALL LETTER O WITH ACUTE
+ [ 0xa3 ] = 0x00fa, // LATIN SMALL LETTER U WITH ACUTE
+ [ 0xa4 ] = 0x00f1, // LATIN SMALL LETTER N WITH TILDE
+ [ 0xa5 ] = 0x00d1, // LATIN CAPITAL LETTER N WITH TILDE
+ [ 0xa6 ] = 0x00aa, // FEMININE ORDINAL INDICATOR
+ [ 0xa7 ] = 0x00ba, // MASCULINE ORDINAL INDICATOR
+ [ 0xa8 ] = 0x00bf, // INVERTED QUESTION MARK
+ [ 0xa9 ] = 0x2310, // REVERSED NOT SIGN
+ [ 0xaa ] = 0x00ac, // NOT SIGN
+ [ 0xab ] = 0x00bd, // VULGAR FRACTION ONE HALF
+ [ 0xac ] = 0x00bc, // VULGAR FRACTION ONE QUARTER
+ [ 0xad ] = 0x00a1, // INVERTED EXCLAMATION MARK
+ [ 0xae ] = 0x00ab, // LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
+ [ 0xaf ] = 0x00bb, // RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
+ [ 0xb0 ] = 0x2591, // LIGHT SHADE
+ [ 0xb1 ] = 0x2592, // MEDIUM SHADE
+ [ 0xb2 ] = 0x2593, // DARK SHADE
+ [ 0xb3 ] = 0x2502, // BOX DRAWINGS LIGHT VERTICAL
+ [ 0xb4 ] = 0x2524, // BOX DRAWINGS LIGHT VERTICAL AND LEFT
+ [ 0xb5 ] = 0x2561, // BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE
+ [ 0xb6 ] = 0x2562, // BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE
+ [ 0xb7 ] = 0x2556, // BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE
+ [ 0xb8 ] = 0x2555, // BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE
+ [ 0xb9 ] = 0x2563, // BOX DRAWINGS DOUBLE VERTICAL AND LEFT
+ [ 0xba ] = 0x2551, // BOX DRAWINGS DOUBLE VERTICAL
+ [ 0xbb ] = 0x2557, // BOX DRAWINGS DOUBLE DOWN AND LEFT
+ [ 0xbc ] = 0x255d, // BOX DRAWINGS DOUBLE UP AND LEFT
+ [ 0xbd ] = 0x255c, // BOX DRAWINGS UP DOUBLE AND LEFT SINGLE
+ [ 0xbe ] = 0x255b, // BOX DRAWINGS UP SINGLE AND LEFT DOUBLE
+ [ 0xbf ] = 0x2510, // BOX DRAWINGS LIGHT DOWN AND LEFT
+ [ 0xc0 ] = 0x2514, // BOX DRAWINGS LIGHT UP AND RIGHT
+ [ 0xc1 ] = 0x2534, // BOX DRAWINGS LIGHT UP AND HORIZONTAL
+ [ 0xc2 ] = 0x252c, // BOX DRAWINGS LIGHT DOWN AND HORIZONTAL
+ [ 0xc3 ] = 0x251c, // BOX DRAWINGS LIGHT VERTICAL AND RIGHT
+ [ 0xc4 ] = 0x2500, // BOX DRAWINGS LIGHT HORIZONTAL
+ [ 0xc5 ] = 0x253c, // BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL
+ [ 0xc6 ] = 0x255e, // BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE
+ [ 0xc7 ] = 0x255f, // BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE
+ [ 0xc8 ] = 0x255a, // BOX DRAWINGS DOUBLE UP AND RIGHT
+ [ 0xc9 ] = 0x2554, // BOX DRAWINGS DOUBLE DOWN AND RIGHT
+ [ 0xca ] = 0x2569, // BOX DRAWINGS DOUBLE UP AND HORIZONTAL
+ [ 0xcb ] = 0x2566, // BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL
+ [ 0xcc ] = 0x2560, // BOX DRAWINGS DOUBLE VERTICAL AND RIGHT
+ [ 0xcd ] = 0x2550, // BOX DRAWINGS DOUBLE HORIZONTAL
+ [ 0xce ] = 0x256c, // BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL
+ [ 0xcf ] = 0x2567, // BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE
+ [ 0xd0 ] = 0x2568, // BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE
+ [ 0xd1 ] = 0x2564, // BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE
+ [ 0xd2 ] = 0x2565, // BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE
+ [ 0xd3 ] = 0x2559, // BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE
+ [ 0xd4 ] = 0x2558, // BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE
+ [ 0xd5 ] = 0x2552, // BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE
+ [ 0xd6 ] = 0x2553, // BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE
+ [ 0xd7 ] = 0x256b, // BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE
+ [ 0xd8 ] = 0x256a, // BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE
+ [ 0xd9 ] = 0x2518, // BOX DRAWINGS LIGHT UP AND LEFT
+ [ 0xda ] = 0x250c, // BOX DRAWINGS LIGHT DOWN AND RIGHT
+ [ 0xdb ] = 0x2588, // FULL BLOCK
+ [ 0xdc ] = 0x2584, // LOWER HALF BLOCK
+ [ 0xdd ] = 0x258c, // LEFT HALF BLOCK
+ [ 0xde ] = 0x2590, // RIGHT HALF BLOCK
+ [ 0xdf ] = 0x2580, // UPPER HALF BLOCK
+ [ 0xe0 ] = 0x03b1, // GREEK SMALL LETTER ALPHA
+ [ 0xe1 ] = 0x00df, // LATIN SMALL LETTER SHARP S
+ [ 0xe2 ] = 0x0393, // GREEK CAPITAL LETTER GAMMA
+ [ 0xe3 ] = 0x03c0, // GREEK SMALL LETTER PI
+ [ 0xe4 ] = 0x03a3, // GREEK CAPITAL LETTER SIGMA
+ [ 0xe5 ] = 0x03c3, // GREEK SMALL LETTER SIGMA
+ [ 0xe6 ] = 0x00b5, // MICRO SIGN
+ [ 0xe7 ] = 0x03c4, // GREEK SMALL LETTER TAU
+ [ 0xe8 ] = 0x03a6, // GREEK CAPITAL LETTER PHI
+ [ 0xe9 ] = 0x0398, // GREEK CAPITAL LETTER THETA
+ [ 0xea ] = 0x03a9, // GREEK CAPITAL LETTER OMEGA
+ [ 0xeb ] = 0x03b4, // GREEK SMALL LETTER DELTA
+ [ 0xec ] = 0x221e, // INFINITY
+ [ 0xed ] = 0x03c6, // GREEK SMALL LETTER PHI
+ [ 0xee ] = 0x03b5, // GREEK SMALL LETTER EPSILON
+ [ 0xef ] = 0x2229, // INTERSECTION
+ [ 0xf0 ] = 0x2261, // IDENTICAL TO
+ [ 0xf1 ] = 0x00b1, // PLUS-MINUS SIGN
+ [ 0xf2 ] = 0x2265, // GREATER-THAN OR EQUAL TO
+ [ 0xf3 ] = 0x2264, // LESS-THAN OR EQUAL TO
+ [ 0xf4 ] = 0x2320, // TOP HALF INTEGRAL
+ [ 0xf5 ] = 0x2321, // BOTTOM HALF INTEGRAL
+ [ 0xf6 ] = 0x00f7, // DIVISION SIGN
+ [ 0xf7 ] = 0x2248, // ALMOST EQUAL TO
+ [ 0xf8 ] = 0x00b0, // DEGREE SIGN
+ [ 0xf9 ] = 0x2219, // BULLET OPERATOR
+ [ 0xfa ] = 0x00b7, // MIDDLE DOT
+ [ 0xfb ] = 0x221a, // SQUARE ROOT
+ [ 0xfc ] = 0x207f, // SUPERSCRIPT LATIN SMALL LETTER N
+ [ 0xfd ] = 0x00b2, // SUPERSCRIPT TWO
+ [ 0xfe ] = 0x25a0, // BLACK SQUARE
+ [ 0xff ] = 0x00a0, // NO-BREAK SPACE
+};
+
+u16 cp437_to_unicode(u8 cp437)
+{
+ return GET_GLOBAL(cp437_to_unicode_map[cp437]);
+}
--
2.9.3
Gerd Hoffmann
2017-09-11 11:18:15 UTC
Permalink
---
src/config.h | 1 -
src/misc.c | 9 ---------
src/sercon.c | 49 ++++++++++++++++++-------------------------------
src/romlayout.S | 5 +++--
4 files changed, 21 insertions(+), 43 deletions(-)

diff --git a/src/config.h b/src/config.h
index baca029f0e..93c8dbc2d5 100644
--- a/src/config.h
+++ b/src/config.h
@@ -76,7 +76,6 @@
#define DEBUG_ISR_08 20
#define DEBUG_ISR_09 9
#define DEBUG_ISR_0e 9
-#define DEBUG_HDL_10 20
#define DEBUG_HDL_11 2
#define DEBUG_HDL_12 2
#define DEBUG_HDL_13 10
diff --git a/src/misc.c b/src/misc.c
index f4b656dd35..387a3482c9 100644
--- a/src/misc.c
+++ b/src/misc.c
@@ -52,15 +52,6 @@ handle_05(struct bregs *regs)
debug_enter(regs, DEBUG_HDL_05);
}

-// INT 10h Video Support Service Entry Point
-void VISIBLE16
-handle_10(struct bregs *regs)
-{
- debug_enter(regs, DEBUG_HDL_10);
- // don't do anything, since the VGA BIOS handles int10h requests
- sercon_10(regs);
-}
-
// NMI handler
void VISIBLE16
handle_02(void)
diff --git a/src/sercon.c b/src/sercon.c
index 5699905f32..9c49a2fc4c 100644
--- a/src/sercon.c
+++ b/src/sercon.c
@@ -325,10 +325,10 @@ static void sercon_1000(struct bregs *regs)
SET_BDA(video_rows, rows-1);
SET_BDA(cursor_type, 0x0007);
} else {
- SET_LOW(sercon_enable, (mode == 0x03));
/* let vgabios handle mode init */
}

+ SET_LOW(sercon_enable, (mode == 0x03));
SET_LOW(sercon_col_last, 0);
SET_LOW(sercon_row_last, 0);
SET_LOW(sercon_attr_last, 0);
@@ -470,40 +470,26 @@ sercon_10(struct bregs *regs)
return;

switch (regs->ah) {
- case 0x00: sercon_1000(regs); break;
- case 0x01: sercon_1001(regs); break;
- case 0x02: sercon_1002(regs); break;
- case 0x03: sercon_1003(regs); break;
- case 0x06: sercon_1006(regs); break;
- case 0x08: sercon_1008(regs); break;
- case 0x09: sercon_1009(regs); break;
- case 0x0e: sercon_100e(regs); break;
- case 0x0f: sercon_100f(regs); break;
- case 0x4f: sercon_104f(regs); break;
- default: sercon_10XX(regs); break;
- }
-}
-
-void VISIBLE16
-sercon_10_splitmode(struct bregs *regs)
-{
- if (!CONFIG_SERCON)
- return;
- if (!GET_LOW(sercon_port))
- return;
-
- switch (regs->ah) {
case 0x01:
case 0x02:
case 0x03:
case 0x08:
case 0x0f:
- /* nothing, vgabios did all work */
- break;
+ if (sercon_splitmode())
+ /* nothing, vgabios handles it */
+ return;
+ }
+
+ switch (regs->ah) {
case 0x00: sercon_1000(regs); break;
+ case 0x01: sercon_1001(regs); break;
+ case 0x02: sercon_1002(regs); break;
+ case 0x03: sercon_1003(regs); break;
case 0x06: sercon_1006(regs); break;
+ case 0x08: sercon_1008(regs); break;
case 0x09: sercon_1009(regs); break;
case 0x0e: sercon_100e(regs); break;
+ case 0x0f: sercon_100f(regs); break;
case 0x4f: sercon_104f(regs); break;
default: sercon_10XX(regs); break;
}
@@ -521,15 +507,16 @@ void sercon_setup(void)
seabios = FUNC16(entry_10);
if (vgabios.seg != seabios.seg ||
vgabios.offset != seabios.offset) {
- dprintf(1, "%s:%d: using splitmode (vgabios %04x:%04x, hook %04x:%04x)\n",
- __func__, __LINE__,
- vgabios.seg, vgabios.offset,
- seabios.seg, seabios.offset);
+ dprintf(1, "sercon: configuring in splitmode (vgabios %04x:%04x)\n",
+ vgabios.seg, vgabios.offset);
sercon_real_vga_handler = vgabios;
- SET_IVT(0x10, FUNC16(entry_sercon));
SET_LOW(sercon_split, 1);
+ } else {
+ dprintf(1, "sercon: configuring as primary display\n");
+ sercon_real_vga_handler = seabios;
}

+ SET_IVT(0x10, FUNC16(entry_sercon));
SET_LOW(sercon_port, addr);
outb(0x03, addr + SEROFF_LCR); // 8N1
outb(0x01, addr + 0x02); // enable fifo
diff --git a/src/romlayout.S b/src/romlayout.S
index 1c9d56df1b..911a416d7f 100644
--- a/src/romlayout.S
+++ b/src/romlayout.S
@@ -440,7 +440,7 @@ entry_sercon:

2: popl %eax
popw %ds
- pushl $sercon_10_splitmode
+ pushl $sercon_10
#if CONFIG_ENTRY_EXTRASTACK
jmp irqentry_arg_extrastack
#else
@@ -643,7 +643,8 @@ entry_10_0x0f:
iretw

ORG 0xf065
- IRQ_ENTRY_ARG 10
+entry_10:
+ iretw

// 0xf0a4 - VideoParams in misc.c
--
2.9.3
Gerd Hoffmann
2017-09-11 11:18:16 UTC
Permalink
---
src/sercon.c | 11 ++++++++++-
src/romlayout.S | 12 +++++++-----
2 files changed, 17 insertions(+), 6 deletions(-)

diff --git a/src/sercon.c b/src/sercon.c
index 9c49a2fc4c..7d38afb816 100644
--- a/src/sercon.c
+++ b/src/sercon.c
@@ -313,11 +313,20 @@ static void sercon_1000(struct bregs *regs)

if (!sercon_splitmode()) {
switch (mode) {
+ case 0x00:
+ case 0x01:
+ cols = 40;
+ rows = 25;
+ regs->al = 0x30;
+ break;
+ case 0x02:
case 0x03:
+ case 0x07:
default:
cols = 80;
rows = 25;
regs->al = 0x30;
+ break;
}
cursor_pos_set(0, 0);
SET_BDA(video_mode, mode);
@@ -328,7 +337,7 @@ static void sercon_1000(struct bregs *regs)
/* let vgabios handle mode init */
}

- SET_LOW(sercon_enable, (mode == 0x03));
+ SET_LOW(sercon_enable, (mode <= 0x03) || (mode == 0x07));
SET_LOW(sercon_col_last, 0);
SET_LOW(sercon_row_last, 0);
SET_LOW(sercon_attr_last, 0);
diff --git a/src/romlayout.S b/src/romlayout.S
index 911a416d7f..2ef857103e 100644
--- a/src/romlayout.S
+++ b/src/romlayout.S
@@ -434,7 +434,7 @@ entry_sercon:
pushl $1f
retl
1: cmpl %esp, %eax
- jne 4f
+ jne 5f
cmpb $0, sercon_enable // Test that sercon is enabled
je 3f

@@ -449,15 +449,17 @@ entry_sercon:

// sercon disabled - verify not 0x03 modeset and otherwise exit
3: popl %eax
+ cmpw $0x0007, %ax
+ je 4f
cmpw $0x0003, %ax
- jne 5f
- pushl %eax
+ jg 6f
+4: pushl %eax
jmp 2b

// Running on broken x86emu - restore stack and exit
-4: movl %eax, %esp
+5: movl %eax, %esp
popl %eax
-5: popw %ds
+6: popw %ds
iretw
--
2.9.3
Kevin O'Connor
2017-09-11 15:05:19 UTC
Permalink
On Mon, Sep 11, 2017 at 01:18:16PM +0200, Gerd Hoffmann wrote:
[...]
Post by Gerd Hoffmann
--- a/src/romlayout.S
+++ b/src/romlayout.S
pushl $1f
retl
1: cmpl %esp, %eax
- jne 4f
+ jne 5f
cmpb $0, sercon_enable // Test that sercon is enabled
je 3f
// sercon disabled - verify not 0x03 modeset and otherwise exit
3: popl %eax
+ cmpw $0x0007, %ax
+ je 4f
cmpw $0x0003, %ax
- jne 5f
- pushl %eax
+ jg 6f
+4: pushl %eax
jmp 2b
// Running on broken x86emu - restore stack and exit
-4: movl %eax, %esp
+5: movl %eax, %esp
popl %eax
-5: popw %ds
+6: popw %ds
iretw
The asm could be simplified a bit:

// Serial console "hooked vga" entry point
DECLFUNC entry_sercon
entry_sercon:
// Setup for chain loading to real vga handler
pushfw
pushl %cs:sercon_real_vga_handler

// Set %ds to zonelow segment
cli
cld
pushw %ds
pushl %eax
movl $_zonelow_seg, %eax
movl %eax, %ds

// Test if the sercon handler can be called
movl %esp, %eax // Test for broken x86emu
pushl $1f
retl
1: cmpl %esp, %eax
jne 4f
cmpb $0, sercon_enable // Test that sercon is enabled
je 3f

// Call handle_sercon()
popl %eax
popw %ds
2: pushl $handle_sercon
#if CONFIG_ENTRY_EXTRASTACK
jmp irqentry_arg_extrastack
#else
jmp irqentry_arg
#endif

// sercon disabled - check for legacy text modeset and otherwise exit
3: popl %eax
popw %ds
cmpw $0x0007, %ax
jle 2b
iretw

// Running on broken x86emu - restore stack and exit
4: movl %eax, %esp
popl %eax
popw %ds
iretw
Kevin O'Connor
2017-09-11 15:20:14 UTC
Permalink
Post by Gerd Hoffmann
---
src/config.h | 1 -
src/misc.c | 9 ---------
src/sercon.c | 49 ++++++++++++++++++-------------------------------
src/romlayout.S | 5 +++--
4 files changed, 21 insertions(+), 43 deletions(-)
diff --git a/src/config.h b/src/config.h
index baca029f0e..93c8dbc2d5 100644
--- a/src/config.h
+++ b/src/config.h
@@ -76,7 +76,6 @@
#define DEBUG_ISR_08 20
#define DEBUG_ISR_09 9
#define DEBUG_ISR_0e 9
-#define DEBUG_HDL_10 20
#define DEBUG_HDL_11 2
#define DEBUG_HDL_12 2
#define DEBUG_HDL_13 10
diff --git a/src/misc.c b/src/misc.c
index f4b656dd35..387a3482c9 100644
--- a/src/misc.c
+++ b/src/misc.c
@@ -52,15 +52,6 @@ handle_05(struct bregs *regs)
debug_enter(regs, DEBUG_HDL_05);
}
-// INT 10h Video Support Service Entry Point
-void VISIBLE16
-handle_10(struct bregs *regs)
-{
- debug_enter(regs, DEBUG_HDL_10);
- // don't do anything, since the VGA BIOS handles int10h requests
- sercon_10(regs);
-}
Thanks. With all the entry points hardened, I'm good with this
series. (All my other comments are minor.)

-Kevin
Loading...