Skip to content

Commit 90f50ac

Browse files
Ricardo KollerMarc Zyngier
authored andcommitted
KVM: selftests: aarch64: Add test_inject_fail to vgic_irq
Add tests for failed injections to vgic_irq. This tests that KVM can handle bogus IRQ numbers. 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 6830fa9 commit 90f50ac

File tree

2 files changed

+109
-20
lines changed

2 files changed

+109
-20
lines changed

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

Lines changed: 105 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -68,21 +68,28 @@ struct kvm_inject_args {
6868
uint32_t first_intid;
6969
uint32_t num;
7070
int level;
71+
bool expect_failure;
7172
};
7273

7374
/* Used on the guest side to perform the hypercall. */
7475
static void kvm_inject_call(kvm_inject_cmd cmd, uint32_t first_intid,
75-
uint32_t num, int level);
76+
uint32_t num, int level, bool expect_failure);
7677

7778
/* Used on the host side to get the hypercall info. */
7879
static void kvm_inject_get_call(struct kvm_vm *vm, struct ucall *uc,
7980
struct kvm_inject_args *args);
8081

81-
#define KVM_INJECT(cmd, intid) \
82-
kvm_inject_call(cmd, intid, 1, -1 /* not used */)
82+
#define _KVM_INJECT_MULTI(cmd, intid, num, expect_failure) \
83+
kvm_inject_call(cmd, intid, num, -1 /* not used */, expect_failure)
8384

8485
#define KVM_INJECT_MULTI(cmd, intid, num) \
85-
kvm_inject_call(cmd, intid, num, -1 /* not used */)
86+
_KVM_INJECT_MULTI(cmd, intid, num, false)
87+
88+
#define _KVM_INJECT(cmd, intid, expect_failure) \
89+
_KVM_INJECT_MULTI(cmd, intid, 1, expect_failure)
90+
91+
#define KVM_INJECT(cmd, intid) \
92+
_KVM_INJECT_MULTI(cmd, intid, 1, false)
8693

8794
struct kvm_inject_desc {
8895
kvm_inject_cmd cmd;
@@ -158,13 +165,14 @@ static void guest_irq_generic_handler(bool eoi_split, bool level_sensitive)
158165
}
159166

160167
static void kvm_inject_call(kvm_inject_cmd cmd, uint32_t first_intid,
161-
uint32_t num, int level)
168+
uint32_t num, int level, bool expect_failure)
162169
{
163170
struct kvm_inject_args args = {
164171
.cmd = cmd,
165172
.first_intid = first_intid,
166173
.num = num,
167174
.level = level,
175+
.expect_failure = expect_failure,
168176
};
169177
GUEST_SYNC(&args);
170178
}
@@ -206,7 +214,19 @@ static void reset_priorities(struct test_args *args)
206214

207215
static void guest_set_irq_line(uint32_t intid, uint32_t level)
208216
{
209-
kvm_inject_call(KVM_SET_IRQ_LINE, intid, 1, level);
217+
kvm_inject_call(KVM_SET_IRQ_LINE, intid, 1, level, false);
218+
}
219+
220+
static void test_inject_fail(struct test_args *args,
221+
uint32_t intid, kvm_inject_cmd cmd)
222+
{
223+
reset_stats();
224+
225+
_KVM_INJECT(cmd, intid, true);
226+
/* no IRQ to handle on entry */
227+
228+
GUEST_ASSERT_EQ(irq_handled, 0);
229+
GUEST_ASSERT_IAR_EMPTY();
210230
}
211231

212232
static void guest_inject(struct test_args *args,
@@ -330,6 +350,16 @@ static void test_injection(struct test_args *args, struct kvm_inject_desc *f)
330350
}
331351
}
332352

353+
static void test_injection_failure(struct test_args *args,
354+
struct kvm_inject_desc *f)
355+
{
356+
uint32_t bad_intid[] = { args->nr_irqs, 1020, 1024, 1120, 5120, ~0U, };
357+
int i;
358+
359+
for (i = 0; i < ARRAY_SIZE(bad_intid); i++)
360+
test_inject_fail(args, bad_intid[i], f->cmd);
361+
}
362+
333363
static void test_preemption(struct test_args *args, struct kvm_inject_desc *f)
334364
{
335365
/*
@@ -376,11 +406,61 @@ static void guest_code(struct test_args args)
376406
for_each_inject_fn(inject_fns, f) {
377407
test_injection(&args, f);
378408
test_preemption(&args, f);
409+
test_injection_failure(&args, f);
379410
}
380411

381412
GUEST_DONE();
382413
}
383414

415+
static void kvm_irq_line_check(struct kvm_vm *vm, uint32_t intid, int level,
416+
struct test_args *test_args, bool expect_failure)
417+
{
418+
int ret;
419+
420+
if (!expect_failure) {
421+
kvm_arm_irq_line(vm, intid, level);
422+
} else {
423+
/* The interface doesn't allow larger intid's. */
424+
if (intid > KVM_ARM_IRQ_NUM_MASK)
425+
return;
426+
427+
ret = _kvm_arm_irq_line(vm, intid, level);
428+
TEST_ASSERT(ret != 0 && errno == EINVAL,
429+
"Bad intid %i did not cause KVM_IRQ_LINE "
430+
"error: rc: %i errno: %i", intid, ret, errno);
431+
}
432+
}
433+
434+
void kvm_irq_set_level_info_check(int gic_fd, uint32_t intid, int level,
435+
bool expect_failure)
436+
{
437+
if (!expect_failure) {
438+
kvm_irq_set_level_info(gic_fd, intid, level);
439+
} else {
440+
int ret = _kvm_irq_set_level_info(gic_fd, intid, level);
441+
/*
442+
* The kernel silently fails for invalid SPIs and SGIs (which
443+
* are not level-sensitive). It only checks for intid to not
444+
* spill over 1U << 10 (the max reserved SPI). Also, callers
445+
* are supposed to mask the intid with 0x3ff (1023).
446+
*/
447+
if (intid > VGIC_MAX_RESERVED)
448+
TEST_ASSERT(ret != 0 && errno == EINVAL,
449+
"Bad intid %i did not cause VGIC_GRP_LEVEL_INFO "
450+
"error: rc: %i errno: %i", intid, ret, errno);
451+
else
452+
TEST_ASSERT(!ret, "KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO "
453+
"for intid %i failed, rc: %i errno: %i",
454+
intid, ret, errno);
455+
}
456+
}
457+
458+
/* handles the valid case: intid=0xffffffff num=1 */
459+
#define for_each_intid(first, num, tmp, i) \
460+
for ((tmp) = (i) = (first); \
461+
(tmp) < (uint64_t)(first) + (uint64_t)(num); \
462+
(tmp)++, (i)++)
463+
384464
static void run_guest_cmd(struct kvm_vm *vm, int gic_fd,
385465
struct kvm_inject_args *inject_args,
386466
struct test_args *test_args)
@@ -389,28 +469,36 @@ static void run_guest_cmd(struct kvm_vm *vm, int gic_fd,
389469
uint32_t intid = inject_args->first_intid;
390470
uint32_t num = inject_args->num;
391471
int level = inject_args->level;
472+
bool expect_failure = inject_args->expect_failure;
473+
uint64_t tmp;
392474
uint32_t i;
393475

394-
assert(intid < UINT_MAX - num);
476+
/* handles the valid case: intid=0xffffffff num=1 */
477+
assert(intid < UINT_MAX - num || num == 1);
395478

396479
switch (cmd) {
397480
case KVM_INJECT_EDGE_IRQ_LINE:
398-
for (i = intid; i < intid + num; i++)
399-
kvm_arm_irq_line(vm, i, 1);
400-
for (i = intid; i < intid + num; i++)
401-
kvm_arm_irq_line(vm, i, 0);
481+
for_each_intid(intid, num, tmp, i)
482+
kvm_irq_line_check(vm, i, 1, test_args,
483+
expect_failure);
484+
for_each_intid(intid, num, tmp, i)
485+
kvm_irq_line_check(vm, i, 0, test_args,
486+
expect_failure);
402487
break;
403488
case KVM_SET_IRQ_LINE:
404-
for (i = intid; i < intid + num; i++)
405-
kvm_arm_irq_line(vm, i, level);
489+
for_each_intid(intid, num, tmp, i)
490+
kvm_irq_line_check(vm, i, level, test_args,
491+
expect_failure);
406492
break;
407493
case KVM_SET_IRQ_LINE_HIGH:
408-
for (i = intid; i < intid + num; i++)
409-
kvm_arm_irq_line(vm, i, 1);
494+
for_each_intid(intid, num, tmp, i)
495+
kvm_irq_line_check(vm, i, 1, test_args,
496+
expect_failure);
410497
break;
411498
case KVM_SET_LEVEL_INFO_HIGH:
412-
for (i = intid; i < intid + num; i++)
413-
kvm_irq_set_level_info(gic_fd, i, 1);
499+
for_each_intid(intid, num, tmp, i)
500+
kvm_irq_set_level_info_check(gic_fd, i, 1,
501+
expect_failure);
414502
break;
415503
default:
416504
break;

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -110,12 +110,13 @@ int _kvm_arm_irq_line(struct kvm_vm *vm, uint32_t intid, int level)
110110
{
111111
uint32_t irq = intid & KVM_ARM_IRQ_NUM_MASK;
112112

113+
TEST_ASSERT(!INTID_IS_SGI(intid), "KVM_IRQ_LINE's interface itself "
114+
"doesn't allow injecting SGIs. There's no mask for it.");
115+
113116
if (INTID_IS_PPI(intid))
114117
irq |= KVM_ARM_IRQ_TYPE_PPI << KVM_ARM_IRQ_TYPE_SHIFT;
115-
else if (INTID_IS_SPI(intid))
116-
irq |= KVM_ARM_IRQ_TYPE_SPI << KVM_ARM_IRQ_TYPE_SHIFT;
117118
else
118-
TEST_FAIL("KVM_IRQ_LINE can't be used with SGIs.");
119+
irq |= KVM_ARM_IRQ_TYPE_SPI << KVM_ARM_IRQ_TYPE_SHIFT;
119120

120121
return _kvm_irq_line(vm, irq, level);
121122
}

0 commit comments

Comments
 (0)