[PATCH 1/3] x86, ras: Add new infrastructure for machine check fixup tables

Tony Luck
2015-11-09T18:41:11Z

Copy the existing page fault fixup mechanisms to create a new table
to be used when fixing machine checks. Note:
1) At this time we only provide a macro to annotate assembly code
2) We assume all fixups will in code builtin to the kernel.

Signed-off-by: Tony Luck <tony.luck@intel.com>
---
arch/x86/include/asm/asm.h | 7 +++++++
arch/x86/include/asm/uaccess.h | 1 +
arch/x86/mm/extable.c | 16 ++++++++++++++++
include/asm-generic/vmlinux.lds.h | 6 ++++++
include/linux/module.h | 1 +
kernel/extable.c | 14 ++++++++++++++
6 files changed, 45 insertions(+)

diff --git a/arch/x86/include/asm/asm.h b/arch/x86/include/asm/asm.h
index 189679aba703..f2fa7973f18f 100644
--- a/arch/x86/include/asm/asm.h
+++ b/arch/x86/include/asm/asm.h
@@ -58,6 +58,13 @@
.long (to) - . + 0x7ffffff0 ; \
.popsection

+# define _ASM_MCEXTABLE(from, to) \
+ .pushsection "__mcex_table", "a" ; \
+ .balign 8 ; \
+ .long (from) - . ; \
+ .long (to) - . ; \
+ .popsection
+
# define _ASM_NOKPROBE(entry) \
.pushsection "_kprobe_blacklist","aw" ; \
_ASM_ALIGN ; \
diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h
index a8df874f3e88..b8231301a224 100644
--- a/arch/x86/include/asm/uaccess.h
+++ b/arch/x86/include/asm/uaccess.h
@@ -111,6 +111,7 @@ struct exception_table_entry {
#define ARCH_HAS_SEARCH_EXTABLE

extern int fixup_exception(struct pt_regs *regs);
+extern int fixup_mcexception(struct pt_regs *regs);
extern int early_fixup_exception(unsigned long *ip);

/*
diff --git a/arch/x86/mm/extable.c b/arch/x86/mm/extable.c
index 903ec1e9c326..5b328ae00365 100644
--- a/arch/x86/mm/extable.c
+++ b/arch/x86/mm/extable.c
@@ -49,6 +49,22 @@ int fixup_exception(struct pt_regs *regs)
return 0;
}

+int fixup_mcexception(struct pt_regs *regs)
+{
+ const struct exception_table_entry *fixup;
+ unsigned long new_ip;
+
+ fixup = search_mcexception_tables(regs->ip);
+ if (fixup) {
+ new_ip = ex_fixup_addr(fixup);
+
+ regs->ip = new_ip;
+ return 1;
+ }
+
+ return 0;
+}
+
/* Restricted version used during very early boot */
int __init early_fixup_exception(unsigned long *ip)
{
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index 1781e54ea6d3..21bb20d1172a 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -473,6 +473,12 @@
VMLINUX_SYMBOL(__start___ex_table) = .; \
*(__ex_table) \
VMLINUX_SYMBOL(__stop___ex_table) = .; \
+ } \
+ . = ALIGN(align); \
+ __mcex_table : AT(ADDR(__mcex_table) - LOAD_OFFSET) { \
+ VMLINUX_SYMBOL(__start___mcex_table) = .; \
+ *(__mcex_table) \
+ VMLINUX_SYMBOL(__stop___mcex_table) = .; \
}

/*
diff --git a/include/linux/module.h b/include/linux/module.h
index 3a19c79918e0..ffecbfcc462c 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -270,6 +270,7 @@ extern const typeof(name) __mod_##type##__##name##_device_table \

/* Given an address, look for it in the exception tables */
const struct exception_table_entry *search_exception_tables(unsigned long add);
+const struct exception_table_entry *search_mcexception_tables(unsigned long a);

struct notifier_block;

diff --git a/kernel/extable.c b/kernel/extable.c
index e820ccee9846..261c3e2816db 100644
--- a/kernel/extable.c
+++ b/kernel/extable.c
@@ -34,6 +34,8 @@ DEFINE_MUTEX(text_mutex);

extern struct exception_table_entry __start___ex_table[];
extern struct exception_table_entry __stop___ex_table[];
+extern struct exception_table_entry __start___mcex_table[];
+extern struct exception_table_entry __stop___mcex_table[];

/* Cleared by build time tools if the table is already sorted. */
u32 __initdata __visible main_extable_sort_needed = 1;
@@ -45,6 +47,8 @@ void __init sort_main_extable(void)
pr_notice("Sorting __ex_table...\n");
sort_extable(__start___ex_table, __stop___ex_table);
}
+ if (__stop___mcex_table > __start___mcex_table)
+ sort_extable(__start___mcex_table, __stop___mcex_table);
}

/* Given an address, look for it in the exception tables. */
@@ -58,6 +62,16 @@ const struct exception_table_entry *search_exception_tables(unsigned long addr)
return e;
}

+/* Given an address, look for it in the machine check exception tables. */
+const struct exception_table_entry *search_mcexception_tables(
+ unsigned long addr)
+{
+ const struct exception_table_entry *e;
+
+ e = search_extable(__start___mcex_table, __stop___mcex_table-1, addr);
+ return e;
+}
+
static inline int init_kernel_text(unsigned long addr)
{
if (addr >= (unsigned long)_sinittext &&
--
2.1.4