aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--tools/libxc/xc_cpufeature.h1
-rw-r--r--tools/libxc/xc_cpuid_x86.c3
-rw-r--r--xen/arch/x86/hvm/hvm.c10
-rw-r--r--xen/arch/x86/hvm/vlapic.c202
-rw-r--r--xen/include/asm-x86/hvm/hvm.h3
-rw-r--r--xen/include/asm-x86/hvm/vlapic.h2
-rw-r--r--xen/include/asm-x86/msr-index.h1
7 files changed, 164 insertions, 58 deletions
diff --git a/tools/libxc/xc_cpufeature.h b/tools/libxc/xc_cpufeature.h
index 96991a6813..b1731d2f4a 100644
--- a/tools/libxc/xc_cpufeature.h
+++ b/tools/libxc/xc_cpufeature.h
@@ -98,6 +98,7 @@
#define X86_FEATURE_DCA (4*32+18) /* Direct Cache Access */
#define X86_FEATURE_SSE4_1 (4*32+19) /* Streaming SIMD Extensions 4.1 */
#define X86_FEATURE_SSE4_2 (4*32+20) /* Streaming SIMD Extensions 4.2 */
+#define X86_FEATURE_X2APIC (4*32+21) /* x2APIC */
#define X86_FEATURE_POPCNT (4*32+23) /* POPCNT instruction */
#define X86_FEATURE_AES (4*32+25) /* AES acceleration instructions */
#define X86_FEATURE_XSAVE (4*32+26) /* XSAVE/XRSTOR/XSETBV/XGETBV */
diff --git a/tools/libxc/xc_cpuid_x86.c b/tools/libxc/xc_cpuid_x86.c
index 7d963a903e..5df426ce6c 100644
--- a/tools/libxc/xc_cpuid_x86.c
+++ b/tools/libxc/xc_cpuid_x86.c
@@ -208,7 +208,8 @@ static void xc_cpuid_hvm_policy(
(bitmaskof(X86_FEATURE_AVX) |
bitmaskof(X86_FEATURE_XSAVE)) : 0);
- regs[2] |= bitmaskof(X86_FEATURE_HYPERVISOR);
+ regs[2] |= (bitmaskof(X86_FEATURE_HYPERVISOR) |
+ bitmaskof(X86_FEATURE_X2APIC));
regs[3] &= (bitmaskof(X86_FEATURE_FPU) |
bitmaskof(X86_FEATURE_VME) |
diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c
index bb50b61131..544286a1ff 100644
--- a/xen/arch/x86/hvm/hvm.c
+++ b/xen/arch/x86/hvm/hvm.c
@@ -2205,6 +2205,11 @@ int hvm_msr_read_intercept(unsigned int msr, uint64_t *msr_content)
*msr_content = vcpu_vlapic(v)->hw.apic_base_msr;
break;
+ case MSR_IA32_APICBASE_MSR ... MSR_IA32_APICBASE_MSR + 0x3ff:
+ if ( hvm_x2apic_msr_read(v, msr, msr_content) )
+ goto gp_fault;
+ break;
+
case MSR_IA32_CR_PAT:
*msr_content = v->arch.hvm_vcpu.pat_cr;
break;
@@ -2312,6 +2317,11 @@ int hvm_msr_write_intercept(unsigned int msr, uint64_t msr_content)
vlapic_msr_set(vcpu_vlapic(v), msr_content);
break;
+ case MSR_IA32_APICBASE_MSR ... MSR_IA32_APICBASE_MSR + 0x3ff:
+ if ( hvm_x2apic_msr_write(v, msr, msr_content) )
+ goto gp_fault;
+ break;
+
case MSR_IA32_CR_PAT:
if ( !pat_msr_set(&v->arch.hvm_vcpu.pat_cr, msr_content) )
goto gp_fault;
diff --git a/xen/arch/x86/hvm/vlapic.c b/xen/arch/x86/hvm/vlapic.c
index f394518caf..483588a99b 100644
--- a/xen/arch/x86/hvm/vlapic.c
+++ b/xen/arch/x86/hvm/vlapic.c
@@ -172,7 +172,13 @@ static uint32_t vlapic_get_ppr(struct vlapic *vlapic)
static int vlapic_match_logical_addr(struct vlapic *vlapic, uint8_t mda)
{
int result = 0;
- uint8_t logical_id;
+ uint32_t logical_id;
+
+ if ( vlapic_x2apic_mode(vlapic) )
+ {
+ logical_id = vlapic_get_reg(vlapic, APIC_LDR);
+ return !!(logical_id & mda);
+ }
logical_id = GET_xAPIC_LOGICAL_ID(vlapic_get_reg(vlapic, APIC_LDR));
@@ -392,7 +398,7 @@ void vlapic_EOI_set(struct vlapic *vlapic)
int vlapic_ipi(
struct vlapic *vlapic, uint32_t icr_low, uint32_t icr_high)
{
- unsigned int dest = GET_xAPIC_DEST_FIELD(icr_high);
+ unsigned int dest;
unsigned int short_hand = icr_low & APIC_SHORT_MASK;
unsigned int dest_mode = !!(icr_low & APIC_DEST_MASK);
struct vlapic *target;
@@ -401,6 +407,10 @@ int vlapic_ipi(
HVM_DBG_LOG(DBG_LEVEL_VLAPIC, "icr = 0x%08x:%08x", icr_high, icr_low);
+ dest = (vlapic_x2apic_mode(vlapic)
+ ? icr_high
+ : GET_xAPIC_DEST_FIELD(icr_high));
+
if ( (icr_low & APIC_MODE_MASK) == APIC_DM_LOWEST )
{
target = vlapic_lowest_prio(vlapic_domain(vlapic), vlapic,
@@ -528,65 +538,42 @@ static int vlapic_read(
return X86EMUL_OKAY;
}
+int hvm_x2apic_msr_read(struct vcpu *v, unsigned int msr, uint64_t *msr_content)
+{
+ struct vlapic *vlapic = vcpu_vlapic(v);
+ uint32_t low, high = 0, offset = (msr - MSR_IA32_APICBASE_MSR) << 4;
+
+ if ( !vlapic_x2apic_mode(vlapic) )
+ return 1;
+
+ vlapic_read_aligned(vlapic, offset, &low);
+ if ( offset == APIC_ICR )
+ vlapic_read_aligned(vlapic, APIC_ICR2, &high);
+
+ *msr_content = (((uint64_t)high) << 32) | low;
+ return 0;
+}
+
static void vlapic_pt_cb(struct vcpu *v, void *data)
{
*(s_time_t *)data = hvm_get_guest_time(v);
}
-static int vlapic_write(struct vcpu *v, unsigned long address,
- unsigned long len, unsigned long val)
+static int vlapic_reg_write(struct vcpu *v,
+ unsigned int offset, unsigned long val)
{
struct vlapic *vlapic = vcpu_vlapic(v);
- unsigned int offset = address - vlapic_base_address(vlapic);
int rc = X86EMUL_OKAY;
- if ( offset != 0xb0 )
- HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
- "offset 0x%x with length 0x%lx, and value is 0x%lx",
- offset, len, val);
-
- /*
- * According to the IA32 Manual, all accesses should be 32 bits.
- * Some OSes do 8- or 16-byte accesses, however.
- */
- val = (uint32_t)val;
- if ( len != 4 )
- {
- unsigned int tmp;
- unsigned char alignment;
-
- gdprintk(XENLOG_INFO, "Notice: Local APIC write with len = %lx\n",len);
-
- alignment = offset & 0x3;
- (void)vlapic_read_aligned(vlapic, offset & ~0x3, &tmp);
-
- switch ( len )
- {
- case 1:
- val = ((tmp & ~(0xff << (8*alignment))) |
- ((val & 0xff) << (8*alignment)));
- break;
-
- case 2:
- if ( alignment & 1 )
- goto unaligned_exit_and_crash;
- val = ((tmp & ~(0xffff << (8*alignment))) |
- ((val & 0xffff) << (8*alignment)));
- break;
-
- default:
- gdprintk(XENLOG_ERR, "Local APIC write with len = %lx, "
- "should be 4 instead\n", len);
- goto exit_and_crash;
- }
- }
- else if ( (offset & 0x3) != 0 )
- goto unaligned_exit_and_crash;
-
- offset &= ~0x3;
-
switch ( offset )
{
+ case APIC_ID:
+ if ( !vlapic_x2apic_mode(vlapic) )
+ vlapic_set_reg(vlapic, APIC_ID, val);
+ else
+ rc = X86EMUL_UNHANDLEABLE;
+ break;
+
case APIC_TASKPRI:
vlapic_set_reg(vlapic, APIC_TASKPRI, val & 0xff);
break;
@@ -596,11 +583,17 @@ static int vlapic_write(struct vcpu *v, unsigned long address,
break;
case APIC_LDR:
- vlapic_set_reg(vlapic, APIC_LDR, val & APIC_LDR_MASK);
+ if ( !vlapic_x2apic_mode(vlapic) )
+ vlapic_set_reg(vlapic, APIC_LDR, val & APIC_LDR_MASK);
+ else
+ rc = X86EMUL_UNHANDLEABLE;
break;
case APIC_DFR:
- vlapic_set_reg(vlapic, APIC_DFR, val | 0x0FFFFFFF);
+ if ( !vlapic_x2apic_mode(vlapic) )
+ vlapic_set_reg(vlapic, APIC_DFR, val | 0x0FFFFFFF);
+ else
+ rc = X86EMUL_UNHANDLEABLE;
break;
case APIC_SPIV:
@@ -628,7 +621,19 @@ static int vlapic_write(struct vcpu *v, unsigned long address,
break;
case APIC_ESR:
- /* Nothing to do. */
+ if ( vlapic_x2apic_mode(vlapic) && (val != 0) )
+ {
+ gdprintk(XENLOG_ERR, "Local APIC write ESR with non-zero %lx\n",
+ val);
+ rc = X86EMUL_UNHANDLEABLE;
+ }
+ break;
+
+ case APIC_SELF_IPI:
+ if ( vlapic_x2apic_mode(vlapic) )
+ vlapic_reg_write(v, APIC_ICR, 0x40000 | (val & 0xff));
+ else
+ rc = X86EMUL_UNHANDLEABLE;
break;
case APIC_ICR:
@@ -639,7 +644,9 @@ static int vlapic_write(struct vcpu *v, unsigned long address,
break;
case APIC_ICR2:
- vlapic_set_reg(vlapic, APIC_ICR2, val & 0xff000000);
+ if ( !vlapic_x2apic_mode(vlapic) )
+ val &= 0xff000000;
+ vlapic_set_reg(vlapic, APIC_ICR2, val);
break;
case APIC_LVTT: /* LVT Timer Reg */
@@ -696,12 +703,67 @@ static int vlapic_write(struct vcpu *v, unsigned long address,
break;
default:
- gdprintk(XENLOG_DEBUG,
- "Local APIC Write to read-only register 0x%x\n", offset);
break;
}
-
+ if (rc == X86EMUL_UNHANDLEABLE)
+ gdprintk(XENLOG_DEBUG,
+ "Local APIC Write wrong to register 0x%x\n", offset);
return rc;
+}
+
+static int vlapic_write(struct vcpu *v, unsigned long address,
+ unsigned long len, unsigned long val)
+{
+ struct vlapic *vlapic = vcpu_vlapic(v);
+ unsigned int offset = address - vlapic_base_address(vlapic);
+ int rc = X86EMUL_OKAY;
+
+ if ( offset != 0xb0 )
+ HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
+ "offset 0x%x with length 0x%lx, and value is 0x%lx",
+ offset, len, val);
+
+ /*
+ * According to the IA32 Manual, all accesses should be 32 bits.
+ * Some OSes do 8- or 16-byte accesses, however.
+ */
+ val = (uint32_t)val;
+ if ( len != 4 )
+ {
+ unsigned int tmp;
+ unsigned char alignment;
+
+ gdprintk(XENLOG_INFO, "Notice: Local APIC write with len = %lx\n",len);
+
+ alignment = offset & 0x3;
+ (void)vlapic_read_aligned(vlapic, offset & ~0x3, &tmp);
+
+ switch ( len )
+ {
+ case 1:
+ val = ((tmp & ~(0xff << (8*alignment))) |
+ ((val & 0xff) << (8*alignment)));
+ break;
+
+ case 2:
+ if ( alignment & 1 )
+ goto unaligned_exit_and_crash;
+ val = ((tmp & ~(0xffff << (8*alignment))) |
+ ((val & 0xffff) << (8*alignment)));
+ break;
+
+ default:
+ gdprintk(XENLOG_ERR, "Local APIC write with len = %lx, "
+ "should be 4 instead\n", len);
+ goto exit_and_crash;
+ }
+ }
+ else if ( (offset & 0x3) != 0 )
+ goto unaligned_exit_and_crash;
+
+ offset &= ~0x3;
+
+ return vlapic_reg_write(v, offset, val);
unaligned_exit_and_crash:
gdprintk(XENLOG_ERR, "Unaligned LAPIC write len=0x%lx at offset=0x%x.\n",
@@ -711,6 +773,25 @@ static int vlapic_write(struct vcpu *v, unsigned long address,
return rc;
}
+int hvm_x2apic_msr_write(struct vcpu *v, unsigned int msr, uint64_t msr_content)
+{
+ struct vlapic *vlapic = vcpu_vlapic(v);
+ uint32_t offset = (msr - MSR_IA32_APICBASE_MSR) << 4;
+ int rc;
+
+ if ( !vlapic_x2apic_mode(vlapic) )
+ return 1;
+
+ if ( offset == APIC_ICR )
+ if ( vlapic_reg_write(v, APIC_ICR2 , (uint32_t)(msr_content >> 32)) )
+ return 1;
+
+ rc = vlapic_reg_write(v, offset, (uint32_t)msr_content);
+
+ /* X86EMUL_RETRY for SIPI */
+ return ((rc != X86EMUL_OKAY) && (rc != X86EMUL_RETRY));
+}
+
static int vlapic_range(struct vcpu *v, unsigned long addr)
{
struct vlapic *vlapic = vcpu_vlapic(v);
@@ -743,6 +824,13 @@ void vlapic_msr_set(struct vlapic *vlapic, uint64_t value)
vlapic->hw.apic_base_msr = value;
+ if ( vlapic_x2apic_mode(vlapic) )
+ {
+ u32 id = vlapic_get_reg(vlapic, APIC_ID);
+ u32 ldr = ((id & ~0xf) << 16) | (1 << (id & 0xf));
+ vlapic_set_reg(vlapic, APIC_LDR, ldr);
+ }
+
vmx_vlapic_msr_changed(vlapic_vcpu(vlapic));
HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
diff --git a/xen/include/asm-x86/hvm/hvm.h b/xen/include/asm-x86/hvm/hvm.h
index 6a98e51a3b..4a7d379acd 100644
--- a/xen/include/asm-x86/hvm/hvm.h
+++ b/xen/include/asm-x86/hvm/hvm.h
@@ -364,4 +364,7 @@ bool_t hvm_hap_nested_page_fault(unsigned long gfn);
? (u32)__d->arch.incarnation : (u32)(v)->arch.hvm_vcpu.msr_tsc_aux; \
})
+int hvm_x2apic_msr_read(struct vcpu *v, unsigned int msr, uint64_t *msr_content);
+int hvm_x2apic_msr_write(struct vcpu *v, unsigned int msr, uint64_t msr_content);
+
#endif /* __ASM_X86_HVM_HVM_H__ */
diff --git a/xen/include/asm-x86/hvm/vlapic.h b/xen/include/asm-x86/hvm/vlapic.h
index 905fff8dae..702ba54276 100644
--- a/xen/include/asm-x86/hvm/vlapic.h
+++ b/xen/include/asm-x86/hvm/vlapic.h
@@ -51,6 +51,8 @@
#define vlapic_base_address(vlapic) \
((vlapic)->hw.apic_base_msr & MSR_IA32_APICBASE_BASE)
+#define vlapic_x2apic_mode(vlapic) \
+ ((vlapic)->hw.apic_base_msr & MSR_IA32_APICBASE_EXTD)
struct vlapic {
struct hvm_hw_lapic hw;
diff --git a/xen/include/asm-x86/msr-index.h b/xen/include/asm-x86/msr-index.h
index aebbe1389b..cc32932cd4 100644
--- a/xen/include/asm-x86/msr-index.h
+++ b/xen/include/asm-x86/msr-index.h
@@ -307,6 +307,7 @@
#define MSR_IA32_APICBASE_EXTD (1<<10)
#define MSR_IA32_APICBASE_ENABLE (1<<11)
#define MSR_IA32_APICBASE_BASE (0xfffff<<12)
+#define MSR_IA32_APICBASE_MSR 0x800
#define MSR_IA32_UCODE_WRITE 0x00000079
#define MSR_IA32_UCODE_REV 0x0000008b