/** @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 asmregparm __noreturn void kernel_thread_fate_entry(unsigned long (*thread_entry)(unsigned long),unsigned long para) { if (thread_entry) ka_call_dynamic_module_entry(thread_entry, para); printk("Kernel level thread die ,entry %x.\n", thread_entry); kt_delete_current(); }
/** @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(); }