/** @brief New process send a startup signal We copy the startup cmdline to the process */ static void process_startup(struct sysreq_process_startup * req) { xstring __user cmdline = req->cmdline_buffer; if (req->func == SYSREQ_PROCESS_STARTUP_FUNC_START) { /* The user buffer can be written ? */ if (ke_validate_user_buffer(cmdline, SYSREQ_PROCESS_STARTUP_MAX_SIZE, true) == false) return; memcpy(cmdline, (void*)(kt_arch_get_sp0(kt_current()) - KT_ARCH_THREAD_CP0_STACK_SIZE), SYSREQ_PROCESS_STARTUP_MAX_SIZE); //printk("cmdline is %s.\n", cmdline); } else if (req->func == SYSREQ_PROCESS_STARTUP_FUNC_SET_PATH) { /* The user buffer can be written ? */ if (ke_validate_user_buffer(cmdline, SYSREQ_PROCESS_STARTUP_MAX_SIZE, false) == false) return; //printk("current dir = %s.\n", cmdline); kt_current()->current_dir = fss_open(NULL, cmdline); } else if (req->func == SYSREQ_PROCESS_STARTUP_FUNC_END) { /* Killing main thread will trigger the process destroying */ kt_delete_current(); } }
/** @brief Page fault handler */ asmregparm void do_page_fault(struct pt_regs * regs, long error_code) { unsigned long error_address = read_cr2(); bool in_user = address_in_user(error_address); struct ko_thread *current; //printk("PAGE fault: eip %x addr %x code %x\n", regs->ip, error_address, error_code); /* Access violation. 读、写和u/s异常 如果是用户模式,那么访问核心层空间时崩溃,其他地方尝试修复 如果是特权模式,都尝试修复 */ if (error_code & PAGE_FAULT_U) { if (in_user == false) goto die_cur; } current = kt_current(); if (unlikely(false == ks_exception(current, error_address, error_code))) goto die_cur; return; die_cur: printk("TODO: Thread deing :eip %x addr %x code %x\n", regs->ip, error_address, error_code); //TODO kill thread //fak_arch_x86_dump_register(regs); kt_delete_current(); }
static bool recover(unsigned long address, int write, int present) { unsigned long core_error_code = 0; if (write) core_error_code |= PAGE_FAULT_W; if (present) core_error_code |= PAGE_FAULT_P; /* Call the exception handler of section */ return ks_exception(kt_current(), address, core_error_code); }
static struct ko_section *map_file(struct ko_process *to, xstring name, page_prot_t prot, size_t __out *size) { void *fp; size_t map_size; struct ko_section *map; //TODO: 此处应该使用to 的原始启动路径来做当前路径 if (NULL == (fp = fss_open(kt_current()->current_dir, name))) goto err0; map_size = fss_get_size(fp); if (NULL == (map = create_file_map(to, fp, map_size, prot))) goto err1; if (size) *size = map_size; return map; err1: fss_close(fp); err0: return NULL; }
static struct ko_section *map_file(struct ko_process *to, xstring name, page_prot_t prot, unsigned long *map_size) { struct ko_section *ks_file; unsigned long size; void *fp; fp = fss_open(kt_current()->current_dir, name); if (!fp) goto end; *map_size = size = fss_get_size(fp); ks_file = ks_create(to, KS_TYPE_FILE, NULL, size, prot); if (!ks_file) goto err1; ks_file->priv.file.file = fp; return ks_file; err1: fss_close(fp); end: return NULL; }
/** @brief Get the TEB in current thread */ static void *thread_teb(struct sysreq_thread_msg *req) { struct ko_thread *kt = kt_current(); return kt->teb; }
/** @brief Thread synchronizing operation @return kt_sync_wait_result */ static int thread_sync_ops(struct sysreq_thread_sync *req) { int i; int ops = req->ops; switch(ops) { /* 等待同步对象 */ case SYSREQ_THREAD_SYNC_WAIT_OBJS: { int count = req->detail.wait_objs.count; struct kt_sync_base *sync_objs[Y_SYNC_MAX_OBJS_COUNT]; y_handle sync_handles[Y_SYNC_MAX_OBJS_COUNT]; kt_sync_wait_result ret = KE_WAIT_ERROR; if (count > Y_SYNC_MAX_OBJS_COUNT) goto wait_end; for (i = 0; i < count; i++) { sync_handles[i] =(ke_handle)req->detail.wait_objs.sync_objects[i]; sync_objs[i] = ke_handle_translate(sync_handles[i]); if (!sync_objs[i]) goto unwind_translate; } ret = kt_wait_objects(kt_current(), count, sync_objs, req->detail.wait_objs.wait_all, req->detail.wait_objs.timeout, NULL); unwind_translate: for (i = 0; i < count; i++) { if (sync_objs[i]) ke_handle_put(sync_handles[i], sync_objs[i]); } wait_end: return ret; } case SYSREQ_THREAD_SYNC_WAIT_MS: { TODO(""); break; } case SYSREQ_THREAD_SYNC_EVENT: { ke_handle hevent; struct ke_event *event; switch (req->detail.event.ops) { case 's': { /* 唤醒线程,返回唤醒数量 */ int count; hevent = req->detail.event.event; if (!(event = ke_handle_translate(hevent))) goto invalid_handle; count = ke_event_set(event); ke_handle_put(hevent, event); return count; } case 'c': { /* Create event, return handle */ if (!(event = ke_event_object_create(req->detail.event.is_manual, req->detail.event.is_set))) goto invalid_handle; if (KE_INVALID_HANDLE == (hevent = ke_handle_create(event))) { km_vfree(event); goto invalid_handle; } return hevent; } case 'd': { /* delete the event, cause everybody wakeup */ #if 0 hevent = req->detail.event.event; if (!(event = ke_handle_translate(hevent))) goto invalid_handle; ke_handle_and_object_destory(hevent, event); #else TODO("事件对象用户模型还缺少cl_object的封装,无法销毁对象"); #endif return 0; } } break; } } invalid_handle: return KE_INVALID_HANDLE; }
/** @brief the page fault happened @param[in] regs thread ctx @param[in] write 0 is read , 1 is write, 2 is the tlb refill @param[in] address the error address where the fault happened @note Interrupt must be disabled! */ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long write, unsigned long address) { struct km * mem; unsigned long pte; struct km_walk_ctx ctx; struct ko_process *real; bool in_user = kmm_arch_address_in_user(address); //trace_page_fault(regs, write, address); /* The fault is triggered when accessing kernel addressing space when the thread is in user mode? */ if (!(regs->cp0_status & ST0_CU0)) { if (in_user == false) goto kill; } //TODO: check interrupt status /* We are using the kernel space? The mem ctx should come from kernel process */ if (in_user == false) real = kp_get_system(); else real = KT_GET_KP(kt_current()); mem = kp_get_mem(real); KM_WALK_INIT(mem, &ctx); if (unlikely(km_walk_to(&ctx, address) == false)) { printk("MIPS 页表异常时无法定位项目.\n"); goto kill2; } /* Read out the PTE */ pte = km_pte_read(&ctx); /* Just refill ? */ if (write == 2) { /* If is valid entry */ if (pte & PAGE_FLAG_VALID) { /* TODO: use the random version,have to close interrupt and scheduler, but the asm opened interrupt. 否则认为是REFILL,但是可能被其他线程给填充了,导致TLB中有相同的转换信息。 */ refill_tbl_to(&ctx, mem->asid/*If in user space, the asid is what we want, if the process in kernel space, refill will add G, asid not used */ , write, 0); mem->hw_refill++; goto end; } } else { /* Sanity check */ /* The exception handler may create a new page and write it just in the handler before it's updated to TLB. This is forbidden, because the TLB will be refill again after the recover */ if (write == 1) { if (pte & PAGE_FLAG_WRITE && pte & PAGE_FLAG_VALID) { hal_panic("TLB错误: PTE 项是正确的并应该触发REFILL, 而不是WRITE.\n"); } } else { if (pte & (PAGE_FLAG_VALID)) { trace_page_fault(regs, write, address); printk("ASID %d.\n", mem->asid); hal_panic("TLB错误: PTE 项是正确的并应该触发REFILL, 而不是READ.\n"); } } } kp_put_mem(mem); /* The PTE is not Refill nor is valid, we need to recover the page to memory */ if (unlikely(recover(address, write, pte & PAGE_FLAG_VALID) == false)) goto kill; /* REFILL exception Check the translation hierarchy and write to TLB. The refill may be triggered by read or write, but we don't care, just fill the TLB. Access violation will be checked if happened in second turn, but in normal case this is the end of the exception except COW. */ mem = kp_get_mem(real); refill_tbl_to(&ctx, mem->asid, write, 2); end: kp_put_mem(mem); return; kill2: kp_put_mem(mem); kill: trace_page_fault(regs, write, address); kt_delete_current(); }