419 lines
12 KiB
C
419 lines
12 KiB
C
#include "../include/task.h"
|
|
#include "../include/common.h"
|
|
#include "../include/graphics.h"
|
|
#include "../include/io.h"
|
|
#include "../include/description_table.h"
|
|
#include "../include/vfs.h"
|
|
#include "../include/timer.h"
|
|
#include "../include/shell.h"
|
|
#include "../include/heap.h"
|
|
#include "../include/elf.h"
|
|
|
|
#define SA_RPL_MASK 0xFFFC
|
|
#define SA_TI_MASK 0xFFFB
|
|
#define GET_SEL(cs, rpl) ((cs & SA_RPL_MASK & SA_TI_MASK) | (rpl))
|
|
|
|
struct task_struct *running_proc_head = NULL;
|
|
struct task_struct *wait_proc_head = NULL;
|
|
struct task_struct *current = NULL;
|
|
|
|
extern page_directory_t *kernel_directory;
|
|
|
|
extern void switch_to(struct context *prev, struct context *next);
|
|
|
|
extern void taskX_switch(struct context *prev, struct context *next);
|
|
|
|
int now_pid = 0;
|
|
int can_sche = 1;
|
|
|
|
struct task_struct *get_current() {
|
|
return current;
|
|
}
|
|
|
|
static uint32_t padding_up(uint32_t num, uint32_t size) {
|
|
return (num + size - 1) / size;
|
|
}
|
|
|
|
void print_proc_t(int *i, struct task_struct *base, struct task_struct *cur, int is_print) {
|
|
if (cur->pid == base->pid) {
|
|
if (is_print) {
|
|
switch (cur->state) {
|
|
case TASK_RUNNABLE:
|
|
printf("%-17s %-2d %s %d\n", cur->name, cur->pid, "Running");
|
|
break;
|
|
case TASK_SLEEPING:
|
|
printf("%-17s %-2d %s %d\n", cur->name, cur->pid, "Sleeping");
|
|
break;
|
|
case TASK_UNINIT:
|
|
printf("%-17s %-2d %s %d\n", cur->name, cur->pid, "Init");
|
|
break;
|
|
case TASK_ZOMBIE:
|
|
printf("%-17s %-2d %s %d\n", cur->name, cur->pid, "Zombie");
|
|
break;
|
|
case TASK_DEATH:
|
|
printf("%-17s %-2d %s %d\n", cur->name, cur->pid, "Death");
|
|
break;
|
|
}
|
|
}
|
|
(*i)++;
|
|
} else {
|
|
if (is_print) {
|
|
switch (cur->state) {
|
|
case TASK_RUNNABLE:
|
|
printf("%-17s %-2d %s %d\n", cur->name, cur->pid, "Running");
|
|
break;
|
|
case TASK_SLEEPING:
|
|
printf("%-17s %-2d %s %d\n", cur->name, cur->pid, "Sleeping");
|
|
break;
|
|
case TASK_UNINIT:
|
|
printf("%-17s %-2d %s %d\n", cur->name, cur->pid, "Init");
|
|
break;
|
|
case TASK_ZOMBIE:
|
|
printf("%-17s %-2d %s %d\n", cur->name, cur->pid, "Zombie");
|
|
break;
|
|
case TASK_DEATH:
|
|
printf("%-17s %-2d %s %d\n", cur->name, cur->pid, "Death");
|
|
break;
|
|
}
|
|
}
|
|
(*i)++;
|
|
print_proc_t(i, base, cur->next, is_print);
|
|
}
|
|
}
|
|
|
|
int get_procs() {
|
|
int index = 0;
|
|
print_proc_t(&index, current, current->next, 0);
|
|
return index;
|
|
}
|
|
|
|
void print_proc() {
|
|
int index = 0;
|
|
print_proc_t(&index, current, current->next, 1);
|
|
printf("====---------------[Processes]----------------====\n");
|
|
printf("Name Pid Status MemUsage [All Proc: %d]\n\n", index);
|
|
}
|
|
|
|
static void
|
|
found_task(int pid, struct task_struct *head, struct task_struct *base, struct task_struct **argv, int first) {
|
|
struct task_struct *t = base;
|
|
if (t == NULL) {
|
|
argv = NULL;
|
|
return;
|
|
}
|
|
if (t->pid == pid) {
|
|
*argv = t;
|
|
return;
|
|
} else {
|
|
if (!first)
|
|
if (head->pid == t->pid) {
|
|
argv = NULL;
|
|
return;
|
|
}
|
|
found_task(pid, head, t->next, argv, 0);
|
|
}
|
|
}
|
|
|
|
struct task_struct *found_task_pid(int pid) {
|
|
struct task_struct *argv = NULL;
|
|
found_task(pid, running_proc_head, running_proc_head, &argv, 1);
|
|
if (argv == NULL) {
|
|
printf("Cannot found task Pid:[%d].\n", pid);
|
|
return NULL;
|
|
}
|
|
return argv;
|
|
}
|
|
|
|
void wait_task(struct task_struct *task) {
|
|
task->state = TASK_SLEEPING;
|
|
}
|
|
|
|
void start_task(struct task_struct *task) {
|
|
task->state = TASK_RUNNABLE;
|
|
}
|
|
|
|
void task_kill(int pid) {
|
|
io_cli();
|
|
struct task_struct *argv = found_task_pid(pid);
|
|
if (argv == NULL) {
|
|
printf("Cannot found task Pid:[%d].\n", pid);
|
|
return;
|
|
}
|
|
if (argv->pid == 0) {
|
|
printf("\033ff3030;[kernel]: Taskkill cannot terminate kernel processes.\033c6c6c6;\n");
|
|
return;
|
|
}
|
|
argv->state = TASK_DEATH;
|
|
printf("Taskkill process PID:%d Name:%s\n", argv->pid, argv->name);
|
|
free_tty(argv);
|
|
struct task_struct *head = running_proc_head;
|
|
struct task_struct *last = NULL;
|
|
while (1) {
|
|
if (head->pid == argv->pid) {
|
|
last->next = argv->next;
|
|
kfree(argv);
|
|
io_sti();
|
|
return;
|
|
}
|
|
last = head;
|
|
head = head->next;
|
|
}
|
|
}
|
|
|
|
void schedule(registers_t *reg) {
|
|
io_cli();
|
|
if (current && can_sche) {
|
|
change_task_to(reg,current->next);
|
|
}
|
|
}
|
|
|
|
void change_task_to(registers_t *reg,struct task_struct *next) {
|
|
if (current != next) {
|
|
struct task_struct *prev = current;
|
|
current = next;
|
|
page_switch(current->pgd_dir);
|
|
set_kernel_stack(current->stack + STACK_SIZE);
|
|
|
|
prev->context.eip = reg->eip;
|
|
prev->context.ds = reg->ds;
|
|
prev->context.cs = reg->cs;
|
|
prev->context.eax = reg->eax;
|
|
prev->context.ss = reg->ss;
|
|
switch_to(&(prev->context), &(current->context));
|
|
reg->ds = current->context.ds;
|
|
reg->cs = current->context.cs;
|
|
reg->eip = current->context.eip;
|
|
reg->eax = current->context.eax;
|
|
reg->ss = current->context.ss;
|
|
}
|
|
}
|
|
|
|
int32_t user_process(char *path, char *name){ // 用户进程创建
|
|
can_sche = 0;
|
|
if(path == NULL){
|
|
return -1;
|
|
}
|
|
uint32_t size = vfs_filesize(path);
|
|
if(size == -1){
|
|
return -1;
|
|
}
|
|
io_cli();
|
|
|
|
struct task_struct *new_task = (struct task_struct *) kmalloc(STACK_SIZE);
|
|
assert(new_task != NULL, "user_pcb: kmalloc error");
|
|
|
|
// 将栈低端结构信息初始化为 0
|
|
memset(new_task, 0, sizeof(struct task_struct));
|
|
|
|
new_task->state = TASK_RUNNABLE;
|
|
new_task->stack = current;
|
|
new_task->pid = now_pid++;
|
|
|
|
page_directory_t *page = clone_directory(kernel_directory);
|
|
new_task->pgd_dir = page;
|
|
new_task->mem_size = 0;
|
|
new_task->program_break = USER_START + 0xf0000;
|
|
new_task->program_break_end = USER_HEAP_END;
|
|
new_task->name = name;
|
|
new_task->isUser = 1;
|
|
new_task->tty = kmalloc(sizeof(tty_t));
|
|
init_default_tty(new_task);
|
|
|
|
extern char root_disk;
|
|
vfs_change_disk(new_task,root_disk);
|
|
|
|
io_sti();
|
|
|
|
page_switch(page);
|
|
|
|
for (int i = USER_START; i < USER_END + 0x1000;i++) { //用户堆以及用户栈映射
|
|
page_t *pg = get_page(i,1,page, false);
|
|
alloc_frame(pg,0,1);
|
|
}
|
|
|
|
for (int i = USER_EXEC_FILE_START; i < USER_EXEC_FILE_START + size; i++) {
|
|
page_t *pg = get_page(i,1,page, false);
|
|
alloc_frame(pg,0,1);
|
|
}
|
|
|
|
char* buffer = USER_EXEC_FILE_START;
|
|
|
|
memset(buffer,0,size);
|
|
vfs_readfile(path,buffer);
|
|
|
|
|
|
Elf32_Ehdr *ehdr = buffer;
|
|
if(!elf32Validate(ehdr)){
|
|
printf("Unknown exec file format.\n");
|
|
return -1;
|
|
}
|
|
uint32_t main = ehdr->e_entry;
|
|
load_elf(ehdr,page);
|
|
|
|
|
|
uint32_t *stack_top = (uint32_t * )((uint32_t) new_task + STACK_SIZE);
|
|
|
|
*(--stack_top) = (uint32_t) main;
|
|
//*(--stack_top) = (uint32_t) buffer;
|
|
*(--stack_top) = (uint32_t) kthread_exit;
|
|
*(--stack_top) = (uint32_t) switch_to_user_mode;
|
|
|
|
new_task->context.esp = (uint32_t) new_task + STACK_SIZE - sizeof(uint32_t) * 3;
|
|
|
|
// 设置新任务的标志寄存器未屏蔽中断,很重要
|
|
new_task->context.eflags = (0 << 12 | 0b10 | 1 << 9);
|
|
new_task->next = running_proc_head;
|
|
|
|
page_switch(kernel_directory);
|
|
|
|
// 找到当前进任务队列,插入到末尾
|
|
struct task_struct *tailt = running_proc_head;
|
|
assert(tailt != NULL, "Must init sched!");
|
|
|
|
while (tailt->next != running_proc_head) {
|
|
tailt = tailt->next;
|
|
}
|
|
tailt->next = new_task;
|
|
can_sche = 1;
|
|
io_sti();
|
|
return new_task->pid;
|
|
}
|
|
|
|
|
|
int32_t kernel_thread(int (*fn)(void *), void *arg, char *name) { // 内核进程(线程) 创建
|
|
io_cli();
|
|
struct task_struct *new_task = (struct task_struct *) kmalloc(STACK_SIZE);
|
|
assert(new_task != NULL, "kern_thread: kmalloc error");
|
|
|
|
// 将栈低端结构信息初始化为 0
|
|
memset(new_task, 0, sizeof(struct task_struct));
|
|
|
|
new_task->state = TASK_RUNNABLE;
|
|
new_task->stack = current;
|
|
new_task->pid = now_pid++;
|
|
new_task->pgd_dir = kernel_directory;
|
|
new_task->mem_size = 0;
|
|
new_task->isUser = 0;
|
|
|
|
extern header_t *head;
|
|
extern header_t *tail;
|
|
extern void *program_break;
|
|
extern void *program_break_end;
|
|
current->head = head;
|
|
current->tail = tail;
|
|
current->program_break = program_break;
|
|
current->program_break_end = program_break_end;
|
|
new_task->name = name;
|
|
|
|
new_task->tty = kmalloc(sizeof(tty_t));
|
|
init_default_tty(new_task);
|
|
|
|
uint32_t *stack_top = (uint32_t * )((uint32_t) new_task + STACK_SIZE);
|
|
|
|
*(--stack_top) = (uint32_t) arg;
|
|
*(--stack_top) = (uint32_t) kthread_exit;
|
|
*(--stack_top) = (uint32_t) fn;
|
|
|
|
new_task->context.esp = (uint32_t) new_task + STACK_SIZE - sizeof(uint32_t) * 3;
|
|
|
|
// 设置新任务的标志寄存器未屏蔽中断,很重要
|
|
new_task->context.eflags = 0x200;
|
|
new_task->next = running_proc_head;
|
|
|
|
// 找到当前进任务队列,插入到末尾
|
|
struct task_struct *tailt = running_proc_head;
|
|
assert(tailt != NULL, "Must init sched!");
|
|
|
|
while (tailt->next != running_proc_head) {
|
|
tailt = tailt->next;
|
|
}
|
|
tailt->next = new_task;
|
|
io_sti();
|
|
return new_task->pid;
|
|
}
|
|
|
|
void kthread_exit() {
|
|
register uint32_t val asm ("eax");
|
|
printf("Task [PID: %d] exited with value %d\n", current->pid,val);
|
|
task_kill(current->pid);
|
|
while (1);
|
|
}
|
|
|
|
void kill_all_task() {
|
|
struct task_struct *head = running_proc_head;
|
|
while (1) {
|
|
head = head->next;
|
|
if (head == NULL || head->pid == running_proc_head->pid) {
|
|
return;
|
|
}
|
|
if (head->pid == current->pid) continue;
|
|
task_kill(head->pid);
|
|
}
|
|
}
|
|
|
|
#define SA_RPL3 3
|
|
|
|
void switch_to_user_mode(uint32_t func) {
|
|
io_cli();
|
|
set_kernel_stack(current->stack + STACK_SIZE);
|
|
unsigned esp = USER_END;
|
|
current->context.eflags = (0 << 12 | 0b10 | 1 << 9);
|
|
intr_frame_t iframe;
|
|
iframe.edi = 1;
|
|
iframe.esi = 2;
|
|
iframe.ebp = 3;
|
|
iframe.esp_dummy = 4;
|
|
iframe.ebx = 5;
|
|
iframe.edx = 6;
|
|
iframe.ecx = 7;
|
|
iframe.eax = 8;
|
|
|
|
iframe.gs = GET_SEL(4 * 8, SA_RPL3);
|
|
iframe.ds = GET_SEL(4 * 8, SA_RPL3);
|
|
iframe.es = GET_SEL(4 * 8, SA_RPL3);
|
|
iframe.fs = GET_SEL(4 * 8, SA_RPL3);
|
|
|
|
iframe.ss = GET_SEL(4 * 8, SA_RPL3);
|
|
iframe.cs = GET_SEL(3 * 8, SA_RPL3);
|
|
//set_tss_ss0(iframe.ss);
|
|
|
|
iframe.eip = func; //用户可执行程序入口
|
|
iframe.eflags = (0 << 12 | 0b10 | 1 << 9);
|
|
iframe.esp = esp; // 设置用户态堆栈
|
|
|
|
intr_frame_t *a = &iframe;
|
|
asm volatile("movl %0, %%esp\n"
|
|
"popa\n"
|
|
"pop %%gs\n"
|
|
"pop %%fs\n"
|
|
"pop %%es\n"
|
|
"pop %%ds\n"
|
|
"iret" ::"m"(a));
|
|
}
|
|
|
|
void init_sched() {
|
|
// 为当前执行流创建信息结构体 该结构位于当前执行流的栈最低端
|
|
current = (struct task_struct *) kmalloc(sizeof(struct task_struct));
|
|
|
|
current->state = TASK_RUNNABLE;
|
|
current->pid = now_pid++;
|
|
current->stack = current; // 该成员指向栈低地址
|
|
current->pgd_dir = kernel_directory;
|
|
current->name = "CPOS-System";
|
|
current->mem_size = 0;
|
|
current->next = current;
|
|
current->isUser = 0;
|
|
init_default_tty(current);
|
|
|
|
extern header_t *head;
|
|
extern header_t *tail;
|
|
extern void *program_break;
|
|
extern void *program_break_end;
|
|
current->head = head;
|
|
current->tail = tail;
|
|
current->program_break = program_break;
|
|
current->program_break_end = program_break_end;
|
|
|
|
running_proc_head = current;
|
|
klogf(true,"Load task schedule. | KernelTaskName: %s PID: %d\n",current->name,current->pid);
|
|
} |