// proc.c // Author: Josh Holtrop // Date; 08/18/05 // Modified: 08/18/05 #define __HOS_CPP__ extern "C" { #include "hos_defines.h" #include "mm/mm.h" #include "mm/vmm.h" #include "lang/lang.h" #include "kernel.h" #include "functions.h" //halt() #include "display/kout.h" extern u32_t mm_freepages; } #include "proc.h" #include "proc/hash.h" extern "C" { u32_t cur_task = 0; u32_t n_processes = 0; tss_t tss0; u32_t pid_base = 1024; u32_t pid_index = 0; } hash *processes; vector *pids; int proc_init() { /* initialize tss0 */ memset(&tss0, 0, sizeof(tss_t)); tss0.ss0 = SEG_KERNEL_DATA; tss0.esp0 = VIRT_STACK_TOP; processes = new hash(); process_t *proc = (process_t *)New(process_t); proc->p_page_dir = read_cr3(); proc->page_dir = (u32_t *)0xFFFFF000; processes->add(0, proc); pids = new vector(); pids->add(0); return 0; } void proc_sched(int_stack_t *int_stack) { u32_t new_pid_index = (pid_index + 1) % pids->size(); switch_task(int_stack, (*pids)[new_pid_index]); pid_index = new_pid_index; } u32_t get_pid() { u32_t potential = pid_base; while (processes->exists(potential)) { potential++; if (potential == 0) potential = PROC_MIN_USER_PID; } pid_base = potential + 1; if (pid_base == 0) pid_base = PROC_MIN_USER_PID; return potential; } void switch_task(int_stack_t *int_stack, u32_t new_task) { memcpy(&((process_t *)processes->get(cur_task))->int_stack, int_stack, sizeof(int_stack_t)); cur_task = new_task; memcpy(int_stack, &((process_t *)processes->get(cur_task))->int_stack, sizeof(int_stack_t)); write_cr3( ((process_t *)processes->get(cur_task))->p_page_dir ); } u32_t create_task(void *base, u32_t image_size, u32_t bss_size, void *entry) { u32_t pid = get_pid(); processes->add(pid, create_process(base, image_size, bss_size, entry)); pids->add(pid); return pid; } /* Create process_t struct for a new process * image_size should be a multiple of 4096 */ process_t *create_process(void *base, u32_t image_size, u32_t bss_size, void *entry) { if (mm_freepages < ((image_size + bss_size) >> 12) + 25) return 0; process_t *process = (process_t *) New(process_t); /* Allocate process_t struct */ create_address_space(process); create_process_stack(process, entry); int i; u32_t *ptr32 = process->v_page_dir = (u32_t *) vmm_palloc(); for (i = 0; i < 1024; i++) *ptr32++ = 0; u32_t code_data_pages = (image_size + 4095) >> 12; u32_t bss_pages = (bss_size + 4095) >> 12; /* Load program at address 0 */ copy_into_address_space(0, (char *) base, code_data_pages, process); zero_address_space(code_data_pages << 12, bss_pages, process); ptr32 = process->v_page_dir; for (i = 0; i < 1024; i++) if (*ptr32) vmm_unmapp((void *)*ptr32); vmm_unmapp(process->v_page_dir); process->v_page_dir = 0; process->size = image_size + bss_size; return process; } void create_address_space(process_t *p) { /* Allocate a new page directory */ p->page_dir = (u32_t *) vmm_palloc_addr(&p->p_page_dir); int i; u32_t *ptr32 = p->page_dir; for (i = 0; i < 768; i++) /* zero 3 gigs */ *ptr32++ = 0; memcpyd(ptr32, (void *)0xFFFFFC00, 256); /* 1 gig kernel mem */ } void create_process_stack(process_t *p, void *entry) { u32_t p_stack_table, p_stack; u32_t *v_stack_table = (u32_t *) vmm_palloc_addr(&p_stack_table); u32_t *v_stack = (u32_t *) vmm_palloc_addr(&p_stack); int i; u32_t *ptr32 = v_stack_table; for (i = 0; i < 1023; i++) *ptr32++ = 0; v_stack_table[1023] = p_stack | 0x7; /* user permissions */ p->page_dir[511] = p_stack_table | 0x7; /* stack at 2GB */ vmm_unmapp(v_stack_table); vmm_unmapp(v_stack); p->int_stack.ds = SEG_USER_DATA | 0x3; p->int_stack.es = SEG_USER_DATA | 0x3; p->int_stack.fs = SEG_USER_DATA | 0x3; p->int_stack.gs = SEG_USER_DATA | 0x3; p->int_stack.ss = SEG_USER_DATA | 0x3; p->int_stack.esp = 0x20000000; p->int_stack.eflags = 0x0202; p->int_stack.cs = SEG_USER_CODE | 0x3; p->int_stack.eip = (u32_t)entry; } /* Copy pages into new address space (v_page_dir must be set up) */ void copy_into_address_space(u32_t dest_addr, char *src_addr, u32_t pages, process_t *p) { u32_t pde, pte; void *page; while (pages) { pde = dest_addr >> 22; pte = (dest_addr >> 12) & 0x3FF; u32_t p_page_addr; if (!p->v_page_dir[pde]) { /* Time for a new page table & page directory entry! */ p->v_page_dir[pde] = (u32_t)vmm_palloc_addr(&p_page_addr); p->page_dir[pde] = p_page_addr | 0x7; } page = vmm_palloc_addr(&p_page_addr); ((u32_t *)(p->v_page_dir[pde]))[pte] = p_page_addr | 0x7; memcpyd(page, src_addr, 1024); vmm_unmapp(page); dest_addr += 4096; src_addr += 4096; pages--; } } /* Zeros pages into new address space (v_page_dir must be set up) */ void zero_address_space(u32_t dest_addr, u32_t pages, process_t *p) { u32_t pde, pte; void *page; while (pages) { pde = dest_addr >> 22; pte = (dest_addr >> 12) & 0x3FF; u32_t p_page_addr; if (!p->v_page_dir[pde]) { /* Time for a new page table & page directory entry! */ p->v_page_dir[pde] = (u32_t)vmm_palloc_addr(&p_page_addr); p->page_dir[pde] = p_page_addr | 0x7; vmm_unmapp((void *)p->v_page_dir[pde]); } page = vmm_palloc_addr(&p_page_addr); ((u32_t *)(p->v_page_dir[pde]))[pte] = p_page_addr | 0x7; memsetd(page, 0, 1024); vmm_unmapp(page); dest_addr += 4096; pages--; } }