diff options
| -rw-r--r-- | arch/x86/Kconfig.debug | 3 | ||||
| -rw-r--r-- | arch/x86/include/asm/mcsafe_test.h | 75 | ||||
| -rw-r--r-- | arch/x86/lib/memcpy_64.S | 10 | ||||
| -rw-r--r-- | tools/testing/nvdimm/test/nfit.c | 104 |
4 files changed, 192 insertions, 0 deletions
diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug index 192e4d2f9efc..c6dd1d980081 100644 --- a/arch/x86/Kconfig.debug +++ b/arch/x86/Kconfig.debug | |||
| @@ -72,6 +72,9 @@ config EARLY_PRINTK_USB_XDBC | |||
| 72 | You should normally say N here, unless you want to debug early | 72 | You should normally say N here, unless you want to debug early |
| 73 | crashes or need a very simple printk logging facility. | 73 | crashes or need a very simple printk logging facility. |
| 74 | 74 | ||
| 75 | config MCSAFE_TEST | ||
| 76 | def_bool n | ||
| 77 | |||
| 75 | config X86_PTDUMP_CORE | 78 | config X86_PTDUMP_CORE |
| 76 | def_bool n | 79 | def_bool n |
| 77 | 80 | ||
diff --git a/arch/x86/include/asm/mcsafe_test.h b/arch/x86/include/asm/mcsafe_test.h new file mode 100644 index 000000000000..eb59804b6201 --- /dev/null +++ b/arch/x86/include/asm/mcsafe_test.h | |||
| @@ -0,0 +1,75 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
| 2 | #ifndef _MCSAFE_TEST_H_ | ||
| 3 | #define _MCSAFE_TEST_H_ | ||
| 4 | |||
| 5 | #ifndef __ASSEMBLY__ | ||
| 6 | #ifdef CONFIG_MCSAFE_TEST | ||
| 7 | extern unsigned long mcsafe_test_src; | ||
| 8 | extern unsigned long mcsafe_test_dst; | ||
| 9 | |||
| 10 | static inline void mcsafe_inject_src(void *addr) | ||
| 11 | { | ||
| 12 | if (addr) | ||
| 13 | mcsafe_test_src = (unsigned long) addr; | ||
| 14 | else | ||
| 15 | mcsafe_test_src = ~0UL; | ||
| 16 | } | ||
| 17 | |||
| 18 | static inline void mcsafe_inject_dst(void *addr) | ||
| 19 | { | ||
| 20 | if (addr) | ||
| 21 | mcsafe_test_dst = (unsigned long) addr; | ||
| 22 | else | ||
| 23 | mcsafe_test_dst = ~0UL; | ||
| 24 | } | ||
| 25 | #else /* CONFIG_MCSAFE_TEST */ | ||
| 26 | static inline void mcsafe_inject_src(void *addr) | ||
| 27 | { | ||
| 28 | } | ||
| 29 | |||
| 30 | static inline void mcsafe_inject_dst(void *addr) | ||
| 31 | { | ||
| 32 | } | ||
| 33 | #endif /* CONFIG_MCSAFE_TEST */ | ||
| 34 | |||
| 35 | #else /* __ASSEMBLY__ */ | ||
| 36 | #include <asm/export.h> | ||
| 37 | |||
| 38 | #ifdef CONFIG_MCSAFE_TEST | ||
| 39 | .macro MCSAFE_TEST_CTL | ||
| 40 | .pushsection .data | ||
| 41 | .align 8 | ||
| 42 | .globl mcsafe_test_src | ||
| 43 | mcsafe_test_src: | ||
| 44 | .quad 0 | ||
| 45 | EXPORT_SYMBOL_GPL(mcsafe_test_src) | ||
| 46 | .globl mcsafe_test_dst | ||
| 47 | mcsafe_test_dst: | ||
| 48 | .quad 0 | ||
| 49 | EXPORT_SYMBOL_GPL(mcsafe_test_dst) | ||
| 50 | .popsection | ||
| 51 | .endm | ||
| 52 | |||
| 53 | .macro MCSAFE_TEST_SRC reg count target | ||
| 54 | leaq \count(\reg), %r9 | ||
| 55 | cmp mcsafe_test_src, %r9 | ||
| 56 | ja \target | ||
| 57 | .endm | ||
| 58 | |||
| 59 | .macro MCSAFE_TEST_DST reg count target | ||
| 60 | leaq \count(\reg), %r9 | ||
| 61 | cmp mcsafe_test_dst, %r9 | ||
| 62 | ja \target | ||
| 63 | .endm | ||
| 64 | #else | ||
| 65 | .macro MCSAFE_TEST_CTL | ||
| 66 | .endm | ||
| 67 | |||
| 68 | .macro MCSAFE_TEST_SRC reg count target | ||
| 69 | .endm | ||
| 70 | |||
| 71 | .macro MCSAFE_TEST_DST reg count target | ||
| 72 | .endm | ||
| 73 | #endif /* CONFIG_MCSAFE_TEST */ | ||
| 74 | #endif /* __ASSEMBLY__ */ | ||
| 75 | #endif /* _MCSAFE_TEST_H_ */ | ||
diff --git a/arch/x86/lib/memcpy_64.S b/arch/x86/lib/memcpy_64.S index c3b527a9f95d..298ef1479240 100644 --- a/arch/x86/lib/memcpy_64.S +++ b/arch/x86/lib/memcpy_64.S | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | #include <linux/linkage.h> | 3 | #include <linux/linkage.h> |
| 4 | #include <asm/errno.h> | 4 | #include <asm/errno.h> |
| 5 | #include <asm/cpufeatures.h> | 5 | #include <asm/cpufeatures.h> |
| 6 | #include <asm/mcsafe_test.h> | ||
| 6 | #include <asm/alternative-asm.h> | 7 | #include <asm/alternative-asm.h> |
| 7 | #include <asm/export.h> | 8 | #include <asm/export.h> |
| 8 | 9 | ||
| @@ -183,6 +184,9 @@ ENTRY(memcpy_orig) | |||
| 183 | ENDPROC(memcpy_orig) | 184 | ENDPROC(memcpy_orig) |
| 184 | 185 | ||
| 185 | #ifndef CONFIG_UML | 186 | #ifndef CONFIG_UML |
| 187 | |||
| 188 | MCSAFE_TEST_CTL | ||
| 189 | |||
| 186 | /* | 190 | /* |
| 187 | * __memcpy_mcsafe - memory copy with machine check exception handling | 191 | * __memcpy_mcsafe - memory copy with machine check exception handling |
| 188 | * Note that we only catch machine checks when reading the source addresses. | 192 | * Note that we only catch machine checks when reading the source addresses. |
| @@ -206,6 +210,8 @@ ENTRY(__memcpy_mcsafe) | |||
| 206 | subl %ecx, %edx | 210 | subl %ecx, %edx |
| 207 | .L_read_leading_bytes: | 211 | .L_read_leading_bytes: |
| 208 | movb (%rsi), %al | 212 | movb (%rsi), %al |
| 213 | MCSAFE_TEST_SRC %rsi 1 .E_leading_bytes | ||
| 214 | MCSAFE_TEST_DST %rdi 1 .E_leading_bytes | ||
| 209 | .L_write_leading_bytes: | 215 | .L_write_leading_bytes: |
| 210 | movb %al, (%rdi) | 216 | movb %al, (%rdi) |
| 211 | incq %rsi | 217 | incq %rsi |
| @@ -221,6 +227,8 @@ ENTRY(__memcpy_mcsafe) | |||
| 221 | 227 | ||
| 222 | .L_read_words: | 228 | .L_read_words: |
| 223 | movq (%rsi), %r8 | 229 | movq (%rsi), %r8 |
| 230 | MCSAFE_TEST_SRC %rsi 8 .E_read_words | ||
| 231 | MCSAFE_TEST_DST %rdi 8 .E_write_words | ||
| 224 | .L_write_words: | 232 | .L_write_words: |
| 225 | movq %r8, (%rdi) | 233 | movq %r8, (%rdi) |
| 226 | addq $8, %rsi | 234 | addq $8, %rsi |
| @@ -237,6 +245,8 @@ ENTRY(__memcpy_mcsafe) | |||
| 237 | movl %edx, %ecx | 245 | movl %edx, %ecx |
| 238 | .L_read_trailing_bytes: | 246 | .L_read_trailing_bytes: |
| 239 | movb (%rsi), %al | 247 | movb (%rsi), %al |
| 248 | MCSAFE_TEST_SRC %rsi 1 .E_trailing_bytes | ||
| 249 | MCSAFE_TEST_DST %rdi 1 .E_trailing_bytes | ||
| 240 | .L_write_trailing_bytes: | 250 | .L_write_trailing_bytes: |
| 241 | movb %al, (%rdi) | 251 | movb %al, (%rdi) |
| 242 | incq %rsi | 252 | incq %rsi |
diff --git a/tools/testing/nvdimm/test/nfit.c b/tools/testing/nvdimm/test/nfit.c index 4ea385be528f..a8fb63edcf89 100644 --- a/tools/testing/nvdimm/test/nfit.c +++ b/tools/testing/nvdimm/test/nfit.c | |||
| @@ -29,6 +29,8 @@ | |||
| 29 | #include "nfit_test.h" | 29 | #include "nfit_test.h" |
| 30 | #include "../watermark.h" | 30 | #include "../watermark.h" |
| 31 | 31 | ||
| 32 | #include <asm/mcsafe_test.h> | ||
| 33 | |||
| 32 | /* | 34 | /* |
| 33 | * Generate an NFIT table to describe the following topology: | 35 | * Generate an NFIT table to describe the following topology: |
| 34 | * | 36 | * |
| @@ -2681,6 +2683,107 @@ static struct platform_driver nfit_test_driver = { | |||
| 2681 | .id_table = nfit_test_id, | 2683 | .id_table = nfit_test_id, |
| 2682 | }; | 2684 | }; |
| 2683 | 2685 | ||
| 2686 | static char mcsafe_buf[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE))); | ||
| 2687 | |||
| 2688 | enum INJECT { | ||
| 2689 | INJECT_NONE, | ||
| 2690 | INJECT_SRC, | ||
| 2691 | INJECT_DST, | ||
| 2692 | }; | ||
| 2693 | |||
| 2694 | static void mcsafe_test_init(char *dst, char *src, size_t size) | ||
| 2695 | { | ||
| 2696 | size_t i; | ||
| 2697 | |||
| 2698 | memset(dst, 0xff, size); | ||
| 2699 | for (i = 0; i < size; i++) | ||
| 2700 | src[i] = (char) i; | ||
| 2701 | } | ||
| 2702 | |||
| 2703 | static bool mcsafe_test_validate(unsigned char *dst, unsigned char *src, | ||
| 2704 | size_t size, unsigned long rem) | ||
| 2705 | { | ||
| 2706 | size_t i; | ||
| 2707 | |||
| 2708 | for (i = 0; i < size - rem; i++) | ||
| 2709 | if (dst[i] != (unsigned char) i) { | ||
| 2710 | pr_info_once("%s:%d: offset: %zd got: %#x expect: %#x\n", | ||
| 2711 | __func__, __LINE__, i, dst[i], | ||
| 2712 | (unsigned char) i); | ||
| 2713 | return false; | ||
| 2714 | } | ||
| 2715 | for (i = size - rem; i < size; i++) | ||
| 2716 | if (dst[i] != 0xffU) { | ||
| 2717 | pr_info_once("%s:%d: offset: %zd got: %#x expect: 0xff\n", | ||
| 2718 | __func__, __LINE__, i, dst[i]); | ||
| 2719 | return false; | ||
| 2720 | } | ||
| 2721 | return true; | ||
| 2722 | } | ||
| 2723 | |||
| 2724 | void mcsafe_test(void) | ||
| 2725 | { | ||
| 2726 | char *inject_desc[] = { "none", "source", "destination" }; | ||
| 2727 | enum INJECT inj; | ||
| 2728 | |||
| 2729 | if (IS_ENABLED(CONFIG_MCSAFE_TEST)) { | ||
| 2730 | pr_info("%s: run...\n", __func__); | ||
| 2731 | } else { | ||
| 2732 | pr_info("%s: di | ||
