From e7cddc3e7e890762a1d08eec53744db8b122025c Mon Sep 17 00:00:00 2001 From: Stefan Lankes Date: Sat, 3 Oct 2015 01:43:17 +0200 Subject: [PATCH] add support of proxy processes --- hermit/arch/x86/kernel/tasks.c | 167 +++++++++++++++++++++++----- hermit/include/hermit/tasks.h | 16 ++- hermit/include/hermit/tasks_types.h | 2 + hermit/kernel/main.c | 85 +++++++++++++- hermit/kernel/syscall.c | 137 +++++++++++++++++++++-- hermit/kernel/tasks.c | 15 +-- hermit/lwip | 2 +- hermit/tools/Makefile | 2 +- 8 files changed, 375 insertions(+), 51 deletions(-) diff --git a/hermit/arch/x86/kernel/tasks.c b/hermit/arch/x86/kernel/tasks.c index 8e16acd1b..6029939b8 100644 --- a/hermit/arch/x86/kernel/tasks.c +++ b/hermit/arch/x86/kernel/tasks.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, Stefan Lankes, RWTH Aachen University + * Copyright (c) 2010-2015, Stefan Lankes, RWTH Aachen University * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -38,6 +38,10 @@ #include #include +#include +#include +#include + #define START_ADDRESS 0x40200000 /* @@ -142,7 +146,7 @@ int create_default_frame(task_t* task, entry_point_t ep, void* arg, uint32_t cor size_t state_size; if (BUILTIN_EXPECT(!task, 0)) - return -EINVAL; + return -EINVAL; if (BUILTIN_EXPECT(!task->stack, 0)) return -EINVAL; @@ -162,7 +166,7 @@ int create_default_frame(task_t* task, entry_point_t ep, void* arg, uint32_t cor * This procedure cleans the task after exit. */ *stack = (size_t) leave_kernel_task; - /* Next bunch on the stack is the initial register state. + /* Next bunch on the stack is the initial register state. * The stack must look like the stack of a task which was * scheduled away previously. */ state_size = sizeof(struct state); @@ -186,7 +190,7 @@ int create_default_frame(task_t* task, entry_point_t ep, void* arg, uint32_t cor } stptr->cs = 0x08; stptr->ss = 0x10; - stptr->gs = core_id * ((size_t) &percore_end0 - (size_t) &percore_start); + stptr->gs = core_id * ((size_t) &percore_end0 - (size_t) &percore_start); stptr->rflags = 0x1202; stptr->userrsp = stptr->rsp; @@ -203,6 +207,10 @@ int create_default_frame(task_t* task, entry_point_t ep, void* arg, uint32_t cor typedef struct { /// Points to the node with the executable in the file system vfs_node_t* node; + /// Points to a copy of the executable + char* executable; + /// Socket descriptor if have no file node + int sd; /// Argument count int argc; /// Environment var count @@ -226,27 +234,29 @@ static int load_task(load_args_t* largs) elf_header_t header; elf_program_header_t prog_header; //elf_section_header_t sec_header; - ///!!! kfree is missing! - fildes_t *file = kmalloc(sizeof(fildes_t)); - file->offset = 0; - file->flags = 0; - int ret = -EINVAL; - - //TODO: init the hole fildes_t struct! + fildes_t file; task_t* curr_task = per_core(current_task); + int ret = -EINVAL; if (!largs) return -EINVAL; - file->node = largs->node; - if (!file->node) + if (largs->node) { + file.node = largs->node; + file.offset = 0; + file.flags = 0; + } else if (!largs->executable || (largs->sd < 0)) return -EINVAL; - ret = read_fs(file, (uint8_t*)&header, sizeof(elf_header_t)); - if (ret < 0) { - kprintf("read_fs failed: %d\n", ret); - goto Lerr; - } + curr_task->sd = largs->sd; + + if (largs->node) { + ret = read_fs(&file, (uint8_t*)&header, sizeof(elf_header_t)); + if (ret < 0) { + kprintf("read_fs failed: %d\n", ret); + goto Lerr; + } + } else memcpy(&header, largs->executable, sizeof(elf_header_t)); if (BUILTIN_EXPECT(header.ident.magic != ELF_MAGIC, 0)) goto Linvalid; @@ -268,11 +278,13 @@ static int load_task(load_args_t* largs) // interpret program header table for (i=0; ioffset = header.ph_offset+i*header.ph_entry_size; - if (read_fs(file, (uint8_t*)&prog_header, sizeof(elf_program_header_t)) == 0) { - kprintf("Could not read programm header!\n"); - continue; - } + if (largs->node) { + file.offset = header.ph_offset+i*header.ph_entry_size; + if (read_fs(&file, (uint8_t*)&prog_header, sizeof(elf_program_header_t)) == 0) { + kprintf("Could not read programm header!\n"); + continue; + } + } else memcpy(&prog_header, largs->executable + header.ph_offset+i*header.ph_entry_size, sizeof(elf_program_header_t)); switch(prog_header.type) { @@ -313,9 +325,12 @@ static int load_task(load_args_t* largs) heap = prog_header.virt_addr + prog_header.mem_size; // load program - file->offset = prog_header.offset; //kprintf("read programm 0x%zx - 0x%zx\n", prog_header.virt_addr, prog_header.virt_addr + prog_header.file_size); - read_fs(file, (uint8_t*)prog_header.virt_addr, prog_header.file_size); + if (largs->node) { + file.offset = prog_header.offset; + read_fs(&file, (uint8_t*)prog_header.virt_addr, prog_header.file_size); + } else + memcpy((uint8_t*)prog_header.virt_addr, largs->executable + prog_header.offset, prog_header.file_size); if (!(prog_header.flags & PF_W)) page_set_flags(prog_header.virt_addr, npages, flags); @@ -463,6 +478,8 @@ static int load_task(load_args_t* largs) offset -= sizeof(ssize_t); *((ssize_t*) (stack+offset)) = (ssize_t) largs->argc; + if (largs->executable) + kfree(largs->executable); kfree(largs); // clear fpu state => currently not supported @@ -492,6 +509,10 @@ Linvalid: kprintf("program entry point 0x%lx\n", (size_t) header.entry); Lerr: + if (largs->executable) + kfree(largs->executable); + kfree(largs); + return ret; } @@ -499,6 +520,8 @@ Lerr: * which want to have a start function and argument list */ static int user_entry(void* arg) { + load_args_t* largs = (load_args_t*) arg; + int ret; finish_task_switch(); @@ -506,12 +529,10 @@ static int user_entry(void* arg) if (BUILTIN_EXPECT(!arg, 0)) return -EINVAL; - ret = load_task((load_args_t*) arg); + ret = load_task(largs); if (ret) kprintf("Load task failed: %d\n", ret); - kfree(arg); - sys_exit(ret); while(1) { @@ -558,6 +579,8 @@ int create_user_task_on_core(tid_t* id, const char* fname, char** argv, uint8_t return -ENOMEM; load_args->node = node; load_args->argc = argc; + load_args->sd = -1; + load_args->executable = NULL; load_args->envc = 0; dest = load_args->buffer; for (i=0; inode = NULL; + load_args->executable = NULL; + load_args->sd = sd; + load_args->argc = argc; + load_args->envc = 0; + dest = load_args->buffer; + + for(i=0, total_len=0; i= MAX_ARGS) + goto out; + + j=0; + while(j < len) + { + ret = read(sd, dest, len-j); + if (ret < 0) + goto out; + dest += ret; + j += ret; + } + } + + // terminate array with a NULL pointer + *dest = 0; + + ret = read(sd, &len, sizeof(int)); + if ((ret != sizeof(int)) || (len <= 0)) + goto out; + kprintf("length of the executable: %d\n", len); + + load_args->executable = kmalloc(len); + if (!load_args->executable) { + err = -ENOMEM; + goto out; + } + + j=0; + while(j < len) + { + ret = read(sd, load_args->executable+j, len-j); + if (ret < 0) + goto out; + j += ret; + } + + /* create new task */ + return create_task(id, user_entry, load_args, prio, core_id); + +out: + kprintf("Unable to load task: %d\n", err); + + if (load_args && load_args->executable) + kfree(load_args->executable); + if (load_args) + kfree(load_args); + + closesocket(sd); + counter++; + + return err; +} diff --git a/hermit/include/hermit/tasks.h b/hermit/include/hermit/tasks.h index af4c9cc84..2e3948ac7 100644 --- a/hermit/include/hermit/tasks.h +++ b/hermit/include/hermit/tasks.h @@ -132,6 +132,7 @@ int create_kernel_task_on_core(tid_t* id, entry_point_t ep, void* args, uint8_t * @param id The value behind this pointer will be set to the new task's id * @param fname Filename of the executable to start the task with * @param argv Pointer to arguments array + * @param prio Desired priority of the new kernel task * * @return * - 0 on success @@ -139,11 +140,24 @@ int create_kernel_task_on_core(tid_t* id, entry_point_t ep, void* args, uint8_t */ int create_user_task(tid_t* id, const char* fame, char** argv, uint8_t prio); +/** @brief Create a user level task on the current core. + * + * @param id The value behind this pointer will be set to the new task's id + * @param sd Socket descriptor to load and to start the executable + * @param prio Desired priority of the new kernel task + * + * @return + * - 0 on success + * - -EINVAL (-22) or -ENOMEM (-12)on failure + */ +int create_user_task_form_socket(tid_t* id, int sd, uint8_t prio); + /** @brief Create a user level task. * * @param id The value behind this pointer will be set to the new task's id - * @param fname Filename of the executable to start the task with + * @param sd Valid socket descriptor to a TCP/IP connection * @param argv Pointer to arguments array + * @param prio Desired priority of the new kernel task * @param core_id Start the new task on the core with this id * * @return diff --git a/hermit/include/hermit/tasks_types.h b/hermit/include/hermit/tasks_types.h index 0239b15b5..19105a19a 100644 --- a/hermit/include/hermit/tasks_types.h +++ b/hermit/include/hermit/tasks_types.h @@ -112,6 +112,8 @@ typedef struct task { size_t tls_mem_size; /// TLS file size size_t tls_file_size; + /// Socket descriptor to the proxy + int sd; /// LwIP error code int lwip_err; /// FPU state diff --git a/hermit/kernel/main.c b/hermit/kernel/main.c index 64b5857c2..4b4d9307e 100644 --- a/hermit/kernel/main.c +++ b/hermit/kernel/main.c @@ -48,11 +48,18 @@ #include #include #include +#include +#include +#include #include #include -static struct netif mmnif_netif; +#define HERMIT_PORT 0x494F +#define HEMRIT_MAGIC 0x7E317 +static struct netif mmnif_netif; +static const int sobufsize = 131072; +volatile int8_t shutdown = 0; /* * Note that linker symbols are not variables, they have no memory allocated for * maintaining a value, rather their address is their value. @@ -76,6 +83,7 @@ extern atomic_int32_t possible_cpus; extern int32_t isle; extern int32_t possible_isles; +#if 0 static int foo(void* arg) { int i; @@ -87,6 +95,7 @@ static int foo(void* arg) return 0; } +#endif static int hermit_init(void) { @@ -173,6 +182,14 @@ static int init_netifs(void) return 0; } +static int network_shutdown(void) +{ + mmnif_shutdown(); + netifapi_netif_set_down(&mmnif_netif); + + return 0; +} + #if MAX_CORES > 1 int smp_main(void) { @@ -202,13 +219,15 @@ int smp_main(void) // init task => creates all other tasks an initialize the LwIP static int initd(void* arg) { + int s, c, len, err; + int32_t magic; + struct sockaddr_in server, client; + //char* argv1[] = {"/bin/hello", NULL}; //char* argv2[] = {"/bin/jacobi", NULL}; //char* argv3[] = {"/bin/stream", NULL}; //char* argv4[] = {"/bin/thr_hello", NULL}; - init_netifs(); - //create_kernel_task(NULL, foo, "foo1", NORMAL_PRIO); //create_kernel_task(NULL, foo, "foo2", NORMAL_PRIO); //create_user_task(NULL, "/bin/hello", argv1, NORMAL_PRIO); @@ -217,6 +236,66 @@ static int initd(void* arg) //create_user_task(NULL, "/bin/stream", argv3, NORMAL_PRIO); //create_user_task(NULL, "/bin/thr_hello", argv4, NORMAL_PRIO); + init_netifs(); + + s = socket(PF_INET , SOCK_STREAM , 0); + if (s < 0) { + kprintf("socket failed: %d\n", server); + return -1; + } + + // prepare the sockaddr_in structure + memset((char *) &server, 0x00, sizeof(server)); + server.sin_family = AF_INET; + server.sin_addr.s_addr = INADDR_ANY; + server.sin_port = htons(HERMIT_PORT); + + if ((err = bind(s, (struct sockaddr *) &server, sizeof(server))) < 0) + { + kprintf("bind failed: %d\n", errno); + closesocket(s); + return -1; + } + + if ((err = listen(s, 2)) < 0) + { + kprintf("listen failed: %d\n", errno); + closesocket(s); + return -1; + } + + len = sizeof(struct sockaddr_in); + while(!shutdown) + { + kputs("TCP server listening.\n"); + + if ((c = accept(s, (struct sockaddr *)&client, (socklen_t*)&len)) < 0) + { + kprintf("accept faild: %d\n", errno); + closesocket(s); + return -1; + } + + kputs("Establish IP connection\n"); + + setsockopt(c, SOL_SOCKET, SO_RCVBUF, (char *) &sobufsize, sizeof(sobufsize)); + setsockopt(c, SOL_SOCKET, SO_SNDBUF, (char *) &sobufsize, sizeof(sobufsize)); + + read(c, &magic, sizeof(int32_t)); + if (magic != HEMRIT_MAGIC) + { + kprintf("Invalid magic number %d\n", magic); + closesocket(c); + continue; + } + + create_user_task_form_socket(NULL, c, NORMAL_PRIO); + } + + closesocket(s); + + network_shutdown(); + return 0; } diff --git a/hermit/kernel/syscall.c b/hermit/kernel/syscall.c index 3994b8f31..cafc66897 100644 --- a/hermit/kernel/syscall.c +++ b/hermit/kernel/syscall.c @@ -34,6 +34,12 @@ #include #include +#include +#include +#include + +static spinlock_t lwip_lock = SPINLOCK_INIT; + static tid_t sys_getpid(void) { task_t* task = per_core(current_task); @@ -53,19 +59,74 @@ static void sys_yield(void) reschedule(); } +void NORETURN do_exit(int arg); + +/** @brief To be called by the systemcall to exit tasks */ +void NORETURN sys_exit(int arg) +{ + task_t* task = per_core(current_task); + int sysnr = __NR_exit; + + if (task->sd >= 0) + { + spinlock_lock(&lwip_lock); + write(task->sd, &sysnr, sizeof(int)); + write(task->sd, &arg, sizeof(int)); + spinlock_unlock(&lwip_lock); + + closesocket(task->sd); + task->sd = -1; + } + + do_exit(arg); +} + static int sys_write(int fd, const char* buf, size_t len) { + task_t* task = per_core(current_task); + int ret, sysnr = __NR_write; size_t i; - //TODO: Currently, we ignore the file descriptor - if (BUILTIN_EXPECT(!buf, 0)) return -1; - for(i=0; isd < 0) + { + for(i=0; isd, &sysnr, sizeof(int)); + if (ret < 0) + goto out; + + ret = write(task->sd, &fd, sizeof(int)); + if (ret < 0) + goto out; + + ret = write(task->sd, &len, sizeof(size_t)); + if (ret < 0) + goto out; + + i=0; + while(isd, (char*)buf+i, len-i); + if (ret < 0) + goto out; + i += ret; + } + + ret = len; + +out: + spinlock_unlock(&lwip_lock); + + return ret; } static ssize_t sys_sbrk(int incr) @@ -96,12 +157,72 @@ static ssize_t sys_sbrk(int incr) static int sys_open(const char* name, int flags, int mode) { - return 0; + task_t* task = per_core(current_task); + int i, ret, sysnr = __NR_open; + size_t len = strlen(name+1); + + if (task->sd < 0) + return 0; + + len = strlen(name+1); + + spinlock_lock(&lwip_lock); + + ret = write(task->sd, &sysnr, sizeof(int)); + if (ret < 0) + goto out; + + ret = write(task->sd, &len, sizeof(size_t)); + if (ret < 0) + goto out; + + i=0; + while(isd, name+i, len-i); + if (ret < 0) + goto out; + i += ret; + } + + ret = write(task->sd, &flags, sizeof(int)); + if (ret < 0) + goto out; + + ret = write(task->sd, &mode, sizeof(int)); + if (ret < 0) + goto out; + + read(task->sd, &ret, sizeof(int)); + +out: + spinlock_unlock(&lwip_lock); + + return ret; } static int sys_close(int fd) { - return 0; + task_t* task = per_core(current_task); + int ret, sysnr = __NR_close; + + if (task->sd < 0) + return 0; + + spinlock_lock(&lwip_lock); + + ret = write(task->sd, &sysnr, sizeof(int)); + if (ret < 0) + goto out; + ret = write(task->sd, &fd, sizeof(int)); + if (ret < 0) + goto out; + read(task->sd, &ret, sizeof(int)); + +out: + spinlock_unlock(&lwip_lock); + + return ret; } static int sys_msleep(unsigned int msec) @@ -171,7 +292,7 @@ static int sys_sem_timedwait(sem_t *sem, unsigned int ms) static int sys_clone(tid_t* id, void* ep, void* argv) { - return clone_task(id, ep, argv, per_core(current_task)->prio); + return clone_task(id, ep, argv, per_core(current_task)->prio); } static int default_handler(void) diff --git a/hermit/kernel/tasks.c b/hermit/kernel/tasks.c index 6cad5e068..c759ab5d4 100644 --- a/hermit/kernel/tasks.c +++ b/hermit/kernel/tasks.c @@ -42,8 +42,8 @@ * A task's id will be its position in this array. */ static task_t task_table[MAX_TASKS] = { \ - [0] = {0, TASK_IDLE, 0, NULL, NULL, TASK_DEFAULT_FLAGS, 0, 0, 0, SPINLOCK_IRQSAVE_INIT, SPINLOCK_INIT, NULL, 0, NULL, NULL, 0, NULL, NULL, 0, 0, 0, 0}, \ - [1 ... MAX_TASKS-1] = {0, TASK_INVALID, 0, NULL, NULL, TASK_DEFAULT_FLAGS, 0, 0, 0, SPINLOCK_IRQSAVE_INIT, SPINLOCK_INIT, NULL, 0, NULL, NULL, 0, NULL, NULL, 0, 0, 0, 0}}; + [0] = {0, TASK_IDLE, 0, NULL, NULL, TASK_DEFAULT_FLAGS, 0, 0, 0, SPINLOCK_IRQSAVE_INIT, SPINLOCK_INIT, NULL, 0, NULL, NULL, 0, NULL, NULL, 0, 0, 0, -1, 0}, \ + [1 ... MAX_TASKS-1] = {0, TASK_INVALID, 0, NULL, NULL, TASK_DEFAULT_FLAGS, 0, 0, 0, SPINLOCK_IRQSAVE_INIT, SPINLOCK_INIT, NULL, 0, NULL, NULL, 0, NULL, NULL, 0, 0, 0, -1, 0}}; static spinlock_irqsave_t table_lock = SPINLOCK_IRQSAVE_INIT; @@ -215,7 +215,7 @@ void finish_task_switch(void) /** @brief A procedure to be called by * procedures which are called by exiting tasks. */ -static void NORETURN do_exit(int arg) +void NORETURN do_exit(int arg) { task_t* curr_task = per_core(current_task); const uint32_t core_id = CORE_ID; @@ -252,11 +252,6 @@ void NORETURN leave_kernel_task(void) { do_exit(result); } -/** @brief To be called by the systemcall to exit tasks */ -void NORETURN sys_exit(int arg) { - do_exit(arg); -} - /** @brief Aborting a task is like exiting it with result -1 */ void NORETURN abort(void) { do_exit(-1); @@ -319,6 +314,7 @@ int clone_task(tid_t* id, entry_point_t ep, void* arg, uint8_t prio) task_table[i].tls_addr = curr_task->tls_addr; task_table[i].tls_mem_size = curr_task->tls_mem_size; task_table[i].tls_file_size = curr_task->tls_file_size; + task_table[i].sd = task_table[i].sd; task_table[i].lwip_err = 0; task_table[i].user_usage = curr_task->user_usage; task_table[i].page_map = curr_task->page_map; @@ -350,7 +346,7 @@ int clone_task(tid_t* id, entry_point_t ep, void* arg, uint8_t prio) } spinlock_irqsave_unlock(&table_lock); -out: +out: if (ret) kfree(stack); @@ -403,6 +399,7 @@ int create_task(tid_t* id, entry_point_t ep, void* arg, uint8_t prio, uint32_t c task_table[i].tls_addr = 0; task_table[i].tls_mem_size = 0; task_table[i].tls_file_size = 0; + task_table[i].sd = -1; task_table[i].lwip_err = 0; spinlock_irqsave_init(&task_table[i].page_lock); diff --git a/hermit/lwip b/hermit/lwip index 6dbcf238e..9209bfad6 160000 --- a/hermit/lwip +++ b/hermit/lwip @@ -1 +1 @@ -Subproject commit 6dbcf238e2e6abe4ae90a8c64521fbf8d75c3ce3 +Subproject commit 9209bfad66bb4ca907bac43515be5b3905fd4f1f diff --git a/hermit/tools/Makefile b/hermit/tools/Makefile index 563a45018..885cfb814 100644 --- a/hermit/tools/Makefile +++ b/hermit/tools/Makefile @@ -5,7 +5,7 @@ CC = gcc CFLAGS = -O2 -Wall HEXDUMP = hexdump LDFLGAS = -EXECFILES = $(shell find ../usr/examples -perm -u+r+x -type f) +EXECFILES = ../usr/examples/hello #$(shell find ../usr/examples -perm -u+r+x -type f) # Prettify output V = 0