:: commit 93a00dee9b198925e1338abcfca1f18419e9f0fa

mintsuki <mintsuki@protonmail.com> — 2022-03-01 16:53

parents: b1cf80c179

io: Complete serial support. Closes #155

diff --git a/common/drivers/gop.c b/common/drivers/gop.c
index f31fc088..222f0e7d 100644
--- a/common/drivers/gop.c
+++ b/common/drivers/gop.c
@@ -152,8 +152,10 @@ bool init_gop(struct fb_info *ret,
         panic(false, "gop: Initialisation failed");
     }
 
-    if (preset_mode == INVALID_PRESET_MODE)
+    if (preset_mode == INVALID_PRESET_MODE) {
         preset_mode = gop->Mode->Mode;
+        current_video_mode = preset_mode;
+    }
 
     struct resolution fallback_resolutions[] = {
         { 0,    0,   0  },   // Overridden by preset mode
diff --git a/common/drivers/serial.h b/common/drivers/serial.h
new file mode 100644
index 00000000..c716054a
--- /dev/null
+++ b/common/drivers/serial.h
@@ -0,0 +1,12 @@
+#ifndef __DRIVERS__SERIAL_H__
+#define __DRIVERS__SERIAL_H__
+
+#include <stdint.h>
+
+void serial_out(uint8_t b);
+
+#if bios == 1
+int serial_in(void);
+#endif
+
+#endif
diff --git a/common/drivers/serial.s2.c b/common/drivers/serial.s2.c
new file mode 100644
index 00000000..20cfa6a2
--- /dev/null
+++ b/common/drivers/serial.s2.c
@@ -0,0 +1,76 @@
+#include <stdint.h>
+#include <stddef.h>
+#include <stdbool.h>
+#include <drivers/serial.h>
+#include <sys/cpu.h>
+#include <lib/blib.h>
+#if uefi == 1
+#  include <efi.h>
+#endif
+
+static bool serial_initialised = false;
+
+#if uefi == 1
+static EFI_SERIAL_IO_PROTOCOL *serial_protocol;
+#endif
+
+static void serial_initialise(void) {
+    if (serial_initialised) {
+        return;
+    }
+
+#if uefi == 1
+    EFI_STATUS status;
+
+    EFI_GUID serial_guid = EFI_SERIAL_IO_PROTOCOL_GUID;
+
+    status = gBS->LocateProtocol(&serial_guid, NULL, (void **)&serial_protocol);
+    if (status) {
+        return;
+    }
+
+    serial_protocol->Reset(serial_protocol);
+#endif
+
+#if bios == 1
+    // Init com1
+    outb(0x3f8 + 1, 0x00);
+    outb(0x3f8 + 3, 0x80);
+    outb(0x3f8 + 0, 0x0c); // 9600 baud
+    outb(0x3f8 + 1, 0x00);
+    outb(0x3f8 + 3, 0x03);
+    outb(0x3f8 + 2, 0xc7);
+    outb(0x3f8 + 4, 0x0b);
+#endif
+
+    serial_initialised = true;
+}
+
+void serial_out(uint8_t b) {
+#if uefi == 1
+    if (efi_boot_services_exited) {
+        return;
+    }
+#endif
+
+    serial_initialise();
+
+#if uefi == 1
+    UINTN bsize = 1;
+    serial_protocol->Write(serial_protocol, &bsize, &b);
+#elif bios == 1
+    while ((inb(0x3f8 + 5) & 0x20) == 0);
+    outb(0x3f8, b);
+#endif
+}
+
+#if bios == 1
+int serial_in(void) {
+    serial_initialise();
+
+    if ((inb(0x3f8 + 5) & 0x01) == 0) {
+        return -1;
+    }
+    return inb(0x3f8);
+}
+#endif
diff --git a/common/lib/print.s2.c b/common/lib/print.s2.c
index fc685f29..06f3ac0e 100644
--- a/common/lib/print.s2.c
+++ b/common/lib/print.s2.c
@@ -9,6 +9,7 @@
 #include <lib/real.h>
 #endif
 #include <sys/cpu.h>
+#include <drivers/serial.h>
 
 #if bios == 1
 static void s2_print(const char *s, size_t len) {
@@ -140,27 +141,7 @@ void print(const char *fmt, ...) {
 
 static char print_buf[PRINT_BUF_MAX];
 
-static void serial_out(uint8_t b) {
-    while ((inb(0x3f8 + 5) & 0x20) == 0);
-    outb(0x3f8, b);
-}
-
 void vprint(const char *fmt, va_list args) {
-    static bool com_initialised = false;
-
-    if (COM_OUTPUT && !com_initialised) {
-        // Init com1
-        outb(0x3F8 + 1, 0x00);
-        outb(0x3F8 + 3, 0x80);
-        outb(0x3F8 + 0, 0x0c); // 9600 baud
-        outb(0x3F8 + 1, 0x00);
-        outb(0x3F8 + 3, 0x03);
-        outb(0x3F8 + 2, 0xc7);
-        outb(0x3F8 + 4, 0x0b);
-
-        com_initialised = true;
-    }
-
     size_t print_buf_i = 0;
 
     for (;;) {
diff --git a/common/lib/readline.c b/common/lib/readline.c
index 1f1cfe2c..a94a6898 100644
--- a/common/lib/readline.c
+++ b/common/lib/readline.c
@@ -10,6 +10,8 @@
 #elif uefi == 1
 #  include <efi.h>
 #endif
+#include <drivers/serial.h>
+#include <sys/cpu.h>
 
 int getchar_internal(uint8_t scancode, uint8_t ascii, uint32_t shift_state) {
     switch (scancode) {
@@ -89,89 +91,171 @@ int getchar_internal(uint8_t scancode, uint8_t ascii, uint32_t shift_state) {
 
 #if bios == 1
 int getchar(void) {
-    uint8_t scancode = 0;
-    uint8_t ascii = 0;
-    uint32_t mods = 0;
-again:;
-    struct rm_regs r = {0};
-    rm_int(0x16, &r, &r);
-    scancode = (r.eax >> 8) & 0xff;
-    ascii = r.eax & 0xff;
-
-    r = (struct rm_regs){ 0 };
-    r.eax = 0x0200; // GET SHIFT FLAGS
-    rm_int(0x16, &r, &r);
-
-    if (r.eax & GETCHAR_LCTRL) {
-        /* the bios subtracts 0x60 from ascii if ctrl is pressed */
-        mods = GETCHAR_LCTRL;
-        ascii += 0x60;
+    for (;;) {
+        int ret = pit_sleep_and_quit_on_keypress(65535);
+        if (ret != 0) {
+            return ret;
+        }
     }
-
-    int ret = getchar_internal(scancode, ascii, mods);
-    if (ret == -1)
-        goto again;
-    return ret;
 }
 
 int _pit_sleep_and_quit_on_keypress(uint32_t ticks);
 
-int pit_sleep_and_quit_on_keypress(int seconds) {
-    return _pit_sleep_and_quit_on_keypress(seconds * 18);
-}
-#endif
-
-#if uefi == 1
-int getchar(void) {
-    EFI_KEY_DATA kd;
+static int input_sequence(void) {
+    int val = 0;
 
-    UINTN which;
+    for (;;) {
+        int ret = -1;
+        size_t retries = 0;
 
-    EFI_EVENT events[1];
+        while (ret == -1 && retries < 1000000) {
+            ret = serial_in();
+            retries++;
+        }
+        if (ret == -1) {
+            return 0;
+        }
 
-    EFI_GUID exproto_guid = EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID;
-    EFI_GUID sproto_guid = EFI_SIMPLE_TEXT_INPUT_PROTOCOL_GUID;
-    EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *exproto = NULL;
-    EFI_SIMPLE_TEXT_IN_PROTOCOL *sproto = NULL;
+        switch (ret) {
+            case 'A':
+                return GETCHAR_CURSOR_UP;
+            case 'B':
+                return GETCHAR_CURSOR_DOWN;
+            case 'C':
+                return GETCHAR_CURSOR_RIGHT;
+            case 'D':
+                return GETCHAR_CURSOR_LEFT;
+            case 'F':
+                return GETCHAR_END;
+            case 'H':
+                return GETCHAR_HOME;
+        }
 
-    if (gBS->HandleProtocol(gST->ConsoleInHandle, &exproto_guid, (void **)&exproto) != EFI_SUCCESS) {
-        if (gBS->HandleProtocol(gST->ConsoleInHandle, &sproto_guid, (void **)&sproto) != EFI_SUCCESS) {
-            panic(false, "Your input device doesn't have an input protocol!");
+        if (ret > '9' || ret < '0') {
+            break;
         }
 
-        events[0] = sproto->WaitForKey;
-    } else {
-        events[0] = exproto->WaitForKeyEx;
+        val *= 10;
+        val += ret - '0';
+    }
+
+    switch (val) {
+        case 3:
+            return GETCHAR_DELETE;
+        case 5:
+            return GETCHAR_PGUP;
+        case 6:
+            return GETCHAR_PGDOWN;
+        case 21:
+            return GETCHAR_F10;
     }
 
+    return 0;
+}
+
+int pit_sleep_and_quit_on_keypress(int seconds) {
+    for (int i = 0; i < seconds * 18; i++) {
+        int ret = _pit_sleep_and_quit_on_keypress(1);
+
+        if (ret != 0) {
+            return ret;
+        }
+
+        if (!serial) {
+            continue;
+        }
+
+        ret = serial_in();
+
+        if (ret != -1) {
 again:
-    memset(&kd, 0, sizeof(EFI_KEY_DATA));
+            switch (ret) {
+                case '\r':
+                    return '\n';
+                case 0x1b:
+                    delay(10000);
+                    ret = serial_in();
+                    if (ret == -1) {
+                        return GETCHAR_ESCAPE;
+                    }
+                    if (ret == '[') {
+                        return input_sequence();
+                    }
+                    goto again;
+            }
 
-    gBS->WaitForEvent(1, events, &which);
+            return ret;
+        }
+    }
 
+    return 0;
+}
+#endif
+
+#if uefi == 1
+static int input_sequence(bool ext,
+                   EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *exproto,
+                   EFI_SIMPLE_TEXT_IN_PROTOCOL *sproto) {
     EFI_STATUS status;
-    if (events[0] == sproto->WaitForKey) {
-        status = sproto->ReadKeyStroke(sproto, &kd.Key);
-    } else {
-        status = exproto->ReadKeyStrokeEx(exproto, &kd);
-    }
+    EFI_KEY_DATA kd;
 
-    if (status != EFI_SUCCESS) {
-        goto again;
+    int val = 0;
+
+    for (;;) {
+        if (ext == false) {
+            status = sproto->ReadKeyStroke(sproto, &kd.Key);
+        } else {
+            status = exproto->ReadKeyStrokeEx(exproto, &kd);
+        }
+
+        if (status != EFI_SUCCESS) {
+            return 0;
+        }
+
+        switch (kd.Key.UnicodeChar) {
+            case 'A':
+                return GETCHAR_CURSOR_UP;
+            case 'B':
+                return GETCHAR_CURSOR_DOWN;
+            case 'C':
+                return GETCHAR_CURSOR_RIGHT;
+            case 'D':
+                return GETCHAR_CURSOR_LEFT;
+            case 'F':
+                return GETCHAR_END;
+            case 'H':
+                return GETCHAR_HOME;
+        }
+
+        if (kd.Key.UnicodeChar > '9' || kd.Key.UnicodeChar < '0') {
+            break;
+        }
+
+        val *= 10;
+        val += kd.Key.UnicodeChar - '0';
     }
 
-    if ((kd.KeyState.KeyShiftState & EFI_SHIFT_STATE_VALID) == 0) {
-        kd.KeyState.KeyShiftState = 0;
+    switch (val) {
+        case 3:
+            return GETCHAR_DELETE;
+        case 5:
+            return GETCHAR_PGUP;
+        case 6:
+            return GETCHAR_PGDOWN;
+        case 21:
+            return GETCHAR_F10;
     }
 
-    int ret = getchar_internal(kd.Key.ScanCode, kd.Key.UnicodeChar,
-                               kd.KeyState.KeyShiftState);
+    return 0;
+}
 
-    if (ret == -1) {
-        goto again;
+int getchar(void) {
+    for (;;) {
+        int ret = pit_sleep_and_quit_on_keypress(65535);
+        if (ret != 0) {
+            return ret;
+        }
     }
-
-    return ret;
 }
 
 int pit_sleep_and_quit_on_keypress(int seconds) {
@@ -224,6 +308,32 @@ again:
         kd.KeyState.KeyShiftState = 0;
     }
 
+    if (kd.Key.ScanCode == SCAN_ESC) {
+        gBS->CreateEvent(EVT_TIMER, TPL_CALLBACK, NULL, NULL, &events[1]);
+
+        gBS->SetTimer(events[1], TimerRelative, 100000);
+
+        gBS->WaitForEvent(2, events, &which);
+
+        if (which == 1) {
+            return GETCHAR_ESCAPE;
+        }
+
+        if (events[0] == sproto->WaitForKey) {
+            status = sproto->ReadKeyStroke(sproto, &kd.Key);
+        } else {
+            status = exproto->ReadKeyStrokeEx(exproto, &kd);
+        }
+
+        if (status != EFI_SUCCESS) {
+            goto again;
+        }
+
+        if (kd.Key.UnicodeChar == '[') {
+            return input_sequence(events[0] == exproto->WaitForKeyEx, exproto, sproto);
+        }
+    }
+
     int ret = getchar_internal(kd.Key.ScanCode, kd.Key.UnicodeChar,
                                kd.KeyState.KeyShiftState);
 
diff --git a/common/lib/term.c b/common/lib/term.c
index 871bc294..e3cdb326 100644
--- a/common/lib/term.c
+++ b/common/lib/term.c
@@ -40,8 +40,8 @@ void term_vbe(size_t width, size_t height) {
     }
 
     if (serial) {
-        term_cols = 80;
-        term_rows = 24;
+        term_cols = term_cols > 80 ? 80 : term_cols;
+        term_rows = term_rows > 24 ? 24 : term_rows;
     }
 
     term_reinit();
@@ -358,8 +358,8 @@ void term_textmode(void) {
     init_vga_textmode(&term_rows, &term_cols, true);
 
     if (serial) {
-        term_cols = 80;
-        term_rows = 24;
+        term_cols = term_cols > 80 ? 80 : term_cols;
+        term_rows = term_rows > 24 ? 24 : term_rows;
     }
 
     term_reinit();
tab: 248 wrap: offon