1 2 /* 3 * Copyright(c) 2022 Qualcomm Innovation Center, Inc. All Rights Reserved. 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, see <http://www.gnu.org/licenses/>. 17 */ 18 19 #include <stdio.h> 20 #include <stdint.h> 21 22 static int err; 23 24 #define check(N, EXPECT) \ 25 do { \ 26 uint64_t value = N; \ 27 uint64_t expect = EXPECT; \ 28 if (value != EXPECT) { \ 29 printf("ERROR: \"%s\" 0x%04llx != 0x%04llx at %s:%d\n", #N, value, \ 30 expect, __FILE__, __LINE__); \ 31 err++; \ 32 } \ 33 } while (0) 34 35 #define check_ne(N, EXPECT) \ 36 do { \ 37 uint64_t value = N; \ 38 uint64_t expect = EXPECT; \ 39 if (value == EXPECT) { \ 40 printf("ERROR: \"%s\" 0x%04llx == 0x%04llx at %s:%d\n", #N, value, \ 41 expect, __FILE__, __LINE__); \ 42 err++; \ 43 } \ 44 } while (0) 45 46 #define WRITE_REG_NOCLOBBER(output, reg_name, input) \ 47 asm volatile(reg_name " = %1\n\t" \ 48 "%0 = " reg_name "\n\t" \ 49 : "=r"(output) \ 50 : "r"(input) \ 51 : ); 52 53 #define WRITE_REG_ENCODED(output, reg_name, input, encoding) \ 54 asm volatile("r0 = %1\n\t" \ 55 encoding "\n\t" \ 56 "%0 = " reg_name "\n\t" \ 57 : "=r"(output) \ 58 : "r"(input) \ 59 : "r0"); 60 61 #define WRITE_REG_PAIR_ENCODED(output, reg_name, input, encoding) \ 62 asm volatile("r1:0 = %1\n\t" \ 63 encoding "\n\t" \ 64 "%0 = " reg_name "\n\t" \ 65 : "=r"(output) \ 66 : "r"(input) \ 67 : "r1:0"); 68 69 /* 70 * Instruction word: { pc = r0 } 71 * 72 * This instruction is barred by the assembler. 73 * 74 * 3 2 1 75 * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 76 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 77 * | Opc[A2_tfrrcr] | Src[R0] |P P| | C9/PC | 78 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 79 */ 80 #define PC_EQ_R0 ".word 0x6220c009" 81 #define C9_8_EQ_R1_0 ".word 0x6320c008" 82 83 static inline void write_control_registers(void) 84 { 85 uint32_t result = 0; 86 87 WRITE_REG_NOCLOBBER(result, "usr", 0xffffffff); 88 check(result, 0x3ecfff3f); 89 90 WRITE_REG_NOCLOBBER(result, "gp", 0xffffffff); 91 check(result, 0xffffffc0); 92 93 WRITE_REG_NOCLOBBER(result, "upcyclelo", 0xffffffff); 94 check(result, 0x00000000); 95 96 WRITE_REG_NOCLOBBER(result, "upcyclehi", 0xffffffff); 97 check(result, 0x00000000); 98 99 WRITE_REG_NOCLOBBER(result, "utimerlo", 0xffffffff); 100 check(result, 0x00000000); 101 102 WRITE_REG_NOCLOBBER(result, "utimerhi", 0xffffffff); 103 check(result, 0x00000000); 104 105 /* 106 * PC is special. Setting it to these values 107 * should cause a catastrophic failure. 108 */ 109 WRITE_REG_ENCODED(result, "pc", 0x00000000, PC_EQ_R0); 110 check_ne(result, 0x00000000); 111 112 WRITE_REG_ENCODED(result, "pc", 0x00000001, PC_EQ_R0); 113 check_ne(result, 0x00000001); 114 115 WRITE_REG_ENCODED(result, "pc", 0xffffffff, PC_EQ_R0); 116 check_ne(result, 0xffffffff); 117 } 118 119 static inline void write_control_register_pairs(void) 120 { 121 uint64_t result = 0; 122 123 WRITE_REG_NOCLOBBER(result, "c11:10", 0xffffffffffffffff); 124 check(result, 0xffffffc0ffffffff); 125 126 WRITE_REG_NOCLOBBER(result, "c15:14", 0xffffffffffffffff); 127 check(result, 0x0000000000000000); 128 129 WRITE_REG_NOCLOBBER(result, "c31:30", 0xffffffffffffffff); 130 check(result, 0x0000000000000000); 131 132 WRITE_REG_PAIR_ENCODED(result, "c9:8", (uint64_t) 0x0000000000000000, 133 C9_8_EQ_R1_0); 134 check_ne(result, 0x000000000000000); 135 136 WRITE_REG_PAIR_ENCODED(result, "c9:8", 0x0000000100000000, C9_8_EQ_R1_0); 137 check_ne(result, 0x0000000100000000); 138 139 WRITE_REG_PAIR_ENCODED(result, "c9:8", 0xffffffffffffffff, C9_8_EQ_R1_0); 140 check_ne(result, 0xffffffffffffffff); 141 } 142 143 int main() 144 { 145 err = 0; 146 147 write_control_registers(); 148 write_control_register_pairs(); 149 150 puts(err ? "FAIL" : "PASS"); 151 return err; 152 } 153