]>
Commit | Line | Data |
---|---|---|
45d80ddf SL |
1 | From 4e7c5f670b90566d2a24e0d694c7f8b2a25afc61 Mon Sep 17 00:00:00 2001 |
2 | From: Michal Suchanek <msuchanek@suse.de> | |
3 | Date: Thu, 11 Apr 2019 21:45:58 +1000 | |
4 | Subject: powerpc/64s: Add support for ori barrier_nospec patching | |
5 | ||
6 | commit 2eea7f067f495e33b8b116b35b5988ab2b8aec55 upstream. | |
7 | ||
8 | Based on the RFI patching. This is required to be able to disable the | |
9 | speculation barrier. | |
10 | ||
11 | Only one barrier type is supported and it does nothing when the | |
12 | firmware does not enable it. Also re-patching modules is not supported | |
13 | So the only meaningful thing that can be done is patching out the | |
14 | speculation barrier at boot when the user says it is not wanted. | |
15 | ||
16 | Signed-off-by: Michal Suchanek <msuchanek@suse.de> | |
17 | Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> | |
18 | Signed-off-by: Sasha Levin <sashal@kernel.org> | |
19 | --- | |
20 | arch/powerpc/include/asm/barrier.h | 2 +- | |
21 | arch/powerpc/include/asm/feature-fixups.h | 9 ++++++++ | |
22 | arch/powerpc/include/asm/setup.h | 1 + | |
23 | arch/powerpc/kernel/security.c | 9 ++++++++ | |
24 | arch/powerpc/kernel/vmlinux.lds.S | 7 ++++++ | |
25 | arch/powerpc/lib/feature-fixups.c | 27 +++++++++++++++++++++++ | |
26 | 6 files changed, 54 insertions(+), 1 deletion(-) | |
27 | ||
28 | diff --git a/arch/powerpc/include/asm/barrier.h b/arch/powerpc/include/asm/barrier.h | |
29 | index 352ea3e3cc05..a8131162104f 100644 | |
30 | --- a/arch/powerpc/include/asm/barrier.h | |
31 | +++ b/arch/powerpc/include/asm/barrier.h | |
32 | @@ -82,7 +82,7 @@ do { \ | |
33 | * Prevent execution of subsequent instructions until preceding branches have | |
34 | * been fully resolved and are no longer executing speculatively. | |
35 | */ | |
36 | -#define barrier_nospec_asm ori 31,31,0 | |
37 | +#define barrier_nospec_asm NOSPEC_BARRIER_FIXUP_SECTION; nop | |
38 | ||
39 | // This also acts as a compiler barrier due to the memory clobber. | |
40 | #define barrier_nospec() asm (stringify_in_c(barrier_nospec_asm) ::: "memory") | |
41 | diff --git a/arch/powerpc/include/asm/feature-fixups.h b/arch/powerpc/include/asm/feature-fixups.h | |
42 | index 0bf8202feca6..afd3efd38938 100644 | |
43 | --- a/arch/powerpc/include/asm/feature-fixups.h | |
44 | +++ b/arch/powerpc/include/asm/feature-fixups.h | |
45 | @@ -213,6 +213,14 @@ void setup_feature_keys(void); | |
46 | FTR_ENTRY_OFFSET 951b-952b; \ | |
47 | .popsection; | |
48 | ||
49 | +#define NOSPEC_BARRIER_FIXUP_SECTION \ | |
50 | +953: \ | |
51 | + .pushsection __barrier_nospec_fixup,"a"; \ | |
52 | + .align 2; \ | |
53 | +954: \ | |
54 | + FTR_ENTRY_OFFSET 953b-954b; \ | |
55 | + .popsection; | |
56 | + | |
57 | ||
58 | #ifndef __ASSEMBLY__ | |
59 | ||
60 | @@ -220,6 +228,7 @@ extern long stf_barrier_fallback; | |
61 | extern long __start___stf_entry_barrier_fixup, __stop___stf_entry_barrier_fixup; | |
62 | extern long __start___stf_exit_barrier_fixup, __stop___stf_exit_barrier_fixup; | |
63 | extern long __start___rfi_flush_fixup, __stop___rfi_flush_fixup; | |
64 | +extern long __start___barrier_nospec_fixup, __stop___barrier_nospec_fixup; | |
65 | ||
66 | #endif | |
67 | ||
68 | diff --git a/arch/powerpc/include/asm/setup.h b/arch/powerpc/include/asm/setup.h | |
69 | index 3f160cd20107..703ddf752516 100644 | |
70 | --- a/arch/powerpc/include/asm/setup.h | |
71 | +++ b/arch/powerpc/include/asm/setup.h | |
72 | @@ -50,6 +50,7 @@ enum l1d_flush_type { | |
73 | ||
74 | void setup_rfi_flush(enum l1d_flush_type, bool enable); | |
75 | void do_rfi_flush_fixups(enum l1d_flush_type types); | |
76 | +void do_barrier_nospec_fixups(bool enable); | |
77 | ||
78 | #endif /* !__ASSEMBLY__ */ | |
79 | ||
80 | diff --git a/arch/powerpc/kernel/security.c b/arch/powerpc/kernel/security.c | |
81 | index 2277df84ef6e..8b1cf9c81b82 100644 | |
82 | --- a/arch/powerpc/kernel/security.c | |
83 | +++ b/arch/powerpc/kernel/security.c | |
84 | @@ -10,10 +10,19 @@ | |
85 | #include <linux/seq_buf.h> | |
86 | ||
87 | #include <asm/security_features.h> | |
88 | +#include <asm/setup.h> | |
89 | ||
90 | ||
91 | unsigned long powerpc_security_features __read_mostly = SEC_FTR_DEFAULT; | |
92 | ||
93 | +static bool barrier_nospec_enabled; | |
94 | + | |
95 | +static void enable_barrier_nospec(bool enable) | |
96 | +{ | |
97 | + barrier_nospec_enabled = enable; | |
98 | + do_barrier_nospec_fixups(enable); | |
99 | +} | |
100 | + | |
101 | ssize_t cpu_show_meltdown(struct device *dev, struct device_attribute *attr, char *buf) | |
102 | { | |
103 | bool thread_priv; | |
104 | diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S | |
105 | index c16fddbb6ab8..61def0be6914 100644 | |
106 | --- a/arch/powerpc/kernel/vmlinux.lds.S | |
107 | +++ b/arch/powerpc/kernel/vmlinux.lds.S | |
108 | @@ -153,6 +153,13 @@ SECTIONS | |
109 | *(__rfi_flush_fixup) | |
110 | __stop___rfi_flush_fixup = .; | |
111 | } | |
112 | + | |
113 | + . = ALIGN(8); | |
114 | + __spec_barrier_fixup : AT(ADDR(__spec_barrier_fixup) - LOAD_OFFSET) { | |
115 | + __start___barrier_nospec_fixup = .; | |
116 | + *(__barrier_nospec_fixup) | |
117 | + __stop___barrier_nospec_fixup = .; | |
118 | + } | |
119 | #endif | |
120 | ||
121 | EXCEPTION_TABLE(0) | |
122 | diff --git a/arch/powerpc/lib/feature-fixups.c b/arch/powerpc/lib/feature-fixups.c | |
123 | index cf1398e3c2e0..f82ae6bb2365 100644 | |
124 | --- a/arch/powerpc/lib/feature-fixups.c | |
125 | +++ b/arch/powerpc/lib/feature-fixups.c | |
126 | @@ -277,6 +277,33 @@ void do_rfi_flush_fixups(enum l1d_flush_type types) | |
127 | (types & L1D_FLUSH_MTTRIG) ? "mttrig type" | |
128 | : "unknown"); | |
129 | } | |
130 | + | |
131 | +void do_barrier_nospec_fixups(bool enable) | |
132 | +{ | |
133 | + unsigned int instr, *dest; | |
134 | + long *start, *end; | |
135 | + int i; | |
136 | + | |
137 | + start = PTRRELOC(&__start___barrier_nospec_fixup), | |
138 | + end = PTRRELOC(&__stop___barrier_nospec_fixup); | |
139 | + | |
140 | + instr = 0x60000000; /* nop */ | |
141 | + | |
142 | + if (enable) { | |
143 | + pr_info("barrier-nospec: using ORI speculation barrier\n"); | |
144 | + instr = 0x63ff0000; /* ori 31,31,0 speculation barrier */ | |
145 | + } | |
146 | + | |
147 | + for (i = 0; start < end; start++, i++) { | |
148 | + dest = (void *)start + *start; | |
149 | + | |
150 | + pr_devel("patching dest %lx\n", (unsigned long)dest); | |
151 | + patch_instruction(dest, instr); | |
152 | + } | |
153 | + | |
154 | + printk(KERN_DEBUG "barrier-nospec: patched %d locations\n", i); | |
155 | +} | |
156 | + | |
157 | #endif /* CONFIG_PPC_BOOK3S_64 */ | |
158 | ||
159 | void do_lwsync_fixups(unsigned long value, void *fixup_start, void *fixup_end) | |
160 | -- | |
161 | 2.19.1 | |
162 |