[SeaBIOS] [PATCH 5/6] sercon: split-output implementation
Gerd Hoffmann
kraxel at redhat.com
Fri Sep 8 08:18:27 CEST 2017
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 <kraxel at 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
More information about the SeaBIOS
mailing list