[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