blob: 6f40a8160bb1cceda902978403666576e80290a4 [file] [log] [blame]
#include "hw/hw.h"
#include "hw/boards.h"
#include "hw/i386/pc.h"
#include "hw/isa/isa.h"
#include "cpu.h"
#include "sysemu/kvm.h"
static const VMStateDescription vmstate_segment = {
.name = "segment",
.version_id = 1,
.minimum_version_id = 1,
.minimum_version_id_old = 1,
.fields = (VMStateField []) {
VMSTATE_UINT32(selector, SegmentCache),
VMSTATE_UINTTL(base, SegmentCache),
VMSTATE_UINT32(limit, SegmentCache),
VMSTATE_UINT32(flags, SegmentCache),
VMSTATE_END_OF_LIST()
}
};
#define VMSTATE_SEGMENT(_field, _state) { \
.name = (stringify(_field)), \
.size = sizeof(SegmentCache), \
.vmsd = &vmstate_segment, \
.flags = VMS_STRUCT, \
.offset = offsetof(_state, _field) \
+ type_check(SegmentCache,typeof_field(_state, _field)) \
}
#define VMSTATE_SEGMENT_ARRAY(_field, _state, _n) \
VMSTATE_STRUCT_ARRAY(_field, _state, _n, 0, vmstate_segment, SegmentCache)
static const VMStateDescription vmstate_xmm_reg = {
.name = "xmm_reg",
.version_id = 1,
.minimum_version_id = 1,
.minimum_version_id_old = 1,
.fields = (VMStateField []) {
VMSTATE_UINT64(XMM_Q(0), XMMReg),
VMSTATE_UINT64(XMM_Q(1), XMMReg),
VMSTATE_END_OF_LIST()
}
};
#define VMSTATE_XMM_REGS(_field, _state, _n) \
VMSTATE_STRUCT_ARRAY(_field, _state, _n, 0, vmstate_xmm_reg, XMMReg)
static const VMStateDescription vmstate_mtrr_var = {
.name = "mtrr_var",
.version_id = 1,
.minimum_version_id = 1,
.minimum_version_id_old = 1,
.fields = (VMStateField []) {
VMSTATE_UINT64(base, MTRRVar),
VMSTATE_UINT64(mask, MTRRVar),
VMSTATE_END_OF_LIST()
}
};
#define VMSTATE_MTRR_VARS(_field, _state, _n) \
VMSTATE_STRUCT_ARRAY(_field, _state, _n, 0, vmstate_mtrr_var, MTRRVar)
static int get_fpregs(QEMUFile *f, void *opaque, size_t size)
{
X86CPU *cpu = opaque;
CPUX86State *env = &cpu->env;
int i;
for (i = 0; i < 8; ++i) {
uint64_t mant;
qemu_get_be64s(f, &mant);
env->fpregs[i].mmx.MMX_Q(0) = mant;
}
return 0;
}
static void put_fpregs(QEMUFile *f, void *opaque, size_t size)
{
X86CPU *cpu = opaque;
CPUX86State *env = &cpu->env;
int i;
for (i = 0; i < 8; ++i) {
qemu_put_be64(f, env->fpregs[i].mmx.MMX_Q(0));
}
}
static const VMStateInfo vmstate_fpregs = {
.name = "fpregs",
.get = get_fpregs,
.put = put_fpregs,
};
#define VMSTATE_FPREGS(_field, _state) \
{ \
.name = "cpu/fpregs", \
.version_id = 1, \
.info = &vmstate_fpregs, \
}
static void put_mce_banks(QEMUFile *f, void *opaque, size_t size)
{
X86CPU *cpu = opaque;
CPUX86State *env = &cpu->env;
int i;
for (i = 0; i < (env->mcg_cap & 0xff); i++) {
qemu_put_be64s(f, &env->mce_banks[4*i]);
qemu_put_be64s(f, &env->mce_banks[4*i + 1]);
qemu_put_be64s(f, &env->mce_banks[4*i + 2]);
qemu_put_be64s(f, &env->mce_banks[4*i + 3]);
}
}
static int get_mce_banks(QEMUFile *f, void *opaque, size_t size)
{
X86CPU *cpu = opaque;
CPUX86State *env = &cpu->env;
int i;
for (i = 0; i < (env->mcg_cap & 0xff); i++) {
qemu_get_be64s(f, &env->mce_banks[4*i]);
qemu_get_be64s(f, &env->mce_banks[4*i + 1]);
qemu_get_be64s(f, &env->mce_banks[4*i + 2]);
qemu_get_be64s(f, &env->mce_banks[4*i + 3]);
}
return 0;
}
static const VMStateInfo vmstate_mce_banks = {
.name = "mce_banks",
.get = get_mce_banks,
.put = put_mce_banks,
};
static const VMStateDescription vmstate_mcg_cap = {
.name = "cpu/mcg_cap",
.version_id = 1,
.minimum_version_id = 1,
.minimum_version_id_old = 1,
.fields = (VMStateField []) {
VMSTATE_UINT64(env.mcg_status, X86CPU),
VMSTATE_UINT64(env.mcg_ctl, X86CPU),
{
.name = "mce_banks",
.version_id = 1,
.info = &vmstate_mce_banks,
},
VMSTATE_END_OF_LIST()
}
};
static bool mce_banks_exists(void *opaque, int version_id)
{
X86CPU *cpu = opaque;
CPUX86State *env = &cpu->env;
return (env->mcg_cap != 0);
}
#define VMSTATE_MCG_CAP(_field, _state) \
{ \
.name = "cpu/mcg_cap", \
.offset = 0, \
.flags = VMS_SINGLE, \
.vmsd = &vmstate_mcg_cap, \
.field_exists = mce_banks_exists, \
}
static void cpu_pre_save(void *opaque)
{
X86CPU* cpu = opaque;
CPUX86State *env = &cpu->env;
int i;
/* FPU */
env->fpus_vmstate = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
env->fptag_vmstate = 0;
for (i = 0; i < 8; ++i) {
env->fptag_vmstate |= ((!env->fptags[i]) << i);
}
env->fpregs_format_vmstate = 1;
}
static int cpu_post_load(void *opaque, int version_id)
{
X86CPU *cpu = opaque;
CPUState *cs = CPU(cpu);
CPUX86State *env = &cpu->env;
int i;
/* XXX: restore FPU round state */
env->fpstt = (env->fpus_vmstate >> 11) & 7;
env->fpus = env->fpus_vmstate & ~0x3800;
env->fptag_vmstate ^= 0xff;
for(i = 0; i < 8; i++) {
env->fptags[i] = (env->fptag_vmstate >> i) & 1;
}
cpu_breakpoint_remove_all(cs, BP_CPU);
cpu_watchpoint_remove_all(cs, BP_CPU);
for (i = 0; i < 4; i++) {
hw_breakpoint_insert(env, i);
}
tlb_flush(cs, 1);
return 0;
}
const VMStateDescription vmstate_cpu_x86 = {
.name = "cpu",
.version_id = 11,
.minimum_version_id = 11,
.minimum_version_id_old = 11,
.pre_save = cpu_pre_save,
.post_load = cpu_post_load,
.fields = (VMStateField []) {
VMSTATE_UINTTL_ARRAY(env.regs, X86CPU, CPU_NB_REGS),
VMSTATE_UINTTL(env.eip, X86CPU),
VMSTATE_UINTTL(env.eflags, X86CPU),
VMSTATE_UINT32(env.hflags, X86CPU),
/* FPU */
VMSTATE_UINT16(env.fpuc, X86CPU),
VMSTATE_UINT16(env.fpus_vmstate, X86CPU),
VMSTATE_UINT16(env.fptag_vmstate, X86CPU),
VMSTATE_UINT16(env.fpregs_format_vmstate, X86CPU),
VMSTATE_FPREGS(env, X86CPU),
VMSTATE_SEGMENT_ARRAY(env.segs, X86CPU, 6),
VMSTATE_SEGMENT(env.ldt, X86CPU),
VMSTATE_SEGMENT(env.tr, X86CPU),
VMSTATE_SEGMENT(env.gdt, X86CPU),
VMSTATE_SEGMENT(env.idt, X86CPU),
VMSTATE_UINT32(env.sysenter_cs, X86CPU),
VMSTATE_UINTTL(env.sysenter_esp, X86CPU),
VMSTATE_UINTTL(env.sysenter_eip, X86CPU),
VMSTATE_UINTTL(env.cr[0], X86CPU),
VMSTATE_UINTTL(env.cr[2], X86CPU),
VMSTATE_UINTTL(env.cr[3], X86CPU),
VMSTATE_UINTTL(env.cr[4], X86CPU),
VMSTATE_UINTTL_ARRAY(env.dr, X86CPU, 8),
/* MMU */
VMSTATE_INT32(env.a20_mask, X86CPU),
/* XMM */
VMSTATE_UINT32(env.mxcsr, X86CPU),
VMSTATE_XMM_REGS(env.xmm_regs, X86CPU, CPU_NB_REGS),
VMSTATE_UINT64(env.efer, X86CPU),
VMSTATE_UINT64(env.star, X86CPU),
#ifdef TARGET_X86_64
VMSTATE_UINT64(env.lstar, X86CPU),
VMSTATE_UINT64(env.cstar, X86CPU),
VMSTATE_UINT64(env.fmask, X86CPU),
VMSTATE_UINT64(env.kernelgsbase, X86CPU),
#endif
VMSTATE_UINT32(env.smbase, X86CPU),
VMSTATE_UINT64(env.pat, X86CPU),
VMSTATE_UINT32(env.hflags2, X86CPU),
VMSTATE_UINT64(env.vm_hsave, X86CPU),
VMSTATE_UINT64(env.vm_vmcb, X86CPU),
VMSTATE_UINT64(env.tsc_offset, X86CPU),
VMSTATE_UINT64(env.intercept, X86CPU),
VMSTATE_UINT16(env.intercept_cr_read, X86CPU),
VMSTATE_UINT16(env.intercept_cr_write, X86CPU),
VMSTATE_UINT16(env.intercept_dr_read, X86CPU),
VMSTATE_UINT16(env.intercept_dr_write, X86CPU),
VMSTATE_UINT32(env.intercept_exceptions, X86CPU),
VMSTATE_UINT8(env.v_tpr, X86CPU),
/* MTRRs */
VMSTATE_UINT64_ARRAY(env.mtrr_fixed, X86CPU, 11),
VMSTATE_UINT64(env.mtrr_deftype, X86CPU),
VMSTATE_MTRR_VARS(env.mtrr_var, X86CPU, 8),
VMSTATE_UINT64_ARRAY(env.interrupt_bitmap, X86CPU, 256 / 64),
VMSTATE_UINT64(env.tsc, X86CPU),
VMSTATE_UINT32(env.mp_state, X86CPU),
/* MCE */
VMSTATE_UINT64(env.mcg_cap, X86CPU),
VMSTATE_MCG_CAP(env, X86CPU),
VMSTATE_END_OF_LIST()
},
};