Tasking rewrite & add multi-threading
This commit is contained in:
parent
5b35498538
commit
57c663a0e0
10
init/main.c
10
init/main.c
@ -129,13 +129,21 @@ char load_task(uint32_t datapos,char* initrd) {
|
|||||||
// return 1;
|
// return 1;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
void thread() {
|
||||||
|
for (;;) yield();
|
||||||
|
}
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
serial_print("IN INIT\n");
|
serial_print("IN INIT\n");
|
||||||
|
new_thread(thread);
|
||||||
blockTask(TASK_BLOCKED);
|
blockTask(TASK_BLOCKED);
|
||||||
for (int i=0;i<4;i++) {
|
for (int i=0;i<5;i++) {
|
||||||
|
serial_print("YIELDING\n");
|
||||||
yield();
|
yield();
|
||||||
|
serial_print("YIELDED\n");
|
||||||
}
|
}
|
||||||
|
serial_print("EXITING\n");
|
||||||
|
exit(0);
|
||||||
// long size=initrd_sz();
|
// long size=initrd_sz();
|
||||||
// char* initrd=malloc(size);
|
// char* initrd=malloc(size);
|
||||||
// initrd_get(initrd);
|
// initrd_get(initrd);
|
||||||
|
@ -17,8 +17,6 @@
|
|||||||
void irq_handler(registers_t* r);
|
void irq_handler(registers_t* r);
|
||||||
static isr_t interrupt_handlers[256];
|
static isr_t interrupt_handlers[256];
|
||||||
|
|
||||||
extern Task* currentTask;
|
|
||||||
|
|
||||||
/* Can't do this with a loop because we need the address
|
/* Can't do this with a loop because we need the address
|
||||||
* of the function names */
|
* of the function names */
|
||||||
void isr_install() {
|
void isr_install() {
|
||||||
@ -131,47 +129,47 @@ __attribute__((unused)) static char *exception_messages[] = {
|
|||||||
|
|
||||||
void isr_handler(registers_t* r) {
|
void isr_handler(registers_t* r) {
|
||||||
if (r->int_no!=80 && r->int_no!=14) {
|
if (r->int_no!=80 && r->int_no!=14) {
|
||||||
vga_write_string(exception_messages[r->int_no]);
|
serial_write_string(exception_messages[r->int_no]);
|
||||||
}
|
}
|
||||||
switch (r->int_no) {
|
switch (r->int_no) {
|
||||||
case 14: {
|
case 14: {
|
||||||
serial_write_string("PAGE FAULT\n");
|
serial_write_string("PAGE FAULT\n");
|
||||||
uint32_t addr;
|
uint32_t addr;
|
||||||
asm("movl %%cr2,%0": "=r"(addr));
|
asm("movl %%cr2,%0": "=r"(addr));
|
||||||
vga_write_string("In PID ");
|
// serial_write_string("In PID ");
|
||||||
char str[11];
|
char str[11];
|
||||||
int_to_ascii(getPID(),str);
|
// int_to_ascii(getPID(),str);
|
||||||
vga_write_string(str);
|
// serial_write_string(str);
|
||||||
vga_write_string(" and address ");
|
serial_write_string(" and address ");
|
||||||
str[0]='\0';
|
str[0]='\0';
|
||||||
hex_to_ascii(r->eip,str);
|
hex_to_ascii(r->eip,str);
|
||||||
vga_write_string(str);
|
serial_write_string(str);
|
||||||
if (r->err_code==0) {
|
if (r->err_code==0) {
|
||||||
vga_write_string(", kernel process tried to read a non-present page entry at address ");
|
serial_write_string(", kernel process tried to read a non-present page entry at address ");
|
||||||
} else if (r->err_code==1) {
|
} else if (r->err_code==1) {
|
||||||
vga_write_string(", kernel process tried to read a page and caused a protection fault at address ");
|
serial_write_string(", kernel process tried to read a page and caused a protection fault at address ");
|
||||||
} else if (r->err_code==2) {
|
} else if (r->err_code==2) {
|
||||||
vga_write_string(", kernel process tried to write to a non-present page entry at address ");
|
serial_write_string(", kernel process tried to write to a non-present page entry at address ");
|
||||||
} else if (r->err_code==3) {
|
} else if (r->err_code==3) {
|
||||||
vga_write_string(", kernel process tried to write a page and caused a protection fault at address ");
|
serial_write_string(", kernel process tried to write a page and caused a protection fault at address ");
|
||||||
} else if (r->err_code==4) {
|
} else if (r->err_code==4) {
|
||||||
vga_write_string(", user process tried to read a non-present page entry at address ");
|
serial_write_string(", user process tried to read a non-present page entry at address ");
|
||||||
} else if (r->err_code==5) {
|
} else if (r->err_code==5) {
|
||||||
vga_write_string(", user process tried to read a page and caused a protection fault at address ");
|
serial_write_string(", user process tried to read a page and caused a protection fault at address ");
|
||||||
} else if (r->err_code==6) {
|
} else if (r->err_code==6) {
|
||||||
vga_write_string(", user process tried to write to a non-present page entry at address ");
|
serial_write_string(", user process tried to write to a non-present page entry at address ");
|
||||||
} else if (r->err_code==7) {
|
} else if (r->err_code==7) {
|
||||||
vga_write_string(", user process tried to write a page and caused a protection fault at address ");
|
serial_write_string(", user process tried to write a page and caused a protection fault at address ");
|
||||||
}
|
}
|
||||||
str[0]='\0';
|
str[0]='\0';
|
||||||
hex_to_ascii(addr,str);
|
hex_to_ascii(addr,str);
|
||||||
vga_write_string(str);
|
serial_write_string(str);
|
||||||
vga_write_string(".");
|
serial_write_string(".");
|
||||||
vga_write_string(" Stack is at ");
|
serial_write_string(" Stack is at ");
|
||||||
str[0]='\0';
|
str[0]='\0';
|
||||||
hex_to_ascii(r->useresp,str);
|
hex_to_ascii(r->useresp,str);
|
||||||
vga_write_string(str);
|
serial_write_string(str);
|
||||||
vga_write_string(".\n");
|
serial_write_string(".\n");
|
||||||
// if ((r->err_code&1)==0) {
|
// if ((r->err_code&1)==0) {
|
||||||
// // int dir_entry=(addr&0xFFC00000)>>22;
|
// // int dir_entry=(addr&0xFFC00000)>>22;
|
||||||
// // int table_entry=(addr&0x3FF000)>12;
|
// // int table_entry=(addr&0x3FF000)>12;
|
||||||
@ -194,16 +192,16 @@ void isr_handler(registers_t* r) {
|
|||||||
case 80:
|
case 80:
|
||||||
switch (r->eax) {
|
switch (r->eax) {
|
||||||
case SYSCALL_CREATEPROC:
|
case SYSCALL_CREATEPROC:
|
||||||
tasking_createTaskCr3KmodeParam((void*)r->ebx,(void*)r->ecx,0,r->edx,r->esi,r->edx,r->edi);
|
tasking_createTask((void*)r->ebx,(void*)r->ecx,0,r->edx,r->esi,r->edx,r->edi,0);
|
||||||
break;
|
break;
|
||||||
case SYSCALL_YIELD:
|
case SYSCALL_YIELD:
|
||||||
tasking_yield(r->ebx);
|
tasking_yield();
|
||||||
break;
|
break;
|
||||||
case SYSCALL_BLOCK:
|
case SYSCALL_BLOCK:
|
||||||
tasking_block(r->ebx);
|
tasking_block(r->ebx);
|
||||||
break;
|
break;
|
||||||
case SYSCALL_UNBLOCK:
|
case SYSCALL_UNBLOCK:
|
||||||
tasking_unblock(r->ebx);
|
tasking_unblock(r->ebx,r->ecx);
|
||||||
break;
|
break;
|
||||||
case SYSCALL_EXIT:
|
case SYSCALL_EXIT:
|
||||||
tasking_exit((uint8_t)r->ebx);
|
tasking_exit((uint8_t)r->ebx);
|
||||||
@ -222,7 +220,7 @@ void isr_handler(registers_t* r) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SYSCALL_PRIV_MAP_PAGES:
|
case SYSCALL_PRIV_MAP_PAGES:
|
||||||
if (!currentTask->priv) {
|
if (tasking_isPrivleged()) {
|
||||||
r->ebx=0;
|
r->ebx=0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -252,6 +250,9 @@ void isr_handler(registers_t* r) {
|
|||||||
serial_printf("Copying initrd\n");
|
serial_printf("Copying initrd\n");
|
||||||
memcpy((char*)r->ebx,initrd,initrd_sz);
|
memcpy((char*)r->ebx,initrd,initrd_sz);
|
||||||
break;
|
break;
|
||||||
|
case SYSCALL_NEW_THREAD:
|
||||||
|
tasking_new_thread((void*)r->ebx);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -9,11 +9,11 @@
|
|||||||
|
|
||||||
static uint32_t page_directory[1024] __attribute__((aligned(4096)));
|
static uint32_t page_directory[1024] __attribute__((aligned(4096)));
|
||||||
static uint32_t kern_page_tables[NUM_KERN_DIRS*1024] __attribute__((aligned(4096)));
|
static uint32_t kern_page_tables[NUM_KERN_DIRS*1024] __attribute__((aligned(4096)));
|
||||||
static uint32_t kstack_page_tables[32*1024] __attribute__((aligned(4096)));
|
static uint32_t kstack_page_tables[218*1024] __attribute__((aligned(4096)));
|
||||||
static uint32_t kmalloc_page_tables[4*1024] __attribute__((aligned(4096)));
|
static uint32_t kmalloc_page_tables[4*1024] __attribute__((aligned(4096)));
|
||||||
static uint32_t smap_page_tables[2048] __attribute__((aligned(4096)));
|
static uint32_t smap_page_tables[2048] __attribute__((aligned(4096)));
|
||||||
static uint32_t* smap=(uint32_t*)0xFF800000;
|
static uint32_t* smap=(uint32_t*)0xFF800000;
|
||||||
|
static uint32_t kstack_bmap[(218*1024)/8];
|
||||||
static char is_page_present(int page) {
|
static char is_page_present(int page) {
|
||||||
int table=page>>10;
|
int table=page>>10;
|
||||||
page=page&0x3FF;
|
page=page&0x3FF;
|
||||||
@ -50,10 +50,42 @@ void map_pages(void* virt_addr_ptr,void* phys_addr_ptr,int num_pages,char usr,ch
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void map_kstack(uint32_t pid) {
|
|
||||||
if (!(kstack_page_tables[pid]&0x1)) {
|
static char get_bmap_bit(uint32_t index) {
|
||||||
kstack_page_tables[pid]=(uint32_t)pmem_alloc(1)|0x3;
|
uint32_t byte=index/8;
|
||||||
|
uint32_t bit=index%8;
|
||||||
|
char entry=kstack_bmap[byte];
|
||||||
|
return (entry&(1<<bit))>0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set_bmap_bit(uint32_t index) {
|
||||||
|
uint32_t byte=index/8;
|
||||||
|
uint32_t bit=index%8;
|
||||||
|
kstack_bmap[byte]=kstack_bmap[byte]|(1<<bit);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void clear_bmap_bit(uint32_t index) {
|
||||||
|
uint32_t byte=index/8;
|
||||||
|
uint32_t bit=index%8;
|
||||||
|
kstack_bmap[byte]=kstack_bmap[byte]&(~(1<<bit));
|
||||||
|
}
|
||||||
|
|
||||||
|
int new_kstack() {
|
||||||
|
int num=-1;
|
||||||
|
for (int i=0;i<(218*1024);i++) {
|
||||||
|
if (get_bmap_bit(i)==0) {
|
||||||
|
num=i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
if (num==-1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
set_bmap_bit(num);
|
||||||
|
if (!(kstack_page_tables[num]&0x1)) {
|
||||||
|
kstack_page_tables[num]=(uint32_t)pmem_alloc(1)|0x3;
|
||||||
|
}
|
||||||
|
return num;
|
||||||
}
|
}
|
||||||
|
|
||||||
void* find_free_pages(int num_pages) {
|
void* find_free_pages(int num_pages) {
|
||||||
@ -204,7 +236,7 @@ void paging_init() {
|
|||||||
for (uint32_t i=0;i<NUM_KERN_DIRS*1024;i++) {
|
for (uint32_t i=0;i<NUM_KERN_DIRS*1024;i++) {
|
||||||
kern_page_tables[i]=(i<<12)|0x3;
|
kern_page_tables[i]=(i<<12)|0x3;
|
||||||
}
|
}
|
||||||
for (uint32_t i=0;i<32*1024;i++) {
|
for (uint32_t i=0;i<218*1024;i++) {
|
||||||
kstack_page_tables[i]=0;
|
kstack_page_tables[i]=0;
|
||||||
}
|
}
|
||||||
for (uint32_t i=0;i<4*1024;i++) {
|
for (uint32_t i=0;i<4*1024;i++) {
|
||||||
@ -219,9 +251,12 @@ void paging_init() {
|
|||||||
page_directory[i+768]=(entry_virt-0xC0000000)|0x3;
|
page_directory[i+768]=(entry_virt-0xC0000000)|0x3;
|
||||||
}
|
}
|
||||||
page_directory[985]=(uint32_t)(pmem_alloc(1024))|0x83;
|
page_directory[985]=(uint32_t)(pmem_alloc(1024))|0x83;
|
||||||
for (uint32_t i=0;i<32;i++) {
|
for (uint32_t i=0;i<10;i++) {
|
||||||
uint32_t entry_virt=(uint32_t)&(kstack_page_tables[i*1024]);
|
uint32_t entry_virt=(uint32_t)&(kstack_page_tables[i*1024]);
|
||||||
page_directory[i+986]=(entry_virt-0xC0000000)|0x3;
|
page_directory[i+800]=(entry_virt-0xC0000000)|0x3;
|
||||||
|
}
|
||||||
|
for (uint32_t i=0;i<(218*1024)/8;i++) {
|
||||||
|
kstack_bmap[i]=0;
|
||||||
}
|
}
|
||||||
for (uint32_t i=0;i<4;i++) {
|
for (uint32_t i=0;i<4;i++) {
|
||||||
uint32_t entry_virt=(uint32_t)&(kmalloc_page_tables[i*1024]);
|
uint32_t entry_virt=(uint32_t)&(kmalloc_page_tables[i*1024]);
|
||||||
|
@ -4,10 +4,10 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "paging_helpers.h"
|
#include "paging_helpers.h"
|
||||||
|
|
||||||
#define NUM_KERN_DIRS 1
|
#define NUM_KERN_DIRS 4
|
||||||
|
|
||||||
void map_pages(void* virt_addr_ptr,void* phys_addr_ptr,int num_pages,char usr,char wr);
|
void map_pages(void* virt_addr_ptr,void* phys_addr_ptr,int num_pages,char usr,char wr);
|
||||||
void map_kstack(uint32_t pid);
|
int new_kstack();
|
||||||
void unmap_pages(void* start_virt,uint32_t num_pages);
|
void unmap_pages(void* start_virt,uint32_t num_pages);
|
||||||
void* alloc_pages(int num_pages);
|
void* alloc_pages(int num_pages);
|
||||||
void alloc_pages_virt(int num_pages,void* addr);
|
void alloc_pages_virt(int num_pages,void* addr);
|
||||||
@ -16,6 +16,7 @@ void* paging_new_address_space();
|
|||||||
void load_address_space(uint32_t cr3);
|
void load_address_space(uint32_t cr3);
|
||||||
void* virt_to_phys(void* virt_addr);
|
void* virt_to_phys(void* virt_addr);
|
||||||
void* find_free_pages(int num_pages);
|
void* find_free_pages(int num_pages);
|
||||||
|
void* find_free_pages_wstart(int num_pages,int start_page);
|
||||||
void load_smap(uint32_t cr3);
|
void load_smap(uint32_t cr3);
|
||||||
char make_protector(int page);
|
char make_protector(int page);
|
||||||
char is_in_protector(uint32_t* addr);
|
char is_in_protector(uint32_t* addr);
|
||||||
|
@ -1,254 +1,358 @@
|
|||||||
#include "tasking_helpers.h"
|
|
||||||
#include "tasking.h"
|
#include "tasking.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"
|
|
||||||
#include "../../vga_err.h"
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#define STACK_PAGES 2
|
#include "kmalloc.h"
|
||||||
|
#include "serial.h"
|
||||||
extern void task_init();
|
#include "../halt.h"
|
||||||
static uint32_t* kstacks=(uint32_t*)0xF6800000;
|
#include "paging.h"
|
||||||
|
#include "tasking_helpers.h"
|
||||||
|
#define MAX_PROCS 32768
|
||||||
|
#define HAS_UNBLOCKED_THREADS(proc) (proc->numThreads!=proc->numThreadsBlocked)
|
||||||
|
#define NUM_UNBLOCKED_THREADS(proc) (proc->numThreads-proc->numThreadsBlocked)
|
||||||
|
#define SAME_PROC(thread1,thread2) (thread1->process->pid==thread2->process->pid)
|
||||||
|
#define SAME_THREAD(thread1,thread2) (thread1->process->pid==thread2->process->pid&&thread1->tid==thread2->tid)
|
||||||
uint32_t next_pid=0;
|
uint32_t next_pid=0;
|
||||||
uint32_t running_blocked_tasks=0;
|
uint32_t num_procs=0;
|
||||||
Task* currentTask=NULL;
|
Process* processes[MAX_PROCS];
|
||||||
static Task* readyToRunHead=NULL;
|
char proc_schedule_bmap[MAX_PROCS/8];
|
||||||
static Task* readyToRunTail=NULL;
|
Thread* currentThread;
|
||||||
static Task* exitedTasksHead=NULL;
|
static Thread* readyToRunHead=NULL;
|
||||||
static Task* exitedTasksTail=NULL;
|
static Thread* readyToRunTail=NULL;
|
||||||
static Task* tasks[32768];
|
static uint32_t* kstacks=(uint32_t*)0xC8000000;
|
||||||
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) {
|
static char is_proc_scheduled(uint32_t index) {
|
||||||
tasking_createTaskCr3KmodeParam(NULL,paging_new_address_space(),1,0,0,0,0);
|
uint32_t byte=index/8;
|
||||||
|
uint32_t bit=index%8;
|
||||||
|
char entry=proc_schedule_bmap[byte];
|
||||||
|
return (entry&(1<<bit))>0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Task* tasking_createTaskCr3KmodeParam(void* eip,void* cr3,char kmode,char param1_exists,uint32_t param1_arg,char param2_exists,uint32_t param2_arg) {
|
static void mark_proc_scheduled(uint32_t index) {
|
||||||
if (next_pid>1024*32) {
|
if (is_proc_scheduled(index)) {
|
||||||
serial_printf("Failed to create a task, as 32k tasks have been created already.\n");
|
serial_printf("Attempt to schedule a thread in a process with a scheduled thread! (PID %d)\n",index);
|
||||||
halt(); //Cannot ever create more than 32k tasks, as I don't currently reuse PIDs.
|
halt();
|
||||||
|
}
|
||||||
|
uint32_t byte=index/8;
|
||||||
|
uint32_t bit=index%8;
|
||||||
|
proc_schedule_bmap[byte]=proc_schedule_bmap[byte]|(1<<bit);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void unmark_proc_scheduled(uint32_t index) {
|
||||||
|
uint32_t byte=index/8;
|
||||||
|
uint32_t bit=index%8;
|
||||||
|
proc_schedule_bmap[byte]=proc_schedule_bmap[byte]&(~(1<<bit));
|
||||||
|
}
|
||||||
|
|
||||||
|
void tasking_createTask(void* eip,void* cr3,char kmode,char param1_exists,uint32_t param1_arg,char param2_exists,uint32_t param2_arg,char isThread) {
|
||||||
|
if (next_pid>MAX_PROCS && !isThread) {
|
||||||
|
serial_printf("Failed to create a process, as 32k processes have been created already.\n");
|
||||||
|
halt(); //Cannot ever create more than 32k processes, as I don't currently reuse PIDs.
|
||||||
|
}
|
||||||
|
uint32_t param1;
|
||||||
|
if (param1_exists) {
|
||||||
|
param1=param1_arg;
|
||||||
|
} else {
|
||||||
|
param1=1;
|
||||||
|
}
|
||||||
|
uint32_t param2;
|
||||||
|
if (param2_exists) {
|
||||||
|
if (isThread) {
|
||||||
|
serial_printf("Param2 in Thread!\n");
|
||||||
|
halt();
|
||||||
}
|
}
|
||||||
Task* task=kmalloc(sizeof(Task));
|
param2=param2_arg;
|
||||||
map_kstack(next_pid);
|
} else {
|
||||||
uint32_t param1;
|
param2=2;
|
||||||
if (param1_exists) {
|
}
|
||||||
param1=param1_arg;
|
Process* proc;
|
||||||
|
Thread* thread=kmalloc(sizeof(Thread));
|
||||||
|
if (isThread) {
|
||||||
|
proc=processes[(pid_t)param2_arg];
|
||||||
|
proc->numThreads++;
|
||||||
|
thread->cr3=proc->firstThread->cr3;
|
||||||
|
} else {
|
||||||
|
proc=kmalloc(sizeof(Process));
|
||||||
|
if (currentThread) {
|
||||||
|
proc->priv=currentThread->process->priv;
|
||||||
} else {
|
} else {
|
||||||
param1=1;
|
proc->priv=1;
|
||||||
}
|
}
|
||||||
uint32_t param2;
|
proc->pid=next_pid;
|
||||||
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(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);
|
|
||||||
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;
|
|
||||||
task->priv=0;
|
|
||||||
task->errno=0;
|
|
||||||
if (currentTask) {
|
|
||||||
task->priv=currentTask->priv;
|
|
||||||
}
|
|
||||||
if (task->pid==1) {
|
|
||||||
task->priv=1;
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
} else {
|
|
||||||
task->state=TASK_RUNNING;
|
|
||||||
currentTask=task;
|
|
||||||
}
|
|
||||||
tasks[next_pid]=task;
|
|
||||||
next_pid++;
|
next_pid++;
|
||||||
running_blocked_tasks++;
|
proc->next_tid=0;
|
||||||
if (task->pid!=0) {
|
proc->numThreads=1;
|
||||||
serial_printf("Created task with PID %d.\n",task->pid);
|
proc->numThreadsBlocked=0;
|
||||||
|
proc->firstThread=thread;
|
||||||
|
processes[proc->pid]=proc;
|
||||||
|
thread->cr3=cr3;
|
||||||
|
}
|
||||||
|
thread->process=proc;
|
||||||
|
thread->errno=0;
|
||||||
|
thread->tid=proc->next_tid;
|
||||||
|
proc->next_tid++;
|
||||||
|
void* old_cr3;
|
||||||
|
asm volatile("movl %%cr3, %%eax; movl %%eax, %0;":"=m"(old_cr3)::"%eax");
|
||||||
|
uint32_t kstack_num=new_kstack();
|
||||||
|
load_address_space((uint32_t)thread->cr3);
|
||||||
|
if (kmode) {
|
||||||
|
uint32_t top_idx=(1024*(kstack_num+1));
|
||||||
|
thread->kernel_esp=((uint32_t)(&kstacks[top_idx-5]));
|
||||||
|
thread->kernel_esp_top=thread->kernel_esp;
|
||||||
|
kstacks[top_idx-1]=(uint32_t)eip;
|
||||||
|
} else {
|
||||||
|
uint32_t top_idx=(1024*(kstack_num+1));
|
||||||
|
thread->kernel_esp=((uint32_t)(&kstacks[top_idx-7]));
|
||||||
|
thread->kernel_esp_top=thread->kernel_esp;
|
||||||
|
kstacks[top_idx-3]=(uint32_t)task_init;
|
||||||
|
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);
|
||||||
|
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((uint32_t)old_cr3);
|
||||||
|
thread->prevReadyToRun=NULL;
|
||||||
|
thread->nextReadyToRun=NULL;
|
||||||
|
if (isThread) {
|
||||||
|
thread->nextThreadInProcess=proc->firstThread;
|
||||||
|
thread->prevThreadInProcess=NULL;
|
||||||
|
thread->state=THREAD_READY;
|
||||||
|
proc->firstThread->prevThreadInProcess=thread;
|
||||||
|
proc->firstThread=thread;
|
||||||
|
} else {
|
||||||
|
thread->nextThreadInProcess=NULL;
|
||||||
|
thread->prevThreadInProcess=NULL;
|
||||||
|
if (!is_proc_scheduled(proc->pid)) {
|
||||||
|
if (readyToRunTail) {
|
||||||
|
thread->state=THREAD_READY;
|
||||||
|
readyToRunTail->nextReadyToRun=thread;
|
||||||
|
thread->prevReadyToRun=readyToRunTail;
|
||||||
|
readyToRunTail=thread;
|
||||||
|
mark_proc_scheduled(proc->pid);
|
||||||
|
} else if (currentThread) {
|
||||||
|
thread->state=THREAD_READY;
|
||||||
|
readyToRunHead=thread;
|
||||||
|
readyToRunTail=thread;
|
||||||
|
mark_proc_scheduled(proc->pid);
|
||||||
|
} else {
|
||||||
|
thread->state=THREAD_RUNNING;
|
||||||
|
currentThread=thread;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return task;
|
}
|
||||||
|
if (!isThread) {
|
||||||
|
num_procs++;
|
||||||
|
}
|
||||||
|
serial_printf("Created thread with PID %d and TID %d.\n",proc->pid,thread->tid);
|
||||||
|
}
|
||||||
|
|
||||||
|
void tasking_init() {
|
||||||
|
void* cr3;
|
||||||
|
asm volatile("movl %%cr3, %%eax; movl %%eax, %0;":"=m"(cr3)::"%eax");
|
||||||
|
tasking_createTask(NULL,cr3,1,0,0,0,0,0);
|
||||||
|
}
|
||||||
|
|
||||||
|
char tasking_isPrivleged() {
|
||||||
|
return currentThread->process->priv;
|
||||||
|
}
|
||||||
|
|
||||||
|
pid_t getPID() {
|
||||||
|
return currentThread->process->pid;
|
||||||
}
|
}
|
||||||
|
|
||||||
int* tasking_get_errno_address() {
|
int* tasking_get_errno_address() {
|
||||||
return &(currentTask->errno);
|
return ¤tThread->errno;
|
||||||
}
|
|
||||||
char isPrivleged(uint32_t pid) {
|
|
||||||
for (Task* task=readyToRunHead;task!=NULL;task=task->next) {
|
|
||||||
if (task->pid==pid) {
|
|
||||||
return task->priv;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Task* tasking_createTask(void* eip) {
|
void tasking_new_thread(void* start) {
|
||||||
return tasking_createTaskCr3KmodeParam(eip,paging_new_address_space(),0,0,0,0,0);
|
tasking_createTask(start,NULL,0,0,0,0,getPID(),1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void switch_to_task(Task* task) {
|
void switch_to_thread(Thread* thread) {
|
||||||
if (task!=readyToRunHead) {
|
// Unlink the thread from the list of ready-to-run threads
|
||||||
// Unlink it from the doubly-linked list of ready-to-run tasks
|
if (thread!=readyToRunHead) {
|
||||||
task->prev->next=task->next;
|
thread->prevReadyToRun->nextReadyToRun=thread->nextReadyToRun;
|
||||||
if (task->next) {
|
if (thread->nextReadyToRun) {
|
||||||
task->next->prev=task->prev;
|
thread->nextReadyToRun->prevReadyToRun=thread->prevReadyToRun;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Unlink the task from the list by advancing the ready to run pointer to the next task
|
readyToRunHead=thread->nextReadyToRun;
|
||||||
readyToRunHead=task->next;
|
|
||||||
// If the task did not have a next task, also clear the ready to run tail pointer
|
|
||||||
if (readyToRunHead==NULL) {
|
if (readyToRunHead==NULL) {
|
||||||
readyToRunTail=NULL;
|
readyToRunTail=NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
task->prev=NULL;
|
unmark_proc_scheduled(thread->process->pid);
|
||||||
task->next=NULL;
|
thread->prevReadyToRun=NULL;
|
||||||
task->state=TASK_RUNNING;
|
thread->nextReadyToRun=NULL;
|
||||||
if (currentTask->state==TASK_RUNNING) {
|
if (currentThread->state==THREAD_RUNNING) {
|
||||||
currentTask->state=TASK_READY;
|
currentThread->state=THREAD_READY;
|
||||||
// Link the task onto the list of ready to run tasks
|
}
|
||||||
if (readyToRunTail) {
|
Thread* currentThreadNextReady=currentThread->nextThreadInProcess;
|
||||||
currentTask->prev=readyToRunTail;
|
while ((currentThreadNextReady&¤tThreadNextReady->state!=THREAD_READY)||(currentThreadNextReady&&SAME_THREAD(thread,currentThreadNextReady))) {
|
||||||
readyToRunTail->next=currentTask;
|
currentThreadNextReady=currentThreadNextReady->nextThreadInProcess;
|
||||||
readyToRunTail=currentTask;
|
}
|
||||||
} else {
|
if (!currentThreadNextReady) {
|
||||||
readyToRunHead=currentTask;
|
currentThreadNextReady=currentThread->process->firstThread;
|
||||||
readyToRunTail=currentTask;
|
while ((currentThreadNextReady&¤tThreadNextReady->state!=THREAD_READY)||(currentThreadNextReady&&SAME_THREAD(thread,currentThreadNextReady))) {
|
||||||
|
currentThreadNextReady=currentThreadNextReady->nextThreadInProcess;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
serial_printf("Yielding to PID %d.\n",task->pid);
|
if (!currentThreadNextReady) {
|
||||||
load_smap(task->cr3);
|
//This process is fully blocked, try the process of the thread we're yielding to
|
||||||
switch_to_task_asm(task);
|
currentThreadNextReady=thread->nextThreadInProcess;
|
||||||
}
|
while ((currentThreadNextReady&¤tThreadNextReady->state!=THREAD_READY)||(currentThreadNextReady&&SAME_THREAD(thread,currentThreadNextReady))) {
|
||||||
|
currentThreadNextReady=currentThreadNextReady->nextThreadInProcess;
|
||||||
void tasking_yield(pid_t pid) {
|
}
|
||||||
if (pid==0) {
|
if (!currentThreadNextReady) {
|
||||||
if (!readyToRunHead) {
|
currentThreadNextReady=thread->process->firstThread;
|
||||||
if (currentTask->state!=TASK_RUNNING) {
|
while ((currentThreadNextReady&¤tThreadNextReady->state!=THREAD_READY)||(currentThreadNextReady&&SAME_THREAD(thread,currentThreadNextReady))) {
|
||||||
//This indicates either all tasks are bloked or the os has shutdown. Check which one it is
|
currentThreadNextReady=currentThreadNextReady->nextThreadInProcess;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (task->state!=TASK_READY) {
|
|
||||||
serial_printf("PID %d is blocked");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
switch_to_task(task);
|
|
||||||
}
|
}
|
||||||
}
|
if (currentThreadNextReady && !is_proc_scheduled(currentThread->process->pid)) {
|
||||||
void tasking_exit(uint8_t code) {
|
// Link the task onto the list of ready to run tasks
|
||||||
serial_printf("PID %d is exiting with code %d.\n",currentTask->pid,code);
|
if (readyToRunTail) {
|
||||||
currentTask->state=TASK_EXITED;
|
currentThreadNextReady->prevReadyToRun=readyToRunTail;
|
||||||
if (exitedTasksHead) {
|
readyToRunTail->nextThreadInProcess=currentThreadNextReady;
|
||||||
exitedTasksTail->next=currentTask;
|
readyToRunTail=currentThreadNextReady;
|
||||||
currentTask->prev=exitedTasksHead;
|
|
||||||
exitedTasksTail=currentTask;
|
|
||||||
} else {
|
|
||||||
exitedTasksHead=currentTask;
|
|
||||||
exitedTasksTail=currentTask;
|
|
||||||
}
|
|
||||||
running_blocked_tasks--;
|
|
||||||
tasking_yield(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t getPID() {
|
|
||||||
return currentTask->pid;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
tasking_yield(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void tasking_unblock(pid_t pid) {
|
|
||||||
serial_printf("Unblocking PID %d\n",pid);
|
|
||||||
tasks[pid]->state=TASK_READY;
|
|
||||||
if(readyToRunHead) {
|
|
||||||
readyToRunTail->next=tasks[pid];
|
|
||||||
readyToRunTail=tasks[pid];
|
|
||||||
} else {
|
} else {
|
||||||
readyToRunHead=tasks[pid];
|
readyToRunHead=currentThreadNextReady;
|
||||||
readyToRunTail=tasks[pid];
|
readyToRunTail=currentThreadNextReady;
|
||||||
}
|
}
|
||||||
|
mark_proc_scheduled(currentThread->process->pid);
|
||||||
|
}
|
||||||
|
serial_printf("Switching to PID %d TID %d.\n",thread->process->pid,thread->tid);
|
||||||
|
load_smap((uint32_t)thread->cr3);
|
||||||
|
switch_to_thread_asm(thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
void tasking_yield() {
|
||||||
|
serial_printf("Attempting to yield\n");
|
||||||
|
if (readyToRunHead) {
|
||||||
|
serial_printf("Attempting to switch to PID %d TID %d\n",readyToRunHead->process->pid,readyToRunHead->tid);
|
||||||
|
switch_to_thread(readyToRunHead);
|
||||||
|
} else {
|
||||||
|
if (NUM_UNBLOCKED_THREADS(currentThread->process)>1) {
|
||||||
|
serial_printf("The ready to run list is empty, and the current process has other unblocked threads? This is an invalid state! Halting!\n");
|
||||||
|
halt();
|
||||||
|
} else if (NUM_UNBLOCKED_THREADS(currentThread->process)==1) {
|
||||||
|
serial_printf("Yield failed, no other ready processes\n");
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
if (num_procs==0) {
|
||||||
|
serial_printf("All processes exited, halting\n");
|
||||||
|
halt();
|
||||||
|
} else {
|
||||||
|
serial_printf("All threads in all processes blocked, waiting for an IRQ which unblocks a thread\n");
|
||||||
|
// All threads in all processes blocked, so wait for an IRQ whose handler unblocks a thread.
|
||||||
|
do {
|
||||||
|
asm volatile("sti"); //As interrupts are stopped, re-enable them.
|
||||||
|
asm volatile("hlt"); //Wait for an interrupt handler to run and return.
|
||||||
|
asm volatile("cli"); //Clear interrupts, as tasking code must not be interrupted.
|
||||||
|
} while (readyToRunHead==NULL);
|
||||||
|
}
|
||||||
|
serial_printf("Attempting to switch to PID %d TID %d\n",readyToRunHead->process->pid,readyToRunHead->tid);
|
||||||
|
switch_to_thread(readyToRunHead);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void tasking_block(ThreadState newstate) {
|
||||||
|
if (readyToRunHead&&SAME_THREAD(readyToRunHead,currentThread)) {
|
||||||
|
readyToRunHead=readyToRunHead->nextReadyToRun;
|
||||||
|
if (readyToRunHead==NULL) {
|
||||||
|
readyToRunTail=NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (readyToRunTail&&SAME_THREAD(readyToRunTail,currentThread)) {
|
||||||
|
readyToRunTail=readyToRunTail->prevReadyToRun;
|
||||||
|
if (readyToRunTail==NULL) {
|
||||||
|
readyToRunHead=NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (readyToRunHead&&readyToRunHead->nextReadyToRun) {
|
||||||
|
for (Thread* thread=readyToRunHead->nextReadyToRun;thread!=NULL;thread=thread->nextReadyToRun) {
|
||||||
|
if (SAME_THREAD(thread,currentThread)) {
|
||||||
|
thread->prevReadyToRun->nextReadyToRun=thread->nextReadyToRun;
|
||||||
|
if (thread->nextReadyToRun) {
|
||||||
|
thread->nextReadyToRun->prevReadyToRun=thread->prevReadyToRun;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (Thread* thread=currentThread->process->firstThread;thread!=NULL;thread=thread->nextThreadInProcess) {
|
||||||
|
if (thread->tid==currentThread->tid) {
|
||||||
|
thread->state=newstate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void tasking_unblock(pid_t pid,uint32_t tid) {
|
||||||
|
serial_printf("Unblocking PID %d TID %d\n",pid,tid);
|
||||||
|
if (!processes[pid]) {
|
||||||
|
serial_printf("PID %d does not exist!\n",pid);
|
||||||
|
}
|
||||||
|
Thread* thread=processes[pid]->firstThread;
|
||||||
|
for (;thread!=NULL;thread=thread->nextThreadInProcess) {
|
||||||
|
if (thread->tid==tid) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!thread) {
|
||||||
|
serial_printf("PID %d TID %d does not exist!\n",pid,thread);
|
||||||
|
}
|
||||||
|
if (thread->tid!=tid) {
|
||||||
|
serial_printf("Error! Got wrong thread! (Wanted TID %d, got TID %d)\n",tid,thread->tid);
|
||||||
|
halt();
|
||||||
|
}
|
||||||
|
thread->state=THREAD_READY;
|
||||||
|
if (!is_proc_scheduled(thread->process->pid)) {
|
||||||
|
// Link the task onto the list of ready to run tasks
|
||||||
|
if (readyToRunTail) {
|
||||||
|
thread->prevReadyToRun=readyToRunTail;
|
||||||
|
readyToRunTail->nextThreadInProcess=thread;
|
||||||
|
readyToRunTail=thread;
|
||||||
|
} else {
|
||||||
|
readyToRunHead=thread;
|
||||||
|
readyToRunTail=thread;
|
||||||
|
}
|
||||||
|
mark_proc_scheduled(thread->process->pid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void tasking_exit(uint8_t code) {
|
||||||
|
serial_printf("PID %d is exiting with code %d.\n",currentThread->process->pid,code);
|
||||||
|
if (readyToRunHead&&SAME_PROC(readyToRunHead,currentThread)) {
|
||||||
|
readyToRunHead=readyToRunHead->nextReadyToRun;
|
||||||
|
if (readyToRunHead==NULL) {
|
||||||
|
readyToRunTail=NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (readyToRunTail&&SAME_PROC(readyToRunTail,currentThread)) {
|
||||||
|
readyToRunTail=readyToRunTail->prevReadyToRun;
|
||||||
|
if (readyToRunTail==NULL) {
|
||||||
|
readyToRunHead=NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (readyToRunHead&&readyToRunHead->nextReadyToRun) {
|
||||||
|
for (Thread* thread=readyToRunHead->nextReadyToRun;thread!=NULL;thread=thread->nextReadyToRun) {
|
||||||
|
if (SAME_PROC(thread,currentThread)) {
|
||||||
|
thread->prevReadyToRun->nextReadyToRun=thread->nextReadyToRun;
|
||||||
|
if (thread->nextReadyToRun) {
|
||||||
|
thread->nextReadyToRun->prevReadyToRun=thread->prevReadyToRun;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (Thread* thread=currentThread->process->firstThread;thread!=NULL;thread=thread->nextThreadInProcess) {
|
||||||
|
thread->state=THREAD_EXITED;
|
||||||
|
}
|
||||||
|
currentThread->process->numThreadsBlocked=currentThread->process->numThreads;
|
||||||
|
num_procs--;
|
||||||
|
tasking_yield();
|
||||||
}
|
}
|
||||||
|
@ -4,24 +4,37 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#ifndef TASKING_H
|
#ifndef TASKING_H
|
||||||
typedef enum TaskState {
|
typedef enum ThreadState {
|
||||||
TASK_RUNNING,
|
THREAD_RUNNING,
|
||||||
TASK_READY,
|
THREAD_READY,
|
||||||
TASK_EXITED,
|
THREAD_EXITED,
|
||||||
TASK_BLOCKED
|
THREAD_BLOCKED
|
||||||
} TaskState;
|
} ThreadState;
|
||||||
#endif
|
#endif
|
||||||
typedef struct Task {
|
|
||||||
|
struct Thread;
|
||||||
|
|
||||||
|
typedef struct Process {
|
||||||
|
char priv;
|
||||||
|
uint32_t pid;
|
||||||
|
uint32_t next_tid;
|
||||||
|
int numThreads;
|
||||||
|
int numThreadsBlocked;
|
||||||
|
struct Thread* firstThread;
|
||||||
|
} Process;
|
||||||
|
|
||||||
|
typedef struct Thread {
|
||||||
uint32_t kernel_esp;
|
uint32_t kernel_esp;
|
||||||
uint32_t kernel_esp_top;
|
uint32_t kernel_esp_top;
|
||||||
uint32_t cr3;
|
void* cr3; //In thread to make the task switch asm easier
|
||||||
uint32_t user_esp;
|
uint32_t tid;
|
||||||
char priv;
|
ThreadState state;
|
||||||
int errno;
|
int errno;
|
||||||
uint32_t pid;
|
struct Thread* nextThreadInProcess;
|
||||||
struct Task* prev;
|
struct Thread* prevThreadInProcess;
|
||||||
struct Task* next;
|
struct Thread* nextReadyToRun;
|
||||||
TaskState state;
|
struct Thread* prevReadyToRun;
|
||||||
} Task;
|
Process* process;
|
||||||
|
} Thread;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
section .text
|
section .text
|
||||||
global switch_to_task_asm
|
global switch_to_thread_asm
|
||||||
extern currentTask
|
extern currentThread
|
||||||
extern tss
|
extern tss
|
||||||
;WARNING: Caller is expected to disable IRQs before calling, and enable IRQs again after function returns
|
;WARNING: Caller is expected to disable IRQs before calling, and enable IRQs again after function returns
|
||||||
|
|
||||||
switch_to_task_asm:
|
switch_to_thread_asm:
|
||||||
|
|
||||||
;Save previous task's state
|
;Save previous task's state
|
||||||
|
|
||||||
@ -19,13 +19,13 @@ switch_to_task_asm:
|
|||||||
push edi
|
push edi
|
||||||
push ebp
|
push ebp
|
||||||
|
|
||||||
mov edi,[currentTask] ;edi = address of the previous task's data structure
|
mov edi,[currentThread] ;edi = address of the previous task's data structure
|
||||||
mov [edi],esp ;Save ESP for the task's kernel stack in the task's data structure
|
mov [edi],esp ;Save ESP for the task's kernel stack in the task's data structure
|
||||||
|
|
||||||
;Load next task's state
|
;Load next task's state
|
||||||
|
|
||||||
mov esi,[esp+(4+1)*4] ;esi = address of the next task's data structure
|
mov esi,[esp+(4+1)*4] ;esi = address of the next task's data structure
|
||||||
mov [currentTask],esi ;Current task's task data is the next task thread data
|
mov [currentThread],esi ;Current task's task data is the next task thread data
|
||||||
|
|
||||||
mov esp,[esi] ;Load ESP for next task's kernel stack from the task's data structure
|
mov esp,[esi] ;Load ESP for next task's kernel stack from the task's data structure
|
||||||
mov eax,[esi+8] ;eax = address of page directory for next task
|
mov eax,[esi+8] ;eax = address of page directory for next task
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "tasking.h"
|
#include "tasking.h"
|
||||||
|
|
||||||
void switch_to_task_asm(Task* task);
|
void switch_to_thread_asm(Thread* thread);
|
||||||
|
void task_init();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -4,16 +4,17 @@
|
|||||||
#include "i386/tasking.h"
|
#include "i386/tasking.h"
|
||||||
#include "i386/isr.h"
|
#include "i386/isr.h"
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
#include "../rpc.h"
|
||||||
|
|
||||||
|
void tasking_createTask(void* eip,void* cr3,char kmode,char param1_exists,uint32_t param1_arg,char param2_exists,uint32_t param2_arg,char isThread);
|
||||||
void tasking_init();
|
void tasking_init();
|
||||||
void tasking_yield(pid_t pid); //set pid to 0 for normal scheduling
|
char tasking_isPrivleged();
|
||||||
Task* tasking_createTask(void* eip);
|
pid_t getPID();
|
||||||
Task* tasking_createTaskCr3KmodeParam(void* eip,void* cr3,char kmode,char param1_exists,uint32_t param1_arg,char param2_exists,uint32_t param2_arg);
|
|
||||||
char isPrivleged(uint32_t pid);
|
|
||||||
uint32_t getPID();
|
|
||||||
void tasking_exit(uint8_t code);
|
|
||||||
void tasking_block(TaskState newstate);
|
|
||||||
void tasking_unblock(pid_t pid);
|
|
||||||
int* tasking_get_errno_address();
|
int* tasking_get_errno_address();
|
||||||
|
void tasking_new_thread(void* start);
|
||||||
|
|
||||||
|
void tasking_exit(uint8_t code);
|
||||||
|
void tasking_block(ThreadState newstate);
|
||||||
|
void tasking_unblock(pid_t pid,uint32_t tid);
|
||||||
|
void tasking_yield();
|
||||||
#endif
|
#endif
|
||||||
|
@ -106,7 +106,7 @@ void kmain(struct multiboot_boot_header_tag* hdr) {
|
|||||||
for (int i=0;i<4;i++) {
|
for (int i=0;i<4;i++) {
|
||||||
yield();
|
yield();
|
||||||
}
|
}
|
||||||
unblockTask(1);
|
unblockTask(1,0);
|
||||||
for (int i=0;i<4;i++) {
|
for (int i=0;i<4;i++) {
|
||||||
yield();
|
yield();
|
||||||
}
|
}
|
||||||
|
43
kernel/rpc.c
43
kernel/rpc.c
@ -1,8 +1,37 @@
|
|||||||
#include "cpu/tasking.h"
|
// #include "cpu/tasking.h"
|
||||||
#include <string.h>
|
// #include <string.h>
|
||||||
#include "rpc.h"
|
// #include "rpc.h"
|
||||||
void rpc_init_struct(TaskRPCStruct* info) {
|
// #include "cpu/i386/serial.h"
|
||||||
info->pendingrpc = 0;
|
// #include "cpu/halt.h"
|
||||||
info->callingpid = 0;
|
// void rpc_init_struct(TaskRPCStruct* info) {
|
||||||
}
|
// for (size_t i = 0; i < 32; i++) {
|
||||||
|
// info->funcs[i].code=NULL;
|
||||||
|
// memset(info->funcs[i].name,'\0',32);
|
||||||
|
// }
|
||||||
|
// info->rpc_response=NULL;
|
||||||
|
// info->next_func=0;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// void rpc_reg_func(void* (*code)(void*),char* name) {
|
||||||
|
// if (strlen(name)>31) {
|
||||||
|
// serial_printf("Max length for RPC function name is 31!\n");
|
||||||
|
// halt();
|
||||||
|
// }
|
||||||
|
// TaskRPCStruct* info=tasking_get_rpc_struct(0);
|
||||||
|
// if (info->next_func==32) {
|
||||||
|
// serial_printf("Maximum # of RPC functions registered\n");
|
||||||
|
// halt();
|
||||||
|
// }
|
||||||
|
// info->funcs[info->next_func].code=code;
|
||||||
|
// strcpy(info->funcs[info->next_func].name,name);
|
||||||
|
// info->next_func++;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// void rpc_call(char* name,pid_t pid,void* data) {
|
||||||
|
// if (strlen(name)>31) {
|
||||||
|
// serial_printf("Max length for RPC function name is 31!\n");
|
||||||
|
// halt();
|
||||||
|
// }
|
||||||
|
// TaskRPCStruct* info=tasking_get_rpc_struct(pid);
|
||||||
|
// int func_idx;
|
||||||
|
// }
|
||||||
|
11
kernel/rpc.h
11
kernel/rpc.h
@ -3,15 +3,16 @@
|
|||||||
|
|
||||||
typedef struct RPCFuncInfo {
|
typedef struct RPCFuncInfo {
|
||||||
char name[32];
|
char name[32];
|
||||||
char* (*code)(char*);
|
void* (*code)(void*);
|
||||||
} RPCFuncInfo;
|
} RPCFuncInfo;
|
||||||
|
|
||||||
typedef struct TaskRPCStruct {
|
typedef struct TaskRPCStruct {
|
||||||
int pendingrpc;
|
RPCFuncInfo funcs[32];
|
||||||
int callingpid;
|
int next_func;
|
||||||
} TaskRPCStruct;
|
void* rpc_response;
|
||||||
|
} ThreadRPCStruct;
|
||||||
|
|
||||||
|
|
||||||
void rpc_init_struct(TaskRPCStruct* info);
|
void rpc_init_struct(ThreadRPCStruct* info);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,6 +1,11 @@
|
|||||||
|
#include <sys/syscalls.h>
|
||||||
|
|
||||||
|
#define QUAUX(X) #X
|
||||||
|
#define QU(X) QUAUX(X)
|
||||||
|
|
||||||
void serial_print(char* str) {
|
void serial_print(char* str) {
|
||||||
asm volatile(" \
|
asm volatile(" \
|
||||||
mov $16, %%eax; \
|
mov $" QU(SYSCALL_SERIAL_PRINT) ", %%eax; \
|
||||||
int $80; \
|
int $80; \
|
||||||
"::"b"(str));
|
"::"b"(str));
|
||||||
}
|
}
|
||||||
|
@ -51,9 +51,16 @@ void blockTask(TaskState state) {
|
|||||||
"::"b"(state));
|
"::"b"(state));
|
||||||
}
|
}
|
||||||
|
|
||||||
void unblockTask(pid_t pid) {
|
void unblockTask(pid_t pid,uint32_t tid) {
|
||||||
asm volatile(" \
|
asm volatile(" \
|
||||||
mov $" QU(SYSCALL_UNBLOCK) ", %%eax; \
|
mov $" QU(SYSCALL_UNBLOCK) ", %%eax; \
|
||||||
int $80; \
|
int $80; \
|
||||||
"::"b"(pid));
|
"::"b"(pid),"c"(tid));
|
||||||
|
}
|
||||||
|
|
||||||
|
void new_thread(void* start) {
|
||||||
|
asm volatile(" \
|
||||||
|
mov $" QU(SYSCALL_NEW_THREAD) ", %%eax; \
|
||||||
|
int $80; \
|
||||||
|
"::"b"(start));
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#define SYSCALL_EXIT 4
|
#define SYSCALL_EXIT 4
|
||||||
#define SYSCALL_GET_ERRNO_ADDR 5
|
#define SYSCALL_GET_ERRNO_ADDR 5
|
||||||
#define SYSCALL_GET_PID 6
|
#define SYSCALL_GET_PID 6
|
||||||
|
#define SYSCALL_NEW_THREAD 14
|
||||||
|
|
||||||
#define SYSCALL_ALLOC_MEM 7
|
#define SYSCALL_ALLOC_MEM 7
|
||||||
#define SYSCALL_PRIV_MAP_PAGES 8
|
#define SYSCALL_PRIV_MAP_PAGES 8
|
||||||
|
@ -20,7 +20,7 @@ void createTaskCr3(void* task,void* cr3);
|
|||||||
void createTaskCr3Param(void* task,void* cr3,uint32_t param1,uint32_t param2);
|
void createTaskCr3Param(void* task,void* cr3,uint32_t param1,uint32_t param2);
|
||||||
char isPrivleged(uint32_t pid);
|
char isPrivleged(uint32_t pid);
|
||||||
void blockTask(TaskState state);
|
void blockTask(TaskState state);
|
||||||
void unblockTask(pid_t pid);
|
void unblockTask(pid_t pid,uint32_t tid);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user