2019-02-11 09:30:28 -06:00
|
|
|
#include "tasking_helpers.h"
|
|
|
|
#include "tasking.h"
|
|
|
|
#include "../tasking.h"
|
|
|
|
#include "isr.h"
|
2019-03-23 07:30:18 -05:00
|
|
|
#include <stdio.h>
|
2019-05-11 10:11:28 -05:00
|
|
|
#include <string.h>
|
2019-03-23 07:30:18 -05:00
|
|
|
#include "kmalloc.h"
|
2019-02-11 09:30:28 -06:00
|
|
|
#include "memory.h"
|
2019-03-17 12:22:00 -05:00
|
|
|
#include "gdt.h"
|
2019-04-13 09:23:40 -05:00
|
|
|
#include "paging.h"
|
2019-02-11 09:30:28 -06:00
|
|
|
#include <stdint.h>
|
2019-04-13 09:23:40 -05:00
|
|
|
#include <stdlib.h>
|
2019-06-29 09:04:34 -05:00
|
|
|
#include "../halt.h"
|
2019-08-04 13:14:35 -05:00
|
|
|
#include "serial.h"
|
2019-08-26 07:43:25 -05:00
|
|
|
#include "../../vga_err.h"
|
2020-07-12 14:28:58 -05:00
|
|
|
#include <sys/types.h>
|
2019-02-11 09:30:28 -06:00
|
|
|
#define STACK_PAGES 2
|
|
|
|
|
2019-05-21 19:16:19 -05:00
|
|
|
extern void task_init();
|
2019-06-29 09:04:34 -05:00
|
|
|
static uint32_t* kstacks=(uint32_t*)0xF6800000;
|
2019-05-21 19:16:19 -05:00
|
|
|
|
|
|
|
|
2020-07-12 14:28:58 -05:00
|
|
|
uint32_t next_pid=0;
|
|
|
|
uint32_t running_blocked_tasks=0;
|
|
|
|
Task* currentTask=NULL;
|
|
|
|
static Task* readyToRunHead=NULL;
|
|
|
|
static Task* readyToRunTail=NULL;
|
|
|
|
static Task* exitedTasksHead=NULL;
|
|
|
|
static Task* exitedTasksTail=NULL;
|
2019-08-04 13:14:35 -05:00
|
|
|
static Task* tasks[32768];
|
2019-05-23 20:21:51 -05:00
|
|
|
Task* tasking_createTaskCr3KmodeParam(void* eip,void* cr3,char kmode,char param1_exists,uint32_t param1_arg,char param2_exists,uint32_t param2_arg);
|
2019-02-11 09:30:28 -06:00
|
|
|
|
2019-05-21 19:16:19 -05:00
|
|
|
void tasking_init(void* esp) {
|
2020-07-12 14:28:58 -05:00
|
|
|
tasking_createTaskCr3KmodeParam(NULL,paging_new_address_space(),1,0,0,0,0);
|
2019-02-11 09:30:28 -06:00
|
|
|
}
|
|
|
|
|
2019-05-23 20:21:51 -05:00
|
|
|
Task* tasking_createTaskCr3KmodeParam(void* eip,void* cr3,char kmode,char param1_exists,uint32_t param1_arg,char param2_exists,uint32_t param2_arg) {
|
2020-07-12 14:28:58 -05:00
|
|
|
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.
|
|
|
|
}
|
2019-03-23 07:30:18 -05:00
|
|
|
Task* task=kmalloc(sizeof(Task));
|
2019-06-22 10:21:50 -05:00
|
|
|
map_kstack(next_pid);
|
2019-05-23 20:21:51 -05:00
|
|
|
uint32_t param1;
|
|
|
|
if (param1_exists) {
|
|
|
|
param1=param1_arg;
|
|
|
|
} else {
|
|
|
|
param1=1;
|
|
|
|
}
|
|
|
|
uint32_t param2;
|
|
|
|
if (param2_exists) {
|
|
|
|
param2=param2_arg;
|
|
|
|
} else {
|
|
|
|
param2=2;
|
|
|
|
}
|
2019-05-11 10:11:28 -05:00
|
|
|
task->cr3=(uint32_t)cr3;
|
2019-05-05 13:01:24 -05:00
|
|
|
uint32_t old_cr3;
|
|
|
|
asm volatile("movl %%cr3, %%eax; movl %%eax, %0;":"=m"(old_cr3)::"%eax");
|
2019-05-11 10:11:28 -05:00
|
|
|
load_address_space(task->cr3);
|
2019-05-21 19:16:19 -05:00
|
|
|
if (kmode) {
|
2019-06-22 10:21:50 -05:00
|
|
|
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;
|
2019-06-29 09:04:34 -05:00
|
|
|
kstacks[top_idx-1]=(uint32_t)eip;
|
2019-05-21 19:16:19 -05:00
|
|
|
} else {
|
2019-06-22 10:21:50 -05:00
|
|
|
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;
|
2019-06-29 09:04:34 -05:00
|
|
|
kstacks[top_idx-3]=(uint32_t)task_init;
|
2019-10-20 09:44:33 -05:00
|
|
|
uint32_t* user_stack=(uint32_t*)(((uint32_t)alloc_pages(2))+0x2000);
|
|
|
|
int buffer_pg_num=(((uint32_t)user_stack)-0x2000)>>12;
|
|
|
|
make_protector(buffer_pg_num);
|
|
|
|
// uint32_t* user_stack=(uint32_t*)(((uint32_t)alloc_pages(1))+0x1000);
|
2019-06-22 10:21:50 -05:00
|
|
|
user_stack-=2;
|
2019-05-23 20:21:51 -05:00
|
|
|
user_stack[0]=param1;
|
|
|
|
user_stack[1]=param2;
|
2019-06-29 09:04:34 -05:00
|
|
|
kstacks[top_idx-2]=(uint32_t)user_stack;
|
|
|
|
kstacks[top_idx-1]=(uint32_t)eip;
|
2019-05-11 10:11:28 -05:00
|
|
|
}
|
2019-05-05 13:01:24 -05:00
|
|
|
load_address_space(old_cr3);
|
2019-02-11 09:30:28 -06:00
|
|
|
task->next=NULL;
|
|
|
|
task->pid=next_pid;
|
2019-02-25 15:42:23 -06:00
|
|
|
task->priv=0;
|
2019-04-08 15:58:30 -05:00
|
|
|
task->errno=0;
|
2019-02-25 15:42:23 -06:00
|
|
|
if (currentTask) {
|
|
|
|
task->priv=currentTask->priv;
|
|
|
|
}
|
|
|
|
if (task->pid==1) {
|
|
|
|
task->priv=1;
|
|
|
|
}
|
2020-07-12 14:28:58 -05:00
|
|
|
task->prev=NULL;
|
|
|
|
task->next=NULL;
|
|
|
|
if (readyToRunTail) {
|
|
|
|
task->state=TASK_READY;
|
|
|
|
readyToRunTail->next=task;
|
|
|
|
task->prev=readyToRunTail;
|
|
|
|
readyToRunTail=task;
|
|
|
|
} else if (currentTask) {
|
|
|
|
task->state=TASK_READY;
|
|
|
|
readyToRunHead=task;
|
|
|
|
readyToRunTail=task;
|
2019-08-25 17:06:19 -05:00
|
|
|
} else {
|
2020-07-12 14:28:58 -05:00
|
|
|
task->state=TASK_RUNNING;
|
|
|
|
currentTask=task;
|
2019-02-11 09:30:28 -06:00
|
|
|
}
|
2020-07-12 14:28:58 -05:00
|
|
|
tasks[next_pid]=task;
|
|
|
|
next_pid++;
|
|
|
|
running_blocked_tasks++;
|
2019-08-04 13:14:35 -05:00
|
|
|
if (task->pid!=0) {
|
|
|
|
serial_printf("Created task with PID %d.\n",task->pid);
|
|
|
|
}
|
2019-02-11 09:30:28 -06:00
|
|
|
return task;
|
|
|
|
}
|
|
|
|
|
2019-04-08 15:58:30 -05:00
|
|
|
int* tasking_get_errno_address() {
|
|
|
|
return &(currentTask->errno);
|
|
|
|
}
|
2019-02-25 15:42:23 -06:00
|
|
|
char isPrivleged(uint32_t pid) {
|
2020-07-12 14:28:58 -05:00
|
|
|
for (Task* task=readyToRunHead;task!=NULL;task=task->next) {
|
2019-02-25 15:42:23 -06:00
|
|
|
if (task->pid==pid) {
|
|
|
|
return task->priv;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-02-11 09:47:28 -06:00
|
|
|
Task* tasking_createTask(void* eip) {
|
2019-05-23 20:21:51 -05:00
|
|
|
return tasking_createTaskCr3KmodeParam(eip,paging_new_address_space(),0,0,0,0,0);
|
2019-02-11 09:30:28 -06:00
|
|
|
}
|
|
|
|
|
2020-07-12 14:28:58 -05:00
|
|
|
void switch_to_task(Task* task) {
|
|
|
|
if (task!=readyToRunHead) {
|
|
|
|
// Unlink it from the doubly-linked list of ready-to-run tasks
|
|
|
|
task->prev->next=task->next;
|
|
|
|
if (task->next) {
|
|
|
|
task->next->prev=task->prev;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// Unlink the task from the list by advancing the ready to run pointer to the next task
|
|
|
|
readyToRunHead=task->next;
|
|
|
|
// If the task did not have a next task, also clear the ready to run tail pointer
|
|
|
|
if (readyToRunHead==NULL) {
|
|
|
|
readyToRunTail=NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
task->prev=NULL;
|
|
|
|
task->next=NULL;
|
|
|
|
task->state=TASK_RUNNING;
|
|
|
|
if (currentTask->state==TASK_RUNNING) {
|
|
|
|
currentTask->state=TASK_READY;
|
|
|
|
// Link the task onto the list of ready to run tasks
|
|
|
|
if (readyToRunTail) {
|
|
|
|
currentTask->prev=readyToRunTail;
|
|
|
|
readyToRunTail->next=currentTask;
|
|
|
|
readyToRunTail=currentTask;
|
|
|
|
} else {
|
|
|
|
readyToRunHead=currentTask;
|
|
|
|
readyToRunTail=currentTask;
|
|
|
|
}
|
2019-05-21 19:16:19 -05:00
|
|
|
}
|
2019-08-04 13:14:35 -05:00
|
|
|
serial_printf("Yielding to PID %d.\n",task->pid);
|
|
|
|
load_smap(task->cr3);
|
2020-07-12 14:28:58 -05:00
|
|
|
switch_to_task_asm(task);
|
|
|
|
}
|
|
|
|
|
2020-07-12 16:29:57 -05:00
|
|
|
void tasking_yield(pid_t pid) {
|
|
|
|
if (pid==0) {
|
|
|
|
if (!readyToRunHead) {
|
|
|
|
if (currentTask->state!=TASK_RUNNING) {
|
|
|
|
//This indicates either all tasks are bloked or the os has shutdown. Check which one it is
|
|
|
|
if (running_blocked_tasks==0) {
|
|
|
|
serial_printf("All tasks exited, halting\n");
|
|
|
|
halt(); //never returns, so we dont need an else
|
|
|
|
}
|
|
|
|
serial_printf("All tasks blocked, waiting for interrupt to unblock task\n");
|
|
|
|
// All tasks blocked
|
|
|
|
// Stop running the current task by setting currentTask to null, though put it in a local variable to keep track of it.
|
|
|
|
Task* task=currentTask;
|
|
|
|
currentTask=NULL;
|
|
|
|
// Wait for an IRQ whose handler unblocks a task
|
|
|
|
do {
|
|
|
|
asm volatile("sti");
|
|
|
|
asm volatile("hlt");
|
|
|
|
asm volatile("cli");
|
|
|
|
} while (readyToRunHead==NULL);
|
|
|
|
currentTask=task;
|
|
|
|
} else {
|
|
|
|
serial_printf("Yield failed, no other ready tasks\n");
|
|
|
|
return;
|
2020-07-12 14:28:58 -05:00
|
|
|
}
|
2020-07-12 16:29:57 -05:00
|
|
|
}
|
|
|
|
switch_to_task(readyToRunHead);
|
|
|
|
} else {
|
|
|
|
serial_printf("Attempting to yield to PID %d",pid);
|
|
|
|
Task* task=tasks[pid];
|
|
|
|
if (!task) {
|
|
|
|
serial_printf("PID %d does not exist.\n",pid);
|
2020-07-12 14:28:58 -05:00
|
|
|
return;
|
|
|
|
}
|
2020-07-12 16:29:57 -05:00
|
|
|
if (task->state!=TASK_READY) {
|
|
|
|
serial_printf("PID %d is blocked");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
switch_to_task(task);
|
2020-07-12 14:28:58 -05:00
|
|
|
}
|
2019-02-11 09:30:28 -06:00
|
|
|
}
|
2019-08-25 17:32:08 -05:00
|
|
|
void tasking_exit(uint8_t code) {
|
|
|
|
serial_printf("PID %d is exiting with code %d.\n",currentTask->pid,code);
|
2020-07-12 14:28:58 -05:00
|
|
|
currentTask->state=TASK_EXITED;
|
|
|
|
if (exitedTasksHead) {
|
|
|
|
exitedTasksTail->next=currentTask;
|
|
|
|
currentTask->prev=exitedTasksHead;
|
|
|
|
exitedTasksTail=currentTask;
|
|
|
|
} else {
|
|
|
|
exitedTasksHead=currentTask;
|
|
|
|
exitedTasksTail=currentTask;
|
2019-08-25 17:32:08 -05:00
|
|
|
}
|
2020-07-12 14:28:58 -05:00
|
|
|
running_blocked_tasks--;
|
2020-07-12 16:29:57 -05:00
|
|
|
tasking_yield(0);
|
2019-08-25 17:32:08 -05:00
|
|
|
}
|
|
|
|
|
2019-07-20 11:03:27 -05:00
|
|
|
uint32_t getPID() {
|
|
|
|
return currentTask->pid;
|
|
|
|
}
|
2020-07-12 14:28:58 -05:00
|
|
|
|
|
|
|
void tasking_block(TaskState newstate) {
|
|
|
|
if (newstate==TASK_RUNNING || newstate==TASK_READY || newstate==TASK_EXITED) {
|
|
|
|
serial_printf("Attempted to block task using a new state of running/ready/exited. This is an error.\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
serial_printf("Blocking PID %d with state %d\n",currentTask->pid,currentTask->state);
|
|
|
|
currentTask->state = newstate;
|
2020-07-12 16:29:57 -05:00
|
|
|
tasking_yield(0);
|
2020-07-12 14:28:58 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void tasking_unblock(pid_t pid) {
|
2020-07-12 16:29:57 -05:00
|
|
|
serial_printf("Unblocking PID %d\n",pid);
|
2020-07-12 14:28:58 -05:00
|
|
|
tasks[pid]->state=TASK_READY;
|
|
|
|
if(readyToRunHead) {
|
|
|
|
readyToRunTail->next=tasks[pid];
|
|
|
|
readyToRunTail=tasks[pid];
|
|
|
|
} else {
|
|
|
|
readyToRunHead=tasks[pid];
|
|
|
|
readyToRunTail=tasks[pid];
|
|
|
|
}
|
|
|
|
}
|