File Index
Files and directories
Sign in
FILE

vgic-sys-reg-v3.c

File preview with syntax highlighting.

linux-6.19.14/arch/arm64/kvm/vgic-sys-reg-v3.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * VGIC system registers handling functions for AArch64 mode
  4 */
  5
  6#include <linux/irqchip/arm-gic-v3.h>
  7#include <linux/kvm.h>
  8#include <linux/kvm_host.h>
  9#include <asm/kvm_emulate.h>
 10#include "vgic/vgic.h"
 11#include "sys_regs.h"
 12
 13static int set_gic_ctlr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
 14			u64 val)
 15{
 16	u32 host_pri_bits, host_id_bits, host_seis, host_a3v, seis, a3v;
 17	struct vgic_cpu *vgic_v3_cpu = &vcpu->arch.vgic_cpu;
 18	struct vgic_vmcr vmcr;
 19
 20	vgic_get_vmcr(vcpu, &vmcr);
 21
 22	/*
 23	 * Disallow restoring VM state if not supported by this
 24	 * hardware.
 25	 */
 26	host_pri_bits = FIELD_GET(ICC_CTLR_EL1_PRI_BITS_MASK, val) + 1;
 27	if (host_pri_bits > vgic_v3_cpu->num_pri_bits)
 28		return -EINVAL;
 29
 30	vgic_v3_cpu->num_pri_bits = host_pri_bits;
 31
 32	host_id_bits = FIELD_GET(ICC_CTLR_EL1_ID_BITS_MASK, val);
 33	if (host_id_bits > vgic_v3_cpu->num_id_bits)
 34		return -EINVAL;
 35
 36	vgic_v3_cpu->num_id_bits = host_id_bits;
 37
 38	host_seis = FIELD_GET(ICH_VTR_EL2_SEIS, kvm_vgic_global_state.ich_vtr_el2);
 39	seis = FIELD_GET(ICC_CTLR_EL1_SEIS_MASK, val);
 40	if (host_seis != seis)
 41		return -EINVAL;
 42
 43	host_a3v = FIELD_GET(ICH_VTR_EL2_A3V, kvm_vgic_global_state.ich_vtr_el2);
 44	a3v = FIELD_GET(ICC_CTLR_EL1_A3V_MASK, val);
 45	if (host_a3v != a3v)
 46		return -EINVAL;
 47
 48	/*
 49	 * Here set VMCR.CTLR in ICC_CTLR_EL1 layout.
 50	 * The vgic_set_vmcr() will convert to ICH_VMCR layout.
 51	 */
 52	vmcr.cbpr = FIELD_GET(ICC_CTLR_EL1_CBPR_MASK, val);
 53	vmcr.eoim = FIELD_GET(ICC_CTLR_EL1_EOImode_MASK, val);
 54	vgic_set_vmcr(vcpu, &vmcr);
 55
 56	return 0;
 57}
 58
 59static int get_gic_ctlr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
 60			u64 *valp)
 61{
 62	struct vgic_cpu *vgic_v3_cpu = &vcpu->arch.vgic_cpu;
 63	struct vgic_vmcr vmcr;
 64	u64 val;
 65
 66	vgic_get_vmcr(vcpu, &vmcr);
 67	val = 0;
 68	val |= FIELD_PREP(ICC_CTLR_EL1_PRI_BITS_MASK, vgic_v3_cpu->num_pri_bits - 1);
 69	val |= FIELD_PREP(ICC_CTLR_EL1_ID_BITS_MASK, vgic_v3_cpu->num_id_bits);
 70	val |= FIELD_PREP(ICC_CTLR_EL1_SEIS_MASK,
 71			  FIELD_GET(ICH_VTR_EL2_SEIS,
 72				    kvm_vgic_global_state.ich_vtr_el2));
 73	val |= FIELD_PREP(ICC_CTLR_EL1_A3V_MASK,
 74			  FIELD_GET(ICH_VTR_EL2_A3V, kvm_vgic_global_state.ich_vtr_el2));
 75	/*
 76	 * The VMCR.CTLR value is in ICC_CTLR_EL1 layout.
 77	 * Extract it directly using ICC_CTLR_EL1 reg definitions.
 78	 */
 79	val |= FIELD_PREP(ICC_CTLR_EL1_CBPR_MASK, vmcr.cbpr);
 80	val |= FIELD_PREP(ICC_CTLR_EL1_EOImode_MASK, vmcr.eoim);
 81
 82	*valp = val;
 83
 84	return 0;
 85}
 86
 87static int set_gic_pmr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
 88		       u64 val)
 89{
 90	struct vgic_vmcr vmcr;
 91
 92	vgic_get_vmcr(vcpu, &vmcr);
 93	vmcr.pmr = FIELD_GET(ICC_PMR_EL1_MASK, val);
 94	vgic_set_vmcr(vcpu, &vmcr);
 95
 96	return 0;
 97}
 98
 99static int get_gic_pmr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
