[SeaBIOS] [PATCH 5/5] [wip] sercon: initial split-output implementation
Gerd Hoffmann
kraxel at redhat.com
Thu Jul 14 10:53:02 CEST 2016
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
---
src/optionroms.c | 2 ++
src/romlayout.S | 39 ++++++++++++++++++++++
src/sercon.c | 99 +++++++++++++++++++++++++++++++++++++++-----------------
3 files changed, 111 insertions(+), 29 deletions(-)
diff --git a/src/optionroms.c b/src/optionroms.c
index f9e9593..f08fcb1 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_enable();
enable_vga_console();
}
diff --git a/src/romlayout.S b/src/romlayout.S
index 53cc0f5..2a645eb 100644
--- a/src/romlayout.S
+++ b/src/romlayout.S
@@ -522,6 +522,45 @@ irqentry_arg:
DECL_IRQ_ENTRY hwpic1
DECL_IRQ_ENTRY hwpic2
+ // hooked int10, for sercon
+ DECLFUNC entry_10_hooked
+entry_10_hooked:
+ pushl $ handle_10
+#if CONFIG_ENTRY_EXTRASTACK
+ // FIXME: too much cut+paste
+ cli
+ cld
+ pushw %ds // Set %ds:%eax to space on ExtraStack
+ pushl %eax
+ movl $_zonelow_seg, %eax
+ movl %eax, %ds
+ movl StackPos, %eax
+ subl $PUSHBREGS_size+16, %eax
+ SAVEBREGS_POP_DSEAX // Save registers on extra stack
+ popl %ecx
+ movl %esp, PUSHBREGS_size+8(%eax)
+ movw %ss, PUSHBREGS_size+12(%eax)
+ popl BREGS_code(%eax)
+ popw BREGS_flags(%eax)
+
+ movw %ds, %dx // Setup %ss/%esp and call function
+ movw %dx, %ss
+ movl %eax, %esp
+ calll *%ecx
+
+ movl %esp, %eax // Restore registers and return
+ movw PUSHBREGS_size+12(%eax), %ss
+ movl PUSHBREGS_size+8(%eax), %esp
+ popl %edx
+ popw %dx
+ pushw BREGS_flags(%eax)
+ pushl BREGS_code(%eax)
+ RESTOREBREGS_DSEAX
+ ljmpw *%cs:sercon_int10_hook_resume
+#else
+#error FIXME: CONFIG_ENTRY_EXTRASTACK=n not supported yet
+#endif
+
// int 18/19 are special - they reset stack and call into 32bit mode.
DECLFUNC entry_19
entry_19:
diff --git a/src/sercon.c b/src/sercon.c
index c1cc738..4be7441 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 "std/cp437.h"
@@ -45,6 +46,8 @@ static void cursor_pos_set(u8 row, u8 col)
****************************************************************/
VARLOW u16 sercon_port;
+VARLOW u8 sercon_split;
+VARFSEG struct segoff_s sercon_int10_hook_resume;
/*
* We have a small output buffer here, for lazy output. That allows
@@ -64,6 +67,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 +182,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 +239,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 +258,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 +273,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 +285,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 +310,27 @@ 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 {
+ /* 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)
@@ -320,24 +341,24 @@ static void sercon_1000(struct bregs *regs)
static void sercon_1001(struct bregs *regs)
{
/* show/hide cursor? */
- SET_BDA(cursor_type, regs->cx);
+ if (!sercon_splitmode())
+ 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);
+ sercon_cursor_pos_set(regs->dh, regs->dl);
}
/* 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();
+ if (!sercon_splitmode()) {
+ regs->cx = GET_BDA(cursor_type);
+ regs->dh = cursor_pos_row();
+ regs->dl = cursor_pos_col();
+ }
}
/* Scroll up window */
@@ -362,8 +383,10 @@ static void sercon_1006(struct bregs *regs)
/* Read character and attribute at cursor position */
static void sercon_1008(struct bregs *regs)
{
- regs->ah = 0x07;
- regs->bh = ' ';
+ if (!sercon_splitmode()) {
+ regs->ah = 0x07;
+ regs->bh = ' ';
+ }
}
/* Write character and attribute at cursor position */
@@ -420,14 +443,18 @@ static void sercon_100e(struct bregs *regs)
/* Get current video mode */
static void sercon_100f(struct bregs *regs)
{
- regs->al = GET_BDA(video_mode);
- regs->ah = GET_BDA(video_cols);
+ if (!sercon_splitmode()) {
+ 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;
+ if (!sercon_splitmode()) {
+ regs->ax = 0x0100;
+ }
}
static void sercon_10XX(struct bregs *regs)
@@ -458,8 +485,22 @@ sercon_10(struct bregs *regs)
void sercon_enable(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_int10_hook_resume = vgabios;
+ SET_IVT(0x10, FUNC16(entry_10_hooked));
+ SET_LOW(sercon_split, 1);
+ }
+
SET_LOW(sercon_port, addr);
outb(0x03, addr + SEROFF_LCR); // 8N1
outb(0x01, addr + 0x02); // enable fifo
--
1.8.3.1
More information about the SeaBIOS
mailing list