1/*
2 * Copyright 2017, Data61
3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO)
4 * ABN 41 687 119 230.
5 *
6 * This software may be distributed and modified according to the terms of
7 * the BSD 2-Clause license. Note that NO WARRANTY is provided.
8 * See "LICENSE_BSD2.txt" for details.
9 *
10 * @TAG(DATA61_BSD)
11 */
12
13#include <autoconf.h>
14#include <assert.h>
15#include <stdio.h>
16#include <stdlib.h>
17#include <sel4/sel4.h>
18#include <sel4utils/arch/util.h>
19#include <utils/util.h>
20
21#include <vka/object.h>
22
23#include "../test.h"
24#include "../helpers.h"
25
26enum {
27    FAULT_DATA_READ_PAGEFAULT = 1,
28    FAULT_DATA_WRITE_PAGEFAULT = 2,
29    FAULT_INSTRUCTION_PAGEFAULT = 3,
30    FAULT_BAD_SYSCALL = 4,
31    FAULT_BAD_INSTRUCTION = 5,
32};
33
34enum {
35    BADGED = seL4_WordBits - 1,
36    RESTART = seL4_WordBits - 2,
37};
38
39/* Use a different test virtual address on 32 and 64-bit systems so that we can exercise
40   the full address space to make sure fault messages are not truncating fault information. */
41#if CONFIG_WORD_SIZE == 32
42#ifdef CONFIG_ARCH_RISCV32
43#define BAD_VADDR 0x7ffedcba    /* 32-bit RISCV userspace */
44#else
45#define BAD_VADDR 0xf123456C
46#endif
47#elif CONFIG_WORD_SIZE == 64
48#ifdef CONFIG_ARCH_RISCV64
49#define BAD_VADDR 0x3CBA987650  /* Valid Sv39 Virtual Address */
50#else
51/* virtual address we test is in the valid 48-bit portion of the virtual address space */
52#define BAD_VADDR 0x7EDCBA987650
53#endif
54#endif
55#define GOOD_MAGIC 0x15831851
56#define BAD_MAGIC ~GOOD_MAGIC
57#define BAD_SYSCALL_NUMBER 0xc1
58
59#define EXPECTED_BADGE 0xabababa
60
61#ifdef CONFIG_ARCH_RISCV
62#if __riscv_xlen == 32
63#define LOAD  lw
64#define STORE sw
65#else /* __riscv_xlen == 64 */
66#define LOAD  ld
67#define STORE sd
68#endif
69
70#define LOAD_S STRINGIFY(LOAD)
71#define STORE_S STRINGIFY(STORE)
72#endif
73
74extern char read_fault_address[];
75extern char read_fault_restart_address[];
76static void __attribute__((noinline))
77do_read_fault(void)
78{
79    int *x = (int *)BAD_VADDR;
80    int val = BAD_MAGIC;
81    /* Do a read fault. */
82#if defined(CONFIG_ARCH_AARCH32)
83    asm volatile(
84        "mov r0, %[val]\n\t"
85        "read_fault_address:\n\t"
86        "ldr r0, [%[addrreg]]\n\t"
87        "read_fault_restart_address:\n\t"
88        "mov %[val], r0\n\t"
89        : [val] "+r"(val)
90        : [addrreg] "r"(x)
91        : "r0"
92    );
93#elif defined(CONFIG_ARCH_AARCH64)
94    asm volatile(
95        "mov x0, %[val]\n\t"
96        "read_fault_address:\n\t"
97        "ldr x0, [%[addrreg]]\n\t"
98        "read_fault_restart_address:\n\t"
99        "mov %[val], x0\n\t"
100        : [val] "+r"(val)
101        : [addrreg] "r"(x)
102        : "x0"
103    );
104#elif defined(CONFIG_ARCH_RISCV)
105    asm volatile(
106        "mv a0, %[val]\n\t"
107        "read_fault_address:\n\t"
108        LOAD_S " a0, 0(%[addrreg])\n\t"
109        "read_fault_restart_address:\n\t"
110        "mv %[val], a0\n\t"
111        : [val] "+r"(val)
112        : [addrreg] "r"(x)
113        : "a0"
114    );
115#elif defined(CONFIG_ARCH_X86)
116    asm volatile(
117        "mov %[val], %%eax\n\t"
118        "read_fault_address:\n\t"
119        "mov (%[addrreg]), %%eax\n\t"
120        "read_fault_restart_address:\n\t"
121        "mov %%eax, %[val]\n\t"
122        : [val] "+r"(val)
123        : [addrreg] "r"(x)
124        : "eax"
125    );
126#else
127#error "Unknown architecture."
128#endif
129    test_check(val == GOOD_MAGIC);
130}
131
132extern char write_fault_address[];
133extern char write_fault_restart_address[];
134static void __attribute__((noinline))
135do_write_fault(void)
136{
137    int *x = (int *)BAD_VADDR;
138    int val = BAD_MAGIC;
139    /* Do a write fault. */
140#if defined(CONFIG_ARCH_AARCH32)
141    asm volatile(
142        "mov r0, %[val]\n\t"
143        "write_fault_address:\n\t"
144        "str r0, [%[addrreg]]\n\t"
145        "write_fault_restart_address:\n\t"
146        "mov %[val], r0\n\t"
147        : [val] "+r"(val)
148        : [addrreg] "r"(x)
149        : "r0"
150    );
151#elif defined(CONFIG_ARCH_AARCH64)
152    asm volatile(
153        "mov x0, %[val]\n\t"
154        "write_fault_address:\n\t"
155        "str x0, [%[addrreg]]\n\t"
156        "write_fault_restart_address:\n\t"
157        "mov %[val], x0\n\t"
158        : [val] "+r"(val)
159        : [addrreg] "r"(x)
160        : "x0"
161    );
162#elif defined(CONFIG_ARCH_RISCV)
163    asm volatile(
164        "mv a0, %[val]\n\t"
165        "write_fault_address:\n\t"
166        STORE_S " a0, 0(%[addrreg])\n\t"
167        "write_fault_restart_address:\n\t"
168        "mv %[val], a0\n\t"
169        : [val] "+r"(val)
170        : [addrreg] "r"(x)
171        : "a0"
172    );
173#elif defined(CONFIG_ARCH_X86)
174    asm volatile(
175        "mov %[val], %%eax\n\t"
176        "write_fault_address:\n\t"
177        "mov %%eax, (%[addrreg])\n\t"
178        "write_fault_restart_address:\n\t"
179        "mov %%eax, %[val]\n\t"
180        : [val] "+r"(val)
181        : [addrreg] "r"(x)
182        : "eax"
183    );
184#else
185#error "Unknown architecture."
186#endif
187    test_check(val == GOOD_MAGIC);
188}
189
190extern char instruction_fault_restart_address[];
191static void __attribute__((noinline))
192do_instruction_fault(void)
193{
194    int *x = (int *)BAD_VADDR;
195    int val = BAD_MAGIC;
196    /* Jump to a crazy address. */
197#if defined(CONFIG_ARCH_AARCH32)
198    asm volatile(
199        "mov r0, %[val]\n\t"
200        "blx %[addrreg]\n\t"
201        "instruction_fault_restart_address:\n\t"
202        "mov %[val], r0\n\t"
203        : [val] "+r"(val)
204        : [addrreg] "r"(x)
205        : "r0", "lr"
206    );
207#elif defined(CONFIG_ARCH_AARCH64)
208    asm volatile(
209        "mov x0, %[val]\n\t"
210        "blr %[addrreg]\n\t"
211        "instruction_fault_restart_address:\n\t"
212        "mov %[val], x0\n\t"
213        : [val] "+r"(val)
214        : [addrreg] "r"(x)
215        : "x0", "x30"
216    );
217#elif defined(CONFIG_ARCH_RISCV)
218    asm volatile(
219        "mv a0, %[val]\n\t"
220        "jalr %[addrreg]\n\t"
221        "instruction_fault_restart_address:\n\t"
222        "mv %[val], a0\n\t"
223        : [val] "+r"(val)
224        : [addrreg] "r"(x)
225        : "a0", "ra"
226    );
227#elif defined(CONFIG_ARCH_X86)
228    asm volatile(
229        "mov %[val], %%eax\n\t"
230        "instruction_fault_address:\n\t"
231        "jmp *%[addrreg]\n\t"
232        "instruction_fault_restart_address:\n\t"
233        "mov %%eax, %[val]\n\t"
234        : [val] "+r"(val)
235        : [addrreg] "r"(x)
236        : "eax"
237    );
238#else
239#error "Unknown architecture."
240#endif
241    test_check(val == GOOD_MAGIC);
242}
243
244extern char bad_syscall_address[];
245extern char bad_syscall_restart_address[];
246static void __attribute__((noinline))
247do_bad_syscall(void)
248{
249    int *x = (int *)BAD_VADDR;
250    int val = BAD_MAGIC;
251    /* Do an undefined system call. */
252#if defined(CONFIG_ARCH_AARCH32)
253    asm volatile(
254        "mov r7, %[scno]\n\t"
255        "mov r0, %[val]\n\t"
256        "bad_syscall_address:\n\t"
257        "svc %[scno]\n\t"
258        "bad_syscall_restart_address:\n\t"
259        "mov %[val], r0\n\t"
260        : [val] "+r"(val)
261        : [addrreg] "r"(x),
262        [scno] "i"(BAD_SYSCALL_NUMBER)
263        : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "memory", "cc"
264    );
265#elif defined(CONFIG_ARCH_AARCH64)
266    asm volatile(
267        "mov x7, %[scno]\n\t"
268        "mov x0, %[val]\n\t"
269        "bad_syscall_address:\n\t"
270        "svc %[scno]\n\t"
271        "bad_syscall_restart_address:\n\t"
272        "mov %[val], x0\n\t"
273        : [val] "+r"(val)
274        : [addrreg] "r"(x),
275        [scno] "i"(BAD_SYSCALL_NUMBER)
276        : "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", "memory", "cc"
277    );
278#elif defined(CONFIG_ARCH_RISCV)
279    asm volatile(
280        "li a7, %[scno]\n\t"
281        "mv a0, %[val]\n\t"
282        "bad_syscall_address:\n\t"
283        "ecall \n\t"
284        "bad_syscall_restart_address:\n\t"
285        "mv %[val], a0\n\t"
286        : [val] "+r"(val)
287        : [addrreg] "r"(x),
288        [scno] "i"(BAD_SYSCALL_NUMBER)
289        : "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7", "memory", "cc"
290    );
291#elif defined(CONFIG_ARCH_X86_64) && defined(CONFIG_SYSENTER)
292    asm volatile(
293        "movl   %[val], %%ebx\n\t"
294        "movq   %%rsp, %%rcx\n\t"
295        "leaq   1f, %%rdx\n\t"
296        "bad_syscall_address:\n\t"
297        "1: \n\t"
298        "sysenter\n\t"
299        "bad_syscall_restart_address:\n\t"
300        "movl   %%ebx, %[val]\n\t"
301        : [val] "+r"(val)
302        : [addrreg] "r"(x),
303        [scno] "a"(BAD_SYSCALL_NUMBER)
304        : "rbx", "rcx", "rdx"
305    );
306#elif defined(CONFIG_SYSCALL)
307    asm volatile(
308        "movl   %[val], %%ebx\n\t"
309        "movq   %%rsp, %%r12\n\t"
310        "bad_syscall_address:\n\t"
311        "syscall\n\t"
312        "bad_syscall_restart_address:\n\t"
313        "movq   %%r12, %%rsp\n"
314        "movl   %%ebx, %[val]\n\t"
315        : [val] "+r"(val)
316        : [addrreg] "r"(x),
317        [scno] "d"(BAD_SYSCALL_NUMBER)
318        : "rax", "rbx", "rcx", "r11", "r12"
319    );
320#elif defined(CONFIG_ARCH_IA32)
321    asm volatile(
322        "mov %[scno], %%eax\n\t"
323        "mov %[val], %%ebx\n\t"
324        "mov %%esp, %%ecx\n\t"
325        "leal 1f, %%edx\n\t"
326        "bad_syscall_address:\n\t"
327        "1:\n\t"
328        "sysenter\n\t"
329        "bad_syscall_restart_address:\n\t"
330        "mov %%ebx, %[val]\n\t"
331        : [val] "+r"(val)
332        : [addrreg] "r"(x),
333        [scno] "i"(BAD_SYSCALL_NUMBER)
334        : "eax", "ebx", "ecx", "edx"
335    );
336#else
337#error "Unknown architecture."
338#endif
339    test_check(val == GOOD_MAGIC);
340}
341
342extern char bad_instruction_address[];
343extern char bad_instruction_restart_address[];
344static seL4_Word bad_instruction_sp; /* To reset afterwards. */
345static seL4_Word bad_instruction_cpsr; /* For checking against. */
346static void __attribute__((noinline))
347do_bad_instruction(void)
348{
349    int val = BAD_MAGIC;
350    /* Execute an undefined instruction. */
351#if defined(CONFIG_ARCH_AARCH32)
352    asm volatile(
353        /* Save SP */
354        "str sp, [%[sp]]\n\t"
355
356        /* Save CPSR */
357        "mrs r0, cpsr\n\t"
358        "str r0, [%[cpsr]]\n\t"
359
360        /* Set SP to val. */
361        "mov sp, %[valptr]\n\t"
362
363        "bad_instruction_address:\n\t"
364        ".word 0xe7f000f0\n\t" /* Guaranteed to be undefined by ARM. */
365        "bad_instruction_restart_address:\n\t"
366        :
367        : [sp] "r"(&bad_instruction_sp),
368        [cpsr] "r"(&bad_instruction_cpsr),
369        [valptr] "r"(&val)
370        : "r0", "memory"
371    );
372#elif defined(CONFIG_ARCH_AARCH64)
373    asm volatile(
374        /* Save SP */
375        "mov x0, sp\n\t"
376        "str x0, [%[sp]]\n\t"
377
378        /* Save PSTATE.nzcv */
379        "mrs x0, nzcv\n\t"
380        "str x0, [%[cpsr]]\n\t"
381
382        /* Set SP to val. */
383        "mov sp, %[valptr]\n\t"
384
385        "bad_instruction_address:\n\t"
386        ".word 0xe7f000f0\n\t" /* Guaranteed to be undefined by ARM. */
387        "bad_instruction_restart_address:\n\t"
388        :
389        : [sp] "r"(&bad_instruction_sp),
390        [cpsr] "r"(&bad_instruction_cpsr),
391        [valptr] "r"(&val)
392        : "x0", "memory"
393    );
394#elif defined(CONFIG_ARCH_RISCV)
395    asm volatile(
396        /* Save SP */
397        "mv  a0, sp\n\t"
398        STORE_S " a0, 0(%[sp])\n\t"
399
400        /* Set SP to val. */
401        "mv sp, %[valptr]\n\t"
402
403        "bad_instruction_address:\n\t"
404        ".word 0xffffffff\n\t"
405        "bad_instruction_restart_address:\n\t"
406        :
407        : [sp] "r"(&bad_instruction_sp),
408        [valptr] "r"(&val)
409        : "a0", "memory"
410    );
411#elif defined(CONFIG_ARCH_X86_64)
412    asm volatile(
413        /* save RSP */
414        "movq   %%rsp, (%[sp])\n\t"
415        "pushf\n\t"
416        "pop    %%rax\n\t"
417        "movq   %%rax, (%[cpsr])\n\t"
418        "movq   %[valptr], %%rsp\n\t"
419        "bad_instruction_address:\n\t"
420        "ud2\n\t"
421        "bad_instruction_restart_address:\n\t"
422        :
423        : [sp] "r"(&bad_instruction_sp),
424        [cpsr] "r"(&bad_instruction_cpsr),
425        [valptr] "r"(&val)
426        : "rax", "memory"
427    );
428#elif defined(CONFIG_ARCH_IA32)
429    asm volatile(
430        /* Save SP */
431        "mov %%esp, (%[sp])\n\t"
432
433        /* Save CPSR */
434        "pushf\n\t"
435        "pop %%eax\n\t"
436        "mov %%eax, (%[cpsr])\n\t"
437
438        /* Set SP to val. */
439        "mov %[valptr], %%esp\n\t"
440
441        "bad_instruction_address:\n\t"
442        "ud2\n\t"
443        "bad_instruction_restart_address:\n\t"
444        :
445        : [sp] "r"(&bad_instruction_sp),
446        [cpsr] "r"(&bad_instruction_cpsr),
447        [valptr] "r"(&val)
448        : "eax", "memory"
449    );
450#else
451#error "Unknown architecture."
452#endif
453    test_check(val == GOOD_MAGIC);
454}
455
456static void __attribute__((noinline))
457set_good_magic_and_set_pc(seL4_CPtr tcb, seL4_Word new_pc)
458{
459    /* Set their register to GOOD_MAGIC and set PC past fault. */
460    int error;
461    seL4_UserContext ctx;
462    error = seL4_TCB_ReadRegisters(tcb,
463                                   false,
464                                   0,
465                                   sizeof(ctx) / sizeof(seL4_Word),
466                                   &ctx);
467    test_check(!error);
468#if defined(CONFIG_ARCH_AARCH32)
469    test_check(ctx.r0 == BAD_MAGIC);
470    ctx.r0 = GOOD_MAGIC;
471    ctx.pc = new_pc;
472#elif defined(CONFIG_ARCH_AARCH64)
473    test_check((int)ctx.x0 == BAD_MAGIC);
474    ctx.x0 = GOOD_MAGIC;
475    ctx.pc = new_pc;
476#elif defined(CONFIG_ARCH_RISCV)
477    test_check((int)ctx.a0 == BAD_MAGIC);
478    ctx.a0 = GOOD_MAGIC;
479    ctx.pc = new_pc;
480#elif defined(CONFIG_ARCH_X86_64)
481    test_check((int)ctx.rax == BAD_MAGIC);
482    ctx.rax = GOOD_MAGIC;
483    ctx.rip = new_pc;
484#elif defined(CONFIG_ARCH_IA32)
485    test_check(ctx.eax == BAD_MAGIC);
486    ctx.eax = GOOD_MAGIC;
487    ctx.eip = new_pc;
488#else
489#error "Unknown architecture."
490#endif
491    error = seL4_TCB_WriteRegisters(tcb,
492                                    false,
493                                    0,
494                                    sizeof(ctx) / sizeof(seL4_Word),
495                                    &ctx);
496    test_check(!error);
497}
498
499static int handle_fault(seL4_CPtr fault_ep, seL4_CPtr tcb, seL4_Word expected_fault,
500                        seL4_Word flags_and_reply)
501{
502    seL4_MessageInfo_t tag;
503    seL4_Word sender_badge = 0;
504    seL4_CPtr reply = flags_and_reply & MASK(RESTART);
505    bool badged = flags_and_reply & BIT(BADGED);
506    bool restart = flags_and_reply & BIT(RESTART);
507
508    tag = api_recv(fault_ep, &sender_badge, reply);
509
510    if (badged) {
511        test_check(sender_badge == EXPECTED_BADGE);
512    } else {
513        test_check(sender_badge == 0);
514    }
515
516    switch (expected_fault) {
517    case FAULT_DATA_READ_PAGEFAULT:
518        test_check(seL4_MessageInfo_get_label(tag) == seL4_Fault_VMFault);
519        test_check(seL4_MessageInfo_get_length(tag) == seL4_VMFault_Length);
520        test_check(seL4_GetMR(seL4_VMFault_IP) == (seL4_Word)read_fault_address);
521        test_check(seL4_GetMR(seL4_VMFault_Addr) == BAD_VADDR);
522        test_check(seL4_GetMR(seL4_VMFault_PrefetchFault) == 0);
523        test_check(sel4utils_is_read_fault());
524
525        /* Clear MRs to ensure they get repopulated. */
526        seL4_SetMR(seL4_VMFault_Addr, 0);
527
528        set_good_magic_and_set_pc(tcb, (seL4_Word)read_fault_restart_address);
529        if (restart) {
530            api_reply(reply, tag);
531        }
532        break;
533
534    case FAULT_DATA_WRITE_PAGEFAULT:
535        test_check(seL4_MessageInfo_get_label(tag) == seL4_Fault_VMFault);
536        test_check(seL4_MessageInfo_get_length(tag) == seL4_VMFault_Length);
537        test_check(seL4_GetMR(seL4_VMFault_IP) == (seL4_Word)write_fault_address);
538        test_check(seL4_GetMR(seL4_VMFault_Addr) == BAD_VADDR);
539        test_check(seL4_GetMR(seL4_VMFault_PrefetchFault) == 0);
540        test_check(!sel4utils_is_read_fault());
541
542        /* Clear MRs to ensure they get repopulated. */
543        seL4_SetMR(seL4_VMFault_Addr, 0);
544
545        set_good_magic_and_set_pc(tcb, (seL4_Word)write_fault_restart_address);
546        if (restart) {
547            api_reply(reply, tag);
548        }
549        break;
550
551    case FAULT_INSTRUCTION_PAGEFAULT:
552        test_check(seL4_MessageInfo_get_label(tag) == seL4_Fault_VMFault);
553        test_check(seL4_MessageInfo_get_length(tag) == seL4_VMFault_Length);
554        test_check(seL4_GetMR(seL4_VMFault_IP) == BAD_VADDR);
555        test_check(seL4_GetMR(seL4_VMFault_Addr) == BAD_VADDR);
556#if defined(CONFIG_ARCH_ARM) || defined(CONFIG_ARCH_RISCV)
557        /* Prefetch fault is only set on ARM and RISCV. */
558        test_check(seL4_GetMR(seL4_VMFault_PrefetchFault) == 1);
559#endif
560        test_check(sel4utils_is_read_fault());
561
562        /* Clear MRs to ensure they get repopulated. */
563        seL4_SetMR(seL4_VMFault_Addr, 0);
564
565        set_good_magic_and_set_pc(tcb, (seL4_Word)instruction_fault_restart_address);
566        if (restart) {
567            api_reply(reply, tag);
568        }
569        break;
570
571    case FAULT_BAD_SYSCALL:
572        test_eq(seL4_MessageInfo_get_label(tag), (seL4_Word) seL4_Fault_UnknownSyscall);
573        test_eq(seL4_MessageInfo_get_length(tag), (seL4_Word) seL4_UnknownSyscall_Length);
574        test_eq(seL4_GetMR(seL4_UnknownSyscall_FaultIP), (seL4_Word) bad_syscall_address);
575        test_eq((int)seL4_GetMR(seL4_UnknownSyscall_Syscall), BAD_SYSCALL_NUMBER);
576        seL4_SetMR(seL4_UnknownSyscall_FaultIP, (seL4_Word)bad_syscall_restart_address);
577#if defined(CONFIG_ARCH_AARCH32)
578        test_eq(seL4_GetMR(seL4_UnknownSyscall_R0), BAD_MAGIC);
579        seL4_SetMR(seL4_UnknownSyscall_R0, GOOD_MAGIC);
580#elif defined(CONFIG_ARCH_AARCH64)
581        test_eq((int)seL4_GetMR(seL4_UnknownSyscall_X0), BAD_MAGIC);
582        seL4_SetMR(seL4_UnknownSyscall_X0, GOOD_MAGIC);
583#elif defined(CONFIG_ARCH_X86_64)
584        test_eq((int)seL4_GetMR(seL4_UnknownSyscall_RBX), BAD_MAGIC);
585        test_eq(seL4_GetMR(seL4_UnknownSyscall_FaultIP), (seL4_Word) bad_syscall_restart_address);
586        seL4_SetMR(seL4_UnknownSyscall_RBX, GOOD_MAGIC);
587#elif defined(CONFIG_ARCH_RISCV)
588        test_eq((int)seL4_GetMR(seL4_UnknownSyscall_A0), BAD_MAGIC);
589        test_eq(seL4_GetMR(seL4_UnknownSyscall_FaultIP), (seL4_Word) bad_syscall_restart_address);
590        seL4_SetMR(seL4_UnknownSyscall_A0, GOOD_MAGIC);
591        seL4_SetMR(seL4_UnknownSyscall_FaultIP, (seL4_Word)bad_syscall_restart_address);
592#elif defined(CONFIG_ARCH_IA32)
593        test_eq(seL4_GetMR(seL4_UnknownSyscall_EBX), BAD_MAGIC);
594        seL4_SetMR(seL4_UnknownSyscall_EBX, GOOD_MAGIC);
595        /* Syscalls on ia32 seem to restart themselves with sysenter. */
596#else
597#error "Unknown architecture."
598#endif
599
600        /* Flag that the thread should be restarted. */
601        if (restart) {
602            seL4_MessageInfo_ptr_set_label(&tag, 0);
603        } else {
604            seL4_MessageInfo_ptr_set_label(&tag, 1);
605        }
606        api_reply(reply, tag);
607        break;
608
609    case FAULT_BAD_INSTRUCTION:
610        test_check(seL4_MessageInfo_get_label(tag) == seL4_Fault_UserException);
611        test_check(seL4_MessageInfo_get_length(tag) == seL4_UserException_Length);
612        test_check(seL4_GetMR(0) == (seL4_Word)bad_instruction_address);
613        int *valptr = (int *)seL4_GetMR(1);
614        test_check(*valptr == BAD_MAGIC);
615#if defined(CONFIG_ARCH_AARCH32)
616        test_check(seL4_GetMR(2) == bad_instruction_cpsr);
617        test_check(seL4_GetMR(3) == 0);
618        test_check(seL4_GetMR(4) == 0);
619#elif defined(CONFIG_ARCH_AARCH64)
620        /* We only can access PSTATE.nzcv flags in EL0 in aarch64
621         * so, just make sure ther are preserved ... */
622        test_check((seL4_GetMR(2) & ~MASK(27)) == bad_instruction_cpsr);
623        /* instruction fault on a 32 bit instruction with ISS = 0 */
624        test_check(seL4_GetMR(3) == 0x02000000);
625        test_check(seL4_GetMR(4) == 0);
626#elif defined(CONFIG_ARCH_RISCV)
627        test_check(seL4_GetMR(2) == 2);
628        test_check(seL4_GetMR(3) == 0);
629#elif defined(CONFIG_ARCH_X86)
630        /*
631         * Curiously, the "resume flag" (bit 16) is set between the
632         * undefined syscall and seL4 grabbing the tasks's flags. This only
633         * happens on x86 hardware, but not qemu. Just ignore it when
634         * checking flags.
635         */
636        seL4_Word mask_out = ~(1 << 16);
637        test_check(((seL4_GetMR(2) ^ bad_instruction_cpsr) & mask_out) == 0);
638#else
639#error "Unknown architecture."
640#endif
641
642        *valptr = GOOD_MAGIC;
643        seL4_SetMR(0, (seL4_Word)bad_instruction_restart_address);
644        seL4_SetMR(1, bad_instruction_sp);
645
646        /* Flag that the thread should be restarted. */
647        if (restart) {
648            seL4_MessageInfo_ptr_set_label(&tag, 0);
649        } else {
650            seL4_MessageInfo_ptr_set_label(&tag, 1);
651        }
652
653        api_reply(reply, tag);
654        break;
655
656    default:
657        /* What? Why are we here? What just happened? */
658        test_assert(0);
659        break;
660    }
661
662    return 0;
663}
664
665static int cause_fault(int fault_type)
666{
667    switch (fault_type) {
668    case FAULT_DATA_READ_PAGEFAULT:
669        do_read_fault();
670        break;
671    case FAULT_DATA_WRITE_PAGEFAULT:
672        do_write_fault();
673        break;
674    case FAULT_INSTRUCTION_PAGEFAULT:
675        do_instruction_fault();
676        break;
677    case FAULT_BAD_SYSCALL:
678        do_bad_syscall();
679        break;
680    case FAULT_BAD_INSTRUCTION:
681        do_bad_instruction();
682        break;
683    }
684
685    return 0;
686}
687
688static int test_fault(env_t env, int fault_type, bool inter_as)
689{
690    helper_thread_t handler_thread;
691    helper_thread_t faulter_thread;
692    int error;
693
694    vka_object_t reply;
695    error = vka_alloc_reply(&env->vka, &reply);
696
697    for (int restart = 0; restart <= 1; restart++) {
698        for (int prio = 100; prio <= 102; prio++) {
699            for (int badged = 0; badged <= 1; badged++) {
700                seL4_Word handler_arg0, handler_arg1;
701                /* The endpoint on which faults are received. */
702                seL4_CPtr fault_ep = vka_alloc_endpoint_leaky(&env->vka);
703                if (badged) {
704                    seL4_CPtr badged_fault_ep = get_free_slot(env);
705                    cnode_mint(env, fault_ep, badged_fault_ep, seL4_AllRights, EXPECTED_BADGE);
706
707                    fault_ep = badged_fault_ep;
708                }
709
710                seL4_CPtr faulter_vspace, faulter_cspace, reply_cptr;
711
712                if (inter_as) {
713                    create_helper_process(env, &faulter_thread);
714                    create_helper_process(env, &handler_thread);
715
716                    /* copy the fault endpoint to the faulter */
717                    cspacepath_t path;
718                    vka_cspace_make_path(&env->vka,  fault_ep, &path);
719                    seL4_CPtr remote_fault_ep = sel4utils_copy_path_to_process(&faulter_thread.process, path);
720                    assert(remote_fault_ep != -1);
721
722                    if (!config_set(CONFIG_KERNEL_MCS)) {
723                        fault_ep = remote_fault_ep;
724                    }
725
726                    /* copy the fault endpoint to the handler */
727                    handler_arg0 = sel4utils_copy_path_to_process(&handler_thread.process, path);
728                    assert(handler_arg0 != -1);
729
730                    /* copy the fault tcb to the handler */
731                    vka_cspace_make_path(&env->vka, get_helper_tcb(&faulter_thread), &path);
732                    handler_arg1 = sel4utils_copy_path_to_process(&handler_thread.process, path);
733                    assert(handler_arg1 != -1);
734
735                    reply_cptr = sel4utils_copy_cap_to_process(&handler_thread.process, &env->vka,
736                                                               reply.cptr);
737                    faulter_cspace = faulter_thread.process.cspace.cptr;
738                    faulter_vspace = faulter_thread.process.pd.cptr;
739                } else {
740                    create_helper_thread(env, &faulter_thread);
741                    create_helper_thread(env, &handler_thread);
742                    faulter_cspace = env->cspace_root;
743                    faulter_vspace = env->page_directory;
744                    handler_arg0 = fault_ep;
745                    handler_arg1 = get_helper_tcb(&faulter_thread);
746                    reply_cptr = reply.cptr;
747                }
748
749                set_helper_priority(env, &handler_thread, 101);
750                error = api_tcb_set_space(get_helper_tcb(&faulter_thread),
751                                          fault_ep,
752                                          faulter_cspace,
753                                          api_make_guard_skip_word(seL4_WordBits - env->cspace_size_bits),
754                                          faulter_vspace, seL4_NilData);
755                test_error_eq(error, seL4_NoError);
756                set_helper_priority(env, &faulter_thread, prio);
757
758                // Ensure that the BADGED and RESTART bits are not
759                // already set on the cptr.
760                test_assert(!(reply_cptr & (BIT(RESTART) | BIT(BADGED))));
761                seL4_Word flags_and_reply = reply_cptr |
762                                            (badged ? BIT(BADGED) : 0) |
763                                            (restart ? BIT(RESTART) : 0);
764
765                start_helper(env, &handler_thread, (helper_fn_t) handle_fault,
766                             handler_arg0, handler_arg1, fault_type, flags_and_reply);
767                start_helper(env, &faulter_thread, (helper_fn_t) cause_fault,
768                             fault_type, 0, 0, 0);
769                wait_for_helper(&handler_thread);
770
771                if (restart) {
772                    wait_for_helper(&faulter_thread);
773                }
774
775                cleanup_helper(env, &handler_thread);
776                cleanup_helper(env, &faulter_thread);
777            }
778        }
779    }
780
781    return sel4test_get_result();
782}
783
784static int test_read_fault(env_t env)
785{
786    return test_fault(env, FAULT_DATA_READ_PAGEFAULT, false);
787}
788DEFINE_TEST(PAGEFAULT0001, "Test read page fault", test_read_fault, !config_set(CONFIG_FT))
789
790static int test_write_fault(env_t env)
791{
792    return test_fault(env, FAULT_DATA_WRITE_PAGEFAULT, false);
793}
794DEFINE_TEST(PAGEFAULT0002, "Test write page fault", test_write_fault, !config_set(CONFIG_FT))
795
796static int test_execute_fault(env_t env)
797{
798    return test_fault(env,  FAULT_INSTRUCTION_PAGEFAULT, false);
799}
800DEFINE_TEST(PAGEFAULT0003, "Test execute page fault", test_execute_fault, !config_set(CONFIG_FT))
801
802static int test_bad_syscall(env_t env)
803{
804    return test_fault(env, FAULT_BAD_SYSCALL, false);
805}
806DEFINE_TEST(PAGEFAULT0004, "Test unknown system call", test_bad_syscall, true)
807
808static int test_bad_instruction(env_t env)
809{
810    return test_fault(env, FAULT_BAD_INSTRUCTION, false);
811}
812DEFINE_TEST(PAGEFAULT0005, "Test undefined instruction", test_bad_instruction, true)
813
814static int test_read_fault_interas(env_t env)
815{
816    return test_fault(env, FAULT_DATA_READ_PAGEFAULT, true);
817}
818DEFINE_TEST(PAGEFAULT1001, "Test read page fault (inter-AS)", test_read_fault_interas, true)
819
820static int test_write_fault_interas(env_t env)
821{
822    return test_fault(env, FAULT_DATA_WRITE_PAGEFAULT, true);
823}
824DEFINE_TEST(PAGEFAULT1002, "Test write page fault (inter-AS)", test_write_fault_interas, true)
825
826static int test_execute_fault_interas(env_t env)
827{
828    return test_fault(env, FAULT_INSTRUCTION_PAGEFAULT, true);
829}
830DEFINE_TEST(PAGEFAULT1003, "Test execute page fault (inter-AS)", test_execute_fault_interas, true)
831
832static int test_bad_syscall_interas(env_t env)
833{
834    return test_fault(env, FAULT_BAD_SYSCALL, true);
835}
836DEFINE_TEST(PAGEFAULT1004, "Test unknown system call (inter-AS)", test_bad_syscall_interas, true)
837
838/* This test currently fails. It is disabled until it can be investigated and fixed. */
839static int test_bad_instruction_interas(env_t env)
840{
841    return test_fault(env, FAULT_BAD_INSTRUCTION, true);
842}
843DEFINE_TEST(PAGEFAULT1005, "Test undefined instruction (inter-AS)", test_bad_instruction_interas, false)
844
845static void
846timeout_fault_0001_fn(void)
847{
848    while (1);
849}
850
851int test_timeout_fault(env_t env)
852{
853    helper_thread_t helper;
854    seL4_Word data = 1;
855    seL4_CPtr endpoint = vka_alloc_endpoint_leaky(&env->vka);
856    seL4_CPtr ro = vka_alloc_reply_leaky(&env->vka);
857
858    create_helper_thread(env, &helper);
859    set_helper_sched_params(env, &helper, US_IN_MS, US_IN_S, data);
860    set_helper_tfep(env, &helper, endpoint);
861    start_helper(env, &helper, (helper_fn_t) timeout_fault_0001_fn, 0, 0, 0, 0);
862
863    /* wait for timeout fault */
864    UNUSED seL4_MessageInfo_t info = api_recv(endpoint, NULL, ro);
865    for (int i = 0; i < 10; i++) {
866#ifdef CONFIG_KERNEL_MCS
867        test_eq(seL4_MessageInfo_get_length(info), (seL4_Word) seL4_Timeout_Length);
868        test_check(seL4_isTimeoutFault_tag(info));
869        test_eq(seL4_GetMR(seL4_Timeout_Data), data);
870#endif
871        info = api_reply_recv(endpoint, seL4_MessageInfo_new(0, 0, 0, 0), NULL, ro);
872    }
873
874    return sel4test_get_result();
875}
876DEFINE_TEST(TIMEOUTFAULT0001, "Test timeout fault", test_timeout_fault, config_set(CONFIG_KERNEL_MCS))
877
878void
879timeout_fault_server_fn(seL4_CPtr ep, env_t env, seL4_CPtr ro)
880{
881    /* signal to initialiser that we are done, and wait for a message from
882     * the client */
883    ZF_LOGD("Server signal recv");
884    api_nbsend_recv(ep, seL4_MessageInfo_new(0, 0, 0, 0), ep, NULL, ro);
885    /* spin, this will use up all of the clients budget */
886    while (true);
887    /* we should not get here, as a timeout fault should have been raised
888     * and the handler will reset us */
889    ZF_LOGF("Should not get here");
890}
891
892static int timeout_fault_client_fn(seL4_CPtr ep)
893{
894    seL4_MessageInfo_t info = seL4_MessageInfo_new(0, 0, 0, 0);
895    while (1) {
896        info = seL4_Call(ep, info);
897        /* call should have failed, timeout fault handler will send a -1 */
898        test_eq(seL4_GetMR(0), (seL4_Word) - 1);
899    }
900    return 0;
901}
902
903int create_passive_thread_with_tfep(env_t env, helper_thread_t *passive, seL4_CPtr tfep,
904                                    seL4_Word badge, helper_fn_t fn, seL4_CPtr ep, seL4_Word arg1,
905                                    seL4_Word arg2, seL4_Word arg3, sel4utils_checkpoint_t *cp)
906{
907    seL4_CPtr minted_tfep = get_free_slot(env);
908    int error = cnode_mint(env, tfep, minted_tfep, seL4_AllRights, badge);
909    test_eq(error, seL4_NoError);
910
911    error = create_passive_thread(env, passive, fn, ep, arg1, arg2, arg3);
912    set_helper_tfep(env, passive, minted_tfep);
913    test_eq(error, 0);
914
915    /* checkpoint */
916    return sel4utils_checkpoint_thread(&passive->thread, cp, false);
917}
918
919static int handle_timeout_fault(seL4_CPtr tfep, seL4_Word expected_badge, sel4utils_thread_t *server,
920                                seL4_CPtr reply, sel4utils_checkpoint_t *cp, seL4_CPtr ep,
921                                seL4_Word expected_data, env_t env)
922{
923    seL4_Word badge;
924    seL4_CPtr server_reply = vka_alloc_reply_leaky(&env->vka);
925
926    /* wait for timeout fault */
927    ZF_LOGD("Wait for tf");
928    seL4_MessageInfo_t info = api_recv(tfep, &badge, server_reply);
929    test_eq(badge, expected_badge);
930#ifdef CONFIG_KERNEL_MCS
931    test_check(seL4_isTimeoutFault_tag(info));
932    test_eq(seL4_GetMR(seL4_Timeout_Data), expected_data);
933    test_eq(seL4_MessageInfo_get_length(info), (seL4_Word) seL4_Timeout_Length);
934#endif
935    /* reply to client on behalf of server */
936    seL4_SetMR(0, -1);
937    seL4_Send(reply, info);
938
939    size_t stack_size = (uintptr_t) cp->thread->stack_top - cp->sp;
940    memcpy((void *) cp->sp, cp->stack, stack_size);
941
942    /* restore server */
943    ZF_LOGD("Restoring server");
944    int error = api_sc_bind(server->sched_context.cptr, server->tcb.cptr);
945    test_eq(error, seL4_NoError);
946
947    ZF_LOGD("Reply to server");
948#ifdef CONFIG_KERNEL_MCS
949    info = seL4_TimeoutReply_new(true, cp->regs, sizeof(seL4_UserContext) / sizeof(seL4_Word));
950#endif
951    /* reply, restoring server state, and wait for server to init */
952    api_reply_recv(ep, info, NULL, server_reply);
953
954    error = api_sc_unbind(server->sched_context.cptr);
955    test_eq(error, seL4_NoError);
956
957    return 0;
958}
959
960static int test_timeout_fault_in_server(env_t env)
961{
962    helper_thread_t client, server;
963    seL4_Word client_data = 1;
964    seL4_Word server_badge = 2;
965    sel4utils_checkpoint_t cp;
966
967    seL4_CPtr tfep = vka_alloc_endpoint_leaky(&env->vka);
968    seL4_CPtr ep = vka_alloc_endpoint_leaky(&env->vka);
969    seL4_CPtr ro = vka_alloc_reply_leaky(&env->vka);
970
971    /* create the server */
972    int error = create_passive_thread_with_tfep(env, &server, tfep, server_badge,
973                                                (helper_fn_t) timeout_fault_server_fn, ep,
974                                                (seL4_Word)env, ro, 0, &cp);
975    test_eq(error, 0);
976
977    /* create the client */
978    create_helper_thread(env, &client);
979    set_helper_sched_params(env, &client, 0.1 * US_IN_S, US_IN_S, client_data);
980    start_helper(env, &client, (helper_fn_t) timeout_fault_client_fn, ep, 0, 0, 0);
981
982    /* handle a few faults */
983    for (int i = 0; i < 5; i++) {
984        ZF_LOGD("Handling fault");
985        error = handle_timeout_fault(tfep, server_badge, &server.thread, ro, &cp, ep,
986                                     client_data, env);
987        test_eq(error, 0);
988    }
989
990    return sel4test_get_result();
991
992}
993DEFINE_TEST(TIMEOUTFAULT0002, "Handle a timeout fault in a server",
994            test_timeout_fault_in_server, config_set(CONFIG_KERNEL_MCS))
995
996static void
997timeout_fault_proxy_fn(seL4_CPtr in, seL4_CPtr out, seL4_CPtr ro)
998{
999    seL4_MessageInfo_t info = seL4_MessageInfo_new(0, 0, 0, 1);
1000    info = api_nbsend_recv(in, info, in, NULL, ro);
1001    while (1) {
1002        info = seL4_Call(out, info);
1003        api_reply_recv(in, info, NULL, ro);
1004    }
1005}
1006
1007static int test_timeout_fault_nested_servers(env_t env)
1008{
1009    helper_thread_t client, server, proxy;
1010    sel4utils_checkpoint_t proxy_cp, server_cp;
1011
1012    seL4_Word client_data = 1;
1013    seL4_Word server_badge = 2;
1014    seL4_Word proxy_badge = 3;
1015
1016    seL4_CPtr client_proxy_ep = vka_alloc_endpoint_leaky(&env->vka);
1017    seL4_CPtr proxy_server_ep = vka_alloc_endpoint_leaky(&env->vka);
1018    seL4_CPtr tfep = vka_alloc_endpoint_leaky(&env->vka);
1019    seL4_CPtr proxy_ro = vka_alloc_reply_leaky(&env->vka);
1020    seL4_CPtr server_ro = vka_alloc_reply_leaky(&env->vka);
1021
1022    /* create server */
1023    int error = create_passive_thread_with_tfep(env, &server, tfep, server_badge,
1024                                                (helper_fn_t) timeout_fault_server_fn, proxy_server_ep,
1025                                                (seL4_Word)env, server_ro, 0, &server_cp);
1026    test_eq(error, 0);
1027
1028    /* create proxy */
1029    error = create_passive_thread_with_tfep(env, &proxy, tfep, proxy_badge,
1030                                            (helper_fn_t) timeout_fault_proxy_fn, client_proxy_ep,
1031                                            proxy_server_ep, proxy_ro, 0, &proxy_cp);
1032    test_eq(error, 0);
1033
1034    /* create client */
1035    create_helper_thread(env, &client);
1036
1037    error = api_sched_ctrl_configure(simple_get_sched_ctrl(&env->simple, 0),
1038                                     client.thread.sched_context.cptr,
1039                                     0.1 * US_IN_S, 0.5 * US_IN_S, 0, client_data);
1040    test_eq(error, 0);
1041
1042    start_helper(env, &client, (helper_fn_t) timeout_fault_client_fn, client_proxy_ep, 0, 0, 0);
1043
1044    /* handle some faults */
1045    for (int i = 0; i < 5; i++) {
1046        /* server fault */
1047        ZF_LOGD("server fault\n");
1048        error = handle_timeout_fault(tfep, server_badge, &server.thread, server_ro, &server_cp,
1049                                     proxy_server_ep, client_data, env);
1050        test_eq(error, 0);
1051
1052        /* proxy fault */
1053        ZF_LOGD("proxy fault\n");
1054        error = handle_timeout_fault(tfep, proxy_badge, &proxy.thread, proxy_ro, &proxy_cp,
1055                                     client_proxy_ep, client_data, env);
1056        test_eq(error, 0);
1057    }
1058
1059    return sel4test_get_result();
1060}
1061/* this test is disabled for the same reason as TIMEOUTFAULT0002 */
1062DEFINE_TEST(TIMEOUTFAULT0003, "Nested timeout fault", test_timeout_fault_nested_servers, config_set(CONFIG_KERNEL_MCS))
1063
1064static void vm_enter(void)
1065{
1066#ifdef CONFIG_VTX
1067    seL4_VMEnter(NULL);
1068#endif
1069}
1070
1071static int test_vm_enter_non_vm(env_t env)
1072{
1073    seL4_Error err;
1074    helper_thread_t helper;
1075    seL4_CPtr fault_ep = vka_alloc_endpoint_leaky(&env->vka);
1076    create_helper_thread(env, &helper);
1077
1078    seL4_Word guard = seL4_WordBits - env->cspace_size_bits;
1079    err = api_tcb_set_space(get_helper_tcb(&helper), fault_ep, env->cspace_root,
1080                            api_make_guard_skip_word(guard),
1081                            env->page_directory, seL4_NilData);
1082    test_eq(err, 0);
1083
1084    seL4_CPtr reply = vka_alloc_reply_leaky(&env->vka);
1085    start_helper(env, &helper, (helper_fn_t) vm_enter, 0, 0, 0, 0);
1086    seL4_MessageInfo_t tag = api_recv(fault_ep, NULL, reply);
1087    test_eq(seL4_MessageInfo_get_label(tag), (seL4_Word) seL4_Fault_UnknownSyscall);
1088    return sel4test_get_result();
1089}
1090DEFINE_TEST(UNKNOWN_SYSCALL_001, "Test seL4_VMEnter in a non-vm thread",
1091            test_vm_enter_non_vm, config_set(CONFIG_VTX));
1092