x86: factor out cpu_get/put_fpreg()
[armpft.git] / target-i386 / machine.c
blob6976c07a3821d639d0aa628a1dece1b02c354f39
1 #include "hw/hw.h"
2 #include "hw/boards.h"
3 #include "hw/pc.h"
4 #include "hw/isa.h"
5 #include "host-utils.h"
7 #include "exec-all.h"
8 #include "kvm.h"
10 static const VMStateDescription vmstate_segment = {
11 .name = "segment",
12 .version_id = 1,
13 .minimum_version_id = 1,
14 .minimum_version_id_old = 1,
15 .fields = (VMStateField []) {
16 VMSTATE_UINT32(selector, SegmentCache),
17 VMSTATE_UINTTL(base, SegmentCache),
18 VMSTATE_UINT32(limit, SegmentCache),
19 VMSTATE_UINT32(flags, SegmentCache),
20 VMSTATE_END_OF_LIST()
24 static void cpu_put_seg(QEMUFile *f, SegmentCache *dt)
26 vmstate_save_state(f, &vmstate_segment, dt);
29 static void cpu_get_seg(QEMUFile *f, SegmentCache *dt)
31 vmstate_load_state(f, &vmstate_segment, dt, vmstate_segment.version_id);
34 static const VMStateDescription vmstate_xmm_reg = {
35 .name = "xmm_reg",
36 .version_id = 1,
37 .minimum_version_id = 1,
38 .minimum_version_id_old = 1,
39 .fields = (VMStateField []) {
40 VMSTATE_UINT64(XMM_Q(0), XMMReg),
41 VMSTATE_UINT64(XMM_Q(1), XMMReg),
42 VMSTATE_END_OF_LIST()
46 static void cpu_put_xmm_reg(QEMUFile *f, XMMReg *xmm_reg)
48 vmstate_save_state(f, &vmstate_xmm_reg, xmm_reg);
51 static void cpu_get_xmm_reg(QEMUFile *f, XMMReg *xmm_reg)
53 vmstate_load_state(f, &vmstate_xmm_reg, xmm_reg, vmstate_xmm_reg.version_id);
56 static const VMStateDescription vmstate_mtrr_var = {
57 .name = "mtrr_var",
58 .version_id = 1,
59 .minimum_version_id = 1,
60 .minimum_version_id_old = 1,
61 .fields = (VMStateField []) {
62 VMSTATE_UINT64(base, MTRRVar),
63 VMSTATE_UINT64(mask, MTRRVar),
64 VMSTATE_END_OF_LIST()
68 static void cpu_put_mtrr_var(QEMUFile *f, MTRRVar *mtrr_var)
70 vmstate_save_state(f, &vmstate_mtrr_var, mtrr_var);
73 static void cpu_get_mtrr_var(QEMUFile *f, MTRRVar *mtrr_var)
75 vmstate_load_state(f, &vmstate_mtrr_var, mtrr_var, vmstate_mtrr_var.version_id);
78 #ifdef USE_X86LDOUBLE
79 /* XXX: add that in a FPU generic layer */
80 union x86_longdouble {
81 uint64_t mant;
82 uint16_t exp;
85 #define MANTD1(fp) (fp & ((1LL << 52) - 1))
86 #define EXPBIAS1 1023
87 #define EXPD1(fp) ((fp >> 52) & 0x7FF)
88 #define SIGND1(fp) ((fp >> 32) & 0x80000000)
90 static void fp64_to_fp80(union x86_longdouble *p, uint64_t temp)
92 int e;
93 /* mantissa */
94 p->mant = (MANTD1(temp) << 11) | (1LL << 63);
95 /* exponent + sign */
96 e = EXPD1(temp) - EXPBIAS1 + 16383;
97 e |= SIGND1(temp) >> 16;
98 p->exp = e;
101 static int get_fpreg(QEMUFile *f, void *opaque, size_t size)
103 FPReg *fp_reg = opaque;
104 uint64_t mant;
105 uint16_t exp;
107 qemu_get_be64s(f, &mant);
108 qemu_get_be16s(f, &exp);
109 fp_reg->d = cpu_set_fp80(mant, exp);
110 return 0;
113 static void put_fpreg(QEMUFile *f, void *opaque, size_t size)
115 FPReg *fp_reg = opaque;
116 uint64_t mant;
117 uint16_t exp;
118 /* we save the real CPU data (in case of MMX usage only 'mant'
119 contains the MMX register */
120 cpu_get_fp80(&mant, &exp, fp_reg->d);
121 qemu_put_be64s(f, &mant);
122 qemu_put_be16s(f, &exp);
125 static int get_fpreg_1_mmx(QEMUFile *f, void *opaque, size_t size)
127 union x86_longdouble *p = opaque;
128 uint64_t mant;
130 qemu_get_be64s(f, &mant);
131 p->mant = mant;
132 p->exp = 0xffff;
133 return 0;
136 static int get_fpreg_1_no_mmx(QEMUFile *f, void *opaque, size_t size)
138 union x86_longdouble *p = opaque;
139 uint64_t mant;
141 qemu_get_be64s(f, &mant);
142 fp64_to_fp80(p, mant);
143 return 0;
146 #else
147 static int get_fpreg(QEMUFile *f, void *opaque, size_t size)
149 FPReg *fp_reg = opaque;
151 qemu_get_be64s(f, &fp_reg->mmx.MMX_Q(0));
152 return 0;
155 static void put_fpreg(QEMUFile *f, void *opaque, size_t size)
157 FPReg *fp_reg = opaque;
158 /* if we use doubles for float emulation, we save the doubles to
159 avoid losing information in case of MMX usage. It can give
160 problems if the image is restored on a CPU where long
161 doubles are used instead. */
162 qemu_put_be64s(f, &fp_reg->mmx.MMX_Q(0));
165 static int get_fpreg_0_mmx(QEMUFile *f, void *opaque, size_t size)
167 FPReg *fp_reg = opaque;
168 uint64_t mant;
169 uint16_t exp;
171 qemu_get_be64s(f, &mant);
172 qemu_get_be16s(f, &exp);
173 fp_reg->mmx.MMX_Q(0) = mant;
174 return 0;
177 static int get_fpreg_0_no_mmx(QEMUFile *f, void *opaque, size_t size)
179 FPReg *fp_reg = opaque;
180 uint64_t mant;
181 uint16_t exp;
183 qemu_get_be64s(f, &mant);
184 qemu_get_be16s(f, &exp);
186 fp_reg->d = cpu_set_fp80(mant, exp);
187 return 0;
190 #endif /* USE_X86LDOUBLE */
192 static void cpu_pre_save(void *opaque)
194 CPUState *env = opaque;
195 int i, bit;
197 cpu_synchronize_state(env);
199 /* FPU */
200 env->fpus_vmstate = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
201 env->fptag_vmstate = 0;
202 for(i = 0; i < 8; i++) {
203 env->fptag_vmstate |= ((!env->fptags[i]) << i);
206 #ifdef USE_X86LDOUBLE
207 env->fpregs_format_vmstate = 0;
208 #else
209 env->fpregs_format_vmstate = 1;
210 #endif
212 /* There can only be one pending IRQ set in the bitmap at a time, so try
213 to find it and save its number instead (-1 for none). */
214 env->pending_irq_vmstate = -1;
215 for (i = 0; i < ARRAY_SIZE(env->interrupt_bitmap); i++) {
216 if (env->interrupt_bitmap[i]) {
217 bit = ctz64(env->interrupt_bitmap[i]);
218 env->pending_irq_vmstate = i * 64 + bit;
219 break;
224 void cpu_save(QEMUFile *f, void *opaque)
226 CPUState *env = opaque;
227 int i;
229 cpu_pre_save(opaque);
231 for(i = 0; i < CPU_NB_REGS; i++)
232 qemu_put_betls(f, &env->regs[i]);
233 qemu_put_betls(f, &env->eip);
234 qemu_put_betls(f, &env->eflags);
235 qemu_put_be32s(f, &env->hflags);
237 /* FPU */
238 qemu_put_be16s(f, &env->fpuc);
239 qemu_put_be16s(f, &env->fpus_vmstate);
240 qemu_put_be16s(f, &env->fptag_vmstate);
242 qemu_put_be16s(f, &env->fpregs_format_vmstate);
244 for(i = 0; i < 8; i++) {
245 put_fpreg(f, &env->fpregs[i], 0);
248 for(i = 0; i < 6; i++)
249 cpu_put_seg(f, &env->segs[i]);
250 cpu_put_seg(f, &env->ldt);
251 cpu_put_seg(f, &env->tr);
252 cpu_put_seg(f, &env->gdt);
253 cpu_put_seg(f, &env->idt);
255 qemu_put_be32s(f, &env->sysenter_cs);
256 qemu_put_betls(f, &env->sysenter_esp);
257 qemu_put_betls(f, &env->sysenter_eip);
259 qemu_put_betls(f, &env->cr[0]);
260 qemu_put_betls(f, &env->cr[2]);
261 qemu_put_betls(f, &env->cr[3]);
262 qemu_put_betls(f, &env->cr[4]);
264 for(i = 0; i < 8; i++)
265 qemu_put_betls(f, &env->dr[i]);
267 /* MMU */
268 qemu_put_sbe32s(f, &env->a20_mask);
270 /* XMM */
271 qemu_put_be32s(f, &env->mxcsr);
272 for(i = 0; i < CPU_NB_REGS; i++) {
273 cpu_put_xmm_reg(f, &env->xmm_regs[i]);
276 #ifdef TARGET_X86_64
277 qemu_put_be64s(f, &env->efer);
278 qemu_put_be64s(f, &env->star);
279 qemu_put_be64s(f, &env->lstar);
280 qemu_put_be64s(f, &env->cstar);
281 qemu_put_be64s(f, &env->fmask);
282 qemu_put_be64s(f, &env->kernelgsbase);
283 #endif
284 qemu_put_be32s(f, &env->smbase);
286 qemu_put_be64s(f, &env->pat);
287 qemu_put_be32s(f, &env->hflags2);
289 qemu_put_be64s(f, &env->vm_hsave);
290 qemu_put_be64s(f, &env->vm_vmcb);
291 qemu_put_be64s(f, &env->tsc_offset);
292 qemu_put_be64s(f, &env->intercept);
293 qemu_put_be16s(f, &env->intercept_cr_read);
294 qemu_put_be16s(f, &env->intercept_cr_write);
295 qemu_put_be16s(f, &env->intercept_dr_read);
296 qemu_put_be16s(f, &env->intercept_dr_write);
297 qemu_put_be32s(f, &env->intercept_exceptions);
298 qemu_put_8s(f, &env->v_tpr);
300 /* MTRRs */
301 for(i = 0; i < 11; i++)
302 qemu_put_be64s(f, &env->mtrr_fixed[i]);
303 qemu_put_be64s(f, &env->mtrr_deftype);
304 for(i = 0; i < 8; i++) {
305 cpu_put_mtrr_var(f, &env->mtrr_var[i]);
308 /* KVM-related states */
310 qemu_put_sbe32s(f, &env->pending_irq_vmstate);
311 qemu_put_be32s(f, &env->mp_state);
312 qemu_put_be64s(f, &env->tsc);
314 /* MCE */
315 qemu_put_be64s(f, &env->mcg_cap);
316 qemu_put_be64s(f, &env->mcg_status);
317 qemu_put_be64s(f, &env->mcg_ctl);
318 for (i = 0; i < MCE_BANKS_DEF * 4; i++) {
319 qemu_put_be64s(f, &env->mce_banks[i]);
321 qemu_put_be64s(f, &env->tsc_aux);
324 static int cpu_pre_load(void *opaque)
326 CPUState *env = opaque;
328 cpu_synchronize_state(env);
329 return 0;
332 static int cpu_post_load(void *opaque, int version_id)
334 CPUState *env = opaque;
335 int i;
337 /* XXX: restore FPU round state */
338 env->fpstt = (env->fpus_vmstate >> 11) & 7;
339 env->fpus = env->fpus_vmstate & ~0x3800;
340 env->fptag_vmstate ^= 0xff;
341 for(i = 0; i < 8; i++) {
342 env->fptags[i] = (env->fptag_vmstate >> i) & 1;
345 cpu_breakpoint_remove_all(env, BP_CPU);
346 cpu_watchpoint_remove_all(env, BP_CPU);
347 for (i = 0; i < 4; i++)
348 hw_breakpoint_insert(env, i);
350 if (version_id >= 9) {
351 memset(&env->interrupt_bitmap, 0, sizeof(env->interrupt_bitmap));
352 if (env->pending_irq_vmstate >= 0) {
353 env->interrupt_bitmap[env->pending_irq_vmstate / 64] |=
354 (uint64_t)1 << (env->pending_irq_vmstate % 64);
358 return cpu_post_load(env, version_id);
361 int cpu_load(QEMUFile *f, void *opaque, int version_id)
363 CPUState *env = opaque;
364 int i, guess_mmx;
366 cpu_pre_load(env);
368 if (version_id < 3 || version_id > CPU_SAVE_VERSION)
369 return -EINVAL;
370 for(i = 0; i < CPU_NB_REGS; i++)
371 qemu_get_betls(f, &env->regs[i]);
372 qemu_get_betls(f, &env->eip);
373 qemu_get_betls(f, &env->eflags);
374 qemu_get_be32s(f, &env->hflags);
376 qemu_get_be16s(f, &env->fpuc);
377 qemu_get_be16s(f, &env->fpus_vmstate);
378 qemu_get_be16s(f, &env->fptag_vmstate);
379 qemu_get_be16s(f, &env->fpregs_format_vmstate);
381 guess_mmx = ((env->fptag_vmstate == 0xff) && (env->fpus_vmstate & 0x3800) == 0);
383 for(i = 0; i < 8; i++) {
384 #ifdef USE_X86LDOUBLE
385 switch(env->fpregs_format_vmstate) {
386 case 0:
387 get_fpreg(f, &env->fpregs[i], 0);
388 break;
389 case 1:
390 if (guess_mmx) {
391 get_fpreg_1_mmx(f, &env->fpregs[i], 0);
392 } else {
393 get_fpreg_1_no_mmx(f, &env->fpregs[i], 0);
395 break;
396 default:
397 return -EINVAL;
399 #else
400 switch(env->fpregs_format_vmstate) {
401 case 0:
402 if (guess_mmx) {
403 get_fpreg_0_mmx(f, &env->fpregs[i], 0);
404 } else {
405 get_fpreg_0_no_mmx(f, &env->fpregs[i], 0);
407 break;
408 case 1:
409 get_fpreg(f, &env->fpregs[i], 0);
410 break;
411 default:
412 return -EINVAL;
414 #endif
417 for(i = 0; i < 6; i++)
418 cpu_get_seg(f, &env->segs[i]);
419 cpu_get_seg(f, &env->ldt);
420 cpu_get_seg(f, &env->tr);
421 cpu_get_seg(f, &env->gdt);
422 cpu_get_seg(f, &env->idt);
424 qemu_get_be32s(f, &env->sysenter_cs);
425 if (version_id >= 7) {
426 qemu_get_betls(f, &env->sysenter_esp);
427 qemu_get_betls(f, &env->sysenter_eip);
428 } else {
429 env->sysenter_esp = qemu_get_be32(f);
430 env->sysenter_eip = qemu_get_be32(f);
433 qemu_get_betls(f, &env->cr[0]);
434 qemu_get_betls(f, &env->cr[2]);
435 qemu_get_betls(f, &env->cr[3]);
436 qemu_get_betls(f, &env->cr[4]);
438 for(i = 0; i < 8; i++)
439 qemu_get_betls(f, &env->dr[i]);
441 qemu_get_sbe32s(f, &env->a20_mask);
443 qemu_get_be32s(f, &env->mxcsr);
444 for(i = 0; i < CPU_NB_REGS; i++) {
445 cpu_get_xmm_reg(f, &env->xmm_regs[i]);
448 #ifdef TARGET_X86_64
449 qemu_get_be64s(f, &env->efer);
450 qemu_get_be64s(f, &env->star);
451 qemu_get_be64s(f, &env->lstar);
452 qemu_get_be64s(f, &env->cstar);
453 qemu_get_be64s(f, &env->fmask);
454 qemu_get_be64s(f, &env->kernelgsbase);
455 #endif
456 if (version_id >= 4) {
457 qemu_get_be32s(f, &env->smbase);
459 if (version_id >= 5) {
460 qemu_get_be64s(f, &env->pat);
461 qemu_get_be32s(f, &env->hflags2);
462 if (version_id < 6)
463 qemu_get_be32s(f, &env->halted);
465 qemu_get_be64s(f, &env->vm_hsave);
466 qemu_get_be64s(f, &env->vm_vmcb);
467 qemu_get_be64s(f, &env->tsc_offset);
468 qemu_get_be64s(f, &env->intercept);
469 qemu_get_be16s(f, &env->intercept_cr_read);
470 qemu_get_be16s(f, &env->intercept_cr_write);
471 qemu_get_be16s(f, &env->intercept_dr_read);
472 qemu_get_be16s(f, &env->intercept_dr_write);
473 qemu_get_be32s(f, &env->intercept_exceptions);
474 qemu_get_8s(f, &env->v_tpr);
477 if (version_id >= 8) {
478 /* MTRRs */
479 for(i = 0; i < 11; i++)
480 qemu_get_be64s(f, &env->mtrr_fixed[i]);
481 qemu_get_be64s(f, &env->mtrr_deftype);
482 for(i = 0; i < 8; i++) {
483 cpu_get_mtrr_var(f, &env->mtrr_var[i]);
487 if (version_id >= 9) {
488 qemu_get_sbe32s(f, &env->pending_irq_vmstate);
489 qemu_get_be32s(f, &env->mp_state);
490 qemu_get_be64s(f, &env->tsc);
493 if (version_id >= 10) {
494 qemu_get_be64s(f, &env->mcg_cap);
495 qemu_get_be64s(f, &env->mcg_status);
496 qemu_get_be64s(f, &env->mcg_ctl);
497 for (i = 0; i < MCE_BANKS_DEF * 4; i++) {
498 qemu_get_be64s(f, &env->mce_banks[i]);
502 if (version_id >= 11) {
503 qemu_get_be64s(f, &env->tsc_aux);
506 tlb_flush(env, 1);
507 return 0;