18da2a883SGabriele Monaco // SPDX-License-Identifier: GPL-2.0 28da2a883SGabriele Monaco /* 38da2a883SGabriele Monaco * Copyright (C) 2026-2029 Red Hat, Inc. Gabriele Monaco <gmonaco@redhat.com> 48da2a883SGabriele Monaco * 58da2a883SGabriele Monaco * RV monitor kunit tests: 68da2a883SGabriele Monaco * Tests the RV monitors by triggering fake events to verify monitor 78da2a883SGabriele Monaco * behavior and reactions. Tests start from the first defined event and 88da2a883SGabriele Monaco * trigger events in order to verify error detection. 98da2a883SGabriele Monaco */ 108da2a883SGabriele Monaco #include <rv/kunit.h> 118da2a883SGabriele Monaco #include <kunit/test-bug.h> 128da2a883SGabriele Monaco #include <linux/kernel.h> 138da2a883SGabriele Monaco #include <linux/rv.h> 148da2a883SGabriele Monaco #include "rv.h" 158da2a883SGabriele Monaco 168da2a883SGabriele Monaco /* 178da2a883SGabriele Monaco * An easy way to pass the context is to use kunit_get_current_test()->priv, 188da2a883SGabriele Monaco * but this doesn't always work (e.g. a reactor running from another context 198da2a883SGabriele Monaco * like softirq). Store the current value here whenever a test is running. 208da2a883SGabriele Monaco */ 218da2a883SGabriele Monaco static struct rv_kunit_ctx *active_ctx; 228da2a883SGabriele Monaco 238da2a883SGabriele Monaco __printf(1, 0) 248da2a883SGabriele Monaco static void rv_kunit_mock_react(const char *msg, va_list args) 258da2a883SGabriele Monaco { 268da2a883SGabriele Monaco if (active_ctx) 278da2a883SGabriele Monaco ++active_ctx->reactions; 288da2a883SGabriele Monaco } 298da2a883SGabriele Monaco 308da2a883SGabriele Monaco /* 318da2a883SGabriele Monaco * teardown_test - Disable the monitor for a kunit test 328da2a883SGabriele Monaco * 338da2a883SGabriele Monaco * Since per-task monitors are special, make sure we reset all the ones we 348da2a883SGabriele Monaco * started manually here, if required. 358da2a883SGabriele Monaco */ 368da2a883SGabriele Monaco void teardown_test(void *arg) 378da2a883SGabriele Monaco { 388da2a883SGabriele Monaco const struct rv_kunit_mon *mon = arg; 398da2a883SGabriele Monaco struct kunit *test = kunit_get_current_test(); 408da2a883SGabriele Monaco 418da2a883SGabriele Monaco if (test) { 428da2a883SGabriele Monaco struct rv_kunit_ctx *ctx = test->priv; 438da2a883SGabriele Monaco 448da2a883SGabriele Monaco RV_KUNIT_EXPECT_NO_REACTION(test, ctx); 458da2a883SGabriele Monaco 468da2a883SGabriele Monaco if (mon->is_per_task && mon->task_reset) { 478da2a883SGabriele Monaco for (int i = 0; i < ctx->mock_task_count; i++) 488da2a883SGabriele Monaco mon->task_reset(ctx->mock_tasks[i]); 498da2a883SGabriele Monaco synchronize_rcu(); 508da2a883SGabriele Monaco } 518da2a883SGabriele Monaco } 528da2a883SGabriele Monaco 538da2a883SGabriele Monaco mon->rv_this->enabled = 0; 548da2a883SGabriele Monaco 558da2a883SGabriele Monaco if (mon->rv_this->reactor) 568da2a883SGabriele Monaco mon->rv_this->react = mon->rv_this->reactor->react; 578da2a883SGabriele Monaco else 588da2a883SGabriele Monaco mon->rv_this->react = NULL; 598da2a883SGabriele Monaco active_ctx = NULL; 60cf8f191cSGabriele Monaco rv_mock_current(NULL); 618da2a883SGabriele Monaco 628da2a883SGabriele Monaco if (mon->is_per_task) 638da2a883SGabriele Monaco *mon->task_slot = RV_PER_TASK_MONITOR_INIT; 648da2a883SGabriele Monaco else 658da2a883SGabriele Monaco mon->monitor_destroy(); 668da2a883SGabriele Monaco } 678da2a883SGabriele Monaco 688da2a883SGabriele Monaco /* 698da2a883SGabriele Monaco * prepare_test - Enable the monitor for a kunit test 708da2a883SGabriele Monaco * 718da2a883SGabriele Monaco * Do the bare minimum to set up the monitor, per-task monitors are special as 728da2a883SGabriele Monaco * "real" initialisation/destruction iterates over real tasks, and may register 738da2a883SGabriele Monaco * handlers. All we need is to select the right slot in the task_struct. 748da2a883SGabriele Monaco */ 758da2a883SGabriele Monaco void prepare_test(struct kunit *test, const struct rv_kunit_mon *mon) 768da2a883SGabriele Monaco { 778da2a883SGabriele Monaco KUNIT_ASSERT_FALSE(test, mon->rv_this->enabled); 788da2a883SGabriele Monaco 798da2a883SGabriele Monaco active_ctx = test->priv; 808da2a883SGabriele Monaco mon->rv_this->react = rv_kunit_mock_react; 818da2a883SGabriele Monaco 828da2a883SGabriele Monaco if (mon->is_per_task) 838da2a883SGabriele Monaco *mon->task_slot = 0; 848da2a883SGabriele Monaco else 858da2a883SGabriele Monaco KUNIT_ASSERT_EQ(test, mon->monitor_init(), 0); 868da2a883SGabriele Monaco 878da2a883SGabriele Monaco mon->rv_this->enabled = 1; 888da2a883SGabriele Monaco 898da2a883SGabriele Monaco KUNIT_ASSERT_EQ(test, 0, 908da2a883SGabriele Monaco kunit_add_action_or_reset(test, teardown_test, (void *)mon)); 918da2a883SGabriele Monaco } 928da2a883SGabriele Monaco 938da2a883SGabriele Monaco struct task_struct *rv_kunit_alloc_mock_task(struct kunit *test) 948da2a883SGabriele Monaco { 958da2a883SGabriele Monaco struct rv_kunit_ctx *ctx = test->priv; 968da2a883SGabriele Monaco struct task_struct *tsk; 978da2a883SGabriele Monaco 988da2a883SGabriele Monaco KUNIT_ASSERT_LT(test, ctx->mock_task_count, RV_KUNIT_MAX_MOCK_TASKS); 998da2a883SGabriele Monaco 1008da2a883SGabriele Monaco tsk = kunit_kzalloc(test, sizeof(struct task_struct), GFP_KERNEL); 1018da2a883SGabriele Monaco KUNIT_ASSERT_NOT_NULL(test, tsk); 1028da2a883SGabriele Monaco 1038da2a883SGabriele Monaco if (!IS_ENABLED(CONFIG_THREAD_INFO_IN_TASK)) { 1048da2a883SGabriele Monaco tsk->stack = kunit_kzalloc(test, sizeof(struct thread_info), GFP_KERNEL); 1058da2a883SGabriele Monaco KUNIT_ASSERT_NOT_NULL(test, tsk->stack); 1068da2a883SGabriele Monaco } 1078da2a883SGabriele Monaco 1088da2a883SGabriele Monaco ctx->mock_tasks[ctx->mock_task_count++] = tsk; 1098da2a883SGabriele Monaco return tsk; 1108da2a883SGabriele Monaco } 1118da2a883SGabriele Monaco 1128da2a883SGabriele Monaco static int rv_mon_test_init(struct kunit *test) 1138da2a883SGabriele Monaco { 1148da2a883SGabriele Monaco struct rv_kunit_ctx *ctx; 1158da2a883SGabriele Monaco 1168da2a883SGabriele Monaco ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); 1178da2a883SGabriele Monaco KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx); 1188da2a883SGabriele Monaco 1198da2a883SGabriele Monaco test->priv = ctx; 1208da2a883SGabriele Monaco 1218da2a883SGabriele Monaco return 0; 1228da2a883SGabriele Monaco } 1238da2a883SGabriele Monaco 1248da2a883SGabriele Monaco static void __maybe_unused rv_test_stub(struct kunit *test) 1258da2a883SGabriele Monaco { 1268da2a883SGabriele Monaco kunit_skip(test, "Monitor not enabled\n"); 1278da2a883SGabriele Monaco } 1288da2a883SGabriele Monaco 1298da2a883SGabriele Monaco /* 1308da2a883SGabriele Monaco * rv_test_dummy - test reactions work as expected 1318da2a883SGabriele Monaco */ 1328da2a883SGabriele Monaco static void rv_test_dummy(struct kunit *test) 1338da2a883SGabriele Monaco { 1348da2a883SGabriele Monaco struct rv_kunit_ctx *ctx = test->priv; 1358da2a883SGabriele Monaco static struct rv_monitor dummy_monitor = { 1368da2a883SGabriele Monaco .name = "dummy", 1378da2a883SGabriele Monaco .react = rv_kunit_mock_react, 1388da2a883SGabriele Monaco }; 1398da2a883SGabriele Monaco 1408da2a883SGabriele Monaco active_ctx = ctx; 1418da2a883SGabriele Monaco 1428da2a883SGabriele Monaco RV_KUNIT_EXPECT_REACTION_HERE(test, ctx) 1438da2a883SGabriele Monaco rv_react(&dummy_monitor, "dummy"); 1448da2a883SGabriele Monaco RV_KUNIT_EXPECT_NO_REACTION(test, ctx); 1458da2a883SGabriele Monaco 1468da2a883SGabriele Monaco active_ctx = NULL; 1478da2a883SGabriele Monaco } 1488da2a883SGabriele Monaco 1498da2a883SGabriele Monaco #include "monitors/sco/sco_kunit.c" 1508da2a883SGabriele Monaco #include "monitors/sssw/sssw_kunit.c" 1518da2a883SGabriele Monaco #include "monitors/sts/sts_kunit.c" 1528da2a883SGabriele Monaco #include "monitors/opid/opid_kunit.c" 1538da2a883SGabriele Monaco #include "monitors/nomiss/nomiss_kunit.c" 154*51f3fe70SGabriele Monaco #include "monitors/pagefault/pagefault_kunit.c" 155*51f3fe70SGabriele Monaco #include "monitors/sleep/sleep_kunit.c" 1568da2a883SGabriele Monaco 1578da2a883SGabriele Monaco static struct kunit_case rv_mon_test_cases[] = { 1588da2a883SGabriele Monaco KUNIT_CASE(rv_test_dummy), 1598da2a883SGabriele Monaco KUNIT_CASE(rv_test_sco), 1608da2a883SGabriele Monaco KUNIT_CASE(rv_test_sssw), 1618da2a883SGabriele Monaco KUNIT_CASE(rv_test_sts), 1628da2a883SGabriele Monaco KUNIT_CASE(rv_test_opid), 1638da2a883SGabriele Monaco KUNIT_CASE(rv_test_nomiss), 164*51f3fe70SGabriele Monaco KUNIT_CASE(rv_test_pagefault), 165*51f3fe70SGabriele Monaco KUNIT_CASE(rv_test_sleep), 1668da2a883SGabriele Monaco {} 1678da2a883SGabriele Monaco }; 1688da2a883SGabriele Monaco 1698da2a883SGabriele Monaco static struct kunit_suite rv_mon_test_suite = { 1708da2a883SGabriele Monaco .name = "rv_mon", 1718da2a883SGabriele Monaco .suite_init = rv_set_testing, 1728da2a883SGabriele Monaco .suite_exit = rv_clear_testing, 1738da2a883SGabriele Monaco .init = rv_mon_test_init, 1748da2a883SGabriele Monaco .test_cases = rv_mon_test_cases, 1758da2a883SGabriele Monaco }; 1768da2a883SGabriele Monaco 1778da2a883SGabriele Monaco kunit_test_suites(&rv_mon_test_suite); 1788da2a883SGabriele Monaco 1798da2a883SGabriele Monaco MODULE_AUTHOR("Gabriele Monaco <gmonaco@redhat.com>"); 1808da2a883SGabriele Monaco MODULE_DESCRIPTION("RV monitor kunit tests: test monitors by triggering reactions"); 1818da2a883SGabriele Monaco MODULE_LICENSE("GPL"); 1828da2a883SGabriele Monaco MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING"); 183