Skip to content

Commit 96c2f03

Browse files
Marc Zyngieroupton
authored andcommitted
KVM: arm64: nv: Plumb handling of GICv3 EL2 accesses
Wire the handling of all GICv3 EL2 registers, and provide emulation for all the non memory-backed registers (ICC_SRE_EL2, ICH_VTR_EL2, ICH_MISR_EL2, ICH_ELRSR_EL2, and ICH_EISR_EL2). Signed-off-by: Marc Zyngier <maz@kernel.org> Link: https://lore.kernel.org/r/20250225172930.1850838-7-maz@kernel.org Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
1 parent 182f159 commit 96c2f03

File tree

4 files changed

+224
-2
lines changed

4 files changed

+224
-2
lines changed

arch/arm64/kvm/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ kvm-y += arm.o mmu.o mmio.o psci.o hypercalls.o pvtime.o \
2323
vgic/vgic-v3.o vgic/vgic-v4.o \
2424
vgic/vgic-mmio.o vgic/vgic-mmio-v2.o \
2525
vgic/vgic-mmio-v3.o vgic/vgic-kvm-device.o \
26-
vgic/vgic-its.o vgic/vgic-debug.o
26+
vgic/vgic-its.o vgic/vgic-debug.o vgic/vgic-v3-nested.o
2727

2828
kvm-$(CONFIG_HW_PERF_EVENTS) += pmu-emul.o pmu.o
2929
kvm-$(CONFIG_ARM64_PTR_AUTH) += pauth.o

arch/arm64/kvm/sys_regs.c

Lines changed: 94 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include <linux/mm.h>
1818
#include <linux/printk.h>
1919
#include <linux/uaccess.h>
20+
#include <linux/irqchip/arm-gic-v3.h>
2021

2122
#include <asm/arm_pmuv3.h>
2223
#include <asm/cacheflush.h>
@@ -531,7 +532,13 @@ static bool access_gic_sre(struct kvm_vcpu *vcpu,
531532
if (p->is_write)
532533
return ignore_write(vcpu, p);
533534

534-
p->regval = vcpu->arch.vgic_cpu.vgic_v3.vgic_sre;
535+
if (p->Op1 == 4) { /* ICC_SRE_EL2 */
536+
p->regval = (ICC_SRE_EL2_ENABLE | ICC_SRE_EL2_SRE |
537+
ICC_SRE_EL1_DIB | ICC_SRE_EL1_DFB);
538+
} else { /* ICC_SRE_EL1 */
539+
p->regval = vcpu->arch.vgic_cpu.vgic_v3.vgic_sre;
540+
}
541+
535542
return true;
536543
}
537544

@@ -2426,6 +2433,59 @@ static bool access_zcr_el2(struct kvm_vcpu *vcpu,
24262433
vq = SYS_FIELD_GET(ZCR_ELx, LEN, p->regval) + 1;
24272434
vq = min(vq, vcpu_sve_max_vq(vcpu));
24282435
vcpu_write_sys_reg(vcpu, vq - 1, ZCR_EL2);
2436+
2437+
return true;
2438+
}
2439+
2440+
static bool access_gic_vtr(struct kvm_vcpu *vcpu,
2441+
struct sys_reg_params *p,
2442+
const struct sys_reg_desc *r)
2443+
{
2444+
if (p->is_write)
2445+
return write_to_read_only(vcpu, p, r);
2446+
2447+
p->regval = kvm_vgic_global_state.ich_vtr_el2;
2448+
p->regval &= ~(ICH_VTR_EL2_DVIM |
2449+
ICH_VTR_EL2_A3V |
2450+
ICH_VTR_EL2_IDbits);
2451+
p->regval |= ICH_VTR_EL2_nV4;
2452+
2453+
return true;
2454+
}
2455+
2456+
static bool access_gic_misr(struct kvm_vcpu *vcpu,
2457+
struct sys_reg_params *p,
2458+
const struct sys_reg_desc *r)
2459+
{
2460+
if (p->is_write)
2461+
return write_to_read_only(vcpu, p, r);
2462+
2463+
p->regval = vgic_v3_get_misr(vcpu);
2464+
2465+
return true;
2466+
}
2467+
2468+
static bool access_gic_eisr(struct kvm_vcpu *vcpu,
2469+
struct sys_reg_params *p,
2470+
const struct sys_reg_desc *r)
2471+
{
2472+
if (p->is_write)
2473+
return write_to_read_only(vcpu, p, r);
2474+
2475+
p->regval = vgic_v3_get_eisr(vcpu);
2476+
2477+
return true;
2478+
}
2479+
2480+
static bool access_gic_elrsr(struct kvm_vcpu *vcpu,
2481+
struct sys_reg_params *p,
2482+
const struct sys_reg_desc *r)
2483+
{
2484+
if (p->is_write)
2485+
return write_to_read_only(vcpu, p, r);
2486+
2487+
p->regval = vgic_v3_get_elrsr(vcpu);
2488+
24292489
return true;
24302490
}
24312491

