Skip to content

Commit 328e566

Browse files
chazyChristoffer Dall
authored andcommitted
KVM: arm/arm64: vgic: Defer touching GICH_VMCR to vcpu_load/put
We don't have to save/restore the VMCR on every entry to/from the guest, since on GICv2 we can access the control interface from EL1 and on VHE systems with GICv3 we can access the control interface from KVM running in EL2. GICv3 systems without VHE becomes the rare case, which has to save/restore the register on each round trip. Note that userspace accesses may see out-of-date values if the VCPU is running while accessing the VGIC state via the KVM device API, but this is already the case and it is up to userspace to quiesce the CPUs before reading the CPU registers from the GIC for an up-to-date view. Reviewed-by: Marc Zyngier <[email protected]> Signed-off-by: Christoffer Dall <[email protected]> Signed-off-by: Christoffer Dall <[email protected]>
1 parent 056aad6 commit 328e566

File tree

11 files changed

+106
-16
lines changed

11 files changed

+106
-16
lines changed

arch/arm/include/asm/kvm_asm.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,10 @@ extern void __init_stage2_translation(void);
7575
extern void __kvm_hyp_reset(unsigned long);
7676

7777
extern u64 __vgic_v3_get_ich_vtr_el2(void);
78+
extern u64 __vgic_v3_read_vmcr(void);
79+
extern void __vgic_v3_write_vmcr(u32 vmcr);
7880
extern void __vgic_v3_init_lrs(void);
81+
7982
#endif
8083

8184
#endif /* __ARM_KVM_ASM_H__ */

arch/arm/kvm/arm.c

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -351,15 +351,14 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
351351
vcpu->arch.host_cpu_context = this_cpu_ptr(kvm_host_cpu_state);
352352

353353
kvm_arm_set_running_vcpu(vcpu);
354+
355+
kvm_vgic_load(vcpu);
354356
}
355357

356358
void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
357359
{
358-
/*
359-
* The arch-generic KVM code expects the cpu field of a vcpu to be -1
360-
* if the vcpu is no longer assigned to a cpu. This is used for the
361-
* optimized make_all_cpus_request path.
362-
*/
360+
kvm_vgic_put(vcpu);
361+
363362
vcpu->cpu = -1;
364363

365364
kvm_arm_set_running_vcpu(NULL);
@@ -633,7 +632,9 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
633632
* non-preemptible context.
634633
*/
635634
preempt_disable();
635+
636636
kvm_pmu_flush_hwstate(vcpu);
637+
637638
kvm_timer_flush_hwstate(vcpu);
638639
kvm_vgic_flush_hwstate(vcpu);
639640

arch/arm64/include/asm/kvm_asm.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ extern void __kvm_tlb_flush_local_vmid(struct kvm_vcpu *vcpu);
5959
extern int __kvm_vcpu_run(struct kvm_vcpu *vcpu);
6060

6161
extern u64 __vgic_v3_get_ich_vtr_el2(void);
62+
extern u64 __vgic_v3_read_vmcr(void);
63+
extern void __vgic_v3_write_vmcr(u32 vmcr);
6264
extern void __vgic_v3_init_lrs(void);
6365

6466
extern u32 __kvm_get_mdcr_el2(void);

include/kvm/arm_vgic.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,9 @@ bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, unsigned int virt_irq);
306306

307307
int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu);
308308

309+
void kvm_vgic_load(struct kvm_vcpu *vcpu);
310+
void kvm_vgic_put(struct kvm_vcpu *vcpu);
311+
309312
#define irqchip_in_kernel(k) (!!((k)->arch.vgic.in_kernel))
310313
#define vgic_initialized(k) ((k)->arch.vgic.initialized)
311314
#define vgic_ready(k) ((k)->arch.vgic.ready)

virt/kvm/arm/hyp/vgic-v2-sr.c

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -114,8 +114,6 @@ void __hyp_text __vgic_v2_save_state(struct kvm_vcpu *vcpu)
114114
if (!base)
115115
return;
116116

117-
cpu_if->vgic_vmcr = readl_relaxed(base + GICH_VMCR);
118-
119117
if (vcpu->arch.vgic_cpu.live_lrs) {
120118
cpu_if->vgic_apr = readl_relaxed(base + GICH_APR);
121119

@@ -165,7 +163,6 @@ void __hyp_text __vgic_v2_restore_state(struct kvm_vcpu *vcpu)
165163
}
166164
}
167165

