diff options
| -rw-r--r-- | arch/x86/Kconfig.debug | 4 | ||||
| -rw-r--r-- | arch/x86/mm/pageattr-test.c | 65 |
2 files changed, 53 insertions, 16 deletions
diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug index 2e1e3af28c3a..fa555148823d 100644 --- a/arch/x86/Kconfig.debug +++ b/arch/x86/Kconfig.debug | |||
| @@ -220,9 +220,9 @@ config DEBUG_BOOT_PARAMS | |||
| 220 | This option will cause struct boot_params to be exported via debugfs. | 220 | This option will cause struct boot_params to be exported via debugfs. |
| 221 | 221 | ||
| 222 | config CPA_DEBUG | 222 | config CPA_DEBUG |
| 223 | bool "CPA self test code" | 223 | bool "CPA self-test code" |
| 224 | depends on DEBUG_KERNEL | 224 | depends on DEBUG_KERNEL |
| 225 | help | 225 | help |
| 226 | Do change_page_attr self tests at boot. | 226 | Do change_page_attr() self-tests every 30 seconds. |
| 227 | 227 | ||
| 228 | endmenu | 228 | endmenu |
diff --git a/arch/x86/mm/pageattr-test.c b/arch/x86/mm/pageattr-test.c index 398f3a578dde..ed8201600354 100644 --- a/arch/x86/mm/pageattr-test.c +++ b/arch/x86/mm/pageattr-test.c | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | * and compares page tables forwards and afterwards. | 5 | * and compares page tables forwards and afterwards. |
| 6 | */ | 6 | */ |
| 7 | #include <linux/bootmem.h> | 7 | #include <linux/bootmem.h> |
| 8 | #include <linux/kthread.h> | ||
| 8 | #include <linux/random.h> | 9 | #include <linux/random.h> |
| 9 | #include <linux/kernel.h> | 10 | #include <linux/kernel.h> |
| 10 | #include <linux/init.h> | 11 | #include <linux/init.h> |
| @@ -14,8 +15,13 @@ | |||
| 14 | #include <asm/pgtable.h> | 15 | #include <asm/pgtable.h> |
| 15 | #include <asm/kdebug.h> | 16 | #include <asm/kdebug.h> |
| 16 | 17 | ||
| 18 | /* | ||
| 19 | * Only print the results of the first pass: | ||
| 20 | */ | ||
| 21 | static __read_mostly int print = 1; | ||
| 22 | |||
| 17 | enum { | 23 | enum { |
| 18 | NTEST = 4000, | 24 | NTEST = 400, |
| 19 | #ifdef CONFIG_X86_64 | 25 | #ifdef CONFIG_X86_64 |
| 20 | LPS = (1 << PMD_SHIFT), | 26 | LPS = (1 << PMD_SHIFT), |
| 21 | #elif defined(CONFIG_X86_PAE) | 27 | #elif defined(CONFIG_X86_PAE) |
| @@ -31,7 +37,7 @@ struct split_state { | |||
| 31 | long min_exec, max_exec; | 37 | long min_exec, max_exec; |
| 32 | }; | 38 | }; |
| 33 | 39 | ||
| 34 | static __init int print_split(struct split_state *s) | 40 | static int print_split(struct split_state *s) |
| 35 | { | 41 | { |
| 36 | long i, expected, missed = 0; | 42 | long i, expected, missed = 0; |
| 37 | int printed = 0; | 43 | int printed = 0; |
| @@ -82,10 +88,13 @@ static __init int print_split(struct split_state *s) | |||
| 82 | s->max_exec = addr; | 88 | s->max_exec = addr; |
| 83 | } | 89 | } |
| 84 | } | 90 | } |
| 85 | printk(KERN_INFO | 91 | if (print) { |
| 86 | "CPA mapping 4k %lu large %lu gb %lu x %lu[%lx-%lx] miss %lu\n", | 92 | printk(KERN_INFO |
| 87 | s->spg, s->lpg, s->gpg, s->exec, | 93 | " 4k %lu large %lu gb %lu x %lu[%lx-%lx] miss %lu\n", |
| 88 | s->min_exec != ~0UL ? s->min_exec : 0, s->max_exec, missed); | 94 | s->spg, s->lpg, s->gpg, s->exec, |
| 95 | s->min_exec != ~0UL ? s->min_exec : 0, | ||
| 96 | s->max_exec, missed); | ||
| 97 | } | ||
| 89 | 98 | ||
| 90 | expected = (s->gpg*GPS + s->lpg*LPS)/PAGE_SIZE + s->spg + missed; | 99 | expected = (s->gpg*GPS + s->lpg*LPS)/PAGE_SIZE + s->spg + missed; |
| 91 | if (expected != i) { | 100 | if (expected != i) { |
| @@ -96,11 +105,11 @@ static __init int print_split(struct split_state *s) | |||
| 96 | return err; | 105 | return err; |
| 97 | } | 106 | } |
| 98 | 107 | ||
| 99 | static unsigned long __initdata addr[NTEST]; | 108 | static unsigned long addr[NTEST]; |
| 100 | static unsigned int __initdata len[NTEST]; | 109 | static unsigned int len[NTEST]; |
| 101 | 110 | ||
| 102 | /* Change the global bit on random pages in the direct mapping */ | 111 | /* Change the global bit on random pages in the direct mapping */ |
| 103 | static __init int exercise_pageattr(void) | 112 | static int pageattr_test(void) |
| 104 | { | 113 | { |
| 105 | struct split_state sa, sb, sc; | 114 | struct split_state sa, sb, sc; |
| 106 | unsigned long *bm; | 115 | unsigned long *bm; |
| @@ -110,7 +119,8 @@ static __init int exercise_pageattr(void) | |||
| 110 | int i, k; | 119 | int i, k; |
| 111 | int err; | 120 | int err; |
| 112 | 121 | ||
| 113 | printk(KERN_INFO "CPA exercising pageattr\n"); | 122 | if (print) |
| 123 | printk(KERN_INFO "CPA self-test:\n"); | ||
| 114 | 124 | ||
| 115 | bm = vmalloc((max_pfn_mapped + 7) / 8); | 125 | bm = vmalloc((max_pfn_mapped + 7) / 8); |
| 116 | if (!bm) { | 126 | if (!bm) { |
| @@ -186,7 +196,6 @@ static __init int exercise_pageattr(void) | |||
| 186 | 196 | ||
| 187 | failed += print_split(&sb); | 197 | failed += print_split(&sb); |
| 188 | 198 | ||
| 189 | printk(KERN_INFO "CPA reverting everything\n"); | ||
| 190 | for (i = 0; i < NTEST; i++) { | 199 | for (i = 0; i < NTEST; i++) { |
| 191 | if (!addr[i]) | 200 | if (!addr[i]) |
| 192 | continue; | 201 | continue; |
| @@ -214,12 +223,40 @@ static __init int exercise_pageattr(void) | |||
| 214 | failed += print_split(&sc); | 223 | failed += print_split(&sc); |
| 215 | 224 | ||
| 216 | if (failed) { | 225 | if (failed) { |
| 217 | printk(KERN_ERR "CPA selftests NOT PASSED. Please report.\n"); | 226 | printk(KERN_ERR "NOT PASSED. Please report.\n"); |
| 218 | WARN_ON(1); | 227 | WARN_ON(1); |
| 228 | return -EINVAL; | ||
| 219 | } else { | 229 | } else { |
| 220 | printk(KERN_INFO "CPA selftests PASSED\n"); | 230 | if (print) |
| 231 | printk(KERN_INFO "ok.\n"); | ||
| 221 | } | 232 | } |
| 222 | 233 | ||
| 223 | return 0; | 234 | return 0; |
| 224 | } | 235 | } |
| 225 | module_init(exercise_pageattr); | 236 | |
| 237 | static int do_pageattr_test(void *__unused) | ||
| 238 | { | ||
| 239 | while (!kthread_should_stop()) { | ||
| 240 | schedule_timeout_interruptible(HZ*30); | ||
| 241 | if (pageattr_test() < 0) | ||
| 242 | break; | ||
| 243 | if (print) | ||
| 244 | print--; | ||
| 245 | } | ||
| 246 | return 0; | ||
| 247 | } | ||
| 248 | |||
| 249 | static int start_pageattr_test(void) | ||
| 250 | { | ||
| 251 | struct task_struct *p; | ||
| 252 | |||
| 253 | p = kthread_create(do_pageattr_test, NULL, "pageattr-test"); | ||
| 254 | if (!IS_ERR(p)) | ||
| 255 | wake_up_process(p); | ||
| 256 | else | ||
| 257 | WARN_ON(1); | ||
| 258 | |||
| 259 | return 0; | ||
| 260 | } | ||
| 261 | |||
| 262 | module_init(start_pageattr_test); | ||
