📄 helper.c.svn-base
字号:
SegmentCache *dt; target_ulong ptr; int type, dpl, selector, cpl, ist; int has_error_code, new_stack; uint32_t e1, e2, e3, ss; target_ulong old_eip, esp, offset; int svm_should_check = 1; if ((env->intercept & INTERCEPT_SVM_MASK) && !is_int && next_eip==-1) { next_eip = EIP; svm_should_check = 0; } if (svm_should_check && INTERCEPTEDl(_exceptions, 1 << intno) && !is_int) { raise_interrupt(intno, is_int, error_code, 0); } has_error_code = 0; if (!is_int && !is_hw) { switch(intno) { case 8: case 10: case 11: case 12: case 13: case 14: case 17: has_error_code = 1; break; } } if (is_int) old_eip = next_eip; else old_eip = env->eip; dt = &env->idt; if (intno * 16 + 15 > dt->limit) raise_exception_err(EXCP0D_GPF, intno * 16 + 2); ptr = dt->base + intno * 16; e1 = ldl_kernel(ptr); e2 = ldl_kernel(ptr + 4); e3 = ldl_kernel(ptr + 8); /* check gate type */ type = (e2 >> DESC_TYPE_SHIFT) & 0x1f; switch(type) { case 14: /* 386 interrupt gate */ case 15: /* 386 trap gate */ break; default: raise_exception_err(EXCP0D_GPF, intno * 16 + 2); break; } dpl = (e2 >> DESC_DPL_SHIFT) & 3; cpl = env->hflags & HF_CPL_MASK; /* check privledge if software int */ if (is_int && dpl < cpl) raise_exception_err(EXCP0D_GPF, intno * 16 + 2); /* check valid bit */ if (!(e2 & DESC_P_MASK)) raise_exception_err(EXCP0B_NOSEG, intno * 16 + 2); selector = e1 >> 16; offset = ((target_ulong)e3 << 32) | (e2 & 0xffff0000) | (e1 & 0x0000ffff); ist = e2 & 7; if ((selector & 0xfffc) == 0) raise_exception_err(EXCP0D_GPF, 0); if (load_segment(&e1, &e2, selector) != 0) raise_exception_err(EXCP0D_GPF, selector & 0xfffc); if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK))) raise_exception_err(EXCP0D_GPF, selector & 0xfffc); dpl = (e2 >> DESC_DPL_SHIFT) & 3; if (dpl > cpl) raise_exception_err(EXCP0D_GPF, selector & 0xfffc); if (!(e2 & DESC_P_MASK)) raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); if (!(e2 & DESC_L_MASK) || (e2 & DESC_B_MASK)) raise_exception_err(EXCP0D_GPF, selector & 0xfffc); if ((!(e2 & DESC_C_MASK) && dpl < cpl) || ist != 0) { /* to inner privilege */ if (ist != 0) esp = get_rsp_from_tss(ist + 3); else esp = get_rsp_from_tss(dpl); esp &= ~0xfLL; /* align stack */ ss = 0; new_stack = 1; } else if ((e2 & DESC_C_MASK) || dpl == cpl) { /* to same privilege */ if (env->eflags & VM_MASK) raise_exception_err(EXCP0D_GPF, selector & 0xfffc); new_stack = 0; if (ist != 0) esp = get_rsp_from_tss(ist + 3); else esp = ESP; esp &= ~0xfLL; /* align stack */ dpl = cpl; } else { raise_exception_err(EXCP0D_GPF, selector & 0xfffc); new_stack = 0; /* avoid warning */ esp = 0; /* avoid warning */ } PUSHQ(esp, env->segs[R_SS].selector); PUSHQ(esp, ESP); PUSHQ(esp, compute_eflags()); PUSHQ(esp, env->segs[R_CS].selector); PUSHQ(esp, old_eip); if (has_error_code) { PUSHQ(esp, error_code); } if (new_stack) { ss = 0 | dpl; cpu_x86_load_seg_cache(env, R_SS, ss, 0, 0, 0); } ESP = esp; selector = (selector & ~3) | dpl; cpu_x86_load_seg_cache(env, R_CS, selector, get_seg_base(e1, e2), get_seg_limit(e1, e2), e2); cpu_x86_set_cpl(env, dpl); env->eip = offset; /* interrupt gate clear IF mask */ if ((type & 1) == 0) { env->eflags &= ~IF_MASK; } env->eflags &= ~(TF_MASK | VM_MASK | RF_MASK | NT_MASK);}#endif#if defined(CONFIG_USER_ONLY)void helper_syscall(int next_eip_addend){ env->exception_index = EXCP_SYSCALL; env->exception_next_eip = env->eip + next_eip_addend; cpu_loop_exit();}#elsevoid helper_syscall(int next_eip_addend){ int selector; if (!(env->efer & MSR_EFER_SCE)) { raise_exception_err(EXCP06_ILLOP, 0); } selector = (env->star >> 32) & 0xffff;#ifdef TARGET_X86_64 if (env->hflags & HF_LMA_MASK) { int code64; ECX = env->eip + next_eip_addend; env->regs[11] = compute_eflags(); code64 = env->hflags & HF_CS64_MASK; cpu_x86_set_cpl(env, 0); cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc, 0, 0xffffffff, DESC_G_MASK | DESC_P_MASK | DESC_S_MASK | DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | DESC_L_MASK); cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc, 0, 0xffffffff, DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | DESC_W_MASK | DESC_A_MASK); env->eflags &= ~env->fmask; if (code64) env->eip = env->lstar; else env->eip = env->cstar; } else#endif { ECX = (uint32_t)(env->eip + next_eip_addend); cpu_x86_set_cpl(env, 0); cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc, 0, 0xffffffff, DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK); cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc, 0, 0xffffffff, DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | DESC_W_MASK | DESC_A_MASK); env->eflags &= ~(IF_MASK | RF_MASK | VM_MASK); env->eip = (uint32_t)env->star; }}#endifvoid helper_sysret(int dflag){ int cpl, selector; if (!(env->efer & MSR_EFER_SCE)) { raise_exception_err(EXCP06_ILLOP, 0); } cpl = env->hflags & HF_CPL_MASK; if (!(env->cr[0] & CR0_PE_MASK) || cpl != 0) { raise_exception_err(EXCP0D_GPF, 0); } selector = (env->star >> 48) & 0xffff;#ifdef TARGET_X86_64 if (env->hflags & HF_LMA_MASK) { if (dflag == 2) { cpu_x86_load_seg_cache(env, R_CS, (selector + 16) | 3, 0, 0xffffffff, DESC_G_MASK | DESC_P_MASK | DESC_S_MASK | (3 << DESC_DPL_SHIFT) | DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | DESC_L_MASK); env->eip = ECX; } else { cpu_x86_load_seg_cache(env, R_CS, selector | 3, 0, 0xffffffff, DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | (3 << DESC_DPL_SHIFT) | DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK); env->eip = (uint32_t)ECX; } cpu_x86_load_seg_cache(env, R_SS, selector + 8, 0, 0xffffffff, DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | (3 << DESC_DPL_SHIFT) | DESC_W_MASK | DESC_A_MASK); load_eflags((uint32_t)(env->regs[11]), TF_MASK | AC_MASK | ID_MASK | IF_MASK | IOPL_MASK | VM_MASK | RF_MASK | NT_MASK); cpu_x86_set_cpl(env, 3); } else#endif { cpu_x86_load_seg_cache(env, R_CS, selector | 3, 0, 0xffffffff, DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | (3 << DESC_DPL_SHIFT) | DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK); env->eip = (uint32_t)ECX; cpu_x86_load_seg_cache(env, R_SS, selector + 8, 0, 0xffffffff, DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | (3 << DESC_DPL_SHIFT) | DESC_W_MASK | DESC_A_MASK); env->eflags |= IF_MASK; cpu_x86_set_cpl(env, 3); }#ifdef USE_KQEMU if (kqemu_is_ok(env)) { if (env->hflags & HF_LMA_MASK) CC_OP = CC_OP_EFLAGS; env->exception_index = -1; cpu_loop_exit(); }#endif}/* real mode interrupt */static void do_interrupt_real(int intno, int is_int, int error_code, unsigned int next_eip){ SegmentCache *dt; target_ulong ptr, ssp; int selector; uint32_t offset, esp; uint32_t old_cs, old_eip; int svm_should_check = 1; if ((env->intercept & INTERCEPT_SVM_MASK) && !is_int && next_eip==-1) { next_eip = EIP; svm_should_check = 0; } if (svm_should_check && INTERCEPTEDl(_exceptions, 1 << intno) && !is_int) { raise_interrupt(intno, is_int, error_code, 0); } /* real mode (simpler !) */ dt = &env->idt; if (intno * 4 + 3 > dt->limit) raise_exception_err(EXCP0D_GPF, intno * 8 + 2); ptr = dt->base + intno * 4; offset = lduw_kernel(ptr); selector = lduw_kernel(ptr + 2); esp = ESP; ssp = env->segs[R_SS].base; if (is_int) old_eip = next_eip; else old_eip = env->eip; old_cs = env->segs[R_CS].selector; /* XXX: use SS segment size ? */ PUSHW(ssp, esp, 0xffff, compute_eflags()); PUSHW(ssp, esp, 0xffff, old_cs); PUSHW(ssp, esp, 0xffff, old_eip); /* update processor state */ ESP = (ESP & ~0xffff) | (esp & 0xffff); env->eip = offset; env->segs[R_CS].selector = selector; env->segs[R_CS].base = (selector << 4); env->eflags &= ~(IF_MASK | TF_MASK | AC_MASK | RF_MASK);}/* fake user mode interrupt */void do_interrupt_user(int intno, int is_int, int error_code, target_ulong next_eip){ SegmentCache *dt; target_ulong ptr; int dpl, cpl, shift; uint32_t e2; dt = &env->idt; if (env->hflags & HF_LMA_MASK) { shift = 4; } else { shift = 3; } ptr = dt->base + (intno << shift); e2 = ldl_kernel(ptr + 4); dpl = (e2 >> DESC_DPL_SHIFT) & 3; cpl = env->hflags & HF_CPL_MASK; /* check privledge if software int */ if (is_int && dpl < cpl) raise_exception_err(EXCP0D_GPF, (intno << shift) + 2); /* Since we emulate only user space, we cannot do more than exiting the emulation with the suitable exception and error code */ if (is_int) EIP = next_eip;}/* * Begin execution of an interruption. is_int is TRUE if coming from * the int instruction. next_eip is the EIP value AFTER the interrupt * instruction. It is only relevant if is_int is TRUE. */void do_interrupt(int intno, int is_int, int error_code, target_ulong next_eip, int is_hw){ if (loglevel & CPU_LOG_INT) { if ((env->cr[0] & CR0_PE_MASK)) { static int count; fprintf(logfile, "%6d: v=%02x e=%04x i=%d cpl=%d IP=%04x:" TARGET_FMT_lx " pc=" TARGET_FMT_lx " SP=%04x:" TARGET_FMT_lx, count, intno, error_code, is_int, env->hflags & HF_CPL_MASK, env->segs[R_CS].selector, EIP, (int)env->segs[R_CS].base + EIP, env->segs[R_SS].selector, ESP); if (intno == 0x0e) { fprintf(logfile, " CR2=" TARGET_FMT_lx, env->cr[2]); } else { fprintf(logfile, " EAX=" TARGET_FMT_lx, EAX); } fprintf(logfile, "\n"); cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);#if 0 { int i; uint8_t *ptr; fprintf(logfile, " code="); ptr = env->segs[R_CS].base + env->eip; for(i = 0; i < 16; i++) { fprintf(logfile, " %02x", ldub(ptr + i)); } fprintf(logfile, "\n"); }#endif count++; } } if (env->cr[0] & CR0_PE_MASK) {#if TARGET_X86_64 if (env->hflags & HF_LMA_MASK) { do_interrupt64(intno, is_int, error_code, next_eip, is_hw); } else#endif { do_interrupt_protected(intno, is_int, error_code, next_eip, is_hw); } } else { do_interrupt_real(intno, is_int, error_code, next_eip); }}/* * Check nested exceptions and change to double or triple fault if * needed. It should only be called, if this is not an interrupt. * Returns the new exception number. */static int check_exception(int intno, int *error_code){ char first_contributory = env->old_exception == 0 || (env->old_exception >= 10 && env->old_exception <= 13); char second_contributory = intno == 0 || (intno >= 10 && intno <= 13); if (loglevel & CPU_LOG_INT) fprintf(logfile, "check_exception old: %x new %x\n", env->old_exception, intno); if (env->old_exception == EXCP08_DBLE) cpu_abort(env, "triple fault"); if ((first_contributory && second_contributory) || (env->old_exception == EXCP0E_PAGE && (second_contributory || (intno == EXCP0E_PAGE)))) { intno = EXCP08_DBLE; *error_code = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -