Skip to content

Commit e5410ee

Browse files
Ricardo KollerMarc Zyngier
authored andcommitted
KVM: selftests: aarch64: Cmdline arg to set number of IRQs in vgic_irq test
Add the ability to specify the number of vIRQs exposed by KVM (arg defaults to 64). Then extend the KVM_IRQ_LINE test by injecting all available SPIs at once (specified by the nr-irqs arg). As a bonus, inject all SGIs at once as well. 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 e1cb399 commit e5410ee

File tree

4 files changed

+127
-35
lines changed

4 files changed

+127
-35
lines changed

tools/testing/selftests/kvm/aarch64/arch_timer.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -382,7 +382,7 @@ static struct kvm_vm *test_vm_create(void)
382382

383383
ucall_init(vm, NULL);
384384
test_init_timer_irq(vm);
385-
vgic_v3_setup(vm, nr_vcpus, GICD_BASE_GPA, GICR_BASE_GPA);
385+
vgic_v3_setup(vm, nr_vcpus, 64, GICD_BASE_GPA, GICR_BASE_GPA);
386386

387387
/* Make all the test's cmdline args visible to the guest */
388388
sync_global_to_guest(vm, test_args);

tools/testing/selftests/kvm/aarch64/vgic_irq.c

Lines changed: 117 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,14 @@
2323
#define GICR_BASE_GPA 0x080A0000ULL
2424
#define VCPU_ID 0
2525

26+
/*
27+
* Stores the user specified args; it's passed to the guest and to every test
28+
* function.
29+
*/
30+
struct test_args {
31+
uint32_t nr_irqs; /* number of KVM supported IRQs. */
32+
};
33+
2634
/*
2735
* KVM implements 32 priority levels:
2836
* 0x00 (highest priority) - 0xF8 (lowest priority), in steps of 8
@@ -51,14 +59,18 @@ typedef enum {
5159

5260
struct kvm_inject_args {
5361
kvm_inject_cmd cmd;
54-
uint32_t intid;
62+
uint32_t first_intid;
63+
uint32_t num;
5564
};
5665

5766
/* Used on the guest side to perform the hypercall. */
58-
static void kvm_inject_call(kvm_inject_cmd cmd, uint32_t intid);
67+
static void kvm_inject_call(kvm_inject_cmd cmd, uint32_t first_intid, uint32_t num);
5968

6069
#define KVM_INJECT(cmd, intid) \
61-
kvm_inject_call(cmd, intid)
70+
kvm_inject_call(cmd, intid, 1)
71+
72+
#define KVM_INJECT_MULTI(cmd, intid, num) \
73+
kvm_inject_call(cmd, intid, num)
6274

6375
/* Used on the host side to get the hypercall info. */
6476
static void kvm_inject_get_call(struct kvm_vm *vm, struct ucall *uc,
@@ -122,11 +134,12 @@ static void guest_irq_handler(struct ex_regs *regs)
122134
GUEST_ASSERT(!gic_irq_get_pending(intid));
123135
}
124136

125-
static void kvm_inject_call(kvm_inject_cmd cmd, uint32_t intid)
137+
static void kvm_inject_call(kvm_inject_cmd cmd, uint32_t first_intid, uint32_t num)
126138
{
127139
struct kvm_inject_args args = {
128140
.cmd = cmd,
129-
.intid = intid,
141+
.first_intid = first_intid,
142+
.num = num,
130143
};
131144
GUEST_SYNC(&args);
132145
}
@@ -138,14 +151,30 @@ do { \
138151
GUEST_ASSERT(_intid == 0 || _intid == IAR_SPURIOUS); \
139152
} while (0)
140153

