KVM: selftests: aarch64: Cmdline arg to set number of IRQs in vgic_irq test
[linux-2.6-microblaze.git] / tools / testing / selftests / kvm / aarch64 / vgic_irq.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * vgic_irq.c - Test userspace injection of IRQs
4  *
5  * This test validates the injection of IRQs from userspace using various
6  * methods (e.g., KVM_IRQ_LINE) and modes (e.g., EOI). The guest "asks" the
7  * host to inject a specific intid via a GUEST_SYNC call, and then checks that
8  * it received it.
9  */
10
11 #include <asm/kvm.h>
12 #include <asm/kvm_para.h>
13 #include <linux/sizes.h>
14
15 #include "processor.h"
16 #include "test_util.h"
17 #include "kvm_util.h"
18 #include "gic.h"
19 #include "gic_v3.h"
20 #include "vgic.h"
21
22 #define GICD_BASE_GPA           0x08000000ULL
23 #define GICR_BASE_GPA           0x080A0000ULL
24 #define VCPU_ID                 0
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
34 /*
35  * KVM implements 32 priority levels:
36  * 0x00 (highest priority) - 0xF8 (lowest priority), in steps of 8
37  *
38  * Note that these macros will still be correct in the case that KVM implements
39  * more priority levels. Also note that 32 is the minimum for GICv3 and GICv2.
40  */
41 #define KVM_NUM_PRIOS           32
42 #define KVM_PRIO_SHIFT          3 /* steps of 8 = 1 << 3 */
43 #define LOWEST_PRIO             (KVM_NUM_PRIOS - 1)
44 #define CPU_PRIO_MASK           (LOWEST_PRIO << KVM_PRIO_SHIFT) /* 0xf8 */
45 #define IRQ_DEFAULT_PRIO        (LOWEST_PRIO - 1)
46 #define IRQ_DEFAULT_PRIO_REG    (IRQ_DEFAULT_PRIO << KVM_PRIO_SHIFT) /* 0xf0 */
47
48 static void *dist = (void *)GICD_BASE_GPA;
49 static void *redist = (void *)GICR_BASE_GPA;
50
51 /*
52  * The kvm_inject_* utilities are used by the guest to ask the host to inject
53  * interrupts (e.g., using the KVM_IRQ_LINE ioctl).
54  */
55
56 typedef enum {
57         KVM_INJECT_EDGE_IRQ_LINE = 1,
58 } kvm_inject_cmd;
59
60 struct kvm_inject_args {
61         kvm_inject_cmd cmd;
62         uint32_t first_intid;
63         uint32_t num;
64 };
65
66 /* Used on the guest side to perform the hypercall. */
67 static void kvm_inject_call(kvm_inject_cmd cmd, uint32_t first_intid, uint32_t num);
68
69 #define KVM_INJECT(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)
74
75 /* Used on the host side to get the hypercall info. */
76 static void kvm_inject_get_call(struct kvm_vm *vm, struct ucall *uc,
77                 struct kvm_inject_args *args);
78
79 struct kvm_inject_desc {
80         kvm_inject_cmd cmd;
81         /* can inject PPIs, PPIs, and/or SPIs. */
82         bool sgi, ppi, spi;
83 };
84
85 static struct kvm_inject_desc inject_edge_fns[] = {
86         /*                                      sgi    ppi    spi */
87         { KVM_INJECT_EDGE_IRQ_LINE,             false, false, true },
88         { 0, },
89 };
90
91 #define for_each_inject_fn(t, f)                                                \
92         for ((f) = (t); (f)->cmd; (f)++)
93
94 /* Shared between the guest main thread and the IRQ handlers. */
95 volatile uint64_t irq_handled;
96 volatile uint32_t irqnr_received[MAX_SPI + 1];
97
98 static void reset_stats(void)
99 {
100         int i;
101
102         irq_handled = 0;
103         for (i = 0; i <= MAX_SPI; i++)
104                 irqnr_received[i] = 0;
105 }
106
107 static uint64_t gic_read_ap1r0(void)
108 {
109         uint64_t reg = read_sysreg_s(SYS_ICV_AP1R0_EL1);
110
111         dsb(sy);
112         return reg;
113 }
114
115 static void guest_irq_handler(struct ex_regs *regs)
116 {
117         uint32_t intid = gic_get_and_ack_irq();
118
119         if (intid == IAR_SPURIOUS)
120                 return;
121
122         GUEST_ASSERT(gic_irq_get_active(intid));
123
124         GUEST_ASSERT(!gic_irq_get_pending(intid));
125
126         GUEST_ASSERT(intid < MAX_SPI);
127         irqnr_received[intid] += 1;
128         irq_handled += 1;
129
130         gic_set_eoi(intid);
131         GUEST_ASSERT_EQ(gic_read_ap1r0(), 0);
132
133         GUEST_ASSERT(!gic_irq_get_active(intid));
134         GUEST_ASSERT(!gic_irq_get_pending(intid));
135 }
136
137 static void kvm_inject_call(kvm_inject_cmd cmd, uint32_t first_intid, uint32_t num)
138 {
139         struct kvm_inject_args args = {
140                 .cmd = cmd,
141                 .first_intid = first_intid,
142                 .num = num,
143         };
144         GUEST_SYNC(&args);
145 }
146
147 #define GUEST_ASSERT_IAR_EMPTY()                                                \
148 do {                                                                            \
149         uint32_t _intid;                                                        \
150         _intid = gic_get_and_ack_irq();                                         \
151         GUEST_ASSERT(_intid == 0 || _intid == IAR_SPURIOUS);                    \
152 } while (0)
153
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)
165 {
166         uint32_t i;
167
168         reset_stats();
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
174         asm volatile("msr daifset, #2" : : : "memory");
175         KVM_INJECT_MULTI(cmd, first_intid, num);
176
177         while (irq_handled < num) {
178                 asm volatile("wfi\n"
179                              "msr daifclr, #2\n"
180                              /* handle IRQ */
181                              "msr daifset, #2\n"
182                              : : : "memory");
183         }
184         asm volatile("msr daifclr, #2" : : : "memory");
185
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);
189         GUEST_ASSERT_IAR_EMPTY();
190
191         reset_priorities(args);
192 }
193
194 static void test_injection(struct test_args *args, struct kvm_inject_desc *f)
195 {
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         }
202
203         if (f->ppi)
204                 guest_inject(args, MIN_PPI, 1, f->cmd);
205
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         }
211 }
212
213 static void guest_code(struct test_args args)
214 {
215         uint32_t i, nr_irqs = args.nr_irqs;
216         struct kvm_inject_desc *f;
217
218         gic_init(GIC_V3, 1, dist, redist);
219
220         for (i = 0; i < nr_irqs; i++)
221                 gic_irq_enable(i);
222
223         reset_priorities(&args);
224         gic_set_priority_mask(CPU_PRIO_MASK);
225
226         local_irq_enable();
227
228         /* Start the tests. */
229         for_each_inject_fn(inject_edge_fns, f)
230                 test_injection(&args, f);
231
232         GUEST_DONE();
233 }
234
235 static void run_guest_cmd(struct kvm_vm *vm, int gic_fd,
236                 struct kvm_inject_args *inject_args,
237                 struct test_args *test_args)
238 {
239         kvm_inject_cmd cmd = inject_args->cmd;
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);
245
246         switch (cmd) {
247         case KVM_INJECT_EDGE_IRQ_LINE:
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);
252                 break;
253         default:
254                 break;
255         }
256 }
257
258 static void kvm_inject_get_call(struct kvm_vm *vm, struct ucall *uc,
259                 struct kvm_inject_args *args)
260 {
261         struct kvm_inject_args *kvm_args_hva;
262         vm_vaddr_t kvm_args_gva;
263
264         kvm_args_gva = uc->args[1];
265         kvm_args_hva = (struct kvm_inject_args *)addr_gva2hva(vm, kvm_args_gva);
266         memcpy(args, kvm_args_hva, sizeof(struct kvm_inject_args));
267 }
268
269 static void print_args(struct test_args *args)
270 {
271         printf("nr-irqs=%d\n", args->nr_irqs);
272 }
273
274 static void test_vgic(uint32_t nr_irqs)
275 {
276         struct ucall uc;
277         int gic_fd;
278         struct kvm_vm *vm;
279         struct kvm_inject_args inject_args;
280
281         struct test_args args = {
282                 .nr_irqs = nr_irqs,
283         };
284
285         print_args(&args);
286
287         vm = vm_create_default(VCPU_ID, 0, guest_code);
288         ucall_init(vm, NULL);
289
290         vm_init_descriptor_tables(vm);
291         vcpu_init_descriptor_tables(vm, VCPU_ID);
292
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);
298
299         vm_install_exception_handler(vm, VECTOR_IRQ_CURRENT,
300                         guest_irq_handler);
301
302         while (1) {
303                 vcpu_run(vm, VCPU_ID);
304
305                 switch (get_ucall(vm, VCPU_ID, &uc)) {
306                 case UCALL_SYNC:
307                         kvm_inject_get_call(vm, &uc, &inject_args);
308                         run_guest_cmd(vm, gic_fd, &inject_args, &args);
309                         break;
310                 case UCALL_ABORT:
311                         TEST_FAIL("%s at %s:%ld\n\tvalues: %#lx, %#lx",
312                                         (const char *)uc.args[0],
313                                         __FILE__, uc.args[1], uc.args[2], uc.args[3]);
314                         break;
315                 case UCALL_DONE:
316                         goto done;
317                 default:
318                         TEST_FAIL("Unknown ucall %lu", uc.cmd);
319                 }
320         }
321
322 done:
323         close(gic_fd);
324         kvm_vm_free(vm);
325 }
326
327 static void help(const char *name)
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
342         /* Tell stdout not to buffer its content */
343         setbuf(stdout, NULL);
344
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);
360
361         return 0;
362 }