toaruos/kernel/core/task.c

255 lines
6.6 KiB
C
Raw Normal View History

/*
* vim:tabstop=4
* vim:noexpandtab
*/
#include <system.h>
2011-03-28 08:58:54 +04:00
#define KERNEL_STACK_SIZE 0x2000
volatile task_t * current_task = NULL;
volatile task_t * ready_queue = NULL;
2011-03-03 10:39:26 +03:00
uint32_t next_pid = 0;
page_directory_t *
clone_directory(
page_directory_t * src
) {
uintptr_t phys;
page_directory_t * dir = (page_directory_t *)kvmalloc_p(sizeof(page_directory_t), &phys);
memset(dir, 0, sizeof(page_directory_t));
uintptr_t offset = (uintptr_t)dir->physical_tables - (uintptr_t)dir;
dir->physical_address = phys + offset;
uint32_t i;
for (i = 0; i < 1024; ++i) {
if (!src->tables[i]) {
continue;
}
if (kernel_directory->tables[i] == src->tables[i]) {
dir->tables[i] = src->tables[i];
dir->physical_tables[i] = src->physical_tables[i];
} else {
uintptr_t phys;
dir->tables[i] = clone_table(src->tables[i], &phys);
dir->physical_tables[i] = phys | 0x07;
}
}
return dir;
}
page_table_t *
clone_table(
page_table_t * src,
uintptr_t * physAddr
) {
page_table_t * table = (page_table_t *)kvmalloc_p(sizeof(page_table_t), physAddr);
memset(table, 0, sizeof(page_directory_t));
uint32_t i;
for (i = 0; i < 1024; ++i) {
if (!src->pages[i].frame) {
continue;
}
alloc_frame(&table->pages[i], 0, 0);
if (src->pages[i].present) table->pages[i].present = 1;
if (src->pages[i].rw) table->pages[i].rw = 1;
if (src->pages[i].user) table->pages[i].user = 1;
if (src->pages[i].accessed) table->pages[i].accessed = 1;
if (src->pages[i].dirty) table->pages[i].dirty = 1;
copy_page_physical(src->pages[i].frame * 0x1000, table->pages[i].frame * 0x1000);
}
return table;
}
void
tasking_install() {
IRQ_OFF;
current_task = (task_t *)kmalloc(sizeof(task_t));
ready_queue = current_task;
current_task->id = next_pid++;
current_task->esp = 0;
current_task->ebp = 0;
current_task->eip = 0;
2011-04-18 03:28:40 +04:00
current_task->stack = initial_esp + 1;
current_task->page_directory = current_directory; //clone_directory(current_directory);
current_task->next = 0;
2011-04-17 05:01:04 +04:00
current_task->descriptors = (fs_node_t **)kmalloc(sizeof(fs_node_t *) * 1024);
current_task->next_fd = 0;
2011-11-18 01:55:59 +04:00
current_task->wd[0] = '/';
current_task->wd[1] = 0;
2011-04-17 05:01:04 +04:00
//switch_page_directory(current_task->page_directory);
IRQ_ON;
}
task_t *
gettask(
uint32_t pid
) {
task_t * output = (task_t *)ready_queue;
2011-04-09 02:53:52 +04:00
while (output != NULL && output->id != pid) {
output = output->next;
}
return output;
}
uint32_t
fork() {
IRQ_OFF;
task_t * parent = (task_t *)current_task;
page_directory_t * directory = clone_directory(current_directory);
task_t * new_task = (task_t *)kmalloc(sizeof(task_t));
new_task->id = next_pid++;
new_task->esp = 0;
new_task->ebp = 0;
new_task->eip = 0;
new_task->page_directory = directory;
new_task->next = NULL;
2011-04-18 03:28:40 +04:00
new_task->stack = kvmalloc(KERNEL_STACK_SIZE) + KERNEL_STACK_SIZE;
2011-04-17 05:01:04 +04:00
new_task->descriptors = (fs_node_t **)kmalloc(sizeof(fs_node_t *) * 1024);
memcpy(new_task->descriptors, parent->descriptors, sizeof(fs_node_t *) * 1024);
new_task->next_fd = 0;
new_task->finished = 0;
2011-04-09 02:53:52 +04:00
new_task->image_size = 0;
/* Some stuff */
new_task->entry = current_task->entry;
new_task->heap = current_task->heap;
new_task->heap_a = current_task->heap_a;
new_task->image_size = current_task->image_size;
2011-11-18 10:00:54 +04:00
for (uint32_t i = 0; i <= strlen((const char *)current_task->wd); ++i) {
2011-11-18 01:55:59 +04:00
new_task->wd[i] = current_task->wd[i];
}
task_t * tmp_task = (task_t *)ready_queue;
2011-04-17 05:01:04 +04:00
new_task->parent = parent;
while (tmp_task->next) {
tmp_task = tmp_task->next;
}
tmp_task->next = new_task;
uintptr_t eip = read_eip();
if (current_task == parent) {
uintptr_t esp;
uintptr_t ebp;
asm volatile ("mov %%esp, %0" : "=r" (esp));
asm volatile ("mov %%ebp, %0" : "=r" (ebp));
if (current_task->stack > new_task->stack) {
2011-04-18 03:28:40 +04:00
new_task->esp = esp - (current_task->stack - new_task->stack);
new_task->ebp = ebp - (current_task->stack - new_task->stack);
} else {
2011-04-18 03:28:40 +04:00
new_task->esp = esp + (new_task->stack - current_task->stack);
new_task->ebp = ebp - (current_task->stack - new_task->stack);
}
// kprintf("old: %x new: %x; end: %x %x\n", esp, new_task->esp, current_task->stack, new_task->stack);
2011-04-18 03:28:40 +04:00
memcpy((void *)(new_task->stack - KERNEL_STACK_SIZE), (void *)(current_task->stack - KERNEL_STACK_SIZE), KERNEL_STACK_SIZE);
new_task->eip = eip;
IRQ_ON;
return new_task->id;
} else {
return 0;
}
}
uint32_t
getpid() {
return current_task->id;
}
void
switch_task() {
if (!current_task) {
return;
}
if (!current_task->next && current_task == ready_queue) return;
2011-03-30 06:08:56 +04:00
uintptr_t esp, ebp, eip;
asm volatile ("mov %%esp, %0" : "=r" (esp));
asm volatile ("mov %%ebp, %0" : "=r" (ebp));
eip = read_eip();
if (eip == 0x10000) {
IRQ_ON;
return;
}
current_task->eip = eip;
current_task->esp = esp;
current_task->ebp = ebp;
current_task = current_task->next;
if (!current_task) {
current_task = ready_queue;
}
2011-04-09 02:53:52 +04:00
if (!current_task) {
HALT_AND_CATCH_FIRE("Empty ready queue!", NULL);
}
eip = current_task->eip;
esp = current_task->esp;
ebp = current_task->ebp;
IRQ_OFF;
asm volatile (
"mov %0, %%ebx\n"
"mov %1, %%esp\n"
"mov %2, %%ebp\n"
"mov %3, %%cr3\n"
"mov $0x10000, %%eax\n"
"sti\n"
"jmp *%%ebx"
: : "r" (eip), "r" (esp), "r" (ebp), "r" (current_directory->physical_address)
: "%ebx", "%esp", "%eax");
switch_page_directory(current_task->page_directory);
}
2011-03-30 06:08:56 +04:00
void
2011-04-18 02:44:29 +04:00
enter_user_jmp(uintptr_t location, int argc, char ** argv, uintptr_t stack) {
2011-04-18 03:28:40 +04:00
set_kernel_stack(current_task->stack);
asm volatile(
2011-04-18 02:44:29 +04:00
"mov %3, %%esp\n"
"mov $0x23, %%ax\n"
"mov %%ax, %%ds\n"
"mov %%ax, %%es\n"
"mov %%ax, %%fs\n"
"mov %%ax, %%gs\n"
"mov %%esp, %%eax\n"
"pushl $0x23\n"
"pushl %%eax\n"
"pushf\n"
"popl %%eax\n"
"orl $0x200, %%eax\n"
"pushl %%eax\n"
"pushl $0x1B\n"
"pushl %2\n"
"pushl %1\n"
"call *%0\n"
: : "m"(location), "m"(argc), "m"(argv), "r"(stack) : "%ax", "%esp", "%eax");
}
void task_exit(int retval) {
IRQ_OFF;
current_task->retval = retval;
current_task->finished = 1;
2011-04-09 02:53:52 +04:00
/* Free the image memory */
for (uintptr_t i = 0; i < current_task->image_size; i += 0x1000) {
//free_frame(get_page(current_task->entry + i, 0, current_directory));
2011-04-09 02:53:52 +04:00
}
/* Dequeue us */
task_t volatile * temp = ready_queue;
task_t volatile * prev = NULL;
while (temp != current_task && temp != NULL) {
prev = temp;
temp = temp->next;
}
if (prev == NULL) {
ready_queue = current_task->next;
} else {
prev->next = current_task->next;
}
//free((void *)(current_task->stack - KERNEL_STACK_SIZE));
free((void *)current_task->page_directory);
2011-04-17 05:01:04 +04:00
free((void *)current_task->descriptors);
//free((void *)current_task);
IRQ_ON;
}
void kexit(int retval) {
task_exit(retval);
STOP;
}