Skip to content

Commit

Permalink
target-i386: preserve FPU and MSR state on INIT
Browse files Browse the repository at this point in the history
Most MSRs, plus the FPU, MMX, MXCSR, XMM and YMM registers should not
be zeroed on INIT (Table 9-1 in the Intel SDM).  Copy them out of
CPUX86State and back in, instead of special casing env->pat.

The relevant fields are already consecutive except PAT and SMBASE.
However:

- KVM and Hyper-V MSRs should be reset because they include memory
locations written by the hypervisor.  These MSRs are moved together
at the end of the preserved area.

- SVM state can be moved out of the way since it is written by VMRUN.

Cc: Andreas Faerber <afaerber@suse.de>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
  • Loading branch information
bonzini committed May 13, 2014
1 parent 05e7e81 commit 43175fa
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 20 deletions.
3 changes: 1 addition & 2 deletions target-i386/cpu.c
Expand Up @@ -2418,8 +2418,7 @@ static void x86_cpu_reset(CPUState *s)

xcc->parent_reset(s);


memset(env, 0, offsetof(CPUX86State, pat));
memset(env, 0, offsetof(CPUX86State, cpuid_level));

tlb_flush(s, 1);

Expand Down
42 changes: 26 additions & 16 deletions target-i386/cpu.h
Expand Up @@ -801,6 +801,9 @@ typedef struct CPUX86State {
BNDCSReg bndcs_regs;
uint64_t msr_bndcfgs;

/* Beginning of state preserved by INIT (dummy marker). */
struct {} start_init_save;

/* FPU state */
unsigned int fpstt; /* top of stack index */
uint16_t fpus;
Expand Down Expand Up @@ -833,27 +836,13 @@ typedef struct CPUX86State {
uint64_t star;

uint64_t vm_hsave;
uint64_t vm_vmcb;
uint64_t tsc_offset;
uint64_t intercept;
uint16_t intercept_cr_read;
uint16_t intercept_cr_write;
uint16_t intercept_dr_read;
uint16_t intercept_dr_write;
uint32_t intercept_exceptions;
uint8_t v_tpr;

#ifdef TARGET_X86_64
target_ulong lstar;
target_ulong cstar;
target_ulong fmask;
target_ulong kernelgsbase;
#endif
uint64_t system_time_msr;
uint64_t wall_clock_msr;
uint64_t steal_time_msr;
uint64_t async_pf_en_msr;
uint64_t pv_eoi_en_msr;

uint64_t tsc;
uint64_t tsc_adjust;
Expand All @@ -870,6 +859,19 @@ typedef struct CPUX86State {
uint64_t msr_fixed_counters[MAX_FIXED_COUNTERS];
uint64_t msr_gp_counters[MAX_GP_COUNTERS];
uint64_t msr_gp_evtsel[MAX_GP_COUNTERS];

uint64_t pat;
uint32_t smbase;

/* End of state preserved by INIT (dummy marker). */
struct {} end_init_save;

uint64_t system_time_msr;
uint64_t wall_clock_msr;
uint64_t steal_time_msr;
uint64_t async_pf_en_msr;
uint64_t pv_eoi_en_msr;

uint64_t msr_hv_hypercall;
uint64_t msr_hv_guest_os_id;
uint64_t msr_hv_vapic;
Expand All @@ -884,17 +886,25 @@ typedef struct CPUX86State {
struct CPUBreakpoint *cpu_breakpoint[4];
struct CPUWatchpoint *cpu_watchpoint[4];
}; /* break/watchpoints for dr[0..3] */
uint32_t smbase;
int old_exception; /* exception in flight */

uint64_t vm_vmcb;
uint64_t tsc_offset;
uint64_t intercept;
uint16_t intercept_cr_read;
uint16_t intercept_cr_write;
uint16_t intercept_dr_read;
uint16_t intercept_dr_write;
uint32_t intercept_exceptions;
uint8_t v_tpr;

/* KVM states, automatically cleared on reset */
uint8_t nmi_injected;
uint8_t nmi_pending;

CPU_COMMON

/* Fields from here on are preserved across CPU reset. */
uint64_t pat;

/* processor features (e.g. for CPUID insn) */
uint32_t cpuid_level;
Expand Down
10 changes: 8 additions & 2 deletions target-i386/helper.c
Expand Up @@ -1330,12 +1330,18 @@ void do_cpu_init(X86CPU *cpu)
{
CPUState *cs = CPU(cpu);
CPUX86State *env = &cpu->env;
CPUX86State *save = g_new(CPUX86State, 1);
int sipi = cs->interrupt_request & CPU_INTERRUPT_SIPI;
uint64_t pat = env->pat;

*save = *env;

cpu_reset(cs);
cs->interrupt_request = sipi;
env->pat = pat;
memcpy(&env->start_init_save, &save->start_init_save,
offsetof(CPUX86State, end_init_save) -
offsetof(CPUX86State, start_init_save));
g_free(save);

if (kvm_enabled()) {
kvm_arch_do_init_vcpu(cpu);
}
Expand Down

0 comments on commit 43175fa

Please sign in to comment.