683 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * sbi_pmu_test.c - Tests the riscv64 SBI PMU functionality.4 *5 * Copyright (c) 2024, Rivos Inc.6 */7 8#include <stdio.h>9#include <stdlib.h>10#include <string.h>11#include <unistd.h>12#include <sys/types.h>13#include "kvm_util.h"14#include "test_util.h"15#include "processor.h"16#include "sbi.h"17#include "arch_timer.h"18#include "ucall_common.h"19 20/* Maximum counters(firmware + hardware) */21#define RISCV_MAX_PMU_COUNTERS 6422union sbi_pmu_ctr_info ctrinfo_arr[RISCV_MAX_PMU_COUNTERS];23 24/* Snapshot shared memory data */25#define PMU_SNAPSHOT_GPA_BASE BIT(30)26static void *snapshot_gva;27static vm_paddr_t snapshot_gpa;28 29static int vcpu_shared_irq_count;30static int counter_in_use;31 32/* Cache the available counters in a bitmask */33static unsigned long counter_mask_available;34 35static bool illegal_handler_invoked;36 37#define SBI_PMU_TEST_BASIC BIT(0)38#define SBI_PMU_TEST_EVENTS BIT(1)39#define SBI_PMU_TEST_SNAPSHOT BIT(2)40#define SBI_PMU_TEST_OVERFLOW BIT(3)41 42static int disabled_tests;43 44unsigned long pmu_csr_read_num(int csr_num)45{46#define switchcase_csr_read(__csr_num, __val) {\47 case __csr_num: \48 __val = csr_read(__csr_num); \49 break; }50#define switchcase_csr_read_2(__csr_num, __val) {\51 switchcase_csr_read(__csr_num + 0, __val) \52 switchcase_csr_read(__csr_num + 1, __val)}53#define switchcase_csr_read_4(__csr_num, __val) {\54 switchcase_csr_read_2(__csr_num + 0, __val) \55 switchcase_csr_read_2(__csr_num + 2, __val)}56#define switchcase_csr_read_8(__csr_num, __val) {\57 switchcase_csr_read_4(__csr_num + 0, __val) \58 switchcase_csr_read_4(__csr_num + 4, __val)}59#define switchcase_csr_read_16(__csr_num, __val) {\60 switchcase_csr_read_8(__csr_num + 0, __val) \61 switchcase_csr_read_8(__csr_num + 8, __val)}62#define switchcase_csr_read_32(__csr_num, __val) {\63 switchcase_csr_read_16(__csr_num + 0, __val) \64 switchcase_csr_read_16(__csr_num + 16, __val)}65 66 unsigned long ret = 0;67 68 switch (csr_num) {69 switchcase_csr_read_32(CSR_CYCLE, ret)70 switchcase_csr_read_32(CSR_CYCLEH, ret)71 default :72 break;73 }74 75 return ret;76#undef switchcase_csr_read_3277#undef switchcase_csr_read_1678#undef switchcase_csr_read_879#undef switchcase_csr_read_480#undef switchcase_csr_read_281#undef switchcase_csr_read82}83 84static inline void dummy_func_loop(uint64_t iter)85{86 int i = 0;87 88 while (i < iter) {89 asm volatile("nop");90 i++;91 }92}93 94static void start_counter(unsigned long counter, unsigned long start_flags,95 unsigned long ival)96{97 struct sbiret ret;98 99 ret = sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_COUNTER_START, counter, 1, start_flags,100 ival, 0, 0);101 __GUEST_ASSERT(ret.error == 0, "Unable to start counter %ld\n", counter);102}103 104/* This should be invoked only for reset counter use case */105static void stop_reset_counter(unsigned long counter, unsigned long stop_flags)106{107 struct sbiret ret;108 109 ret = sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_COUNTER_STOP, counter, 1,110 stop_flags | SBI_PMU_STOP_FLAG_RESET, 0, 0, 0);111 __GUEST_ASSERT(ret.error == SBI_ERR_ALREADY_STOPPED,112 "Unable to stop counter %ld\n", counter);113}114 115static void stop_counter(unsigned long counter, unsigned long stop_flags)116{117 struct sbiret ret;118 119 ret = sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_COUNTER_STOP, counter, 1, stop_flags,120 0, 0, 0);121 __GUEST_ASSERT(ret.error == 0, "Unable to stop counter %ld error %ld\n",122 counter, ret.error);123}124 125static void guest_illegal_exception_handler(struct ex_regs *regs)126{127 __GUEST_ASSERT(regs->cause == EXC_INST_ILLEGAL,128 "Unexpected exception handler %lx\n", regs->cause);129 130 illegal_handler_invoked = true;131 /* skip the trapping instruction */132 regs->epc += 4;133}134 135static void guest_irq_handler(struct ex_regs *regs)136{137 unsigned int irq_num = regs->cause & ~CAUSE_IRQ_FLAG;138 struct riscv_pmu_snapshot_data *snapshot_data = snapshot_gva;139 unsigned long overflown_mask;140 unsigned long counter_val = 0;141 142 /* Validate that we are in the correct irq handler */143 GUEST_ASSERT_EQ(irq_num, IRQ_PMU_OVF);144 145 /* Stop all counters first to avoid further interrupts */146 stop_counter(counter_in_use, SBI_PMU_STOP_FLAG_TAKE_SNAPSHOT);147 148 csr_clear(CSR_SIP, BIT(IRQ_PMU_OVF));149 150 overflown_mask = READ_ONCE(snapshot_data->ctr_overflow_mask);151 GUEST_ASSERT(overflown_mask & 0x01);152 153 WRITE_ONCE(vcpu_shared_irq_count, vcpu_shared_irq_count+1);154 155 counter_val = READ_ONCE(snapshot_data->ctr_values[0]);156 /* Now start the counter to mimick the real driver behavior */157 start_counter(counter_in_use, SBI_PMU_START_FLAG_SET_INIT_VALUE, counter_val);158}159 160static unsigned long get_counter_index(unsigned long cbase, unsigned long cmask,161 unsigned long cflags,162 unsigned long event)163{164 struct sbiret ret;165 166 ret = sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_COUNTER_CFG_MATCH, cbase, cmask,167 cflags, event, 0, 0);168 __GUEST_ASSERT(ret.error == 0, "config matching failed %ld\n", ret.error);169 GUEST_ASSERT(ret.value < RISCV_MAX_PMU_COUNTERS);170 GUEST_ASSERT(BIT(ret.value) & counter_mask_available);171 172 return ret.value;173}174 175static unsigned long get_num_counters(void)176{177 struct sbiret ret;178 179 ret = sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_NUM_COUNTERS, 0, 0, 0, 0, 0, 0);180 181 __GUEST_ASSERT(ret.error == 0, "Unable to retrieve number of counters from SBI PMU");182 __GUEST_ASSERT(ret.value < RISCV_MAX_PMU_COUNTERS,183 "Invalid number of counters %ld\n", ret.value);184 185 return ret.value;186}187 188static void update_counter_info(int num_counters)189{190 int i = 0;191 struct sbiret ret;192 193 for (i = 0; i < num_counters; i++) {194 ret = sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_COUNTER_GET_INFO, i, 0, 0, 0, 0, 0);195 196 /* There can be gaps in logical counter indicies*/197 if (ret.error)198 continue;199 GUEST_ASSERT_NE(ret.value, 0);200 201 ctrinfo_arr[i].value = ret.value;202 counter_mask_available |= BIT(i);203 }204 205 GUEST_ASSERT(counter_mask_available > 0);206}207 208static unsigned long read_fw_counter(int idx, union sbi_pmu_ctr_info ctrinfo)209{210 struct sbiret ret;211 212 ret = sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_COUNTER_FW_READ, idx, 0, 0, 0, 0, 0);213 GUEST_ASSERT(ret.error == 0);214 return ret.value;215}216 217static unsigned long read_counter(int idx, union sbi_pmu_ctr_info ctrinfo)218{219 unsigned long counter_val = 0;220 221 __GUEST_ASSERT(ctrinfo.type < 2, "Invalid counter type %d", ctrinfo.type);222 223 if (ctrinfo.type == SBI_PMU_CTR_TYPE_HW)224 counter_val = pmu_csr_read_num(ctrinfo.csr);225 else if (ctrinfo.type == SBI_PMU_CTR_TYPE_FW)226 counter_val = read_fw_counter(idx, ctrinfo);227 228 return counter_val;229}230 231static inline void verify_sbi_requirement_assert(void)232{233 long out_val = 0;234 bool probe;235 236 probe = guest_sbi_probe_extension(SBI_EXT_PMU, &out_val);237 GUEST_ASSERT(probe && out_val == 1);238 239 if (get_host_sbi_spec_version() < sbi_mk_version(2, 0))240 __GUEST_ASSERT(0, "SBI implementation version doesn't support PMU Snapshot");241}242 243static void snapshot_set_shmem(vm_paddr_t gpa, unsigned long flags)244{245 unsigned long lo = (unsigned long)gpa;246#if __riscv_xlen == 32247 unsigned long hi = (unsigned long)(gpa >> 32);248#else249 unsigned long hi = gpa == -1 ? -1 : 0;250#endif251 struct sbiret ret = sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_SNAPSHOT_SET_SHMEM,252 lo, hi, flags, 0, 0, 0);253 254 GUEST_ASSERT(ret.value == 0 && ret.error == 0);255}256 257static void test_pmu_event(unsigned long event)258{259 unsigned long counter;260 unsigned long counter_value_pre, counter_value_post;261 unsigned long counter_init_value = 100;262 263 counter = get_counter_index(0, counter_mask_available, 0, event);264 counter_value_pre = read_counter(counter, ctrinfo_arr[counter]);265 266 /* Do not set the initial value */267 start_counter(counter, 0, 0);268 dummy_func_loop(10000);269 stop_counter(counter, 0);270 271 counter_value_post = read_counter(counter, ctrinfo_arr[counter]);272 __GUEST_ASSERT(counter_value_post > counter_value_pre,273 "Event update verification failed: post [%lx] pre [%lx]\n",274 counter_value_post, counter_value_pre);275 276 /*277 * We can't just update the counter without starting it.278 * Do start/stop twice to simulate that by first initializing to a very279 * high value and a low value after that.280 */281 start_counter(counter, SBI_PMU_START_FLAG_SET_INIT_VALUE, ULONG_MAX/2);282 stop_counter(counter, 0);283 counter_value_pre = read_counter(counter, ctrinfo_arr[counter]);284 285 start_counter(counter, SBI_PMU_START_FLAG_SET_INIT_VALUE, counter_init_value);286 stop_counter(counter, 0);287 counter_value_post = read_counter(counter, ctrinfo_arr[counter]);288 __GUEST_ASSERT(counter_value_pre > counter_value_post,289 "Counter reinitialization verification failed : post [%lx] pre [%lx]\n",290 counter_value_post, counter_value_pre);291 292 /* Now set the initial value and compare */293 start_counter(counter, SBI_PMU_START_FLAG_SET_INIT_VALUE, counter_init_value);294 dummy_func_loop(10000);295 stop_counter(counter, 0);296 297 counter_value_post = read_counter(counter, ctrinfo_arr[counter]);298 __GUEST_ASSERT(counter_value_post > counter_init_value,299 "Event update verification failed: post [%lx] pre [%lx]\n",300 counter_value_post, counter_init_value);301 302 stop_reset_counter(counter, 0);303}304 305static void test_pmu_event_snapshot(unsigned long event)306{307 unsigned long counter;308 unsigned long counter_value_pre, counter_value_post;309 unsigned long counter_init_value = 100;310 struct riscv_pmu_snapshot_data *snapshot_data = snapshot_gva;311 312 counter = get_counter_index(0, counter_mask_available, 0, event);313 counter_value_pre = read_counter(counter, ctrinfo_arr[counter]);314 315 /* Do not set the initial value */316 start_counter(counter, 0, 0);317 dummy_func_loop(10000);318 stop_counter(counter, SBI_PMU_STOP_FLAG_TAKE_SNAPSHOT);319 320 /* The counter value is updated w.r.t relative index of cbase */321 counter_value_post = READ_ONCE(snapshot_data->ctr_values[0]);322 __GUEST_ASSERT(counter_value_post > counter_value_pre,323 "Event update verification failed: post [%lx] pre [%lx]\n",324 counter_value_post, counter_value_pre);325 326 /*327 * We can't just update the counter without starting it.328 * Do start/stop twice to simulate that by first initializing to a very329 * high value and a low value after that.330 */331 WRITE_ONCE(snapshot_data->ctr_values[0], ULONG_MAX/2);332 start_counter(counter, SBI_PMU_START_FLAG_INIT_SNAPSHOT, 0);333 stop_counter(counter, SBI_PMU_STOP_FLAG_TAKE_SNAPSHOT);334 counter_value_pre = READ_ONCE(snapshot_data->ctr_values[0]);335 336 WRITE_ONCE(snapshot_data->ctr_values[0], counter_init_value);337 start_counter(counter, SBI_PMU_START_FLAG_INIT_SNAPSHOT, 0);338 stop_counter(counter, SBI_PMU_STOP_FLAG_TAKE_SNAPSHOT);339 counter_value_post = READ_ONCE(snapshot_data->ctr_values[0]);340 __GUEST_ASSERT(counter_value_pre > counter_value_post,341 "Counter reinitialization verification failed : post [%lx] pre [%lx]\n",342 counter_value_post, counter_value_pre);343 344 /* Now set the initial value and compare */345 WRITE_ONCE(snapshot_data->ctr_values[0], counter_init_value);346 start_counter(counter, SBI_PMU_START_FLAG_INIT_SNAPSHOT, 0);347 dummy_func_loop(10000);348 stop_counter(counter, SBI_PMU_STOP_FLAG_TAKE_SNAPSHOT);349 350 counter_value_post = READ_ONCE(snapshot_data->ctr_values[0]);351 __GUEST_ASSERT(counter_value_post > counter_init_value,352 "Event update verification failed: post [%lx] pre [%lx]\n",353 counter_value_post, counter_init_value);354 355 stop_reset_counter(counter, 0);356}357 358static void test_pmu_event_overflow(unsigned long event)359{360 unsigned long counter;361 unsigned long counter_value_post;362 unsigned long counter_init_value = ULONG_MAX - 10000;363 struct riscv_pmu_snapshot_data *snapshot_data = snapshot_gva;364 365 counter = get_counter_index(0, counter_mask_available, 0, event);366 counter_in_use = counter;367 368 /* The counter value is updated w.r.t relative index of cbase passed to start/stop */369 WRITE_ONCE(snapshot_data->ctr_values[0], counter_init_value);370 start_counter(counter, SBI_PMU_START_FLAG_INIT_SNAPSHOT, 0);371 dummy_func_loop(10000);372 udelay(msecs_to_usecs(2000));373 /* irq handler should have stopped the counter */374 stop_counter(counter, SBI_PMU_STOP_FLAG_TAKE_SNAPSHOT);375 376 counter_value_post = READ_ONCE(snapshot_data->ctr_values[0]);377 /* The counter value after stopping should be less the init value due to overflow */378 __GUEST_ASSERT(counter_value_post < counter_init_value,379 "counter_value_post %lx counter_init_value %lx for counter\n",380 counter_value_post, counter_init_value);381 382 stop_reset_counter(counter, 0);383}384 385static void test_invalid_event(void)386{387 struct sbiret ret;388 unsigned long event = 0x1234; /* A random event */389 390 ret = sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_COUNTER_CFG_MATCH, 0,391 counter_mask_available, 0, event, 0, 0);392 GUEST_ASSERT_EQ(ret.error, SBI_ERR_NOT_SUPPORTED);393}394 395static void test_pmu_events(void)396{397 int num_counters = 0;398 399 /* Get the counter details */400 num_counters = get_num_counters();401 update_counter_info(num_counters);402 403 /* Sanity testing for any random invalid event */404 test_invalid_event();405 406 /* Only these two events are guaranteed to be present */407 test_pmu_event(SBI_PMU_HW_CPU_CYCLES);408 test_pmu_event(SBI_PMU_HW_INSTRUCTIONS);409 410 GUEST_DONE();411}412 413static void test_pmu_basic_sanity(void)414{415 long out_val = 0;416 bool probe;417 struct sbiret ret;418 int num_counters = 0, i;419 union sbi_pmu_ctr_info ctrinfo;420 421 probe = guest_sbi_probe_extension(SBI_EXT_PMU, &out_val);422 GUEST_ASSERT(probe && out_val == 1);423 424 num_counters = get_num_counters();425 426 for (i = 0; i < num_counters; i++) {427 ret = sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_COUNTER_GET_INFO, i,428 0, 0, 0, 0, 0);429 430 /* There can be gaps in logical counter indicies*/431 if (ret.error)432 continue;433 GUEST_ASSERT_NE(ret.value, 0);434 435 ctrinfo.value = ret.value;436 437 /**438 * Accessibility check of hardware and read capability of firmware counters.439 * The spec doesn't mandate any initial value. No need to check any value.440 */441 if (ctrinfo.type == SBI_PMU_CTR_TYPE_HW) {442 pmu_csr_read_num(ctrinfo.csr);443 GUEST_ASSERT(illegal_handler_invoked);444 } else if (ctrinfo.type == SBI_PMU_CTR_TYPE_FW) {445 read_fw_counter(i, ctrinfo);446 }447 }448 449 GUEST_DONE();450}451 452static void test_pmu_events_snaphost(void)453{454 int num_counters = 0;455 struct riscv_pmu_snapshot_data *snapshot_data = snapshot_gva;456 int i;457 458 /* Verify presence of SBI PMU and minimum requrired SBI version */459 verify_sbi_requirement_assert();460 461 snapshot_set_shmem(snapshot_gpa, 0);462 463 /* Get the counter details */464 num_counters = get_num_counters();465 update_counter_info(num_counters);466 467 /* Validate shared memory access */468 GUEST_ASSERT_EQ(READ_ONCE(snapshot_data->ctr_overflow_mask), 0);469 for (i = 0; i < num_counters; i++) {470 if (counter_mask_available & (BIT(i)))471 GUEST_ASSERT_EQ(READ_ONCE(snapshot_data->ctr_values[i]), 0);472 }473 /* Only these two events are guranteed to be present */474 test_pmu_event_snapshot(SBI_PMU_HW_CPU_CYCLES);475 test_pmu_event_snapshot(SBI_PMU_HW_INSTRUCTIONS);476 477 GUEST_DONE();478}479 480static void test_pmu_events_overflow(void)481{482 int num_counters = 0;483 484 /* Verify presence of SBI PMU and minimum requrired SBI version */485 verify_sbi_requirement_assert();486 487 snapshot_set_shmem(snapshot_gpa, 0);488 csr_set(CSR_IE, BIT(IRQ_PMU_OVF));489 local_irq_enable();490 491 /* Get the counter details */492 num_counters = get_num_counters();493 update_counter_info(num_counters);494 495 /*496 * Qemu supports overflow for cycle/instruction.497 * This test may fail on any platform that do not support overflow for these two events.498 */499 test_pmu_event_overflow(SBI_PMU_HW_CPU_CYCLES);500 GUEST_ASSERT_EQ(vcpu_shared_irq_count, 1);501 502 test_pmu_event_overflow(SBI_PMU_HW_INSTRUCTIONS);503 GUEST_ASSERT_EQ(vcpu_shared_irq_count, 2);504 505 GUEST_DONE();506}507 508static void run_vcpu(struct kvm_vcpu *vcpu)509{510 struct ucall uc;511 512 vcpu_run(vcpu);513 switch (get_ucall(vcpu, &uc)) {514 case UCALL_ABORT:515 REPORT_GUEST_ASSERT(uc);516 break;517 case UCALL_DONE:518 case UCALL_SYNC:519 break;520 default:521 TEST_FAIL("Unknown ucall %lu", uc.cmd);522 break;523 }524}525 526void test_vm_destroy(struct kvm_vm *vm)527{528 memset(ctrinfo_arr, 0, sizeof(union sbi_pmu_ctr_info) * RISCV_MAX_PMU_COUNTERS);529 counter_mask_available = 0;530 kvm_vm_free(vm);531}532 533static void test_vm_basic_test(void *guest_code)534{535 struct kvm_vm *vm;536 struct kvm_vcpu *vcpu;537 538 vm = vm_create_with_one_vcpu(&vcpu, guest_code);539 __TEST_REQUIRE(__vcpu_has_sbi_ext(vcpu, KVM_RISCV_SBI_EXT_PMU),540 "SBI PMU not available, skipping test");541 vm_init_vector_tables(vm);542 /* Illegal instruction handler is required to verify read access without configuration */543 vm_install_exception_handler(vm, EXC_INST_ILLEGAL, guest_illegal_exception_handler);544 545 vcpu_init_vector_tables(vcpu);546 run_vcpu(vcpu);547 548 test_vm_destroy(vm);549}550 551static void test_vm_events_test(void *guest_code)552{553 struct kvm_vm *vm = NULL;554 struct kvm_vcpu *vcpu = NULL;555 556 vm = vm_create_with_one_vcpu(&vcpu, guest_code);557 __TEST_REQUIRE(__vcpu_has_sbi_ext(vcpu, KVM_RISCV_SBI_EXT_PMU),558 "SBI PMU not available, skipping test");559 run_vcpu(vcpu);560 561 test_vm_destroy(vm);562}563 564static void test_vm_setup_snapshot_mem(struct kvm_vm *vm, struct kvm_vcpu *vcpu)565{566 /* PMU Snapshot requires single page only */567 vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, PMU_SNAPSHOT_GPA_BASE, 1, 1, 0);568 /* PMU_SNAPSHOT_GPA_BASE is identity mapped */569 virt_map(vm, PMU_SNAPSHOT_GPA_BASE, PMU_SNAPSHOT_GPA_BASE, 1);570 571 snapshot_gva = (void *)(PMU_SNAPSHOT_GPA_BASE);572 snapshot_gpa = addr_gva2gpa(vcpu->vm, (vm_vaddr_t)snapshot_gva);573 sync_global_to_guest(vcpu->vm, snapshot_gva);574 sync_global_to_guest(vcpu->vm, snapshot_gpa);575}576 577static void test_vm_events_snapshot_test(void *guest_code)578{579 struct kvm_vm *vm = NULL;580 struct kvm_vcpu *vcpu;581 582 vm = vm_create_with_one_vcpu(&vcpu, guest_code);583 __TEST_REQUIRE(__vcpu_has_sbi_ext(vcpu, KVM_RISCV_SBI_EXT_PMU),584 "SBI PMU not available, skipping test");585 586 test_vm_setup_snapshot_mem(vm, vcpu);587 588 run_vcpu(vcpu);589 590 test_vm_destroy(vm);591}592 593static void test_vm_events_overflow(void *guest_code)594{595 struct kvm_vm *vm = NULL;596 struct kvm_vcpu *vcpu;597 598 vm = vm_create_with_one_vcpu(&vcpu, guest_code);599 __TEST_REQUIRE(__vcpu_has_sbi_ext(vcpu, KVM_RISCV_SBI_EXT_PMU),600 "SBI PMU not available, skipping test");601 602 __TEST_REQUIRE(__vcpu_has_isa_ext(vcpu, KVM_RISCV_ISA_EXT_SSCOFPMF),603 "Sscofpmf is not available, skipping overflow test");604 605 test_vm_setup_snapshot_mem(vm, vcpu);606 vm_init_vector_tables(vm);607 vm_install_interrupt_handler(vm, guest_irq_handler);608 609 vcpu_init_vector_tables(vcpu);610 /* Initialize guest timer frequency. */611 vcpu_get_reg(vcpu, RISCV_TIMER_REG(frequency), &timer_freq);612 sync_global_to_guest(vm, timer_freq);613 614 run_vcpu(vcpu);615 616 test_vm_destroy(vm);617}618 619static void test_print_help(char *name)620{621 pr_info("Usage: %s [-h] [-d <test name>]\n", name);622 pr_info("\t-d: Test to disable. Available tests are 'basic', 'events', 'snapshot', 'overflow'\n");623 pr_info("\t-h: print this help screen\n");624}625 626static bool parse_args(int argc, char *argv[])627{628 int opt;629 630 while ((opt = getopt(argc, argv, "hd:")) != -1) {631 switch (opt) {632 case 'd':633 if (!strncmp("basic", optarg, 5))634 disabled_tests |= SBI_PMU_TEST_BASIC;635 else if (!strncmp("events", optarg, 6))636 disabled_tests |= SBI_PMU_TEST_EVENTS;637 else if (!strncmp("snapshot", optarg, 8))638 disabled_tests |= SBI_PMU_TEST_SNAPSHOT;639 else if (!strncmp("overflow", optarg, 8))640 disabled_tests |= SBI_PMU_TEST_OVERFLOW;641 else642 goto done;643 break;644 case 'h':645 default:646 goto done;647 }648 }649 650 return true;651done:652 test_print_help(argv[0]);653 return false;654}655 656int main(int argc, char *argv[])657{658 if (!parse_args(argc, argv))659 exit(KSFT_SKIP);660 661 if (!(disabled_tests & SBI_PMU_TEST_BASIC)) {662 test_vm_basic_test(test_pmu_basic_sanity);663 pr_info("SBI PMU basic test : PASS\n");664 }665 666 if (!(disabled_tests & SBI_PMU_TEST_EVENTS)) {667 test_vm_events_test(test_pmu_events);668 pr_info("SBI PMU event verification test : PASS\n");669 }670 671 if (!(disabled_tests & SBI_PMU_TEST_SNAPSHOT)) {672 test_vm_events_snapshot_test(test_pmu_events_snaphost);673 pr_info("SBI PMU event verification with snapshot test : PASS\n");674 }675 676 if (!(disabled_tests & SBI_PMU_TEST_OVERFLOW)) {677 test_vm_events_overflow(test_pmu_events_overflow);678 pr_info("SBI PMU event verification with overflow test : PASS\n");679 }680 681 return 0;682}683