@@ -3102,7 +3162,40 @@ static const struct sys_reg_desc sys_reg_descs[] = {
31023162
EL2_REG(RVBAR_EL2, access_rw, reset_val, 0),
31033163
{ SYS_DESC(SYS_RMR_EL2), undef_access },
31043164

3165+
EL2_REG_VNCR(ICH_AP0R0_EL2, reset_val, 0),
3166+
EL2_REG_VNCR(ICH_AP0R1_EL2, reset_val, 0),
3167+
EL2_REG_VNCR(ICH_AP0R2_EL2, reset_val, 0),
3168+
EL2_REG_VNCR(ICH_AP0R3_EL2, reset_val, 0),
3169+
EL2_REG_VNCR(ICH_AP1R0_EL2, reset_val, 0),
3170+
EL2_REG_VNCR(ICH_AP1R1_EL2, reset_val, 0),
3171+
EL2_REG_VNCR(ICH_AP1R2_EL2, reset_val, 0),
3172+
EL2_REG_VNCR(ICH_AP1R3_EL2, reset_val, 0),
3173+
3174+
{ SYS_DESC(SYS_ICC_SRE_EL2), access_gic_sre },
3175+
31053176
EL2_REG_VNCR(ICH_HCR_EL2, reset_val, 0),
3177+
{ SYS_DESC(SYS_ICH_VTR_EL2), access_gic_vtr },
3178+
{ SYS_DESC(SYS_ICH_MISR_EL2), access_gic_misr },
3179+
{ SYS_DESC(SYS_ICH_EISR_EL2), access_gic_eisr },
3180+
{ SYS_DESC(SYS_ICH_ELRSR_EL2), access_gic_elrsr },
3181+
EL2_REG_VNCR(ICH_VMCR_EL2, reset_val, 0),
3182+
3183+
EL2_REG_VNCR(ICH_LR0_EL2, reset_val, 0),
3184+
EL2_REG_VNCR(ICH_LR1_EL2, reset_val, 0),
3185+
EL2_REG_VNCR(ICH_LR2_EL2, reset_val, 0),
3186+
EL2_REG_VNCR(ICH_LR3_EL2, reset_val, 0),
3187+
EL2_REG_VNCR(ICH_LR4_EL2, reset_val, 0),
3188+
EL2_REG_VNCR(ICH_LR5_EL2, reset_val, 0),
3189+
EL2_REG_VNCR(ICH_LR6_EL2, reset_val, 0),
3190+
EL2_REG_VNCR(ICH_LR7_EL2, reset_val, 0),
3191+
EL2_REG_VNCR(ICH_LR8_EL2, reset_val, 0),
3192+
EL2_REG_VNCR(ICH_LR9_EL2, reset_val, 0),
3193+
EL2_REG_VNCR(ICH_LR10_EL2, reset_val, 0),
3194+
EL2_REG_VNCR(ICH_LR11_EL2, reset_val, 0),
3195+
EL2_REG_VNCR(ICH_LR12_EL2, reset_val, 0),
3196+
EL2_REG_VNCR(ICH_LR13_EL2, reset_val, 0),
3197+
EL2_REG_VNCR(ICH_LR14_EL2, reset_val, 0),
3198+
EL2_REG_VNCR(ICH_LR15_EL2, reset_val, 0),
31063199

31073200
EL2_REG(CONTEXTIDR_EL2, access_rw, reset_val, 0),
31083201
EL2_REG(TPIDR_EL2, access_rw, reset_val, 0),

arch/arm64/kvm/vgic/vgic-v3-nested.c

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
3+
#include <linux/cpu.h>
4+
#include <linux/kvm.h>
5+
#include <linux/kvm_host.h>
6+
#include <linux/interrupt.h>
7+
#include <linux/io.h>
8+
#include <linux/uaccess.h>
9+
10+
#include <kvm/arm_vgic.h>
11+
12+
#include <asm/kvm_arm.h>
13+
#include <asm/kvm_emulate.h>
14+
#include <asm/kvm_nested.h>
15+
16+
#include "vgic.h"
17+
18+
#define ICH_LRN(n) (ICH_LR0_EL2 + (n))
19+
20+
struct mi_state {
21+
u16 eisr;
22+
u16 elrsr;
23+
bool pend;
24+
};
25+
26+
/*
27+
* Nesting GICv3 support
28+
*
29+
* System register emulation:
30+
*
31+
* We get two classes of registers:
32+
*
33+
* - those backed by memory (LRs, APRs, HCR, VMCR): L1 can freely access
34+
* them, and L0 doesn't see a thing.
35+
*
36+
* - those that always trap (ELRSR, EISR, MISR): these are status registers
37+
* that are built on the fly based on the in-memory state.
38+
*
39+
* Only L1 can access the ICH_*_EL2 registers. A non-NV L2 obviously cannot,
40+
* and a NV L2 would either access the VNCR page provided by L1 (memory
41+
* based registers), or see the access redirected to L1 (registers that
42+
* trap) thanks to NV being set by L1.
43+
*/
44+
45+
static bool lr_triggers_eoi(u64 lr)
46+
{
47+
return !(lr & (ICH_LR_STATE | ICH_LR_HW)) && (lr & ICH_LR_EOI);
48+
}
49+
50+
static void vgic_compute_mi_state(struct kvm_vcpu *vcpu, struct mi_state *mi_state)
51+
{
52+
u16 eisr = 0, elrsr = 0;
53+
bool pend = false;
54+
55+
for (int i = 0; i < kvm_vgic_global_state.nr_lr; i++) {
56+
u64 lr = __vcpu_sys_reg(vcpu, ICH_LRN(i));
57+
58+
if (lr_triggers_eoi(lr))
59+
eisr |= BIT(i);
60+
if (!(lr & ICH_LR_STATE))
61+
elrsr |= BIT(i);
62+
pend |= (lr & ICH_LR_PENDING_BIT);
63+
}
64+
65+
mi_state->eisr = eisr;
66+
mi_state->elrsr = elrsr;
67+
mi_state->pend = pend;
68+
}
69+
70+
u16 vgic_v3_get_eisr(struct kvm_vcpu *vcpu)
71+
{
72+
struct mi_state mi_state;
73+
74+
vgic_compute_mi_state(vcpu, &mi_state);
75+
return mi_state.eisr;
76+
}
77+
78+
u16 vgic_v3_get_elrsr(struct kvm_vcpu *vcpu)
79+
{
80+
struct mi_state mi_state;
81+
82+
vgic_compute_mi_state(vcpu, &mi_state);
83+
return mi_state.elrsr;
84+
}
85+
86+
u64 vgic_v3_get_misr(struct kvm_vcpu *vcpu)
87+
{
88+
struct mi_state mi_state;
89+
u64 reg = 0, hcr, vmcr;
90+
91+
hcr = __vcpu_sys_reg(vcpu, ICH_HCR_EL2);
92+
vmcr = __vcpu_sys_reg(vcpu, ICH_VMCR_EL2);
93+
94+
vgic_compute_mi_state(vcpu, &mi_state);
95+
96+
if (mi_state.eisr)
97+
reg |= ICH_MISR_EL2_EOI;
98+
99+
if (__vcpu_sys_reg(vcpu, ICH_HCR_EL2) & ICH_HCR_EL2_UIE) {
100+
int used_lrs = kvm_vgic_global_state.nr_lr;
101+
102+
used_lrs -= hweight16(mi_state.elrsr);
103+
reg |= (used_lrs <= 1) ? ICH_MISR_EL2_U : 0;
104+
}
105+
106+
if ((hcr & ICH_HCR_EL2_LRENPIE) && FIELD_GET(ICH_HCR_EL2_EOIcount_MASK, hcr))
107+
reg |= ICH_MISR_EL2_LRENP;
108+
109+
if ((hcr & ICH_HCR_EL2_NPIE) && !mi_state.pend)
110+
reg |= ICH_MISR_EL2_NP;
111+
112+
if ((hcr & ICH_HCR_EL2_VGrp0EIE) && (vmcr & ICH_VMCR_ENG0_MASK))
113+
reg |= ICH_MISR_EL2_VGrp0E;
114+
115+
if ((hcr & ICH_HCR_EL2_VGrp0DIE) && !(vmcr & ICH_VMCR_ENG0_MASK))
116+
reg |= ICH_MISR_EL2_VGrp0D;
117+
118+
if ((hcr & ICH_HCR_EL2_VGrp1EIE) && (vmcr & ICH_VMCR_ENG1_MASK))
119+
reg |= ICH_MISR_EL2_VGrp1E;
120+
121+
if ((hcr & ICH_HCR_EL2_VGrp1DIE) && !(vmcr & ICH_VMCR_ENG1_MASK))
122+
reg |= ICH_MISR_EL2_VGrp1D;
123+
124+
return reg;
125+
}

include/kvm/arm_vgic.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,10 @@ int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu);
389389
void kvm_vgic_load(struct kvm_vcpu *vcpu);
390390
void kvm_vgic_put(struct kvm_vcpu *vcpu);
391391

392+
u16 vgic_v3_get_eisr(struct kvm_vcpu *vcpu);
393+
u16 vgic_v3_get_elrsr(struct kvm_vcpu *vcpu);
394+
u64 vgic_v3_get_misr(struct kvm_vcpu *vcpu);
395+
392396
#define irqchip_in_kernel(k) (!!((k)->arch.vgic.in_kernel))
393397
#define vgic_initialized(k) ((k)->arch.vgic.initialized)
394398
#define vgic_ready(k) ((k)->arch.vgic.ready)

0 commit comments

Comments
 (0)