168-
writel_relaxed(cpu_if->vgic_vmcr, base + GICH_VMCR);
169166
vcpu->arch.vgic_cpu.live_lrs = live_lrs;
170167
}
171168

virt/kvm/arm/hyp/vgic-v3-sr.c

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -159,8 +159,6 @@ void __hyp_text __vgic_v3_save_state(struct kvm_vcpu *vcpu)
159159
if (!cpu_if->vgic_sre)
160160
dsb(st);
161161

162-
cpu_if->vgic_vmcr = read_gicreg(ICH_VMCR_EL2);
163-
164162
if (vcpu->arch.vgic_cpu.live_lrs) {
165163
int i;
166164
u32 max_lr_idx, nr_pri_bits;
@@ -261,8 +259,6 @@ void __hyp_text __vgic_v3_restore_state(struct kvm_vcpu *vcpu)
261259
live_lrs |= (1 << i);
262260
}
263261

264-
write_gicreg(cpu_if->vgic_vmcr, ICH_VMCR_EL2);
265-
266262
if (live_lrs) {
267263
write_gicreg(cpu_if->vgic_hcr, ICH_HCR_EL2);
268264

@@ -326,3 +322,13 @@ u64 __hyp_text __vgic_v3_get_ich_vtr_el2(void)
326322
{
327323
return read_gicreg(ICH_VTR_EL2);
328324
}
325+
326+
u64 __hyp_text __vgic_v3_read_vmcr(void)
327+
{
328+
return read_gicreg(ICH_VMCR_EL2);
329+
}
330+
331+
void __hyp_text __vgic_v3_write_vmcr(u32 vmcr)
332+
{
333+
write_gicreg(vmcr, ICH_VMCR_EL2);
334+
}

virt/kvm/arm/vgic/vgic-init.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,18 @@ int vgic_init(struct kvm *kvm)
262262
vgic_debug_init(kvm);
263263

264264
dist->initialized = true;
265+
266+
/*
267+
* If we're initializing GICv2 on-demand when first running the VCPU
268+
* then we need to load the VGIC state onto the CPU. We can detect
269+
* this easily by checking if we are in between vcpu_load and vcpu_put
270+
* when we just initialized the VGIC.
271+
*/
272+
preempt_disable();
273+
vcpu = kvm_arm_get_running_vcpu();
274+
if (vcpu)
275+
kvm_vgic_load(vcpu);
276+
preempt_enable();
265277
out:
266278
return ret;
267279
}

virt/kvm/arm/vgic/vgic-v2.c

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,7 @@ void vgic_v2_clear_lr(struct kvm_vcpu *vcpu, int lr)
184184

185185
void vgic_v2_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
186186
{
187+
struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
187188
u32 vmcr;
188189

189190
vmcr = (vmcrp->ctlr << GICH_VMCR_CTRL_SHIFT) & GICH_VMCR_CTRL_MASK;
@@ -194,12 +195,15 @@ void vgic_v2_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
194195
vmcr |= (vmcrp->pmr << GICH_VMCR_PRIMASK_SHIFT) &
195196
GICH_VMCR_PRIMASK_MASK;
196197

197-
vcpu->arch.vgic_cpu.vgic_v2.vgic_vmcr = vmcr;
198+
cpu_if->vgic_vmcr = vmcr;
198199
}
199200

200201
void vgic_v2_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
201202
{
202-
u32 vmcr = vcpu->arch.vgic_cpu.vgic_v2.vgic_vmcr;
203+
struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
204+
u32 vmcr;
205+
206+
vmcr = cpu_if->vgic_vmcr;
203207

204208
vmcrp->ctlr = (vmcr & GICH_VMCR_CTRL_MASK) >>
205209
GICH_VMCR_CTRL_SHIFT;
@@ -375,3 +379,19 @@ int vgic_v2_probe(const struct gic_kvm_info *info)
375379

376380
return ret;
377381
}
382+
383+
void vgic_v2_load(struct kvm_vcpu *vcpu)
384+
{
385+
struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
386+
struct vgic_dist *vgic = &vcpu->kvm->arch.vgic;
387+
388+
writel_relaxed(cpu_if->vgic_vmcr, vgic->vctrl_base + GICH_VMCR);
389+
}
390+
391+
void vgic_v2_put(struct kvm_vcpu *vcpu)
392+
{
393+
struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
394+
struct vgic_dist *vgic = &vcpu->kvm->arch.vgic;
395+
396+
cpu_if->vgic_vmcr = readl_relaxed(vgic->vctrl_base + GICH_VMCR);
397+
}

