]>
Commit | Line | Data |
---|---|---|
b2441318 | 1 | // SPDX-License-Identifier: GPL-2.0 |
28a375df | 2 | /** |
32ed42ad | 3 | * imr_selftest.c -- Intel Isolated Memory Region self-test driver |
28a375df BD |
4 | * |
5 | * Copyright(c) 2013 Intel Corporation. | |
6 | * Copyright(c) 2015 Bryan O'Donoghue <pure.logic@nexus-software.ie> | |
7 | * | |
8 | * IMR self test. The purpose of this module is to run a set of tests on the | |
9 | * IMR API to validate it's sanity. We check for overlapping, reserved | |
10 | * addresses and setup/teardown sanity. | |
11 | * | |
12 | */ | |
13 | ||
14 | #include <asm-generic/sections.h> | |
a6fcb6d4 | 15 | #include <asm/cpu_device_id.h> |
28a375df BD |
16 | #include <asm/imr.h> |
17 | #include <linux/init.h> | |
18 | #include <linux/mm.h> | |
28a375df BD |
19 | #include <linux/types.h> |
20 | ||
21 | #define SELFTEST KBUILD_MODNAME ": " | |
22 | /** | |
23 | * imr_self_test_result - Print result string for self test. | |
24 | * | |
25 | * @res: result code - true if test passed false otherwise. | |
26 | * @fmt: format string. | |
27 | * ... variadic argument list. | |
28 | */ | |
9120cf4f NI |
29 | static __printf(2, 3) |
30 | void __init imr_self_test_result(int res, const char *fmt, ...) | |
28a375df BD |
31 | { |
32 | va_list vlist; | |
33 | ||
34 | /* Print pass/fail. */ | |
35 | if (res) | |
36 | pr_info(SELFTEST "pass "); | |
37 | else | |
38 | pr_info(SELFTEST "fail "); | |
39 | ||
40 | /* Print variable string. */ | |
41 | va_start(vlist, fmt); | |
42 | vprintk(fmt, vlist); | |
43 | va_end(vlist); | |
44 | ||
45 | /* Optional warning. */ | |
46 | WARN(res == 0, "test failed"); | |
47 | } | |
48 | #undef SELFTEST | |
49 | ||
50 | /** | |
51 | * imr_self_test | |
52 | * | |
53 | * Verify IMR self_test with some simple tests to verify overlap, | |
54 | * zero sized allocations and 1 KiB sized areas. | |
55 | * | |
56 | */ | |
57 | static void __init imr_self_test(void) | |
58 | { | |
59 | phys_addr_t base = virt_to_phys(&_text); | |
60 | size_t size = virt_to_phys(&__end_rodata) - base; | |
61 | const char *fmt_over = "overlapped IMR @ (0x%08lx - 0x%08lx)\n"; | |
62 | int ret; | |
63 | ||
64 | /* Test zero zero. */ | |
c637fa52 | 65 | ret = imr_add_range(0, 0, 0, 0); |
28a375df BD |
66 | imr_self_test_result(ret < 0, "zero sized IMR\n"); |
67 | ||
68 | /* Test exact overlap. */ | |
c637fa52 | 69 | ret = imr_add_range(base, size, IMR_CPU, IMR_CPU); |
28a375df BD |
70 | imr_self_test_result(ret < 0, fmt_over, __va(base), __va(base + size)); |
71 | ||
72 | /* Test overlap with base inside of existing. */ | |
73 | base += size - IMR_ALIGN; | |
c637fa52 | 74 | ret = imr_add_range(base, size, IMR_CPU, IMR_CPU); |
28a375df BD |
75 | imr_self_test_result(ret < 0, fmt_over, __va(base), __va(base + size)); |
76 | ||
77 | /* Test overlap with end inside of existing. */ | |
78 | base -= size + IMR_ALIGN * 2; | |
c637fa52 | 79 | ret = imr_add_range(base, size, IMR_CPU, IMR_CPU); |
28a375df BD |
80 | imr_self_test_result(ret < 0, fmt_over, __va(base), __va(base + size)); |
81 | ||
82 | /* Test that a 1 KiB IMR @ zero with read/write all will bomb out. */ | |
83 | ret = imr_add_range(0, IMR_ALIGN, IMR_READ_ACCESS_ALL, | |
c637fa52 | 84 | IMR_WRITE_ACCESS_ALL); |
28a375df BD |
85 | imr_self_test_result(ret < 0, "1KiB IMR @ 0x00000000 - access-all\n"); |
86 | ||
87 | /* Test that a 1 KiB IMR @ zero with CPU only will work. */ | |
c637fa52 | 88 | ret = imr_add_range(0, IMR_ALIGN, IMR_CPU, IMR_CPU); |
28a375df BD |
89 | imr_self_test_result(ret >= 0, "1KiB IMR @ 0x00000000 - cpu-access\n"); |
90 | if (ret >= 0) { | |
91 | ret = imr_remove_range(0, IMR_ALIGN); | |
92 | imr_self_test_result(ret == 0, "teardown - cpu-access\n"); | |
93 | } | |
94 | ||
95 | /* Test 2 KiB works. */ | |
96 | size = IMR_ALIGN * 2; | |
c637fa52 | 97 | ret = imr_add_range(0, size, IMR_READ_ACCESS_ALL, IMR_WRITE_ACCESS_ALL); |
28a375df BD |
98 | imr_self_test_result(ret >= 0, "2KiB IMR @ 0x00000000\n"); |
99 | if (ret >= 0) { | |
100 | ret = imr_remove_range(0, size); | |
101 | imr_self_test_result(ret == 0, "teardown 2KiB\n"); | |
102 | } | |
103 | } | |
104 | ||
a6fcb6d4 BD |
105 | static const struct x86_cpu_id imr_ids[] __initconst = { |
106 | { X86_VENDOR_INTEL, 5, 9 }, /* Intel Quark SoC X1000. */ | |
107 | {} | |
108 | }; | |
a6fcb6d4 | 109 | |
28a375df BD |
110 | /** |
111 | * imr_self_test_init - entry point for IMR driver. | |
112 | * | |
113 | * return: -ENODEV for no IMR support 0 if good to go. | |
114 | */ | |
115 | static int __init imr_self_test_init(void) | |
116 | { | |
a6fcb6d4 BD |
117 | if (x86_match_cpu(imr_ids)) |
118 | imr_self_test(); | |
28a375df BD |
119 | return 0; |
120 | } | |
121 | ||
122 | /** | |
123 | * imr_self_test_exit - exit point for IMR code. | |
124 | * | |
125 | * return: | |
126 | */ | |
32ed42ad | 127 | device_initcall(imr_self_test_init); |