1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * SBI verification 4 * 5 * Copyright (C) 2024, Rivos Inc., Clément Léger <cleger@rivosinc.com> 6 */ 7 #include <libcflat.h> 8 #include <stdlib.h> 9 10 #include <asm/csr.h> 11 #include <asm/processor.h> 12 #include <asm/ptrace.h> 13 #include <asm/sbi.h> 14 15 #include "sbi-tests.h" 16 17 void check_fwft(void); 18 19 20 static struct sbiret fwft_set_raw(unsigned long feature, unsigned long value, unsigned long flags) 21 { 22 return sbi_ecall(SBI_EXT_FWFT, SBI_EXT_FWFT_SET, feature, value, flags, 0, 0, 0); 23 } 24 25 static struct sbiret fwft_set(uint32_t feature, unsigned long value, unsigned long flags) 26 { 27 return fwft_set_raw(feature, value, flags); 28 } 29 30 static struct sbiret fwft_get_raw(unsigned long feature) 31 { 32 return sbi_ecall(SBI_EXT_FWFT, SBI_EXT_FWFT_GET, feature, 0, 0, 0, 0, 0); 33 } 34 35 static struct sbiret fwft_get(uint32_t feature) 36 { 37 return fwft_get_raw(feature); 38 } 39 40 static void fwft_check_reserved(unsigned long id) 41 { 42 struct sbiret ret; 43 44 ret = fwft_get(id); 45 sbiret_report_error(&ret, SBI_ERR_DENIED, "get reserved feature 0x%lx", id); 46 47 ret = fwft_set(id, 1, 0); 48 sbiret_report_error(&ret, SBI_ERR_DENIED, "set reserved feature 0x%lx", id); 49 } 50 51 static void fwft_check_base(void) 52 { 53 report_prefix_push("base"); 54 55 fwft_check_reserved(SBI_FWFT_LOCAL_RESERVED_START); 56 fwft_check_reserved(SBI_FWFT_LOCAL_RESERVED_END); 57 fwft_check_reserved(SBI_FWFT_GLOBAL_RESERVED_START); 58 fwft_check_reserved(SBI_FWFT_GLOBAL_RESERVED_END); 59 60 #if __riscv_xlen > 32 61 /* Check id > 32 bits */ 62 { 63 struct sbiret ret; 64 65 ret = fwft_get_raw(BIT(32)); 66 sbiret_report_error(&ret, SBI_ERR_INVALID_PARAM, 67 "get feature with bit 32 set error"); 68 69 ret = fwft_set_raw(BIT(32), 0, 0); 70 sbiret_report_error(&ret, SBI_ERR_INVALID_PARAM, 71 "set feature with bit 32 set error"); 72 } 73 #endif 74 75 report_prefix_pop(); 76 } 77 78 static bool misaligned_handled; 79 80 static void misaligned_handler(struct pt_regs *regs) 81 { 82 misaligned_handled = true; 83 regs->epc += 4; 84 } 85 86 static struct sbiret fwft_misaligned_exc_set(unsigned long value, unsigned long flags) 87 { 88 return fwft_set(SBI_FWFT_MISALIGNED_EXC_DELEG, value, flags); 89 } 90 91 static struct sbiret fwft_misaligned_exc_get(void) 92 { 93 return fwft_get(SBI_FWFT_MISALIGNED_EXC_DELEG); 94 } 95 96 static void fwft_check_misaligned_exc_deleg(void) 97 { 98 struct sbiret ret; 99 100 report_prefix_push("misaligned_exc_deleg"); 101 102 ret = fwft_misaligned_exc_get(); 103 if (ret.error == SBI_ERR_NOT_SUPPORTED) { 104 report_skip("SBI_FWFT_MISALIGNED_EXC_DELEG is not supported"); 105 return; 106 } 107 108 if (!sbiret_report_error(&ret, SBI_SUCCESS, "Get misaligned deleg feature")) 109 return; 110 111 ret = fwft_misaligned_exc_set(2, 0); 112 sbiret_report_error(&ret, SBI_ERR_INVALID_PARAM, 113 "Set misaligned deleg feature invalid value 2"); 114 ret = fwft_misaligned_exc_set(0xFFFFFFFF, 0); 115 sbiret_report_error(&ret, SBI_ERR_INVALID_PARAM, 116 "Set misaligned deleg feature invalid value 0xFFFFFFFF"); 117 118 #if __riscv_xlen > 32 119 ret = fwft_misaligned_exc_set(BIT(32), 0); 120 sbiret_report_error(&ret, SBI_ERR_INVALID_PARAM, 121 "Set misaligned deleg with invalid value > 32bits"); 122 123 ret = fwft_misaligned_exc_set(0, BIT(32)); 124 sbiret_report_error(&ret, SBI_ERR_INVALID_PARAM, 125 "Set misaligned deleg with invalid flag > 32bits"); 126 #endif 127 128 /* Set to 0 and check after with get */ 129 ret = fwft_misaligned_exc_set(0, 0); 130 sbiret_report_error(&ret, SBI_SUCCESS, "Set misaligned deleg feature value 0"); 131 ret = fwft_misaligned_exc_get(); 132 sbiret_report(&ret, SBI_SUCCESS, 0, "Get misaligned deleg feature expected value 0"); 133 134 /* Set to 1 and check after with get */ 135 ret = fwft_misaligned_exc_set(1, 0); 136 sbiret_report_error(&ret, SBI_SUCCESS, "Set misaligned deleg feature value 1"); 137 ret = fwft_misaligned_exc_get(); 138 sbiret_report(&ret, SBI_SUCCESS, 1, "Get misaligned deleg feature expected value 1"); 139 140 install_exception_handler(EXC_LOAD_MISALIGNED, misaligned_handler); 141 142 asm volatile ( 143 ".option push\n" 144 /* 145 * Disable compression so the lw takes exactly 4 bytes and thus 146 * can be skipped reliably from the exception handler. 147 */ 148 ".option arch,-c\n" 149 "lw %[val], 1(%[val_addr])\n" 150 ".option pop\n" 151 : [val] "+r" (ret.value) 152 : [val_addr] "r" (&ret.value) 153 : "memory"); 154 155 /* 156 * Even though the SBI delegated the misaligned exception to S-mode, it might not trap on 157 * misaligned load/store access, report that during tests. 158 */ 159 if (!misaligned_handled) 160 report_skip("Misaligned load exception does not trap in S-mode"); 161 else 162 report_pass("Misaligned load exception trap in S-mode"); 163 164 install_exception_handler(EXC_LOAD_MISALIGNED, NULL); 165 166 /* Lock the feature */ 167 ret = fwft_misaligned_exc_set(0, SBI_FWFT_SET_FLAG_LOCK); 168 sbiret_report_error(&ret, SBI_SUCCESS, "Set misaligned deleg feature value 0 and lock"); 169 ret = fwft_misaligned_exc_set(1, 0); 170 sbiret_report_error(&ret, SBI_ERR_DENIED_LOCKED, 171 "Set locked misaligned deleg feature to new value"); 172 ret = fwft_misaligned_exc_get(); 173 sbiret_report(&ret, SBI_SUCCESS, 0, "Get misaligned deleg locked value 0"); 174 175 report_prefix_pop(); 176 } 177 178 void check_fwft(void) 179 { 180 report_prefix_push("fwft"); 181 182 if (!sbi_probe(SBI_EXT_FWFT)) { 183 report_skip("FWFT extension not available"); 184 report_prefix_pop(); 185 return; 186 } 187 188 fwft_check_base(); 189 fwft_check_misaligned_exc_deleg(); 190 191 report_prefix_pop(); 192 } 193