os/kernel/cpu/i386/tasking.c
pjht 3ca8b5a232 Add a very basic exit function and fix kmalloc.
Exit function does not deallocate task memory except for the data block, 
and does not are about the exit code except for logging.
2019-08-25 17:32:08 -05:00

174 lines
4.5 KiB
C

#include "tasking_helpers.h"
#include "tasking.h"
#include "../tasking.h"
#include "isr.h"
#include <stdio.h>
#include <string.h>
#include "kmalloc.h"
#include "memory.h"
#include "gdt.h"
#include "paging.h"
#include <stdint.h>
#include <stdlib.h>
#include "../halt.h"
#include "serial.h"
#define STACK_PAGES 2
extern void task_init();
static uint32_t* kstacks=(uint32_t*)0xF6800000;
uint32_t next_pid;
Task* currentTask;
static Task* headTask;
static Task* tailTask;
static Task* tasks[32768];
Task* tasking_createTaskCr3KmodeParam(void* eip,void* cr3,char kmode,char param1_exists,uint32_t param1_arg,char param2_exists,uint32_t param2_arg);
void tasking_init(void* esp) {
currentTask=NULL;
next_pid=0;
headTask=tasking_createTaskCr3KmodeParam(NULL,paging_new_address_space(),1,0,0,0,0);
currentTask=headTask;
tailTask=headTask;
}
Task* tasking_createTaskCr3KmodeParam(void* eip,void* cr3,char kmode,char param1_exists,uint32_t param1_arg,char param2_exists,uint32_t param2_arg) {
Task* task=kmalloc(sizeof(Task));
map_kstack(next_pid);
uint32_t param1;
if (param1_exists) {
param1=param1_arg;
} else {
param1=1;
}
uint32_t param2;
if (param2_exists) {
param2=param2_arg;
} else {
param2=2;
}
task->cr3=(uint32_t)cr3;
uint32_t old_cr3;
asm volatile("movl %%cr3, %%eax; movl %%eax, %0;":"=m"(old_cr3)::"%eax");
load_address_space(task->cr3);
if (kmode) {
uint32_t top_idx=(1024*(next_pid+1));
task->kernel_esp=((uint32_t)(&kstacks[top_idx-5]));
task->kernel_esp_top=task->kernel_esp;
kstacks[top_idx-5]=0;
kstacks[top_idx-4]=0;
kstacks[top_idx-3]=0;
kstacks[top_idx-2]=0;
kstacks[top_idx-1]=(uint32_t)eip;
} else {
uint32_t top_idx=(1024*(next_pid+1));
task->kernel_esp=((uint32_t)(&kstacks[top_idx-7]));
task->kernel_esp_top=task->kernel_esp;
kstacks[top_idx-7]=0;
kstacks[top_idx-6]=0;
kstacks[top_idx-5]=0;
kstacks[top_idx-4]=0;
kstacks[top_idx-3]=(uint32_t)task_init;
uint32_t* user_stack=(uint32_t*)(((uint32_t)alloc_pages(1))+0x1000);
user_stack-=2;
user_stack[0]=param1;
user_stack[1]=param2;
kstacks[top_idx-2]=(uint32_t)user_stack;
kstacks[top_idx-1]=(uint32_t)eip;
}
load_address_space(old_cr3);
task->next=NULL;
task->pid=next_pid;
tasks[next_pid]=task;
task->priv=0;
task->errno=0;
if (currentTask) {
task->priv=currentTask->priv;
}
if (task->pid==1) {
task->priv=1;
}
next_pid++;
if (next_pid>1024*32) {
serial_printf("Failed to create a task, as 32k tasks have been created already.\n");
halt(); //Cannot ever create more than 32k tasks, as I don't currently reuse PIDs.
}
if (tailTask) {
tailTask->next=task;
task->prev=tailTask;
tailTask=task;
} else {
task->prev=NULL;
}
if (task->pid!=0) {
serial_printf("Created task with PID %d.\n",task->pid);
}
return task;
}
int* tasking_get_errno_address() {
return &(currentTask->errno);
}
char isPrivleged(uint32_t pid) {
for (Task* task=headTask;task!=NULL;task=task->next) {
if (task->pid==pid) {
return task->priv;
}
}
return 0;
}
Task* tasking_createTask(void* eip) {
return tasking_createTaskCr3KmodeParam(eip,paging_new_address_space(),0,0,0,0,0);
}
void tasking_yield(registers_t registers) {
Task* task=currentTask->next;
if (!task) {
task=headTask;
}
serial_printf("Yielding to PID %d.\n",task->pid);
load_smap(task->cr3);
switch_to_task(task);
}
void tasking_yieldToPID(uint32_t pid) {
Task* task=tasks[pid];
if (!task) {
serial_printf("PID %d does not exist.\n",pid);
return;
}
serial_printf("Yielding to PID %d.\n",task->pid);
load_smap(task->cr3);
switch_to_task(task);
}
void tasking_exit(uint8_t code) {
serial_printf("PID %d is exiting with code %d.\n",currentTask->pid,code);
if (currentTask->prev) {
currentTask->prev->next=currentTask->next;
}
if (currentTask->next) {
currentTask->next->prev=currentTask->prev;
}
if (headTask==currentTask) {
if (!currentTask->next) {
serial_write_string("ERROR! Head task exited with no child tasks! Halting!\n");
vga_write_string("ERROR! Head task exited with no child tasks! Halting!\n");
halt();
}
headTask=currentTask->next;
}
Task* task=currentTask->next;
kfree(currentTask);
serial_printf("Exit yielding to PID %d.\n",task->pid);
load_smap(task->cr3);
switch_to_task(task);
}
uint32_t getPID() {
return currentTask->pid;
}