aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/entry/calling.h
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/entry/calling.h')
-rw-r--r--arch/x86/entry/calling.h147
1 files changed, 147 insertions, 0 deletions
diff --git a/arch/x86/entry/calling.h b/arch/x86/entry/calling.h
index 3fd8bc560fae..3f48f695d5e6 100644
--- a/arch/x86/entry/calling.h
+++ b/arch/x86/entry/calling.h
@@ -1,6 +1,11 @@
1/* SPDX-License-Identifier: GPL-2.0 */ 1/* SPDX-License-Identifier: GPL-2.0 */
2#include <linux/jump_label.h> 2#include <linux/jump_label.h>
3#include <asm/unwind_hints.h> 3#include <asm/unwind_hints.h>
4#include <asm/cpufeatures.h>
5#include <asm/page_types.h>
6#include <asm/percpu.h>
7#include <asm/asm-offsets.h>
8#include <asm/processor-flags.h>
4 9
5/* 10/*
6 11
@@ -187,6 +192,148 @@ For 32-bit we have the following conventions - kernel is built with
187#endif 192#endif
188.endm 193.endm
189 194
195#ifdef CONFIG_PAGE_TABLE_ISOLATION
196
197/*
198 * PAGE_TABLE_ISOLATION PGDs are 8k. Flip bit 12 to switch between the two
199 * halves:
200 */
201#define PTI_USER_PGTABLE_BIT PAGE_SHIFT
202#define PTI_USER_PGTABLE_MASK (1 << PTI_USER_PGTABLE_BIT)
203#define PTI_USER_PCID_BIT X86_CR3_PTI_PCID_USER_BIT
204#define PTI_USER_PCID_MASK (1 << PTI_USER_PCID_BIT)
205#define PTI_USER_PGTABLE_AND_PCID_MASK (PTI_USER_PCID_MASK | PTI_USER_PGTABLE_MASK)
206
207.macro SET_NOFLUSH_BIT reg:req
208 bts $X86_CR3_PCID_NOFLUSH_BIT, \reg
209.endm
210
211.macro ADJUST_KERNEL_CR3 reg:req
212 ALTERNATIVE "", "SET_NOFLUSH_BIT \reg", X86_FEATURE_PCID
213 /* Clear PCID and "PAGE_TABLE_ISOLATION bit", point CR3 at kernel pagetables: */
214 andq $(~PTI_USER_PGTABLE_AND_PCID_MASK), \reg
215.endm
216
217.macro SWITCH_TO_KERNEL_CR3 scratch_reg:req
218 ALTERNATIVE "jmp .Lend_\@", "", X86_FEATURE_PTI
219 mov %cr3, \scratch_reg
220 ADJUST_KERNEL_CR3 \scratch_reg
221 mov \scratch_reg, %cr3
222.Lend_\@:
223.endm
224
225#define THIS_CPU_user_pcid_flush_mask \
226 PER_CPU_VAR(cpu_tlbstate) + TLB_STATE_user_pcid_flush_mask
227
228.macro SWITCH_TO_USER_CR3_NOSTACK scratch_reg:req scratch_reg2:req
229 ALTERNATIVE "jmp .Lend_\@", "", X86_FEATURE_PTI
230 mov %cr3, \scratch_reg
231
232 ALTERNATIVE "jmp .Lwrcr3_\@", "", X86_FEATURE_PCID
233
234 /*
235 * Test if the ASID needs a flush.
236 */
237 movq \scratch_reg, \scratch_reg2
238 andq $(0x7FF), \scratch_reg /* mask ASID */
239 bt \scratch_reg, THIS_CPU_user_pcid_flush_mask
240 jnc .Lnoflush_\@
241
242 /* Flush needed, clear the bit */
243 btr \scratch_reg, THIS_CPU_user_pcid_flush_mask
244 movq \scratch_reg2, \scratch_reg
245 jmp .Lwrcr3_pcid_\@
246
247.Lnoflush_\@:
248 movq \scratch_reg2, \scratch_reg
249 SET_NOFLUSH_BIT \scratch_reg
250
251.Lwrcr3_pcid_\@:
252 /* Flip the ASID to the user version */
253 orq $(PTI_USER_PCID_MASK), \scratch_reg
254
255.Lwrcr3_\@:
256 /* Flip the PGD to the user version */
257 orq $(PTI_USER_PGTABLE_MASK), \scratch_reg
258 mov \scratch_reg, %cr3
259.Lend_\@:
260.endm
261
262.macro SWITCH_TO_USER_CR3_STACK scratch_reg:req
263 pushq %rax
264 SWITCH_TO_USER_CR3_NOSTACK scratch_reg=\scratch_reg scratch_reg2=%rax
265 popq %rax
266.endm
267
268.macro SAVE_AND_SWITCH_TO_KERNEL_CR3 scratch_reg:req save_reg:req
269 ALTERNATIVE "jmp .Ldone_\@", "", X86_FEATURE_PTI
270 movq %cr3, \scratch_reg
271 movq \scratch_reg, \save_reg
272 /*
273 * Test the user pagetable bit. If set, then the user page tables
274 * are active. If clear CR3 already has the kernel page table
275 * active.
276 */
277 bt $PTI_USER_PGTABLE_BIT, \scratch_reg
278 jnc .Ldone_\@
279
280 ADJUST_KERNEL_CR3 \scratch_reg
281 movq \scratch_reg, %cr3
282
283.Ldone_\@:
284.endm
285
286.macro RESTORE_CR3 scratch_reg:req save_reg:req
287 ALTERNATIVE "jmp .Lend_\@", "", X86_FEATURE_PTI
288
289 ALTERNATIVE "jmp .Lwrcr3_\@", "", X86_FEATURE_PCID
290
291 /*
292 * KERNEL pages can always resume with NOFLUSH as we do
293 * explicit flushes.
294 */
295 bt $PTI_USER_PGTABLE_BIT, \save_reg
296 jnc .Lnoflush_\@
297
298 /*
299 * Check if there's a pending flush for the user ASID we're
300 * about to set.
301 */
302 movq \save_reg, \scratch_reg
303 andq $(0x7FF), \scratch_reg
304 bt \scratch_reg, THIS_CPU_user_pcid_flush_mask
305 jnc .Lnoflush_\@
306
307 btr \scratch_reg, THIS_CPU_user_pcid_flush_mask
308 jmp .Lwrcr3_\@
309
310.Lnoflush_\@:
311 SET_NOFLUSH_BIT \save_reg
312
313.Lwrcr3_\@:
314 /*
315 * The CR3 write could be avoided when not changing its value,
316 * but would require a CR3 read *and* a scratch register.
317 */
318 movq \save_reg, %cr3
319.Lend_\@:
320.endm
321
322#else /* CONFIG_PAGE_TABLE_ISOLATION=n: */
323
324.macro SWITCH_TO_KERNEL_CR3 scratch_reg:req
325.endm
326.macro SWITCH_TO_USER_CR3_NOSTACK scratch_reg:req scratch_reg2:req
327.endm
328.macro SWITCH_TO_USER_CR3_STACK scratch_reg:req
329.endm
330.macro SAVE_AND_SWITCH_TO_KERNEL_CR3 scratch_reg:req save_reg:req
331.endm
332.macro RESTORE_CR3 scratch_reg:req save_reg:req
333.endm
334
335#endif
336
190#endif /* CONFIG_X86_64 */ 337#endif /* CONFIG_X86_64 */
191 338
192/* 339/*