1 2 /* 3 * Copyright(c) 2022-2023 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 #include "hex_test.h" 25 26 #define WRITE_REG_NOCLOBBER(output, reg_name, input) \ 27 asm volatile(reg_name " = %1\n\t" \ 28 "%0 = " reg_name "\n\t" \ 29 : "=r"(output) \ 30 : "r"(input) \ 31 : ); 32 33 #define WRITE_REG_ENCODED(output, reg_name, input, encoding) \ 34 asm volatile("r0 = %1\n\t" \ 35 encoding "\n\t" \ 36 "%0 = " reg_name "\n\t" \ 37 : "=r"(output) \ 38 : "r"(input) \ 39 : "r0"); 40 41 #define WRITE_REG_PAIR_ENCODED(output, reg_name, input, encoding) \ 42 asm volatile("r1:0 = %1\n\t" \ 43 encoding "\n\t" \ 44 "%0 = " reg_name "\n\t" \ 45 : "=r"(output) \ 46 : "r"(input) \ 47 : "r1:0"); 48 49 /* 50 * Instruction word: { pc = r0 } 51 * 52 * This instruction is barred by the assembler. 53 * 54 * 3 2 1 55 * 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 56 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 57 * | Opc[A2_tfrrcr] | Src[R0] |P P| | C9/PC | 58 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 59 */ 60 #define PC_EQ_R0 ".word 0x6220c009" 61 #define C9_8_EQ_R1_0 ".word 0x6320c008" 62 63 static inline void write_control_registers(void) 64 { 65 uint32_t result = 0; 66 67 WRITE_REG_NOCLOBBER(result, "usr", 0xffffffff); 68 check32(result, 0x3ecfff3f); 69 70 WRITE_REG_NOCLOBBER(result, "gp", 0xffffffff); 71 check32(result, 0xffffffc0); 72 73 WRITE_REG_NOCLOBBER(result, "upcyclelo", 0xffffffff); 74 check32(result, 0x00000000); 75 76 WRITE_REG_NOCLOBBER(result, "upcyclehi", 0xffffffff); 77 check32(result, 0x00000000); 78 79 WRITE_REG_NOCLOBBER(result, "utimerlo", 0xffffffff); 80 check32(result, 0x00000000); 81 82 WRITE_REG_NOCLOBBER(result, "utimerhi", 0xffffffff); 83 check32(result, 0x00000000); 84 85 /* 86 * PC is special. Setting it to these values 87 * should cause a catastrophic failure. 88 */ 89 WRITE_REG_ENCODED(result, "pc", 0x00000000, PC_EQ_R0); 90 check32_ne(result, 0x00000000); 91 92 WRITE_REG_ENCODED(result, "pc", 0x00000001, PC_EQ_R0); 93 check32_ne(result, 0x00000001); 94 95 WRITE_REG_ENCODED(result, "pc", 0xffffffff, PC_EQ_R0); 96 check32_ne(result, 0xffffffff); 97 } 98 99 static inline void write_control_register_pairs(void) 100 { 101 uint64_t result = 0; 102 103 WRITE_REG_NOCLOBBER(result, "c11:10", 0xffffffffffffffff); 104 check64(result, 0xffffffc0ffffffff); 105 106 WRITE_REG_NOCLOBBER(result, "c15:14", 0xffffffffffffffff); 107 check64(result, 0x0000000000000000); 108 109 WRITE_REG_NOCLOBBER(result, "c31:30", 0xffffffffffffffff); 110 check64(result, 0x0000000000000000); 111 112 WRITE_REG_PAIR_ENCODED(result, "c9:8", (uint64_t) 0x0000000000000000, 113 C9_8_EQ_R1_0); 114 check64_ne(result, 0x000000000000000); 115 116 WRITE_REG_PAIR_ENCODED(result, "c9:8", 0x0000000100000000, C9_8_EQ_R1_0); 117 check64_ne(result, 0x0000000100000000); 118 119 WRITE_REG_PAIR_ENCODED(result, "c9:8", 0xffffffffffffffff, C9_8_EQ_R1_0); 120 check64_ne(result, 0xffffffffffffffff); 121 } 122 123 int main() 124 { 125 err = 0; 126 127 write_control_registers(); 128 write_control_register_pairs(); 129 130 puts(err ? "FAIL" : "PASS"); 131 return err; 132 } 133