Commit 872929aa59cba19fd83b98f87929ccda12a2cbbb
1 parent
893f9865
SVM rework
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4605 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
8 changed files
with
383 additions
and
478 deletions
cpu-exec.c
... | ... | @@ -171,7 +171,6 @@ static inline TranslationBlock *tb_find_fast(void) |
171 | 171 | #if defined(TARGET_I386) |
172 | 172 | flags = env->hflags; |
173 | 173 | flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK)); |
174 | - flags |= env->intercept; | |
175 | 174 | cs_base = env->segs[R_CS].base; |
176 | 175 | pc = cs_base + env->eip; |
177 | 176 | #elif defined(TARGET_ARM) | ... | ... |
target-i386/TODO
1 | 1 | Correctness issues: |
2 | 2 | |
3 | 3 | - some eflags manipulation incorrectly reset the bit 0x2. |
4 | -- SVM: rework the implementation: simplify code, move most intercept | |
5 | - tests as dynamic, correct segment access, verify exception safety, | |
6 | - cpu save/restore, SMM save/restore. | |
4 | +- SVM: test, cpu save/restore, SMM save/restore. | |
7 | 5 | - x86_64: lcall/ljmp intel/amd differences ? |
8 | 6 | - better code fetch (different exception handling + CS.limit support) |
9 | 7 | - user/kernel PUSHL/POPL in helper.c | ... | ... |
target-i386/cpu.h
... | ... | @@ -149,6 +149,8 @@ |
149 | 149 | #define HF_GIF_SHIFT 20 /* if set CPU takes interrupts */ |
150 | 150 | #define HF_HIF_SHIFT 21 /* shadow copy of IF_MASK when in SVM */ |
151 | 151 | #define HF_NMI_SHIFT 22 /* CPU serving NMI */ |
152 | +#define HF_SVME_SHIFT 23 /* SVME enabled (copy of EFER.SVME */ | |
153 | +#define HF_SVMI_SHIFT 24 /* SVM intercepts are active */ | |
152 | 154 | |
153 | 155 | #define HF_CPL_MASK (3 << HF_CPL_SHIFT) |
154 | 156 | #define HF_SOFTMMU_MASK (1 << HF_SOFTMMU_SHIFT) |
... | ... | @@ -169,6 +171,8 @@ |
169 | 171 | #define HF_GIF_MASK (1 << HF_GIF_SHIFT) |
170 | 172 | #define HF_HIF_MASK (1 << HF_HIF_SHIFT) |
171 | 173 | #define HF_NMI_MASK (1 << HF_NMI_SHIFT) |
174 | +#define HF_SVME_MASK (1 << HF_SVME_SHIFT) | |
175 | +#define HF_SVMI_MASK (1 << HF_SVMI_SHIFT) | |
172 | 176 | |
173 | 177 | #define CR0_PE_MASK (1 << 0) |
174 | 178 | #define CR0_MP_MASK (1 << 1) |
... | ... | @@ -242,6 +246,7 @@ |
242 | 246 | #define MSR_EFER_LME (1 << 8) |
243 | 247 | #define MSR_EFER_LMA (1 << 10) |
244 | 248 | #define MSR_EFER_NXE (1 << 11) |
249 | +#define MSR_EFER_SVME (1 << 12) | |
245 | 250 | #define MSR_EFER_FFXSR (1 << 14) |
246 | 251 | |
247 | 252 | #define MSR_STAR 0xc0000081 |
... | ... | @@ -322,6 +327,7 @@ |
322 | 327 | #define CPUID_EXT3_3DNOWPREFETCH (1 << 8) |
323 | 328 | #define CPUID_EXT3_OSVW (1 << 9) |
324 | 329 | #define CPUID_EXT3_IBS (1 << 10) |
330 | +#define CPUID_EXT3_SKINIT (1 << 12) | |
325 | 331 | |
326 | 332 | #define EXCP00_DIVZ 0 |
327 | 333 | #define EXCP01_SSTP 1 | ... | ... |
target-i386/helper.c
... | ... | @@ -1096,16 +1096,15 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, |
1096 | 1096 | (env->efer & MSR_EFER_NXE) && |
1097 | 1097 | (env->cr[4] & CR4_PAE_MASK)) |
1098 | 1098 | error_code |= PG_ERROR_I_D_MASK; |
1099 | - if (INTERCEPTEDl(_exceptions, 1 << EXCP0E_PAGE)) { | |
1100 | - stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), addr); | |
1099 | + if (env->intercept_exceptions & (1 << EXCP0E_PAGE)) { | |
1100 | + /* cr2 is not modified in case of exceptions */ | |
1101 | + stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), | |
1102 | + addr); | |
1101 | 1103 | } else { |
1102 | 1104 | env->cr[2] = addr; |
1103 | 1105 | } |
1104 | 1106 | env->error_code = error_code; |
1105 | 1107 | env->exception_index = EXCP0E_PAGE; |
1106 | - /* the VMM will handle this */ | |
1107 | - if (INTERCEPTEDl(_exceptions, 1 << EXCP0E_PAGE)) | |
1108 | - return 2; | |
1109 | 1108 | return 1; |
1110 | 1109 | } |
1111 | 1110 | ... | ... |
target-i386/helper.h
... | ... | @@ -43,7 +43,8 @@ DEF_HELPER(void, helper_lcall_protected, (int new_cs, target_ulong new_eip, |
43 | 43 | DEF_HELPER(void, helper_iret_real, (int shift)) |
44 | 44 | DEF_HELPER(void, helper_iret_protected, (int shift, int next_eip)) |
45 | 45 | DEF_HELPER(void, helper_lret_protected, (int shift, int addend)) |
46 | -DEF_HELPER(void, helper_movl_crN_T0, (int reg, target_ulong t0)) | |
46 | +DEF_HELPER(target_ulong, helper_read_crN, (int reg)) | |
47 | +DEF_HELPER(void, helper_write_crN, (int reg, target_ulong t0)) | |
47 | 48 | DEF_HELPER(void, helper_lmsw, (target_ulong t0)) |
48 | 49 | DEF_HELPER(void, helper_clts, (void)) |
49 | 50 | #if !defined(CONFIG_USER_ONLY) | ... | ... |
target-i386/op_helper.c
... | ... | @@ -625,18 +625,7 @@ static void do_interrupt_protected(int intno, int is_int, int error_code, |
625 | 625 | int has_error_code, new_stack, shift; |
626 | 626 | uint32_t e1, e2, offset, ss, esp, ss_e1, ss_e2; |
627 | 627 | uint32_t old_eip, sp_mask; |
628 | - int svm_should_check = 1; | |
629 | 628 | |
630 | - if ((env->intercept & INTERCEPT_SVM_MASK) && !is_int && next_eip==-1) { | |
631 | - next_eip = EIP; | |
632 | - svm_should_check = 0; | |
633 | - } | |
634 | - | |
635 | - if (svm_should_check | |
636 | - && (INTERCEPTEDl(_exceptions, 1 << intno) | |
637 | - && !is_int)) { | |
638 | - raise_interrupt(intno, is_int, error_code, 0); | |
639 | - } | |
640 | 629 | has_error_code = 0; |
641 | 630 | if (!is_int && !is_hw) { |
642 | 631 | switch(intno) { |
... | ... | @@ -872,17 +861,7 @@ static void do_interrupt64(int intno, int is_int, int error_code, |
872 | 861 | int has_error_code, new_stack; |
873 | 862 | uint32_t e1, e2, e3, ss; |
874 | 863 | target_ulong old_eip, esp, offset; |
875 | - int svm_should_check = 1; | |
876 | 864 | |
877 | - if ((env->intercept & INTERCEPT_SVM_MASK) && !is_int && next_eip==-1) { | |
878 | - next_eip = EIP; | |
879 | - svm_should_check = 0; | |
880 | - } | |
881 | - if (svm_should_check | |
882 | - && INTERCEPTEDl(_exceptions, 1 << intno) | |
883 | - && !is_int) { | |
884 | - raise_interrupt(intno, is_int, error_code, 0); | |
885 | - } | |
886 | 865 | has_error_code = 0; |
887 | 866 | if (!is_int && !is_hw) { |
888 | 867 | switch(intno) { |
... | ... | @@ -1139,17 +1118,7 @@ static void do_interrupt_real(int intno, int is_int, int error_code, |
1139 | 1118 | int selector; |
1140 | 1119 | uint32_t offset, esp; |
1141 | 1120 | uint32_t old_cs, old_eip; |
1142 | - int svm_should_check = 1; | |
1143 | 1121 | |
1144 | - if ((env->intercept & INTERCEPT_SVM_MASK) && !is_int && next_eip==-1) { | |
1145 | - next_eip = EIP; | |
1146 | - svm_should_check = 0; | |
1147 | - } | |
1148 | - if (svm_should_check | |
1149 | - && INTERCEPTEDl(_exceptions, 1 << intno) | |
1150 | - && !is_int) { | |
1151 | - raise_interrupt(intno, is_int, error_code, 0); | |
1152 | - } | |
1153 | 1122 | /* real mode (simpler !) */ |
1154 | 1123 | dt = &env->idt; |
1155 | 1124 | if (intno * 4 + 3 > dt->limit) |
... | ... | @@ -1307,6 +1276,8 @@ void raise_interrupt(int intno, int is_int, int error_code, |
1307 | 1276 | if (!is_int) { |
1308 | 1277 | helper_svm_check_intercept_param(SVM_EXIT_EXCP_BASE + intno, error_code); |
1309 | 1278 | intno = check_exception(intno, &error_code); |
1279 | + } else { | |
1280 | + helper_svm_check_intercept_param(SVM_EXIT_SWINT, 0); | |
1310 | 1281 | } |
1311 | 1282 | |
1312 | 1283 | env->exception_index = intno; |
... | ... | @@ -1316,18 +1287,6 @@ void raise_interrupt(int intno, int is_int, int error_code, |
1316 | 1287 | cpu_loop_exit(); |
1317 | 1288 | } |
1318 | 1289 | |
1319 | -/* same as raise_exception_err, but do not restore global registers */ | |
1320 | -static void raise_exception_err_norestore(int exception_index, int error_code) | |
1321 | -{ | |
1322 | - exception_index = check_exception(exception_index, &error_code); | |
1323 | - | |
1324 | - env->exception_index = exception_index; | |
1325 | - env->error_code = error_code; | |
1326 | - env->exception_is_int = 0; | |
1327 | - env->exception_next_eip = 0; | |
1328 | - longjmp(env->jmp_env, 1); | |
1329 | -} | |
1330 | - | |
1331 | 1290 | /* shortcuts to generate exceptions */ |
1332 | 1291 | |
1333 | 1292 | void (raise_exception_err)(int exception_index, int error_code) |
... | ... | @@ -1921,8 +1880,10 @@ void helper_single_step(void) |
1921 | 1880 | void helper_cpuid(void) |
1922 | 1881 | { |
1923 | 1882 | uint32_t index; |
1924 | - index = (uint32_t)EAX; | |
1925 | 1883 | |
1884 | + helper_svm_check_intercept_param(SVM_EXIT_CPUID, 0); | |
1885 | + | |
1886 | + index = (uint32_t)EAX; | |
1926 | 1887 | /* test if maximum index reached */ |
1927 | 1888 | if (index & 0x80000000) { |
1928 | 1889 | if (index > env->cpuid_xlevel) |
... | ... | @@ -2957,9 +2918,35 @@ void helper_sysexit(void) |
2957 | 2918 | #endif |
2958 | 2919 | } |
2959 | 2920 | |
2960 | -void helper_movl_crN_T0(int reg, target_ulong t0) | |
2921 | +#if defined(CONFIG_USER_ONLY) | |
2922 | +target_ulong helper_read_crN(int reg) | |
2961 | 2923 | { |
2962 | -#if !defined(CONFIG_USER_ONLY) | |
2924 | + return 0; | |
2925 | +} | |
2926 | + | |
2927 | +void helper_write_crN(int reg, target_ulong t0) | |
2928 | +{ | |
2929 | +} | |
2930 | +#else | |
2931 | +target_ulong helper_read_crN(int reg) | |
2932 | +{ | |
2933 | + target_ulong val; | |
2934 | + | |
2935 | + helper_svm_check_intercept_param(SVM_EXIT_READ_CR0 + reg, 0); | |
2936 | + switch(reg) { | |
2937 | + default: | |
2938 | + val = env->cr[reg]; | |
2939 | + break; | |
2940 | + case 8: | |
2941 | + val = cpu_get_apic_tpr(env); | |
2942 | + break; | |
2943 | + } | |
2944 | + return val; | |
2945 | +} | |
2946 | + | |
2947 | +void helper_write_crN(int reg, target_ulong t0) | |
2948 | +{ | |
2949 | + helper_svm_check_intercept_param(SVM_EXIT_WRITE_CR0 + reg, 0); | |
2963 | 2950 | switch(reg) { |
2964 | 2951 | case 0: |
2965 | 2952 | cpu_x86_update_cr0(env, t0); |
... | ... | @@ -2978,15 +2965,15 @@ void helper_movl_crN_T0(int reg, target_ulong t0) |
2978 | 2965 | env->cr[reg] = t0; |
2979 | 2966 | break; |
2980 | 2967 | } |
2981 | -#endif | |
2982 | 2968 | } |
2969 | +#endif | |
2983 | 2970 | |
2984 | 2971 | void helper_lmsw(target_ulong t0) |
2985 | 2972 | { |
2986 | 2973 | /* only 4 lower bits of CR0 are modified. PE cannot be set to zero |
2987 | 2974 | if already set to one. */ |
2988 | 2975 | t0 = (env->cr[0] & ~0xe) | (t0 & 0xf); |
2989 | - helper_movl_crN_T0(0, t0); | |
2976 | + helper_write_crN(0, t0); | |
2990 | 2977 | } |
2991 | 2978 | |
2992 | 2979 | void helper_clts(void) |
... | ... | @@ -3010,6 +2997,7 @@ void helper_movl_drN_T0(int reg, target_ulong t0) |
3010 | 2997 | |
3011 | 2998 | void helper_invlpg(target_ulong addr) |
3012 | 2999 | { |
3000 | + helper_svm_check_intercept_param(SVM_EXIT_INVLPG, 0); | |
3013 | 3001 | cpu_x86_flush_tlb(env, addr); |
3014 | 3002 | } |
3015 | 3003 | |
... | ... | @@ -3020,6 +3008,8 @@ void helper_rdtsc(void) |
3020 | 3008 | if ((env->cr[4] & CR4_TSD_MASK) && ((env->hflags & HF_CPL_MASK) != 0)) { |
3021 | 3009 | raise_exception(EXCP0D_GPF); |
3022 | 3010 | } |
3011 | + helper_svm_check_intercept_param(SVM_EXIT_RDTSC, 0); | |
3012 | + | |
3023 | 3013 | val = cpu_get_tsc(env); |
3024 | 3014 | EAX = (uint32_t)(val); |
3025 | 3015 | EDX = (uint32_t)(val >> 32); |
... | ... | @@ -3030,7 +3020,6 @@ void helper_rdpmc(void) |
3030 | 3020 | if ((env->cr[4] & CR4_PCE_MASK) && ((env->hflags & HF_CPL_MASK) != 0)) { |
3031 | 3021 | raise_exception(EXCP0D_GPF); |
3032 | 3022 | } |
3033 | - | |
3034 | 3023 | helper_svm_check_intercept_param(SVM_EXIT_RDPMC, 0); |
3035 | 3024 | |
3036 | 3025 | /* currently unimplemented */ |
... | ... | @@ -3050,6 +3039,8 @@ void helper_wrmsr(void) |
3050 | 3039 | { |
3051 | 3040 | uint64_t val; |
3052 | 3041 | |
3042 | + helper_svm_check_intercept_param(SVM_EXIT_MSR, 1); | |
3043 | + | |
3053 | 3044 | val = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32); |
3054 | 3045 | |
3055 | 3046 | switch((uint32_t)ECX) { |
... | ... | @@ -3119,6 +3110,9 @@ void helper_wrmsr(void) |
3119 | 3110 | void helper_rdmsr(void) |
3120 | 3111 | { |
3121 | 3112 | uint64_t val; |
3113 | + | |
3114 | + helper_svm_check_intercept_param(SVM_EXIT_MSR, 0); | |
3115 | + | |
3122 | 3116 | switch((uint32_t)ECX) { |
3123 | 3117 | case MSR_IA32_SYSENTER_CS: |
3124 | 3118 | val = env->sysenter_cs; |
... | ... | @@ -4549,6 +4543,8 @@ void helper_idivq_EAX(target_ulong t0) |
4549 | 4543 | |
4550 | 4544 | void helper_hlt(void) |
4551 | 4545 | { |
4546 | + helper_svm_check_intercept_param(SVM_EXIT_HLT, 0); | |
4547 | + | |
4552 | 4548 | env->hflags &= ~HF_INHIBIT_IRQ_MASK; /* needed if sti is just before */ |
4553 | 4549 | env->hflags |= HF_HALTED_MASK; |
4554 | 4550 | env->exception_index = EXCP_HLT; |
... | ... | @@ -4560,12 +4556,14 @@ void helper_monitor(target_ulong ptr) |
4560 | 4556 | if ((uint32_t)ECX != 0) |
4561 | 4557 | raise_exception(EXCP0D_GPF); |
4562 | 4558 | /* XXX: store address ? */ |
4559 | + helper_svm_check_intercept_param(SVM_EXIT_MONITOR, 0); | |
4563 | 4560 | } |
4564 | 4561 | |
4565 | 4562 | void helper_mwait(void) |
4566 | 4563 | { |
4567 | 4564 | if ((uint32_t)ECX != 0) |
4568 | 4565 | raise_exception(EXCP0D_GPF); |
4566 | + helper_svm_check_intercept_param(SVM_EXIT_MWAIT, 0); | |
4569 | 4567 | /* XXX: not complete but not completely erroneous */ |
4570 | 4568 | if (env->cpu_index != 0 || env->next_cpu != NULL) { |
4571 | 4569 | /* more than one CPU: do not sleep because another CPU may |
... | ... | @@ -4706,10 +4704,7 @@ void tlb_fill(target_ulong addr, int is_write, int mmu_idx, void *retaddr) |
4706 | 4704 | cpu_restore_state(tb, env, pc, NULL); |
4707 | 4705 | } |
4708 | 4706 | } |
4709 | - if (retaddr) | |
4710 | - raise_exception_err(env->exception_index, env->error_code); | |
4711 | - else | |
4712 | - raise_exception_err_norestore(env->exception_index, env->error_code); | |
4707 | + raise_exception_err(env->exception_index, env->error_code); | |
4713 | 4708 | } |
4714 | 4709 | env = saved_env; |
4715 | 4710 | } |
... | ... | @@ -4717,16 +4712,6 @@ void tlb_fill(target_ulong addr, int is_write, int mmu_idx, void *retaddr) |
4717 | 4712 | |
4718 | 4713 | /* Secure Virtual Machine helpers */ |
4719 | 4714 | |
4720 | -void helper_stgi(void) | |
4721 | -{ | |
4722 | - env->hflags |= HF_GIF_MASK; | |
4723 | -} | |
4724 | - | |
4725 | -void helper_clgi(void) | |
4726 | -{ | |
4727 | - env->hflags &= ~HF_GIF_MASK; | |
4728 | -} | |
4729 | - | |
4730 | 4715 | #if defined(CONFIG_USER_ONLY) |
4731 | 4716 | |
4732 | 4717 | void helper_vmrun(void) |
... | ... | @@ -4741,6 +4726,12 @@ void helper_vmload(void) |
4741 | 4726 | void helper_vmsave(void) |
4742 | 4727 | { |
4743 | 4728 | } |
4729 | +void helper_stgi(void) | |
4730 | +{ | |
4731 | +} | |
4732 | +void helper_clgi(void) | |
4733 | +{ | |
4734 | +} | |
4744 | 4735 | void helper_skinit(void) |
4745 | 4736 | { |
4746 | 4737 | } |
... | ... | @@ -4760,20 +4751,37 @@ void helper_svm_check_io(uint32_t port, uint32_t param, |
4760 | 4751 | } |
4761 | 4752 | #else |
4762 | 4753 | |
4763 | -static inline uint32_t | |
4764 | -vmcb2cpu_attrib(uint16_t vmcb_attrib, uint32_t vmcb_base, uint32_t vmcb_limit) | |
4754 | +static inline void svm_save_seg(target_phys_addr_t addr, | |
4755 | + const SegmentCache *sc) | |
4765 | 4756 | { |
4766 | - return ((vmcb_attrib & 0x00ff) << 8) /* Type, S, DPL, P */ | |
4767 | - | ((vmcb_attrib & 0x0f00) << 12) /* AVL, L, DB, G */ | |
4768 | - | ((vmcb_base >> 16) & 0xff) /* Base 23-16 */ | |
4769 | - | (vmcb_base & 0xff000000) /* Base 31-24 */ | |
4770 | - | (vmcb_limit & 0xf0000); /* Limit 19-16 */ | |
4757 | + stw_phys(addr + offsetof(struct vmcb_seg, selector), | |
4758 | + sc->selector); | |
4759 | + stq_phys(addr + offsetof(struct vmcb_seg, base), | |
4760 | + sc->base); | |
4761 | + stl_phys(addr + offsetof(struct vmcb_seg, limit), | |
4762 | + sc->limit); | |
4763 | + stw_phys(addr + offsetof(struct vmcb_seg, attrib), | |
4764 | + (sc->flags >> 8) | ((sc->flags >> 12) & 0x0f00)); | |
4765 | +} | |
4766 | + | |
4767 | +static inline void svm_load_seg(target_phys_addr_t addr, SegmentCache *sc) | |
4768 | +{ | |
4769 | + unsigned int flags; | |
4770 | + | |
4771 | + sc->selector = lduw_phys(addr + offsetof(struct vmcb_seg, selector)); | |
4772 | + sc->base = ldq_phys(addr + offsetof(struct vmcb_seg, base)); | |
4773 | + sc->limit = ldl_phys(addr + offsetof(struct vmcb_seg, limit)); | |
4774 | + flags = lduw_phys(addr + offsetof(struct vmcb_seg, attrib)); | |
4775 | + sc->flags = ((flags & 0xff) << 8) | ((flags & 0x0f00) << 12); | |
4771 | 4776 | } |
4772 | 4777 | |
4773 | -static inline uint16_t cpu2vmcb_attrib(uint32_t cpu_attrib) | |
4778 | +static inline void svm_load_seg_cache(target_phys_addr_t addr, | |
4779 | + CPUState *env, int seg_reg) | |
4774 | 4780 | { |
4775 | - return ((cpu_attrib >> 8) & 0xff) /* Type, S, DPL, P */ | |
4776 | - | ((cpu_attrib & 0xf00000) >> 12); /* AVL, L, DB, G */ | |
4781 | + SegmentCache sc1, *sc = &sc1; | |
4782 | + svm_load_seg(addr, sc); | |
4783 | + cpu_x86_load_seg_cache(env, seg_reg, sc->selector, | |
4784 | + sc->base, sc->limit, sc->flags); | |
4777 | 4785 | } |
4778 | 4786 | |
4779 | 4787 | void helper_vmrun(void) |
... | ... | @@ -4782,6 +4790,8 @@ void helper_vmrun(void) |
4782 | 4790 | uint32_t event_inj; |
4783 | 4791 | uint32_t int_ctl; |
4784 | 4792 | |
4793 | + helper_svm_check_intercept_param(SVM_EXIT_VMRUN, 0); | |
4794 | + | |
4785 | 4795 | addr = EAX; |
4786 | 4796 | if (loglevel & CPU_LOG_TB_IN_ASM) |
4787 | 4797 | fprintf(logfile,"vmrun! " TARGET_FMT_lx "\n", addr); |
... | ... | @@ -4806,10 +4816,14 @@ void helper_vmrun(void) |
4806 | 4816 | stq_phys(env->vm_hsave + offsetof(struct vmcb, save.efer), env->efer); |
4807 | 4817 | stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rflags), compute_eflags()); |
4808 | 4818 | |
4809 | - SVM_SAVE_SEG(env->vm_hsave, segs[R_ES], es); | |
4810 | - SVM_SAVE_SEG(env->vm_hsave, segs[R_CS], cs); | |
4811 | - SVM_SAVE_SEG(env->vm_hsave, segs[R_SS], ss); | |
4812 | - SVM_SAVE_SEG(env->vm_hsave, segs[R_DS], ds); | |
4819 | + svm_save_seg(env->vm_hsave + offsetof(struct vmcb, save.es), | |
4820 | + &env->segs[R_ES]); | |
4821 | + svm_save_seg(env->vm_hsave + offsetof(struct vmcb, save.cs), | |
4822 | + &env->segs[R_CS]); | |
4823 | + svm_save_seg(env->vm_hsave + offsetof(struct vmcb, save.ss), | |
4824 | + &env->segs[R_SS]); | |
4825 | + svm_save_seg(env->vm_hsave + offsetof(struct vmcb, save.ds), | |
4826 | + &env->segs[R_DS]); | |
4813 | 4827 | |
4814 | 4828 | stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rip), EIP); |
4815 | 4829 | stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rsp), ESP); |
... | ... | @@ -4817,15 +4831,16 @@ void helper_vmrun(void) |
4817 | 4831 | |
4818 | 4832 | /* load the interception bitmaps so we do not need to access the |
4819 | 4833 | vmcb in svm mode */ |
4820 | - /* We shift all the intercept bits so we can OR them with the TB | |
4821 | - flags later on */ | |
4822 | - env->intercept = (ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept)) << INTERCEPT_INTR) | INTERCEPT_SVM_MASK; | |
4834 | + env->intercept = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept)); | |
4823 | 4835 | env->intercept_cr_read = lduw_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_cr_read)); |
4824 | 4836 | env->intercept_cr_write = lduw_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_cr_write)); |
4825 | 4837 | env->intercept_dr_read = lduw_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_dr_read)); |
4826 | 4838 | env->intercept_dr_write = lduw_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_dr_write)); |
4827 | 4839 | env->intercept_exceptions = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_exceptions)); |
4828 | 4840 | |
4841 | + /* enable intercepts */ | |
4842 | + env->hflags |= HF_SVMI_MASK; | |
4843 | + | |
4829 | 4844 | env->gdt.base = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.base)); |
4830 | 4845 | env->gdt.limit = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.limit)); |
4831 | 4846 | |
... | ... | @@ -4857,12 +4872,15 @@ void helper_vmrun(void) |
4857 | 4872 | load_eflags(ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rflags)), |
4858 | 4873 | ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK)); |
4859 | 4874 | CC_OP = CC_OP_EFLAGS; |
4860 | - CC_DST = 0xffffffff; | |
4861 | 4875 | |
4862 | - SVM_LOAD_SEG(env->vm_vmcb, ES, es); | |
4863 | - SVM_LOAD_SEG(env->vm_vmcb, CS, cs); | |
4864 | - SVM_LOAD_SEG(env->vm_vmcb, SS, ss); | |
4865 | - SVM_LOAD_SEG(env->vm_vmcb, DS, ds); | |
4876 | + svm_load_seg_cache(env->vm_vmcb + offsetof(struct vmcb, save.es), | |
4877 | + env, R_ES); | |
4878 | + svm_load_seg_cache(env->vm_vmcb + offsetof(struct vmcb, save.cs), | |
4879 | + env, R_CS); | |
4880 | + svm_load_seg_cache(env->vm_vmcb + offsetof(struct vmcb, save.ss), | |
4881 | + env, R_SS); | |
4882 | + svm_load_seg_cache(env->vm_vmcb + offsetof(struct vmcb, save.ds), | |
4883 | + env, R_DS); | |
4866 | 4884 | |
4867 | 4885 | EIP = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rip)); |
4868 | 4886 | env->eip = EIP; |
... | ... | @@ -4933,7 +4951,8 @@ void helper_vmrun(void) |
4933 | 4951 | if (loglevel & CPU_LOG_TB_IN_ASM) |
4934 | 4952 | fprintf(logfile, " %#x %#x\n", env->exception_index, env->error_code); |
4935 | 4953 | } |
4936 | - if ((int_ctl & V_IRQ_MASK) || (env->intercept & INTERCEPT_VINTR)) { | |
4954 | + if ((int_ctl & V_IRQ_MASK) || | |
4955 | + (env->intercept & (1ULL << (SVM_EXIT_INTR - SVM_EXIT_INTR)))) { | |
4937 | 4956 | env->interrupt_request |= CPU_INTERRUPT_VIRQ; |
4938 | 4957 | } |
4939 | 4958 | |
... | ... | @@ -4942,23 +4961,30 @@ void helper_vmrun(void) |
4942 | 4961 | |
4943 | 4962 | void helper_vmmcall(void) |
4944 | 4963 | { |
4945 | - if (loglevel & CPU_LOG_TB_IN_ASM) | |
4946 | - fprintf(logfile,"vmmcall!\n"); | |
4964 | + helper_svm_check_intercept_param(SVM_EXIT_VMMCALL, 0); | |
4965 | + raise_exception(EXCP06_ILLOP); | |
4947 | 4966 | } |
4948 | 4967 | |
4949 | 4968 | void helper_vmload(void) |
4950 | 4969 | { |
4951 | 4970 | target_ulong addr; |
4971 | + helper_svm_check_intercept_param(SVM_EXIT_VMLOAD, 0); | |
4972 | + | |
4973 | + /* XXX: invalid in 32 bit */ | |
4952 | 4974 | addr = EAX; |
4953 | 4975 | if (loglevel & CPU_LOG_TB_IN_ASM) |
4954 | 4976 | fprintf(logfile,"vmload! " TARGET_FMT_lx "\nFS: %016" PRIx64 " | " TARGET_FMT_lx "\n", |
4955 | 4977 | addr, ldq_phys(addr + offsetof(struct vmcb, save.fs.base)), |
4956 | 4978 | env->segs[R_FS].base); |
4957 | 4979 | |
4958 | - SVM_LOAD_SEG2(addr, segs[R_FS], fs); | |
4959 | - SVM_LOAD_SEG2(addr, segs[R_GS], gs); | |
4960 | - SVM_LOAD_SEG2(addr, tr, tr); | |
4961 | - SVM_LOAD_SEG2(addr, ldt, ldtr); | |
4980 | + svm_load_seg_cache(addr + offsetof(struct vmcb, save.fs), | |
4981 | + env, R_FS); | |
4982 | + svm_load_seg_cache(addr + offsetof(struct vmcb, save.gs), | |
4983 | + env, R_GS); | |
4984 | + svm_load_seg(addr + offsetof(struct vmcb, save.tr), | |
4985 | + &env->tr); | |
4986 | + svm_load_seg(addr + offsetof(struct vmcb, save.ldtr), | |
4987 | + &env->ldt); | |
4962 | 4988 | |
4963 | 4989 | #ifdef TARGET_X86_64 |
4964 | 4990 | env->kernelgsbase = ldq_phys(addr + offsetof(struct vmcb, save.kernel_gs_base)); |
... | ... | @@ -4975,16 +5001,21 @@ void helper_vmload(void) |
4975 | 5001 | void helper_vmsave(void) |
4976 | 5002 | { |
4977 | 5003 | target_ulong addr; |
5004 | + helper_svm_check_intercept_param(SVM_EXIT_VMSAVE, 0); | |
4978 | 5005 | addr = EAX; |
4979 | 5006 | if (loglevel & CPU_LOG_TB_IN_ASM) |
4980 | 5007 | fprintf(logfile,"vmsave! " TARGET_FMT_lx "\nFS: %016" PRIx64 " | " TARGET_FMT_lx "\n", |
4981 | 5008 | addr, ldq_phys(addr + offsetof(struct vmcb, save.fs.base)), |
4982 | 5009 | env->segs[R_FS].base); |
4983 | 5010 | |
4984 | - SVM_SAVE_SEG(addr, segs[R_FS], fs); | |
4985 | - SVM_SAVE_SEG(addr, segs[R_GS], gs); | |
4986 | - SVM_SAVE_SEG(addr, tr, tr); | |
4987 | - SVM_SAVE_SEG(addr, ldt, ldtr); | |
5011 | + svm_save_seg(addr + offsetof(struct vmcb, save.fs), | |
5012 | + &env->segs[R_FS]); | |
5013 | + svm_save_seg(addr + offsetof(struct vmcb, save.gs), | |
5014 | + &env->segs[R_GS]); | |
5015 | + svm_save_seg(addr + offsetof(struct vmcb, save.tr), | |
5016 | + &env->tr); | |
5017 | + svm_save_seg(addr + offsetof(struct vmcb, save.ldtr), | |
5018 | + &env->ldt); | |
4988 | 5019 | |
4989 | 5020 | #ifdef TARGET_X86_64 |
4990 | 5021 | stq_phys(addr + offsetof(struct vmcb, save.kernel_gs_base), env->kernelgsbase); |
... | ... | @@ -4998,50 +5029,65 @@ void helper_vmsave(void) |
4998 | 5029 | stq_phys(addr + offsetof(struct vmcb, save.sysenter_eip), env->sysenter_eip); |
4999 | 5030 | } |
5000 | 5031 | |
5032 | +void helper_stgi(void) | |
5033 | +{ | |
5034 | + helper_svm_check_intercept_param(SVM_EXIT_STGI, 0); | |
5035 | + env->hflags |= HF_GIF_MASK; | |
5036 | +} | |
5037 | + | |
5038 | +void helper_clgi(void) | |
5039 | +{ | |
5040 | + helper_svm_check_intercept_param(SVM_EXIT_CLGI, 0); | |
5041 | + env->hflags &= ~HF_GIF_MASK; | |
5042 | +} | |
5043 | + | |
5001 | 5044 | void helper_skinit(void) |
5002 | 5045 | { |
5046 | + helper_svm_check_intercept_param(SVM_EXIT_SKINIT, 0); | |
5047 | + /* XXX: not implemented */ | |
5003 | 5048 | if (loglevel & CPU_LOG_TB_IN_ASM) |
5004 | 5049 | fprintf(logfile,"skinit!\n"); |
5050 | + raise_exception(EXCP06_ILLOP); | |
5005 | 5051 | } |
5006 | 5052 | |
5007 | 5053 | void helper_invlpga(void) |
5008 | 5054 | { |
5055 | + helper_svm_check_intercept_param(SVM_EXIT_INVLPGA, 0); | |
5009 | 5056 | tlb_flush(env, 0); |
5010 | 5057 | } |
5011 | 5058 | |
5012 | 5059 | void helper_svm_check_intercept_param(uint32_t type, uint64_t param) |
5013 | 5060 | { |
5061 | + if (likely(!(env->hflags & HF_SVMI_MASK))) | |
5062 | + return; | |
5014 | 5063 | switch(type) { |
5015 | 5064 | case SVM_EXIT_READ_CR0 ... SVM_EXIT_READ_CR0 + 8: |
5016 | - if (INTERCEPTEDw(_cr_read, (1 << (type - SVM_EXIT_READ_CR0)))) { | |
5065 | + if (env->intercept_cr_read & (1 << (type - SVM_EXIT_READ_CR0))) { | |
5017 | 5066 | helper_vmexit(type, param); |
5018 | 5067 | } |
5019 | 5068 | break; |
5020 | - case SVM_EXIT_READ_DR0 ... SVM_EXIT_READ_DR0 + 8: | |
5021 | - if (INTERCEPTEDw(_dr_read, (1 << (type - SVM_EXIT_READ_DR0)))) { | |
5069 | + case SVM_EXIT_WRITE_CR0 ... SVM_EXIT_WRITE_CR0 + 8: | |
5070 | + if (env->intercept_cr_write & (1 << (type - SVM_EXIT_WRITE_CR0))) { | |
5022 | 5071 | helper_vmexit(type, param); |
5023 | 5072 | } |
5024 | 5073 | break; |
5025 | - case SVM_EXIT_WRITE_CR0 ... SVM_EXIT_WRITE_CR0 + 8: | |
5026 | - if (INTERCEPTEDw(_cr_write, (1 << (type - SVM_EXIT_WRITE_CR0)))) { | |
5074 | + case SVM_EXIT_READ_DR0 ... SVM_EXIT_READ_DR0 + 7: | |
5075 | + if (env->intercept_dr_read & (1 << (type - SVM_EXIT_READ_DR0))) { | |
5027 | 5076 | helper_vmexit(type, param); |
5028 | 5077 | } |
5029 | 5078 | break; |
5030 | - case SVM_EXIT_WRITE_DR0 ... SVM_EXIT_WRITE_DR0 + 8: | |
5031 | - if (INTERCEPTEDw(_dr_write, (1 << (type - SVM_EXIT_WRITE_DR0)))) { | |
5079 | + case SVM_EXIT_WRITE_DR0 ... SVM_EXIT_WRITE_DR0 + 7: | |
5080 | + if (env->intercept_dr_write & (1 << (type - SVM_EXIT_WRITE_DR0))) { | |
5032 | 5081 | helper_vmexit(type, param); |
5033 | 5082 | } |
5034 | 5083 | break; |
5035 | - case SVM_EXIT_EXCP_BASE ... SVM_EXIT_EXCP_BASE + 16: | |
5036 | - if (INTERCEPTEDl(_exceptions, (1 << (type - SVM_EXIT_EXCP_BASE)))) { | |
5084 | + case SVM_EXIT_EXCP_BASE ... SVM_EXIT_EXCP_BASE + 31: | |
5085 | + if (env->intercept_exceptions & (1 << (type - SVM_EXIT_EXCP_BASE))) { | |
5037 | 5086 | helper_vmexit(type, param); |
5038 | 5087 | } |
5039 | 5088 | break; |
5040 | - case SVM_EXIT_IOIO: | |
5041 | - break; | |
5042 | - | |
5043 | 5089 | case SVM_EXIT_MSR: |
5044 | - if (INTERCEPTED(1ULL << INTERCEPT_MSR_PROT)) { | |
5090 | + if (env->intercept & (1ULL << (SVM_EXIT_MSR - SVM_EXIT_INTR))) { | |
5045 | 5091 | /* FIXME: this should be read in at vmrun (faster this way?) */ |
5046 | 5092 | uint64_t addr = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.msrpm_base_pa)); |
5047 | 5093 | uint32_t t0, t1; |
... | ... | @@ -5071,7 +5117,7 @@ void helper_svm_check_intercept_param(uint32_t type, uint64_t param) |
5071 | 5117 | } |
5072 | 5118 | break; |
5073 | 5119 | default: |
5074 | - if (INTERCEPTED((1ULL << ((type - SVM_EXIT_INTR) + INTERCEPT_INTR)))) { | |
5120 | + if (env->intercept & (1ULL << (type - SVM_EXIT_INTR))) { | |
5075 | 5121 | helper_vmexit(type, param); |
5076 | 5122 | } |
5077 | 5123 | break; |
... | ... | @@ -5081,7 +5127,7 @@ void helper_svm_check_intercept_param(uint32_t type, uint64_t param) |
5081 | 5127 | void helper_svm_check_io(uint32_t port, uint32_t param, |
5082 | 5128 | uint32_t next_eip_addend) |
5083 | 5129 | { |
5084 | - if (INTERCEPTED(1ULL << INTERCEPT_IOIO_PROT)) { | |
5130 | + if (env->intercept & (1ULL << (SVM_EXIT_IOIO - SVM_EXIT_INTR))) { | |
5085 | 5131 | /* FIXME: this should be read in at vmrun (faster this way?) */ |
5086 | 5132 | uint64_t addr = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.iopm_base_pa)); |
5087 | 5133 | uint16_t mask = (1 << ((param >> 4) & 7)) - 1; |
... | ... | @@ -5113,10 +5159,14 @@ void helper_vmexit(uint32_t exit_code, uint64_t exit_info_1) |
5113 | 5159 | } |
5114 | 5160 | |
5115 | 5161 | /* Save the VM state in the vmcb */ |
5116 | - SVM_SAVE_SEG(env->vm_vmcb, segs[R_ES], es); | |
5117 | - SVM_SAVE_SEG(env->vm_vmcb, segs[R_CS], cs); | |
5118 | - SVM_SAVE_SEG(env->vm_vmcb, segs[R_SS], ss); | |
5119 | - SVM_SAVE_SEG(env->vm_vmcb, segs[R_DS], ds); | |
5162 | + svm_save_seg(env->vm_vmcb + offsetof(struct vmcb, save.es), | |
5163 | + &env->segs[R_ES]); | |
5164 | + svm_save_seg(env->vm_vmcb + offsetof(struct vmcb, save.cs), | |
5165 | + &env->segs[R_CS]); | |
5166 | + svm_save_seg(env->vm_vmcb + offsetof(struct vmcb, save.ss), | |
5167 | + &env->segs[R_SS]); | |
5168 | + svm_save_seg(env->vm_vmcb + offsetof(struct vmcb, save.ds), | |
5169 | + &env->segs[R_DS]); | |
5120 | 5170 | |
5121 | 5171 | stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.base), env->gdt.base); |
5122 | 5172 | stl_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.limit), env->gdt.limit); |
... | ... | @@ -5146,6 +5196,7 @@ void helper_vmexit(uint32_t exit_code, uint64_t exit_info_1) |
5146 | 5196 | |
5147 | 5197 | /* Reload the host state from vm_hsave */ |
5148 | 5198 | env->hflags &= ~HF_HIF_MASK; |
5199 | + env->hflags &= ~HF_SVMI_MASK; | |
5149 | 5200 | env->intercept = 0; |
5150 | 5201 | env->intercept_exceptions = 0; |
5151 | 5202 | env->interrupt_request &= ~CPU_INTERRUPT_VIRQ; |
... | ... | @@ -5169,6 +5220,14 @@ void helper_vmexit(uint32_t exit_code, uint64_t exit_info_1) |
5169 | 5220 | env->hflags &= ~HF_LMA_MASK; |
5170 | 5221 | if (env->efer & MSR_EFER_LMA) |
5171 | 5222 | env->hflags |= HF_LMA_MASK; |
5223 | + /* XXX: should also emulate the VM_CR MSR */ | |
5224 | + env->hflags &= ~HF_SVME_MASK; | |
5225 | + if (env->cpuid_ext3_features & CPUID_EXT3_SVM) { | |
5226 | + if (env->efer & MSR_EFER_SVME) | |
5227 | + env->hflags |= HF_SVME_MASK; | |
5228 | + } else { | |
5229 | + env->efer &= ~MSR_EFER_SVME; | |
5230 | + } | |
5172 | 5231 | #endif |
5173 | 5232 | |
5174 | 5233 | env->eflags = 0; |
... | ... | @@ -5176,10 +5235,14 @@ void helper_vmexit(uint32_t exit_code, uint64_t exit_info_1) |
5176 | 5235 | ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK)); |
5177 | 5236 | CC_OP = CC_OP_EFLAGS; |
5178 | 5237 | |
5179 | - SVM_LOAD_SEG(env->vm_hsave, ES, es); | |
5180 | - SVM_LOAD_SEG(env->vm_hsave, CS, cs); | |
5181 | - SVM_LOAD_SEG(env->vm_hsave, SS, ss); | |
5182 | - SVM_LOAD_SEG(env->vm_hsave, DS, ds); | |
5238 | + svm_load_seg_cache(env->vm_hsave + offsetof(struct vmcb, save.es), | |
5239 | + env, R_ES); | |
5240 | + svm_load_seg_cache(env->vm_hsave + offsetof(struct vmcb, save.cs), | |
5241 | + env, R_CS); | |
5242 | + svm_load_seg_cache(env->vm_hsave + offsetof(struct vmcb, save.ss), | |
5243 | + env, R_SS); | |
5244 | + svm_load_seg_cache(env->vm_hsave + offsetof(struct vmcb, save.ds), | |
5245 | + env, R_DS); | |
5183 | 5246 | |
5184 | 5247 | EIP = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.rip)); |
5185 | 5248 | ESP = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.rsp)); | ... | ... |
target-i386/svm.h
1 | 1 | #ifndef __SVM_H |
2 | 2 | #define __SVM_H |
3 | 3 | |
4 | -enum { | |
5 | - /* We shift all the intercept bits so we can OR them with the | |
6 | - TB flags later on */ | |
7 | - INTERCEPT_INTR = HF_HIF_SHIFT, | |
8 | - INTERCEPT_NMI, | |
9 | - INTERCEPT_SMI, | |
10 | - INTERCEPT_INIT, | |
11 | - INTERCEPT_VINTR, | |
12 | - INTERCEPT_SELECTIVE_CR0, | |
13 | - INTERCEPT_STORE_IDTR, | |
14 | - INTERCEPT_STORE_GDTR, | |
15 | - INTERCEPT_STORE_LDTR, | |
16 | - INTERCEPT_STORE_TR, | |
17 | - INTERCEPT_LOAD_IDTR, | |
18 | - INTERCEPT_LOAD_GDTR, | |
19 | - INTERCEPT_LOAD_LDTR, | |
20 | - INTERCEPT_LOAD_TR, | |
21 | - INTERCEPT_RDTSC, | |
22 | - INTERCEPT_RDPMC, | |
23 | - INTERCEPT_PUSHF, | |
24 | - INTERCEPT_POPF, | |
25 | - INTERCEPT_CPUID, | |
26 | - INTERCEPT_RSM, | |
27 | - INTERCEPT_IRET, | |
28 | - INTERCEPT_INTn, | |
29 | - INTERCEPT_INVD, | |
30 | - INTERCEPT_PAUSE, | |
31 | - INTERCEPT_HLT, | |
32 | - INTERCEPT_INVLPG, | |
33 | - INTERCEPT_INVLPGA, | |
34 | - INTERCEPT_IOIO_PROT, | |
35 | - INTERCEPT_MSR_PROT, | |
36 | - INTERCEPT_TASK_SWITCH, | |
37 | - INTERCEPT_FERR_FREEZE, | |
38 | - INTERCEPT_SHUTDOWN, | |
39 | - INTERCEPT_VMRUN, | |
40 | - INTERCEPT_VMMCALL, | |
41 | - INTERCEPT_VMLOAD, | |
42 | - INTERCEPT_VMSAVE, | |
43 | - INTERCEPT_STGI, | |
44 | - INTERCEPT_CLGI, | |
45 | - INTERCEPT_SKINIT, | |
46 | - INTERCEPT_RDTSCP, | |
47 | - INTERCEPT_ICEBP, | |
48 | - INTERCEPT_WBINVD, | |
49 | -}; | |
50 | -/* This is not really an intercept but rather a placeholder to | |
51 | - show that we are in an SVM (just like a hidden flag, but keeps the | |
52 | - TBs clean) */ | |
53 | -#define INTERCEPT_SVM 63 | |
54 | -#define INTERCEPT_SVM_MASK (1ULL << INTERCEPT_SVM) | |
55 | - | |
56 | -struct __attribute__ ((__packed__)) vmcb_control_area { | |
57 | - uint16_t intercept_cr_read; | |
58 | - uint16_t intercept_cr_write; | |
59 | - uint16_t intercept_dr_read; | |
60 | - uint16_t intercept_dr_write; | |
61 | - uint32_t intercept_exceptions; | |
62 | - uint64_t intercept; | |
63 | - uint8_t reserved_1[44]; | |
64 | - uint64_t iopm_base_pa; | |
65 | - uint64_t msrpm_base_pa; | |
66 | - uint64_t tsc_offset; | |
67 | - uint32_t asid; | |
68 | - uint8_t tlb_ctl; | |
69 | - uint8_t reserved_2[3]; | |
70 | - uint32_t int_ctl; | |
71 | - uint32_t int_vector; | |
72 | - uint32_t int_state; | |
73 | - uint8_t reserved_3[4]; | |
74 | - uint64_t exit_code; | |
75 | - uint64_t exit_info_1; | |
76 | - uint64_t exit_info_2; | |
77 | - uint32_t exit_int_info; | |
78 | - uint32_t exit_int_info_err; | |
79 | - uint64_t nested_ctl; | |
80 | - uint8_t reserved_4[16]; | |
81 | - uint32_t event_inj; | |
82 | - uint32_t event_inj_err; | |
83 | - uint64_t nested_cr3; | |
84 | - uint64_t lbr_ctl; | |
85 | - uint8_t reserved_5[832]; | |
86 | -}; | |
87 | - | |
88 | - | |
89 | 4 | #define TLB_CONTROL_DO_NOTHING 0 |
90 | 5 | #define TLB_CONTROL_FLUSH_ALL_ASID 1 |
91 | 6 | |
... | ... | @@ -116,104 +31,6 @@ struct __attribute__ ((__packed__)) vmcb_control_area { |
116 | 31 | #define SVM_IOIO_SIZE_MASK (7 << SVM_IOIO_SIZE_SHIFT) |
117 | 32 | #define SVM_IOIO_ASIZE_MASK (7 << SVM_IOIO_ASIZE_SHIFT) |
118 | 33 | |
119 | -struct __attribute__ ((__packed__)) vmcb_seg { | |
120 | - uint16_t selector; | |
121 | - uint16_t attrib; | |
122 | - uint32_t limit; | |
123 | - uint64_t base; | |
124 | -}; | |
125 | - | |
126 | -struct __attribute__ ((__packed__)) vmcb_save_area { | |
127 | - struct vmcb_seg es; | |
128 | - struct vmcb_seg cs; | |
129 | - struct vmcb_seg ss; | |
130 | - struct vmcb_seg ds; | |
131 | - struct vmcb_seg fs; | |
132 | - struct vmcb_seg gs; | |
133 | - struct vmcb_seg gdtr; | |
134 | - struct vmcb_seg ldtr; | |
135 | - struct vmcb_seg idtr; | |
136 | - struct vmcb_seg tr; | |
137 | - uint8_t reserved_1[43]; | |
138 | - uint8_t cpl; | |
139 | - uint8_t reserved_2[4]; | |
140 | - uint64_t efer; | |
141 | - uint8_t reserved_3[112]; | |
142 | - uint64_t cr4; | |
143 | - uint64_t cr3; | |
144 | - uint64_t cr0; | |
145 | - uint64_t dr7; | |
146 | - uint64_t dr6; | |
147 | - uint64_t rflags; | |
148 | - uint64_t rip; | |
149 | - uint8_t reserved_4[88]; | |
150 | - uint64_t rsp; | |
151 | - uint8_t reserved_5[24]; | |
152 | - uint64_t rax; | |
153 | - uint64_t star; | |
154 | - uint64_t lstar; | |
155 | - uint64_t cstar; | |
156 | - uint64_t sfmask; | |
157 | - uint64_t kernel_gs_base; | |
158 | - uint64_t sysenter_cs; | |
159 | - uint64_t sysenter_esp; | |
160 | - uint64_t sysenter_eip; | |
161 | - uint64_t cr2; | |
162 | - /* qemu: cr8 added to reuse this as hsave */ | |
163 | - uint64_t cr8; | |
164 | - uint8_t reserved_6[32 - 8]; /* originally 32 */ | |
165 | - uint64_t g_pat; | |
166 | - uint64_t dbgctl; | |
167 | - uint64_t br_from; | |
168 | - uint64_t br_to; | |
169 | - uint64_t last_excp_from; | |
170 | - uint64_t last_excp_to; | |
171 | -}; | |
172 | - | |
173 | -struct __attribute__ ((__packed__)) vmcb { | |
174 | - struct vmcb_control_area control; | |
175 | - struct vmcb_save_area save; | |
176 | -}; | |
177 | - | |
178 | -#define SVM_CPUID_FEATURE_SHIFT 2 | |
179 | -#define SVM_CPUID_FUNC 0x8000000a | |
180 | - | |
181 | -#define MSR_EFER_SVME_MASK (1ULL << 12) | |
182 | - | |
183 | -#define SVM_SELECTOR_S_SHIFT 4 | |
184 | -#define SVM_SELECTOR_DPL_SHIFT 5 | |
185 | -#define SVM_SELECTOR_P_SHIFT 7 | |
186 | -#define SVM_SELECTOR_AVL_SHIFT 8 | |
187 | -#define SVM_SELECTOR_L_SHIFT 9 | |
188 | -#define SVM_SELECTOR_DB_SHIFT 10 | |
189 | -#define SVM_SELECTOR_G_SHIFT 11 | |
190 | - | |
191 | -#define SVM_SELECTOR_TYPE_MASK (0xf) | |
192 | -#define SVM_SELECTOR_S_MASK (1 << SVM_SELECTOR_S_SHIFT) | |
193 | -#define SVM_SELECTOR_DPL_MASK (3 << SVM_SELECTOR_DPL_SHIFT) | |
194 | -#define SVM_SELECTOR_P_MASK (1 << SVM_SELECTOR_P_SHIFT) | |
195 | -#define SVM_SELECTOR_AVL_MASK (1 << SVM_SELECTOR_AVL_SHIFT) | |
196 | -#define SVM_SELECTOR_L_MASK (1 << SVM_SELECTOR_L_SHIFT) | |
197 | -#define SVM_SELECTOR_DB_MASK (1 << SVM_SELECTOR_DB_SHIFT) | |
198 | -#define SVM_SELECTOR_G_MASK (1 << SVM_SELECTOR_G_SHIFT) | |
199 | - | |
200 | -#define SVM_SELECTOR_WRITE_MASK (1 << 1) | |
201 | -#define SVM_SELECTOR_READ_MASK SVM_SELECTOR_WRITE_MASK | |
202 | -#define SVM_SELECTOR_CODE_MASK (1 << 3) | |
203 | - | |
204 | -#define INTERCEPT_CR0_MASK 1 | |
205 | -#define INTERCEPT_CR3_MASK (1 << 3) | |
206 | -#define INTERCEPT_CR4_MASK (1 << 4) | |
207 | - | |
208 | -#define INTERCEPT_DR0_MASK 1 | |
209 | -#define INTERCEPT_DR1_MASK (1 << 1) | |
210 | -#define INTERCEPT_DR2_MASK (1 << 2) | |
211 | -#define INTERCEPT_DR3_MASK (1 << 3) | |
212 | -#define INTERCEPT_DR4_MASK (1 << 4) | |
213 | -#define INTERCEPT_DR5_MASK (1 << 5) | |
214 | -#define INTERCEPT_DR6_MASK (1 << 6) | |
215 | -#define INTERCEPT_DR7_MASK (1 << 7) | |
216 | - | |
217 | 34 | #define SVM_EVTINJ_VEC_MASK 0xff |
218 | 35 | |
219 | 36 | #define SVM_EVTINJ_TYPE_SHIFT 8 |
... | ... | @@ -313,37 +130,95 @@ struct __attribute__ ((__packed__)) vmcb { |
313 | 130 | |
314 | 131 | #define SVM_CR0_SELECTIVE_MASK (1 << 3 | 1) /* TS and MP */ |
315 | 132 | |
316 | -#define SVM_VMLOAD ".byte 0x0f, 0x01, 0xda" | |
317 | -#define SVM_VMRUN ".byte 0x0f, 0x01, 0xd8" | |
318 | -#define SVM_VMSAVE ".byte 0x0f, 0x01, 0xdb" | |
319 | -#define SVM_CLGI ".byte 0x0f, 0x01, 0xdd" | |
320 | -#define SVM_STGI ".byte 0x0f, 0x01, 0xdc" | |
321 | -#define SVM_INVLPGA ".byte 0x0f, 0x01, 0xdf" | |
322 | - | |
323 | -/* function references */ | |
324 | - | |
325 | -#define INTERCEPTED(mask) (env->intercept & mask) | |
326 | -#define INTERCEPTEDw(var, mask) (env->intercept ## var & mask) | |
327 | -#define INTERCEPTEDl(var, mask) (env->intercept ## var & mask) | |
133 | +struct __attribute__ ((__packed__)) vmcb_control_area { | |
134 | + uint16_t intercept_cr_read; | |
135 | + uint16_t intercept_cr_write; | |
136 | + uint16_t intercept_dr_read; | |
137 | + uint16_t intercept_dr_write; | |
138 | + uint32_t intercept_exceptions; | |
139 | + uint64_t intercept; | |
140 | + uint8_t reserved_1[44]; | |
141 | + uint64_t iopm_base_pa; | |
142 | + uint64_t msrpm_base_pa; | |
143 | + uint64_t tsc_offset; | |
144 | + uint32_t asid; | |
145 | + uint8_t tlb_ctl; | |
146 | + uint8_t reserved_2[3]; | |
147 | + uint32_t int_ctl; | |
148 | + uint32_t int_vector; | |
149 | + uint32_t int_state; | |
150 | + uint8_t reserved_3[4]; | |
151 | + uint64_t exit_code; | |
152 | + uint64_t exit_info_1; | |
153 | + uint64_t exit_info_2; | |
154 | + uint32_t exit_int_info; | |
155 | + uint32_t exit_int_info_err; | |
156 | + uint64_t nested_ctl; | |
157 | + uint8_t reserved_4[16]; | |
158 | + uint32_t event_inj; | |
159 | + uint32_t event_inj_err; | |
160 | + uint64_t nested_cr3; | |
161 | + uint64_t lbr_ctl; | |
162 | + uint8_t reserved_5[832]; | |
163 | +}; | |
328 | 164 | |
329 | -#define SVM_LOAD_SEG(addr, seg_index, seg) \ | |
330 | - cpu_x86_load_seg_cache(env, \ | |
331 | - R_##seg_index, \ | |
332 | - lduw_phys(addr + offsetof(struct vmcb, save.seg.selector)),\ | |
333 | - ldq_phys(addr + offsetof(struct vmcb, save.seg.base)),\ | |
334 | - ldl_phys(addr + offsetof(struct vmcb, save.seg.limit)),\ | |
335 | - vmcb2cpu_attrib(lduw_phys(addr + offsetof(struct vmcb, save.seg.attrib)), ldq_phys(addr + offsetof(struct vmcb, save.seg.base)), ldl_phys(addr + offsetof(struct vmcb, save.seg.limit)))) | |
165 | +struct __attribute__ ((__packed__)) vmcb_seg { | |
166 | + uint16_t selector; | |
167 | + uint16_t attrib; | |
168 | + uint32_t limit; | |
169 | + uint64_t base; | |
170 | +}; | |
336 | 171 | |
337 | -#define SVM_LOAD_SEG2(addr, seg_qemu, seg_vmcb) \ | |
338 | - env->seg_qemu.selector = lduw_phys(addr + offsetof(struct vmcb, save.seg_vmcb.selector)); \ | |
339 | - env->seg_qemu.base = ldq_phys(addr + offsetof(struct vmcb, save.seg_vmcb.base)); \ | |
340 | - env->seg_qemu.limit = ldl_phys(addr + offsetof(struct vmcb, save.seg_vmcb.limit)); \ | |
341 | - env->seg_qemu.flags = vmcb2cpu_attrib(lduw_phys(addr + offsetof(struct vmcb, save.seg_vmcb.attrib)), env->seg_qemu.base, env->seg_qemu.limit) | |
172 | +struct __attribute__ ((__packed__)) vmcb_save_area { | |
173 | + struct vmcb_seg es; | |
174 | + struct vmcb_seg cs; | |
175 | + struct vmcb_seg ss; | |
176 | + struct vmcb_seg ds; | |
177 | + struct vmcb_seg fs; | |
178 | + struct vmcb_seg gs; | |
179 | + struct vmcb_seg gdtr; | |
180 | + struct vmcb_seg ldtr; | |
181 | + struct vmcb_seg idtr; | |
182 | + struct vmcb_seg tr; | |
183 | + uint8_t reserved_1[43]; | |
184 | + uint8_t cpl; | |
185 | + uint8_t reserved_2[4]; | |
186 | + uint64_t efer; | |
187 | + uint8_t reserved_3[112]; | |
188 | + uint64_t cr4; | |
189 | + uint64_t cr3; | |
190 | + uint64_t cr0; | |
191 | + uint64_t dr7; | |
192 | + uint64_t dr6; | |
193 | + uint64_t rflags; | |
194 | + uint64_t rip; | |
195 | + uint8_t reserved_4[88]; | |
196 | + uint64_t rsp; | |
197 | + uint8_t reserved_5[24]; | |
198 | + uint64_t rax; | |
199 | + uint64_t star; | |
200 | + uint64_t lstar; | |
201 | + uint64_t cstar; | |
202 | + uint64_t sfmask; | |
203 | + uint64_t kernel_gs_base; | |
204 | + uint64_t sysenter_cs; | |
205 | + uint64_t sysenter_esp; | |
206 | + uint64_t sysenter_eip; | |
207 | + uint64_t cr2; | |
208 | + /* qemu: cr8 added to reuse this as hsave */ | |
209 | + uint64_t cr8; | |
210 | + uint8_t reserved_6[32 - 8]; /* originally 32 */ | |
211 | + uint64_t g_pat; | |
212 | + uint64_t dbgctl; | |
213 | + uint64_t br_from; | |
214 | + uint64_t br_to; | |
215 | + uint64_t last_excp_from; | |
216 | + uint64_t last_excp_to; | |
217 | +}; | |
342 | 218 | |
343 | -#define SVM_SAVE_SEG(addr, seg_qemu, seg_vmcb) \ | |
344 | - stw_phys(addr + offsetof(struct vmcb, save.seg_vmcb.selector), env->seg_qemu.selector); \ | |
345 | - stq_phys(addr + offsetof(struct vmcb, save.seg_vmcb.base), env->seg_qemu.base); \ | |
346 | - stl_phys(addr + offsetof(struct vmcb, save.seg_vmcb.limit), env->seg_qemu.limit); \ | |
347 | - stw_phys(addr + offsetof(struct vmcb, save.seg_vmcb.attrib), cpu2vmcb_attrib(env->seg_qemu.flags)) | |
219 | +struct __attribute__ ((__packed__)) vmcb { | |
220 | + struct vmcb_control_area control; | |
221 | + struct vmcb_save_area save; | |
222 | +}; | |
348 | 223 | |
349 | 224 | #endif | ... | ... |
target-i386/translate.c
... | ... | @@ -733,7 +733,7 @@ static void gen_check_io(DisasContext *s, int ot, target_ulong cur_eip, |
733 | 733 | tcg_gen_helper_0_1(gen_check_io_func[ot], |
734 | 734 | cpu_tmp2_i32); |
735 | 735 | } |
736 | - if(s->flags & (1ULL << INTERCEPT_IOIO_PROT)) { | |
736 | + if(s->flags & HF_SVMI_MASK) { | |
737 | 737 | if (!state_saved) { |
738 | 738 | if (s->cc_op != CC_OP_DYNAMIC) |
739 | 739 | gen_op_set_cc_op(s->cc_op); |
... | ... | @@ -2322,59 +2322,24 @@ static inline int svm_is_rep(int prefixes) |
2322 | 2322 | return ((prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) ? 8 : 0); |
2323 | 2323 | } |
2324 | 2324 | |
2325 | -static inline int | |
2325 | +static inline void | |
2326 | 2326 | gen_svm_check_intercept_param(DisasContext *s, target_ulong pc_start, |
2327 | 2327 | uint32_t type, uint64_t param) |
2328 | 2328 | { |
2329 | - if(!(s->flags & (INTERCEPT_SVM_MASK))) | |
2330 | - /* no SVM activated */ | |
2331 | - return 0; | |
2332 | - switch(type) { | |
2333 | - /* CRx and DRx reads/writes */ | |
2334 | - case SVM_EXIT_READ_CR0 ... SVM_EXIT_EXCP_BASE - 1: | |
2335 | - if (s->cc_op != CC_OP_DYNAMIC) { | |
2336 | - gen_op_set_cc_op(s->cc_op); | |
2337 | - } | |
2338 | - gen_jmp_im(pc_start - s->cs_base); | |
2339 | - tcg_gen_helper_0_2(helper_svm_check_intercept_param, | |
2340 | - tcg_const_i32(type), tcg_const_i64(param)); | |
2341 | - /* this is a special case as we do not know if the interception occurs | |
2342 | - so we assume there was none */ | |
2343 | - return 0; | |
2344 | - case SVM_EXIT_MSR: | |
2345 | - if(s->flags & (1ULL << INTERCEPT_MSR_PROT)) { | |
2346 | - if (s->cc_op != CC_OP_DYNAMIC) { | |
2347 | - gen_op_set_cc_op(s->cc_op); | |
2348 | - } | |
2349 | - gen_jmp_im(pc_start - s->cs_base); | |
2350 | - tcg_gen_helper_0_2(helper_svm_check_intercept_param, | |
2351 | - tcg_const_i32(type), tcg_const_i64(param)); | |
2352 | - /* this is a special case as we do not know if the interception occurs | |
2353 | - so we assume there was none */ | |
2354 | - return 0; | |
2355 | - } | |
2356 | - break; | |
2357 | - default: | |
2358 | - if(s->flags & (1ULL << ((type - SVM_EXIT_INTR) + INTERCEPT_INTR))) { | |
2359 | - if (s->cc_op != CC_OP_DYNAMIC) { | |
2360 | - gen_op_set_cc_op(s->cc_op); | |
2361 | - } | |
2362 | - gen_jmp_im(pc_start - s->cs_base); | |
2363 | - tcg_gen_helper_0_2(helper_vmexit, | |
2364 | - tcg_const_i32(type), tcg_const_i64(param)); | |
2365 | - /* we can optimize this one so TBs don't get longer | |
2366 | - than up to vmexit */ | |
2367 | - gen_eob(s); | |
2368 | - return 1; | |
2369 | - } | |
2370 | - } | |
2371 | - return 0; | |
2329 | + /* no SVM activated; fast case */ | |
2330 | + if (likely(!(s->flags & HF_SVMI_MASK))) | |
2331 | + return; | |
2332 | + if (s->cc_op != CC_OP_DYNAMIC) | |
2333 | + gen_op_set_cc_op(s->cc_op); | |
2334 | + gen_jmp_im(pc_start - s->cs_base); | |
2335 | + tcg_gen_helper_0_2(helper_svm_check_intercept_param, | |
2336 | + tcg_const_i32(type), tcg_const_i64(param)); | |
2372 | 2337 | } |
2373 | 2338 | |
2374 | -static inline int | |
2339 | +static inline void | |
2375 | 2340 | gen_svm_check_intercept(DisasContext *s, target_ulong pc_start, uint64_t type) |
2376 | 2341 | { |
2377 | - return gen_svm_check_intercept_param(s, pc_start, type, 0); | |
2342 | + gen_svm_check_intercept_param(s, pc_start, type, 0); | |
2378 | 2343 | } |
2379 | 2344 | |
2380 | 2345 | static inline void gen_stack_update(DisasContext *s, int addend) |
... | ... | @@ -5743,8 +5708,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) |
5743 | 5708 | val = 0; |
5744 | 5709 | goto do_lret; |
5745 | 5710 | case 0xcf: /* iret */ |
5746 | - if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_IRET)) | |
5747 | - break; | |
5711 | + gen_svm_check_intercept(s, pc_start, SVM_EXIT_IRET); | |
5748 | 5712 | if (!s->pe) { |
5749 | 5713 | /* real mode */ |
5750 | 5714 | tcg_gen_helper_0_1(helper_iret_real, tcg_const_i32(s->dflag)); |
... | ... | @@ -5890,8 +5854,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) |
5890 | 5854 | /************************/ |
5891 | 5855 | /* flags */ |
5892 | 5856 | case 0x9c: /* pushf */ |
5893 | - if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_PUSHF)) | |
5894 | - break; | |
5857 | + gen_svm_check_intercept(s, pc_start, SVM_EXIT_PUSHF); | |
5895 | 5858 | if (s->vm86 && s->iopl != 3) { |
5896 | 5859 | gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); |
5897 | 5860 | } else { |
... | ... | @@ -5902,8 +5865,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) |
5902 | 5865 | } |
5903 | 5866 | break; |
5904 | 5867 | case 0x9d: /* popf */ |
5905 | - if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_POPF)) | |
5906 | - break; | |
5868 | + gen_svm_check_intercept(s, pc_start, SVM_EXIT_POPF); | |
5907 | 5869 | if (s->vm86 && s->iopl != 3) { |
5908 | 5870 | gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); |
5909 | 5871 | } else { |
... | ... | @@ -6187,14 +6149,10 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) |
6187 | 6149 | } |
6188 | 6150 | break; |
6189 | 6151 | case 0xcc: /* int3 */ |
6190 | - if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_SWINT)) | |
6191 | - break; | |
6192 | 6152 | gen_interrupt(s, EXCP03_INT3, pc_start - s->cs_base, s->pc - s->cs_base); |
6193 | 6153 | break; |
6194 | 6154 | case 0xcd: /* int N */ |
6195 | 6155 | val = ldub_code(s->pc++); |
6196 | - if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_SWINT)) | |
6197 | - break; | |
6198 | 6156 | if (s->vm86 && s->iopl != 3) { |
6199 | 6157 | gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); |
6200 | 6158 | } else { |
... | ... | @@ -6204,16 +6162,13 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) |
6204 | 6162 | case 0xce: /* into */ |
6205 | 6163 | if (CODE64(s)) |
6206 | 6164 | goto illegal_op; |
6207 | - if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_SWINT)) | |
6208 | - break; | |
6209 | 6165 | if (s->cc_op != CC_OP_DYNAMIC) |
6210 | 6166 | gen_op_set_cc_op(s->cc_op); |
6211 | 6167 | gen_jmp_im(pc_start - s->cs_base); |
6212 | 6168 | tcg_gen_helper_0_1(helper_into, tcg_const_i32(s->pc - pc_start)); |
6213 | 6169 | break; |
6214 | 6170 | case 0xf1: /* icebp (undocumented, exits to external debugger) */ |
6215 | - if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_ICEBP)) | |
6216 | - break; | |
6171 | + gen_svm_check_intercept(s, pc_start, SVM_EXIT_ICEBP); | |
6217 | 6172 | #if 1 |
6218 | 6173 | gen_debug(s, pc_start - s->cs_base); |
6219 | 6174 | #else |
... | ... | @@ -6371,25 +6326,25 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) |
6371 | 6326 | if (s->cpl != 0) { |
6372 | 6327 | gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); |
6373 | 6328 | } else { |
6374 | - int retval = 0; | |
6329 | + if (s->cc_op != CC_OP_DYNAMIC) | |
6330 | + gen_op_set_cc_op(s->cc_op); | |
6331 | + gen_jmp_im(pc_start - s->cs_base); | |
6375 | 6332 | if (b & 2) { |
6376 | - retval = gen_svm_check_intercept_param(s, pc_start, SVM_EXIT_MSR, 0); | |
6377 | 6333 | tcg_gen_helper_0_0(helper_rdmsr); |
6378 | 6334 | } else { |
6379 | - retval = gen_svm_check_intercept_param(s, pc_start, SVM_EXIT_MSR, 1); | |
6380 | 6335 | tcg_gen_helper_0_0(helper_wrmsr); |
6381 | 6336 | } |
6382 | - if(retval) | |
6383 | - gen_eob(s); | |
6384 | 6337 | } |
6385 | 6338 | break; |
6386 | 6339 | case 0x131: /* rdtsc */ |
6387 | - if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_RDTSC)) | |
6388 | - break; | |
6340 | + if (s->cc_op != CC_OP_DYNAMIC) | |
6341 | + gen_op_set_cc_op(s->cc_op); | |
6389 | 6342 | gen_jmp_im(pc_start - s->cs_base); |
6390 | 6343 | tcg_gen_helper_0_0(helper_rdtsc); |
6391 | 6344 | break; |
6392 | 6345 | case 0x133: /* rdpmc */ |
6346 | + if (s->cc_op != CC_OP_DYNAMIC) | |
6347 | + gen_op_set_cc_op(s->cc_op); | |
6393 | 6348 | gen_jmp_im(pc_start - s->cs_base); |
6394 | 6349 | tcg_gen_helper_0_0(helper_rdpmc); |
6395 | 6350 | break; |
... | ... | @@ -6452,16 +6407,12 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) |
6452 | 6407 | break; |
6453 | 6408 | #endif |
6454 | 6409 | case 0x1a2: /* cpuid */ |
6455 | - if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_CPUID)) | |
6456 | - break; | |
6457 | 6410 | tcg_gen_helper_0_0(helper_cpuid); |
6458 | 6411 | break; |
6459 | 6412 | case 0xf4: /* hlt */ |
6460 | 6413 | if (s->cpl != 0) { |
6461 | 6414 | gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); |
6462 | 6415 | } else { |
6463 | - if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_HLT)) | |
6464 | - break; | |
6465 | 6416 | if (s->cc_op != CC_OP_DYNAMIC) |
6466 | 6417 | gen_op_set_cc_op(s->cc_op); |
6467 | 6418 | gen_jmp_im(s->pc - s->cs_base); |
... | ... | @@ -6477,8 +6428,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) |
6477 | 6428 | case 0: /* sldt */ |
6478 | 6429 | if (!s->pe || s->vm86) |
6479 | 6430 | goto illegal_op; |
6480 | - if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_LDTR_READ)) | |
6481 | - break; | |
6431 | + gen_svm_check_intercept(s, pc_start, SVM_EXIT_LDTR_READ); | |
6482 | 6432 | tcg_gen_ld32u_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,ldt.selector)); |
6483 | 6433 | ot = OT_WORD; |
6484 | 6434 | if (mod == 3) |
... | ... | @@ -6491,8 +6441,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) |
6491 | 6441 | if (s->cpl != 0) { |
6492 | 6442 | gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); |
6493 | 6443 | } else { |
6494 | - if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_LDTR_WRITE)) | |
6495 | - break; | |
6444 | + gen_svm_check_intercept(s, pc_start, SVM_EXIT_LDTR_WRITE); | |
6496 | 6445 | gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0); |
6497 | 6446 | gen_jmp_im(pc_start - s->cs_base); |
6498 | 6447 | tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); |
... | ... | @@ -6502,8 +6451,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) |
6502 | 6451 | case 1: /* str */ |
6503 | 6452 | if (!s->pe || s->vm86) |
6504 | 6453 | goto illegal_op; |
6505 | - if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_TR_READ)) | |
6506 | - break; | |
6454 | + gen_svm_check_intercept(s, pc_start, SVM_EXIT_TR_READ); | |
6507 | 6455 | tcg_gen_ld32u_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,tr.selector)); |
6508 | 6456 | ot = OT_WORD; |
6509 | 6457 | if (mod == 3) |
... | ... | @@ -6516,8 +6464,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) |
6516 | 6464 | if (s->cpl != 0) { |
6517 | 6465 | gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); |
6518 | 6466 | } else { |
6519 | - if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_TR_WRITE)) | |
6520 | - break; | |
6467 | + gen_svm_check_intercept(s, pc_start, SVM_EXIT_TR_WRITE); | |
6521 | 6468 | gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0); |
6522 | 6469 | gen_jmp_im(pc_start - s->cs_base); |
6523 | 6470 | tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); |
... | ... | @@ -6550,8 +6497,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) |
6550 | 6497 | case 0: /* sgdt */ |
6551 | 6498 | if (mod == 3) |
6552 | 6499 | goto illegal_op; |
6553 | - if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_GDTR_READ)) | |
6554 | - break; | |
6500 | + gen_svm_check_intercept(s, pc_start, SVM_EXIT_GDTR_READ); | |
6555 | 6501 | gen_lea_modrm(s, modrm, ®_addr, &offset_addr); |
6556 | 6502 | tcg_gen_ld32u_tl(cpu_T[0], cpu_env, offsetof(CPUX86State, gdt.limit)); |
6557 | 6503 | gen_op_st_T0_A0(OT_WORD + s->mem_index); |
... | ... | @@ -6568,8 +6514,6 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) |
6568 | 6514 | if (!(s->cpuid_ext_features & CPUID_EXT_MONITOR) || |
6569 | 6515 | s->cpl != 0) |
6570 | 6516 | goto illegal_op; |
6571 | - if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_MONITOR)) | |
6572 | - break; | |
6573 | 6517 | gen_jmp_im(pc_start - s->cs_base); |
6574 | 6518 | #ifdef TARGET_X86_64 |
6575 | 6519 | if (s->aflag == 2) { |
... | ... | @@ -6592,8 +6536,6 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) |
6592 | 6536 | gen_op_set_cc_op(s->cc_op); |
6593 | 6537 | s->cc_op = CC_OP_DYNAMIC; |
6594 | 6538 | } |
6595 | - if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_MWAIT)) | |
6596 | - break; | |
6597 | 6539 | gen_jmp_im(s->pc - s->cs_base); |
6598 | 6540 | tcg_gen_helper_0_0(helper_mwait); |
6599 | 6541 | gen_eob(s); |
... | ... | @@ -6602,8 +6544,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) |
6602 | 6544 | goto illegal_op; |
6603 | 6545 | } |
6604 | 6546 | } else { /* sidt */ |
6605 | - if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_IDTR_READ)) | |
6606 | - break; | |
6547 | + gen_svm_check_intercept(s, pc_start, SVM_EXIT_IDTR_READ); | |
6607 | 6548 | gen_lea_modrm(s, modrm, ®_addr, &offset_addr); |
6608 | 6549 | tcg_gen_ld32u_tl(cpu_T[0], cpu_env, offsetof(CPUX86State, idt.limit)); |
6609 | 6550 | gen_op_st_T0_A0(OT_WORD + s->mem_index); |
... | ... | @@ -6617,52 +6558,85 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) |
6617 | 6558 | case 2: /* lgdt */ |
6618 | 6559 | case 3: /* lidt */ |
6619 | 6560 | if (mod == 3) { |
6561 | + if (s->cc_op != CC_OP_DYNAMIC) | |
6562 | + gen_op_set_cc_op(s->cc_op); | |
6563 | + gen_jmp_im(pc_start - s->cs_base); | |
6620 | 6564 | switch(rm) { |
6621 | 6565 | case 0: /* VMRUN */ |
6622 | - if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_VMRUN)) | |
6566 | + if (!(s->flags & HF_SVME_MASK) || !s->pe) | |
6567 | + goto illegal_op; | |
6568 | + if (s->cpl != 0) { | |
6569 | + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); | |
6623 | 6570 | break; |
6624 | - if (s->cc_op != CC_OP_DYNAMIC) | |
6625 | - gen_op_set_cc_op(s->cc_op); | |
6626 | - gen_jmp_im(s->pc - s->cs_base); | |
6627 | - tcg_gen_helper_0_0(helper_vmrun); | |
6628 | - s->cc_op = CC_OP_EFLAGS; | |
6629 | - gen_eob(s); | |
6571 | + } else { | |
6572 | + tcg_gen_helper_0_0(helper_vmrun); | |
6573 | + s->cc_op = CC_OP_EFLAGS; | |
6574 | + gen_eob(s); | |
6575 | + } | |
6630 | 6576 | break; |
6631 | 6577 | case 1: /* VMMCALL */ |
6632 | - if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_VMMCALL)) | |
6633 | - break; | |
6634 | - /* FIXME: cause #UD if hflags & SVM */ | |
6578 | + if (!(s->flags & HF_SVME_MASK)) | |
6579 | + goto illegal_op; | |
6635 | 6580 | tcg_gen_helper_0_0(helper_vmmcall); |
6636 | 6581 | break; |
6637 | 6582 | case 2: /* VMLOAD */ |
6638 | - if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_VMLOAD)) | |
6639 | - break; | |
6640 | - tcg_gen_helper_0_0(helper_vmload); | |
6583 | + if (!(s->flags & HF_SVME_MASK) || !s->pe) | |
6584 | + goto illegal_op; | |
6585 | + if (s->cpl != 0) { | |
6586 | + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); | |
6587 | + break; | |
6588 | + } else { | |
6589 | + tcg_gen_helper_0_0(helper_vmload); | |
6590 | + } | |
6641 | 6591 | break; |
6642 | 6592 | case 3: /* VMSAVE */ |
6643 | - if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_VMSAVE)) | |
6644 | - break; | |
6645 | - tcg_gen_helper_0_0(helper_vmsave); | |
6593 | + if (!(s->flags & HF_SVME_MASK) || !s->pe) | |
6594 | + goto illegal_op; | |
6595 | + if (s->cpl != 0) { | |
6596 | + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); | |
6597 | + break; | |
6598 | + } else { | |
6599 | + tcg_gen_helper_0_0(helper_vmsave); | |
6600 | + } | |
6646 | 6601 | break; |
6647 | 6602 | case 4: /* STGI */ |
6648 | - if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_STGI)) | |
6649 | - break; | |
6650 | - tcg_gen_helper_0_0(helper_stgi); | |
6603 | + if ((!(s->flags & HF_SVME_MASK) && | |
6604 | + !(s->cpuid_ext3_features & CPUID_EXT3_SKINIT)) || | |
6605 | + !s->pe) | |
6606 | + goto illegal_op; | |
6607 | + if (s->cpl != 0) { | |
6608 | + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); | |
6609 | + break; | |
6610 | + } else { | |
6611 | + tcg_gen_helper_0_0(helper_stgi); | |
6612 | + } | |
6651 | 6613 | break; |
6652 | 6614 | case 5: /* CLGI */ |
6653 | - if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_CLGI)) | |
6654 | - break; | |
6655 | - tcg_gen_helper_0_0(helper_clgi); | |
6615 | + if (!(s->flags & HF_SVME_MASK) || !s->pe) | |
6616 | + goto illegal_op; | |
6617 | + if (s->cpl != 0) { | |
6618 | + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); | |
6619 | + break; | |
6620 | + } else { | |
6621 | + tcg_gen_helper_0_0(helper_clgi); | |
6622 | + } | |
6656 | 6623 | break; |
6657 | 6624 | case 6: /* SKINIT */ |
6658 | - if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_SKINIT)) | |
6659 | - break; | |
6625 | + if ((!(s->flags & HF_SVME_MASK) && | |
6626 | + !(s->cpuid_ext3_features & CPUID_EXT3_SKINIT)) || | |
6627 | + !s->pe) | |
6628 | + goto illegal_op; | |
6660 | 6629 | tcg_gen_helper_0_0(helper_skinit); |
6661 | 6630 | break; |
6662 | 6631 | case 7: /* INVLPGA */ |
6663 | - if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_INVLPGA)) | |
6664 | - break; | |
6665 | - tcg_gen_helper_0_0(helper_invlpga); | |
6632 | + if (!(s->flags & HF_SVME_MASK) || !s->pe) | |
6633 | + goto illegal_op; | |
6634 | + if (s->cpl != 0) { | |
6635 | + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); | |
6636 | + break; | |
6637 | + } else { | |
6638 | + tcg_gen_helper_0_0(helper_invlpga); | |
6639 | + } | |
6666 | 6640 | break; |
6667 | 6641 | default: |
6668 | 6642 | goto illegal_op; |
... | ... | @@ -6670,9 +6644,8 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) |
6670 | 6644 | } else if (s->cpl != 0) { |
6671 | 6645 | gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); |
6672 | 6646 | } else { |
6673 | - if (gen_svm_check_intercept(s, pc_start, | |
6674 | - op==2 ? SVM_EXIT_GDTR_WRITE : SVM_EXIT_IDTR_WRITE)) | |
6675 | - break; | |
6647 | + gen_svm_check_intercept(s, pc_start, | |
6648 | + op==2 ? SVM_EXIT_GDTR_WRITE : SVM_EXIT_IDTR_WRITE); | |
6676 | 6649 | gen_lea_modrm(s, modrm, ®_addr, &offset_addr); |
6677 | 6650 | gen_op_ld_T1_A0(OT_WORD + s->mem_index); |
6678 | 6651 | gen_add_A0_im(s, 2); |
... | ... | @@ -6689,8 +6662,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) |
6689 | 6662 | } |
6690 | 6663 | break; |
6691 | 6664 | case 4: /* smsw */ |
6692 | - if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_READ_CR0)) | |
6693 | - break; | |
6665 | + gen_svm_check_intercept(s, pc_start, SVM_EXIT_READ_CR0); | |
6694 | 6666 | tcg_gen_ld32u_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,cr[0])); |
6695 | 6667 | gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 1); |
6696 | 6668 | break; |
... | ... | @@ -6698,8 +6670,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) |
6698 | 6670 | if (s->cpl != 0) { |
6699 | 6671 | gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); |
6700 | 6672 | } else { |
6701 | - if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_WRITE_CR0)) | |
6702 | - break; | |
6673 | + gen_svm_check_intercept(s, pc_start, SVM_EXIT_WRITE_CR0); | |
6703 | 6674 | gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0); |
6704 | 6675 | tcg_gen_helper_0_1(helper_lmsw, cpu_T[0]); |
6705 | 6676 | gen_jmp_im(s->pc - s->cs_base); |
... | ... | @@ -6724,8 +6695,6 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) |
6724 | 6695 | goto illegal_op; |
6725 | 6696 | } |
6726 | 6697 | } else { |
6727 | - if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_INVLPG)) | |
6728 | - break; | |
6729 | 6698 | gen_lea_modrm(s, modrm, ®_addr, &offset_addr); |
6730 | 6699 | tcg_gen_helper_0_1(helper_invlpg, cpu_A0); |
6731 | 6700 | gen_jmp_im(s->pc - s->cs_base); |
... | ... | @@ -6742,8 +6711,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) |
6742 | 6711 | if (s->cpl != 0) { |
6743 | 6712 | gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); |
6744 | 6713 | } else { |
6745 | - if (gen_svm_check_intercept(s, pc_start, (b & 2) ? SVM_EXIT_INVD : SVM_EXIT_WBINVD)) | |
6746 | - break; | |
6714 | + gen_svm_check_intercept(s, pc_start, (b & 2) ? SVM_EXIT_INVD : SVM_EXIT_WBINVD); | |
6747 | 6715 | /* nothing to do */ |
6748 | 6716 | } |
6749 | 6717 | break; |
... | ... | @@ -6892,21 +6860,18 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) |
6892 | 6860 | case 3: |
6893 | 6861 | case 4: |
6894 | 6862 | case 8: |
6863 | + if (s->cc_op != CC_OP_DYNAMIC) | |
6864 | + gen_op_set_cc_op(s->cc_op); | |
6865 | + gen_jmp_im(pc_start - s->cs_base); | |
6895 | 6866 | if (b & 2) { |
6896 | - gen_svm_check_intercept(s, pc_start, SVM_EXIT_WRITE_CR0 + reg); | |
6897 | 6867 | gen_op_mov_TN_reg(ot, 0, rm); |
6898 | - tcg_gen_helper_0_2(helper_movl_crN_T0, | |
6868 | + tcg_gen_helper_0_2(helper_write_crN, | |
6899 | 6869 | tcg_const_i32(reg), cpu_T[0]); |
6900 | 6870 | gen_jmp_im(s->pc - s->cs_base); |
6901 | 6871 | gen_eob(s); |
6902 | 6872 | } else { |
6903 | - gen_svm_check_intercept(s, pc_start, SVM_EXIT_READ_CR0 + reg); | |
6904 | -#if !defined(CONFIG_USER_ONLY) | |
6905 | - if (reg == 8) | |
6906 | - tcg_gen_helper_1_0(helper_movtl_T0_cr8, cpu_T[0]); | |
6907 | - else | |
6908 | -#endif | |
6909 | - tcg_gen_ld_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,cr[reg])); | |
6873 | + tcg_gen_helper_1_1(helper_read_crN, | |
6874 | + cpu_T[0], tcg_const_i32(reg)); | |
6910 | 6875 | gen_op_mov_reg_T0(ot, rm); |
6911 | 6876 | } |
6912 | 6877 | break; |
... | ... | @@ -7054,8 +7019,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) |
7054 | 7019 | /* ignore for now */ |
7055 | 7020 | break; |
7056 | 7021 | case 0x1aa: /* rsm */ |
7057 | - if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_RSM)) | |
7058 | - break; | |
7022 | + gen_svm_check_intercept(s, pc_start, SVM_EXIT_RSM); | |
7059 | 7023 | if (!(s->flags & HF_SMM_MASK)) |
7060 | 7024 | goto illegal_op; |
7061 | 7025 | if (s->cc_op != CC_OP_DYNAMIC) { | ... | ... |