]>
Commit | Line | Data |
---|---|---|
8dd3dca3 AJ |
1 | #include "hw/hw.h" |
2 | #include "hw/boards.h" | |
0d09e41a PB |
3 | #include "hw/i386/pc.h" |
4 | #include "hw/isa/isa.h" | |
8dd3dca3 | 5 | |
2b41f10e | 6 | #include "cpu.h" |
9c17d615 | 7 | #include "sysemu/kvm.h" |
8dd3dca3 | 8 | |
66e6d55b JQ |
9 | static const VMStateDescription vmstate_segment = { |
10 | .name = "segment", | |
11 | .version_id = 1, | |
12 | .minimum_version_id = 1, | |
d49805ae | 13 | .fields = (VMStateField[]) { |
66e6d55b JQ |
14 | VMSTATE_UINT32(selector, SegmentCache), |
15 | VMSTATE_UINTTL(base, SegmentCache), | |
16 | VMSTATE_UINT32(limit, SegmentCache), | |
17 | VMSTATE_UINT32(flags, SegmentCache), | |
18 | VMSTATE_END_OF_LIST() | |
19 | } | |
20 | }; | |
21 | ||
0cb892aa JQ |
22 | #define VMSTATE_SEGMENT(_field, _state) { \ |
23 | .name = (stringify(_field)), \ | |
24 | .size = sizeof(SegmentCache), \ | |
25 | .vmsd = &vmstate_segment, \ | |
26 | .flags = VMS_STRUCT, \ | |
27 | .offset = offsetof(_state, _field) \ | |
28 | + type_check(SegmentCache,typeof_field(_state, _field)) \ | |
8dd3dca3 AJ |
29 | } |
30 | ||
0cb892aa JQ |
31 | #define VMSTATE_SEGMENT_ARRAY(_field, _state, _n) \ |
32 | VMSTATE_STRUCT_ARRAY(_field, _state, _n, 0, vmstate_segment, SegmentCache) | |
8dd3dca3 | 33 | |
fc3b0aa2 JQ |
34 | static const VMStateDescription vmstate_xmm_reg = { |
35 | .name = "xmm_reg", | |
36 | .version_id = 1, | |
37 | .minimum_version_id = 1, | |
d49805ae | 38 | .fields = (VMStateField[]) { |
fc3b0aa2 JQ |
39 | VMSTATE_UINT64(XMM_Q(0), XMMReg), |
40 | VMSTATE_UINT64(XMM_Q(1), XMMReg), | |
41 | VMSTATE_END_OF_LIST() | |
42 | } | |
43 | }; | |
44 | ||
0cb892aa JQ |
45 | #define VMSTATE_XMM_REGS(_field, _state, _n) \ |
46 | VMSTATE_STRUCT_ARRAY(_field, _state, _n, 0, vmstate_xmm_reg, XMMReg) | |
fc3b0aa2 | 47 | |
f1665b21 SY |
48 | /* YMMH format is the same as XMM */ |
49 | static const VMStateDescription vmstate_ymmh_reg = { | |
50 | .name = "ymmh_reg", | |
51 | .version_id = 1, | |
52 | .minimum_version_id = 1, | |
d49805ae | 53 | .fields = (VMStateField[]) { |
f1665b21 SY |
54 | VMSTATE_UINT64(XMM_Q(0), XMMReg), |
55 | VMSTATE_UINT64(XMM_Q(1), XMMReg), | |
56 | VMSTATE_END_OF_LIST() | |
57 | } | |
58 | }; | |
59 | ||
60 | #define VMSTATE_YMMH_REGS_VARS(_field, _state, _n, _v) \ | |
61 | VMSTATE_STRUCT_ARRAY(_field, _state, _n, _v, vmstate_ymmh_reg, XMMReg) | |
62 | ||
79e9ebeb LJ |
63 | static const VMStateDescription vmstate_bnd_regs = { |
64 | .name = "bnd_regs", | |
65 | .version_id = 1, | |
66 | .minimum_version_id = 1, | |
d49805ae | 67 | .fields = (VMStateField[]) { |
79e9ebeb LJ |
68 | VMSTATE_UINT64(lb, BNDReg), |
69 | VMSTATE_UINT64(ub, BNDReg), | |
70 | VMSTATE_END_OF_LIST() | |
71 | } | |
72 | }; | |
73 | ||
74 | #define VMSTATE_BND_REGS(_field, _state, _n) \ | |
75 | VMSTATE_STRUCT_ARRAY(_field, _state, _n, 0, vmstate_bnd_regs, BNDReg) | |
76 | ||
216c07c3 JQ |
77 | static const VMStateDescription vmstate_mtrr_var = { |
78 | .name = "mtrr_var", | |
79 | .version_id = 1, | |
80 | .minimum_version_id = 1, | |
d49805ae | 81 | .fields = (VMStateField[]) { |
216c07c3 JQ |
82 | VMSTATE_UINT64(base, MTRRVar), |
83 | VMSTATE_UINT64(mask, MTRRVar), | |
84 | VMSTATE_END_OF_LIST() | |
85 | } | |
86 | }; | |
87 | ||
0cb892aa JQ |
88 | #define VMSTATE_MTRR_VARS(_field, _state, _n, _v) \ |
89 | VMSTATE_STRUCT_ARRAY(_field, _state, _n, _v, vmstate_mtrr_var, MTRRVar) | |
216c07c3 | 90 | |
0cb892aa | 91 | static void put_fpreg_error(QEMUFile *f, void *opaque, size_t size) |
216c07c3 | 92 | { |
0cb892aa JQ |
93 | fprintf(stderr, "call put_fpreg() with invalid arguments\n"); |
94 | exit(0); | |
216c07c3 JQ |
95 | } |
96 | ||
3c8ce630 JQ |
97 | /* XXX: add that in a FPU generic layer */ |
98 | union x86_longdouble { | |
99 | uint64_t mant; | |
100 | uint16_t exp; | |
101 | }; | |
102 | ||
103 | #define MANTD1(fp) (fp & ((1LL << 52) - 1)) | |
104 | #define EXPBIAS1 1023 | |
105 | #define EXPD1(fp) ((fp >> 52) & 0x7FF) | |
106 | #define SIGND1(fp) ((fp >> 32) & 0x80000000) | |
107 | ||
108 | static void fp64_to_fp80(union x86_longdouble *p, uint64_t temp) | |
109 | { | |
110 | int e; | |
111 | /* mantissa */ | |
112 | p->mant = (MANTD1(temp) << 11) | (1LL << 63); | |
113 | /* exponent + sign */ | |
114 | e = EXPD1(temp) - EXPBIAS1 + 16383; | |
115 | e |= SIGND1(temp) >> 16; | |
116 | p->exp = e; | |
117 | } | |
118 | ||
119 | static int get_fpreg(QEMUFile *f, void *opaque, size_t size) | |
120 | { | |
121 | FPReg *fp_reg = opaque; | |
122 | uint64_t mant; | |
123 | uint16_t exp; | |
124 | ||
125 | qemu_get_be64s(f, &mant); | |
126 | qemu_get_be16s(f, &exp); | |
127 | fp_reg->d = cpu_set_fp80(mant, exp); | |
128 | return 0; | |
129 | } | |
130 | ||
131 | static void put_fpreg(QEMUFile *f, void *opaque, size_t size) | |
132 | { | |
133 | FPReg *fp_reg = opaque; | |
134 | uint64_t mant; | |
135 | uint16_t exp; | |
136 | /* we save the real CPU data (in case of MMX usage only 'mant' | |
137 | contains the MMX register */ | |
138 | cpu_get_fp80(&mant, &exp, fp_reg->d); | |
139 | qemu_put_be64s(f, &mant); | |
140 | qemu_put_be16s(f, &exp); | |
141 | } | |
142 | ||
976b2037 | 143 | static const VMStateInfo vmstate_fpreg = { |
0cb892aa JQ |
144 | .name = "fpreg", |
145 | .get = get_fpreg, | |
146 | .put = put_fpreg, | |
147 | }; | |
148 | ||
3c8ce630 JQ |
149 | static int get_fpreg_1_mmx(QEMUFile *f, void *opaque, size_t size) |
150 | { | |
151 | union x86_longdouble *p = opaque; | |
152 | uint64_t mant; | |
153 | ||
154 | qemu_get_be64s(f, &mant); | |
155 | p->mant = mant; | |
156 | p->exp = 0xffff; | |
157 | return 0; | |
158 | } | |
159 | ||
976b2037 | 160 | static const VMStateInfo vmstate_fpreg_1_mmx = { |
0cb892aa JQ |
161 | .name = "fpreg_1_mmx", |
162 | .get = get_fpreg_1_mmx, | |
163 | .put = put_fpreg_error, | |
164 | }; | |
165 | ||
3c8ce630 JQ |
166 | static int get_fpreg_1_no_mmx(QEMUFile *f, void *opaque, size_t size) |
167 | { | |
168 | union x86_longdouble *p = opaque; | |
169 | uint64_t mant; | |
170 | ||
171 | qemu_get_be64s(f, &mant); | |
172 | fp64_to_fp80(p, mant); | |
173 | return 0; | |
174 | } | |
175 | ||
976b2037 | 176 | static const VMStateInfo vmstate_fpreg_1_no_mmx = { |
0cb892aa JQ |
177 | .name = "fpreg_1_no_mmx", |
178 | .get = get_fpreg_1_no_mmx, | |
179 | .put = put_fpreg_error, | |
180 | }; | |
181 | ||
182 | static bool fpregs_is_0(void *opaque, int version_id) | |
183 | { | |
f56e3a14 AF |
184 | X86CPU *cpu = opaque; |
185 | CPUX86State *env = &cpu->env; | |
0cb892aa JQ |
186 | |
187 | return (env->fpregs_format_vmstate == 0); | |
188 | } | |
189 | ||
190 | static bool fpregs_is_1_mmx(void *opaque, int version_id) | |
191 | { | |
f56e3a14 AF |
192 | X86CPU *cpu = opaque; |
193 | CPUX86State *env = &cpu->env; | |
0cb892aa JQ |
194 | int guess_mmx; |
195 | ||
196 | guess_mmx = ((env->fptag_vmstate == 0xff) && | |
197 | (env->fpus_vmstate & 0x3800) == 0); | |
198 | return (guess_mmx && (env->fpregs_format_vmstate == 1)); | |
199 | } | |
200 | ||
201 | static bool fpregs_is_1_no_mmx(void *opaque, int version_id) | |
202 | { | |
f56e3a14 AF |
203 | X86CPU *cpu = opaque; |
204 | CPUX86State *env = &cpu->env; | |
0cb892aa JQ |
205 | int guess_mmx; |
206 | ||
207 | guess_mmx = ((env->fptag_vmstate == 0xff) && | |
208 | (env->fpus_vmstate & 0x3800) == 0); | |
209 | return (!guess_mmx && (env->fpregs_format_vmstate == 1)); | |
210 | } | |
211 | ||
212 | #define VMSTATE_FP_REGS(_field, _state, _n) \ | |
213 | VMSTATE_ARRAY_TEST(_field, _state, _n, fpregs_is_0, vmstate_fpreg, FPReg), \ | |
214 | VMSTATE_ARRAY_TEST(_field, _state, _n, fpregs_is_1_mmx, vmstate_fpreg_1_mmx, FPReg), \ | |
215 | VMSTATE_ARRAY_TEST(_field, _state, _n, fpregs_is_1_no_mmx, vmstate_fpreg_1_no_mmx, FPReg) | |
216 | ||
0cb892aa JQ |
217 | static bool version_is_5(void *opaque, int version_id) |
218 | { | |
219 | return version_id == 5; | |
220 | } | |
221 | ||
222 | #ifdef TARGET_X86_64 | |
223 | static bool less_than_7(void *opaque, int version_id) | |
224 | { | |
225 | return version_id < 7; | |
226 | } | |
227 | ||
228 | static int get_uint64_as_uint32(QEMUFile *f, void *pv, size_t size) | |
229 | { | |
230 | uint64_t *v = pv; | |
231 | *v = qemu_get_be32(f); | |
232 | return 0; | |
233 | } | |
234 | ||
235 | static void put_uint64_as_uint32(QEMUFile *f, void *pv, size_t size) | |
236 | { | |
237 | uint64_t *v = pv; | |
238 | qemu_put_be32(f, *v); | |
239 | } | |
240 | ||
976b2037 | 241 | static const VMStateInfo vmstate_hack_uint64_as_uint32 = { |
0cb892aa JQ |
242 | .name = "uint64_as_uint32", |
243 | .get = get_uint64_as_uint32, | |
244 | .put = put_uint64_as_uint32, | |
245 | }; | |
246 | ||
247 | #define VMSTATE_HACK_UINT32(_f, _s, _t) \ | |
d4829d49 | 248 | VMSTATE_SINGLE_TEST(_f, _s, _t, 0, vmstate_hack_uint64_as_uint32, uint64_t) |
0cb892aa JQ |
249 | #endif |
250 | ||
c4c38c8c | 251 | static void cpu_pre_save(void *opaque) |
8dd3dca3 | 252 | { |
f56e3a14 AF |
253 | X86CPU *cpu = opaque; |
254 | CPUX86State *env = &cpu->env; | |
0e607a80 | 255 | int i; |
8dd3dca3 | 256 | |
8dd3dca3 | 257 | /* FPU */ |
67b8f419 | 258 | env->fpus_vmstate = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11; |
cdc0c58f | 259 | env->fptag_vmstate = 0; |
8dd3dca3 | 260 | for(i = 0; i < 8; i++) { |
cdc0c58f | 261 | env->fptag_vmstate |= ((!env->fptags[i]) << i); |
8dd3dca3 AJ |
262 | } |
263 | ||
60a902f1 | 264 | env->fpregs_format_vmstate = 0; |
3e47c249 OW |
265 | |
266 | /* | |
267 | * Real mode guest segments register DPL should be zero. | |
268 | * Older KVM version were setting it wrongly. | |
269 | * Fixing it will allow live migration to host with unrestricted guest | |
270 | * support (otherwise the migration will fail with invalid guest state | |
271 | * error). | |
272 | */ | |
273 | if (!(env->cr[0] & CR0_PE_MASK) && | |
274 | (env->segs[R_CS].flags >> DESC_DPL_SHIFT & 3) != 0) { | |
275 | env->segs[R_CS].flags &= ~(env->segs[R_CS].flags & DESC_DPL_MASK); | |
276 | env->segs[R_DS].flags &= ~(env->segs[R_DS].flags & DESC_DPL_MASK); | |
277 | env->segs[R_ES].flags &= ~(env->segs[R_ES].flags & DESC_DPL_MASK); | |
278 | env->segs[R_FS].flags &= ~(env->segs[R_FS].flags & DESC_DPL_MASK); | |
279 | env->segs[R_GS].flags &= ~(env->segs[R_GS].flags & DESC_DPL_MASK); | |
280 | env->segs[R_SS].flags &= ~(env->segs[R_SS].flags & DESC_DPL_MASK); | |
281 | } | |
282 | ||
c4c38c8c JQ |
283 | } |
284 | ||
468f6581 JQ |
285 | static int cpu_post_load(void *opaque, int version_id) |
286 | { | |
f56e3a14 | 287 | X86CPU *cpu = opaque; |
75a34036 | 288 | CPUState *cs = CPU(cpu); |
f56e3a14 | 289 | CPUX86State *env = &cpu->env; |
468f6581 JQ |
290 | int i; |
291 | ||
444ba679 OW |
292 | /* |
293 | * Real mode guest segments register DPL should be zero. | |
294 | * Older KVM version were setting it wrongly. | |
295 | * Fixing it will allow live migration from such host that don't have | |
296 | * restricted guest support to a host with unrestricted guest support | |
297 | * (otherwise the migration will fail with invalid guest state | |
298 | * error). | |
299 | */ | |
300 | if (!(env->cr[0] & CR0_PE_MASK) && | |
301 | (env->segs[R_CS].flags >> DESC_DPL_SHIFT & 3) != 0) { | |
302 | env->segs[R_CS].flags &= ~(env->segs[R_CS].flags & DESC_DPL_MASK); | |
303 | env->segs[R_DS].flags &= ~(env->segs[R_DS].flags & DESC_DPL_MASK); | |
304 | env->segs[R_ES].flags &= ~(env->segs[R_ES].flags & DESC_DPL_MASK); | |
305 | env->segs[R_FS].flags &= ~(env->segs[R_FS].flags & DESC_DPL_MASK); | |
306 | env->segs[R_GS].flags &= ~(env->segs[R_GS].flags & DESC_DPL_MASK); | |
307 | env->segs[R_SS].flags &= ~(env->segs[R_SS].flags & DESC_DPL_MASK); | |
308 | } | |
309 | ||
7125c937 PB |
310 | /* Older versions of QEMU incorrectly used CS.DPL as the CPL when |
311 | * running under KVM. This is wrong for conforming code segments. | |
312 | * Luckily, in our implementation the CPL field of hflags is redundant | |
313 | * and we can get the right value from the SS descriptor privilege level. | |
314 | */ | |
315 | env->hflags &= ~HF_CPL_MASK; | |
316 | env->hflags |= (env->segs[R_SS].flags >> DESC_DPL_SHIFT) & HF_CPL_MASK; | |
317 | ||
468f6581 JQ |
318 | env->fpstt = (env->fpus_vmstate >> 11) & 7; |
319 | env->fpus = env->fpus_vmstate & ~0x3800; | |
320 | env->fptag_vmstate ^= 0xff; | |
321 | for(i = 0; i < 8; i++) { | |
322 | env->fptags[i] = (env->fptag_vmstate >> i) & 1; | |
323 | } | |
5bde1407 | 324 | update_fp_status(env); |
468f6581 | 325 | |
b3310ab3 | 326 | cpu_breakpoint_remove_all(cs, BP_CPU); |
75a34036 | 327 | cpu_watchpoint_remove_all(cs, BP_CPU); |
428065ce | 328 | for (i = 0; i < DR7_MAX_BP; i++) { |
468f6581 | 329 | hw_breakpoint_insert(env, i); |
428065ce | 330 | } |
00c8cb0a | 331 | tlb_flush(cs, 1); |
428065ce | 332 | |
1e7fbc6d | 333 | return 0; |
468f6581 JQ |
334 | } |
335 | ||
f6584ee2 GN |
336 | static bool async_pf_msr_needed(void *opaque) |
337 | { | |
f56e3a14 | 338 | X86CPU *cpu = opaque; |
f6584ee2 | 339 | |
f56e3a14 | 340 | return cpu->env.async_pf_en_msr != 0; |
f6584ee2 GN |
341 | } |
342 | ||
bc9a839d MT |
343 | static bool pv_eoi_msr_needed(void *opaque) |
344 | { | |
f56e3a14 | 345 | X86CPU *cpu = opaque; |
bc9a839d | 346 | |
f56e3a14 | 347 | return cpu->env.pv_eoi_en_msr != 0; |
bc9a839d MT |
348 | } |
349 | ||
917367aa MT |
350 | static bool steal_time_msr_needed(void *opaque) |
351 | { | |
0e503577 | 352 | X86CPU *cpu = opaque; |
917367aa | 353 | |
0e503577 | 354 | return cpu->env.steal_time_msr != 0; |
917367aa MT |
355 | } |
356 | ||
357 | static const VMStateDescription vmstate_steal_time_msr = { | |
358 | .name = "cpu/steal_time_msr", | |
359 | .version_id = 1, | |
360 | .minimum_version_id = 1, | |
d49805ae | 361 | .fields = (VMStateField[]) { |
0e503577 | 362 | VMSTATE_UINT64(env.steal_time_msr, X86CPU), |
917367aa MT |
363 | VMSTATE_END_OF_LIST() |
364 | } | |
365 | }; | |
366 | ||
f6584ee2 GN |
367 | static const VMStateDescription vmstate_async_pf_msr = { |
368 | .name = "cpu/async_pf_msr", | |
369 | .version_id = 1, | |
370 | .minimum_version_id = 1, | |
d49805ae | 371 | .fields = (VMStateField[]) { |
f56e3a14 | 372 | VMSTATE_UINT64(env.async_pf_en_msr, X86CPU), |
f6584ee2 GN |
373 | VMSTATE_END_OF_LIST() |
374 | } | |
375 | }; | |
376 | ||
bc9a839d MT |
377 | static const VMStateDescription vmstate_pv_eoi_msr = { |
378 | .name = "cpu/async_pv_eoi_msr", | |
379 | .version_id = 1, | |
380 | .minimum_version_id = 1, | |
d49805ae | 381 | .fields = (VMStateField[]) { |
f56e3a14 | 382 | VMSTATE_UINT64(env.pv_eoi_en_msr, X86CPU), |
bc9a839d MT |
383 | VMSTATE_END_OF_LIST() |
384 | } | |
385 | }; | |
386 | ||
42cc8fa6 JK |
387 | static bool fpop_ip_dp_needed(void *opaque) |
388 | { | |
f56e3a14 AF |
389 | X86CPU *cpu = opaque; |
390 | CPUX86State *env = &cpu->env; | |
42cc8fa6 JK |
391 | |
392 | return env->fpop != 0 || env->fpip != 0 || env->fpdp != 0; | |
393 | } | |
394 | ||
395 | static const VMStateDescription vmstate_fpop_ip_dp = { | |
396 | .name = "cpu/fpop_ip_dp", | |
397 | .version_id = 1, | |
398 | .minimum_version_id = 1, | |
d49805ae | 399 | .fields = (VMStateField[]) { |
f56e3a14 AF |
400 | VMSTATE_UINT16(env.fpop, X86CPU), |
401 | VMSTATE_UINT64(env.fpip, X86CPU), | |
402 | VMSTATE_UINT64(env.fpdp, X86CPU), | |
42cc8fa6 JK |
403 | VMSTATE_END_OF_LIST() |
404 | } | |
405 | }; | |
406 | ||
f28558d3 WA |
407 | static bool tsc_adjust_needed(void *opaque) |
408 | { | |
f56e3a14 AF |
409 | X86CPU *cpu = opaque; |
410 | CPUX86State *env = &cpu->env; | |
f28558d3 WA |
411 | |
412 | return env->tsc_adjust != 0; | |
413 | } | |
414 | ||
415 | static const VMStateDescription vmstate_msr_tsc_adjust = { | |
416 | .name = "cpu/msr_tsc_adjust", | |
417 | .version_id = 1, | |
418 | .minimum_version_id = 1, | |
d49805ae | 419 | .fields = (VMStateField[]) { |
f56e3a14 | 420 | VMSTATE_UINT64(env.tsc_adjust, X86CPU), |
f28558d3 WA |
421 | VMSTATE_END_OF_LIST() |
422 | } | |
423 | }; | |
424 | ||
aa82ba54 LJ |
425 | static bool tscdeadline_needed(void *opaque) |
426 | { | |
f56e3a14 AF |
427 | X86CPU *cpu = opaque; |
428 | CPUX86State *env = &cpu->env; | |
aa82ba54 LJ |
429 | |
430 | return env->tsc_deadline != 0; | |
431 | } | |
432 | ||
433 | static const VMStateDescription vmstate_msr_tscdeadline = { | |
434 | .name = "cpu/msr_tscdeadline", | |
435 | .version_id = 1, | |
436 | .minimum_version_id = 1, | |
d49805ae | 437 | .fields = (VMStateField[]) { |
f56e3a14 | 438 | VMSTATE_UINT64(env.tsc_deadline, X86CPU), |
aa82ba54 LJ |
439 | VMSTATE_END_OF_LIST() |
440 | } | |
441 | }; | |
442 | ||
21e87c46 AK |
443 | static bool misc_enable_needed(void *opaque) |
444 | { | |
f56e3a14 AF |
445 | X86CPU *cpu = opaque; |
446 | CPUX86State *env = &cpu->env; | |
21e87c46 AK |
447 | |
448 | return env->msr_ia32_misc_enable != MSR_IA32_MISC_ENABLE_DEFAULT; | |
449 | } | |
450 | ||
0779caeb ACL |
451 | static bool feature_control_needed(void *opaque) |
452 | { | |
453 | X86CPU *cpu = opaque; | |
454 | CPUX86State *env = &cpu->env; | |
455 | ||
456 | return env->msr_ia32_feature_control != 0; | |
457 | } | |
458 | ||
21e87c46 AK |
459 | static const VMStateDescription vmstate_msr_ia32_misc_enable = { |
460 | .name = "cpu/msr_ia32_misc_enable", | |
461 | .version_id = 1, | |
462 | .minimum_version_id = 1, | |
d49805ae | 463 | .fields = (VMStateField[]) { |
f56e3a14 | 464 | VMSTATE_UINT64(env.msr_ia32_misc_enable, X86CPU), |
21e87c46 AK |
465 | VMSTATE_END_OF_LIST() |
466 | } | |
467 | }; | |
468 | ||
0779caeb ACL |
469 | static const VMStateDescription vmstate_msr_ia32_feature_control = { |
470 | .name = "cpu/msr_ia32_feature_control", | |
471 | .version_id = 1, | |
472 | .minimum_version_id = 1, | |
d49805ae | 473 | .fields = (VMStateField[]) { |
0779caeb ACL |
474 | VMSTATE_UINT64(env.msr_ia32_feature_control, X86CPU), |
475 | VMSTATE_END_OF_LIST() | |
476 | } | |
477 | }; | |
478 | ||
0d894367 PB |
479 | static bool pmu_enable_needed(void *opaque) |
480 | { | |
481 | X86CPU *cpu = opaque; | |
482 | CPUX86State *env = &cpu->env; | |
483 | int i; | |
484 | ||
485 | if (env->msr_fixed_ctr_ctrl || env->msr_global_ctrl || | |
486 | env->msr_global_status || env->msr_global_ovf_ctrl) { | |
487 | return true; | |
488 | } | |
489 | for (i = 0; i < MAX_FIXED_COUNTERS; i++) { | |
490 | if (env->msr_fixed_counters[i]) { | |
491 | return true; | |
492 | } | |
493 | } | |
494 | for (i = 0; i < MAX_GP_COUNTERS; i++) { | |
495 | if (env->msr_gp_counters[i] || env->msr_gp_evtsel[i]) { | |
496 | return true; | |
497 | } | |
498 | } | |
499 | ||
500 | return false; | |
501 | } | |
502 | ||
503 | static const VMStateDescription vmstate_msr_architectural_pmu = { | |
504 | .name = "cpu/msr_architectural_pmu", | |
505 | .version_id = 1, | |
506 | .minimum_version_id = 1, | |
d49805ae | 507 | .fields = (VMStateField[]) { |
0d894367 PB |
508 | VMSTATE_UINT64(env.msr_fixed_ctr_ctrl, X86CPU), |
509 | VMSTATE_UINT64(env.msr_global_ctrl, X86CPU), | |
510 | VMSTATE_UINT64(env.msr_global_status, X86CPU), | |
511 | VMSTATE_UINT64(env.msr_global_ovf_ctrl, X86CPU), | |
512 | VMSTATE_UINT64_ARRAY(env.msr_fixed_counters, X86CPU, MAX_FIXED_COUNTERS), | |
513 | VMSTATE_UINT64_ARRAY(env.msr_gp_counters, X86CPU, MAX_GP_COUNTERS), | |
514 | VMSTATE_UINT64_ARRAY(env.msr_gp_evtsel, X86CPU, MAX_GP_COUNTERS), | |
515 | VMSTATE_END_OF_LIST() | |
516 | } | |
517 | }; | |
518 | ||
79e9ebeb LJ |
519 | static bool mpx_needed(void *opaque) |
520 | { | |
521 | X86CPU *cpu = opaque; | |
522 | CPUX86State *env = &cpu->env; | |
523 | unsigned int i; | |
524 | ||
525 | for (i = 0; i < 4; i++) { | |
526 | if (env->bnd_regs[i].lb || env->bnd_regs[i].ub) { | |
527 | return true; | |
528 | } | |
529 | } | |
530 | ||
531 | if (env->bndcs_regs.cfgu || env->bndcs_regs.sts) { | |
532 | return true; | |
533 | } | |
534 | ||
535 | return !!env->msr_bndcfgs; | |
536 | } | |
537 | ||
538 | static const VMStateDescription vmstate_mpx = { | |
539 | .name = "cpu/mpx", | |
540 | .version_id = 1, | |
541 | .minimum_version_id = 1, | |
d49805ae | 542 | .fields = (VMStateField[]) { |
79e9ebeb LJ |
543 | VMSTATE_BND_REGS(env.bnd_regs, X86CPU, 4), |
544 | VMSTATE_UINT64(env.bndcs_regs.cfgu, X86CPU), | |
545 | VMSTATE_UINT64(env.bndcs_regs.sts, X86CPU), | |
546 | VMSTATE_UINT64(env.msr_bndcfgs, X86CPU), | |
547 | VMSTATE_END_OF_LIST() | |
548 | } | |
549 | }; | |
550 | ||
1c90ef26 VR |
551 | static bool hyperv_hypercall_enable_needed(void *opaque) |
552 | { | |
553 | X86CPU *cpu = opaque; | |
554 | CPUX86State *env = &cpu->env; | |
555 | ||
556 | return env->msr_hv_hypercall != 0 || env->msr_hv_guest_os_id != 0; | |
557 | } | |
558 | ||
559 | static const VMStateDescription vmstate_msr_hypercall_hypercall = { | |
560 | .name = "cpu/msr_hyperv_hypercall", | |
561 | .version_id = 1, | |
562 | .minimum_version_id = 1, | |
d49805ae | 563 | .fields = (VMStateField[]) { |
1c90ef26 | 564 | VMSTATE_UINT64(env.msr_hv_guest_os_id, X86CPU), |
466e6e9d | 565 | VMSTATE_UINT64(env.msr_hv_hypercall, X86CPU), |
1c90ef26 VR |
566 | VMSTATE_END_OF_LIST() |
567 | } | |
568 | }; | |
569 | ||
5ef68987 VR |
570 | static bool hyperv_vapic_enable_needed(void *opaque) |
571 | { | |
572 | X86CPU *cpu = opaque; | |
573 | CPUX86State *env = &cpu->env; | |
574 | ||
575 | return env->msr_hv_vapic != 0; | |
576 | } | |
577 | ||
578 | static const VMStateDescription vmstate_msr_hyperv_vapic = { | |
579 | .name = "cpu/msr_hyperv_vapic", | |
580 | .version_id = 1, | |
581 | .minimum_version_id = 1, | |
d49805ae | 582 | .fields = (VMStateField[]) { |
5ef68987 VR |
583 | VMSTATE_UINT64(env.msr_hv_vapic, X86CPU), |
584 | VMSTATE_END_OF_LIST() | |
585 | } | |
586 | }; | |
587 | ||
48a5f3bc VR |
588 | static bool hyperv_time_enable_needed(void *opaque) |
589 | { | |
590 | X86CPU *cpu = opaque; | |
591 | CPUX86State *env = &cpu->env; | |
592 | ||
593 | return env->msr_hv_tsc != 0; | |
594 | } | |
595 | ||
596 | static const VMStateDescription vmstate_msr_hyperv_time = { | |
597 | .name = "cpu/msr_hyperv_time", | |
598 | .version_id = 1, | |
599 | .minimum_version_id = 1, | |
d49805ae | 600 | .fields = (VMStateField[]) { |
48a5f3bc VR |
601 | VMSTATE_UINT64(env.msr_hv_tsc, X86CPU), |
602 | VMSTATE_END_OF_LIST() | |
603 | } | |
604 | }; | |
605 | ||
68bfd0ad | 606 | VMStateDescription vmstate_x86_cpu = { |
0cb892aa | 607 | .name = "cpu", |
f56e3a14 | 608 | .version_id = 12, |
0cb892aa | 609 | .minimum_version_id = 3, |
0cb892aa | 610 | .pre_save = cpu_pre_save, |
0cb892aa | 611 | .post_load = cpu_post_load, |
d49805ae | 612 | .fields = (VMStateField[]) { |
f56e3a14 AF |
613 | VMSTATE_UINTTL_ARRAY(env.regs, X86CPU, CPU_NB_REGS), |
614 | VMSTATE_UINTTL(env.eip, X86CPU), | |
615 | VMSTATE_UINTTL(env.eflags, X86CPU), | |
616 | VMSTATE_UINT32(env.hflags, X86CPU), | |
0cb892aa | 617 | /* FPU */ |
f56e3a14 AF |
618 | VMSTATE_UINT16(env.fpuc, X86CPU), |
619 | VMSTATE_UINT16(env.fpus_vmstate, X86CPU), | |
620 | VMSTATE_UINT16(env.fptag_vmstate, X86CPU), | |
621 | VMSTATE_UINT16(env.fpregs_format_vmstate, X86CPU), | |
622 | VMSTATE_FP_REGS(env.fpregs, X86CPU, 8), | |
623 | ||
624 | VMSTATE_SEGMENT_ARRAY(env.segs, X86CPU, 6), | |
625 | VMSTATE_SEGMENT(env.ldt, X86CPU), | |
626 | VMSTATE_SEGMENT(env.tr, X86CPU), | |
627 | VMSTATE_SEGMENT(env.gdt, X86CPU), | |
628 | VMSTATE_SEGMENT(env.idt, X86CPU), | |
629 | ||
630 | VMSTATE_UINT32(env.sysenter_cs, X86CPU), | |
0cb892aa JQ |
631 | #ifdef TARGET_X86_64 |
632 | /* Hack: In v7 size changed from 32 to 64 bits on x86_64 */ | |
f56e3a14 AF |
633 | VMSTATE_HACK_UINT32(env.sysenter_esp, X86CPU, less_than_7), |
634 | VMSTATE_HACK_UINT32(env.sysenter_eip, X86CPU, less_than_7), | |
635 | VMSTATE_UINTTL_V(env.sysenter_esp, X86CPU, 7), | |
636 | VMSTATE_UINTTL_V(env.sysenter_eip, X86CPU, 7), | |
8dd3dca3 | 637 | #else |
f56e3a14 AF |
638 | VMSTATE_UINTTL(env.sysenter_esp, X86CPU), |
639 | VMSTATE_UINTTL(env.sysenter_eip, X86CPU), | |
3c8ce630 | 640 | #endif |
8dd3dca3 | 641 | |
f56e3a14 AF |
642 | VMSTATE_UINTTL(env.cr[0], X86CPU), |
643 | VMSTATE_UINTTL(env.cr[2], X86CPU), | |
644 | VMSTATE_UINTTL(env.cr[3], X86CPU), | |
645 | VMSTATE_UINTTL(env.cr[4], X86CPU), | |
646 | VMSTATE_UINTTL_ARRAY(env.dr, X86CPU, 8), | |
0cb892aa | 647 | /* MMU */ |
f56e3a14 | 648 | VMSTATE_INT32(env.a20_mask, X86CPU), |
0cb892aa | 649 | /* XMM */ |
f56e3a14 AF |
650 | VMSTATE_UINT32(env.mxcsr, X86CPU), |
651 | VMSTATE_XMM_REGS(env.xmm_regs, X86CPU, CPU_NB_REGS), | |
8dd3dca3 AJ |
652 | |
653 | #ifdef TARGET_X86_64 | |
f56e3a14 AF |
654 | VMSTATE_UINT64(env.efer, X86CPU), |
655 | VMSTATE_UINT64(env.star, X86CPU), | |
656 | VMSTATE_UINT64(env.lstar, X86CPU), | |
657 | VMSTATE_UINT64(env.cstar, X86CPU), | |
658 | VMSTATE_UINT64(env.fmask, X86CPU), | |
659 | VMSTATE_UINT64(env.kernelgsbase, X86CPU), | |
8dd3dca3 | 660 | #endif |
f56e3a14 AF |
661 | VMSTATE_UINT32_V(env.smbase, X86CPU, 4), |
662 | ||
663 | VMSTATE_UINT64_V(env.pat, X86CPU, 5), | |
664 | VMSTATE_UINT32_V(env.hflags2, X86CPU, 5), | |
665 | ||
259186a7 | 666 | VMSTATE_UINT32_TEST(parent_obj.halted, X86CPU, version_is_5), |
f56e3a14 AF |
667 | VMSTATE_UINT64_V(env.vm_hsave, X86CPU, 5), |
668 | VMSTATE_UINT64_V(env.vm_vmcb, X86CPU, 5), | |
669 | VMSTATE_UINT64_V(env.tsc_offset, X86CPU, 5), | |
670 | VMSTATE_UINT64_V(env.intercept, X86CPU, 5), | |
671 | VMSTATE_UINT16_V(env.intercept_cr_read, X86CPU, 5), | |
672 | VMSTATE_UINT16_V(env.intercept_cr_write, X86CPU, 5), | |
673 | VMSTATE_UINT16_V(env.intercept_dr_read, X86CPU, 5), | |
674 | VMSTATE_UINT16_V(env.intercept_dr_write, X86CPU, 5), | |
675 | VMSTATE_UINT32_V(env.intercept_exceptions, X86CPU, 5), | |
676 | VMSTATE_UINT8_V(env.v_tpr, X86CPU, 5), | |
dd5e3b17 | 677 | /* MTRRs */ |
f56e3a14 AF |
678 | VMSTATE_UINT64_ARRAY_V(env.mtrr_fixed, X86CPU, 11, 8), |
679 | VMSTATE_UINT64_V(env.mtrr_deftype, X86CPU, 8), | |
d8b5c67b | 680 | VMSTATE_MTRR_VARS(env.mtrr_var, X86CPU, MSR_MTRRcap_VCNT, 8), |
0cb892aa | 681 | /* KVM-related states */ |
f56e3a14 AF |
682 | VMSTATE_INT32_V(env.interrupt_injected, X86CPU, 9), |
683 | VMSTATE_UINT32_V(env.mp_state, X86CPU, 9), | |
684 | VMSTATE_UINT64_V(env.tsc, X86CPU, 9), | |
685 | VMSTATE_INT32_V(env.exception_injected, X86CPU, 11), | |
686 | VMSTATE_UINT8_V(env.soft_interrupt, X86CPU, 11), | |
687 | VMSTATE_UINT8_V(env.nmi_injected, X86CPU, 11), | |
688 | VMSTATE_UINT8_V(env.nmi_pending, X86CPU, 11), | |
689 | VMSTATE_UINT8_V(env.has_error_code, X86CPU, 11), | |
690 | VMSTATE_UINT32_V(env.sipi_vector, X86CPU, 11), | |
0cb892aa | 691 | /* MCE */ |
f56e3a14 AF |
692 | VMSTATE_UINT64_V(env.mcg_cap, X86CPU, 10), |
693 | VMSTATE_UINT64_V(env.mcg_status, X86CPU, 10), | |
694 | VMSTATE_UINT64_V(env.mcg_ctl, X86CPU, 10), | |
695 | VMSTATE_UINT64_ARRAY_V(env.mce_banks, X86CPU, MCE_BANKS_DEF * 4, 10), | |
0cb892aa | 696 | /* rdtscp */ |
f56e3a14 | 697 | VMSTATE_UINT64_V(env.tsc_aux, X86CPU, 11), |
1a03675d | 698 | /* KVM pvclock msr */ |
f56e3a14 AF |
699 | VMSTATE_UINT64_V(env.system_time_msr, X86CPU, 11), |
700 | VMSTATE_UINT64_V(env.wall_clock_msr, X86CPU, 11), | |
f1665b21 | 701 | /* XSAVE related fields */ |
f56e3a14 AF |
702 | VMSTATE_UINT64_V(env.xcr0, X86CPU, 12), |
703 | VMSTATE_UINT64_V(env.xstate_bv, X86CPU, 12), | |
704 | VMSTATE_YMMH_REGS_VARS(env.ymmh_regs, X86CPU, CPU_NB_REGS, 12), | |
0cb892aa | 705 | VMSTATE_END_OF_LIST() |
a0fb002c | 706 | /* The above list is not sorted /wrt version numbers, watch out! */ |
f6584ee2 GN |
707 | }, |
708 | .subsections = (VMStateSubsection []) { | |
709 | { | |
710 | .vmsd = &vmstate_async_pf_msr, | |
711 | .needed = async_pf_msr_needed, | |
bc9a839d MT |
712 | } , { |
713 | .vmsd = &vmstate_pv_eoi_msr, | |
714 | .needed = pv_eoi_msr_needed, | |
917367aa MT |
715 | } , { |
716 | .vmsd = &vmstate_steal_time_msr, | |
717 | .needed = steal_time_msr_needed, | |
42cc8fa6 JK |
718 | } , { |
719 | .vmsd = &vmstate_fpop_ip_dp, | |
720 | .needed = fpop_ip_dp_needed, | |
f28558d3 WA |
721 | }, { |
722 | .vmsd = &vmstate_msr_tsc_adjust, | |
723 | .needed = tsc_adjust_needed, | |
aa82ba54 LJ |
724 | }, { |
725 | .vmsd = &vmstate_msr_tscdeadline, | |
726 | .needed = tscdeadline_needed, | |
21e87c46 AK |
727 | }, { |
728 | .vmsd = &vmstate_msr_ia32_misc_enable, | |
729 | .needed = misc_enable_needed, | |
0779caeb ACL |
730 | }, { |
731 | .vmsd = &vmstate_msr_ia32_feature_control, | |
732 | .needed = feature_control_needed, | |
0d894367 PB |
733 | }, { |
734 | .vmsd = &vmstate_msr_architectural_pmu, | |
735 | .needed = pmu_enable_needed, | |
79e9ebeb LJ |
736 | } , { |
737 | .vmsd = &vmstate_mpx, | |
738 | .needed = mpx_needed, | |
1c90ef26 VR |
739 | }, { |
740 | .vmsd = &vmstate_msr_hypercall_hypercall, | |
741 | .needed = hyperv_hypercall_enable_needed, | |
5ef68987 VR |
742 | }, { |
743 | .vmsd = &vmstate_msr_hyperv_vapic, | |
744 | .needed = hyperv_vapic_enable_needed, | |
48a5f3bc VR |
745 | }, { |
746 | .vmsd = &vmstate_msr_hyperv_time, | |
747 | .needed = hyperv_time_enable_needed, | |
f6584ee2 GN |
748 | } , { |
749 | /* empty */ | |
750 | } | |
79c4f6b0 | 751 | } |
0cb892aa | 752 | }; |