30
30
struct test_args {
31
31
uint32_t nr_irqs ; /* number of KVM supported IRQs. */
32
32
bool eoi_split ; /* 1 is eoir+dir, 0 is eoir only */
33
+ bool level_sensitive ; /* 1 is level, 0 is edge */
33
34
};
34
35
35
36
/*
@@ -57,27 +58,31 @@ static void *redist = (void *)GICR_BASE_GPA;
57
58
58
59
typedef enum {
59
60
KVM_INJECT_EDGE_IRQ_LINE = 1 ,
61
+ KVM_SET_IRQ_LINE ,
62
+ KVM_SET_IRQ_LINE_HIGH ,
60
63
} kvm_inject_cmd ;
61
64
62
65
struct kvm_inject_args {
63
66
kvm_inject_cmd cmd ;
64
67
uint32_t first_intid ;
65
68
uint32_t num ;
69
+ int level ;
66
70
};
67
71
68
72
/* Used on the guest side to perform the hypercall. */
69
- static void kvm_inject_call (kvm_inject_cmd cmd , uint32_t first_intid , uint32_t num );
70
-
71
- #define KVM_INJECT (cmd , intid ) \
72
- kvm_inject_call(cmd, intid, 1)
73
-
74
- #define KVM_INJECT_MULTI (cmd , intid , num ) \
75
- kvm_inject_call(cmd, intid, num)
73
+ static void kvm_inject_call (kvm_inject_cmd cmd , uint32_t first_intid ,
74
+ uint32_t num , int level );
76
75
77
76
/* Used on the host side to get the hypercall info. */
78
77
static void kvm_inject_get_call (struct kvm_vm * vm , struct ucall * uc ,
79
78
struct kvm_inject_args * args );
80
79
80
+ #define KVM_INJECT (cmd , intid ) \
81
+ kvm_inject_call(cmd, intid, 1, -1 /* not used */ )
82
+
83
+ #define KVM_INJECT_MULTI (cmd , intid , num ) \
84
+ kvm_inject_call(cmd, intid, num, -1 /* not used */ )
85
+
81
86
struct kvm_inject_desc {
82
87
kvm_inject_cmd cmd ;
83
88
/* can inject PPIs, PPIs, and/or SPIs. */
@@ -90,6 +95,12 @@ static struct kvm_inject_desc inject_edge_fns[] = {
90
95
{ 0 , },
91
96
};
92
97
98
+ static struct kvm_inject_desc inject_level_fns [] = {
99
+ /* sgi ppi spi */
100
+ { KVM_SET_IRQ_LINE_HIGH , false, true, true },
101
+ { 0 , },
102
+ };
103
+
93
104
#define for_each_inject_fn (t , f ) \
94
105
for ((f) = (t); (f)->cmd; (f)++)
95
106
@@ -114,7 +125,9 @@ static uint64_t gic_read_ap1r0(void)
114
125
return reg ;
115
126
}
116
127
117
- static void guest_irq_generic_handler (bool eoi_split )
128
+ static void guest_set_irq_line (uint32_t intid , uint32_t level );
129
+
130
+ static void guest_irq_generic_handler (bool eoi_split , bool level_sensitive )
118
131
{
119
132
uint32_t intid = gic_get_and_ack_irq ();
120
133
@@ -123,7 +136,11 @@ static void guest_irq_generic_handler(bool eoi_split)
123
136
124
137
GUEST_ASSERT (gic_irq_get_active (intid ));
125
138
126
- GUEST_ASSERT (!gic_irq_get_pending (intid ));
139
+ if (!level_sensitive )
140
+ GUEST_ASSERT (!gic_irq_get_pending (intid ));
141
+
142
+ if (level_sensitive )
143
+ guest_set_irq_line (intid , 0 );
127
144
128
145
GUEST_ASSERT (intid < MAX_SPI );
129
146
irqnr_received [intid ] += 1 ;
@@ -138,12 +155,14 @@ static void guest_irq_generic_handler(bool eoi_split)
138
155
GUEST_ASSERT (!gic_irq_get_pending (intid ));
139
156
}
140
157
141
- static void kvm_inject_call (kvm_inject_cmd cmd , uint32_t first_intid , uint32_t num )
158
+ static void kvm_inject_call (kvm_inject_cmd cmd , uint32_t first_intid ,
159
+ uint32_t num , int level )
142
160
{
143
161
struct kvm_inject_args args = {
144
162
.cmd = cmd ,
145
163
.first_intid = first_intid ,
146
164
.num = num ,
165
+ .level = level ,
147
166
};
148
167
GUEST_SYNC (& args );
149
168
}
@@ -158,19 +177,21 @@ do { \
158
177
#define CAT_HELPER (a , b ) a ## b
159
178
#define CAT (a , b ) CAT_HELPER(a, b)
160
179
#define PREFIX guest_irq_handler_
161
- #define GUEST_IRQ_HANDLER_NAME (split ) CAT(PREFIX, split)
162
- #define GENERATE_GUEST_IRQ_HANDLER (split ) \
163
- static void CAT(PREFIX, split) (struct ex_regs *regs) \
180
+ #define GUEST_IRQ_HANDLER_NAME (split , lev ) CAT(PREFIX, CAT( split, lev) )
181
+ #define GENERATE_GUEST_IRQ_HANDLER (split , lev ) \
182
+ static void CAT(PREFIX, CAT( split, lev)) (struct ex_regs *regs) \
164
183
{ \
165
- guest_irq_generic_handler(split); \
184
+ guest_irq_generic_handler(split, lev ); \
166
185
}
167
186
168
- GENERATE_GUEST_IRQ_HANDLER (0 );
169
- GENERATE_GUEST_IRQ_HANDLER (1 );
187
+ GENERATE_GUEST_IRQ_HANDLER (0 , 0 );
188
+ GENERATE_GUEST_IRQ_HANDLER (0 , 1 );
189
+ GENERATE_GUEST_IRQ_HANDLER (1 , 0 );
190
+ GENERATE_GUEST_IRQ_HANDLER (1 , 1 );
170
191
171
- static void (* guest_irq_handlers [2 ])(struct ex_regs * ) = {
172
- GUEST_IRQ_HANDLER_NAME (0 ) ,
173
- GUEST_IRQ_HANDLER_NAME (1 ) ,
192
+ static void (* guest_irq_handlers [2 ][ 2 ] )(struct ex_regs * ) = {
193
+ { GUEST_IRQ_HANDLER_NAME (0 , 0 ), GUEST_IRQ_HANDLER_NAME ( 0 , 1 ),} ,
194
+ { GUEST_IRQ_HANDLER_NAME (1 , 0 ), GUEST_IRQ_HANDLER_NAME ( 1 , 1 ),} ,
174
195
};
175
196
176
197
static void reset_priorities (struct test_args * args )
@@ -181,6 +202,11 @@ static void reset_priorities(struct test_args *args)
181
202
gic_set_priority (i , IRQ_DEFAULT_PRIO_REG );
182
203
}
183
204
205
+ static void guest_set_irq_line (uint32_t intid , uint32_t level )
206
+ {
207
+ kvm_inject_call (KVM_SET_IRQ_LINE , intid , 1 , level );
208
+ }
209
+
184
210
static void guest_inject (struct test_args * args ,
185
211
uint32_t first_intid , uint32_t num ,
186
212
kvm_inject_cmd cmd )
@@ -257,10 +283,12 @@ static void test_inject_preemption(struct test_args *args,
257
283
for (i = 0 ; i < num ; i ++ ) {
258
284
uint32_t tmp ;
259
285
intid = i + first_intid ;
260
- kvm_inject_call (cmd , intid , 1 );
286
+ KVM_INJECT (cmd , intid );
261
287
/* Each successive IRQ will preempt the previous one. */
262
288
tmp = wait_for_and_activate_irq ();
263
289
GUEST_ASSERT_EQ (tmp , intid );
290
+ if (args -> level_sensitive )
291
+ guest_set_irq_line (intid , 0 );
264
292
}
265
293
266
294
/* finish handling the IRQs starting with the highest priority one. */
@@ -321,22 +349,29 @@ static void test_preemption(struct test_args *args, struct kvm_inject_desc *f)
321
349
static void guest_code (struct test_args args )
322
350
{
323
351
uint32_t i , nr_irqs = args .nr_irqs ;
324
- struct kvm_inject_desc * f ;
352
+ bool level_sensitive = args .level_sensitive ;
353
+ struct kvm_inject_desc * f , * inject_fns ;
325
354
326
355
gic_init (GIC_V3 , 1 , dist , redist );
327
356
328
357
for (i = 0 ; i < nr_irqs ; i ++ )
329
358
gic_irq_enable (i );
330
359
360
+ for (i = MIN_SPI ; i < nr_irqs ; i ++ )
361
+ gic_irq_set_config (i , !args .level_sensitive );
362
+
331
363
gic_set_eoi_split (args .eoi_split );
332
364
333
365
reset_priorities (& args );
334
366
gic_set_priority_mask (CPU_PRIO_MASK );
335
367
368
+ inject_fns = level_sensitive ? inject_level_fns
369
+ : inject_edge_fns ;
370
+
336
371
local_irq_enable ();
337
372
338
373
/* Start the tests. */
339
- for_each_inject_fn (inject_edge_fns , f ) {
374
+ for_each_inject_fn (inject_fns , f ) {
340
375
test_injection (& args , f );
341
376
test_preemption (& args , f );
342
377
}
@@ -351,6 +386,7 @@ static void run_guest_cmd(struct kvm_vm *vm, int gic_fd,
351
386
kvm_inject_cmd cmd = inject_args -> cmd ;
352
387
uint32_t intid = inject_args -> first_intid ;
353
388
uint32_t num = inject_args -> num ;
389
+ int level = inject_args -> level ;
354
390
uint32_t i ;
355
391
356
392
assert (intid < UINT_MAX - num );
@@ -362,6 +398,14 @@ static void run_guest_cmd(struct kvm_vm *vm, int gic_fd,
362
398
for (i = intid ; i < intid + num ; i ++ )
363
399
kvm_arm_irq_line (vm , i , 0 );
364
400
break ;
401
+ case KVM_SET_IRQ_LINE :
402
+ for (i = intid ; i < intid + num ; i ++ )
403
+ kvm_arm_irq_line (vm , i , level );
404
+ break ;
405
+ case KVM_SET_IRQ_LINE_HIGH :
406
+ for (i = intid ; i < intid + num ; i ++ )
407
+ kvm_arm_irq_line (vm , i , 1 );
408
+ break ;
365
409
default :
366
410
break ;
367
411
}
@@ -380,11 +424,12 @@ static void kvm_inject_get_call(struct kvm_vm *vm, struct ucall *uc,
380
424
381
425
static void print_args (struct test_args * args )
382
426
{
383
- printf ("nr-irqs=%d eoi-split=%d\n" ,
384
- args -> nr_irqs , args -> eoi_split );
427
+ printf ("nr-irqs=%d level-sensitive=%d eoi-split=%d\n" ,
428
+ args -> nr_irqs , args -> level_sensitive ,
429
+ args -> eoi_split );
385
430
}
386
431
387
- static void test_vgic (uint32_t nr_irqs , bool eoi_split )
432
+ static void test_vgic (uint32_t nr_irqs , bool level_sensitive , bool eoi_split )
388
433
{
389
434
struct ucall uc ;
390
435
int gic_fd ;
@@ -393,6 +438,7 @@ static void test_vgic(uint32_t nr_irqs, bool eoi_split)
393
438
394
439
struct test_args args = {
395
440
.nr_irqs = nr_irqs ,
441
+ .level_sensitive = level_sensitive ,
396
442
.eoi_split = eoi_split ,
397
443
};
398
444
@@ -411,7 +457,7 @@ static void test_vgic(uint32_t nr_irqs, bool eoi_split)
411
457
GICD_BASE_GPA , GICR_BASE_GPA );
412
458
413
459
vm_install_exception_handler (vm , VECTOR_IRQ_CURRENT ,
414
- guest_irq_handlers [args .eoi_split ]);
460
+ guest_irq_handlers [args .eoi_split ][ args . level_sensitive ]);
415
461
416
462
while (1 ) {
417
463
vcpu_run (vm , VCPU_ID );
@@ -442,11 +488,12 @@ static void help(const char *name)
442
488
{
443
489
printf (
444
490
"\n"
445
- "usage: %s [-n num_irqs] [-e eoi_split]\n" , name );
446
- printf (" -n: specify the number of IRQs to configure the vgic with. "
491
+ "usage: %s [-n num_irqs] [-e eoi_split] [-l level_sensitive] \n" , name );
492
+ printf (" -n: specify number of IRQs to setup the vgic with. "
447
493
"It has to be a multiple of 32 and between 64 and 1024.\n" );
448
494
printf (" -e: if 1 then EOI is split into a write to DIR on top "
449
495
"of writing EOI.\n" );
496
+ printf (" -l: specify whether the IRQs are level-sensitive (1) or not (0)." );
450
497
puts ("" );
451
498
exit (1 );
452
499
}
@@ -455,13 +502,14 @@ int main(int argc, char **argv)
455
502
{
456
503
uint32_t nr_irqs = 64 ;
457
504
bool default_args = true;
505
+ bool level_sensitive = false;
458
506
int opt ;
459
507
bool eoi_split = false;
460
508
461
509
/* Tell stdout not to buffer its content */
462
510
setbuf (stdout , NULL );
463
511
464
- while ((opt = getopt (argc , argv , "hn:e:" )) != -1 ) {
512
+ while ((opt = getopt (argc , argv , "hn:e:l: " )) != -1 ) {
465
513
switch (opt ) {
466
514
case 'n' :
467
515
nr_irqs = atoi (optarg );
@@ -472,6 +520,10 @@ int main(int argc, char **argv)
472
520
eoi_split = (bool )atoi (optarg );
473
521
default_args = false;
474
522
break ;
523
+ case 'l' :
524
+ level_sensitive = (bool )atoi (optarg );
525
+ default_args = false;
526
+ break ;
475
527
case 'h' :
476
528
default :
477
529
help (argv [0 ]);
@@ -483,10 +535,12 @@ int main(int argc, char **argv)
483
535
* combinations.
484
536
*/
485
537
if (default_args ) {
486
- test_vgic (nr_irqs , false /* eoi_split */ );
487
- test_vgic (nr_irqs , true /* eoi_split */ );
538
+ test_vgic (nr_irqs , false /* level */ , false /* eoi_split */ );
539
+ test_vgic (nr_irqs , false /* level */ , true /* eoi_split */ );
540
+ test_vgic (nr_irqs , true /* level */ , false /* eoi_split */ );
541
+ test_vgic (nr_irqs , true /* level */ , true /* eoi_split */ );
488
542
} else {
489
- test_vgic (nr_irqs , eoi_split );
543
+ test_vgic (nr_irqs , level_sensitive , eoi_split );
490
544
}
491
545
492
546
return 0 ;
0 commit comments