}
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
{
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)) {
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;
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;
}
}
}
serial_accept_buffer(pos->sdev, tmpbuf, i);
+ serial_accept_one(pos->sdev, 0);
+
serial_end_recv(pos->sdev);
}
_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;
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') {
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);
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:
}
}
- if (should_flush && !(_lf & _NOFLSH)) {
+ if (!rbuffer_empty(output) && !(_lf & _NOFLSH)) {
term_flush(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
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)
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;
{
struct device* chdev = tdev->chdev;
return do_read_raw(tdev);
- ;
}
static 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;
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 */
ptr_t ksections;
size_t size;
- char** argv;
- size_t argc;
+ char* cmdline;
+ size_t len;
} kexec;
struct
void
boot_begin(struct boot_handoff*);
+void
+boot_parse_cmdline(struct boot_handoff*);
+
void
boot_end(struct boot_handoff*);
#define stringify(v) #v
#define stringify__(v) stringify(v)
+#define compact __attribute__((packed))
+#define align(v) __attribute__((aligned (v)))
+
inline static void noret
spin()
{
--- /dev/null
+#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 */
#include <lunaix/mm/pmm.h>
#include <lunaix/mm/vmm.h>
#include <lunaix/spike.h>
+#include <lunaix/kcmd.h>
#include <sys/mm/mempart.h>
/**
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
--- /dev/null
+#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
/* Setup kernel memory layout and services */
kmem_init(bhctx);
+ boot_parse_cmdline(bhctx);
+
/* Prepare stack trace environment */
trace_modksyms_init(bhctx);