@@ -68,21 +68,28 @@ struct kvm_inject_args {
68
68
uint32_t first_intid ;
69
69
uint32_t num ;
70
70
int level ;
71
+ bool expect_failure ;
71
72
};
72
73
73
74
/* Used on the guest side to perform the hypercall. */
74
75
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 );
76
77
77
78
/* Used on the host side to get the hypercall info. */
78
79
static void kvm_inject_get_call (struct kvm_vm * vm , struct ucall * uc ,
79
80
struct kvm_inject_args * args );
80
81
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 )
83
84
84
85
#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)
86
93
87
94
struct kvm_inject_desc {
88
95
kvm_inject_cmd cmd ;
@@ -158,13 +165,14 @@ static void guest_irq_generic_handler(bool eoi_split, bool level_sensitive)
158
165
}
159
166
160
167
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 )
162
169
{
163
170
struct kvm_inject_args args = {
164
171
.cmd = cmd ,
165
172
.first_intid = first_intid ,
166
173
.num = num ,
167
174
.level = level ,
175
+ .expect_failure = expect_failure ,
168
176
};
169
177
GUEST_SYNC (& args );
170
178
}
@@ -206,7 +214,19 @@ static void reset_priorities(struct test_args *args)
206
214
207
215
static void guest_set_irq_line (uint32_t intid , uint32_t level )
208
216
{
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 ();
210
230
}
211
231
212
232
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)
330
350
}
331
351
}
332
352
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
+
333
363
static void test_preemption (struct test_args * args , struct kvm_inject_desc * f )
334
364
{
335
365
/*
@@ -376,11 +406,61 @@ static void guest_code(struct test_args args)
376
406
for_each_inject_fn (inject_fns , f ) {
377
407
test_injection (& args , f );
378
408
test_preemption (& args , f );
409
+ test_injection_failure (& args , f );
379
410
}
380
411
381
412
GUEST_DONE ();
382
413
}
383
414
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
+
384
464
static void run_guest_cmd (struct kvm_vm * vm , int gic_fd ,
385
465
struct kvm_inject_args * inject_args ,
386
466
struct test_args * test_args )
@@ -389,28 +469,36 @@ static void run_guest_cmd(struct kvm_vm *vm, int gic_fd,
389
469
uint32_t intid = inject_args -> first_intid ;
390
470
uint32_t num = inject_args -> num ;
391
471
int level = inject_args -> level ;
472
+ bool expect_failure = inject_args -> expect_failure ;
473
+ uint64_t tmp ;
392
474
uint32_t i ;
393
475
394
- assert (intid < UINT_MAX - num );
476
+ /* handles the valid case: intid=0xffffffff num=1 */
477
+ assert (intid < UINT_MAX - num || num == 1 );
395
478
396
479
switch (cmd ) {
397
480
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 );
402
487
break ;
403
488
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 );
406
492
break ;
407
493
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 );
410
497
break ;
411
498
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 );
414
502
break ;
415
503
default :
416
504
break ;
0 commit comments