:: commit f59444e6d6f92833be12d2ab43ab8bad4f41b897

mintsuki <mintsuki@protonmail.com> — 2021-10-09 11:32

parents: 56d50b80b4

console: Introduce Limine console

diff --git a/stage23/console.c b/stage23/console.c
new file mode 100644
index 00000000..ee4556de
--- /dev/null
+++ b/stage23/console.c
@@ -0,0 +1,50 @@
+#include <stddef.h>
+#include <stdint.h>
+#include <console.h>
+#include <mm/pmm.h>
+#include <lib/print.h>
+#include <lib/readline.h>
+#include <lib/libc.h>
+#include <lib/blib.h>
+#include <lib/term.h>
+
+static void console_help(void) {
+    print(
+        "Available commands:\n"
+        "exit      -- Return to boot menu.\n"
+        "version   -- Print version.\n"
+        "copyright -- Print copyright.\n"
+        "license   -- Print license.\n"
+        "help      -- Print this help message.\n"
+    );
+}
+
+void console(void) {
+    print("Welcome to the Limine console.\nType 'help' for more information.\n\n");
+
+    static char *prompt = NULL;
+    if (prompt == NULL) {
+        prompt = ext_mem_alloc(256);
+    }
+
+    for (;;) {
+        print(">>> ");
+        readline("", prompt, 256);
+
+        if (strcmp(prompt, "help") == 0) {
+            console_help();
+        } else if (strcmp(prompt, "exit") == 0) {
+            reset_term();
+            return;
+        } else if (strcmp(prompt, "version") == 0) {
+            print(LIMINE_VERSION "\n");
+        } else if (strcmp(prompt, "copyright") == 0) {
+            print(LIMINE_COPYRIGHT "\n");
+            print("Limine is distributed under the terms of the BSD-2-Clause license.\n");
+        } else if (strcmp(prompt, "license") == 0) {
+            print("%s", bsd_2_clause);
+        } else if (*prompt != 0) {
+            print("Invalid command: `%s`.\n", prompt);
+        }
+    }
+}
diff --git a/stage23/console.h b/stage23/console.h
new file mode 100644
index 00000000..4ea97c71
--- /dev/null
+++ b/stage23/console.h
@@ -0,0 +1,6 @@
+#ifndef __CONSOLE_H__
+#define __CONSOLE_H__
+
+void console(void);
+
+#endif
diff --git a/stage23/entry.s2.c b/stage23/entry.s2.c
index 29d0ae1d..663ea65f 100644
--- a/stage23/entry.s2.c
+++ b/stage23/entry.s2.c
@@ -81,8 +81,6 @@ void entry(uint8_t boot_drive, int boot_from) {
 
     term_textmode();
 
-    copyright_notice();
-
     init_idt();
 
     disk_create_index();
diff --git a/stage23/entry.s3.c b/stage23/entry.s3.c
index 26cae860..a5e50e6c 100644
--- a/stage23/entry.s3.c
+++ b/stage23/entry.s3.c
@@ -58,16 +58,13 @@ void uefi_entry(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) {
 
     status = gBS->SetWatchdogTimer(0, 0x10000, 0, NULL);
     if (status) {
+        term_vbe(0, 0);
+        early_term = true;
         print("WARNING: Failed to disable watchdog timer!\n");
     }
 
     init_memmap();
 
-    term_vbe(0, 0);
-    early_term = true;
-
-    copyright_notice();
-
     disk_create_index();
 
     boot_volume = NULL;
@@ -75,6 +72,9 @@ void uefi_entry(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) {
     EFI_HANDLE current_handle = ImageHandle;
     for (;;) {
         if (current_handle == NULL) {
+            term_vbe(0, 0);
+            early_term = true;
+
             print("WARNING: Could not meaningfully match the boot device handle with a volume.\n");
             print("         Using the first volume containing a Limine configuration!\n");
 
@@ -111,6 +111,8 @@ void uefi_entry(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) {
                                      (void **)&loaded_image);
 
         if (status) {
+            term_vbe(0, 0);
+            early_term = true;
             panic("HandleProtocol failure (%x)", status);
         }
 
diff --git a/stage23/lib/blib.c b/stage23/lib/blib.c
index 12f2f7fb..32224ebd 100644
--- a/stage23/lib/blib.c
+++ b/stage23/lib/blib.c
@@ -268,3 +268,25 @@ fail:
 }
 
 #endif
+
+const char bsd_2_clause[] =
+"Redistribution and use in source and binary forms, with or without\n"
+"modification, are permitted provided that the following conditions are met:\n"
+"\n"
+"1. Redistributions of source code must retain the above copyright notice, this\n"
+"   list of conditions and the following disclaimer.\n"
+"\n"
+"2. Redistributions in binary form must reproduce the above copyright notice,\n"
+"   this list of conditions and the following disclaimer in the documentation\n"
+"   and/or other materials provided with the distribution.\n"
+"\n"
+"THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n"
+"AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n"
+"IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n"
+"DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\n"
+"FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n"
+"DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\n"
+"SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\n"
+"CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\n"
+"OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n"
+"OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n";
diff --git a/stage23/lib/blib.h b/stage23/lib/blib.h
index e0caa157..1a4ca703 100644
--- a/stage23/lib/blib.h
+++ b/stage23/lib/blib.h
@@ -24,7 +24,7 @@ extern bool efi_boot_services_exited;
 bool efi_exit_boot_services(void);
 #endif
 
-void copyright_notice(void);
+extern const char bsd_2_clause[];
 
 extern struct volume *boot_volume;
 
diff --git a/stage23/lib/blib.s2.c b/stage23/lib/blib.s2.c
index 19098c5f..9513fb13 100644
--- a/stage23/lib/blib.s2.c
+++ b/stage23/lib/blib.s2.c
@@ -5,12 +5,6 @@
 
 bool verbose = true;
 
-void copyright_notice(void) {
-    print("Limine " LIMINE_VERSION "\n");
-    print(LIMINE_COPYRIGHT "\n");
-    print("This bootloader is distributed under the terms of the BSD-2-Clause license.\n\n");
-}
-
 uint8_t bcd_to_int(uint8_t val) {
     return (val & 0x0f) + ((val & 0xf0) >> 4) * 10;
 }
diff --git a/stage23/lib/gterm.h b/stage23/lib/gterm.h
index a4e16912..65a39282 100644
--- a/stage23/lib/gterm.h
+++ b/stage23/lib/gterm.h
@@ -7,7 +7,6 @@
 #include <drivers/vbe.h>
 
 extern struct fb_info fbinfo;
-extern bool term_autoflush;
 
 bool gterm_init(size_t *_rows, size_t *_cols, size_t width, size_t height);
 void gterm_deinit(void);
diff --git a/stage23/lib/print.s2.c b/stage23/lib/print.s2.c
index 62d4036e..52bde60d 100644
--- a/stage23/lib/print.s2.c
+++ b/stage23/lib/print.s2.c
@@ -9,7 +9,7 @@
 
 static const char *base_digits = "0123456789abcdef";
 
-#define PRINT_BUF_MAX 512
+#define PRINT_BUF_MAX 4096
 
 static void prn_str(char *print_buf, size_t *print_buf_i, const char *string) {
     size_t i;
diff --git a/stage23/lib/readline.c b/stage23/lib/readline.c
index fdf8e67a..2979a6ab 100644
--- a/stage23/lib/readline.c
+++ b/stage23/lib/readline.c
@@ -232,3 +232,107 @@ again:
     return ret;
 }
 #endif
+
+static void reprint_string(int x, int y, const char *s) {
+    size_t orig_x, orig_y;
+    disable_cursor();
+    get_cursor_pos(&orig_x, &orig_y);
+    set_cursor_pos(x, y);
+    term_write((uintptr_t)s, strlen(s));
+    set_cursor_pos(orig_x, orig_y);
+    enable_cursor();
+}
+
+static void cursor_back(void) {
+    size_t x, y;
+    get_cursor_pos(&x, &y);
+    if (x) {
+        x--;
+    } else if (y) {
+        y--;
+        x = term_cols - 1;
+    }
+    set_cursor_pos(x, y);
+}
+
+static void cursor_fwd(void) {
+    size_t x, y;
+    get_cursor_pos(&x, &y);
+    if (x < term_cols - 1) {
+        x++;
+    } else if (y < term_rows - 1) {
+        y++;
+        x = 0;
+    }
+    set_cursor_pos(x, y);
+}
+
+void readline(const char *orig_str, char *buf, size_t limit) {
+    bool prev_autoflush = term_autoflush;
+    term_autoflush = false;
+
+    size_t orig_str_len = strlen(orig_str);
+    memmove(buf, orig_str, orig_str_len);
+    buf[orig_str_len] = 0;
+
+    size_t orig_x, orig_y;
+    get_cursor_pos(&orig_x, &orig_y);
+
+    term_write((uintptr_t)orig_str, orig_str_len);
+
+    for (size_t i = orig_str_len; ; ) {
+        term_double_buffer_flush();
+        int c = getchar();
+        switch (c) {
+            case GETCHAR_CURSOR_LEFT:
+                if (i) {
+                    i--;
+                    cursor_back();
+                }
+                continue;
+            case GETCHAR_CURSOR_RIGHT:
+                if (i < strlen(buf)) {
+                    i++;
+                    cursor_fwd();
+                }
+                continue;
+            case '\b':
+                if (i) {
+                    i--;
+                    cursor_back();
+            case GETCHAR_DELETE:;
+                    size_t j;
+                    for (j = i; ; j++) {
+                        buf[j] = buf[j+1];
+                        if (!buf[j]) {
+                            buf[j] = ' ';
+                            break;
+                        }
+                    }
+                    reprint_string(orig_x, orig_y, buf);
+                    buf[j] = 0;
+                }
+                continue;
+            case '\n':
+                term_write((uintptr_t)"\n", 1);
+                goto out;
+            default: {
+                if (strlen(buf) < limit - 1) {
+                    for (size_t j = strlen(buf); ; j--) {
+                        buf[j+1] = buf[j];
+                        if (j == i)
+                            break;
+                    }
+                    buf[i] = c;
+                    i++;
+                    cursor_fwd();
+                    reprint_string(orig_x, orig_y, buf);
+                }
+            }
+        }
+    }
+
+out:
+    term_double_buffer_flush();
+    term_autoflush = prev_autoflush;
+}
diff --git a/stage23/lib/term.h b/stage23/lib/term.h
index a2c8dfbb..0338e1d3 100644
--- a/stage23/lib/term.h
+++ b/stage23/lib/term.h
@@ -92,4 +92,13 @@ extern void (*term_full_refresh)(void);
 
 extern void (*term_callback)(uint64_t, uint64_t, uint64_t, uint64_t);
 
+extern bool term_autoflush;
+
+inline void reset_term(void) {
+    term_autoflush = true;
+    enable_cursor();
+    clear(true);
+    term_double_buffer_flush();
+}
+
 #endif
diff --git a/stage23/menu.c b/stage23/menu.c
index 5b70d82a..2acb0686 100644
--- a/stage23/menu.c
+++ b/stage23/menu.c
@@ -12,6 +12,7 @@
 #include <lib/uri.h>
 #include <mm/pmm.h>
 #include <drivers/vbe.h>
+#include <console.h>
 
 static char *menu_branding = NULL;
 static char *menu_branding_colour = NULL;
@@ -573,11 +574,11 @@ char *menu(char **cmdline) {
         term_vbe(req_width, req_height);
     }
 
+refresh:
     disable_cursor();
 
     term_autoflush = false;
 
-refresh:
     clear(true);
     {
         size_t x, y;
@@ -643,6 +644,8 @@ refresh:
             print("    \e[32mARROWS\e[0m Select    \e[32mENTER\e[0m %s",
                   selected_menu_entry->expanded ? "Collapse" : "Expand");
         }
+        set_cursor_pos(term_cols - 12, 3);
+        print("\e[32mC\e[0m Console");
         set_cursor_pos(x, y);
     }
 
@@ -699,7 +702,6 @@ timeout_aborted:
                     selected_menu_entry->expanded = !selected_menu_entry->expanded;
                     goto refresh;
                 }
-                enable_cursor();
                 *cmdline = config_get_value(selected_menu_entry->body, 0, "KERNEL_CMDLINE");
                 if (!*cmdline) {
                     *cmdline = config_get_value(selected_menu_entry->body, 0, "CMDLINE");
@@ -707,8 +709,7 @@ timeout_aborted:
                 if (!*cmdline) {
                     *cmdline = "";
                 }
-                clear(true);
-                term_autoflush = true;
+                reset_term();
                 return selected_menu_entry->body;
             case 'e': {
                 if (editor_enabled) {
@@ -721,6 +722,12 @@ timeout_aborted:
                     selected_menu_entry->body = new_body;
                     goto autoboot;
                 }
+                break;
+            }
+            case 'c': {
+                reset_term();
+                console();
+                goto refresh;
             }
         }
     }
diff --git a/test/limine.cfg b/test/limine.cfg
index 9d74e626..7123ab86 100644
--- a/test/limine.cfg
+++ b/test/limine.cfg
@@ -1,6 +1,6 @@
 DEFAULT_ENTRY=1
 TIMEOUT=3
-GRAPHICS=yes
+#GRAPHICS=yes
 VERBOSE=yes
 
 THEME_BACKGROUND=50000000
tab: 248 wrap: offon