1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * SBI DBTR testsuite 4 * 5 * Copyright (C) 2025, Rivos Inc., Jesse Taube <jesse@rivosinc.com> 6 */ 7 8 #include <libcflat.h> 9 #include <bitops.h> 10 11 #include <asm/io.h> 12 #include <asm/processor.h> 13 14 #include "sbi-tests.h" 15 16 #define RV_MAX_TRIGGERS 32 17 18 #define SBI_DBTR_TRIG_STATE_MAPPED BIT(0) 19 #define SBI_DBTR_TRIG_STATE_U BIT(1) 20 #define SBI_DBTR_TRIG_STATE_S BIT(2) 21 #define SBI_DBTR_TRIG_STATE_VU BIT(3) 22 #define SBI_DBTR_TRIG_STATE_VS BIT(4) 23 #define SBI_DBTR_TRIG_STATE_HAVE_HW_TRIG BIT(5) 24 #define SBI_DBTR_TRIG_STATE_RESERVED GENMASK(7, 6) 25 26 #define SBI_DBTR_TRIG_STATE_HW_TRIG_IDX_SHIFT 8 27 #define SBI_DBTR_TRIG_STATE_HW_TRIG_IDX(trig_state) (trig_state >> SBI_DBTR_TRIG_STATE_HW_TRIG_IDX_SHIFT) 28 29 #define SBI_DBTR_TDATA1_TYPE_SHIFT (__riscv_xlen - 4) 30 #define SBI_DBTR_TDATA1_DMODE BIT_UL(__riscv_xlen - 5) 31 32 #define SBI_DBTR_TDATA1_MCONTROL6_LOAD BIT(0) 33 #define SBI_DBTR_TDATA1_MCONTROL6_STORE BIT(1) 34 #define SBI_DBTR_TDATA1_MCONTROL6_EXECUTE BIT(2) 35 #define SBI_DBTR_TDATA1_MCONTROL6_U BIT(3) 36 #define SBI_DBTR_TDATA1_MCONTROL6_S BIT(4) 37 #define SBI_DBTR_TDATA1_MCONTROL6_M BIT(6) 38 #define SBI_DBTR_TDATA1_MCONTROL6_SIZE_SHIFT 16 39 #define SBI_DBTR_TDATA1_MCONTROL6_SIZE_MASK 0x7 40 #define SBI_DBTR_TDATA1_MCONTROL6_SELECT BIT(21) 41 #define SBI_DBTR_TDATA1_MCONTROL6_VU BIT(23) 42 #define SBI_DBTR_TDATA1_MCONTROL6_VS BIT(24) 43 44 #define SBI_DBTR_TDATA1_MCONTROL_LOAD BIT(0) 45 #define SBI_DBTR_TDATA1_MCONTROL_STORE BIT(1) 46 #define SBI_DBTR_TDATA1_MCONTROL_EXECUTE BIT(2) 47 #define SBI_DBTR_TDATA1_MCONTROL_U BIT(3) 48 #define SBI_DBTR_TDATA1_MCONTROL_S BIT(4) 49 #define SBI_DBTR_TDATA1_MCONTROL_M BIT(6) 50 #define SBI_DBTR_TDATA1_MCONTROL_SIZELO_SHIFT 16 51 #define SBI_DBTR_TDATA1_MCONTROL_SIZELO_MASK 0x3 52 #define SBI_DBTR_TDATA1_MCONTROL_SELECT BIT(19) 53 #define SBI_DBTR_TDATA1_MCONTROL_SIZEHI_SHIFT 21 54 #define SBI_DBTR_TDATA1_MCONTROL_SIZEHI_MASK 0x3 55 56 enum McontrolType { 57 SBI_DBTR_TDATA1_TYPE_NONE = (0UL << SBI_DBTR_TDATA1_TYPE_SHIFT), 58 SBI_DBTR_TDATA1_TYPE_LEGACY = (1UL << SBI_DBTR_TDATA1_TYPE_SHIFT), 59 SBI_DBTR_TDATA1_TYPE_MCONTROL = (2UL << SBI_DBTR_TDATA1_TYPE_SHIFT), 60 SBI_DBTR_TDATA1_TYPE_ICOUNT = (3UL << SBI_DBTR_TDATA1_TYPE_SHIFT), 61 SBI_DBTR_TDATA1_TYPE_ITRIGGER = (4UL << SBI_DBTR_TDATA1_TYPE_SHIFT), 62 SBI_DBTR_TDATA1_TYPE_ETRIGGER = (5UL << SBI_DBTR_TDATA1_TYPE_SHIFT), 63 SBI_DBTR_TDATA1_TYPE_MCONTROL6 = (6UL << SBI_DBTR_TDATA1_TYPE_SHIFT), 64 SBI_DBTR_TDATA1_TYPE_TMEXTTRIGGER = (7UL << SBI_DBTR_TDATA1_TYPE_SHIFT), 65 SBI_DBTR_TDATA1_TYPE_RESERVED0 = (8UL << SBI_DBTR_TDATA1_TYPE_SHIFT), 66 SBI_DBTR_TDATA1_TYPE_RESERVED1 = (9UL << SBI_DBTR_TDATA1_TYPE_SHIFT), 67 SBI_DBTR_TDATA1_TYPE_RESERVED2 = (10UL << SBI_DBTR_TDATA1_TYPE_SHIFT), 68 SBI_DBTR_TDATA1_TYPE_RESERVED3 = (11UL << SBI_DBTR_TDATA1_TYPE_SHIFT), 69 SBI_DBTR_TDATA1_TYPE_CUSTOM0 = (12UL << SBI_DBTR_TDATA1_TYPE_SHIFT), 70 SBI_DBTR_TDATA1_TYPE_CUSTOM1 = (13UL << SBI_DBTR_TDATA1_TYPE_SHIFT), 71 SBI_DBTR_TDATA1_TYPE_CUSTOM2 = (14UL << SBI_DBTR_TDATA1_TYPE_SHIFT), 72 SBI_DBTR_TDATA1_TYPE_DISABLED = (15UL << SBI_DBTR_TDATA1_TYPE_SHIFT), 73 }; 74 75 enum Tdata1Size { 76 SIZE_ANY = 0, 77 SIZE_8BIT, 78 SIZE_16BIT, 79 SIZE_32BIT, 80 SIZE_48BIT, 81 SIZE_64BIT, 82 }; 83 84 enum Tdata1Value { 85 VALUE_NONE = 0, 86 VALUE_LOAD = BIT(0), 87 VALUE_STORE = BIT(1), 88 VALUE_EXECUTE = BIT(2), 89 }; 90 91 enum Tdata1Mode { 92 MODE_NONE = 0, 93 MODE_M = BIT(0), 94 MODE_U = BIT(1), 95 MODE_S = BIT(2), 96 MODE_VU = BIT(3), 97 MODE_VS = BIT(4), 98 }; 99 100 enum sbi_ext_dbtr_fid { 101 SBI_EXT_DBTR_NUM_TRIGGERS = 0, 102 SBI_EXT_DBTR_SETUP_SHMEM, 103 SBI_EXT_DBTR_TRIGGER_READ, 104 SBI_EXT_DBTR_TRIGGER_INSTALL, 105 SBI_EXT_DBTR_TRIGGER_UPDATE, 106 SBI_EXT_DBTR_TRIGGER_UNINSTALL, 107 SBI_EXT_DBTR_TRIGGER_ENABLE, 108 SBI_EXT_DBTR_TRIGGER_DISABLE, 109 }; 110 111 struct sbi_dbtr_data_msg { 112 unsigned long tstate; 113 unsigned long tdata1; 114 unsigned long tdata2; 115 unsigned long tdata3; 116 }; 117 118 struct sbi_dbtr_id_msg { 119 unsigned long idx; 120 }; 121 122 /* SBI shared mem messages layout */ 123 struct sbi_dbtr_shmem_entry { 124 union { 125 struct sbi_dbtr_data_msg data; 126 struct sbi_dbtr_id_msg id; 127 }; 128 }; 129 130 static bool dbtr_handled; 131 132 /* Expected to be leaf function as not to disrupt frame-pointer */ 133 static __attribute__((naked)) void exec_call(void) 134 { 135 /* skip over nop when triggered instead of ret. */ 136 asm volatile (".option push\n" 137 ".option arch, -c\n" 138 "nop\n" 139 "ret\n" 140 ".option pop\n"); 141 } 142 143 static void dbtr_exception_handler(struct pt_regs *regs) 144 { 145 dbtr_handled = true; 146 147 /* Reading *epc may cause a fault, skip over nop */ 148 if ((void *)regs->epc == exec_call) { 149 regs->epc += 4; 150 return; 151 } 152 153 /* WARNING: Skips over the trapped intruction */ 154 regs->epc += RV_INSN_LEN(readw((void *)regs->epc)); 155 } 156 157 static bool do_store(void *tdata2) 158 { 159 bool ret; 160 161 writel(0, tdata2); 162 163 ret = dbtr_handled; 164 dbtr_handled = false; 165 166 return ret; 167 } 168 169 static bool do_load(void *tdata2) 170 { 171 bool ret; 172 173 readl(tdata2); 174 175 ret = dbtr_handled; 176 dbtr_handled = false; 177 178 return ret; 179 } 180 181 static bool do_exec(void) 182 { 183 bool ret; 184 185 exec_call(); 186 187 ret = dbtr_handled; 188 dbtr_handled = false; 189 190 return ret; 191 } 192 193 static unsigned long mcontrol_size(enum Tdata1Size mode) 194 { 195 unsigned long ret = 0; 196 197 ret |= ((mode >> 2) & SBI_DBTR_TDATA1_MCONTROL_SIZEHI_MASK) 198 << SBI_DBTR_TDATA1_MCONTROL_SIZEHI_SHIFT; 199 ret |= (mode & SBI_DBTR_TDATA1_MCONTROL_SIZELO_MASK) 200 << SBI_DBTR_TDATA1_MCONTROL_SIZELO_SHIFT; 201 202 return ret; 203 } 204 205 static unsigned long mcontrol6_size(enum Tdata1Size mode) 206 { 207 return (mode & SBI_DBTR_TDATA1_MCONTROL6_SIZE_MASK) 208 << SBI_DBTR_TDATA1_MCONTROL6_SIZE_SHIFT; 209 } 210 211 static unsigned long gen_tdata1_mcontrol(enum Tdata1Mode mode, enum Tdata1Value value) 212 { 213 unsigned long tdata1 = SBI_DBTR_TDATA1_TYPE_MCONTROL; 214 215 if (value & VALUE_LOAD) 216 tdata1 |= SBI_DBTR_TDATA1_MCONTROL_LOAD; 217 218 if (value & VALUE_STORE) 219 tdata1 |= SBI_DBTR_TDATA1_MCONTROL_STORE; 220 221 if (value & VALUE_EXECUTE) 222 tdata1 |= SBI_DBTR_TDATA1_MCONTROL_EXECUTE; 223 224 if (mode & MODE_M) 225 tdata1 |= SBI_DBTR_TDATA1_MCONTROL_M; 226 227 if (mode & MODE_U) 228 tdata1 |= SBI_DBTR_TDATA1_MCONTROL_U; 229 230 if (mode & MODE_S) 231 tdata1 |= SBI_DBTR_TDATA1_MCONTROL_S; 232 233 return tdata1; 234 } 235 236 static unsigned long gen_tdata1_mcontrol6(enum Tdata1Mode mode, enum Tdata1Value value) 237 { 238 unsigned long tdata1 = SBI_DBTR_TDATA1_TYPE_MCONTROL6; 239 240 if (value & VALUE_LOAD) 241 tdata1 |= SBI_DBTR_TDATA1_MCONTROL6_LOAD; 242 243 if (value & VALUE_STORE) 244 tdata1 |= SBI_DBTR_TDATA1_MCONTROL6_STORE; 245 246 if (value & VALUE_EXECUTE) 247 tdata1 |= SBI_DBTR_TDATA1_MCONTROL6_EXECUTE; 248 249 if (mode & MODE_M) 250 tdata1 |= SBI_DBTR_TDATA1_MCONTROL6_M; 251 252 if (mode & MODE_U) 253 tdata1 |= SBI_DBTR_TDATA1_MCONTROL6_U; 254 255 if (mode & MODE_S) 256 tdata1 |= SBI_DBTR_TDATA1_MCONTROL6_S; 257 258 if (mode & MODE_VU) 259 tdata1 |= SBI_DBTR_TDATA1_MCONTROL6_VU; 260 261 if (mode & MODE_VS) 262 tdata1 |= SBI_DBTR_TDATA1_MCONTROL6_VS; 263 264 return tdata1; 265 } 266 267 static unsigned long gen_tdata1(enum McontrolType type, enum Tdata1Value value, enum Tdata1Mode mode) 268 { 269 switch (type) { 270 case SBI_DBTR_TDATA1_TYPE_MCONTROL: 271 return gen_tdata1_mcontrol(mode, value) | mcontrol_size(SIZE_32BIT); 272 case SBI_DBTR_TDATA1_TYPE_MCONTROL6: 273 return gen_tdata1_mcontrol6(mode, value) | mcontrol6_size(SIZE_32BIT); 274 default: 275 assert_msg(false, "Invalid mcontrol type: %lu", (unsigned long)type); 276 } 277 } 278 279 static struct sbiret sbi_debug_num_triggers(unsigned long trig_tdata1) 280 { 281 return sbi_ecall(SBI_EXT_DBTR, SBI_EXT_DBTR_NUM_TRIGGERS, trig_tdata1, 0, 0, 0, 0, 0); 282 } 283 284 static struct sbiret sbi_debug_set_shmem_raw(unsigned long shmem_phys_lo, 285 unsigned long shmem_phys_hi, 286 unsigned long flags) 287 { 288 return sbi_ecall(SBI_EXT_DBTR, SBI_EXT_DBTR_SETUP_SHMEM, shmem_phys_lo, 289 shmem_phys_hi, flags, 0, 0, 0); 290 } 291 292 static struct sbiret sbi_debug_set_shmem(void *shmem) 293 { 294 unsigned long base_addr_lo, base_addr_hi; 295 296 split_phys_addr(virt_to_phys(shmem), &base_addr_hi, &base_addr_lo); 297 return sbi_debug_set_shmem_raw(base_addr_lo, base_addr_hi, 0); 298 } 299 300 static struct sbiret sbi_debug_read_triggers(unsigned long trig_idx_base, 301 unsigned long trig_count) 302 { 303 return sbi_ecall(SBI_EXT_DBTR, SBI_EXT_DBTR_TRIGGER_READ, trig_idx_base, 304 trig_count, 0, 0, 0, 0); 305 } 306 307 static struct sbiret sbi_debug_install_triggers(unsigned long trig_count) 308 { 309 return sbi_ecall(SBI_EXT_DBTR, SBI_EXT_DBTR_TRIGGER_INSTALL, trig_count, 0, 0, 0, 0, 0); 310 } 311 312 static struct sbiret sbi_debug_update_triggers(unsigned long trig_count) 313 { 314 return sbi_ecall(SBI_EXT_DBTR, SBI_EXT_DBTR_TRIGGER_UPDATE, trig_count, 0, 0, 0, 0, 0); 315 } 316 317 static struct sbiret sbi_debug_uninstall_triggers(unsigned long trig_idx_base, 318 unsigned long trig_idx_mask) 319 { 320 return sbi_ecall(SBI_EXT_DBTR, SBI_EXT_DBTR_TRIGGER_UNINSTALL, trig_idx_base, 321 trig_idx_mask, 0, 0, 0, 0); 322 } 323 324 static struct sbiret sbi_debug_enable_triggers(unsigned long trig_idx_base, 325 unsigned long trig_idx_mask) 326 { 327 return sbi_ecall(SBI_EXT_DBTR, SBI_EXT_DBTR_TRIGGER_ENABLE, trig_idx_base, 328 trig_idx_mask, 0, 0, 0, 0); 329 } 330 331 static struct sbiret sbi_debug_disable_triggers(unsigned long trig_idx_base, 332 unsigned long trig_idx_mask) 333 { 334 return sbi_ecall(SBI_EXT_DBTR, SBI_EXT_DBTR_TRIGGER_DISABLE, trig_idx_base, 335 trig_idx_mask, 0, 0, 0, 0); 336 } 337 338 static bool dbtr_install_trigger(struct sbi_dbtr_shmem_entry *shmem, void *trigger, 339 unsigned long control) 340 { 341 struct sbiret sbi_ret; 342 bool ret; 343 344 shmem->data.tdata1 = control; 345 shmem->data.tdata2 = (unsigned long)trigger; 346 347 sbi_ret = sbi_debug_install_triggers(1); 348 ret = sbiret_report_error(&sbi_ret, SBI_SUCCESS, "sbi_debug_install_triggers"); 349 if (ret) 350 install_exception_handler(EXC_BREAKPOINT, dbtr_exception_handler); 351 352 return ret; 353 } 354 355 static bool dbtr_uninstall_trigger(void) 356 { 357 struct sbiret ret; 358 359 install_exception_handler(EXC_BREAKPOINT, NULL); 360 361 ret = sbi_debug_uninstall_triggers(0, 1); 362 return sbiret_report_error(&ret, SBI_SUCCESS, "sbi_debug_uninstall_triggers"); 363 } 364 365 static unsigned long dbtr_test_num_triggers(void) 366 { 367 struct sbiret ret; 368 unsigned long tdata1 = 0; 369 /* sbi_debug_num_triggers will return trig_max in sbiret.value when trig_tdata1 == 0 */ 370 371 report_prefix_push("available triggers"); 372 373 /* should be at least one trigger. */ 374 ret = sbi_debug_num_triggers(tdata1); 375 sbiret_report_error(&ret, SBI_SUCCESS, "sbi_debug_num_triggers"); 376 377 if (ret.value == 0) { 378 report_fail("Returned 0 triggers available"); 379 } else { 380 report_pass("Returned triggers available"); 381 report_info("Returned %lu triggers available", ret.value); 382 } 383 384 report_prefix_pop(); 385 return ret.value; 386 } 387 388 static enum McontrolType dbtr_test_type(unsigned long *num_trig) 389 { 390 struct sbiret ret; 391 unsigned long tdata1 = SBI_DBTR_TDATA1_TYPE_MCONTROL6; 392 393 report_prefix_push("test type"); 394 report_prefix_push("sbi_debug_num_triggers"); 395 396 ret = sbi_debug_num_triggers(tdata1); 397 sbiret_report_error(&ret, SBI_SUCCESS, "mcontrol6"); 398 *num_trig = ret.value; 399 if (ret.value > 0) { 400 report_pass("Returned mcontrol6 triggers available"); 401 report_info("Returned %lu mcontrol6 triggers available", 402 ret.value); 403 report_prefix_popn(2); 404 return tdata1; 405 } 406 407 tdata1 = SBI_DBTR_TDATA1_TYPE_MCONTROL; 408 409 ret = sbi_debug_num_triggers(tdata1); 410 sbiret_report_error(&ret, SBI_SUCCESS, "mcontrol"); 411 *num_trig = ret.value; 412 if (ret.value > 0) { 413 report_pass("Returned mcontrol triggers available"); 414 report_info("Returned %lu mcontrol triggers available", 415 ret.value); 416 report_prefix_popn(2); 417 return tdata1; 418 } 419 420 report_fail("Returned 0 mcontrol(6) triggers available"); 421 report_prefix_popn(2); 422 423 return SBI_DBTR_TDATA1_TYPE_NONE; 424 } 425 426 static struct sbiret dbtr_test_store_install_uninstall(struct sbi_dbtr_shmem_entry *shmem, 427 enum McontrolType type) 428 { 429 static unsigned long test; 430 struct sbiret ret; 431 432 report_prefix_push("store trigger"); 433 434 shmem->data.tdata1 = gen_tdata1(type, VALUE_STORE, MODE_S); 435 shmem->data.tdata2 = (unsigned long)&test; 436 437 ret = sbi_debug_install_triggers(1); 438 if (!sbiret_report_error(&ret, SBI_SUCCESS, "sbi_debug_install_triggers")) { 439 report_prefix_pop(); 440 return ret; 441 } 442 443 install_exception_handler(EXC_BREAKPOINT, dbtr_exception_handler); 444 445 report(do_store(&test), "triggered"); 446 447 if (do_load(&test)) 448 report_fail("triggered by load"); 449 450 ret = sbi_debug_uninstall_triggers(0, 1); 451 sbiret_report_error(&ret, SBI_SUCCESS, "sbi_debug_uninstall_triggers"); 452 453 if (do_store(&test)) 454 report_fail("triggered after uninstall"); 455 456 install_exception_handler(EXC_BREAKPOINT, NULL); 457 report_prefix_pop(); 458 459 return ret; 460 } 461 462 static void dbtr_test_update(struct sbi_dbtr_shmem_entry *shmem, enum McontrolType type) 463 { 464 static unsigned long test; 465 struct sbiret ret; 466 bool kfail; 467 468 report_prefix_push("update trigger"); 469 470 if (!dbtr_install_trigger(shmem, NULL, gen_tdata1(type, VALUE_NONE, MODE_NONE))) { 471 report_prefix_pop(); 472 return; 473 } 474 475 shmem->id.idx = 0; 476 shmem->data.tdata1 = gen_tdata1(type, VALUE_STORE, MODE_S); 477 shmem->data.tdata2 = (unsigned long)&test; 478 479 ret = sbi_debug_update_triggers(1); 480 sbiret_report_error(&ret, SBI_SUCCESS, "sbi_debug_update_triggers"); 481 482 /* 483 * Known broken update_triggers. 484 * https://lore.kernel.org/opensbi/aDdp1UeUh7GugeHp@ghost/T/#t 485 */ 486 kfail = __sbi_get_imp_id() == SBI_IMPL_OPENSBI && 487 __sbi_get_imp_version() < sbi_impl_opensbi_mk_version(1, 7); 488 report_kfail(kfail, do_store(&test), "triggered"); 489 490 dbtr_uninstall_trigger(); 491 report_prefix_pop(); 492 } 493 494 static void dbtr_test_load(struct sbi_dbtr_shmem_entry *shmem, enum McontrolType type) 495 { 496 static unsigned long test; 497 498 report_prefix_push("load trigger"); 499 if (!dbtr_install_trigger(shmem, &test, gen_tdata1(type, VALUE_LOAD, MODE_S))) { 500 report_prefix_pop(); 501 return; 502 } 503 504 report(do_load(&test), "triggered"); 505 506 if (do_store(&test)) 507 report_fail("triggered by store"); 508 509 dbtr_uninstall_trigger(); 510 report_prefix_pop(); 511 } 512 513 static void dbtr_test_disable_enable(struct sbi_dbtr_shmem_entry *shmem, enum McontrolType type) 514 { 515 static unsigned long test; 516 struct sbiret ret; 517 518 report_prefix_push("disable trigger"); 519 if (!dbtr_install_trigger(shmem, &test, gen_tdata1(type, VALUE_STORE, MODE_S))) { 520 report_prefix_pop(); 521 return; 522 } 523 524 ret = sbi_debug_disable_triggers(0, 1); 525 sbiret_report_error(&ret, SBI_SUCCESS, "sbi_debug_disable_triggers"); 526 527 if (!report(!do_store(&test), "should not trigger")) { 528 dbtr_uninstall_trigger(); 529 report_prefix_pop(); 530 report_skip("enable trigger: no disable"); 531 532 return; 533 } 534 535 report_prefix_pop(); 536 report_prefix_push("enable trigger"); 537 538 ret = sbi_debug_enable_triggers(0, 1); 539 sbiret_report_error(&ret, SBI_SUCCESS, "sbi_debug_enable_triggers"); 540 541 report(do_store(&test), "triggered"); 542 543 dbtr_uninstall_trigger(); 544 report_prefix_pop(); 545 } 546 547 static void dbtr_test_exec(struct sbi_dbtr_shmem_entry *shmem, enum McontrolType type) 548 { 549 static unsigned long test; 550 551 report_prefix_push("exec trigger"); 552 /* check if loads and stores trigger exec */ 553 if (!dbtr_install_trigger(shmem, &test, gen_tdata1(type, VALUE_EXECUTE, MODE_S))) { 554 report_prefix_pop(); 555 return; 556 } 557 558 if (do_load(&test)) 559 report_fail("triggered by load"); 560 561 if (do_store(&test)) 562 report_fail("triggered by store"); 563 564 dbtr_uninstall_trigger(); 565 566 /* Check if exec works */ 567 if (!dbtr_install_trigger(shmem, exec_call, gen_tdata1(type, VALUE_EXECUTE, MODE_S))) { 568 report_prefix_pop(); 569 return; 570 } 571 report(do_exec(), "triggered"); 572 573 dbtr_uninstall_trigger(); 574 report_prefix_pop(); 575 } 576 577 static void dbtr_test_read(struct sbi_dbtr_shmem_entry *shmem, enum McontrolType type) 578 { 579 const unsigned long tstatus_expected = SBI_DBTR_TRIG_STATE_S | SBI_DBTR_TRIG_STATE_MAPPED; 580 const unsigned long tdata1 = gen_tdata1(type, VALUE_STORE, MODE_S); 581 static unsigned long test; 582 struct sbiret ret; 583 584 report_prefix_push("read trigger"); 585 if (!dbtr_install_trigger(shmem, &test, tdata1)) { 586 report_prefix_pop(); 587 return; 588 } 589 590 ret = sbi_debug_read_triggers(0, 1); 591 sbiret_report_error(&ret, SBI_SUCCESS, "sbi_debug_read_triggers"); 592 593 if (!report(shmem->data.tdata1 == tdata1, "tdata1 expected: 0x%016lx", tdata1)) 594 report_info("tdata1 found: 0x%016lx", shmem->data.tdata1); 595 if (!report(shmem->data.tdata2 == ((unsigned long)&test), "tdata2 expected: 0x%016lx", 596 (unsigned long)&test)) 597 report_info("tdata2 found: 0x%016lx", shmem->data.tdata2); 598 if (!report(shmem->data.tstate == tstatus_expected, "tstate expected: 0x%016lx", tstatus_expected)) 599 report_info("tstate found: 0x%016lx", shmem->data.tstate); 600 601 dbtr_uninstall_trigger(); 602 report_prefix_pop(); 603 } 604 605 static void check_exec(unsigned long base) 606 { 607 struct sbiret ret; 608 609 report(do_exec(), "exec triggered"); 610 611 ret = sbi_debug_uninstall_triggers(base, 1); 612 sbiret_report_error(&ret, SBI_SUCCESS, "sbi_debug_uninstall_triggers"); 613 } 614 615 static void dbtr_test_multiple(struct sbi_dbtr_shmem_entry *shmem, enum McontrolType type, 616 unsigned long num_trigs) 617 { 618 static unsigned long test[2]; 619 struct sbiret ret; 620 bool have_three = num_trigs > 2; 621 622 if (num_trigs < 2) { 623 report_skip("test multiple"); 624 return; 625 } 626 627 report_prefix_push("test multiple"); 628 629 if (!dbtr_install_trigger(shmem, &test[0], gen_tdata1(type, VALUE_STORE, MODE_S))) { 630 report_prefix_pop(); 631 return; 632 } 633 if (!dbtr_install_trigger(shmem, &test[1], gen_tdata1(type, VALUE_LOAD, MODE_S))) 634 goto error; 635 if (have_three && 636 !dbtr_install_trigger(shmem, exec_call, gen_tdata1(type, VALUE_EXECUTE, MODE_S))) { 637 ret = sbi_debug_uninstall_triggers(1, 1); 638 sbiret_report_error(&ret, SBI_SUCCESS, "sbi_debug_uninstall_triggers"); 639 goto error; 640 } 641 642 report(do_store(&test[0]), "store triggered"); 643 644 if (do_load(&test[0])) 645 report_fail("store triggered by load"); 646 647 report(do_load(&test[1]), "load triggered"); 648 649 if (do_store(&test[1])) 650 report_fail("load triggered by store"); 651 652 if (have_three) 653 check_exec(2); 654 655 ret = sbi_debug_uninstall_triggers(1, 1); 656 sbiret_report_error(&ret, SBI_SUCCESS, "sbi_debug_uninstall_triggers"); 657 658 if (do_load(&test[1])) 659 report_fail("load triggered after uninstall"); 660 661 report(do_store(&test[0]), "store triggered"); 662 663 if (!have_three && 664 dbtr_install_trigger(shmem, exec_call, gen_tdata1(type, VALUE_EXECUTE, MODE_S))) 665 check_exec(1); 666 667 error: 668 ret = sbi_debug_uninstall_triggers(0, 1); 669 sbiret_report_error(&ret, SBI_SUCCESS, "sbi_debug_uninstall_triggers"); 670 671 install_exception_handler(EXC_BREAKPOINT, NULL); 672 report_prefix_pop(); 673 } 674 675 static void dbtr_test_multiple_types(struct sbi_dbtr_shmem_entry *shmem, unsigned long type) 676 { 677 static unsigned long test; 678 679 report_prefix_push("test multiple types"); 680 681 /* check if loads and stores trigger exec */ 682 if (!dbtr_install_trigger(shmem, &test, 683 gen_tdata1(type, VALUE_EXECUTE | VALUE_LOAD | VALUE_STORE, MODE_S))) { 684 report_prefix_pop(); 685 return; 686 } 687 688 report(do_load(&test), "load triggered"); 689 690 report(do_store(&test), "store triggered"); 691 692 dbtr_uninstall_trigger(); 693 694 /* Check if exec works */ 695 if (!dbtr_install_trigger(shmem, exec_call, 696 gen_tdata1(type, VALUE_EXECUTE | VALUE_LOAD | VALUE_STORE, MODE_S))) { 697 report_prefix_pop(); 698 return; 699 } 700 701 report(do_exec(), "exec triggered"); 702 703 dbtr_uninstall_trigger(); 704 report_prefix_pop(); 705 } 706 707 static void dbtr_test_disable_uninstall(struct sbi_dbtr_shmem_entry *shmem, enum McontrolType type) 708 { 709 static unsigned long test; 710 struct sbiret ret; 711 712 report_prefix_push("disable uninstall"); 713 if (!dbtr_install_trigger(shmem, &test, gen_tdata1(type, VALUE_STORE, MODE_S))) { 714 report_prefix_pop(); 715 return; 716 } 717 718 ret = sbi_debug_disable_triggers(0, 1); 719 sbiret_report_error(&ret, SBI_SUCCESS, "sbi_debug_disable_triggers"); 720 721 dbtr_uninstall_trigger(); 722 723 if (!dbtr_install_trigger(shmem, &test, gen_tdata1(type, VALUE_STORE, MODE_S))) { 724 report_prefix_pop(); 725 return; 726 } 727 728 report(do_store(&test), "triggered"); 729 730 dbtr_uninstall_trigger(); 731 report_prefix_pop(); 732 } 733 734 static void dbtr_test_uninstall_enable(struct sbi_dbtr_shmem_entry *shmem, enum McontrolType type) 735 { 736 static unsigned long test; 737 struct sbiret ret; 738 739 report_prefix_push("uninstall enable"); 740 if (!dbtr_install_trigger(shmem, &test, gen_tdata1(type, VALUE_STORE, MODE_S))) { 741 report_prefix_pop(); 742 return; 743 } 744 dbtr_uninstall_trigger(); 745 746 ret = sbi_debug_enable_triggers(0, 1); 747 sbiret_report_error(&ret, SBI_SUCCESS, "sbi_debug_enable_triggers"); 748 749 install_exception_handler(EXC_BREAKPOINT, dbtr_exception_handler); 750 751 report(!do_store(&test), "should not trigger"); 752 753 install_exception_handler(EXC_BREAKPOINT, NULL); 754 report_prefix_pop(); 755 } 756 757 static void dbtr_test_uninstall_update(struct sbi_dbtr_shmem_entry *shmem, enum McontrolType type) 758 { 759 static unsigned long test; 760 struct sbiret ret; 761 bool kfail; 762 763 report_prefix_push("uninstall update"); 764 if (!dbtr_install_trigger(shmem, NULL, gen_tdata1(type, VALUE_NONE, MODE_NONE))) { 765 report_prefix_pop(); 766 return; 767 } 768 769 dbtr_uninstall_trigger(); 770 771 shmem->id.idx = 0; 772 shmem->data.tdata1 = gen_tdata1(type, VALUE_STORE, MODE_S); 773 shmem->data.tdata2 = (unsigned long)&test; 774 775 /* 776 * Known broken update_triggers. 777 * https://lore.kernel.org/opensbi/aDdp1UeUh7GugeHp@ghost/T/#t 778 */ 779 kfail = __sbi_get_imp_id() == SBI_IMPL_OPENSBI && 780 __sbi_get_imp_version() < sbi_impl_opensbi_mk_version(1, 7); 781 ret = sbi_debug_update_triggers(1); 782 sbiret_kfail_error(kfail, &ret, SBI_ERR_FAILURE, "sbi_debug_update_triggers"); 783 784 install_exception_handler(EXC_BREAKPOINT, dbtr_exception_handler); 785 786 report(!do_store(&test), "should not trigger"); 787 788 install_exception_handler(EXC_BREAKPOINT, NULL); 789 report_prefix_pop(); 790 } 791 792 static void dbtr_test_disable_read(struct sbi_dbtr_shmem_entry *shmem, enum McontrolType type) 793 { 794 const unsigned long tstatus_expected = SBI_DBTR_TRIG_STATE_S | SBI_DBTR_TRIG_STATE_MAPPED; 795 const unsigned long tdata1 = gen_tdata1(type, VALUE_STORE, MODE_NONE); 796 static unsigned long test; 797 struct sbiret ret; 798 799 report_prefix_push("disable read"); 800 if (!dbtr_install_trigger(shmem, &test, gen_tdata1(type, VALUE_STORE, MODE_S))) { 801 report_prefix_pop(); 802 return; 803 } 804 805 ret = sbi_debug_disable_triggers(0, 1); 806 sbiret_report_error(&ret, SBI_SUCCESS, "sbi_debug_disable_triggers"); 807 808 ret = sbi_debug_read_triggers(0, 1); 809 sbiret_report_error(&ret, SBI_SUCCESS, "sbi_debug_read_triggers"); 810 811 if (!report(shmem->data.tdata1 == tdata1, "tdata1 expected: 0x%016lx", tdata1)) 812 report_info("tdata1 found: 0x%016lx", shmem->data.tdata1); 813 if (!report(shmem->data.tdata2 == ((unsigned long)&test), "tdata2 expected: 0x%016lx", 814 (unsigned long)&test)) 815 report_info("tdata2 found: 0x%016lx", shmem->data.tdata2); 816 if (!report(shmem->data.tstate == tstatus_expected, "tstate expected: 0x%016lx", tstatus_expected)) 817 report_info("tstate found: 0x%016lx", shmem->data.tstate); 818 819 dbtr_uninstall_trigger(); 820 report_prefix_pop(); 821 } 822 823 void check_dbtr(void) 824 { 825 static struct sbi_dbtr_shmem_entry shmem[RV_MAX_TRIGGERS] = {}; 826 unsigned long num_trigs; 827 enum McontrolType trig_type; 828 struct sbiret ret; 829 830 report_prefix_push("dbtr"); 831 832 if (!sbi_probe(SBI_EXT_DBTR)) { 833 report_skip("extension not available"); 834 goto exit_test; 835 } 836 837 num_trigs = dbtr_test_num_triggers(); 838 if (!num_trigs) 839 goto exit_test; 840 841 trig_type = dbtr_test_type(&num_trigs); 842 if (trig_type == SBI_DBTR_TDATA1_TYPE_NONE) 843 goto exit_test; 844 845 ret = sbi_debug_set_shmem(shmem); 846 sbiret_report_error(&ret, SBI_SUCCESS, "sbi_debug_set_shmem"); 847 848 ret = dbtr_test_store_install_uninstall(&shmem[0], trig_type); 849 /* install or uninstall failed */ 850 if (ret.error != SBI_SUCCESS) 851 goto exit_test; 852 853 dbtr_test_load(&shmem[0], trig_type); 854 dbtr_test_exec(&shmem[0], trig_type); 855 dbtr_test_read(&shmem[0], trig_type); 856 dbtr_test_disable_enable(&shmem[0], trig_type); 857 dbtr_test_update(&shmem[0], trig_type); 858 dbtr_test_multiple_types(&shmem[0], trig_type); 859 dbtr_test_multiple(shmem, trig_type, num_trigs); 860 dbtr_test_disable_uninstall(&shmem[0], trig_type); 861 dbtr_test_uninstall_enable(&shmem[0], trig_type); 862 dbtr_test_uninstall_update(&shmem[0], trig_type); 863 dbtr_test_disable_read(&shmem[0], trig_type); 864 865 exit_test: 866 report_prefix_pop(); 867 } 868