From: Minep Date: Sat, 9 Dec 2023 20:56:32 +0000 (+0000) Subject: feat: a better boot command line parser X-Git-Url: https://scm.lunaixsky.com/lunaix-os.git/commitdiff_plain/64e5fa9a495e388c922157b9a616204c299f5e05?ds=sidebyside feat: a better boot command line parser fix: bugs in term interfacing --- diff --git a/lunaix-os/arch/i386/boot/mb_parser.c b/lunaix-os/arch/i386/boot/mb_parser.c index 81e2716..64a4051 100644 --- a/lunaix-os/arch/i386/boot/mb_parser.c +++ b/lunaix-os/arch/i386/boot/mb_parser.c @@ -60,28 +60,9 @@ mb_parse_cmdline(struct boot_handoff* bhctx, void* buffer, char* cmdline) } 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 @@ -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]; + + *bhctx = (struct boot_handoff){ }; /* Parse memory map */ if ((mb->flags & MULTIBOOT_INFO_MEM_MAP)) { diff --git a/lunaix-os/hal/char/serial.c b/lunaix-os/hal/char/serial.c index d353a16..1dbdb68 100644 --- a/lunaix-os/hal/char/serial.c +++ b/lunaix-os/hal/char/serial.c @@ -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; + 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; diff --git a/lunaix-os/hal/char/uart/16550_base.c b/lunaix-os/hal/char/uart/16550_base.c index e3dda36..8ec752e 100644 --- a/lunaix-os/hal/char/uart/16550_base.c +++ b/lunaix-os/hal/char/uart/16550_base.c @@ -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); - if (iv == pos->iv && (is == UART_DATA_OK || is == UART_CHR_TIMEOUT)) { + if (iv == pos->iv && (is == UART_CHR_TIMEOUT)) { goto done; } } @@ -91,5 +91,7 @@ done: } serial_accept_buffer(pos->sdev, tmpbuf, i); + serial_accept_one(pos->sdev, 0); + serial_end_recv(pos->sdev); } diff --git a/lunaix-os/hal/term/lcntls/lcntl.c b/lunaix-os/hal/term/lcntls/lcntl.c index aab02c0..fdaf244 100644 --- a/lunaix-os/hal/term/lcntls/lcntl.c +++ b/lunaix-os/hal/term/lcntls/lcntl.c @@ -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; - bool should_flush = false; 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 ((_if & _INLCR) || (_of & (_ONLRET | _ONLCR))) { + if ((_if & _INLCR) || (_of & (_ONLRET))) { c = '\r'; } } if (c == '\0') { + if ((_if & _IGNBRK)) { + continue; + } + if ((_if & _BRKINT)) { raise_sig(tdev, lbuf, SIGINT); break; } - - if ((_if & _IGNBRK)) { - continue; - } } 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); } - should_flush = true; } if (out) { - goto put_char; + goto do_out; } // 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); @@ -117,18 +114,28 @@ lcntl_transform_seq(struct term* tdev, struct linebuffer* lbuf, bool out) 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); } - 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: @@ -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); } @@ -157,5 +164,5 @@ lcntl_transform_inseq(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 diff --git a/lunaix-os/hal/term/term.c b/lunaix-os/hal/term/term.c index 289179d..0c404a5 100644 --- a/lunaix-os/hal/term/term.c +++ b/lunaix-os/hal/term/term.c @@ -145,7 +145,7 @@ tdev_do_read(struct device* dev, void* buf, size_t offset, size_t len) 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) @@ -175,8 +175,9 @@ term_create(struct device* chardev, char* suffix) 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; diff --git a/lunaix-os/hal/term/term_io.c b/lunaix-os/hal/term/term_io.c index 729e549..8042e3b 100644 --- a/lunaix-os/hal/term/term_io.c +++ b/lunaix-os/hal/term/term_io.c @@ -61,7 +61,6 @@ term_read_noncano(struct term* tdev) { struct device* chdev = tdev->chdev; return do_read_raw(tdev); - ; } static int @@ -95,7 +94,7 @@ int term_flush(struct term* tdev) { if ((tdev->oflags & _OPOST)) { - lcntl_transform_inseq(tdev); + lcntl_transform_outseq(tdev); } struct linebuffer* line_out = &tdev->line_out; diff --git a/lunaix-os/includes/klibc/stdlib.h b/lunaix-os/includes/klibc/stdlib.h index 05509cd..a6c83a9 100644 --- a/lunaix-os/includes/klibc/stdlib.h +++ b/lunaix-os/includes/klibc/stdlib.h @@ -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* itoa(int value, char* str, int base); #endif /* __LUNAIX_STDLIB_H */ diff --git a/lunaix-os/includes/lunaix/boot_generic.h b/lunaix-os/includes/lunaix/boot_generic.h index 93e9e3d..a229c45 100644 --- a/lunaix-os/includes/lunaix/boot_generic.h +++ b/lunaix-os/includes/lunaix/boot_generic.h @@ -41,8 +41,8 @@ struct boot_handoff ptr_t ksections; size_t size; - char** argv; - size_t argc; + char* cmdline; + size_t len; } kexec; struct @@ -61,6 +61,9 @@ struct boot_handoff void boot_begin(struct boot_handoff*); +void +boot_parse_cmdline(struct boot_handoff*); + void boot_end(struct boot_handoff*); diff --git a/lunaix-os/includes/lunaix/compiler.h b/lunaix-os/includes/lunaix/compiler.h index 68a43ea..3ee6fa0 100644 --- a/lunaix-os/includes/lunaix/compiler.h +++ b/lunaix-os/includes/lunaix/compiler.h @@ -21,6 +21,9 @@ #define stringify(v) #v #define stringify__(v) stringify(v) +#define compact __attribute__((packed)) +#define align(v) __attribute__((aligned (v))) + 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 index 0000000..7ec1c05 --- /dev/null +++ b/lunaix-os/includes/lunaix/kcmd.h @@ -0,0 +1,21 @@ +#ifndef __LUNAIX_KCMD_H +#define __LUNAIX_KCMD_H + +#include +#include +#include + +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 */ diff --git a/lunaix-os/kernel/boot_helper.c b/lunaix-os/kernel/boot_helper.c index 1383f60..d50e471 100644 --- a/lunaix-os/kernel/boot_helper.c +++ b/lunaix-os/kernel/boot_helper.c @@ -4,6 +4,7 @@ #include #include #include +#include #include /** @@ -88,4 +89,13 @@ boot_cleanup() 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 diff --git a/lunaix-os/kernel/kcmd.c b/lunaix-os/kernel/kcmd.c new file mode 100644 index 0000000..dc06c18 --- /dev/null +++ b/lunaix-os/kernel/kcmd.c @@ -0,0 +1,139 @@ +#include +#include +#include +#include + +#include + +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 diff --git a/lunaix-os/kernel/kinit.c b/lunaix-os/kernel/kinit.c index 501c8f4..b21a759 100644 --- a/lunaix-os/kernel/kinit.c +++ b/lunaix-os/kernel/kinit.c @@ -49,6 +49,8 @@ kernel_bootstrap(struct boot_handoff* bhctx) /* Setup kernel memory layout and services */ kmem_init(bhctx); + boot_parse_cmdline(bhctx); + /* Prepare stack trace environment */ trace_modksyms_init(bhctx);