| 1 | /* |
| 2 | * Test that invalid slot assignments are properly rejected. |
| 3 | * |
| 4 | * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. |
| 5 | * SPDX-License-Identifier: GPL-2.0-or-later |
| 6 | */ |
| 7 | |
| 8 | #include <assert.h> |
| 9 | #include <signal.h> |
| 10 | #include <stdio.h> |
| 11 | #include <stdlib.h> |
| 12 | #include <string.h> |
| 13 | #include <unistd.h> |
| 14 | |
| 15 | static void *resume_pc; |
| 16 | |
| 17 | static void handle_sigill(int sig, siginfo_t *info, void *puc) |
| 18 | { |
| 19 | ucontext_t *uc = (ucontext_t *)puc; |
| 20 | |
| 21 | if (sig != SIGILL) { |
| 22 | _exit(EXIT_FAILURE); |
| 23 | } |
| 24 | |
| 25 | uc->uc_mcontext.r0 = SIGILL; |
| 26 | uc->uc_mcontext.pc = (unsigned long)resume_pc; |
| 27 | } |
| 28 | |
| 29 | char mem[8] __attribute__((aligned(8))); |
| 30 | |
| 31 | /* |
| 32 | * Invalid packet with 2 instructions at slot 0: |
| 33 | * - Word 0: 0xa1804100 = memw(r0) = r1 |
| 34 | * - Word 1: 0x28032804 = { r3 = #0; r4 = #0 } |
| 35 | * |
| 36 | * This should raise SIGILL due to the invalid slot assignment. |
| 37 | */ |
| 38 | static int test_invalid_slots(void) |
| 39 | { |
| 40 | int sig; |
| 41 | |
| 42 | asm volatile( |
| 43 | "r0 = #0\n" |
| 44 | "r1 = ##1f\n" |
| 45 | "memw(%1) = r1\n" |
| 46 | "r0 = #mem\n" |
| 47 | ".word 0xa1804100\n" /* { memw(r0) = r1; */ |
| 48 | ".word 0x28032804\n" /* r3 = #0; r4 = #0 } */ |
| 49 | "1:\n" |
| 50 | "%0 = r0\n" |
| 51 | : "=r"(sig) |
| 52 | : "r"(&resume_pc) |
| 53 | : "r0", "r1", "r3", "r4", "memory"); |
| 54 | |
| 55 | return sig; |
| 56 | } |
| 57 | |
| 58 | /* Load then indirect jump, load encoded first: no high slot left for jump. */ |
| 59 | static int test_invalid_slots_highslot(void) |
| 60 | { |
| 61 | int sig; |
| 62 | |
| 63 | asm volatile( |
| 64 | "r0 = #0\n" |
| 65 | "r1 = ##1f\n" |
| 66 | "memw(%1) = r1\n" |
| 67 | "r3 = #mem\n" |
| 68 | ".word 0x91834006\n" /* { r6 = memw(r3+#0); */ |
| 69 | ".word 0x529fc000\n" /* jumpr r31 } */ |
| 70 | "1:\n" |
| 71 | "%0 = r0\n" |
| 72 | : "=r"(sig) |
| 73 | : "r"(&resume_pc) |
| 74 | : "r0", "r1", "r3", "r6", "memory"); |
| 75 | |
| 76 | return sig; |
| 77 | } |
| 78 | |
| 79 | /* |
| 80 | * Three predicate-logical ops: each is restricted to slots 2 and 3, so the |
| 81 | * fourth-and-fifth-slot-free packet still has only two slots for three ops. |
| 82 | * No change-of-flow is involved, so the only reason to reject it is the slot |
| 83 | * conflict. |
| 84 | */ |
| 85 | static int test_invalid_slots_crslot23(void) |
| 86 | { |
| 87 | int sig; |
| 88 | |
| 89 | asm volatile( |
| 90 | "r0 = #0\n" |
| 91 | "r1 = ##1f\n" |
| 92 | "memw(%1) = r1\n" |
| 93 | ".word 0x6b024100\n" /* { p0 = and(p1, p2); */ |
| 94 | ".word 0x6b224103\n" /* p3 = or(p1, p2); */ |
| 95 | ".word 0x6b42c301\n" /* p1 = xor(p2, p3) } */ |
| 96 | "1:\n" |
| 97 | "%0 = r0\n" |
| 98 | : "=r"(sig) |
| 99 | : "r"(&resume_pc) |
| 100 | : "r0", "r1", "p0", "p1", "p3", "memory"); |
| 101 | |
| 102 | return sig; |
| 103 | } |
| 104 | |
| 105 | /* Three transfers plus a duplex: five ops for four slots. */ |
| 106 | static int test_invalid_slots_five(void) |
| 107 | { |
| 108 | int sig; |
| 109 | |
| 110 | asm volatile( |
| 111 | "r0 = #0\n" |
| 112 | "r1 = ##1f\n" |
| 113 | "memw(%1) = r1\n" |
| 114 | ".word 0x78004020\n" /* { r0 = #1; */ |
| 115 | ".word 0x78004041\n" /* r1 = #2; */ |
| 116 | ".word 0x78004062\n" /* r2 = #3; */ |
| 117 | ".word 0x28452856\n" /* r5 = #4; r6 = #5 } */ |
| 118 | "1:\n" |
| 119 | "%0 = r0\n" |
| 120 | : "=r"(sig) |
| 121 | : "r"(&resume_pc) |
| 122 | : "r0", "r1", "r2", "r5", "r6", "memory"); |
| 123 | |
| 124 | return sig; |
| 125 | } |
| 126 | |
| 127 | int main() |
| 128 | { |
| 129 | struct sigaction act; |
| 130 | |
| 131 | memset(&act, 0, sizeof(act)); |
| 132 | act.sa_sigaction = handle_sigill; |
| 133 | act.sa_flags = SA_SIGINFO; |
| 134 | assert(sigaction(SIGILL, &act, NULL) == 0); |
| 135 | |
| 136 | assert(test_invalid_slots() == SIGILL); |
| 137 | assert(test_invalid_slots_highslot() == SIGILL); |
| 138 | assert(test_invalid_slots_crslot23() == SIGILL); |
| 139 | assert(test_invalid_slots_five() == SIGILL); |
| 140 | |
| 141 | puts("PASS"); |
| 142 | return EXIT_SUCCESS; |
| 143 | } |