In preparation to add support for the CMCI LVT, which is discontiguous to
the other LVTs, add a level of indirection. Rename the prior
vlapic_lvt_mask[] while doing so (as subsequently a 2nd array will want
adding, for use by guest_wrmsr_x2apic()).
Signed-off-by: Jan Beulich <jbeulich@suse.com>
---
The new name (lvt_valid[]) reflects its present contents. When re-based on
top of "x86/hvm: vlapic: fix RO bits emulation in LVTx regs", the name
wants to change to lvt_writable[] (or the 2nd array be added right away,
with lvt_valid[] then used by guest_wrmsr_x2apic()). Alternatively the
order of patches may want changing.
---
v2: Check incoming MAXLVT in lapic_check_regs().
--- a/xen/arch/x86/hvm/vlapic.c
+++ b/xen/arch/x86/hvm/vlapic.c
@@ -32,7 +32,16 @@
#include <public/hvm/params.h>
#define VLAPIC_VERSION 0x00050014
-#define VLAPIC_LVT_NUM 6
+#define LVT_BIAS(reg) (((reg) - APIC_LVTT) >> 4)
+
+#define LVTS \
+ LVT(LVTT), LVT(LVTTHMR), LVT(LVTPC), LVT(LVT0), LVT(LVT1), LVT(LVTERR),
+
+static const unsigned int lvt_reg[] = {
+#define LVT(which) APIC_ ## which
+ LVTS
+#undef LVT
+};
#define LVT_MASK \
(APIC_LVT_MASKED | APIC_SEND_PENDING | APIC_VECTOR_MASK)
@@ -41,20 +50,21 @@
(LVT_MASK | APIC_DM_MASK | APIC_INPUT_POLARITY |\
APIC_LVT_REMOTE_IRR | APIC_LVT_LEVEL_TRIGGER)
-static const unsigned int vlapic_lvt_mask[VLAPIC_LVT_NUM] =
+static const unsigned int lvt_valid[] =
{
- /* LVTT */
- LVT_MASK | APIC_TIMER_MODE_MASK,
- /* LVTTHMR */
- LVT_MASK | APIC_DM_MASK,
- /* LVTPC */
- LVT_MASK | APIC_DM_MASK,
- /* LVT0-1 */
- LINT_MASK, LINT_MASK,
- /* LVTERR */
- LVT_MASK
+#define LVTT_VALID (LVT_MASK | APIC_TIMER_MODE_MASK)
+#define LVTTHMR_VALID (LVT_MASK | APIC_DM_MASK)
+#define LVTPC_VALID (LVT_MASK | APIC_DM_MASK)
+#define LVT0_VALID LINT_MASK
+#define LVT1_VALID LINT_MASK
+#define LVTERR_VALID LVT_MASK
+#define LVT(which) [LVT_BIAS(APIC_ ## which)] = which ## _VALID
+ LVTS
+#undef LVT
};
+#undef LVTS
+
#define vlapic_lvtt_period(vlapic) \
((vlapic_get_reg(vlapic, APIC_LVTT) & APIC_TIMER_MODE_MASK) \
== APIC_TIMER_MODE_PERIODIC)
@@ -827,16 +837,16 @@ void vlapic_reg_write(struct vcpu *v, un
if ( !(val & APIC_SPIV_APIC_ENABLED) )
{
- int i;
+ unsigned int i,
+ nr = GET_APIC_MAXLVT(vlapic_get_reg(vlapic, APIC_LVR)) + 1;
uint32_t lvt_val;
vlapic->hw.disabled |= VLAPIC_SW_DISABLED;
- for ( i = 0; i < VLAPIC_LVT_NUM; i++ )
+ for ( i = 0; i < nr; i++ )
{
- lvt_val = vlapic_get_reg(vlapic, APIC_LVTT + 0x10 * i);
- vlapic_set_reg(vlapic, APIC_LVTT + 0x10 * i,
- lvt_val | APIC_LVT_MASKED);
+ lvt_val = vlapic_get_reg(vlapic, lvt_reg[i]);
+ vlapic_set_reg(vlapic, lvt_reg[i], lvt_val | APIC_LVT_MASKED);
}
}
else
@@ -878,7 +888,7 @@ void vlapic_reg_write(struct vcpu *v, un
case APIC_LVTERR: /* LVT Error Reg */
if ( vlapic_sw_disabled(vlapic) )
val |= APIC_LVT_MASKED;
- val &= array_access_nospec(vlapic_lvt_mask, (reg - APIC_LVTT) >> 4);
+ val &= array_access_nospec(lvt_valid, LVT_BIAS(reg));
vlapic_set_reg(vlapic, reg, val);
if ( reg == APIC_LVT0 )
{
@@ -1424,7 +1434,7 @@ bool is_vlapic_lvtpc_enabled(struct vlap
/* Reset the VLAPIC back to its init state. */
static void vlapic_do_init(struct vlapic *vlapic)
{
- int i;
+ unsigned int i, nr;
if ( !has_vlapic(vlapic_vcpu(vlapic)->domain) )
return;
@@ -1452,8 +1462,9 @@ static void vlapic_do_init(struct vlapic
vlapic_set_reg(vlapic, APIC_DFR, 0xffffffffU);
- for ( i = 0; i < VLAPIC_LVT_NUM; i++ )
- vlapic_set_reg(vlapic, APIC_LVTT + 0x10 * i, APIC_LVT_MASKED);
+ nr = GET_APIC_MAXLVT(vlapic_get_reg(vlapic, APIC_LVR)) + 1;
+ for ( i = 0; i < nr; i++ )
+ vlapic_set_reg(vlapic, lvt_reg[i], APIC_LVT_MASKED);
vlapic_set_reg(vlapic, APIC_SPIV, 0xff);
vlapic->hw.disabled |= VLAPIC_SW_DISABLED;
@@ -1639,13 +1650,23 @@ static int cf_check lapic_check_regs(con
{
unsigned int vcpuid = hvm_load_instance(h);
int rc;
+ const struct hvm_hw_lapic_regs *regs;
if ( (rc = lapic_check_common(d, vcpuid)) )
return rc;
- if ( !hvm_get_entry(LAPIC_REGS, h) )
+ regs = hvm_get_entry(LAPIC_REGS, h);
+ if ( !regs )
return -ENODATA;
+/* Like vlapic_get_reg(), but without having a struct vlapic instance. */
+#define GET_REG(reg) (*(const uint32_t *)®s->data[reg])
+
+ if ( GET_APIC_MAXLVT(GET_REG(APIC_LVR)) >= ARRAY_SIZE(lvt_reg) )
+ return -ERANGE;
+
+#undef GET_REG
+
return 0;
}
© 2016 - 2025 Red Hat, Inc.