feat: a better boot command line parser
authorMinep <lunaixsky@qq.com>
Sat, 9 Dec 2023 20:56:32 +0000 (20:56 +0000)
committerMinep <lunaixsky@qq.com>
Sat, 9 Dec 2023 20:56:32 +0000 (20:56 +0000)
fix: bugs in term interfacing

13 files changed:
lunaix-os/arch/i386/boot/mb_parser.c
lunaix-os/hal/char/serial.c
lunaix-os/hal/char/uart/16550_base.c
lunaix-os/hal/term/lcntls/lcntl.c
lunaix-os/hal/term/term.c
lunaix-os/hal/term/term_io.c
lunaix-os/includes/klibc/stdlib.h
lunaix-os/includes/lunaix/boot_generic.h
lunaix-os/includes/lunaix/compiler.h
lunaix-os/includes/lunaix/kcmd.h [new file with mode: 0644]
lunaix-os/kernel/boot_helper.c
lunaix-os/kernel/kcmd.c [new file with mode: 0644]
lunaix-os/kernel/kinit.c

index 81e271679c1dd3eaee129a526f9c5d544844750f..64a405188511192461140049511149050b899261 100644 (file)
@@ -60,28 +60,9 @@ mb_parse_cmdline(struct boot_handoff* bhctx, void* buffer, char* cmdline)
     }
 
     mb_memcpy(buffer, (u8_t*)cmdline, slen);
     }
 
     mb_memcpy(buffer, (u8_t*)cmdline, slen);
+    bhctx->kexec.len = slen;
 
 
-    cmdline = (char*)buffer;
-    buffer = &cmdline[slen];
-
-    char c, prev = SPACE;
-    int i = 0, argc = 0;
-    ptr_t argptr = (ptr_t)cmdline;
-
-    while ((c = cmdline[i])) {
-        if (c == SPACE && prev != SPACE) {
-            ((ptr_t*)buffer)[argc++] = argptr;
-        } else if (c != SPACE && prev == SPACE) {
-            argptr = (ptr_t)&cmdline[i];
-        }
-        prev = c;
-        i++;
-    }
-
-    bhctx->kexec.argv = (char**)buffer;
-    bhctx->kexec.argc = argc;
-
-    return slen + argc * sizeof(ptr_t);
+    return slen;
 }
 
 size_t boot_text
 }
 
 size_t boot_text
@@ -165,6 +146,8 @@ mb_parse(struct multiboot_info* mb)
 {
     struct boot_handoff* bhctx = (struct boot_handoff*)bhctx_buffer;
     ptr_t bhctx_ex = (ptr_t)&bhctx[1];
 {
     struct boot_handoff* bhctx = (struct boot_handoff*)bhctx_buffer;
     ptr_t bhctx_ex = (ptr_t)&bhctx[1];
+    
+    *bhctx = (struct boot_handoff){ };
 
     /* Parse memory map */
     if ((mb->flags & MULTIBOOT_INFO_MEM_MAP)) {
 
     /* Parse memory map */
     if ((mb->flags & MULTIBOOT_INFO_MEM_MAP)) {
index d353a163fbad23fef25857ffafce2116b0208ce4..1dbdb6821eec2447a7548e270aedb0f51b9a9212 100644 (file)
@@ -209,6 +209,8 @@ serial_create(struct devclass* class, char* if_ident)
     struct device* dev = device_allocseq(NULL, sdev);
     dev->ops.read = __serial_read;
     dev->ops.read_page = __serial_read_page;
     struct device* dev = device_allocseq(NULL, sdev);
     dev->ops.read = __serial_read;
     dev->ops.read_page = __serial_read_page;
+    dev->ops.read_async = __serial_read_async;
+    dev->ops.write_async = __serial_write_async;
     dev->ops.write = __serial_write;
     dev->ops.write_page = __serial_write_page;
     dev->ops.exec_cmd = __serial_exec_command;
     dev->ops.write = __serial_write;
     dev->ops.write_page = __serial_write_page;
     dev->ops.exec_cmd = __serial_exec_command;
index e3dda36e48823b7d704dfe2b8e16f4c9da3137fb..8ec752e3349816e730059b7623f253d01602c943 100644 (file)
@@ -66,7 +66,7 @@ uart_general_irq_handler(int iv, struct llist_header* ports)
     llist_for_each(pos, n, ports, local_ports)
     {
         int is = uart_intr_identify(pos);
     llist_for_each(pos, n, ports, local_ports)
     {
         int is = uart_intr_identify(pos);
-        if (iv == pos->iv && (is == UART_DATA_OK || is == UART_CHR_TIMEOUT)) {
+        if (iv == pos->iv && (is == UART_CHR_TIMEOUT)) {
             goto done;
         }
     }
             goto done;
         }
     }
@@ -91,5 +91,7 @@ done:
     }
 
     serial_accept_buffer(pos->sdev, tmpbuf, i);
     }
 
     serial_accept_buffer(pos->sdev, tmpbuf, i);
+    serial_accept_one(pos->sdev, 0);
+    
     serial_end_recv(pos->sdev);
 }
     serial_end_recv(pos->sdev);
 }
