diff options
author | Alex AUVOLAT <alexis211@gmail.com> | 2012-05-04 20:06:37 +0200 |
---|---|---|
committer | Alex AUVOLAT <alexis211@gmail.com> | 2012-05-04 20:06:37 +0200 |
commit | 277e4af4fa9e80816c809542d792ee6bebb7f202 (patch) | |
tree | 9abb7f207d185909427137e4861b81c057de1259 /src/kernel/task/task.c | |
parent | e9683297bf480f9590b0e5796f4520fb430e2e03 (diff) | |
download | TCE-277e4af4fa9e80816c809542d792ee6bebb7f202.tar.gz TCE-277e4af4fa9e80816c809542d792ee6bebb7f202.zip |
Migration to C++!
Diffstat (limited to 'src/kernel/task/task.c')
-rw-r--r-- | src/kernel/task/task.c | 410 |
1 files changed, 0 insertions, 410 deletions
diff --git a/src/kernel/task/task.c b/src/kernel/task/task.c deleted file mode 100644 index 9d98165..0000000 --- a/src/kernel/task/task.c +++ /dev/null @@ -1,410 +0,0 @@ -#include "task.h" -#include "sched.h" -#include <core/sys.h> -#include <core/monitor.h> -#include <mem/mem.h> -#include <mem/seg.h> -#include <mem/gdt.h> -#include "timer.h" - -#define KSTACKSIZE 0x8000 - -//Static routines for handling threads exiting and all cleanup -static void thread_exit_stackJmp(uint32_t reason); -static void thread_exit2(uint32_t reason); -static void thread_delete(struct thread *th); -static void process_delete(struct process *pr); - -//From task_.asm -extern uint32_t read_eip(); -extern void task_idle(void*); - -static uint32_t nextpid = 1; -struct process *processes = 0, *kernel_process; -struct thread *current_thread = 0, *idle_thread = 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() { - cli(); - kernel_process = kmalloc(sizeof(struct process)); //This process must be hidden to users - kernel_process->pid = kernel_process->uid = kernel_process->thread_count = 0; - kernel_process->privilege = PL_KERNEL; - kernel_process->parent = kernel_process; - kernel_process->pagedir = kernel_pagedir; - kernel_process->next = 0; - kernel_process->threads = 0; - current_thread = 0; - idle_thread = thread_new(kernel_process, task_idle, 0, 0); - sti(); - monitor_write("[Tasking] "); -} - -/* Called by the paging functions when a page table is allocated in the kernel space (>K_HIGHHALF_ADDR). - Updates the page directories of all the processes. */ -void tasking_updateKernelPagetable(uint32_t idx, struct page_table *table, uint32_t tablephysical) { - if (idx < FIRST_KERNEL_PAGETABLE) return; - struct process* it = processes; - while (it != 0) { - 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 !"); - asm volatile("cli"); - - uint32_t esp, ebp, eip; - - asm volatile("mov %%esp, %0" : "=r"(esp)); - asm volatile("mov %%ebp, %0" : "=r"(ebp)); - eip = read_eip(); - - if (eip == 0x12345) { - return; - } - - if (current_thread != 0) { - current_thread->esp = esp; - current_thread->ebp = ebp; - current_thread->eip = eip; - if (current_thread->state == TS_RUNNING) sched_enqueue(current_thread); - } - - current_thread = sched_dequeue(); - ASSERT(current_thread != 0); - - pagedir_switch(current_thread->process->pagedir); - - gdt_setKernelStack(((uint32_t)current_thread->kernelStack_addr) + current_thread->kernelStack_size); - - asm volatile(" \ - mov %0, %%ebp; \ - mov %1, %%esp; \ - mov %2, %%ecx; \ - mov $0x12345, %%eax; \ - jmp *%%ecx;" - : : "r"(current_thread->ebp), "r"(current_thread->esp), "r"(current_thread->eip)); -} - -/* Called when an exception happens. Provides a stack trace if it was in kernel land. - Ends the thread for most exceptions, ends the whole process for page faults. */ -uint32_t tasking_handleException(struct registers *regs) { - if (current_thread == 0) return 0; //No tasking yet - NL; WHERE; monitor_write("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", - "Page Fault","Unknown Interrupt","Coprocessor Fault","Alignment Check","Machine Check"}; - monitor_write(exception_messages[regs->int_no]); - monitor_write("'\teip:"); monitor_writeHex(regs->eip); - if (regs->eip >= K_HIGHHALF_ADDR) { - monitor_write("\n Exception stack trace :\n"); - stack_trace(regs->ebp); - PANIC("Kernel error'd."); - } - if (regs->int_no == 14) { - monitor_write("\n>>> Process exiting.\n"); - thread_exit_stackJmp(EX_PR_EXCEPTION); - } else { - monitor_write("\n>>> Thread exiting.\n"); - thread_exit_stackJmp(EX_TH_EXCEPTION); - } - PANIC("This should never have happened. Please report this."); - return 0; -} - -/* Puts the current thread in an inactive state. */ -void thread_goInactive() { - current_thread->state = TS_WAKEWAIT; - schedule(); -} - -/* Wakes up the given thread. */ -void thread_wakeUp(struct thread* t) { - if (t->state == TS_WAKEWAIT) { - t->state = TS_RUNNING; - sched_enqueue(t); - } -} - -/* Returns the privilege level of the current process. */ -int proc_priv() { - if (current_thread == 0 || current_thread->process == 0) return PL_UNKNOWN; - return current_thread->process->privilege; -} - -/* For internal use only. Called by thread_exit_stackJmp on a stack that will not be deleted. - Exits current thread or process, depending on the reason. */ -void thread_exit2(uint32_t reason) { //See EX_TH_* defines in task.h - /* - * if reason == EX_TH_NORMAL, it is just one thread exiting because it has to - * if reason == EX_TH_EXCEPTION, it is just one thread exiting because of an exception - * if reason is none of the two cases above, it is the whole process exiting (with error code = reason) - */ - struct thread *th = current_thread; - if (th == 0 || th->process == 0) goto retrn; - struct process *pr = th->process; - if ((reason == EX_TH_NORMAL || reason == EX_TH_EXCEPTION) && pr->thread_count > 1) { - thread_delete(th); - } else { - process_delete(pr); - } - retrn: - sti(); - schedule(); -} - -/* For internal use only. Called by thread_exit and process_exit. - Switches to a stack that will not be deleted when current thread is deleted. */ -void thread_exit_stackJmp(uint32_t reason) { - cli(); - uint32_t *stack; - stack = tasking_tmpStack + (KSTACKSIZE / 4); - stack--; *stack = reason; - stack--; *stack = 0; - asm volatile(" \ - mov %0, %%esp; \ - mov %1, %%ebp; \ - mov %2, %%ecx; \ - mov %3, %%cr3; \ - jmp *%%ecx;" : : - "r"(stack), "r"(stack), "r"(thread_exit2), "r"(kernel_pagedir->physicalAddr)); -} - -/* System call. Exit the current thread. */ -void thread_exit() { - thread_exit_stackJmp(EX_TH_NORMAL); -} - -/* System call. Exit the current process. */ -void process_exit(size_t retval) { - if (retval == EX_TH_NORMAL || retval == EX_TH_EXCEPTION) retval = EX_PR_EXCEPTION; - thread_exit_stackJmp(retval); -} - -/* For internal use only. This is called when a newly created thread first runs - (its address is the value given for EIP). - It switches to user mode if necessary and calls the entry point. */ -static void thread_run(void* u_esp, struct thread *thread, thread_entry entry_point, void *data) { - pagedir_switch(thread->process->pagedir); - if (thread->process->privilege >= PL_USER) { //User mode ! - uint32_t *stack = u_esp; - - stack--; *stack = (uint32_t)data; - stack--; *stack = 0; - size_t esp = (size_t)stack, eip = (size_t)entry_point; - //Setup a false structure for returning from an interrupt : - //value for esp is in ebx, for eip is in ecx - //- update data segments to 0x23 = user data segment with RPL=3 - //- push value for ss : 0x23 (user data seg rpl3) - //- push value for esp - //- push flags - //- update flags, set IF = 1 (interrupts flag) - //- push value for cs : 0x1B = user code segment with RPL=3 - //- push eip - //- return from fake interrupt - asm volatile(" \ - mov $0x23, %%ax; \ - mov %%ax, %%ds; \ - mov %%ax, %%es; \ - mov %%ax, %%fs; \ - mov %%ax, %%gs; \ - \ - pushl $0x23; \ - pushl %%ebx; \ - pushf; \ - pop %%eax; \ - or $0x200, %%eax; \ - push %%eax; \ - pushl $0x1B; \ - push %%ecx; \ - iret; \ - " : : "b"(esp), "c"(eip)); - } else { - asm volatile("sti"); - entry_point(data); - } - thread_exit(0); -} - -/* Creates a new thread for given process. - Allocates a kernel stack and a user stack if necessary. - Sets up the kernel stack for values to be passed to thread_run. */ -struct thread *thread_new(struct process *proc, thread_entry entry_point, void *data, void *u_esp) { - struct thread *t = kmalloc(sizeof(struct thread)); - t->process = proc; - t->next = 0; - proc->thread_count++; - - if (u_esp == 0) u_esp = (void*)proc->stack; - - t->kernelStack_addr = kmalloc(KSTACKSIZE); - t->kernelStack_size = KSTACKSIZE; - - uint32_t *stack = (uint32_t*)((size_t)t->kernelStack_addr + t->kernelStack_size); - - //Pass parameters - stack--; *stack = (uint32_t)data; - stack--; *stack = (uint32_t)entry_point; - stack--; *stack = (uint32_t)t; - stack--; *stack = (uint32_t)u_esp; - stack--; *stack = 0; - t->esp = (uint32_t)stack; - t->ebp = t->esp + 8; - t->eip = (uint32_t)thread_run; - - t->state = TS_RUNNING; - sched_enqueue(t); - - if (proc->threads == 0) { - proc->threads = t; - } else { - struct thread *i = proc->threads; - while (i->next != 0) i = i->next; - i->next = t; - } - return t; -} - -/* Creates a new process. Creates a struct process and fills it up. */ -struct process *process_new(struct process* parent, uint32_t uid, uint32_t privilege) { - struct process* p = kmalloc(sizeof(struct process)); - p->pid = (nextpid++); - p->uid = uid; - p->thread_count = 0; - p->threads = 0; - p->privilege = privilege; - p->parent = parent; - p->pagedir = pagedir_new(); - p->next = processes; - p->data = 0; - p->dataseg = 0; - - p->stack = 0; - if (p->privilege >= PL_USER) { //We are running in user mode - size_t stacksBottom = K_HIGHHALF_ADDR - 0x01000000; - seg_map(simpleseg_make(stacksBottom, USER_STACK_SIZE, 1), p->pagedir, 0); - p->stack = stacksBottom + USER_STACK_SIZE - 4; - } - - processes = p; - return p; -} - -/* Deletes given thread, freeing the stack(s). */ -static void thread_delete(struct thread *th) { - if (th->process->threads == th) { - th->process->threads = th->next; - } else { - struct thread *it = th->process->threads; - while (it) { - if (it->next == th) { - it->next = th->next; - break; - } - it = it->next; - } - } - if (current_thread == th) current_thread = 0; - th->process->thread_count--; - kfree(th->kernelStack_addr); - kfree(th); -} - -/* Deletes a process. First, deletes all its threads. Also deletes the corresponding page directory. */ -static void process_delete(struct process *pr) { - struct thread *it = pr->threads; - while (it != 0) { - thread_delete(it); - it = it->next; - } - if (processes == pr) { - processes = pr->next; - } else { - struct process *it = processes; - while (it) { - if (it->next == pr) { - it->next = pr->next; - break; - } - it = it->next; - } - } - pagedir_delete(pr->pagedir); - kfree(pr); -} - -/* System call. Called by the app to define the place for the heap. */ -/*int process_setheapseg(size_t start, size_t end) { //syscall - struct process *p = current_thread->process; - if (start >= K_HIGHHALF_ADDR || end >= K_HIGHHALF_ADDR) return -1; - if (p->heapseg == 0) { - struct segment *s = simpleseg_make(start, end - start, 1); - if (s == 0) return -5; - p->heapseg = seg_map(s, p->pagedir, 0); - if (p->heapseg == 0) return -1; - return 0; - } else if (p->heapseg->start != start) { - seg_unmap(p->heapseg); - struct segment *s = simpleseg_make(start, end - start, 1); - if (s == 0) return -5; - p->heapseg = seg_map(s, p->pagedir, 0); - if (p->heapseg == 0) return -1; - return 0; - } else { - return simpleseg_resize(p->heapseg, end - start); - } -}*/ - -size_t process_sbrk(size_t size) { - struct process *p = current_thread->process; - if (p->data == 0) return -1; - ASSERT(p->data < K_HIGHHALF_ADDR); - if (p->data + size >= K_HIGHHALF_ADDR) return -1; - - size_t ret; - if (p->dataseg == 0) { - size_t start = p->data; - if (start & 0x0FFF) start = (start & 0xFFFFF000) + 0x1000; - size_t end = start + size; - if (end & 0x0FFF) end = (end & 0xFFFFF000) + 0x1000; - - struct segment *s = simpleseg_make(start, end - start, 1); - if (s == 0) return -5; - p->dataseg = seg_map(s, p->pagedir, 0); - if (p->dataseg == 0) return -1; - - ret = start; - p->data = start + size; - } else { - size_t start = p->dataseg->start; - size_t end = p->data + size; - if (end <= start) return -1; - - if (end & 0x0FFF) end = (end & 0xFFFFF000) + 0x1000; - simpleseg_resize(p->dataseg, end - start); - - ret = p->data; - p->data += size; - } - /* (DBG) monitor_write("(sbrk "); - monitor_writeHex(size); - monitor_write(" "); - monitor_writeHex(ret); - monitor_write(")"); */ - return ret; -} - -void process_brk(size_t ptr) { - struct process *p = current_thread->process; - - ASSERT(ptr < K_HIGHHALF_ADDR); - process_sbrk(ptr - p->data); -} - |