📄 helper.c
字号:
target_ulong next_eip, int is_hw){ 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; 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 priviledge */ 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 priviledge */ 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);}#endifvoid 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; }}void 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; /* 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; uint32_t e2; dt = &env->idt; ptr = dt->base + (intno * 8); 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 * 8 + 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); }}/* * Signal an interruption. It is executed in the main CPU loop. * 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 raise_interrupt(int intno, int is_int, int error_code, int next_eip_addend){ env->exception_index = intno; env->error_code = error_code; env->exception_is_int = is_int; env->exception_next_eip = env->eip + next_eip_addend; cpu_loop_exit();}/* same as raise_exception_err, but do not restore global registers */static void raise_exception_err_norestore(int exception_index, int error_code){ env->exception_index = exception_index; env->error_code = error_code; env->exception_is_int = 0; env->exception_next_eip = 0; longjmp(env->jmp_env, 1);}/* shortcuts to generate exceptions */void (raise_exception_err)(int exception_index, int error_code){ raise_interrupt(exception_index, 0, error_code, 0);}void raise_exception(int exception_index){ raise_interrupt(exception_index, 0, 0, 0);}/* SMM support */#if defined(CONFIG_USER_ONLY) void do_smm_enter(void){}void helper_rsm(void){}#else#ifdef TARGET_X86_64#define SMM_REVISION_ID 0x00020064
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -