cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

executor.c (7274B)


      1// SPDX-License-Identifier: GPL-2.0
      2
      3#include <linux/reboot.h>
      4#include <kunit/test.h>
      5#include <linux/glob.h>
      6#include <linux/moduleparam.h>
      7
      8/*
      9 * These symbols point to the .kunit_test_suites section and are defined in
     10 * include/asm-generic/vmlinux.lds.h, and consequently must be extern.
     11 */
     12extern struct kunit_suite * const * const __kunit_suites_start[];
     13extern struct kunit_suite * const * const __kunit_suites_end[];
     14
     15#if IS_BUILTIN(CONFIG_KUNIT)
     16
     17static char *filter_glob_param;
     18static char *action_param;
     19
     20module_param_named(filter_glob, filter_glob_param, charp, 0);
     21MODULE_PARM_DESC(filter_glob,
     22		"Filter which KUnit test suites/tests run at boot-time, e.g. list* or list*.*del_test");
     23module_param_named(action, action_param, charp, 0);
     24MODULE_PARM_DESC(action,
     25		 "Changes KUnit executor behavior, valid values are:\n"
     26		 "<none>: run the tests like normal\n"
     27		 "'list' to list test names instead of running them.\n");
     28
     29/* glob_match() needs NULL terminated strings, so we need a copy of filter_glob_param. */
     30struct kunit_test_filter {
     31	char *suite_glob;
     32	char *test_glob;
     33};
     34
     35/* Split "suite_glob.test_glob" into two. Assumes filter_glob is not empty. */
     36static void kunit_parse_filter_glob(struct kunit_test_filter *parsed,
     37				    const char *filter_glob)
     38{
     39	const int len = strlen(filter_glob);
     40	const char *period = strchr(filter_glob, '.');
     41
     42	if (!period) {
     43		parsed->suite_glob = kzalloc(len + 1, GFP_KERNEL);
     44		parsed->test_glob = NULL;
     45		strcpy(parsed->suite_glob, filter_glob);
     46		return;
     47	}
     48
     49	parsed->suite_glob = kzalloc(period - filter_glob + 1, GFP_KERNEL);
     50	parsed->test_glob = kzalloc(len - (period - filter_glob) + 1, GFP_KERNEL);
     51
     52	strncpy(parsed->suite_glob, filter_glob, period - filter_glob);
     53	strncpy(parsed->test_glob, period + 1, len - (period - filter_glob));
     54}
     55
     56/* Create a copy of suite with only tests that match test_glob. */
     57static struct kunit_suite *
     58kunit_filter_tests(struct kunit_suite *const suite, const char *test_glob)
     59{
     60	int n = 0;
     61	struct kunit_case *filtered, *test_case;
     62	struct kunit_suite *copy;
     63
     64	kunit_suite_for_each_test_case(suite, test_case) {
     65		if (!test_glob || glob_match(test_glob, test_case->name))
     66			++n;
     67	}
     68
     69	if (n == 0)
     70		return NULL;
     71
     72	/* Use memcpy to workaround copy->name being const. */
     73	copy = kmalloc(sizeof(*copy), GFP_KERNEL);
     74	if (!copy)
     75		return ERR_PTR(-ENOMEM);
     76	memcpy(copy, suite, sizeof(*copy));
     77
     78	filtered = kcalloc(n + 1, sizeof(*filtered), GFP_KERNEL);
     79	if (!filtered)
     80		return ERR_PTR(-ENOMEM);
     81
     82	n = 0;
     83	kunit_suite_for_each_test_case(suite, test_case) {
     84		if (!test_glob || glob_match(test_glob, test_case->name))
     85			filtered[n++] = *test_case;
     86	}
     87
     88	copy->test_cases = filtered;
     89	return copy;
     90}
     91
     92static char *kunit_shutdown;
     93core_param(kunit_shutdown, kunit_shutdown, charp, 0644);
     94
     95static struct kunit_suite * const *
     96kunit_filter_subsuite(struct kunit_suite * const * const subsuite,
     97		      struct kunit_test_filter *filter)
     98{
     99	int i, n = 0;
    100	struct kunit_suite **filtered, *filtered_suite;
    101
    102	n = 0;
    103	for (i = 0; subsuite[i]; ++i) {
    104		if (glob_match(filter->suite_glob, subsuite[i]->name))
    105			++n;
    106	}
    107
    108	if (n == 0)
    109		return NULL;
    110
    111	filtered = kmalloc_array(n + 1, sizeof(*filtered), GFP_KERNEL);
    112	if (!filtered)
    113		return ERR_PTR(-ENOMEM);
    114
    115	n = 0;
    116	for (i = 0; subsuite[i] != NULL; ++i) {
    117		if (!glob_match(filter->suite_glob, subsuite[i]->name))
    118			continue;
    119		filtered_suite = kunit_filter_tests(subsuite[i], filter->test_glob);
    120		if (IS_ERR(filtered_suite))
    121			return ERR_CAST(filtered_suite);
    122		else if (filtered_suite)
    123			filtered[n++] = filtered_suite;
    124	}
    125	filtered[n] = NULL;
    126
    127	return filtered;
    128}
    129
    130struct suite_set {
    131	struct kunit_suite * const * const *start;
    132	struct kunit_suite * const * const *end;
    133};
    134
    135static void kunit_free_subsuite(struct kunit_suite * const *subsuite)
    136{
    137	unsigned int i;
    138
    139	for (i = 0; subsuite[i]; i++)
    140		kfree(subsuite[i]);
    141
    142	kfree(subsuite);
    143}
    144
    145static void kunit_free_suite_set(struct suite_set suite_set)
    146{
    147	struct kunit_suite * const * const *suites;
    148
    149	for (suites = suite_set.start; suites < suite_set.end; suites++)
    150		kunit_free_subsuite(*suites);
    151	kfree(suite_set.start);
    152}
    153
    154static struct suite_set kunit_filter_suites(const struct suite_set *suite_set,
    155					    const char *filter_glob,
    156					    int *err)
    157{
    158	int i;
    159	struct kunit_suite * const **copy, * const *filtered_subsuite;
    160	struct suite_set filtered;
    161	struct kunit_test_filter filter;
    162
    163	const size_t max = suite_set->end - suite_set->start;
    164
    165	copy = kmalloc_array(max, sizeof(*filtered.start), GFP_KERNEL);
    166	filtered.start = copy;
    167	if (!copy) { /* won't be able to run anything, return an empty set */
    168		filtered.end = copy;
    169		return filtered;
    170	}
    171
    172	kunit_parse_filter_glob(&filter, filter_glob);
    173
    174	for (i = 0; i < max; ++i) {
    175		filtered_subsuite = kunit_filter_subsuite(suite_set->start[i], &filter);
    176		if (IS_ERR(filtered_subsuite)) {
    177			*err = PTR_ERR(filtered_subsuite);
    178			return filtered;
    179		}
    180		if (filtered_subsuite)
    181			*copy++ = filtered_subsuite;
    182	}
    183	filtered.end = copy;
    184
    185	kfree(filter.suite_glob);
    186	kfree(filter.test_glob);
    187	return filtered;
    188}
    189
    190static void kunit_handle_shutdown(void)
    191{
    192	if (!kunit_shutdown)
    193		return;
    194
    195	if (!strcmp(kunit_shutdown, "poweroff"))
    196		kernel_power_off();
    197	else if (!strcmp(kunit_shutdown, "halt"))
    198		kernel_halt();
    199	else if (!strcmp(kunit_shutdown, "reboot"))
    200		kernel_restart(NULL);
    201
    202}
    203
    204static void kunit_print_tap_header(struct suite_set *suite_set)
    205{
    206	struct kunit_suite * const * const *suites, * const *subsuite;
    207	int num_of_suites = 0;
    208
    209	for (suites = suite_set->start; suites < suite_set->end; suites++)
    210		for (subsuite = *suites; *subsuite != NULL; subsuite++)
    211			num_of_suites++;
    212
    213	pr_info("TAP version 14\n");
    214	pr_info("1..%d\n", num_of_suites);
    215}
    216
    217static void kunit_exec_run_tests(struct suite_set *suite_set)
    218{
    219	struct kunit_suite * const * const *suites;
    220
    221	kunit_print_tap_header(suite_set);
    222
    223	for (suites = suite_set->start; suites < suite_set->end; suites++)
    224		__kunit_test_suites_init(*suites);
    225}
    226
    227static void kunit_exec_list_tests(struct suite_set *suite_set)
    228{
    229	unsigned int i;
    230	struct kunit_suite * const * const *suites;
    231	struct kunit_case *test_case;
    232
    233	/* Hack: print a tap header so kunit.py can find the start of KUnit output. */
    234	pr_info("TAP version 14\n");
    235
    236	for (suites = suite_set->start; suites < suite_set->end; suites++)
    237		for (i = 0; (*suites)[i] != NULL; i++) {
    238			kunit_suite_for_each_test_case((*suites)[i], test_case) {
    239				pr_info("%s.%s\n", (*suites)[i]->name, test_case->name);
    240			}
    241		}
    242}
    243
    244int kunit_run_all_tests(void)
    245{
    246	struct suite_set suite_set = {
    247		.start = __kunit_suites_start,
    248		.end = __kunit_suites_end,
    249	};
    250	int err = 0;
    251
    252	if (filter_glob_param) {
    253		suite_set = kunit_filter_suites(&suite_set, filter_glob_param, &err);
    254		if (err) {
    255			pr_err("kunit executor: error filtering suites: %d\n", err);
    256			goto out;
    257		}
    258	}
    259
    260	if (!action_param)
    261		kunit_exec_run_tests(&suite_set);
    262	else if (strcmp(action_param, "list") == 0)
    263		kunit_exec_list_tests(&suite_set);
    264	else
    265		pr_err("kunit executor: unknown action '%s'\n", action_param);
    266
    267	if (filter_glob_param) { /* a copy was made of each array */
    268		kunit_free_suite_set(suite_set);
    269	}
    270
    271
    272out:
    273	kunit_handle_shutdown();
    274	return err;
    275}
    276
    277#if IS_BUILTIN(CONFIG_KUNIT_TEST)
    278#include "executor_test.c"
    279#endif
    280
    281#endif /* IS_BUILTIN(CONFIG_KUNIT) */