diff --git a/include/sys/thread.h b/include/sys/thread.h index e0e63d4..d576ebd 100644 --- a/include/sys/thread.h +++ b/include/sys/thread.h @@ -21,6 +21,9 @@ struct thread { __plat_thread data; struct image_info image; + // Arguments are stored here + uintptr_t argp_page; + uintptr_t argp_page_phys; uint64_t flags; uint32_t pid; diff --git a/sys/amd64/sys/thread.c b/sys/amd64/sys/thread.c index ee23138..96504d5 100644 --- a/sys/amd64/sys/thread.c +++ b/sys/amd64/sys/thread.c @@ -1,6 +1,7 @@ #include "sys/amd64/mm/mm.h" #include "sys/amd64/mm/phys.h" #include "sys/amd64/mm/pool.h" +#include "sys/amd64/mm/map.h" #include "sys/binfmt_elf.h" #include "sys/amd64/cpu.h" #include "sys/assert.h" @@ -52,6 +53,14 @@ int thread_init( t->data.data_flags |= 2 /* Don't free ustack */; } + if (!(flags & THREAD_KERNEL)) { + _assert((t->argp_page_phys = amd64_phys_alloc_page()) != MM_NADDR); + t->argp_page = 0x100000000; + _assert(!amd64_map_single(space, t->argp_page, t->argp_page_phys, 1 | (1 << 1) | (1 << 2))); + } else { + t->argp_page = MM_NADDR; + } + t->data.stack0_base = rsp0_base; t->data.stack0_size = rsp0_size; t->data.rsp0 = t->data.stack0_base + t->data.stack0_size - sizeof(struct cpu_context); @@ -61,7 +70,6 @@ int thread_init( t->data.stack3_size = rsp3_size; } - // Alloc signal handling kstack void *kstack_sig = kmalloc(THREAD_KSTACK_SIZE); _assert(kstack_sig); @@ -206,6 +214,36 @@ int sys_execve(const char *filename, const char *const argv[], const char *const mm_space_t space = thr->space; + // Buffer page used for argp construction + // Before we released the old memory, copy + // the needed stuff from it + uintptr_t argp_page_phys = amd64_phys_alloc_page(); + _assert(argp_page_phys != MM_NADDR); + char **dst_argp = (char **) MM_VIRTUALIZE(argp_page_phys); + size_t argp_offset = 0, argp_offset2 = 0; + size_t argc = 0; + if (argv) { + while (argv[argc]) { + dst_argp[argc] = (char *) argp_offset2; + argp_offset2 += strlen(argv[argc]) + 1; + if (argp_offset2 >= 4096) { + panic("argp buffer overflow\n"); + } + ++argc; + } + dst_argp[argc] = NULL; + argp_offset = (size_t) &dst_argp[argc + 1]; + // Convert offsets to pointers + for (size_t i = 0; i < argc; ++i) { + char *ent = dst_argp[i] + argp_offset; + dst_argp[i] = (char *) (MM_PHYS(ent) - argp_page_phys); + strcpy(ent, argv[i]); + kdebug("Cloning argument: %s -> %p\n", ent, dst_argp[i]); + } + } else { + dst_argp[0] = NULL; + } + // 1. Discard memory // XXX: And this is why I need CoW mm_space_release(space); @@ -221,7 +259,20 @@ int sys_execve(const char *filename, const char *const argv[], const char *const THREAD_CTX_ONLY, NULL ) == 0); + // Revirtualize offsets + for (size_t i = 0; i < argc; ++i) { + dst_argp[i] = (char *) ((uintptr_t) dst_argp[i] + thr->argp_page); + } + // Copy the data block + memcpy((void *) MM_VIRTUALIZE(thr->argp_page_phys), dst_argp, 4096); + amd64_phys_free(argp_page_phys); + for (size_t i = 0; i < argc; ++i) { + kdebug("%p[%d] = %p\n", thr->argp_page, i, ((char **) MM_VIRTUALIZE(thr->argp_page_phys))[i]); + } + kdebug("argp buffer = %p\n", thr->argp_page); + struct cpu_context *ctx = (struct cpu_context *) thr->data.rsp0; + ctx->rdi = thr->argp_page; // 3. Load new binary _assert(elf_load(thr, file_buf) == 0); diff --git a/sys/amd64/syscall.c b/sys/amd64/syscall.c index 867c360..5530b01 100644 --- a/sys/amd64/syscall.c +++ b/sys/amd64/syscall.c @@ -49,7 +49,7 @@ intptr_t amd64_syscall(uintptr_t rdi, uintptr_t rsi, uintptr_t rdx, uintptr_t rc case SYSCALL_NR_STAT: return sys_stat((const char *) rdi, (struct stat *) rsi); case SYSCALL_NR_EXECVE: - return sys_execve((const char *) rdi, NULL, NULL); + return sys_execve((const char *) rdi, (const char **) rsi, NULL); case SYSCALL_NR_READDIR: return sys_readdir((int) rdi, (struct dirent *) rsi); case SYSCALL_NR_GETCWD: diff --git a/usr/hello.c b/usr/hello.c index 7f1f87d..46b9da6 100644 --- a/usr/hello.c +++ b/usr/hello.c @@ -1,6 +1,95 @@ +#include +#include #include -int main() { - printf("Hello!\n"); +#define LINE_LENGTH 16 + +static void line_print(size_t off, const char *line, size_t len) { + printf("%08x: ", off); + for (size_t i = 0; i < LINE_LENGTH; ++i) { + // XXX: This is needed because I didn't implement h/hh modifiers in printf + uint64_t byte = (uint64_t) line[i] & 0xFF; + if (i < len) { + printf("%02x", byte); + } else { + printf(" "); + } + if (i % 2) { + printf(" "); + } + } + printf("| "); + for (size_t i = 0; i < len; ++i) { + // TODO: isprint? + if (line[i] >= ' ') { + printf("%c", line[i]); + } else { + printf("."); + } + } + printf("\n"); +} + +int main(int argc, char **argv) { + int fd; + const char *path; + char buf[512]; + char line[LINE_LENGTH]; + ssize_t bread; + size_t offset; + size_t linel; + size_t n_full_zero; + + // TODO: first argument is used for the program name itself + if (argc != 1) { + printf("wrong\n"); + return -1; + } + + path = argv[0]; + printf("open file %s\n", path); + + if ((fd = open(path, O_RDONLY, 0)) < 0) { + perror(path); + return -1; + } + + offset = 0; + linel = 0; + n_full_zero = 0; + while ((bread = read(fd, buf, sizeof(buf))) > 0) { + for (size_t i = 0; i < bread; ++i) { + line[linel++] = buf[i]; + if (linel == LINE_LENGTH) { + // Check if the line is all zeros + int all_zeros = 1; + for (size_t j = 0; j < LINE_LENGTH; ++j) { + if (line[j]) { + all_zeros = 0; + break; + } + } + if (all_zeros) { + ++n_full_zero; + } else { + n_full_zero = 0; + } + + if (n_full_zero < 3) { + line_print(offset, line, linel); + } else if (n_full_zero == 3) { + printf(" ... \n"); + } + offset += LINE_LENGTH; + linel = 0; + } + } + } + if (linel) { + line_print(offset, line, linel); + } + + close(fd); + return 0; } diff --git a/usr/init.c b/usr/init.c index a013bf9..e4f49a8 100644 --- a/usr/init.c +++ b/usr/init.c @@ -57,13 +57,17 @@ static int cmd_exec(const char *cmd) { return 0; } - if (!strcmp(cmd, "hello")) { + if (!strcmp(cmd, "hello") || !strncmp(cmd, "hello ", 6)) { int res; if ((res = fork()) == 0) { + const char *argument = cmd[5] ? &cmd[6] : "nothing"; printf("In child\n"); + const char *argp[] = { + argument, 0 + }; - res = execve("/hello", NULL, NULL); + res = execve("/hello", argp, NULL); if (res < 0) { perror("execve()"); diff --git a/usr/libc/crt0.S b/usr/libc/crt0.S index 7476a2f..9d23bfd 100644 --- a/usr/libc/crt0.S +++ b/usr/libc/crt0.S @@ -2,8 +2,7 @@ .global _start .type _start, %function // Arguments: -// %rdi - argc (well, not quite yet) -// %rsi - argv +// %rdi - argp _start: movq $0, %rbp // For callee linkage @@ -11,12 +10,13 @@ _start: pushq %rbp movq %rsp, %rbp + push %rdi call __libc_init call _init - // Ignore %rdi/%rsi for now - xorq %rdi, %rdi + mov __libc_argc, %rdi + pop %rsi // exit(main(argc, argv)) call main diff --git a/usr/libc/global.c b/usr/libc/global.c index b84c61b..1c04fb7 100644 --- a/usr/libc/global.c +++ b/usr/libc/global.c @@ -1,3 +1,4 @@ #include "bits/global.h" void *__cur_brk; +uint64_t __libc_argc = 0; diff --git a/usr/libc/include/bits/global.h b/usr/libc/include/bits/global.h index 01f7869..6b0435b 100644 --- a/usr/libc/include/bits/global.h +++ b/usr/libc/include/bits/global.h @@ -1,3 +1,5 @@ #pragma once +#include extern void *__cur_brk; +extern uint64_t __libc_argc; diff --git a/usr/libc/init.c b/usr/libc/init.c index bc28c2b..bed2401 100644 --- a/usr/libc/init.c +++ b/usr/libc/init.c @@ -3,9 +3,17 @@ extern char __heap_start; extern void __libc_signal_init(void); +static const char *argp_dummy[] = { 0 }; -void __libc_init(void) { +void __libc_init(char **argp) { __libc_signal_init(); + __libc_argc = 0; + if (argp) { + while (argp[__libc_argc]) { + printf("%s\n", argp[__libc_argc]); + ++__libc_argc; + } + } __cur_brk = &__heap_start; errno = 0; }