Commit 971a52d6 authored by Ingo Molnar's avatar Ingo Molnar

x86: delay CPA self-test and repeat it

delay the CPA self-test so that any impact (corruption) of
user-space pagetables can be triggered. Repeat the test
every 30 seconds.

this would have prevented the bug fixed by 8cb2a7c1,
at its source.
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
parent f1fbabb3
...@@ -220,9 +220,9 @@ config DEBUG_BOOT_PARAMS ...@@ -220,9 +220,9 @@ config DEBUG_BOOT_PARAMS
This option will cause struct boot_params to be exported via debugfs. This option will cause struct boot_params to be exported via debugfs.
config CPA_DEBUG config CPA_DEBUG
bool "CPA self test code" bool "CPA self-test code"
depends on DEBUG_KERNEL depends on DEBUG_KERNEL
help help
Do change_page_attr self tests at boot. Do change_page_attr() self-tests every 30 seconds.
endmenu endmenu
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
* and compares page tables forwards and afterwards. * and compares page tables forwards and afterwards.
*/ */
#include <linux/bootmem.h> #include <linux/bootmem.h>
#include <linux/kthread.h>
#include <linux/random.h> #include <linux/random.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/init.h> #include <linux/init.h>
...@@ -14,8 +15,13 @@ ...@@ -14,8 +15,13 @@
#include <asm/pgtable.h> #include <asm/pgtable.h>
#include <asm/kdebug.h> #include <asm/kdebug.h>
/*
* Only print the results of the first pass:
*/
static __read_mostly int print = 1;
enum { enum {
NTEST = 4000, NTEST = 400,
#ifdef CONFIG_X86_64 #ifdef CONFIG_X86_64
LPS = (1 << PMD_SHIFT), LPS = (1 << PMD_SHIFT),
#elif defined(CONFIG_X86_PAE) #elif defined(CONFIG_X86_PAE)
...@@ -31,7 +37,7 @@ struct split_state { ...@@ -31,7 +37,7 @@ struct split_state {
long min_exec, max_exec; long min_exec, max_exec;
}; };
static __init int print_split(struct split_state *s) static int print_split(struct split_state *s)
{ {
long i, expected, missed = 0; long i, expected, missed = 0;
int printed = 0; int printed = 0;
...@@ -82,10 +88,13 @@ static __init int print_split(struct split_state *s) ...@@ -82,10 +88,13 @@ static __init int print_split(struct split_state *s)
s->max_exec = addr; s->max_exec = addr;
} }
} }
printk(KERN_INFO if (print) {
"CPA mapping 4k %lu large %lu gb %lu x %lu[%lx-%lx] miss %lu\n", printk(KERN_INFO
s->spg, s->lpg, s->gpg, s->exec, " 4k %lu large %lu gb %lu x %lu[%lx-%lx] miss %lu\n",
s->min_exec != ~0UL ? s->min_exec : 0, s->max_exec, missed); s->spg, s->lpg, s->gpg, s->exec,
s->min_exec != ~0UL ? s->min_exec : 0,
s->max_exec, missed);
}
expected = (s->gpg*GPS + s->lpg*LPS)/PAGE_SIZE + s->spg + missed; expected = (s->gpg*GPS + s->lpg*LPS)/PAGE_SIZE + s->spg + missed;
if (expected != i) { if (expected != i) {
...@@ -96,11 +105,11 @@ static __init int print_split(struct split_state *s) ...@@ -96,11 +105,11 @@ static __init int print_split(struct split_state *s)
return err; return err;
} }
static unsigned long __initdata addr[NTEST]; static unsigned long addr[NTEST];
static unsigned int __initdata len[NTEST]; static unsigned int len[NTEST];
/* Change the global bit on random pages in the direct mapping */ /* Change the global bit on random pages in the direct mapping */
static __init int exercise_pageattr(void) static int pageattr_test(void)
{ {
struct split_state sa, sb, sc; struct split_state sa, sb, sc;
unsigned long *bm; unsigned long *bm;
...@@ -110,7 +119,8 @@ static __init int exercise_pageattr(void) ...@@ -110,7 +119,8 @@ static __init int exercise_pageattr(void)
int i, k; int i, k;
int err; int err;
printk(KERN_INFO "CPA exercising pageattr\n"); if (print)
printk(KERN_INFO "CPA self-test:\n");
bm = vmalloc((max_pfn_mapped + 7) / 8); bm = vmalloc((max_pfn_mapped + 7) / 8);
if (!bm) { if (!bm) {
...@@ -186,7 +196,6 @@ static __init int exercise_pageattr(void) ...@@ -186,7 +196,6 @@ static __init int exercise_pageattr(void)
failed += print_split(&sb); failed += print_split(&sb);
printk(KERN_INFO "CPA reverting everything\n");
for (i = 0; i < NTEST; i++) { for (i = 0; i < NTEST; i++) {
if (!addr[i]) if (!addr[i])
continue; continue;
...@@ -214,12 +223,40 @@ static __init int exercise_pageattr(void) ...@@ -214,12 +223,40 @@ static __init int exercise_pageattr(void)
failed += print_split(&sc); failed += print_split(&sc);
if (failed) { if (failed) {
printk(KERN_ERR "CPA selftests NOT PASSED. Please report.\n"); printk(KERN_ERR "NOT PASSED. Please report.\n");
WARN_ON(1); WARN_ON(1);
return -EINVAL;
} else { } else {
printk(KERN_INFO "CPA selftests PASSED\n"); if (print)
printk(KERN_INFO "ok.\n");
} }
return 0; return 0;
} }
module_init(exercise_pageattr);
static int do_pageattr_test(void *__unused)
{
while (!kthread_should_stop()) {
schedule_timeout_interruptible(HZ*30);
if (pageattr_test() < 0)
break;
if (print)
print--;
}
return 0;
}
static int start_pageattr_test(void)
{
struct task_struct *p;
p = kthread_create(do_pageattr_test, NULL, "pageattr-test");
if (!IS_ERR(p))
wake_up_process(p);
else
WARN_ON(1);
return 0;
}
module_init(start_pageattr_test);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment