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