virt/kvm/arm/vgic/vgic-v3.c

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ void vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr)
173173

174174
void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
175175
{
176+
struct vgic_v3_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v3;
176177
u32 vmcr;
177178

178179
/*
@@ -188,12 +189,15 @@ void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
188189
vmcr |= (vmcrp->grpen0 << ICH_VMCR_ENG0_SHIFT) & ICH_VMCR_ENG0_MASK;
189190
vmcr |= (vmcrp->grpen1 << ICH_VMCR_ENG1_SHIFT) & ICH_VMCR_ENG1_MASK;
190191

191-
vcpu->arch.vgic_cpu.vgic_v3.vgic_vmcr = vmcr;
192+
cpu_if->vgic_vmcr = vmcr;
192193
}
193194

194195
void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
195196
{
196-
u32 vmcr = vcpu->arch.vgic_cpu.vgic_v3.vgic_vmcr;
197+
struct vgic_v3_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v3;
198+
u32 vmcr;
199+
200+
vmcr = cpu_if->vgic_vmcr;
197201

198202
/*
199203
* Ignore the FIQen bit, because GIC emulation always implies
@@ -386,3 +390,17 @@ int vgic_v3_probe(const struct gic_kvm_info *info)
386390

387391
return 0;
388392
}
393+
394+
void vgic_v3_load(struct kvm_vcpu *vcpu)
395+
{
396+
struct vgic_v3_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v3;
397+
398+
kvm_call_hyp(__vgic_v3_write_vmcr, cpu_if->vgic_vmcr);
399+
}
400+
401+
void vgic_v3_put(struct kvm_vcpu *vcpu)
402+
{
403+
struct vgic_v3_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v3;
404+
405+
cpu_if->vgic_vmcr = kvm_call_hyp(__vgic_v3_read_vmcr);
406+
}

virt/kvm/arm/vgic/vgic.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -656,6 +656,28 @@ void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
656656
spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
657657
}
658658

659+
void kvm_vgic_load(struct kvm_vcpu *vcpu)
660+
{
661+
if (unlikely(!vgic_initialized(vcpu->kvm)))
662+
return;
663+
664+
if (kvm_vgic_global_state.type == VGIC_V2)
665+
vgic_v2_load(vcpu);
666+
else
667+
vgic_v3_load(vcpu);
668+
}
669+
670+
void kvm_vgic_put(struct kvm_vcpu *vcpu)
671+
{
672+
if (unlikely(!vgic_initialized(vcpu->kvm)))
673+
return;
674+
675+
if (kvm_vgic_global_state.type == VGIC_V2)
676+
vgic_v2_put(vcpu);
677+
else
678+
vgic_v3_put(vcpu);
679+
}
680+
659681
int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu)
660682
{
661683
struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;

virt/kvm/arm/vgic/vgic.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,9 @@ int vgic_v2_map_resources(struct kvm *kvm);
130130
int vgic_register_dist_iodev(struct kvm *kvm, gpa_t dist_base_address,
131131
enum vgic_type);
132132

133+
void vgic_v2_load(struct kvm_vcpu *vcpu);
134+
void vgic_v2_put(struct kvm_vcpu *vcpu);
135+
133136
static inline void vgic_get_irq_kref(struct vgic_irq *irq)
134137
{
135138
if (irq->intid < VGIC_MIN_LPI)
@@ -150,6 +153,9 @@ int vgic_v3_probe(const struct gic_kvm_info *info);
150153
int vgic_v3_map_resources(struct kvm *kvm);
151154
int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t dist_base_address);
152155

156+
void vgic_v3_load(struct kvm_vcpu *vcpu);
157+
void vgic_v3_put(struct kvm_vcpu *vcpu);
158+
153159
int vgic_register_its_iodevs(struct kvm *kvm);
154160
bool vgic_has_its(struct kvm *kvm);
155161
int kvm_vgic_register_its_device(void);

0 commit comments

Comments
 (0)