index aab02c097974552ffd2eeeaaf2e5a8121adb7c00..fdaf244275811feb83a4e5b876cefa199b72602f 100644 (file)
@@ -32,7 +32,6 @@ lcntl_transform_seq(struct term* tdev, struct linebuffer* lbuf, bool out)
         _lf = tdev->lflags;
     int allow_more = 1, latest_eol = cooked->ptr;
     char c;
         _lf = tdev->lflags;
     int allow_more = 1, latest_eol = cooked->ptr;
     char c;
-    bool should_flush = false;
 
     int (*lcntl_slave_put)(struct term*, struct linebuffer*, char) =
         tdev->lcntl->process_and_put;
 
     int (*lcntl_slave_put)(struct term*, struct linebuffer*, char) =
         tdev->lcntl->process_and_put;
@@ -57,20 +56,20 @@ lcntl_transform_seq(struct term* tdev, struct linebuffer* lbuf, bool out)
         if (c == '\r' && ((_if & _ICRNL) || (_of & _OCRNL))) {
             c = '\n';
         } else if (c == '\n') {
         if (c == '\r' && ((_if & _ICRNL) || (_of & _OCRNL))) {
             c = '\n';
         } else if (c == '\n') {
-            if ((_if & _INLCR) || (_of & (_ONLRET | _ONLCR))) {
+            if ((_if & _INLCR) || (_of & (_ONLRET))) {
                 c = '\r';
             }
         }
 
         if (c == '\0') {
                 c = '\r';
             }
         }
 
         if (c == '\0') {
+            if ((_if & _IGNBRK)) {
+                continue;
+            }
+
             if ((_if & _BRKINT)) {
                 raise_sig(tdev, lbuf, SIGINT);
                 break;
             }
             if ((_if & _BRKINT)) {
                 raise_sig(tdev, lbuf, SIGINT);
                 break;
             }
-
-            if ((_if & _IGNBRK)) {
-                continue;
-            }
         }
 
         if ('a' <= c && c <= 'z') {
         }
 
         if ('a' <= c && c <= 'z') {
@@ -86,18 +85,16 @@ lcntl_transform_seq(struct term* tdev, struct linebuffer* lbuf, bool out)
             if (!out && (_lf & _ECHONL)) {
                 rbuffer_put(output, c);
             }
             if (!out && (_lf & _ECHONL)) {
                 rbuffer_put(output, c);
             }
-            should_flush = true;
         }
 
         if (out) {
         }
 
         if (out) {
-            goto put_char;
+            goto do_out;
         }
 
         // For input procesing
 
         if (c == '\n' || c == EOL) {
             lbuf->sflags |= LSTATE_EOL;
         }
 
         // For input procesing
 
         if (c == '\n' || c == EOL) {
             lbuf->sflags |= LSTATE_EOL;
-            goto keep;
         } else if (c == EOF) {
             lbuf->sflags |= LSTATE_EOF;
             rbuffer_clear(raw);
         } else if (c == EOF) {
             lbuf->sflags |= LSTATE_EOF;
             rbuffer_clear(raw);
@@ -117,18 +114,28 @@ lcntl_transform_seq(struct term* tdev, struct linebuffer* lbuf, bool out)
             goto keep;
         }
 
             goto keep;
         }
 
+        if ((_lf & _ECHOE) && c == ERASE) {
+            rbuffer_put(output, '\x8'); 
+            rbuffer_put(output, ' '); 
+            rbuffer_put(output, '\x8'); 
+        }
+        if ((_lf & _ECHOK) && c == KILL) {
+            rbuffer_put(output, c);
+            rbuffer_put(output, '\n');
+        }
+
         continue;
 
     keep:
         if ((_lf & _ECHO)) {
             rbuffer_put(output, c);
         }
         continue;
 
     keep:
         if ((_lf & _ECHO)) {
             rbuffer_put(output, c);
         }
-        if ((_lf & _ECHOE) && c == ERASE) {
-            rbuffer_erase(output);
-        }
-        if ((_lf & _ECHOK) && c == KILL) {
-            rbuffer_put(output, c);
-            rbuffer_put(output, '\n');
+
+        goto put_char;
+
+    do_out:
+        if (c == '\n' && (_of & _ONLCR)) {
+            rbuffer_put(cooked, '\r');
         }
 
     put_char:
         }
 
     put_char:
@@ -139,7 +146,7 @@ lcntl_transform_seq(struct term* tdev, struct linebuffer* lbuf, bool out)
         }
     }
 
         }
     }
 
-    if (should_flush && !(_lf & _NOFLSH)) {
+    if (!rbuffer_empty(output) && !(_lf & _NOFLSH)) {
         term_flush(tdev);
     }
 
         term_flush(tdev);
     }
 
@@ -157,5 +164,5 @@ lcntl_transform_inseq(struct term* tdev)
 int
 lcntl_transform_outseq(struct term* tdev)
 {
 int
 lcntl_transform_outseq(struct term* tdev)
 {
-    return lcntl_transform_seq(tdev, &tdev->line_in, true);
+    return lcntl_transform_seq(tdev, &tdev->line_out, true);
 }
\ No newline at end of file
 }
\ No newline at end of file
index 289179da77b9744f451bd3594401c1964ed95530..0c404a51208d035111b54a936e5c8db55ff494ae 100644 (file)
@@ -145,7 +145,7 @@ tdev_do_read(struct device* dev, void* buf, size_t offset, size_t len)
     return rdsz;
 }
 
     return rdsz;
 }
 
-static cc_t default_cc[_NCCS] = {4, '\n', 8, 3, 1, 24, 22, 0, 0, 1, 1};
+static cc_t default_cc[_NCCS] = {4, '\n', 0x7f, 3, 1, 24, 22, 0, 0, 1, 1};
 
 struct term*
 term_create(struct device* chardev, char* suffix)
 
 struct term*
 term_create(struct device* chardev, char* suffix)
@@ -175,8 +175,9 @@ term_create(struct device* chardev, char* suffix)
         device_register(terminal->dev, &termdev, "tty%d", termdev.variant++);
     }
 
         device_register(terminal->dev, &termdev, "tty%d", termdev.variant++);
     }
 
-    terminal->lflags = _ICANON | _IEXTEN | _ISIG | _ECHO;
-    terminal->iflags = _ICRNL;
+    terminal->lflags = _ICANON | _IEXTEN | _ISIG | _ECHO | _ECHOE | _ECHONL;
+    terminal->iflags = _ICRNL | _IGNBRK;
+    terminal->oflags = _ONLCR | _OPOST;
     memcpy(terminal->cc, default_cc, _NCCS * sizeof(cc_t));
 
     return terminal;
     memcpy(terminal->cc, default_cc, _NCCS * sizeof(cc_t));
 
     return terminal;
index 729e5496b083bc22e51b2bac9ec1c31f407c0152..8042e3b2eae71859816926bcbf8d420c2f873001 100644 (file)
@@ -61,7 +61,6 @@ term_read_noncano(struct term* tdev)
 {
     struct device* chdev = tdev->chdev;
     return do_read_raw(tdev);
 {
     struct device* chdev = tdev->chdev;
     return do_read_raw(tdev);
-    ;
 }
 
 static int
 }
 
 static int