100		       u64 *val)
101{
102	struct vgic_vmcr vmcr;
103
104	vgic_get_vmcr(vcpu, &vmcr);
105	*val = FIELD_PREP(ICC_PMR_EL1_MASK, vmcr.pmr);
106
107	return 0;
108}
109
110static int set_gic_bpr0(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
111			u64 val)
112{
113	struct vgic_vmcr vmcr;
114
115	vgic_get_vmcr(vcpu, &vmcr);
116	vmcr.bpr = FIELD_GET(ICC_BPR0_EL1_MASK, val);
117	vgic_set_vmcr(vcpu, &vmcr);
118
119	return 0;
120}
121
122static int get_gic_bpr0(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
123			u64 *val)
124{
125	struct vgic_vmcr vmcr;
126
127	vgic_get_vmcr(vcpu, &vmcr);
128	*val = FIELD_PREP(ICC_BPR0_EL1_MASK, vmcr.bpr);
129
130	return 0;
131}
132
133static int set_gic_bpr1(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
134			u64 val)
135{
136	struct vgic_vmcr vmcr;
137
138	vgic_get_vmcr(vcpu, &vmcr);
139	if (!vmcr.cbpr) {
140		vmcr.abpr = FIELD_GET(ICC_BPR1_EL1_MASK, val);
141		vgic_set_vmcr(vcpu, &vmcr);
142	}
143
144	return 0;
145}
146
147static int get_gic_bpr1(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
148			u64 *val)
149{
150	struct vgic_vmcr vmcr;
151
152	vgic_get_vmcr(vcpu, &vmcr);
153	if (!vmcr.cbpr)
154		*val = FIELD_PREP(ICC_BPR1_EL1_MASK, vmcr.abpr);
155	else
156		*val = min((vmcr.bpr + 1), 7U);
157
158
159	return 0;
160}
161
162static int set_gic_grpen0(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
163			  u64 val)
164{
165	struct vgic_vmcr vmcr;
166
167	vgic_get_vmcr(vcpu, &vmcr);
168	vmcr.grpen0 = FIELD_GET(ICC_IGRPEN0_EL1_MASK, val);
169	vgic_set_vmcr(vcpu, &vmcr);
170
171	return 0;
172}
173
174static int get_gic_grpen0(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
175			  u64 *val)
176{
177	struct vgic_vmcr vmcr;
178
179	vgic_get_vmcr(vcpu, &vmcr);
180	*val = FIELD_PREP(ICC_IGRPEN0_EL1_MASK, vmcr.grpen0);
181
182	return 0;
183}
184
185static int set_gic_grpen1(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
186			  u64 val)
187{
188	struct vgic_vmcr vmcr;
189
190	vgic_get_vmcr(vcpu, &vmcr);
191	vmcr.grpen1 = FIELD_GET(ICC_IGRPEN1_EL1_MASK, val);
192	vgic_set_vmcr(vcpu, &vmcr);
193
194	return 0;
195}
196
197static int get_gic_grpen1(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
198			  u64 *val)
199{
200	struct vgic_vmcr vmcr;
201
202	vgic_get_vmcr(vcpu, &vmcr);
203	*val = FIELD_GET(ICC_IGRPEN1_EL1_MASK, vmcr.grpen1);
204
205	return 0;
206}
207
208static void set_apr_reg(struct kvm_vcpu *vcpu, u64 val, u8 apr, u8 idx)
209{
210	struct vgic_v3_cpu_if *vgicv3 = &vcpu->arch.vgic_cpu.vgic_v3;
211
212	if (apr)
213		vgicv3->vgic_ap1r[idx] = val;
214	else
215		vgicv3->vgic_ap0r[idx] = val;
216}
217
218static u64 get_apr_reg(struct kvm_vcpu *vcpu, u8 apr, u8 idx)
219{
220	struct vgic_v3_cpu_if *vgicv3 = &vcpu->arch.vgic_cpu.vgic_v3;
221
222	if (apr)
223		return vgicv3->vgic_ap1r[idx];
224	else
225		return vgicv3->vgic_ap0r[idx];
226}
227
228static int set_gic_ap0r(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
229			u64 val)
230
231{
232	u8 idx = r->Op2 & 3;
233
234	if (idx > vgic_v3_max_apr_idx(vcpu))
235		return -EINVAL;
236
237	set_apr_reg(vcpu, val, 0, idx);
238	return 0;
239}
240
241static int get_gic_ap0r(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
242			u64 *val)
243{
244	u8 idx = r->Op2 & 3;
245
246	if (idx > vgic_v3_max_apr_idx(vcpu))
247		return -EINVAL;
248
249	*val = get_apr_reg(vcpu, 0, idx);
250
251	return 0;
252}
253
254static int set_gic_ap1r(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
255			u64 val)
256
257{
258	u8 idx = r->Op2 & 3;
259
260	if (idx > vgic_v3_max_apr_idx(vcpu))
261		return -EINVAL;
262
263	set_apr_reg(vcpu, val, 1, idx);
264	return 0;
265}
266
267static int get_gic_ap1r(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
268			u64 *val)
269{
270	u8 idx = r->Op2 & 3;
271
272	if (idx > vgic_v3_max_apr_idx(vcpu))
273		return -EINVAL;
274
275	*val = get_apr_reg(vcpu, 1, idx);
276
277	return 0;
278}
279
280static int set_gic_sre(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
281		       u64 val)
282{
283	/* Validate SRE bit */
284	if (!(val & ICC_SRE_EL1_SRE))
285		return -EINVAL;
286
287	return 0;
288}
289
290static int get_gic_sre(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
291		       u64 *val)
292{
293	struct vgic_v3_cpu_if *vgicv3 = &vcpu->arch.vgic_cpu.vgic_v3;
294
295	*val = vgicv3->vgic_sre;
296
297	return 0;
298}
299
300static int set_gic_ich_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
301			   u64 val)
302{
303	__vcpu_assign_sys_reg(vcpu, r->reg, val);
304	return 0;
305}
306
307static int get_gic_ich_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
308			    u64 *val)
309{
310	*val = __vcpu_sys_reg(vcpu, r->reg);
311	return 0;
312}
313
314static int set_gic_ich_apr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
315			   u64 val)
316{
317	u8 idx = r->Op2 & 3;
318
319	if (idx > vgic_v3_max_apr_idx(vcpu))
320		return -EINVAL;
321
322	return set_gic_ich_reg(vcpu, r, val);
323}
324
325static int get_gic_ich_apr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
326			    u64 *val)
327{
328	u8 idx = r->Op2 & 3;
329
330	if (idx > vgic_v3_max_apr_idx(vcpu))
331		return -EINVAL;
332
333	return get_gic_ich_reg(vcpu, r, val);
334}
335
336static int set_gic_icc_sre(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
337			   u64 val)
338{
339	if (val != KVM_ICC_SRE_EL2)
340		return -EINVAL;
341	return 0;
342}
343
344static int get_gic_icc_sre(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
345			   u64 *val)
346{
347	*val = KVM_ICC_SRE_EL2;
348	return 0;
349}
350
351static int set_gic_ich_vtr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
352			   u64 val)
353{
354	if (val != kvm_get_guest_vtr_el2())
355		return -EINVAL;
356	return 0;
357}
358
359static int get_gic_ich_vtr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
360			   u64 *val)
361{
362	*val = kvm_get_guest_vtr_el2();
363	return 0;
364}
365
366static unsigned int el2_visibility(const struct kvm_vcpu *vcpu,
367				   const struct sys_reg_desc *rd)
368{
369	return vcpu_has_nv(vcpu) ? 0 : REG_HIDDEN;
370}
371
372#define __EL2_REG(r, acc, i)			\
373	{					\
374		SYS_DESC(SYS_ ## r),		\
375		.get_user = get_gic_ ## acc,	\
376		.set_user = set_gic_ ## acc,	\
377		.reg = i,			\
378		.visibility = el2_visibility,	\
379	}
380
381#define EL2_REG(r, acc)		__EL2_REG(r, acc, r)
382
383#define EL2_REG_RO(r, acc)	__EL2_REG(r, acc, 0)
384
385static const struct sys_reg_desc gic_v3_icc_reg_descs[] = {
386	{ SYS_DESC(SYS_ICC_PMR_EL1),
387	  .set_user = set_gic_pmr, .get_user = get_gic_pmr, },
388	{ SYS_DESC(SYS_ICC_BPR0_EL1),
389	  .set_user = set_gic_bpr0, .get_user = get_gic_bpr0, },
390	{ SYS_DESC(SYS_ICC_AP0R0_EL1),
391	  .set_user = set_gic_ap0r, .get_user = get_gic_ap0r, },
392	{ SYS_DESC(SYS_ICC_AP0R1_EL1),
393	  .set_user = set_gic_ap0r, .get_user = get_gic_ap0r, },
394	{ SYS_DESC(SYS_ICC_AP0R2_EL1),
395	  .set_user = set_gic_ap0r, .get_user = get_gic_ap0r, },
396	{ SYS_DESC(SYS_ICC_AP0R3_EL1),
397	  .set_user = set_gic_ap0r, .get_user = get_gic_ap0r, },
398	{ SYS_DESC(SYS_ICC_AP1R0_EL1),
399	  .set_user = set_gic_ap1r, .get_user = get_gic_ap1r, },
400	{ SYS_DESC(SYS_ICC_AP1R1_EL1),
401	  .set_user = set_gic_ap1r, .get_user = get_gic_ap1r, },
402	{ SYS_DESC(SYS_ICC_AP1R2_EL1),
403	  .set_user = set_gic_ap1r, .get_user = get_gic_ap1r, },
404	{ SYS_DESC(SYS_ICC_AP1R3_EL1),
405	  .set_user = set_gic_ap1r, .get_user = get_gic_ap1r, },
406	{ SYS_DESC(SYS_ICC_BPR1_EL1),
407	  .set_user = set_gic_bpr1, .get_user = get_gic_bpr1, },
408	{ SYS_DESC(SYS_ICC_CTLR_EL1),
409	  .set_user = set_gic_ctlr, .get_user = get_gic_ctlr, },
410	{ SYS_DESC(SYS_ICC_SRE_EL1),
411	  .set_user = set_gic_sre, .get_user = get_gic_sre, },
412	{ SYS_DESC(SYS_ICC_IGRPEN0_EL1),
413	  .set_user = set_gic_grpen0, .get_user = get_gic_grpen0, },
414	{ SYS_DESC(SYS_ICC_IGRPEN1_EL1),
415	  .set_user = set_gic_grpen1, .get_user = get_gic_grpen1, },
416	EL2_REG(ICH_AP0R0_EL2, ich_apr),
417	EL2_REG(ICH_AP0R1_EL2, ich_apr),
418	EL2_REG(ICH_AP0R2_EL2, ich_apr),
419	EL2_REG(ICH_AP0R3_EL2, ich_apr),
420	EL2_REG(ICH_AP1R0_EL2, ich_apr),
421	EL2_REG(ICH_AP1R1_EL2, ich_apr),
422	EL2_REG(ICH_AP1R2_EL2, ich_apr),
423	EL2_REG(ICH_AP1R3_EL2, ich_apr),
424	EL2_REG_RO(ICC_SRE_EL2, icc_sre),
425	EL2_REG(ICH_HCR_EL2, ich_reg),
426	EL2_REG_RO(ICH_VTR_EL2, ich_vtr),
427	EL2_REG(ICH_VMCR_EL2, ich_reg),
428	EL2_REG(ICH_LR0_EL2, ich_reg),
429	EL2_REG(ICH_LR1_EL2, ich_reg),
430	EL2_REG(ICH_LR2_EL2, ich_reg),
431	EL2_REG(ICH_LR3_EL2, ich_reg),
432	EL2_REG(ICH_LR4_EL2, ich_reg),
433	EL2_REG(ICH_LR5_EL2, ich_reg),
434	EL2_REG(ICH_LR6_EL2, ich_reg),
435	EL2_REG(ICH_LR7_EL2, ich_reg),
436	EL2_REG(ICH_LR8_EL2, ich_reg),
437	EL2_REG(ICH_LR9_EL2, ich_reg),
438	EL2_REG(ICH_LR10_EL2, ich_reg),
439	EL2_REG(ICH_LR11_EL2, ich_reg),
440	EL2_REG(ICH_LR12_EL2, ich_reg),
441	EL2_REG(ICH_LR13_EL2, ich_reg),
442	EL2_REG(ICH_LR14_EL2, ich_reg),
443	EL2_REG(ICH_LR15_EL2, ich_reg),
444};
445
446const struct sys_reg_desc *vgic_v3_get_sysreg_table(unsigned int *sz)
447{
448	*sz = ARRAY_SIZE(gic_v3_icc_reg_descs);
449	return gic_v3_icc_reg_descs;
450}
451
452static u64 attr_to_id(u64 attr)
453{
454	return ARM64_SYS_REG(FIELD_GET(KVM_REG_ARM_VGIC_SYSREG_OP0_MASK, attr),
455			     FIELD_GET(KVM_REG_ARM_VGIC_SYSREG_OP1_MASK, attr),
456			     FIELD_GET(KVM_REG_ARM_VGIC_SYSREG_CRN_MASK, attr),
457			     FIELD_GET(KVM_REG_ARM_VGIC_SYSREG_CRM_MASK, attr),
458			     FIELD_GET(KVM_REG_ARM_VGIC_SYSREG_OP2_MASK, attr));
459}
460
461int vgic_v3_has_cpu_sysregs_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr)
462{
463	const struct sys_reg_desc *r;
464
465	r = get_reg_by_id(attr_to_id(attr->attr), gic_v3_icc_reg_descs,
466			  ARRAY_SIZE(gic_v3_icc_reg_descs));
467
468	if (r && !sysreg_hidden(vcpu, r))
469		return 0;
470
471	return -ENXIO;
472}
473
474int vgic_v3_cpu_sysregs_uaccess(struct kvm_vcpu *vcpu,
475				struct kvm_device_attr *attr,
476				bool is_write)
477{
478	struct kvm_one_reg reg = {
479		.id	= attr_to_id(attr->attr),
480		.addr	= attr->addr,
481	};
482
483	if (is_write)
484		return kvm_sys_reg_set_user(vcpu, &reg, gic_v3_icc_reg_descs,
485					    ARRAY_SIZE(gic_v3_icc_reg_descs));
486	else
487		return kvm_sys_reg_get_user(vcpu, &reg, gic_v3_icc_reg_descs,
488					    ARRAY_SIZE(gic_v3_icc_reg_descs));
489}
~/ Read-only file preview.