/* * Copyright(c) 2022 Qualcomm Innovation Center, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ #include #include static int err; #define check(N, EXPECT) \ do { \ uint64_t value = N; \ uint64_t expect = EXPECT; \ if (value != EXPECT) { \ printf("ERROR: \"%s\" 0x%04llx != 0x%04llx at %s:%d\n", #N, value, \ expect, __FILE__, __LINE__); \ err++; \ } \ } while (0) #define check_ne(N, EXPECT) \ do { \ uint64_t value = N; \ uint64_t expect = EXPECT; \ if (value == EXPECT) { \ printf("ERROR: \"%s\" 0x%04llx == 0x%04llx at %s:%d\n", #N, value, \ expect, __FILE__, __LINE__); \ err++; \ } \ } while (0) #define WRITE_REG_NOCLOBBER(output, reg_name, input) \ asm volatile(reg_name " = %1\n\t" \ "%0 = " reg_name "\n\t" \ : "=r"(output) \ : "r"(input) \ : ); #define WRITE_REG_ENCODED(output, reg_name, input, encoding) \ asm volatile("r0 = %1\n\t" \ encoding "\n\t" \ "%0 = " reg_name "\n\t" \ : "=r"(output) \ : "r"(input) \ : "r0"); #define WRITE_REG_PAIR_ENCODED(output, reg_name, input, encoding) \ asm volatile("r1:0 = %1\n\t" \ encoding "\n\t" \ "%0 = " reg_name "\n\t" \ : "=r"(output) \ : "r"(input) \ : "r1:0"); /* * Instruction word: { pc = r0 } * * This instruction is barred by the assembler. * * 3 2 1 * 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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Opc[A2_tfrrcr] | Src[R0] |P P| | C9/PC | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ #define PC_EQ_R0 ".word 0x6220c009" #define C9_8_EQ_R1_0 ".word 0x6320c008" static inline void write_control_registers(void) { uint32_t result = 0; WRITE_REG_NOCLOBBER(result, "usr", 0xffffffff); check(result, 0x3ecfff3f); WRITE_REG_NOCLOBBER(result, "gp", 0xffffffff); check(result, 0xffffffc0); WRITE_REG_NOCLOBBER(result, "upcyclelo", 0xffffffff); check(result, 0x00000000); WRITE_REG_NOCLOBBER(result, "upcyclehi", 0xffffffff); check(result, 0x00000000); WRITE_REG_NOCLOBBER(result, "utimerlo", 0xffffffff); check(result, 0x00000000); WRITE_REG_NOCLOBBER(result, "utimerhi", 0xffffffff); check(result, 0x00000000); /* * PC is special. Setting it to these values * should cause a catastrophic failure. */ WRITE_REG_ENCODED(result, "pc", 0x00000000, PC_EQ_R0); check_ne(result, 0x00000000); WRITE_REG_ENCODED(result, "pc", 0x00000001, PC_EQ_R0); check_ne(result, 0x00000001); WRITE_REG_ENCODED(result, "pc", 0xffffffff, PC_EQ_R0); check_ne(result, 0xffffffff); } static inline void write_control_register_pairs(void) { uint64_t result = 0; WRITE_REG_NOCLOBBER(result, "c11:10", 0xffffffffffffffff); check(result, 0xffffffc0ffffffff); WRITE_REG_NOCLOBBER(result, "c15:14", 0xffffffffffffffff); check(result, 0x0000000000000000); WRITE_REG_NOCLOBBER(result, "c31:30", 0xffffffffffffffff); check(result, 0x0000000000000000); WRITE_REG_PAIR_ENCODED(result, "c9:8", (uint64_t) 0x0000000000000000, C9_8_EQ_R1_0); check_ne(result, 0x000000000000000); WRITE_REG_PAIR_ENCODED(result, "c9:8", 0x0000000100000000, C9_8_EQ_R1_0); check_ne(result, 0x0000000100000000); WRITE_REG_PAIR_ENCODED(result, "c9:8", 0xffffffffffffffff, C9_8_EQ_R1_0); check_ne(result, 0xffffffffffffffff); } int main() { err = 0; write_control_registers(); write_control_register_pairs(); puts(err ? "FAIL" : "PASS"); return err; }