@@ -95,7 +94,7 @@ int
 term_flush(struct term* tdev)
 {
     if ((tdev->oflags & _OPOST)) {
 term_flush(struct term* tdev)
 {
     if ((tdev->oflags & _OPOST)) {
-        lcntl_transform_inseq(tdev);
+        lcntl_transform_outseq(tdev);
     }
 
     struct linebuffer* line_out = &tdev->line_out;
     }
 
     struct linebuffer* line_out = &tdev->line_out;
index 05509cd9d0ce0525b1492d73d7021cec98e8335a..a6c83a9fb75f88721ff52ea1c9d2e93db15ef359 100644 (file)
@@ -5,6 +5,7 @@
 char* __uitoa_internal(unsigned int value, char* str, int base, unsigned int* size);
 char* __itoa_internal(int value, char* str, int base, unsigned int* size);
 #endif
 char* __uitoa_internal(unsigned int value, char* str, int base, unsigned int* size);
 char* __itoa_internal(int value, char* str, int base, unsigned int* size);
 #endif
+
 char* itoa(int value, char* str, int base);
 
 #endif /* __LUNAIX_STDLIB_H */
 char* itoa(int value, char* str, int base);
 
 #endif /* __LUNAIX_STDLIB_H */
index 93e9e3db6b7c53d424ee6ee8b703c5cd2d00ba6c..a229c454b8f8668251b140eaeab8d1746a13e504 100644 (file)
@@ -41,8 +41,8 @@ struct boot_handoff
         ptr_t ksections;
         size_t size;
 
         ptr_t ksections;
         size_t size;
 
-        char** argv;
-        size_t argc;
+        char* cmdline;
+        size_t len;
     } kexec;
 
     struct
     } kexec;
 
     struct
@@ -61,6 +61,9 @@ struct boot_handoff
 void
 boot_begin(struct boot_handoff*);
 
 void
 boot_begin(struct boot_handoff*);
 
+void
+boot_parse_cmdline(struct boot_handoff*);
+
 void
 boot_end(struct boot_handoff*);
 
 void
 boot_end(struct boot_handoff*);
 
index 68a43ead66721a7998af8dcbb9bf2f6ebd811edb..3ee6fa0ebff472b42afae3a14ab2bdda96b51813 100644 (file)
@@ -21,6 +21,9 @@
 #define stringify(v) #v
 #define stringify__(v) stringify(v)
 
 #define stringify(v) #v
 #define stringify__(v) stringify(v)
 
