Stop secondary VMs from accessing GIC system registers.
Bug: 132960440
Change-Id: I2505afe9e885406a5b91811ff1a3451fa3a34393
diff --git a/src/arch/aarch64/cpu.c b/src/arch/aarch64/cpu.c
index b7b5b99..bfe9c42 100644
--- a/src/arch/aarch64/cpu.c
+++ b/src/arch/aarch64/cpu.c
@@ -33,6 +33,20 @@
__asm__ volatile("msr DAIFClr, #0xf");
}
+static void gic_regs_reset(struct arch_regs *r, bool is_primary)
+{
+#if GIC_VERSION == 3 || GIC_VERSION == 4
+ uint32_t ich_hcr = 0;
+
+ if (!is_primary) {
+ /* Trap EL1 access to GICv3 system registers. */
+ ich_hcr =
+ (0x1fu << 10); /* TDIR, TSEI, TALL1, TALL0, TC bits. */
+ }
+ r->gic.ich_hcr_el2 = ich_hcr;
+#endif
+}
+
void arch_regs_reset(struct arch_regs *r, bool is_primary, uint64_t vm_id,
uint64_t vcpu_id, paddr_t table)
{
@@ -81,6 +95,8 @@
/* TODO: Use constant here. */
r->spsr = 5 | /* M bits, set to EL1h. */
(0xf << 6); /* DAIF bits set; disable interrupts. */
+
+ gic_regs_reset(r, is_primary);
}
void arch_regs_set_pc_arg(struct arch_regs *r, ipaddr_t pc, uintreg_t arg)
diff --git a/src/arch/aarch64/hftest/interrupts_gicv3.c b/src/arch/aarch64/hftest/interrupts_gicv3.c
index 4c036d4..a3fd489 100644
--- a/src/arch/aarch64/hftest/interrupts_gicv3.c
+++ b/src/arch/aarch64/hftest/interrupts_gicv3.c
@@ -41,12 +41,12 @@
/* Set exception vector table. */
write_msr(VBAR_EL1, &vector_table_el1);
-
- write_msr(ICC_CTLR_EL1, 0);
}
void interrupt_gic_setup(void)
{
+ write_msr(ICC_CTLR_EL1, 0);
+
GICD_CTLR = 1u << 4 /* Enable affinity routing. */
| 1u << 1; /* Enable group 1 non-secure interrupts. */
diff --git a/src/arch/aarch64/hypervisor/exceptions.S b/src/arch/aarch64/hypervisor/exceptions.S
index ea17ffa..9acd240 100644
--- a/src/arch/aarch64/hypervisor/exceptions.S
+++ b/src/arch/aarch64/hypervisor/exceptions.S
@@ -312,6 +312,15 @@
mrs x28, vttbr_el2
str x28, [x1, #VCPU_LAZY + 16 * 14]
+ /* Save GIC registers. */
+#if GIC_VERSION == 3 || GIC_VERSION == 4
+ /* Offset is too large, so start from a new base. */
+ add x2, x1, #VCPU_GIC
+
+ mrs x3, ich_hcr_el2
+ str x3, [x2, #16 * 0]
+#endif
+
/*
* Save floating point registers.
*
@@ -382,7 +391,7 @@
ldp q24, q25, [x2, #32 * 12]
ldp q26, q27, [x2, #32 * 13]
ldp q28, q29, [x2, #32 * 14]
- /* Offest becomes too large, so move the base. */
+ /* Offset becomes too large, so move the base. */
ldp q30, q31, [x2, #32 * 15]!
ldp x3, x4, [x2, #32 * 1]
msr fpsr, x3
@@ -458,6 +467,15 @@
ldr x28, [x0, #VCPU_LAZY + 16 * 14]
msr vttbr_el2, x28
+ /* Restore GIC registers. */
+#if GIC_VERSION == 3 || GIC_VERSION == 4
+ /* Offset is too large, so start from a new base. */
+ add x2, x0, #VCPU_GIC
+
+ ldr x3, [x2, #16 * 0]
+ msr ich_hcr_el2, x3
+#endif
+
/* Restore non-volatile registers. */
ldp x19, x20, [x0, #VCPU_REGS + 8 * 19]
ldp x21, x22, [x0, #VCPU_REGS + 8 * 21]
diff --git a/src/arch/aarch64/hypervisor/offsets.c b/src/arch/aarch64/hypervisor/offsets.c
index f85cf05..366a595 100644
--- a/src/arch/aarch64/hypervisor/offsets.c
+++ b/src/arch/aarch64/hypervisor/offsets.c
@@ -31,3 +31,7 @@
CHECK_OFFSET(VCPU_REGS, struct vcpu, regs);
CHECK_OFFSET(VCPU_LAZY, struct vcpu, regs.lazy);
CHECK_OFFSET(VCPU_FREGS, struct vcpu, regs.fp);
+
+#ifdef VCPU_GIC
+CHECK_OFFSET(VCPU_GIC, struct vcpu, regs.gic);
+#endif
diff --git a/src/arch/aarch64/hypervisor/offsets.h b/src/arch/aarch64/hypervisor/offsets.h
index d872e64..51724e0 100644
--- a/src/arch/aarch64/hypervisor/offsets.h
+++ b/src/arch/aarch64/hypervisor/offsets.h
@@ -21,4 +21,8 @@
#define CPU_STACK_BOTTOM 8
#define VCPU_REGS 32
#define VCPU_LAZY (VCPU_REGS + 264)
-#define VCPU_FREGS (VCPU_LAZY + 248)
+#define VCPU_FREGS (VCPU_LAZY + 232)
+
+#if GIC_VERSION == 3 || GIC_VERSION == 4
+#define VCPU_GIC (VCPU_FREGS + 528)
+#endif
diff --git a/src/arch/aarch64/inc/hf/arch/types.h b/src/arch/aarch64/inc/hf/arch/types.h
index e6f1b9d..f768309 100644
--- a/src/arch/aarch64/inc/hf/arch/types.h
+++ b/src/arch/aarch64/inc/hf/arch/types.h
@@ -56,6 +56,7 @@
uintreg_t r[31];
uintreg_t pc;
uintreg_t spsr;
+
/* System registers. */
struct {
uintreg_t vmpidr_el2;
@@ -88,6 +89,18 @@
uintreg_t cnthctl_el2;
uintreg_t vttbr_el2;
} lazy;
+
+ /* Floating point registers. */
+ struct float_reg fp[32];
+ uintreg_t fpsr;
+ uintreg_t fpcr;
+
+#if GIC_VERSION == 3 || GIC_VERSION == 4
+ struct {
+ uintreg_t ich_hcr_el2;
+ } gic;
+#endif
+
/*
* Peripheral registers, handled separately from other system registers.
*/
@@ -95,8 +108,4 @@
uintreg_t cntv_cval_el0;
uintreg_t cntv_ctl_el0;
} peripherals;
- /* Floating point registers. */
- struct float_reg fp[32];
- uintreg_t fpsr;
- uintreg_t fpcr;
};