From 7e6454020ed1143e05e83a683606f318995458e5 Mon Sep 17 00:00:00 2001 From: Alex AUVOLAT Date: Fri, 18 May 2012 16:16:07 +0200 Subject: Can now spawn new processes. --- src/include/tce/syscalls.h | 3 + src/kernel/linker/elf.cpp | 2 +- src/kernel/task/syscall.cpp | 9 ++- src/kernel/task/task.cpp | 129 ++++++++++++++++++++++++++++--------- src/kernel/task/task.h | 9 ++- src/kernel/ui/vt.cpp | 1 + src/kernel/vfs/node.cpp | 5 +- src/user/lib/include/tce/syscall.h | 3 + src/user/lib/tce/syscall.c | 10 +++ src/user/test/main.c | 44 +++++++++---- 10 files changed, 162 insertions(+), 53 deletions(-) diff --git a/src/include/tce/syscalls.h b/src/include/tce/syscalls.h index e14768f..26021a0 100644 --- a/src/include/tce/syscalls.h +++ b/src/include/tce/syscalls.h @@ -16,6 +16,9 @@ #define SC_MMAP 12 #define SC_MUNMAP 13 +#define SC_RUN 14 +#define SC_WAITPID 15 + #define SC_OPEN 20 #define SC_OPEN_RELATIVE 21 #define SC_STAT 22 diff --git a/src/kernel/linker/elf.cpp b/src/kernel/linker/elf.cpp index 8fc2e0c..6c45f10 100644 --- a/src/kernel/linker/elf.cpp +++ b/src/kernel/linker/elf.cpp @@ -45,7 +45,7 @@ thread_entry elf_load(uint8_t *data, process* process) { } process* elf_exec(uint8_t *data, int privilege, char** args) { - if (elf_check(data)) return 0; + if (elf_check(data) != 0) return 0; process* p = new process(0, 0, privilege); diff --git a/src/kernel/task/syscall.cpp b/src/kernel/task/syscall.cpp index e9f9d3a..4eddb61 100644 --- a/src/kernel/task/syscall.cpp +++ b/src/kernel/task/syscall.cpp @@ -28,6 +28,7 @@ CALL1V(idt_waitIrq, irq_wait_sc); CALL0(proc_priv, proc_priv_sc); CALL1(process_sbrk, proc_sbrk_sc); CALL1V(process_brk, proc_brk_sc); +CALL1(process_waitpid, waitpid_sc); CALL1V(close, close_sc); @@ -41,6 +42,10 @@ static void thread_new_sc(registers* r) { sti(); } +static void run_sc(registers *r) { + r->eax = process_run((char*)r->ebx, (char**)r->ecx); +} + static void open_sc(registers *r) { r->eax = open((char*)r->ebx, r->ecx); } @@ -89,8 +94,8 @@ int_callback syscalls[NUMBER_OF_SYSCALLS] = { // This must correspond to common proc_brk_sc, 0, 0, - 0, - 0, //15 + run_sc, + waitpid_sc, //15 0, 0, 0, diff --git a/src/kernel/task/task.cpp b/src/kernel/task/task.cpp index 1a5d535..02294bd 100644 --- a/src/kernel/task/task.cpp +++ b/src/kernel/task/task.cpp @@ -6,6 +6,10 @@ #include #include "timer.h" +#include + +#include +#include #include #define KSTACKSIZE 0x8000 @@ -14,29 +18,37 @@ static void thread_exit_stackJmp(uint32_t reason); static void thread_exit2(uint32_t reason); static void thread_delete(thread *th); -static void process_delete(process *pr); +static void process_finish(process *pr, int retval); //From task_.asm extern "C" uint32_t read_eip(); extern "C" void task_idle(void*); -static uint32_t nextpid = 1; -process *processes = 0, *kernel_process = 0, *current_process = 0; +earray *proc_by_pid; +earray *proc_retval; + +process *kernel_process = 0, *current_process = 0; thread *current_thread = 0, *idle_thread = 0; +int proc_count = 0; + uint32_t tasking_tmpStack[KSTACKSIZE]; /* Sets up tasking. Called by kmain on startup. Creates a kernel process and an IDLE thread in it. */ void tasking_init() { + proc_by_pid = new earray(12, 32); + proc_retval = new earray(12, 32); + cli(); - kernel_process = new process(); //This process must be hidden to users - kernel_process->pid = kernel_process->uid = kernel_process->thread_count = 0; + kernel_process = new process(); + kernel_process->uid = kernel_process->thread_count = 0; + kernel_process->pid = proc_by_pid->add(kernel_process); kernel_process->privilege = PL_KERNEL; kernel_process->parent = kernel_process; kernel_process->pagedir = kernel_pagedir; - kernel_process->next = 0; kernel_process->threads = 0; + kernel_process->threads_waiting = 0; current_thread = 0; idle_thread = new thread(kernel_process, task_idle, 0, 0); sti(); @@ -46,17 +58,17 @@ void tasking_init() { Updates the page directories of all the processes. */ void tasking_updateKernelPagetable(uint32_t idx, page_table *table, uint32_t tablephysical) { if (idx < FIRST_KERNEL_PAGETABLE) return; - process* it = processes; - while (it != 0) { + for (int i = 0; i < proc_by_pid->count(); i++) { + process *it = proc_by_pid->at(i); + if (it == 0) continue; it->pagedir->tables[idx] = table; it->pagedir->tablesPhysical[idx] = tablephysical; - it = it->next; } } /* Called when a timer IRQ fires. Does a context switch. */ void schedule() { - if (processes == 0) PANIC("No processes are running !"); + //if (processes == 0) PANIC("No processes are running !"); asm volatile("cli"); uint32_t esp, ebp, eip; @@ -97,7 +109,7 @@ void schedule() { Ends the thread for most exceptions, ends the whole process for page faults. */ uint32_t tasking_handleException(registers *regs) { if (current_thread == 0) return 0; //No tasking yet - NL; WHERE; ke_vt->writeStr("exception:`"); + NL; WHERE; ke_vt->writeStr("Exception: `"); char *exception_messages[] = {"Division By Zero","Debug","Non Maskable Interrupt","Breakpoint", "Into Detected Overflow","Out of Bounds","Invalid Opcode","No Coprocessor", "Double Fault", "Coprocessor Segment Overrun","Bad TSS","Segment Not Present","Stack Fault","General Protection Fault", @@ -105,10 +117,9 @@ uint32_t tasking_handleException(registers *regs) { *ke_vt << exception_messages[regs->int_no]; *ke_vt << "'\teip:" << regs->eip; if (regs->eip >= K_HIGHHALF_ADDR) { - *ke_vt << "\n Exception stack trace :\n"; + *ke_vt << "\nException in kernel. Stack trace:\n"; stack_trace(regs->ebp); - PANIC("Kernel error'd."); - } + } if (regs->int_no == 14) { *ke_vt << "\n>>> Process exiting.\n"; thread_exit_stackJmp(EX_PR_EXCEPTION); @@ -155,7 +166,7 @@ void thread_exit2(uint32_t reason) { //See EX_TH_* defines in task.h if ((reason == EX_TH_NORMAL || reason == EX_TH_EXCEPTION) && pr->thread_count > 1) { thread_delete(th); } else { - process_delete(pr); + process_finish(pr, reason); } retrn: sti(); @@ -274,14 +285,13 @@ thread::thread(class process *proc, thread_entry entry_point, void *data, void * /* Creates a new process. Creates a struct process and fills it up. */ process::process(process* _parent, uint32_t _uid, uint32_t _privilege) : fd(12, 64) { - pid = (nextpid++); uid = _uid; thread_count = 0; threads = 0; + threads_waiting = 0; privilege = _privilege; parent = _parent; pagedir = pagedir_new(); - next = processes; data = 0; dataseg = 0; @@ -294,7 +304,9 @@ process::process(process* _parent, uint32_t _uid, uint32_t _privilege) : fd(12, stack = stacksBottom + USER_STACK_SIZE - 4; } - processes = this; + pid = proc_by_pid->add(this); + + proc_count++; } /* Deletes given thread, freeing the stack(s). */ @@ -318,26 +330,25 @@ static void thread_delete(thread *th) { } /* Deletes a process. First, deletes all its threads. Also deletes the corresponding page directory. */ -static void process_delete(process *pr) { +static void process_finish(process *pr, int retval) { + proc_retval->set(pr->pid, (void*)retval); + + thread *it = pr->threads; while (it != 0) { thread_delete(it); it = it->next; } - if (processes == pr) { - processes = pr->next; - } else { - process *it = processes; - while (it) { - if (it->next == pr) { - it->next = pr->next; - break; - } - it = it->next; - } - } pagedir_delete(pr->pagedir); + proc_by_pid->set(pr->pid, 0); + while (pr->threads_waiting != 0) { + pr->threads_waiting->wakeUp(); + pr->threads_waiting = pr->threads_waiting->queue_next; + } kfree(pr); + + proc_count--; + if (proc_count == 0) PANIC("No more processes are running! This is bad! Or is it?"); } size_t process::sbrk(size_t size) { @@ -408,11 +419,65 @@ void* process::set_args(char** args) { return p; } -// syscalls +// ===================== SYSTEM CALLS + + size_t process_sbrk(size_t size) { return current_process->sbrk(size); } + void process_brk(size_t ptr) { ASSERT(ptr < K_HIGHHALF_ADDR); current_process->sbrk(ptr - current_process->data); } + +int process_run(char* file, char** args) { + node* bin = vfs_find(root, file); + if (bin == 0) return E_NOT_FOUND; + if ((bin->type & FT_FILE) == 0) return E_INVALID; + + int len = bin->get_size(); + void *v = kmalloc(len); + int r = bin->read(0, len, (char*)v); + if (r != len) { + kfree(v); + return E_NOT_IMPLEMENTED; + } + if (elf_check((uint8_t*)v) != 0) { + kfree(v); + return E_NOT_IMPLEMENTED; + } + + // copy arguments to kernel + char **arg_data; + int argc = 0; + if (args != 0) { + for (char** a = args; *a != 0; a++) argc++; + arg_data = (char**)kmalloc(sizeof(char*) * (argc + 2)); + for (int i = 0; i < argc; i++) arg_data[i+1] = strdup(args[i]); + } else { + arg_data = (char**)kmalloc(sizeof(char*)*2); + } + arg_data[0] = strdup(file); + arg_data[argc + 1] = 0; + + // load + process *p = elf_exec((uint8_t*)v, PL_USER, arg_data); + + kfree(v); + for (int i = 0; arg_data[i] != 0; i++) kfree(arg_data[i]); + kfree(arg_data); + return (p == 0 ? E_INVALID : p->pid); +} + +int process_waitpid(int pid) { + if (pid <= 0) return E_INVALID_RANGE; + + process *p = proc_by_pid->at(pid); + if (p != 0) { + current_thread->queue_next = p->threads_waiting; + p->threads_waiting = current_thread; + thread_goInactive(); + } + return (int)proc_retval->at(pid); +} diff --git a/src/kernel/task/task.h b/src/kernel/task/task.h index 99738b9..2ebb66e 100644 --- a/src/kernel/task/task.h +++ b/src/kernel/task/task.h @@ -34,8 +34,8 @@ class process { segment_map *dataseg; - process *next; //Forms a linked list thread *threads; + thread *threads_waiting; // threads waiting for this process to end earray fd; // file descriptors @@ -77,9 +77,12 @@ uint32_t tasking_handleException(registers *regs); void thread_goInactive(); //Blocks the current thread. it is then waked up by another thread or a system event. int proc_priv(); //Returns current privilege level -void thread_exit(); //syscall -void process_exit(size_t retval); //syscall +// syscalls +void thread_exit(); +void process_exit(size_t retval); size_t process_sbrk(size_t size); void process_brk(size_t ptr); +int process_run(char* file, char** args); +int process_waitpid(int pid); #endif diff --git a/src/kernel/ui/vt.cpp b/src/kernel/ui/vt.cpp index 48a2da4..2869fec 100644 --- a/src/kernel/ui/vt.cpp +++ b/src/kernel/ui/vt.cpp @@ -215,6 +215,7 @@ int vt::read(size_t offset, size_t len, char* buffer) { } if (end || c == len) return c; + if (kbd_waiter != 0) return c; kbd_waiter = current_thread; thread_goInactive(); } diff --git a/src/kernel/vfs/node.cpp b/src/kernel/vfs/node.cpp index 08c7817..ea7b531 100644 --- a/src/kernel/vfs/node.cpp +++ b/src/kernel/vfs/node.cpp @@ -25,8 +25,10 @@ void vfs_setup() { root->add_child(".ui", dot_ui); } -node* vfs_find(node* root, char* path) { +node* vfs_find(node* root, char* fn) { node* el = root; + char *path = strdup(fn); + char *s = path; char *member = path; while (*path != 0 && el != 0) { @@ -47,6 +49,7 @@ node* vfs_find(node* root, char* path) { if (el != 0 && member != path) { el = el->get_child(member); } + kfree(s); return el; } diff --git a/src/user/lib/include/tce/syscall.h b/src/user/lib/include/tce/syscall.h index 028b544..1811422 100644 --- a/src/user/lib/include/tce/syscall.h +++ b/src/user/lib/include/tce/syscall.h @@ -19,6 +19,9 @@ int proc_priv(); void* sbrk(size_t size); void brk(void* ptr); +int run(char* file, char** args); +int waitpid(int pid); + FILE open(char* filename, int mode); FILE open_relative(FILE root, char* filename, int mode); int stat(char* filename, file_info *info); diff --git a/src/user/lib/tce/syscall.c b/src/user/lib/tce/syscall.c index 3e8d75e..bc8bfd8 100644 --- a/src/user/lib/tce/syscall.c +++ b/src/user/lib/tce/syscall.c @@ -73,6 +73,16 @@ void brk(void* ptr) { return call (SC_BRK, ptr, 0, 0, 0, 0); } +// ********** proc + +int run(char* filename, char** args) { + return call(SC_RUN, (unsigned)filename, (unsigned)args, 0, 0, 0); +} + +int waitpid(int p) { + return call(SC_WAITPID, p, 0, 0, 0, 0); +} + // ********** file FILE open(char* filename, int mode) { diff --git a/src/user/test/main.c b/src/user/test/main.c index 81753bd..eb289ca 100644 --- a/src/user/test/main.c +++ b/src/user/test/main.c @@ -74,6 +74,19 @@ void list_dir(FILE f, int lv) { } } +void list_root() { + FILE f = open("/", 0); + if (f <= 0) { + printk(" -> Could not open '/', error #"); + printk_int(f); + printk("...\n"); + } else { + printk("Now enumerating '/' (fd "); printk_int(f); printk(") :\n"); + list_dir(f, 1); + close(f); + } +} + void fprint(FILE f, char *s) { write(f, 0, strlen(s), s); } @@ -102,19 +115,9 @@ int main(char** args) { if (threads == 0) break; } printk("\n -> Ok, let's try something else.\n"); + list_root(); - FILE f = open("/", 0); - if (f <= 0) { - printk(" -> Could not open '/', error #"); - printk_int(f); - printk("...\n"); - } else { - printk("Now enumerating '/' (fd "); printk_int(f); printk(") :\n"); - list_dir(f, 1); - close(f); - } - - f = open("/.ui/klog", 0); + FILE f = open("/.ui/klog", 0); if (f <= 0) { printk(" -> Error #"); printk_int(f); printk(" - too bad. Exiting.\n"); } else { @@ -133,13 +136,26 @@ int main(char** args) { } else if (strcmp(buffer, "help") == 0) { fprint(f, "Available commands: about, help, exit.\n"); } else if (strcmp(buffer, "exit") == 0) { - fprint(f, "Exiting the shell. I think the system is pretty likely to panic.\n"); + fprint(f, "Exiting the shell. See you later!\n"); break; } else if (strcmp(buffer, "gotosleep") == 0) { while (1) thread_sleep(1000); + } else if (strcmp(buffer, "spawn") == 0) { + char *args[] = {"hello", "world", 0}; + int pid = run("/somewhere/bin/test", args); + if (pid < 0) { + printk("Error "); printk_int(pid); printk("\n"); + } else { + printk("Launched, pid="); printk_int(pid); printk("\n"); + int ret = waitpid(pid); + printk("Exited, ret="); printk_int(ret); printk("\n"); + } + } else if (strcmp(buffer, "root") == 0) { + list_root(); } else { - fprint(f, "Unknown command. "); + fprint(f, "Unknown command : "); fprint(f, buffer); + fprint(f, "\n"); } } else { fprint(f, " - - - oops\n"); -- cgit v1.2.3