Skip to content

Commit e95def3

Browse files
Ricardo KollerMarc Zyngier
authored andcommitted
KVM: selftests: aarch64: Add vGIC library functions to deal with vIRQ state
Add a set of library functions for userspace code in selftests to deal with vIRQ state (i.e., ioctl wrappers). Signed-off-by: Ricardo Koller <[email protected]> Acked-by: Andrew Jones <[email protected]> Signed-off-by: Marc Zyngier <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 227895e commit e95def3

File tree

3 files changed

+116
-1
lines changed

3 files changed

+116
-1
lines changed

tools/testing/selftests/kvm/include/aarch64/gic.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,16 @@ enum gic_type {
1111
GIC_TYPE_MAX,
1212
};
1313

14+
#define MIN_SGI 0
15+
#define MIN_PPI 16
16+
#define MIN_SPI 32
17+
#define MAX_SPI 1019
18+
#define IAR_SPURIOUS 1023
19+
20+
#define INTID_IS_SGI(intid) (0 <= (intid) && (intid) < MIN_PPI)
21+
#define INTID_IS_PPI(intid) (MIN_PPI <= (intid) && (intid) < MIN_SPI)
22+
#define INTID_IS_SPI(intid) (MIN_SPI <= (intid) && (intid) <= MAX_SPI)
23+
1424
void gic_init(enum gic_type type, unsigned int nr_cpus,
1525
void *dist_base, void *redist_base);
1626
void gic_irq_enable(unsigned int intid);

tools/testing/selftests/kvm/include/aarch64/vgic.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,16 @@
1717
int vgic_v3_setup(struct kvm_vm *vm, unsigned int nr_vcpus,
1818
uint64_t gicd_base_gpa, uint64_t gicr_base_gpa);
1919

20-
#endif /* SELFTEST_KVM_VGIC_H */
20+
#define VGIC_MAX_RESERVED 1023
21+
22+
void kvm_irq_set_level_info(int gic_fd, uint32_t intid, int level);
23+
int _kvm_irq_set_level_info(int gic_fd, uint32_t intid, int level);
24+
25+
void kvm_arm_irq_line(struct kvm_vm *vm, uint32_t intid, int level);
26+
int _kvm_arm_irq_line(struct kvm_vm *vm, uint32_t intid, int level);
27+
28+
/* The vcpu arg only applies to private interrupts. */
29+
void kvm_irq_write_ispendr(int gic_fd, uint32_t intid, uint32_t vcpu);
30+
void kvm_irq_write_isactiver(int gic_fd, uint32_t intid, uint32_t vcpu);
31+
32+
#endif // SELFTEST_KVM_VGIC_H

tools/testing/selftests/kvm/lib/aarch64/vgic.c

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,14 @@
55

66
#include <linux/kvm.h>
77
#include <linux/sizes.h>
8+
#include <asm/kvm_para.h>
89
#include <asm/kvm.h>
910

1011
#include "kvm_util.h"
1112
#include "../kvm_util_internal.h"
1213
#include "vgic.h"
14+
#include "gic.h"
15+
#include "gic_v3.h"
1316

1417
/*
1518
* vGIC-v3 default host setup
@@ -68,3 +71,93 @@ int vgic_v3_setup(struct kvm_vm *vm, unsigned int nr_vcpus,
6871

6972
return gic_fd;
7073
}
74+
75+
/* should only work for level sensitive interrupts */
76+
int _kvm_irq_set_level_info(int gic_fd, uint32_t intid, int level)
77+
{
78+
uint64_t attr = 32 * (intid / 32);
79+
uint64_t index = intid % 32;
80+
uint64_t val;
81+
int ret;
82+
83+
ret = _kvm_device_access(gic_fd, KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO,
84+
attr, &val, false);
85+
if (ret != 0)
86+
return ret;
87+
88+
val |= 1U << index;
89+
ret = _kvm_device_access(gic_fd, KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO,
90+
attr, &val, true);
91+
return ret;
92+
}
93+
94+
void kvm_irq_set_level_info(int gic_fd, uint32_t intid, int level)
95+
{
96+
int ret = _kvm_irq_set_level_info(gic_fd, intid, level);
97+
98+
TEST_ASSERT(ret == 0, "KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO failed, "
99+
"rc: %i errno: %i", ret, errno);
100+
}
101+
102+
int _kvm_arm_irq_line(struct kvm_vm *vm, uint32_t intid, int level)
103+
{
104+
uint32_t irq = intid & KVM_ARM_IRQ_NUM_MASK;
105+
106+
if (INTID_IS_PPI(intid))
107+
irq |= KVM_ARM_IRQ_TYPE_PPI << KVM_ARM_IRQ_TYPE_SHIFT;
108+
else if (INTID_IS_SPI(intid))
109+
irq |= KVM_ARM_IRQ_TYPE_SPI << KVM_ARM_IRQ_TYPE_SHIFT;
110+
else
111+
TEST_FAIL("KVM_IRQ_LINE can't be used with SGIs.");
112+
113+
return _kvm_irq_line(vm, irq, level);
114+
}
115+
116+
void kvm_arm_irq_line(struct kvm_vm *vm, uint32_t intid, int level)
117+
{
118+
int ret = _kvm_arm_irq_line(vm, intid, level);
119+
120+
TEST_ASSERT(ret == 0, "KVM_IRQ_LINE failed, rc: %i errno: %i",
121+
ret, errno);
122+
}
123+
124+
static void vgic_poke_irq(int gic_fd, uint32_t intid,
125+
uint32_t vcpu, uint64_t reg_off)
126+
{
127+
uint64_t reg = intid / 32;
128+
uint64_t index = intid % 32;
129+
uint64_t attr = reg_off + reg * 4;
130+
uint64_t val;
131+
bool intid_is_private = INTID_IS_SGI(intid) || INTID_IS_PPI(intid);
132+
133+
/* Check that the addr part of the attr is within 32 bits. */
134+
assert(attr <= KVM_DEV_ARM_VGIC_OFFSET_MASK);
135+
136+
uint32_t group = intid_is_private ? KVM_DEV_ARM_VGIC_GRP_REDIST_REGS
137+
: KVM_DEV_ARM_VGIC_GRP_DIST_REGS;
138+
139+
if (intid_is_private) {
140+
/* TODO: only vcpu 0 implemented for now. */
141+
assert(vcpu == 0);
142+
attr += SZ_64K;
143+
}
144+
145+
/* All calls will succeed, even with invalid intid's, as long as the
146+
* addr part of the attr is within 32 bits (checked above). An invalid
147+
* intid will just make the read/writes point to above the intended
148+
* register space (i.e., ICPENDR after ISPENDR).
149+
*/
150+
kvm_device_access(gic_fd, group, attr, &val, false);
151+
val |= 1ULL << index;
152+
kvm_device_access(gic_fd, group, attr, &val, true);
153+
}
154+
155+
void kvm_irq_write_ispendr(int gic_fd, uint32_t intid, uint32_t vcpu)
156+
{
157+
vgic_poke_irq(gic_fd, intid, vcpu, GICD_ISPENDR);
158+
}
159+
160+
void kvm_irq_write_isactiver(int gic_fd, uint32_t intid, uint32_t vcpu)
161+
{
162+
vgic_poke_irq(gic_fd, intid, vcpu, GICD_ISACTIVER);
163+
}

0 commit comments

Comments
 (0)