23
23
#define GICR_BASE_GPA 0x080A0000ULL
24
24
#define VCPU_ID 0
25
25
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
+
26
34
/*
27
35
* KVM implements 32 priority levels:
28
36
* 0x00 (highest priority) - 0xF8 (lowest priority), in steps of 8
@@ -51,14 +59,18 @@ typedef enum {
51
59
52
60
struct kvm_inject_args {
53
61
kvm_inject_cmd cmd ;
54
- uint32_t intid ;
62
+ uint32_t first_intid ;
63
+ uint32_t num ;
55
64
};
56
65
57
66
/* 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 );
59
68
60
69
#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)
62
74
63
75
/* Used on the host side to get the hypercall info. */
64
76
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)
122
134
GUEST_ASSERT (!gic_irq_get_pending (intid ));
123
135
}
124
136
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 )
126
138
{
127
139
struct kvm_inject_args args = {
128
140
.cmd = cmd ,
129
- .intid = intid ,
141
+ .first_intid = first_intid ,
142
+ .num = num ,
130
143
};
131
144
GUEST_SYNC (& args );
132
145
}
@@ -138,14 +151,30 @@ do { \
138
151
GUEST_ASSERT(_intid == 0 || _intid == IAR_SPURIOUS); \
139
152
} while (0)
140
153
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 )
142
165
{
166
+ uint32_t i ;
167
+
143
168
reset_stats ();
144
169
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
+
145
174
asm volatile ("msr daifset, #2" : : : "memory" );
146
- KVM_INJECT (cmd , intid );
175
+ KVM_INJECT_MULTI (cmd , first_intid , num );
147
176
148
- while (irq_handled < 1 ) {
177
+ while (irq_handled < num ) {
149
178
asm volatile ("wfi\n"
150
179
"msr daifclr, #2\n"
151
180
/* handle IRQ */
@@ -154,57 +183,72 @@ static void guest_inject(uint32_t intid, kvm_inject_cmd cmd)
154
183
}
155
184
asm volatile ("msr daifclr, #2" : : : "memory" );
156
185
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 );
159
189
GUEST_ASSERT_IAR_EMPTY ();
190
+
191
+ reset_priorities (args );
160
192
}
161
193
162
- static void test_injection (struct kvm_inject_desc * f )
194
+ static void test_injection (struct test_args * args , struct kvm_inject_desc * f )
163
195
{
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
+ }
166
202
167
203
if (f -> ppi )
168
- guest_inject (MIN_PPI , f -> cmd );
204
+ guest_inject (args , MIN_PPI , 1 , f -> cmd );
169
205
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
+ }
172
211
}
173
212
174
- static void guest_code (void )
213
+ static void guest_code (struct test_args args )
175
214
{
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 ;
178
216
struct kvm_inject_desc * f ;
179
217
180
218
gic_init (GIC_V3 , 1 , dist , redist );
181
219
182
- for (i = 0 ; i < nr_irqs ; i ++ ) {
220
+ for (i = 0 ; i < nr_irqs ; i ++ )
183
221
gic_irq_enable (i );
184
- gic_set_priority (i , IRQ_DEFAULT_PRIO_REG );
185
- }
186
222
223
+ reset_priorities (& args );
187
224
gic_set_priority_mask (CPU_PRIO_MASK );
188
225
189
226
local_irq_enable ();
190
227
191
228
/* Start the tests. */
192
229
for_each_inject_fn (inject_edge_fns , f )
193
- test_injection (f );
230
+ test_injection (& args , f );
194
231
195
232
GUEST_DONE ();
196
233
}
197
234
198
235
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 )
200
238
{
201
239
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 );
203
245
204
246
switch (cmd ) {
205
247
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 );
208
252
break ;
209
253
default :
210
254
break ;
@@ -222,21 +266,35 @@ static void kvm_inject_get_call(struct kvm_vm *vm, struct ucall *uc,
222
266
memcpy (args , kvm_args_hva , sizeof (struct kvm_inject_args ));
223
267
}
224
268
269
+ static void print_args (struct test_args * args )
270
+ {
271
+ printf ("nr-irqs=%d\n" , args -> nr_irqs );
272
+ }
225
273
226
- static void test_vgic (void )
274
+ static void test_vgic (uint32_t nr_irqs )
227
275
{
228
276
struct ucall uc ;
229
277
int gic_fd ;
230
278
struct kvm_vm * vm ;
231
279
struct kvm_inject_args inject_args ;
232
280
281
+ struct test_args args = {
282
+ .nr_irqs = nr_irqs ,
283
+ };
284
+
285
+ print_args (& args );
286
+
233
287
vm = vm_create_default (VCPU_ID , 0 , guest_code );
234
288
ucall_init (vm , NULL );
235
289
236
290
vm_init_descriptor_tables (vm );
237
291
vcpu_init_descriptor_tables (vm , VCPU_ID );
238
292
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 );
240
298
241
299
vm_install_exception_handler (vm , VECTOR_IRQ_CURRENT ,
242
300
guest_irq_handler );
@@ -247,7 +305,7 @@ static void test_vgic(void)
247
305
switch (get_ucall (vm , VCPU_ID , & uc )) {
248
306
case UCALL_SYNC :
249
307
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 );
251
309
break ;
252
310
case UCALL_ABORT :
253
311
TEST_FAIL ("%s at %s:%ld\n\tvalues: %#lx, %#lx" ,
@@ -266,12 +324,39 @@ static void test_vgic(void)
266
324
kvm_vm_free (vm );
267
325
}
268
326
269
- int main ( int ac , char * * av )
327
+ static void help ( const char * name )
270
328
{
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
+
271
342
/* Tell stdout not to buffer its content */
272
343
setbuf (stdout , NULL );
273
344
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 );
275
360
276
361
return 0 ;
277
362
}
0 commit comments