1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * SBI verification 4 * 5 * Copyright (C) 2023, Ventana Micro Systems Inc., Andrew Jones <ajones@ventanamicro.com> 6 */ 7 #include <libcflat.h> 8 #include <alloc_page.h> 9 #include <cpumask.h> 10 #include <limits.h> 11 #include <memregions.h> 12 #include <on-cpus.h> 13 #include <rand.h> 14 #include <stdlib.h> 15 #include <string.h> 16 #include <vmalloc.h> 17 18 #include <asm/barrier.h> 19 #include <asm/csr.h> 20 #include <asm/delay.h> 21 #include <asm/io.h> 22 #include <asm/mmu.h> 23 #include <asm/processor.h> 24 #include <asm/sbi.h> 25 #include <asm/smp.h> 26 #include <asm/timer.h> 27 28 #define HIGH_ADDR_BOUNDARY ((phys_addr_t)1 << 32) 29 30 static long __labs(long a) 31 { 32 return __builtin_labs(a); 33 } 34 35 static void help(void) 36 { 37 puts("Test SBI\n"); 38 puts("An environ must be provided where expected values are given.\n"); 39 } 40 41 static struct sbiret sbi_base(int fid, unsigned long arg0) 42 { 43 return sbi_ecall(SBI_EXT_BASE, fid, arg0, 0, 0, 0, 0, 0); 44 } 45 46 static struct sbiret sbi_dbcn_write(unsigned long num_bytes, unsigned long base_addr_lo, 47 unsigned long base_addr_hi) 48 { 49 return sbi_ecall(SBI_EXT_DBCN, SBI_EXT_DBCN_CONSOLE_WRITE, 50 num_bytes, base_addr_lo, base_addr_hi, 0, 0, 0); 51 } 52 53 static struct sbiret sbi_dbcn_write_byte(uint8_t byte) 54 { 55 return sbi_ecall(SBI_EXT_DBCN, SBI_EXT_DBCN_CONSOLE_WRITE_BYTE, byte, 0, 0, 0, 0, 0); 56 } 57 58 static int rand_online_cpu(prng_state *ps) 59 { 60 int cpu, me = smp_processor_id(); 61 62 for (;;) { 63 cpu = prng32(ps) % nr_cpus; 64 cpu = cpumask_next(cpu - 1, &cpu_present_mask); 65 if (cpu != nr_cpus && cpu != me && cpu_present(cpu)) 66 break; 67 } 68 69 return cpu; 70 } 71 72 static void split_phys_addr(phys_addr_t paddr, unsigned long *hi, unsigned long *lo) 73 { 74 *lo = (unsigned long)paddr; 75 *hi = 0; 76 if (__riscv_xlen == 32) 77 *hi = (unsigned long)(paddr >> 32); 78 } 79 80 static bool check_addr(phys_addr_t start, phys_addr_t size) 81 { 82 struct mem_region *r = memregions_find(start); 83 return r && r->end - start >= size && r->flags == MR_F_UNUSED; 84 } 85 86 static phys_addr_t get_highest_addr(void) 87 { 88 phys_addr_t highest_end = 0; 89 struct mem_region *r; 90 91 for (r = mem_regions; r->end; ++r) { 92 if (r->end > highest_end) 93 highest_end = r->end; 94 } 95 96 return highest_end - 1; 97 } 98 99 static bool env_or_skip(const char *env) 100 { 101 if (!getenv(env)) { 102 report_skip("missing %s environment variable", env); 103 return false; 104 } 105 106 return true; 107 } 108 109 static void gen_report(struct sbiret *ret, 110 long expected_error, long expected_value) 111 { 112 bool check_error = ret->error == expected_error; 113 bool check_value = ret->value == expected_value; 114 115 if (!check_error || !check_value) 116 report_info("expected (error: %ld, value: %ld), received: (error: %ld, value %ld)", 117 expected_error, expected_value, ret->error, ret->value); 118 119 report(check_error, "expected sbi.error"); 120 report(check_value, "expected sbi.value"); 121 } 122 123 static void check_base(void) 124 { 125 struct sbiret ret; 126 long expected; 127 128 report_prefix_push("base"); 129 130 ret = sbi_base(SBI_EXT_BASE_GET_SPEC_VERSION, 0); 131 132 report_prefix_push("spec_version"); 133 if (env_or_skip("SBI_SPEC_VERSION")) { 134 expected = (long)strtoul(getenv("SBI_SPEC_VERSION"), NULL, 0); 135 assert_msg(!(expected & BIT(31)), "SBI spec version bit 31 must be zero"); 136 assert_msg(__riscv_xlen == 32 || !(expected >> 32), "SBI spec version bits greater than 31 must be zero"); 137 gen_report(&ret, 0, expected); 138 } 139 report_prefix_pop(); 140 141 ret.value &= 0x7ffffffful; 142 143 if (ret.error || ret.value < 2) { 144 report_skip("SBI spec version 0.2 or higher required"); 145 return; 146 } 147 148 report_prefix_push("impl_id"); 149 if (env_or_skip("SBI_IMPL_ID")) { 150 expected = (long)strtoul(getenv("SBI_IMPL_ID"), NULL, 0); 151 ret = sbi_base(SBI_EXT_BASE_GET_IMP_ID, 0); 152 gen_report(&ret, 0, expected); 153 } 154 report_prefix_pop(); 155 156 report_prefix_push("impl_version"); 157 if (env_or_skip("SBI_IMPL_VERSION")) { 158 expected = (long)strtoul(getenv("SBI_IMPL_VERSION"), NULL, 0); 159 ret = sbi_base(SBI_EXT_BASE_GET_IMP_VERSION, 0); 160 gen_report(&ret, 0, expected); 161 } 162 report_prefix_pop(); 163 164 report_prefix_push("probe_ext"); 165 expected = getenv("SBI_PROBE_EXT") ? (long)strtoul(getenv("SBI_PROBE_EXT"), NULL, 0) : 1; 166 ret = sbi_base(SBI_EXT_BASE_PROBE_EXT, SBI_EXT_BASE); 167 gen_report(&ret, 0, expected); 168 report_prefix_push("unavailable"); 169 ret = sbi_base(SBI_EXT_BASE_PROBE_EXT, 0xb000000); 170 gen_report(&ret, 0, 0); 171 report_prefix_popn(2); 172 173 report_prefix_push("mvendorid"); 174 if (env_or_skip("MVENDORID")) { 175 expected = (long)strtoul(getenv("MVENDORID"), NULL, 0); 176 assert(__riscv_xlen == 32 || !(expected >> 32)); 177 ret = sbi_base(SBI_EXT_BASE_GET_MVENDORID, 0); 178 gen_report(&ret, 0, expected); 179 } 180 report_prefix_pop(); 181 182 report_prefix_push("marchid"); 183 if (env_or_skip("MARCHID")) { 184 expected = (long)strtoul(getenv("MARCHID"), NULL, 0); 185 ret = sbi_base(SBI_EXT_BASE_GET_MARCHID, 0); 186 gen_report(&ret, 0, expected); 187 } 188 report_prefix_pop(); 189 190 report_prefix_push("mimpid"); 191 if (env_or_skip("MIMPID")) { 192 expected = (long)strtoul(getenv("MIMPID"), NULL, 0); 193 ret = sbi_base(SBI_EXT_BASE_GET_MIMPID, 0); 194 gen_report(&ret, 0, expected); 195 } 196 report_prefix_popn(2); 197 } 198 199 struct timer_info { 200 bool timer_works; 201 bool mask_timer_irq; 202 bool timer_irq_set; 203 bool timer_irq_cleared; 204 unsigned long timer_irq_count; 205 }; 206 207 static struct timer_info timer_info; 208 209 static bool timer_irq_pending(void) 210 { 211 return csr_read(CSR_SIP) & IP_TIP; 212 } 213 214 static void timer_irq_handler(struct pt_regs *regs) 215 { 216 timer_info.timer_works = true; 217 218 if (timer_info.timer_irq_count < ULONG_MAX) 219 ++timer_info.timer_irq_count; 220 221 if (timer_irq_pending()) 222 timer_info.timer_irq_set = true; 223 224 if (timer_info.mask_timer_irq) 225 timer_irq_disable(); 226 else 227 sbi_set_timer(ULONG_MAX); 228 229 if (!timer_irq_pending()) 230 timer_info.timer_irq_cleared = true; 231 } 232 233 static void timer_check_set_timer(bool mask_timer_irq) 234 { 235 struct sbiret ret; 236 unsigned long begin, end, duration; 237 const char *mask_test_str = mask_timer_irq ? " for mask irq test" : ""; 238 unsigned long d = getenv("SBI_TIMER_DELAY") ? strtol(getenv("SBI_TIMER_DELAY"), NULL, 0) : 200000; 239 unsigned long margin = getenv("SBI_TIMER_MARGIN") ? strtol(getenv("SBI_TIMER_MARGIN"), NULL, 0) : 200000; 240 241 d = usec_to_cycles(d); 242 margin = usec_to_cycles(margin); 243 244 timer_info = (struct timer_info){ .mask_timer_irq = mask_timer_irq }; 245 begin = timer_get_cycles(); 246 ret = sbi_set_timer(begin + d); 247 248 report(!ret.error, "set timer%s", mask_test_str); 249 if (ret.error) 250 report_info("set timer%s failed with %ld\n", mask_test_str, ret.error); 251 252 while ((end = timer_get_cycles()) <= (begin + d + margin) && !timer_info.timer_works) 253 cpu_relax(); 254 255 report(timer_info.timer_works, "timer interrupt received%s", mask_test_str); 256 report(timer_info.timer_irq_set, "pending timer interrupt bit set in irq handler%s", mask_test_str); 257 258 if (!mask_timer_irq) { 259 report(timer_info.timer_irq_set && timer_info.timer_irq_cleared, 260 "pending timer interrupt bit cleared by setting timer to -1"); 261 } 262 263 if (timer_info.timer_works) { 264 duration = end - begin; 265 report(duration >= d && duration <= (d + margin), "timer delay honored%s", mask_test_str); 266 } 267 268 report(timer_info.timer_irq_count == 1, "timer interrupt received exactly once%s", mask_test_str); 269 } 270 271 static void check_time(void) 272 { 273 bool pending; 274 275 report_prefix_push("time"); 276 277 if (!sbi_probe(SBI_EXT_TIME)) { 278 report_skip("time extension not available"); 279 report_prefix_pop(); 280 return; 281 } 282 283 report_prefix_push("set_timer"); 284 285 install_irq_handler(IRQ_S_TIMER, timer_irq_handler); 286 local_irq_enable(); 287 timer_irq_enable(); 288 289 timer_check_set_timer(false); 290 291 if (csr_read(CSR_SIE) & IE_TIE) 292 timer_check_set_timer(true); 293 else 294 report_skip("timer irq enable bit is not writable, skipping mask irq test"); 295 296 timer_irq_disable(); 297 sbi_set_timer(0); 298 pending = timer_irq_pending(); 299 report(pending, "timer immediately pending by setting timer to 0"); 300 sbi_set_timer(ULONG_MAX); 301 if (pending) 302 report(!timer_irq_pending(), "pending timer cleared while masked"); 303 else 304 report_skip("timer is not pending, skipping timer cleared while masked test"); 305 306 local_irq_disable(); 307 install_irq_handler(IRQ_S_TIMER, NULL); 308 309 report_prefix_popn(2); 310 } 311 312 static bool ipi_received[NR_CPUS]; 313 static bool ipi_timeout[NR_CPUS]; 314 static cpumask_t ipi_done; 315 316 static void ipi_timeout_handler(struct pt_regs *regs) 317 { 318 timer_stop(); 319 ipi_timeout[smp_processor_id()] = true; 320 } 321 322 static void ipi_irq_handler(struct pt_regs *regs) 323 { 324 ipi_ack(); 325 ipi_received[smp_processor_id()] = true; 326 } 327 328 static void ipi_hart_wait(void *data) 329 { 330 unsigned long timeout = (unsigned long)data; 331 int me = smp_processor_id(); 332 333 install_irq_handler(IRQ_S_SOFT, ipi_irq_handler); 334 install_irq_handler(IRQ_S_TIMER, ipi_timeout_handler); 335 local_ipi_enable(); 336 timer_irq_enable(); 337 local_irq_enable(); 338 339 timer_start(timeout); 340 while (!READ_ONCE(ipi_received[me]) && !READ_ONCE(ipi_timeout[me])) 341 cpu_relax(); 342 local_irq_disable(); 343 timer_stop(); 344 local_ipi_disable(); 345 timer_irq_disable(); 346 347 cpumask_set_cpu(me, &ipi_done); 348 } 349 350 static void ipi_hart_check(cpumask_t *mask) 351 { 352 int cpu; 353 354 for_each_cpu(cpu, mask) { 355 if (ipi_timeout[cpu]) { 356 const char *rec = ipi_received[cpu] ? "but was still received" 357 : "and has still not been received"; 358 report_fail("ipi timed out on cpu%d %s", cpu, rec); 359 } 360 361 ipi_timeout[cpu] = false; 362 ipi_received[cpu] = false; 363 } 364 } 365 366 static void check_ipi(void) 367 { 368 unsigned long d = getenv("SBI_IPI_TIMEOUT") ? strtol(getenv("SBI_IPI_TIMEOUT"), NULL, 0) : 200000; 369 int nr_cpus_present = cpumask_weight(&cpu_present_mask); 370 int me = smp_processor_id(); 371 unsigned long max_hartid = 0; 372 unsigned long hartid1, hartid2; 373 cpumask_t ipi_receivers; 374 static prng_state ps; 375 struct sbiret ret; 376 int cpu, cpu2; 377 378 ps = prng_init(0xDEADBEEF); 379 380 report_prefix_push("ipi"); 381 382 if (!sbi_probe(SBI_EXT_IPI)) { 383 report_skip("ipi extension not available"); 384 report_prefix_pop(); 385 return; 386 } 387 388 if (nr_cpus_present < 2) { 389 report_skip("At least 2 cpus required"); 390 report_prefix_pop(); 391 return; 392 } 393 394 report_prefix_push("random hart"); 395 cpumask_clear(&ipi_done); 396 cpumask_clear(&ipi_receivers); 397 cpu = rand_online_cpu(&ps); 398 cpumask_set_cpu(cpu, &ipi_receivers); 399 on_cpu_async(cpu, ipi_hart_wait, (void *)d); 400 ret = sbi_send_ipi_cpu(cpu); 401 report(ret.error == SBI_SUCCESS, "ipi returned success"); 402 while (!cpumask_equal(&ipi_done, &ipi_receivers)) 403 cpu_relax(); 404 ipi_hart_check(&ipi_receivers); 405 report_prefix_pop(); 406 407 report_prefix_push("two in hart_mask"); 408 409 if (nr_cpus_present < 3) { 410 report_skip("3 cpus required"); 411 goto end_two; 412 } 413 414 cpu = rand_online_cpu(&ps); 415 hartid1 = cpus[cpu].hartid; 416 hartid2 = 0; 417 for_each_present_cpu(cpu2) { 418 if (cpu2 == cpu || cpu2 == me) 419 continue; 420 hartid2 = cpus[cpu2].hartid; 421 if (__labs(hartid2 - hartid1) < BITS_PER_LONG) 422 break; 423 } 424 if (cpu2 == nr_cpus) { 425 report_skip("hartids are too sparse"); 426 goto end_two; 427 } 428 429 cpumask_clear(&ipi_done); 430 cpumask_clear(&ipi_receivers); 431 cpumask_set_cpu(cpu, &ipi_receivers); 432 cpumask_set_cpu(cpu2, &ipi_receivers); 433 on_cpu_async(cpu, ipi_hart_wait, (void *)d); 434 on_cpu_async(cpu2, ipi_hart_wait, (void *)d); 435 ret = sbi_send_ipi((1UL << __labs(hartid2 - hartid1)) | 1UL, hartid1 < hartid2 ? hartid1 : hartid2); 436 report(ret.error == SBI_SUCCESS, "ipi returned success"); 437 while (!cpumask_equal(&ipi_done, &ipi_receivers)) 438 cpu_relax(); 439 ipi_hart_check(&ipi_receivers); 440 end_two: 441 report_prefix_pop(); 442 443 report_prefix_push("broadcast"); 444 cpumask_clear(&ipi_done); 445 cpumask_copy(&ipi_receivers, &cpu_present_mask); 446 cpumask_clear_cpu(me, &ipi_receivers); 447 on_cpumask_async(&ipi_receivers, ipi_hart_wait, (void *)d); 448 ret = sbi_send_ipi_broadcast(); 449 report(ret.error == SBI_SUCCESS, "ipi returned success"); 450 while (!cpumask_equal(&ipi_done, &ipi_receivers)) 451 cpu_relax(); 452 ipi_hart_check(&ipi_receivers); 453 report_prefix_pop(); 454 455 report_prefix_push("invalid parameters"); 456 457 for_each_present_cpu(cpu) { 458 if (cpus[cpu].hartid > max_hartid) 459 max_hartid = cpus[cpu].hartid; 460 } 461 462 /* Try the next higher hartid than the max */ 463 ret = sbi_send_ipi(2, max_hartid); 464 report_kfail(true, ret.error == SBI_ERR_INVALID_PARAM, "hart_mask got expected error (%ld)", ret.error); 465 ret = sbi_send_ipi(1, max_hartid + 1); 466 report_kfail(true, ret.error == SBI_ERR_INVALID_PARAM, "hart_mask_base got expected error (%ld)", ret.error); 467 468 report_prefix_pop(); 469 470 report_prefix_pop(); 471 } 472 473 #define DBCN_WRITE_TEST_STRING "DBCN_WRITE_TEST_STRING\n" 474 #define DBCN_WRITE_BYTE_TEST_BYTE ((u8)'a') 475 476 static void dbcn_write_test(const char *s, unsigned long num_bytes, bool xfail) 477 { 478 unsigned long base_addr_lo, base_addr_hi; 479 phys_addr_t paddr = virt_to_phys((void *)s); 480 int num_calls = 0; 481 struct sbiret ret; 482 483 split_phys_addr(paddr, &base_addr_hi, &base_addr_lo); 484 485 do { 486 ret = sbi_dbcn_write(num_bytes, base_addr_lo, base_addr_hi); 487 num_bytes -= ret.value; 488 paddr += ret.value; 489 split_phys_addr(paddr, &base_addr_hi, &base_addr_lo); 490 num_calls++; 491 } while (num_bytes != 0 && ret.error == SBI_SUCCESS); 492 493 report_xfail(xfail, ret.error == SBI_SUCCESS, "write success (error=%ld)", ret.error); 494 report_info("%d sbi calls made", num_calls); 495 } 496 497 static void dbcn_high_write_test(const char *s, unsigned long num_bytes, 498 phys_addr_t page_addr, size_t page_offset, 499 bool highmem_supported) 500 { 501 int nr_pages = page_offset ? 2 : 1; 502 void *vaddr; 503 504 if (page_addr != PAGE_ALIGN(page_addr) || page_addr + PAGE_SIZE < HIGH_ADDR_BOUNDARY || 505 !check_addr(page_addr, nr_pages * PAGE_SIZE)) { 506 report_skip("Memory above 4G required"); 507 return; 508 } 509 510 vaddr = alloc_vpages(nr_pages); 511 512 for (int i = 0; i < nr_pages; ++i) 513 install_page(current_pgtable(), page_addr + i * PAGE_SIZE, vaddr + i * PAGE_SIZE); 514 memcpy(vaddr + page_offset, DBCN_WRITE_TEST_STRING, num_bytes); 515 dbcn_write_test(vaddr + page_offset, num_bytes, !highmem_supported); 516 } 517 518 /* 519 * Only the write functionality is tested here. There's no easy way to 520 * non-interactively test SBI_EXT_DBCN_CONSOLE_READ. 521 */ 522 static void check_dbcn(void) 523 { 524 unsigned long num_bytes = strlen(DBCN_WRITE_TEST_STRING); 525 unsigned long base_addr_lo, base_addr_hi; 526 bool do_invalid_addr = false; 527 bool highmem_supported = true; 528 phys_addr_t paddr; 529 struct sbiret ret; 530 const char *tmp; 531 char *buf; 532 533 report_prefix_push("dbcn"); 534 535 if (!sbi_probe(SBI_EXT_DBCN)) { 536 report_skip("DBCN extension unavailable"); 537 report_prefix_pop(); 538 return; 539 } 540 541 report_prefix_push("write"); 542 543 dbcn_write_test(DBCN_WRITE_TEST_STRING, num_bytes, false); 544 545 assert(num_bytes < PAGE_SIZE); 546 547 report_prefix_push("page boundary"); 548 buf = alloc_pages(1); 549 memcpy(&buf[PAGE_SIZE - num_bytes / 2], DBCN_WRITE_TEST_STRING, num_bytes); 550 dbcn_write_test(&buf[PAGE_SIZE - num_bytes / 2], num_bytes, false); 551 report_prefix_pop(); 552 553 tmp = getenv("SBI_HIGHMEM_NOT_SUPPORTED"); 554 if (tmp && atol(tmp) != 0) 555 highmem_supported = false; 556 557 report_prefix_push("high boundary"); 558 tmp = getenv("SBI_DBCN_SKIP_HIGH_BOUNDARY"); 559 if (!tmp || atol(tmp) == 0) 560 dbcn_high_write_test(DBCN_WRITE_TEST_STRING, num_bytes, 561 HIGH_ADDR_BOUNDARY - PAGE_SIZE, PAGE_SIZE - num_bytes / 2, 562 highmem_supported); 563 else 564 report_skip("user disabled"); 565 report_prefix_pop(); 566 567 report_prefix_push("high page"); 568 tmp = getenv("SBI_DBCN_SKIP_HIGH_PAGE"); 569 if (!tmp || atol(tmp) == 0) { 570 paddr = HIGH_ADDR_BOUNDARY; 571 tmp = getenv("HIGH_PAGE"); 572 if (tmp) 573 paddr = strtoull(tmp, NULL, 0); 574 dbcn_high_write_test(DBCN_WRITE_TEST_STRING, num_bytes, paddr, 0, highmem_supported); 575 } else { 576 report_skip("user disabled"); 577 } 578 report_prefix_pop(); 579 580 /* Bytes are read from memory and written to the console */ 581 report_prefix_push("invalid parameter"); 582 tmp = getenv("INVALID_ADDR_AUTO"); 583 if (tmp && atol(tmp) == 1) { 584 paddr = get_highest_addr() + 1; 585 do_invalid_addr = true; 586 } else if (env_or_skip("INVALID_ADDR")) { 587 paddr = strtoull(getenv("INVALID_ADDR"), NULL, 0); 588 do_invalid_addr = true; 589 } 590 591 if (do_invalid_addr) { 592 split_phys_addr(paddr, &base_addr_hi, &base_addr_lo); 593 ret = sbi_dbcn_write(1, base_addr_lo, base_addr_hi); 594 report(ret.error == SBI_ERR_INVALID_PARAM, "address (error=%ld)", ret.error); 595 } 596 report_prefix_popn(2); 597 report_prefix_push("write_byte"); 598 599 puts("DBCN_WRITE_BYTE TEST BYTE: "); 600 ret = sbi_dbcn_write_byte(DBCN_WRITE_BYTE_TEST_BYTE); 601 puts("\n"); 602 report(ret.error == SBI_SUCCESS, "write success (error=%ld)", ret.error); 603 report(ret.value == 0, "expected ret.value (%ld)", ret.value); 604 605 puts("DBCN_WRITE_BYTE TEST WORD: "); /* still expect 'a' in the output */ 606 ret = sbi_ecall(SBI_EXT_DBCN, SBI_EXT_DBCN_CONSOLE_WRITE_BYTE, 0x64636261, 0, 0, 0, 0, 0); 607 puts("\n"); 608 report(ret.error == SBI_SUCCESS, "write success (error=%ld)", ret.error); 609 report(ret.value == 0, "expected ret.value (%ld)", ret.value); 610 611 report_prefix_popn(2); 612 } 613 614 int main(int argc, char **argv) 615 { 616 if (argc > 1 && !strcmp(argv[1], "-h")) { 617 help(); 618 exit(0); 619 } 620 621 report_prefix_push("sbi"); 622 check_base(); 623 check_time(); 624 check_ipi(); 625 check_dbcn(); 626 627 return report_summary(); 628 } 629