+#define compact __attribute__((packed))
+#define align(v) __attribute__((aligned (v)))
+
 inline static void noret
 spin()
 {
 inline static void noret
 spin()
 {
diff --git a/lunaix-os/includes/lunaix/kcmd.h b/lunaix-os/includes/lunaix/kcmd.h
new file mode 100644 (file)
index 0000000..7ec1c05
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef __LUNAIX_KCMD_H
+#define __LUNAIX_KCMD_H
+
+#include <lunaix/compiler.h>
+#include <lunaix/ds/hashtable.h>
+#include <lunaix/ds/hstr.h>
+
+struct align(64) koption {
+    struct hlist_node node;
+    struct hstr hashkey;
+    char* value;
+    char buf[0];
+};
+
+void kcmd_parse_cmdline(char* cmd_line);
+
+bool kcmd_get_option(char* key, char** out_value);
+
+
+
+#endif /* __LUNAIX_KCMD_H */
index 1383f60af7290181a01d8524b9485810c0201fcc..d50e471afedf868eebf78f78eb026038f6d985d8 100644 (file)
@@ -4,6 +4,7 @@
 #include <lunaix/mm/pmm.h>
 #include <lunaix/mm/vmm.h>
 #include <lunaix/spike.h>
 #include <lunaix/mm/pmm.h>
 #include <lunaix/mm/vmm.h>
 #include <lunaix/spike.h>
+#include <lunaix/kcmd.h>
 #include <sys/mm/mempart.h>
 
 /**
 #include <sys/mm/mempart.h>
 
 /**
@@ -88,4 +89,13 @@ boot_cleanup()
         vmm_del_mapping(VMS_SELF, (ptr_t)i);
         pmm_free_page(KERNEL_PID, (ptr_t)i);
     }
         vmm_del_mapping(VMS_SELF, (ptr_t)i);
         pmm_free_page(KERNEL_PID, (ptr_t)i);
     }
+}
+
+void
+boot_parse_cmdline(struct boot_handoff* bhctx) {
+    if (!bhctx->kexec.len) {
+        return;
+    }
+
+    kcmd_parse_cmdline(bhctx->kexec.cmdline);
 }
\ No newline at end of file
 }
\ No newline at end of file
diff --git a/lunaix-os/kernel/kcmd.c b/lunaix-os/kernel/kcmd.c
new file mode 100644 (file)
index 0000000..dc06c18
--- /dev/null
@@ -0,0 +1,139 @@
+#include <lunaix/kcmd.h>
+#include <lunaix/syslog.h>
+#include <lunaix/mm/valloc.h>
+#include <lunaix/spike.h>
+
+#include <klibc/string.h>
+
+LOG_MODULE("kcmd");
+
+struct substr {
+    int pos;
+    size_t len;
+};
+
+struct extractor {
+    char* cmdline;
+    int pos;
+
+    struct substr key;
+    struct substr val;
+};
+
+static DECLARE_HASHTABLE(options, 8);
+
+static bool
+extract_next_option(struct extractor* ctx) 
+{
+#define is_valid_char(c) ((unsigned int)(((c) & ~0x80) - 'A') < 'Z')
+#define PARSE_KEY 0
+#define PARSE_VAL 1
+    char c;
+    int i = ctx->pos, state = PARSE_KEY;
+    struct substr* s = &ctx->key;
+    s->len = 0;
+    s->pos = i;
+
+    while((c = ctx->cmdline[i++])) {
+        if (c == ' ') {
+            while ((c = ctx->cmdline[i++]) && c == ' ');
+            break;
+        }
+
+        if (c == '=') {
+            if (state == PARSE_KEY) {
+                if (s->len == 0) {
+                    WARN("unexpected character: '=' (pos:%d). skipping...\n", i + 1);
+                    while ((c = ctx->cmdline[i++]) && c != ' ');
+                    break;
+                }
+                state = PARSE_VAL;
+                s = &ctx->val;
+                s->len = 0;
+                s->pos = i + 1;
+                continue;
+            }
+        }
+
+        while ((c = ctx->cmdline[i++]) && c != ' ') {
+            s->len++;
+        }
+
+        i--;
+    }
+
+    ctx->pos = i;
+
+    return !!c;
+}
+
+#define MAX_KEYSIZE 16
+
+void 
+kcmd_parse_cmdline(char* cmd_line) 
+{
+    struct extractor ctx = { .cmdline = cmd_line, .pos = 0 };
+    
+    while(extract_next_option(&ctx)) {
+        if (!ctx.key.len) {
+            continue;
+        }
+        
+        size_t maxlen = sizeof(struct koption) - offsetof(struct koption, buf);
+
+        if (ctx.key.len >= maxlen) {
+            WARN("option key too big. skipping...\n");
+            continue;
+        }
+
+        if (ctx.val.len >= 256) {
+            WARN("option value too big. skipping...\n");
+            continue;
+        }
+
+        struct koption* kopt = 
+            (struct koption*) vzalloc(sizeof(*kopt));
+        
+        memcpy(kopt->buf, &cmd_line[ctx.key.pos], ctx.key.len);
+        
+        if (ctx.val.len) {
+            kopt->value = &kopt->buf[ctx.key.len + 1];
+            size_t max_val_len = maxlen - ctx.key.len;
+
+            // value too big to fit inplace
+            if (max_val_len <= ctx.val.len) {
+                kopt->value = vzalloc(ctx.val.len + 1);
+            }
+
+            memcpy(kopt->value, &cmd_line[ctx.val.pos], ctx.val.len);
+        }
+        
+        kopt->hashkey = HSTR(kopt->buf, ctx.key.len);
+        hstr_rehash(&kopt->hashkey, HSTR_FULL_HASH);
+
+        hashtable_hash_in(options, &kopt->node, kopt->hashkey.hash);
+    }
+}
+
+bool 
+kcmd_get_option(char* key, char** out_value) 
+{
+    struct hstr hkey = HSTR(key, strlen(key));
+    hstr_rehash(&hkey, HSTR_FULL_HASH);
+
+    struct koption *pos, *n;
+    hashtable_hash_foreach(options, hkey.hash, pos, n, node) {
+        if (HSTR_EQ(&pos->hashkey, &hkey)) {
+            goto found;
+        }
+    }
+
+    return false;
+
+found:
+    if (out_value) {
+        *out_value = pos->value;
+    }
+
+    return true;
+}
\ No newline at end of file
index 501c8f45a14063c34454d2d223785b18e48d7982..b21a7596f97afd39b4ee393d7b1c26d41fff4933 100644 (file)
@@ -49,6 +49,8 @@ kernel_bootstrap(struct boot_handoff* bhctx)
     /* Setup kernel memory layout and services */
     kmem_init(bhctx);
 
     /* Setup kernel memory layout and services */
     kmem_init(bhctx);
 
+    boot_parse_cmdline(bhctx);
+
     /* Prepare stack trace environment */
     trace_modksyms_init(bhctx);
 
     /* Prepare stack trace environment */
     trace_modksyms_init(bhctx);