]>
Commit | Line | Data |
---|---|---|
f7b2429f BS |
1 | /* |
2 | * x86 misc helpers | |
3 | * | |
4 | * Copyright (c) 2003 Fabrice Bellard | |
5 | * | |
6 | * This library is free software; you can redistribute it and/or | |
7 | * modify it under the terms of the GNU Lesser General Public | |
8 | * License as published by the Free Software Foundation; either | |
d9ff33ad | 9 | * version 2.1 of the License, or (at your option) any later version. |
f7b2429f BS |
10 | * |
11 | * This library is distributed in the hope that it will be useful, | |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 | * Lesser General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU Lesser General Public | |
17 | * License along with this library; if not, see <http://www.gnu.org/licenses/>. | |
18 | */ | |
19 | ||
b6a0aa05 | 20 | #include "qemu/osdep.h" |
cd617484 | 21 | #include "qemu/log.h" |
f7b2429f | 22 | #include "cpu.h" |
2ef6175a | 23 | #include "exec/helper-proto.h" |
63c91552 | 24 | #include "exec/exec-all.h" |
ed69e831 | 25 | #include "helper-tcg.h" |
92fc4b58 | 26 | |
69483f31 CF |
27 | /* |
28 | * NOTE: the translator must set DisasContext.cc_op to CC_OP_EFLAGS | |
29 | * after generating a call to a helper that uses this. | |
30 | */ | |
31 | void cpu_load_eflags(CPUX86State *env, int eflags, int update_mask) | |
32 | { | |
33 | CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); | |
34 | CC_OP = CC_OP_EFLAGS; | |
35 | env->df = 1 - (2 * ((eflags >> 10) & 1)); | |
36 | env->eflags = (env->eflags & ~update_mask) | | |
37 | (eflags & update_mask) | 0x2; | |
38 | } | |
39 | ||
4a7443be | 40 | void helper_into(CPUX86State *env, int next_eip_addend) |
f7b2429f BS |
41 | { |
42 | int eflags; | |
43 | ||
f0967a1a | 44 | eflags = cpu_cc_compute_all(env, CC_OP); |
f7b2429f BS |
45 | if (eflags & CC_O) { |
46 | raise_interrupt(env, EXCP04_INTO, 1, 0, next_eip_addend); | |
47 | } | |
48 | } | |
49 | ||
4a7443be | 50 | void helper_cpuid(CPUX86State *env) |
f7b2429f BS |
51 | { |
52 | uint32_t eax, ebx, ecx, edx; | |
53 | ||
65c9d60a | 54 | cpu_svm_check_intercept_param(env, SVM_EXIT_CPUID, 0, GETPC()); |
f7b2429f | 55 | |
90a2541b LG |
56 | cpu_x86_cpuid(env, (uint32_t)env->regs[R_EAX], (uint32_t)env->regs[R_ECX], |
57 | &eax, &ebx, &ecx, &edx); | |
4b34e3ad | 58 | env->regs[R_EAX] = eax; |
70b51365 | 59 | env->regs[R_EBX] = ebx; |
a4165610 | 60 | env->regs[R_ECX] = ecx; |
00f5e6f2 | 61 | env->regs[R_EDX] = edx; |
f7b2429f BS |
62 | } |
63 | ||
4a7443be | 64 | void helper_rdtsc(CPUX86State *env) |
f7b2429f BS |
65 | { |
66 | uint64_t val; | |
67 | ||
68 | if ((env->cr[4] & CR4_TSD_MASK) && ((env->hflags & HF_CPL_MASK) != 0)) { | |
4054cdec | 69 | raise_exception_ra(env, EXCP0D_GPF, GETPC()); |
f7b2429f | 70 | } |
65c9d60a | 71 | cpu_svm_check_intercept_param(env, SVM_EXIT_RDTSC, 0, GETPC()); |
f7b2429f BS |
72 | |
73 | val = cpu_get_tsc(env) + env->tsc_offset; | |
4b34e3ad | 74 | env->regs[R_EAX] = (uint32_t)(val); |
00f5e6f2 | 75 | env->regs[R_EDX] = (uint32_t)(val >> 32); |
f7b2429f BS |
76 | } |
77 | ||
8905770b | 78 | G_NORETURN void helper_rdpmc(CPUX86State *env) |
f7b2429f | 79 | { |
c45b426a ZZL |
80 | if (((env->cr[4] & CR4_PCE_MASK) == 0 ) && |
81 | ((env->hflags & HF_CPL_MASK) != 0)) { | |
4054cdec | 82 | raise_exception_ra(env, EXCP0D_GPF, GETPC()); |
f7b2429f | 83 | } |
65c9d60a | 84 | cpu_svm_check_intercept_param(env, SVM_EXIT_RDPMC, 0, GETPC()); |
f7b2429f BS |
85 | |
86 | /* currently unimplemented */ | |
87 | qemu_log_mask(LOG_UNIMP, "x86: unimplemented rdpmc\n"); | |
88 | raise_exception_err(env, EXCP06_ILLOP, 0); | |
89 | } | |
90 | ||
8905770b | 91 | G_NORETURN void do_pause(CPUX86State *env) |
81f3053b | 92 | { |
eb26784f | 93 | CPUState *cs = env_cpu(env); |
81f3053b PB |
94 | |
95 | /* Just let another CPU run. */ | |
27103424 | 96 | cs->exception_index = EXCP_INTERRUPT; |
5638d180 | 97 | cpu_loop_exit(cs); |
81f3053b PB |
98 | } |
99 | ||
8905770b | 100 | G_NORETURN void helper_pause(CPUX86State *env, int next_eip_addend) |
81f3053b | 101 | { |
65c9d60a | 102 | cpu_svm_check_intercept_param(env, SVM_EXIT_PAUSE, 0, GETPC()); |
81f3053b PB |
103 | env->eip += next_eip_addend; |
104 | ||
eb26784f | 105 | do_pause(env); |
81f3053b PB |
106 | } |
107 | ||
0f70ed47 PB |
108 | uint64_t helper_rdpkru(CPUX86State *env, uint32_t ecx) |
109 | { | |
110 | if ((env->cr[4] & CR4_PKE_MASK) == 0) { | |
111 | raise_exception_err_ra(env, EXCP06_ILLOP, 0, GETPC()); | |
112 | } | |
113 | if (ecx != 0) { | |
114 | raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC()); | |
115 | } | |
116 | ||
117 | return env->pkru; | |
118 | } | |
119 | ||
120 | void helper_wrpkru(CPUX86State *env, uint32_t ecx, uint64_t val) | |
121 | { | |
6aa9e42f | 122 | CPUState *cs = env_cpu(env); |
0f70ed47 PB |
123 | |
124 | if ((env->cr[4] & CR4_PKE_MASK) == 0) { | |
125 | raise_exception_err_ra(env, EXCP06_ILLOP, 0, GETPC()); | |
126 | } | |
127 | if (ecx != 0 || (val & 0xFFFFFFFF00000000ull)) { | |
128 | raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC()); | |
129 | } | |
130 | ||
131 | env->pkru = val; | |
d10eb08f | 132 | tlb_flush(cs); |
0f70ed47 | 133 | } |
6750485b PB |
134 | |
135 | target_ulong HELPER(rdpid)(CPUX86State *env) | |
136 | { | |
137 | #if defined CONFIG_SOFTMMU | |
138 | return env->tsc_aux; | |
139 | #elif defined CONFIG_LINUX && defined CONFIG_GETCPU | |
140 | unsigned cpu, node; | |
141 | getcpu(&cpu, &node); | |
142 | return (node << 12) | (cpu & 0xfff); | |
143 | #elif defined CONFIG_SCHED_GETCPU | |
144 | return sched_getcpu(); | |
145 | #else | |
146 | return 0; | |
147 | #endif | |
148 | } |