141-
static void guest_inject(uint32_t intid, kvm_inject_cmd cmd)
154+
static void reset_priorities(struct test_args *args)
155+
{
156+
int i;
157+
158+
for (i = 0; i < args->nr_irqs; i++)
159+
gic_set_priority(i, IRQ_DEFAULT_PRIO_REG);
160+
}
161+
162+
static void guest_inject(struct test_args *args,
163+
uint32_t first_intid, uint32_t num,
164+
kvm_inject_cmd cmd)
142165
{
166+
uint32_t i;
167+
143168
reset_stats();
144169

170+
/* Cycle over all priorities to make things more interesting. */
171+
for (i = first_intid; i < num + first_intid; i++)
172+
gic_set_priority(i, (i % (KVM_NUM_PRIOS - 1)) << 3);
173+
145174
asm volatile("msr daifset, #2" : : : "memory");
146-
KVM_INJECT(cmd, intid);
175+
KVM_INJECT_MULTI(cmd, first_intid, num);
147176

148-
while (irq_handled < 1) {
177+
while (irq_handled < num) {
149178
asm volatile("wfi\n"
150179
"msr daifclr, #2\n"
151180
/* handle IRQ */
@@ -154,57 +183,72 @@ static void guest_inject(uint32_t intid, kvm_inject_cmd cmd)
154183
}
155184
asm volatile("msr daifclr, #2" : : : "memory");
156185

157-
GUEST_ASSERT_EQ(irq_handled, 1);
158-
GUEST_ASSERT_EQ(irqnr_received[intid], 1);
186+
GUEST_ASSERT_EQ(irq_handled, num);
187+
for (i = first_intid; i < num + first_intid; i++)
188+
GUEST_ASSERT_EQ(irqnr_received[i], 1);
159189
GUEST_ASSERT_IAR_EMPTY();
190+
191+
reset_priorities(args);
160192
}
161193

162-
static void test_injection(struct kvm_inject_desc *f)
194+
static void test_injection(struct test_args *args, struct kvm_inject_desc *f)
163195
{
164-
if (f->sgi)
165-
guest_inject(MIN_SGI, f->cmd);
196+
uint32_t nr_irqs = args->nr_irqs;
197+
198+
if (f->sgi) {
199+
guest_inject(args, MIN_SGI, 1, f->cmd);
200+
guest_inject(args, 0, 16, f->cmd);
201+
}
166202

167203
if (f->ppi)
168-
guest_inject(MIN_PPI, f->cmd);
204+
guest_inject(args, MIN_PPI, 1, f->cmd);
169205

170-
if (f->spi)
171-
guest_inject(MIN_SPI, f->cmd);
206+
if (f->spi) {
207+
guest_inject(args, MIN_SPI, 1, f->cmd);
208+
guest_inject(args, nr_irqs - 1, 1, f->cmd);
209+
guest_inject(args, MIN_SPI, nr_irqs - MIN_SPI, f->cmd);
210+
}
172211
}
173212

174-
static void guest_code(void)
213+
static void guest_code(struct test_args args)
175214
{
176-
uint32_t i;
177-
uint32_t nr_irqs = 64; /* absolute minimum number of IRQs supported. */
215+
uint32_t i, nr_irqs = args.nr_irqs;
178216
struct kvm_inject_desc *f;
179217

180218
gic_init(GIC_V3, 1, dist, redist);
181219

182-
for (i = 0; i < nr_irqs; i++) {
220+
for (i = 0; i < nr_irqs; i++)
183221
gic_irq_enable(i);
184-
gic_set_priority(i, IRQ_DEFAULT_PRIO_REG);
185-
}
186222

223+
reset_priorities(&args);
187224
gic_set_priority_mask(CPU_PRIO_MASK);
188225

189226
local_irq_enable();
190227

191228
/* Start the tests. */
192229
for_each_inject_fn(inject_edge_fns, f)
193-
test_injection(f);
230+
test_injection(&args, f);
194231

195232
GUEST_DONE();
196233
}
197234

198235
static void run_guest_cmd(struct kvm_vm *vm, int gic_fd,
199-
struct kvm_inject_args *inject_args)
236+
struct kvm_inject_args *inject_args,
237+
struct test_args *test_args)
200238
{
201239
kvm_inject_cmd cmd = inject_args->cmd;
202-
uint32_t intid = inject_args->intid;
240+
uint32_t intid = inject_args->first_intid;
241+
uint32_t num = inject_args->num;
242+
uint32_t i;
243+
244+
assert(intid < UINT_MAX - num);
203245

204246
switch (cmd) {
205247
case KVM_INJECT_EDGE_IRQ_LINE:
206-
kvm_arm_irq_line(vm, intid, 1);
207-
kvm_arm_irq_line(vm, intid, 0);
248+
for (i = intid; i < intid + num; i++)
249+
kvm_arm_irq_line(vm, i, 1);
250+
for (i = intid; i < intid + num; i++)
251+
kvm_arm_irq_line(vm, i, 0);
208252
break;
209253
default:
210254
break;
@@ -222,21 +266,35 @@ static void kvm_inject_get_call(struct kvm_vm *vm, struct ucall *uc,
222266
memcpy(args, kvm_args_hva, sizeof(struct kvm_inject_args));
223267
}
224268

269+
static void print_args(struct test_args *args)
270+
{
271+
printf("nr-irqs=%d\n", args->nr_irqs);
272+
}
225273

226-
static void test_vgic(void)
274+
static void test_vgic(uint32_t nr_irqs)
227275
{
228276
struct ucall uc;
229277
int gic_fd;
230278
struct kvm_vm *vm;
231279
struct kvm_inject_args inject_args;
232280

281+
struct test_args args = {
282+
.nr_irqs = nr_irqs,
283+
};
284+
285+
print_args(&args);
286+
233287
vm = vm_create_default(VCPU_ID, 0, guest_code);
234288
ucall_init(vm, NULL);
235289

236290
vm_init_descriptor_tables(vm);
237291
vcpu_init_descriptor_tables(vm, VCPU_ID);
238292

239-
gic_fd = vgic_v3_setup(vm, 1, GICD_BASE_GPA, GICR_BASE_GPA);
293+
/* Setup the guest args page (so it gets the args). */
294+
vcpu_args_set(vm, 0, 1, args);
295+
296+
gic_fd = vgic_v3_setup(vm, 1, nr_irqs,
297+
GICD_BASE_GPA, GICR_BASE_GPA);
240298

241299
vm_install_exception_handler(vm, VECTOR_IRQ_CURRENT,
242300
guest_irq_handler);
@@ -247,7 +305,7 @@ static void test_vgic(void)
247305
switch (get_ucall(vm, VCPU_ID, &uc)) {
248306
case UCALL_SYNC:
249307
kvm_inject_get_call(vm, &uc, &inject_args);
250-
run_guest_cmd(vm, gic_fd, &inject_args);
308+
run_guest_cmd(vm, gic_fd, &inject_args, &args);
251309
break;
252310
case UCALL_ABORT:
253311
TEST_FAIL("%s at %s:%ld\n\tvalues: %#lx, %#lx",
@@ -266,12 +324,39 @@ static void test_vgic(void)
266324
kvm_vm_free(vm);
267325
}
268326

269-
int main(int ac, char **av)
327+
static void help(const char *name)
270328
{
329+
printf(
330+
"\n"
331+
"usage: %s [-n num_irqs]\n", name);
332+
printf(" -n: specify the number of IRQs to configure the vgic with.\n");
333+
puts("");
334+
exit(1);
335+
}
336+
337+
int main(int argc, char **argv)
338+
{
339+
uint32_t nr_irqs = 64;
340+
int opt;
341+
271342
/* Tell stdout not to buffer its content */
272343
setbuf(stdout, NULL);
273344

274-
test_vgic();
345+
while ((opt = getopt(argc, argv, "hg:n:")) != -1) {
346+
switch (opt) {
347+
case 'n':
348+
nr_irqs = atoi(optarg);
349+
if (nr_irqs > 1024 || nr_irqs % 32)
350+
help(argv[0]);
351+
break;
352+
case 'h':
353+
default:
354+
help(argv[0]);
355+
break;
356+
}
357+
}
358+
359+
test_vgic(nr_irqs);
275360

276361
return 0;
277362
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
((uint64_t)(flags) << 12) | \
1515
index)
1616

17-
int vgic_v3_setup(struct kvm_vm *vm, unsigned int nr_vcpus,
17+
int vgic_v3_setup(struct kvm_vm *vm, unsigned int nr_vcpus, uint32_t nr_irqs,
1818
uint64_t gicd_base_gpa, uint64_t gicr_base_gpa);
1919

2020
#define VGIC_MAX_RESERVED 1023

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

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
* redistributor regions of the guest. Since it depends on the number of
3232
* vCPUs for the VM, it must be called after all the vCPUs have been created.
3333
*/
34-
int vgic_v3_setup(struct kvm_vm *vm, unsigned int nr_vcpus,
34+
int vgic_v3_setup(struct kvm_vm *vm, unsigned int nr_vcpus, uint32_t nr_irqs,
3535
uint64_t gicd_base_gpa, uint64_t gicr_base_gpa)
3636
{
3737
int gic_fd;
@@ -53,6 +53,13 @@ int vgic_v3_setup(struct kvm_vm *vm, unsigned int nr_vcpus,
5353

5454
/* Distributor setup */
5555
gic_fd = kvm_create_device(vm, KVM_DEV_TYPE_ARM_VGIC_V3, false);
56+
57+
kvm_device_access(gic_fd, KVM_DEV_ARM_VGIC_GRP_NR_IRQS,
58+
0, &nr_irqs, true);
59+
60+
kvm_device_access(gic_fd, KVM_DEV_ARM_VGIC_GRP_CTRL,
61+
KVM_DEV_ARM_VGIC_CTRL_INIT, NULL, true);
62+
5663
kvm_device_access(gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
5764
KVM_VGIC_V3_ADDR_TYPE_DIST, &gicd_base_gpa, true);
5865
nr_gic_pages = vm_calc_num_guest_pages(vm->mode, KVM_VGIC_V3_DIST_SIZE);

0 commit comments

Comments
 (0)