@@ -874,7 +874,7 @@ static int read_msr(unsigned int reg, ui
struct vcpu *curr = current;
const struct domain *currd = curr->domain;
const struct cpuid_policy *cp = currd->arch.cpuid;
- bool vpmu_msr = false;
+ bool vpmu_msr = false, warn = false;
uint64_t tmp;
int ret;
@@ -883,7 +883,7 @@ static int read_msr(unsigned int reg, ui
if ( ret == X86EMUL_EXCEPTION )
x86_emul_hw_exception(TRAP_gp_fault, 0, ctxt);
- return ret;
+ goto done;
}
switch ( reg )
@@ -993,7 +993,7 @@ static int read_msr(unsigned int reg, ui
return X86EMUL_OKAY;
}
- gdprintk(XENLOG_WARNING, "RDMSR 0x%08x unimplemented\n", reg);
+ warn = true;
break;
normal:
@@ -1002,7 +1002,19 @@ static int read_msr(unsigned int reg, ui
return X86EMUL_OKAY;
}
- return X86EMUL_UNHANDLEABLE;
+ done:
+ if ( ret != X86EMUL_OKAY && !curr->arch.pv.trap_ctxt[X86_EXC_GP].address &&
+ (reg >> 16) != 0x4000 && !rdmsr_safe(reg, tmp) )
+ {
+ gprintk(XENLOG_WARNING, "faking RDMSR 0x%08x\n", reg);
+ *val = 0;
+ x86_emul_reset_event(ctxt);
+ ret = X86EMUL_OKAY;
+ }
+ else if ( warn )
+ gdprintk(XENLOG_WARNING, "RDMSR 0x%08x unimplemented\n", reg);
+
+ return ret;
}
static int write_msr(unsigned int reg, uint64_t val,
@@ -143,6 +143,12 @@ typedef unsigned long xen_ulong_t;
* Level == 1: Kernel may enter
* Level == 2: Kernel may enter
* Level == 3: Everyone may enter
+ *
+ * Note: For compatibility with kernels not setting up exception handlers
+ * early enough, Xen will avoid trying to inject #GP (and hence crash
+ * the domain) when an RDMSR would require this, but no handler was
+ * set yet. The precise conditions are implementation specific, and
+ * new code may not rely on such behavior anyway.
*/
#define TI_GET_DPL(_ti) ((_ti)->flags & 3)
#define TI_GET_IF(_ti) ((_ti)->flags & 4)