📄 helper.c
字号:
if ((type & 8) && (env->cr[0] & CR0_PG_MASK)) { cpu_x86_update_cr3(env, new_cr3); } /* load all registers without an exception, then reload them with possible exception */ env->eip = new_eip; eflags_mask = TF_MASK | AC_MASK | ID_MASK | IF_MASK | IOPL_MASK | VM_MASK | RF_MASK | NT_MASK; if (!(type & 8)) eflags_mask &= 0xffff; load_eflags(new_eflags, eflags_mask); /* XXX: what to do in 16 bit case ? */ EAX = new_regs[0]; ECX = new_regs[1]; EDX = new_regs[2]; EBX = new_regs[3]; ESP = new_regs[4]; EBP = new_regs[5]; ESI = new_regs[6]; EDI = new_regs[7]; if (new_eflags & VM_MASK) { for(i = 0; i < 6; i++) load_seg_vm(i, new_segs[i]); /* in vm86, CPL is always 3 */ cpu_x86_set_cpl(env, 3); } else { /* CPL is set the RPL of CS */ cpu_x86_set_cpl(env, new_segs[R_CS] & 3); /* first just selectors as the rest may trigger exceptions */ for(i = 0; i < 6; i++) cpu_x86_load_seg_cache(env, i, new_segs[i], 0, 0, 0); } env->ldt.selector = new_ldt & ~4; env->ldt.base = 0; env->ldt.limit = 0; env->ldt.flags = 0; /* load the LDT */ if (new_ldt & 4) raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc); if ((new_ldt & 0xfffc) != 0) { dt = &env->gdt; index = new_ldt & ~7; if ((index + 7) > dt->limit) raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc); ptr = dt->base + index; e1 = ldl_kernel(ptr); e2 = ldl_kernel(ptr + 4); if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2) raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc); if (!(e2 & DESC_P_MASK)) raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc); load_seg_cache_raw_dt(&env->ldt, e1, e2); } /* load the segments */ if (!(new_eflags & VM_MASK)) { tss_load_seg(R_CS, new_segs[R_CS]); tss_load_seg(R_SS, new_segs[R_SS]); tss_load_seg(R_ES, new_segs[R_ES]); tss_load_seg(R_DS, new_segs[R_DS]); tss_load_seg(R_FS, new_segs[R_FS]); tss_load_seg(R_GS, new_segs[R_GS]); } /* check that EIP is in the CS segment limits */ if (new_eip > env->segs[R_CS].limit) { /* XXX: different exception if CALL ? */ raise_exception_err(EXCP0D_GPF, 0); }}/* check if Port I/O is allowed in TSS */static inline void check_io(int addr, int size){ int io_offset, val, mask; /* TSS must be a valid 32 bit one */ if (!(env->tr.flags & DESC_P_MASK) || ((env->tr.flags >> DESC_TYPE_SHIFT) & 0xf) != 9 || env->tr.limit < 103) goto fail; io_offset = lduw_kernel(env->tr.base + 0x66); io_offset += (addr >> 3); /* Note: the check needs two bytes */ if ((io_offset + 1) > env->tr.limit) goto fail; val = lduw_kernel(env->tr.base + io_offset); val >>= (addr & 7); mask = (1 << size) - 1; /* all bits must be zero to allow the I/O */ if ((val & mask) != 0) { fail: raise_exception_err(EXCP0D_GPF, 0); }}void check_iob_T0(void){ check_io(T0, 1);}void check_iow_T0(void){ check_io(T0, 2);}void check_iol_T0(void){ check_io(T0, 4);}void check_iob_DX(void){ check_io(EDX & 0xffff, 1);}void check_iow_DX(void){ check_io(EDX & 0xffff, 2);}void check_iol_DX(void){ check_io(EDX & 0xffff, 4);}static inline unsigned int get_sp_mask(unsigned int e2){ if (e2 & DESC_B_MASK) return 0xffffffff; else return 0xffff;}#ifdef TARGET_X86_64#define SET_ESP(val, sp_mask)\do {\ if ((sp_mask) == 0xffff)\ ESP = (ESP & ~0xffff) | ((val) & 0xffff);\ else if ((sp_mask) == 0xffffffffLL)\ ESP = (uint32_t)(val);\ else\ ESP = (val);\} while (0)#else#define SET_ESP(val, sp_mask) ESP = (ESP & ~(sp_mask)) | ((val) & (sp_mask))#endif/* XXX: add a is_user flag to have proper security support */#define PUSHW(ssp, sp, sp_mask, val)\{\ sp -= 2;\ stw_kernel((ssp) + (sp & (sp_mask)), (val));\}#define PUSHL(ssp, sp, sp_mask, val)\{\ sp -= 4;\ stl_kernel((ssp) + (sp & (sp_mask)), (val));\}#define POPW(ssp, sp, sp_mask, val)\{\ val = lduw_kernel((ssp) + (sp & (sp_mask)));\ sp += 2;\}#define POPL(ssp, sp, sp_mask, val)\{\ val = (uint32_t)ldl_kernel((ssp) + (sp & (sp_mask)));\ sp += 4;\}/* protected mode interrupt */static void do_interrupt_protected(int intno, int is_int, int error_code, unsigned int next_eip, int is_hw){ SegmentCache *dt; target_ulong ptr, ssp; int type, dpl, selector, ss_dpl, cpl; int has_error_code, new_stack, shift; uint32_t e1, e2, offset, ss, esp, ss_e1, ss_e2; uint32_t old_eip, sp_mask; 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 * 8 + 7 > dt->limit) raise_exception_err(EXCP0D_GPF, intno * 8 + 2); ptr = dt->base + intno * 8; e1 = ldl_kernel(ptr); e2 = ldl_kernel(ptr + 4); /* check gate type */ type = (e2 >> DESC_TYPE_SHIFT) & 0x1f; switch(type) { case 5: /* task gate */ /* must do that check here to return the correct error code */ if (!(e2 & DESC_P_MASK)) raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2); switch_tss(intno * 8, e1, e2, SWITCH_TSS_CALL, old_eip); if (has_error_code) { int type; uint32_t mask; /* push the error code */ type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf; shift = type >> 3; if (env->segs[R_SS].flags & DESC_B_MASK) mask = 0xffffffff; else mask = 0xffff; esp = (ESP - (2 << shift)) & mask; ssp = env->segs[R_SS].base + esp; if (shift) stl_kernel(ssp, error_code); else stw_kernel(ssp, error_code); SET_ESP(esp, mask); } return; case 6: /* 286 interrupt gate */ case 7: /* 286 trap gate */ case 14: /* 386 interrupt gate */ case 15: /* 386 trap gate */ break; default: raise_exception_err(EXCP0D_GPF, intno * 8 + 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 * 8 + 2); /* check valid bit */ if (!(e2 & DESC_P_MASK)) raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2); selector = e1 >> 16; offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff); 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_C_MASK) && dpl < cpl) { /* to inner priviledge */ get_ss_esp_from_tss(&ss, &esp, dpl); if ((ss & 0xfffc) == 0) raise_exception_err(EXCP0A_TSS, ss & 0xfffc); if ((ss & 3) != dpl) raise_exception_err(EXCP0A_TSS, ss & 0xfffc); if (load_segment(&ss_e1, &ss_e2, ss) != 0) raise_exception_err(EXCP0A_TSS, ss & 0xfffc); ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3; if (ss_dpl != dpl) raise_exception_err(EXCP0A_TSS, ss & 0xfffc); if (!(ss_e2 & DESC_S_MASK) || (ss_e2 & DESC_CS_MASK) || !(ss_e2 & DESC_W_MASK)) raise_exception_err(EXCP0A_TSS, ss & 0xfffc); if (!(ss_e2 & DESC_P_MASK)) raise_exception_err(EXCP0A_TSS, ss & 0xfffc); new_stack = 1; sp_mask = get_sp_mask(ss_e2); ssp = get_seg_base(ss_e1, ss_e2); } 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; sp_mask = get_sp_mask(env->segs[R_SS].flags); ssp = env->segs[R_SS].base; esp = ESP; dpl = cpl; } else { raise_exception_err(EXCP0D_GPF, selector & 0xfffc); new_stack = 0; /* avoid warning */ sp_mask = 0; /* avoid warning */ ssp = 0; /* avoid warning */ esp = 0; /* avoid warning */ } shift = type >> 3;#if 0 /* XXX: check that enough room is available */ push_size = 6 + (new_stack << 2) + (has_error_code << 1); if (env->eflags & VM_MASK) push_size += 8; push_size <<= shift;#endif if (shift == 1) { if (new_stack) { if (env->eflags & VM_MASK) { PUSHL(ssp, esp, sp_mask, env->segs[R_GS].selector); PUSHL(ssp, esp, sp_mask, env->segs[R_FS].selector); PUSHL(ssp, esp, sp_mask, env->segs[R_DS].selector); PUSHL(ssp, esp, sp_mask, env->segs[R_ES].selector); } PUSHL(ssp, esp, sp_mask, env->segs[R_SS].selector); PUSHL(ssp, esp, sp_mask, ESP); } PUSHL(ssp, esp, sp_mask, compute_eflags()); PUSHL(ssp, esp, sp_mask, env->segs[R_CS].selector); PUSHL(ssp, esp, sp_mask, old_eip); if (has_error_code) { PUSHL(ssp, esp, sp_mask, error_code); } } else { if (new_stack) { if (env->eflags & VM_MASK) { PUSHW(ssp, esp, sp_mask, env->segs[R_GS].selector); PUSHW(ssp, esp, sp_mask, env->segs[R_FS].selector); PUSHW(ssp, esp, sp_mask, env->segs[R_DS].selector); PUSHW(ssp, esp, sp_mask, env->segs[R_ES].selector); } PUSHW(ssp, esp, sp_mask, env->segs[R_SS].selector); PUSHW(ssp, esp, sp_mask, ESP); } PUSHW(ssp, esp, sp_mask, compute_eflags()); PUSHW(ssp, esp, sp_mask, env->segs[R_CS].selector); PUSHW(ssp, esp, sp_mask, old_eip); if (has_error_code) { PUSHW(ssp, esp, sp_mask, error_code); } } if (new_stack) { if (env->eflags & VM_MASK) { cpu_x86_load_seg_cache(env, R_ES, 0, 0, 0, 0); cpu_x86_load_seg_cache(env, R_DS, 0, 0, 0, 0); cpu_x86_load_seg_cache(env, R_FS, 0, 0, 0, 0); cpu_x86_load_seg_cache(env, R_GS, 0, 0, 0, 0); } ss = (ss & ~3) | dpl; cpu_x86_load_seg_cache(env, R_SS, ss, ssp, get_seg_limit(ss_e1, ss_e2), ss_e2); } SET_ESP(esp, sp_mask); 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);}#ifdef TARGET_X86_64#define PUSHQ(sp, val)\{\ sp -= 8;\ stq_kernel(sp, (val));\}#define POPQ(sp, val)\{\ val = ldq_kernel(sp);\ sp += 8;\}static inline target_ulong get_rsp_from_tss(int level){ int index; #if 0 printf("TR: base=" TARGET_FMT_lx " limit=%x\n", env->tr.base, env->tr.limit);#endif if (!(env->tr.flags & DESC_P_MASK)) cpu_abort(env, "invalid tss"); index = 8 * level + 4; if ((index + 7) > env->tr.limit) raise_exception_err(EXCP0A_TSS, env->tr.selector & 0xfffc); return ldq_kernel(env->tr.base + index);}/* 64 bit interrupt */static void do_interrupt64(int intno, int is_int, int error_code,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -