aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndre Przywara <andre.przywara@arm.com>2014-06-03 02:58:15 -0400
committerChristoffer Dall <christoffer.dall@linaro.org>2015-01-20 12:25:28 -0500
commit2f5fa41a7a7f47f3109a6596b0ec96258dbf06e6 (patch)
tree6e75ee4272712add84e6d0a1f547caaacc38a7d3
parent3caa2d8c3b2d80f5e342fe8cec07c03c8147dcab (diff)
arm/arm64: KVM: make the value of ICC_SRE_EL1 a per-VM variable
ICC_SRE_EL1 is a system register allowing msr/mrs accesses to the GIC CPU interface for EL1 (guests). Currently we force it to 0, but for proper GICv3 support we have to allow guests to use it (depending on their selected virtual GIC model). So add ICC_SRE_EL1 to the list of saved/restored registers on a world switch, but actually disallow a guest to change it by only restoring a fixed, once-initialized value. This value depends on the GIC model userland has chosen for a guest. Signed-off-by: Andre Przywara <andre.przywara@arm.com> Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org> Acked-by: Marc Zyngier <marc.zyngier@arm.com> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
-rw-r--r--arch/arm64/kernel/asm-offsets.c1
-rw-r--r--arch/arm64/kvm/vgic-v3-switch.S14
-rw-r--r--include/kvm/arm_vgic.h1
-rw-r--r--virt/kvm/arm/vgic-v3.c8
4 files changed, 17 insertions, 7 deletions
diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c
index 9a9fce090d58..9d34486985fd 100644
--- a/arch/arm64/kernel/asm-offsets.c
+++ b/arch/arm64/kernel/asm-offsets.c
@@ -140,6 +140,7 @@ int main(void)
140 DEFINE(VGIC_V2_CPU_ELRSR, offsetof(struct vgic_cpu, vgic_v2.vgic_elrsr)); 140 DEFINE(VGIC_V2_CPU_ELRSR, offsetof(struct vgic_cpu, vgic_v2.vgic_elrsr));
141 DEFINE(VGIC_V2_CPU_APR, offsetof(struct vgic_cpu, vgic_v2.vgic_apr)); 141 DEFINE(VGIC_V2_CPU_APR, offsetof(struct vgic_cpu, vgic_v2.vgic_apr));
142 DEFINE(VGIC_V2_CPU_LR, offsetof(struct vgic_cpu, vgic_v2.vgic_lr)); 142 DEFINE(VGIC_V2_CPU_LR, offsetof(struct vgic_cpu, vgic_v2.vgic_lr));
143 DEFINE(VGIC_V3_CPU_SRE, offsetof(struct vgic_cpu, vgic_v3.vgic_sre));
143 DEFINE(VGIC_V3_CPU_HCR, offsetof(struct vgic_cpu, vgic_v3.vgic_hcr)); 144 DEFINE(VGIC_V3_CPU_HCR, offsetof(struct vgic_cpu, vgic_v3.vgic_hcr));
144 DEFINE(VGIC_V3_CPU_VMCR, offsetof(struct vgic_cpu, vgic_v3.vgic_vmcr)); 145 DEFINE(VGIC_V3_CPU_VMCR, offsetof(struct vgic_cpu, vgic_v3.vgic_vmcr));
145 DEFINE(VGIC_V3_CPU_MISR, offsetof(struct vgic_cpu, vgic_v3.vgic_misr)); 146 DEFINE(VGIC_V3_CPU_MISR, offsetof(struct vgic_cpu, vgic_v3.vgic_misr));
diff --git a/arch/arm64/kvm/vgic-v3-switch.S b/arch/arm64/kvm/vgic-v3-switch.S
index d16046999e06..617a012a0107 100644
--- a/arch/arm64/kvm/vgic-v3-switch.S
+++ b/arch/arm64/kvm/vgic-v3-switch.S
@@ -148,17 +148,18 @@
148 * x0: Register pointing to VCPU struct 148 * x0: Register pointing to VCPU struct
149 */ 149 */
150.macro restore_vgic_v3_state 150.macro restore_vgic_v3_state
151 // Disable SRE_EL1 access. Necessary, otherwise
152 // ICH_VMCR_EL2.VFIQEn becomes one, and FIQ happens...
153 msr_s ICC_SRE_EL1, xzr
154 isb
155
156 // Compute the address of struct vgic_cpu 151 // Compute the address of struct vgic_cpu
157 add x3, x0, #VCPU_VGIC_CPU 152 add x3, x0, #VCPU_VGIC_CPU
158 153
159 // Restore all interesting registers 154 // Restore all interesting registers
160 ldr w4, [x3, #VGIC_V3_CPU_HCR] 155 ldr w4, [x3, #VGIC_V3_CPU_HCR]
161 ldr w5, [x3, #VGIC_V3_CPU_VMCR] 156 ldr w5, [x3, #VGIC_V3_CPU_VMCR]
157 ldr w25, [x3, #VGIC_V3_CPU_SRE]
158
159 msr_s ICC_SRE_EL1, x25
160
161 // make sure SRE is valid before writing the other registers
162 isb
162 163
163 msr_s ICH_HCR_EL2, x4 164 msr_s ICH_HCR_EL2, x4
164 msr_s ICH_VMCR_EL2, x5 165 msr_s ICH_VMCR_EL2, x5
@@ -244,9 +245,12 @@
244 dsb sy 245 dsb sy
245 246
246 // Prevent the guest from touching the GIC system registers 247 // Prevent the guest from touching the GIC system registers
248 // if SRE isn't enabled for GICv3 emulation
249 cbnz x25, 1f
247 mrs_s x5, ICC_SRE_EL2 250 mrs_s x5, ICC_SRE_EL2
248 and x5, x5, #~ICC_SRE_EL2_ENABLE 251 and x5, x5, #~ICC_SRE_EL2_ENABLE
249 msr_s ICC_SRE_EL2, x5 252 msr_s ICC_SRE_EL2, x5
2531:
250.endm 254.endm
251 255
252ENTRY(__save_vgic_v3_state) 256ENTRY(__save_vgic_v3_state)
diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index 1c0e9dbabe6d..ff04afd0d901 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -245,6 +245,7 @@ struct vgic_v3_cpu_if {
245#ifdef CONFIG_ARM_GIC_V3 245#ifdef CONFIG_ARM_GIC_V3
246 u32 vgic_hcr; 246 u32 vgic_hcr;
247 u32 vgic_vmcr; 247 u32 vgic_vmcr;
248 u32 vgic_sre; /* Restored only, change ignored */
248 u32 vgic_misr; /* Saved only */ 249 u32 vgic_misr; /* Saved only */
249 u32 vgic_eisr; /* Saved only */ 250 u32 vgic_eisr; /* Saved only */
250 u32 vgic_elrsr; /* Saved only */ 251 u32 vgic_elrsr; /* Saved only */
diff --git a/virt/kvm/arm/vgic-v3.c b/virt/kvm/arm/vgic-v3.c
index ea39bad4b004..52490480b6f9 100644
--- a/virt/kvm/arm/vgic-v3.c
+++ b/virt/kvm/arm/vgic-v3.c
@@ -145,15 +145,19 @@ static void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
145 145
146static void vgic_v3_enable(struct kvm_vcpu *vcpu) 146static void vgic_v3_enable(struct kvm_vcpu *vcpu)
147{ 147{
148 struct vgic_v3_cpu_if *vgic_v3 = &vcpu->arch.vgic_cpu.vgic_v3;
149
148 /* 150 /*
149 * By forcing VMCR to zero, the GIC will restore the binary 151 * By forcing VMCR to zero, the GIC will restore the binary
150 * points to their reset values. Anything else resets to zero 152 * points to their reset values. Anything else resets to zero
151 * anyway. 153 * anyway.
152 */ 154 */
153 vcpu->arch.vgic_cpu.vgic_v3.vgic_vmcr = 0; 155 vgic_v3->vgic_vmcr = 0;
156
157 vgic_v3->vgic_sre = 0;
154 158
155 /* Get the show on the road... */ 159 /* Get the show on the road... */
156 vcpu->arch.vgic_cpu.vgic_v3.vgic_hcr = ICH_HCR_EN; 160 vgic_v3->vgic_hcr = ICH_HCR_EN;
157} 161}
158 162
159static const struct vgic_ops vgic_v3_ops = { 163static const struct vgic_ops vgic_v3_ops = {