x86/mm: Add KAISER support
Subsystems (13)
cover x86/mm: Add KAISER support
Sending this out for another round of review.
These are the main KAISER patches, on top of the preparatory series I just sent. This includes KAISER support plus enhancements on top, all the latest code.
( All review feedback so far is incorporated - if anything is missing please
let me know. )
Thanks,
Ingo
=====================>
Dave Hansen (17):
x86/mm/kaiser: Disable global pages by default with KAISER x86/mm/kaiser: Prepare the x86/entry assembly code for entry/exit CR3 switching x86/mm/kaiser: Introduce user-mapped per-CPU areas
x86/mm/kaiser: Unmap kernel mappings from userspace page tables, core patch x86/mm/kaiser: Allow NX poison to be set in p4d/pgd
x86/mm/kaiser: Make sure the static PGDs are 8k in size x86/mm/kaiser: Map the CPU entry area
x86/mm/kaiser: Map the dynamically-allocated LDTs
x86/mm/kaiser: Map the espfix structures
x86/mm/kaiser: Map the entry stack variables
x86/mm: Move the CR3 construction functions to tlbflush.h
x86/mm: Remove hard-coded ASID limit checks
x86/mm: Put MMU-to-h/w ASID translation in one place
x86/mm: Allow flushing for future ASID switches
x86/mm/kaiser: Use PCID feature to make user and kernel switches faster x86/mm/kaiser: Disable native VSYSCALL
x86/mm/kaiser: Add Kconfig
Hugh Dickins (1):
x86/mm/kaiser: Map virtually-addressed performance monitoring buffers
Peter Zijlstra (1):
x86/mm/kaiser: Use the other page_table_lock pattern
Thomas Gleixner (5):
x86/mm/kaiser: Respect disabled CPU features x86/mm/kaiser: Simplify disabling of global pages x86/mm/dump_pagetables: Check Kaiser shadow page table for WX pages x86/mm/debug_pagetables: Allow dumping current pagetables x86/mm/kaiser: Add boot time disable switch
Documentation/x86/kaiser.txt | 159 +++++++++ arch/x86/Kconfig | 8 + arch/x86/entry/calling.h | 84 +++++ arch/x86/entry/entry_64.S | 38 +- arch/x86/entry/entry_64_compat.S | 24 +- arch/x86/events/intel/ds.c | 49 ++- arch/x86/include/asm/cpufeatures.h | 1 + arch/x86/include/asm/kaiser.h | 73 ++++ arch/x86/include/asm/mmu_context.h | 29 +- arch/x86/include/asm/pgtable.h | 20 +- arch/x86/include/asm/pgtable_64.h | 140 ++++++++ arch/x86/include/asm/pgtable_types.h | 14 +- arch/x86/include/asm/tlbflush.h | 208 +++++++++-- arch/x86/include/uapi/asm/processor-flags.h | 3 +- arch/x86/kernel/cpu/common.c | 6 +- arch/x86/kernel/espfix_64.c | 28 +- arch/x86/kernel/head_64.S | 30 +- arch/x86/kernel/ldt.c | 25 +- arch/x86/kernel/process_64.c | 2 +- arch/x86/kvm/x86.c | 3 +- arch/x86/mm/Makefile | 1 + arch/x86/mm/debug_pagetables.c | 81 ++++- arch/x86/mm/dump_pagetables.c | 32 +- arch/x86/mm/init.c | 89 +++-- arch/x86/mm/kaiser.c | 521 ++++++++++++++++++++++++++++ arch/x86/mm/pageattr.c | 2 +- arch/x86/mm/pgtable.c | 16 +- arch/x86/mm/tlb.c | 105 +++++- include/asm-generic/vmlinux.lds.h | 7 + include/linux/kaiser.h | 32 ++ include/linux/percpu-defs.h | 30 ++ init/main.c | 3 + kernel/fork.c | 1 + security/Kconfig | 10 + 34 files changed, 1744 insertions(+), 130 deletions(-) create mode 100644 Documentation/x86/kaiser.txt create mode 100644 arch/x86/include/asm/kaiser.h create mode 100644 arch/x86/mm/kaiser.c create mode 100644 include/linux/kaiser.h
Signature · 1 line
2.14.1
PATCH 1/24 x86/mm/kaiser: Disable global pages by default with KAISER
From: Dave Hansen <[email protected]>
Global pages stay in the TLB across context switches. Since all contexts share the same kernel mapping, these mappings are marked as global pages so kernel entries in the TLB are not flushed out on a context switch.
But, even having these entries in the TLB opens up something that an attacker can use, such as the double-page-fault attack:
http://www.ieee-security.org/TC/SP2013/papers/4977a191.pdf
That means that even when KAISER switches page tables on return to user space the global pages would stay in the TLB cache.
Disable global pages so that kernel TLB entries can be flushed before returning to user space. This way, all accesses to kernel addresses from userspace result in a TLB miss independent of the existence of a kernel mapping.
Replace _PAGE_GLOBAL by __PAGE_KERNEL_GLOBAL and keep _PAGE_GLOBAL available so that it can still be used for a few selected kernel mappings which must be visible to userspace, when KAISER is enabled, like the entry/exit code and data.
--- arch/x86/include/asm/pgtable_types.h | 17 ++++++++++++++++- arch/x86/mm/pageattr.c | 16 ++++++++-------- 2 files changed, 24 insertions(+), 9 deletions(-)
arch/x86/include/asm/pgtable_types.h +16 -1
@@ -180,8 +180,23 @@ enum page_cache_mode {#define PAGE_READONLY_EXEC __pgprot(_PAGE_PRESENT | _PAGE_USER | \ _PAGE_ACCESSED) +/* +* Disable global pages for anything using the default +* __PAGE_KERNEL* macros. +* +* PGE will still be enabled and _PAGE_GLOBAL may still be used carefully +* for a few selected kernel mappings which must be visible to userspace, +* when KAISER is enabled, like the entry/exit code and data. +*/ +#ifdef CONFIG_KAISER +#define __PAGE_KERNEL_GLOBAL 0 +#else +#define __PAGE_KERNEL_GLOBAL _PAGE_GLOBAL +#endif +#define __PAGE_KERNEL_EXEC \ - (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_GLOBAL) + (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED | \ + __PAGE_KERNEL_GLOBAL)#define __PAGE_KERNEL (__PAGE_KERNEL_EXEC | _PAGE_NX)#define __PAGE_KERNEL_RO (__PAGE_KERNEL & ~_PAGE_RW)
arch/x86/mm/pageattr.c +8 -8
@@ -585,9 +585,9 @@ try_preserve_large_page(pte_t *kpte, unsigned long address,* for the ancient hardware that doesn't support it. */ if (pgprot_val (req_prot) & _PAGE_PRESENT) -pgprot_val (req_prot) |= _PAGE_PSE | _PAGE_GLOBAL; +pgprot_val (req_prot) |= _PAGE_PSE | __PAGE_KERNEL_GLOBAL;else -pgprot_val (req_prot) &= ~(_PAGE_PSE | _PAGE_GLOBAL); +pgprot_val (req_prot) &= ~(_PAGE_PSE | __PAGE_KERNEL_GLOBAL); req_prot =canon_pgprot (req_prot);
@@ -705,9 +705,9 @@ __split_large_page(struct cpa_data *cpa, pte_t *kpte, unsigned long address,* for the ancient hardware that doesn't support it. */ if (pgprot_val (ref_prot) & _PAGE_PRESENT) -pgprot_val (ref_prot) |= _PAGE_GLOBAL; +pgprot_val (ref_prot) |= __PAGE_KERNEL_GLOBAL;else -pgprot_val (ref_prot) &= ~_PAGE_GLOBAL; +pgprot_val (ref_prot) &= ~__PAGE_KERNEL_GLOBAL;/* * Get the target pfn from the original entry:
@@ -938,9 +938,9 @@ static void populate_pte(struct cpa_data *cpa,* support it. */ if (pgprot_val (pgprot) & _PAGE_PRESENT) -pgprot_val (pgprot) |= _PAGE_GLOBAL; +pgprot_val (pgprot) |= __PAGE_KERNEL_GLOBAL;else -pgprot_val (pgprot) &= ~_PAGE_GLOBAL; +pgprot_val (pgprot) &= ~__PAGE_KERNEL_GLOBAL; pgprot =canon_pgprot (pgprot);
@@ -1242,9 +1242,9 @@ static int __change_page_attr(struct cpa_data *cpa, int primary)* support it. */ if (pgprot_val (new_prot) & _PAGE_PRESENT) -pgprot_val (new_prot) |= _PAGE_GLOBAL; +pgprot_val (new_prot) |= __PAGE_KERNEL_GLOBAL;else -pgprot_val (new_prot) &= ~_PAGE_GLOBAL; +pgprot_val (new_prot) &= ~__PAGE_KERNEL_GLOBAL;/* * We need to keep the pfn from the existing PTE,
Signature · 1 line
2.14.1
PATCH 2/24 x86/mm/kaiser: Prepare the x86/entry assembly code for entry/exit CR3 switching
In reply to Ingo MolnarFrom: Dave Hansen <[email protected]>
This is largely code from Andy Lutomirski. I fixed a few bugs in it, and added a few SWITCH_TO_* spots.
KAISER needs to switch to a different CR3 value when it enters the kernel and switch back when it exits. This essentially needs to be done before leaving assembly code.
This is extra challenging because the switching context is
tricky: the registers that can be clobbered can vary. It is also hard to store things on the stack because there is an established ABI (ptregs) or the stack is entirely unsafe to use.
This patch establishes a set of macros that allow changing to the user and kernel CR3 values.
Interactions with SWAPGS: previous versions of the KAISER code relied on having per-CPU scratch space to save/restore a register that can be used for the CR3 MOV. The %GS register is used to index into our per-CPU space, so SWAPGS *had* to be done before the CR3 switch. That scratch space is gone now, but the semantic that SWAPGS must be done before the CR3 MOV is retained. This is good to keep because it is not that hard to do and it allows us to do things like add per-CPU debugging information to help us figure out what goes wrong sometimes.
What this does in the NMI code is worth pointing out. NMIs can interrupt *any* context and they can also be nested with NMIs interrupting other NMIs. The comments below ".Lnmi_from_kernel" explain the format of the stack during this situation. Changing the format of this stack is not a fun
exercise: I tried. Instead of storing the old CR3 value on the stack, this patch depend on the *regular* register save/restore mechanism and then uses %r14 to keep CR3 during the NMI. It is callee-saved and will not be clobbered by the C NMI handlers that get called.
--- arch/x86/entry/calling.h | 65 ++++++++++++++++++++++++++++++++++++++++ arch/x86/entry/entry_64.S | 38 +++++++++++++++++++++-- arch/x86/entry/entry_64_compat.S | 24 ++++++++++++++- 3 files changed, 123 insertions(+), 4 deletions(-)
arch/x86/entry/calling.h +65 -0
@@ -1,6 +1,7 @@/* SPDX-License-Identifier: GPL-2.0 */ #include <linux/jump_label.h> #include <asm/unwind_hints.h> +#include <asm/cpufeatures.h> /*
@@ -187,6 +188,70 @@ For 32-bit we have the following conventions - kernel is built with #endif .endm +#ifdef CONFIG_KAISER + +/* KAISER PGDs are 8k. Flip bit 12 to switch between the two halves: */ +#define KAISER_SWITCH_MASK (1<<PAGE_SHIFT) + +.macro ADJUST_KERNEL_CR3 reg:req + /* Clear "KAISER bit", point CR3 at kernel pagetables: */ + andq $(~KAISER_SWITCH_MASK), \reg +.endm + +.macro ADJUST_USER_CR3 reg:req + /* Move CR3 up a page to the user page tables: */ + orq $(KAISER_SWITCH_MASK), \reg +.endm + +.macro SWITCH_TO_KERNEL_CR3 scratch_reg:req + mov %cr3, \scratch_reg + ADJUST_KERNEL_CR3 \scratch_reg + mov \scratch_reg, %cr3 +.endm + +.macro SWITCH_TO_USER_CR3 scratch_reg:req + mov %cr3, \scratch_reg + ADJUST_USER_CR3 \scratch_reg + mov \scratch_reg, %cr3 +.endm + +.macro SAVE_AND_SWITCH_TO_KERNEL_CR3 scratch_reg:req save_reg:req + movq %cr3, %r\scratch_reg + movq %r\scratch_reg, \save_reg + /* + * Is the switch bit zero? This means the address is + * up in real KAISER patches in a moment. + */ + testq $(KAISER_SWITCH_MASK), %r\scratch_reg + jz .Ldone_\@ + + ADJUST_KERNEL_CR3 %r\scratch_reg + movq %r\scratch_reg, %cr3 + +.Ldone_\@: +.endm + +.macro RESTORE_CR3 save_reg:req + /* + * The CR3 write could be avoided when not changing its value, + * but would require a CR3 read *and* a scratch register. + */ + movq \save_reg, %cr3 +.endm + +#else /* CONFIG_KAISER=n: */ + +.macro SWITCH_TO_KERNEL_CR3 scratch_reg:req +.endm +.macro SWITCH_TO_USER_CR3 scratch_reg:req +.endm +.macro SAVE_AND_SWITCH_TO_KERNEL_CR3 scratch_reg:req save_reg:req +.endm +.macro RESTORE_CR3 save_reg:req +.endm + +#endif + #endif /* CONFIG_X86_64 */ /*
arch/x86/entry/entry_64.S +35 -3
@@ -168,6 +168,9 @@ ENTRY(entry_SYSCALL_64_trampoline) /* Stash the user RSP. */ movq %rsp, RSP_SCRATCH + /* Note: using %rsp as a scratch reg. */ + SWITCH_TO_KERNEL_CR3 scratch_reg=%rsp + /* Load the top of the task stack into RSP */ movq CPU_ENTRY_AREA_tss + TSS_sp1 + CPU_ENTRY_AREA, %rsp
@@ -198,6 +201,14 @@ ENTRY(entry_SYSCALL_64) swapgs movq %rsp, PER_CPU_VAR(rsp_scratch) + + /* + * The kernel CR3 is needed to map the process stack, but we + * need a scratch register to be able to load CR3. %rsp is + * clobberable right now, so use it as a scratch register. + * %rsp will look crazy here for a couple instructions. + */ + SWITCH_TO_KERNEL_CR3 scratch_reg=%rsp movq PER_CPU_VAR(cpu_current_top_of_stack), %rsp /* Construct struct pt_regs on stack */
@@ -393,6 +404,7 @@ GLOBAL(entry_SYSCALL_64_after_hwframe) * We are on the trampoline stack. All regs except RDI are live. * We can do future final exit work right here. */ + SWITCH_TO_USER_CR3 scratch_reg=%rdi popq %rdi popq %rsp
@@ -729,6 +741,8 @@ GLOBAL(swapgs_restore_regs_and_return_to_usermode) * We can do future final exit work right here. */ + SWITCH_TO_USER_CR3 scratch_reg=%rdi + /* Restore RDI. */ popq %rdi SWAPGS
@@ -938,6 +952,8 @@ ENTRY(switch_to_thread_stack) UNWIND_HINT_FUNC pushq %rdi + /* Need to switch before accessing the thread stack. */ + SWITCH_TO_KERNEL_CR3 scratch_reg=%rdi movq %rsp, %rdi movq PER_CPU_VAR(cpu_current_top_of_stack), %rsp UNWIND_HINT sp_offset=16 sp_reg=ORC_REG_DI
@@ -1239,7 +1255,11 @@ ENTRY(paranoid_entry) js 1f /* negative -> in kernel */ SWAPGS xorl %ebx, %ebx -1: ret + +1: + SAVE_AND_SWITCH_TO_KERNEL_CR3 scratch_reg=ax save_reg=%r14 + + ret END(paranoid_entry) /*
@@ -1261,6 +1281,7 @@ ENTRY(paranoid_exit) testl %ebx, %ebx /* swapgs needed? */ jnz .Lparanoid_exit_no_swapgs TRACE_IRQS_IRETQ + RESTORE_CR3 save_reg=%r14 SWAPGS_UNSAFE_STACK jmp .Lparanoid_exit_restore .Lparanoid_exit_no_swapgs:
@@ -1288,6 +1309,8 @@ ENTRY(error_entry) * from user mode due to an IRET fault. */ SWAPGS + /* We have user CR3. Change to kernel CR3. */ + SWITCH_TO_KERNEL_CR3 scratch_reg=%rax .Lerror_entry_from_usermode_after_swapgs: /* Put us onto the real thread stack. */
@@ -1334,6 +1357,7 @@ ENTRY(error_entry) * .Lgs_change's error handler with kernel gsbase. */ SWAPGS + SWITCH_TO_KERNEL_CR3 scratch_reg=%rax jmp .Lerror_entry_done .Lbstep_iret:
@@ -1343,10 +1367,11 @@ ENTRY(error_entry) .Lerror_bad_iret: /* - * We came from an IRET to user mode, so we have user gsbase. - * Switch to kernel gsbase: + * We came from an IRET to user mode, so we have user + * gsbase and CR3. Switch to kernel gsbase and CR3: */ SWAPGS + SWITCH_TO_KERNEL_CR3 scratch_reg=%rax /* * Pretend that the exception came from user mode: set up pt_regs
@@ -1378,6 +1403,10 @@ END(error_exit) /* * Runs on exception stack. Xen PV does not go through this path at all, * so we can use real assembly here. + * + * Registers: + * %r14: Used to save/restore the CR3 of the interrupted context + * when KAISER is in use. Do not clobber. */ ENTRY(nmi) UNWIND_HINT_IRET_REGS
@@ -1441,6 +1470,7 @@ ENTRY(nmi) swapgs cld + SWITCH_TO_KERNEL_CR3 scratch_reg=%rdx movq %rsp, %rdx movq PER_CPU_VAR(cpu_current_top_of_stack), %rsp UNWIND_HINT_IRET_REGS base=%rdx offset=8
@@ -1693,6 +1723,8 @@ ENTRY(nmi) movq $-1, %rsi call do_nmi + RESTORE_CR3 save_reg=%r14 + testl %ebx, %ebx /* swapgs needed? */ jnz nmi_restore nmi_swapgs:
arch/x86/entry/entry_64_compat.S +23 -1
@@ -49,6 +49,10 @@ ENTRY(entry_SYSENTER_compat) /* Interrupts are off on entry. */ SWAPGS + + /* We are about to clobber %rsp anyway, clobbering here is OK */ + SWITCH_TO_KERNEL_CR3 scratch_reg=%rsp + movq PER_CPU_VAR(cpu_current_top_of_stack), %rsp /*
@@ -215,6 +219,12 @@ GLOBAL(entry_SYSCALL_compat_after_hwframe) pushq $0 /* pt_regs->r14 = 0 */ pushq $0 /* pt_regs->r15 = 0 */ + /* + * We just saved %rdi so it is safe to clobber. It is not + * preserved during the C calls inside TRACE_IRQS_OFF anyway. + */ + SWITCH_TO_KERNEL_CR3 scratch_reg=%rdi + /* * User mode is traced as though IRQs are on, and SYSENTER * turned them off.
@@ -256,10 +266,22 @@ GLOBAL(entry_SYSCALL_compat_after_hwframe) * when the system call started, which is already known to user * code. We zero R8-R10 to avoid info leaks. */ + movq RSP-ORIG_RAX(%rsp), %rsp + + /* + * The original userspace %rsp (RSP-ORIG_RAX(%rsp)) is stored + * on the process stack which is not mapped to userspace and + * not readable after we SWITCH_TO_USER_CR3. Delay the CR3 + * switch until after after the last reference to the process + * stack. + * + * %r8 is zeroed before the sysret, thus safe to clobber. + */ + SWITCH_TO_USER_CR3 scratch_reg=%r8 + xorq %r8, %r8 xorq %r9, %r9 xorq %r10, %r10 - movq RSP-ORIG_RAX(%rsp), %rsp swapgs sysretl END(entry_SYSCALL_compat)
Signature · 1 line
2.14.1
Peter Zijlstra
maintainerRe: [PATCH 02/24] x86/mm/kaiser: Prepare the x86/entry assembly code for entry/exit CR3 switching
Quoted 8 lines · Ingo Molnar
arch/x86/entry/entry_64.S +1
-0@@ -198,6 +201,14 @@ ENTRY(entry_SYSCALL_64) swapgs movq %rsp, PER_CPU_VAR(rsp_scratch) +
arch/x86/entry/entry_64.S ENTRY(entry_SYSCALL_64) · line 214
Quoted 10 lines
arch/x86/entry/entry_64.S +7
-0+ /* + * The kernel CR3 is needed to map the process stack, but we + * need a scratch register to be able to load CR3. %rsp is + * clobberable right now, so use it as a scratch register. + * %rsp will look crazy here for a couple instructions. + */ + SWITCH_TO_KERNEL_CR3 scratch_reg=%rsp movq PER_CPU_VAR(cpu_current_top_of_stack), %rsp /* Construct struct pt_regs on stack */
I think we can do away with this one, on account of never getting here because of entry_SYSCALL_64_trampoline.
Re: [PATCH 02/24] x86/mm/kaiser: Prepare the x86/entry assembly code for entry/exit CR3 switching
Quoted 18 lines · Peter Zijlstra
Quoted 17 lines · Ingo Molnar
arch/x86/entry/entry_64.S +8
-0@@ -198,6 +201,14 @@ ENTRY(entry_SYSCALL_64) swapgs movq %rsp, PER_CPU_VAR(rsp_scratch) + + /* + * The kernel CR3 is needed to map the process stack, but we + * need a scratch register to be able to load CR3. %rsp is + * clobberable right now, so use it as a scratch register. + * %rsp will look crazy here for a couple instructions. + */ + SWITCH_TO_KERNEL_CR3 scratch_reg=%rsp movq PER_CPU_VAR(cpu_current_top_of_stack), %rsp
Quoted 4 lines
arch/x86/entry/entry_64.S ENTRY(entry_SYSCALL_64) · line 214
Quoted 1 line
arch/x86/entry/entry_64.S +0
-0/* Construct struct pt_regs on stack */I think we can do away with this one, on account of never getting here because of
entry_SYSCALL_64_trampoline.
It's on my list already. About 5 people noticed :)
Still trying to decode that paravirt fail.....
Thanks,
tglx
Peter Zijlstra
maintainerRe: [PATCH 02/24] x86/mm/kaiser: Prepare the x86/entry assembly code for entry/exit CR3 switching
Quoted 19 lines · Thomas Gleixner
Quoted 18 lines · Peter Zijlstra
Quoted 17 lines · Ingo Molnar
arch/x86/entry/entry_64.S +8
-0@@ -198,6 +201,14 @@ ENTRY(entry_SYSCALL_64) swapgs movq %rsp, PER_CPU_VAR(rsp_scratch) + + /* + * The kernel CR3 is needed to map the process stack, but we + * need a scratch register to be able to load CR3. %rsp is + * clobberable right now, so use it as a scratch register. + * %rsp will look crazy here for a couple instructions. + */ + SWITCH_TO_KERNEL_CR3 scratch_reg=%rsp movq PER_CPU_VAR(cpu_current_top_of_stack), %rsp
Quoted 6 lines
Quoted 4 lines
arch/x86/entry/entry_64.S ENTRY(entry_SYSCALL_64) · line 214
Quoted 1 line
arch/x86/entry/entry_64.S +0
-0/* Construct struct pt_regs on stack */I think we can do away with this one, on account of never getting here because of
entry_SYSCALL_64_trampoline.It's on my list already. About 5 people noticed :)
Hey, at least we all agree ;-)
PATCH 3/24 x86/mm/kaiser: Introduce user-mapped per-CPU areas
In reply to Ingo MolnarFrom: Dave Hansen <[email protected]>
These patches are based on work from a team at Graz University of Technology posted here:
https://github.com/IAIK/KAISER
The KAISER approach keeps two copies of the page tables: one for running in the kernel and one for running userspace. But, there are a few structures that are needed for switching in and out of the kernel and a good subset of *those* are per-CPU data.
This patch creates a new kind of per-CPU data that is mapped and can be used no matter which copy of the page tables is active. Users of this new section will be forthcoming.
Thanks to Hugh Dickins for cleanups to this code.
--- include/asm-generic/vmlinux.lds.h | 7 +++++++ include/linux/percpu-defs.h | 30 ++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+)
include/asm-generic/vmlinux.lds.h +7 -0
@@ -826,7 +826,14 @@*/ #define PERCPU_INPUT (cacheline) \ VMLINUX_SYMBOL(__per_cpu_start) = .; \ + VMLINUX_SYMBOL(__per_cpu_user_mapped_start) = .; \ *(.data..percpu..first) \ + . = ALIGN(cacheline); \ + *(.data..percpu..user_mapped) \ + *(.data..percpu..user_mapped..shared_aligned) \ + . = ALIGN(PAGE_SIZE); \ + *(.data..percpu..user_mapped..page_aligned) \ + VMLINUX_SYMBOL(__per_cpu_user_mapped_end) = .; \ . = ALIGN(PAGE_SIZE); \ *(.data..percpu..page_aligned) \ . = ALIGN(cacheline); \
include/linux/percpu-defs.h +30 -0
@@ -35,6 +35,12 @@#endif +#ifdef CONFIG_KAISER +#define USER_MAPPED_SECTION "..user_mapped" +#else +#define USER_MAPPED_SECTION "" +#endif +/* * Base implementations of per-CPU variable declarations and definitions, where * the section in which the variable is to be placed is provided by the
@@ -115,6 +121,12 @@#define DEFINE_PER_CPU (type, name) \ DEFINE_PER_CPU_SECTION(type, name, "") +#define DECLARE_PER_CPU_USER_MAPPED (type, name) \ + DECLARE_PER_CPU_SECTION(type, name, USER_MAPPED_SECTION) + +#define DEFINE_PER_CPU_USER_MAPPED (type, name) \ + DEFINE_PER_CPU_SECTION(type, name, USER_MAPPED_SECTION) +/* * Declaration/definition used for per-CPU variables that must come first in * the set of variables.
@@ -144,6 +156,14 @@ DEFINE_PER_CPU_SECTION(type, name, PER_CPU_SHARED_ALIGNED_SECTION) \ ____cacheline_aligned_in_smp +#define DECLARE_PER_CPU_SHARED_ALIGNED_USER_MAPPED (type, name) \ + DECLARE_PER_CPU_SECTION(type, name, USER_MAPPED_SECTION PER_CPU_SHARED_ALIGNED_SECTION) \ + ____cacheline_aligned_in_smp + +#define DEFINE_PER_CPU_SHARED_ALIGNED_USER_MAPPED (type, name) \ + DEFINE_PER_CPU_SECTION(type, name, USER_MAPPED_SECTION PER_CPU_SHARED_ALIGNED_SECTION) \ + ____cacheline_aligned_in_smp +#define DECLARE_PER_CPU_ALIGNED (type, name) \ DECLARE_PER_CPU_SECTION(type, name, PER_CPU_ALIGNED_SECTION) \ ____cacheline_aligned
@@ -162,6 +182,16 @@#define DEFINE_PER_CPU_PAGE_ALIGNED (type, name) \ DEFINE_PER_CPU_SECTION(type, name, "..page_aligned") \ __aligned(PAGE_SIZE) +/* +* Declaration/definition used for per-CPU variables that must be page aligned and need to be mapped in user mode. +*/ +#define DECLARE_PER_CPU_PAGE_ALIGNED_USER_MAPPED (type, name) \ + DECLARE_PER_CPU_SECTION(type, name, USER_MAPPED_SECTION"..page_aligned") \ + __aligned(PAGE_SIZE) + +#define DEFINE_PER_CPU_PAGE_ALIGNED_USER_MAPPED (type, name) \ + DEFINE_PER_CPU_SECTION(type, name, USER_MAPPED_SECTION"..page_aligned") \ + __aligned(PAGE_SIZE)/* * Declaration/definition used for per-CPU variables that must be read mostly.
Signature · 1 line
2.14.1
PATCH 4/24 x86/mm/kaiser: Unmap kernel mappings from userspace page tables, core patch
In reply to Ingo MolnarFrom: Dave Hansen <[email protected]>
These patches are based on work from a team at the Graz University of Technology:
https://github.com/IAIK/KAISER
Signed off by the following gentlemen:
* Signed-off-by: Richard Fellner <[email protected]> * Signed-off-by: Moritz Lipp <[email protected]> * Signed-off-by: Daniel Gruss <[email protected]> * Signed-off-by: Michael Schwarz <[email protected]>
This work would not have been possible without their work as a starting point.
To credit the original work we kept the 'KAISER' name, and added the Signed-off-by tags to the KAISER source code file itself. This patch also carries their 'Originally-by' tags to show credit. (We could not keep the original Signed-off-by tags for the patch itself, as it was changed significantly.)
KAISER is a countermeasure against side channel attacks against kernel virtual memory. It leaves the existing page tables largely alone and refers to them as the "kernel page tables. It adds a "shadow" PGD for every process which is intended for use when running userspace. The shadow PGD maps all the same user memory as the "kernel" copy, but only maps a minimal set of kernel memory.
Whenever entering the kernel (syscalls, interrupts, exceptions), the PGD is switched to the "kernel" copy. When switching back to user mode, the shadow PGD is used.
The minimalistic kernel page tables try to map only what is needed to enter/exit the kernel such as the entry/exit functions themselves and the interrupt descriptors (IDT).
=== Page Table Poisoning ===
KAISER has two copies of the page tables: one for the kernel and one for when running in userspace. There is also a kernel portion of each of the page tables: the part that *maps* the kernel.
The kernel portion is relatively static and uses pre-populated PGDs. Nobody ever calls set_pgd() on the kernel portion during normal operation.
The userspace portion of the page tables is updated frequently as userspace pages are mapped and page table pages are allocated. These updates of the userspace *portion* of the tables need to be reflected into both the kernel and user/shadow copies.
The original KAISER patches did this by effectively looking at the address that is being updated. If it is <PAGE_OFFSET, it is considered to be doing an update for the userspace portion of the page tables and must make an entry in the shadow.
However, this has a wrinkle: there are a few places where low addresses are used in supervisor (kernel) mode. When EFI calls are made, they use what are traditionally user addresses in supervisor mode and trip over these checks. The trampoline code that used for booting secondary CPUs has a similar issue.
Remember, there are two things that KAISER needs performed on a userspace PGD:
1. Populate the shadow itself
2. Poison the kernel PGD so it can not be used by userspace.
Only perform these actions when dealing with a user address *and* the PGD has _PAGE_USER set. That way, in-kernel users of low addresses typically used by userspace are not accidentally poisoned.
Here an (incomplete) list of changes from original KAISER patch:
* Gobs of coding style cleanups
* The original patch tried to allocate an order-2 page, then 8k-align the result. That's silly since order-2 is already guaranteed to be 16k-aligned. Removed that gunk and just allocate an order-1 page.
* Handle (or at least detect and warn on) allocation failures
* Use _KERNPG_TABLE, not _PAGE_TABLE when creating mappings for the kernel in the shadow (user) page tables.
* BUG_ON() for !pte_none() case was totally insane: it checked the physical address of the 'struct page' against the physical address of the page being mapped.
* Added 5-level page table support
* Never free KAISER page tables. We don't have the locking to keep them from getting referenced during the freeing process.
* Use a totally different scheme in the entry code. The original code just fell apart in horrific ways in debug faults, NMIs, or when iret faults. Big thanks to Andy Lutomirski for reducing the number of places that needed to be patched. He made the code a ton simpler.
* Use new entry trampoline instead of mapping process stacks.
--- Documentation/x86/kaiser.txt | 159 ++++++++++++++ arch/x86/entry/calling.h | 1 + arch/x86/include/asm/kaiser.h | 57 +++++ arch/x86/include/asm/pgtable.h | 5 + arch/x86/include/asm/pgtable_64.h | 133 ++++++++++++ arch/x86/kernel/espfix_64.c | 18 ++ arch/x86/kernel/head_64.S | 14 +- arch/x86/mm/Makefile | 1 + arch/x86/mm/kaiser.c | 444 ++++++++++++++++++++++++++++++++++++++ arch/x86/mm/pageattr.c | 2 +- arch/x86/mm/pgtable.c | 16 +- include/linux/kaiser.h | 29 +++ init/main.c | 3 + kernel/fork.c | 1 + 14 files changed, 877 insertions(+), 6 deletions(-)
Documentation/x86/kaiser.txt new file +159 -0
@@ -0,0 +1,159 @@ +Overview +======== + +KAISER is a countermeasure against attacks on kernel address +information. There are at least three existing, published, +approaches using the shared user/kernel mapping and hardware features +to defeat KASLR. One approach referenced in the paper +(https://gruss.cc/files/kaiser.pdf) locates the kernel by +observing differences in page fault timing between +present-but-inaccessible kernel pages and non-present pages. + +When the kernel is entered via syscalls, interrupts or exceptions, +page tables are switched to the full "kernel" copy. When the +system switches back to user mode, the user/shadow copy is used. + +The minimalistic kernel portion of the user page tables try to +map only what is needed to enter/exit the kernel such as the +entry/exit functions themselves and the interrupt descriptor +table (IDT). + +This helps to ensure that side-channel attacks that leverage the +paging structures do not function when KAISER is enabled, by setting +CONFIG_KAISER=y. + +Page Table Management +===================== + +When KAISER is enabled, the kernel manages two sets of page +tables. The first copy is very similar to what would be present +for a kernel without KAISER. It includes a complete mapping of +userspace that the kernel needs for things like copy_*_user(). + +The second (shadow) is used when running userspace and mirrors the +mapping of userspace present in the kernel copy. It maps only +the kernel data needed to enter and exit the kernel. + +The shadow is populated by the kaiser_add_*() functions. Only +kernel data which has been explicitly mapped will appear in the +shadow copy. These calls are rare at runtime. + +For a new userspace mapping, the kernel makes the entries in its +page tables like normal. The only difference is when the kernel +makes entries in the top (PGD) level. In addition to setting the +entry in the main kernel PGD, a copy of the entry is made in the +shadow PGD. + +For user space mappings the kernel creates an entry in the kernel +PGD and the same entry in the shadow PGD, so the underlying page +table to which the PGD entry points to, is shared down to the PTE +level. This leaves a single, shared set of userspace page tables +to manage. One PTE to lock, one set of accessed, dirty bits, etc... + +Overhead +======== + +Protection against side-channel attacks is important. But, +this protection comes at a cost: + +1. Increased Memory Use + a. Each process now needs an order-1 PGD instead of order-0. + (Consumes 4k per process). + b. The pre-allocated second-level (p4d or pud) kernel page + table pages cost ~1MB of additional memory at boot. This + is not totally wasted because some of these pages would + have been needed eventually for normal kernel page tables + and things in the vmalloc() area like vmemmap[]. + c. Statically-allocated structures and entry/exit text must + be padded out to 4k (or 8k for PGDs) so they can be mapped + into the user page tables. This bloats the kernel image + by ~20-30k. + d. The shadow page tables eventually grow to map all of used + vmalloc() space. They can have roughly the same memory + consumption as the vmalloc() page tables. + +2. Runtime Cost + a. CR3 manipulation to switch between the page table copies + must be done at interrupt, syscall, and exception entry + and exit (it can be skipped when the kernel is interrupted, + though.) CR3 modifications are in the order of a hundred + cycles, and are required at every entry and exit. + b. Task stacks must be mapped/unmapped. We need to walk + and modify the shadow page tables at fork() and exit(). + c. Global pages are disabled. This feature of the MMU + allows different processes to share TLB entries mapping + the kernel. Losing the feature means potentially more + TLB misses after a context switch. + d. Process Context IDentifiers (PCID) is a CPU feature that + allows us to skip flushing the entire TLB when switching + page tables. This makes switching the page tables (at + context switch, or kernel entry/exit) cheaper. But, on + systems with PCID support, the context switch code must flush + both the user and kernel entries out of the TLB, with an + INVPCID in addition to the CR3 write. This INVPCID is + generally slower than a CR3 write, but still in the order of + a hundred cycles. + e. The shadow page tables must be populated for each new + process. Even without KAISER, the shared kernel mappings + are created by copying top-level (PGD) entries into each + new process. But, with KAISER, there are now *two* kernel + mappings: one in the kernel page tables that maps everything + and one in the user/shadow page tables mapping the "minimal" + kernel. At fork(), a copy of the portion of the shadow PGD + that maps the minimal kernel structures is needed in + addition to the normal kernel PGD. + f. In addition to the fork()-time copying, there must also + be an update to the shadow PGD any time a set_pgd() is done + on a PGD used to map userspace. This ensures that the kernel + and user/shadow copies always map the same userspace + memory. + g. On systems without PCID support, each CR3 write flushes + the entire TLB. That means that each syscall, interrupt + or exception flushes the TLB. + +Possible Future Work: +1. We can be more careful about not actually writing to CR3 + unless its value is actually changed. +2. Compress the user/shadow-mapped data to be mapped together + underneath a single PGD entry. +3. Re-enable global pages, but use them for mappings in the + user/shadow page tables. This would allow the kernel to + take advantage of TLB entries that were established from + the user page tables. This might speed up the entry/exit + code or userspace since it will not have to reload all of + its TLB entries. However, its upside is limited by PCID + being used. +4. Allow KAISER to be enabled/disabled at runtime so folks can + run a single kernel image. + +Debugging: + +Bugs in KAISER cause a few different signatures of crashes +that are worth noting here. + + * Crashes in early boot, especially around CPU bringup. Bugs + in the trampoline code or mappings cause these. + * Crashes at the first interrupt. Caused by bugs in entry_64.S, + like screwing up a page table switch. Also caused by + incorrectly mapping the IRQ handler entry code. + * Crashes at the first NMI. The NMI code is separate from main + interrupt handlers and can have bugs that do not affect + normal interrupts. Also caused by incorrectly mapping NMI + code. NMIs that interrupt the entry code must be very + careful and can be the cause of crashes that show up when + running perf. + * Kernel crashes at the first exit to userspace. entry_64.S + bugs, or failing to map some of the exit code. + * Crashes at the first interrupt that interrupts userspace. The paths + in entry_64.S that return to userspace are sometimes separate + from the ones that return to the kernel. + * Double faults: overflowing the kernel stack because of page + faults upon page faults. Caused by touching non-kaiser-mapped + data in the entry code, or forgetting to switch to kernel + CR3 before calling into C functions which are not kaiser-mapped. + * Failures of the selftests/x86 code. Usually a bug in one of the + more obscure corners of entry_64.S + * Userspace segfaults early in boot, sometimes manifesting + as mount(8) failing to mount the rootfs. These have + tended to be TLB invalidation issues. Usually invalidating + the wrong PCID, or otherwise missing an invalidation.
arch/x86/entry/calling.h +1 -0
@@ -2,6 +2,7 @@#include <linux/jump_label.h> #include <asm/unwind_hints.h> #include <asm/cpufeatures.h> +#include <asm/page_types.h> /*
arch/x86/include/asm/kaiser.h new file +57 -0
57 lines not on this page · raw message
arch/x86/include/asm/pgtable.h +5 -0
@@ -1106,6 +1106,11 @@ static inline void pmdp_set_wrprotect(struct mm_struct *mm,static inline void clone_pgd_range (pgd_t *dst,pgd_t *src,int count) {memcpy (dst, src, count *sizeof (pgd_t)); +#ifdef CONFIG_KAISER +/* Clone the shadow pgd part as well */ +memcpy (kernel_to_shadow_pgdp (dst),kernel_to_shadow_pgdp (src), + count *sizeof (pgd_t)); +#endif }#define PTE_SHIFT ilog2(PTRS_PER_PTE)
arch/x86/include/asm/pgtable_64.h +133 -0
149 lines not on this page · raw message
arch/x86/kernel/espfix_64.c +18 -0
@@ -41,6 +41,7 @@#include <asm/pgalloc.h> #include <asm/setup.h> #include <asm/espfix.h> +#include <asm/kaiser.h> /* * Note: we only need 6*8 = 48 bytes for the espfix stack, but round
@@ -129,6 +130,23 @@ void __init init_espfix_bsp(void) p4d =p4d_alloc (&init_mm, pgd,ESPFIX_BASE_ADDR );p4d_populate (&init_mm, p4d, espfix_pud_page); +/* +* Just copy the top-level PGD that is mapping the espfix +* area to ensure it is mapped into the shadow user page +* tables. +* +* For 5-level paging, the espfix pgd was populated when +* kaiser_init() pre-populated all the pgd entries. The above +* p4d_alloc() would never do anything and the p4d_populate() +* would be done to a p4d already mapped in the userspace pgd. +*/ +#ifdef CONFIG_KAISER +if (CONFIG_PGTABLE_LEVELS <=4 ) { +set_pgd (kernel_to_shadow_pgdp (pgd), +__pgd (_KERNPG_TABLE | (p4d_pfn (*p4d) <<PAGE_SHIFT ))); + } +#endif +/* Randomize the locations */ init_espfix_random ();
arch/x86/kernel/head_64.S +11 -3
@@ -341,6 +341,14 @@ GLOBAL(early_recursion_flag) .balign PAGE_SIZE; \ GLOBAL(name) +#ifdef CONFIG_KAISER +#define NEXT_PGD_PAGE(name) \ + .balign 2 * PAGE_SIZE; \ +GLOBAL(name) +#else +#define NEXT_PGD_PAGE(name) NEXT_PAGE(name) +#endif + /* Automate the creation of 1 to 1 mapping pmd entries */ #define PMDS(START, PERM, COUNT) \ i = 0 ; \
@@ -350,7 +358,7 @@ GLOBAL(name) .endr __INITDATA -NEXT_PAGE(early_top_pgt) +NEXT_PGD_PAGE(early_top_pgt) .fill 511,8,0 #ifdef CONFIG_X86_5LEVEL .quad level4_kernel_pgt - __START_KERNEL_map + _PAGE_TABLE_NOENC
@@ -364,7 +372,7 @@ NEXT_PAGE(early_dynamic_pgts) .data #if defined(CONFIG_XEN_PV) || defined(CONFIG_XEN_PVH) -NEXT_PAGE(init_top_pgt) +NEXT_PGD_PAGE(init_top_pgt) .quad level3_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE_NOENC .org init_top_pgt + PGD_PAGE_OFFSET*8, 0 .quad level3_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE_NOENC
@@ -381,7 +389,7 @@ NEXT_PAGE(level2_ident_pgt) */ PMDS(0, __PAGE_KERNEL_IDENT_LARGE_EXEC, PTRS_PER_PMD) #else -NEXT_PAGE(init_top_pgt) +NEXT_PGD_PAGE(init_top_pgt) .fill 512,8,0 #endif
arch/x86/mm/Makefile +1 -0
@@ -46,6 +46,7 @@ obj-$(CONFIG_NUMA_EMU) += numa_emulation.o obj-$(CONFIG_X86_INTEL_MPX) += mpx.o obj-$(CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS) += pkeys.o obj-$(CONFIG_RANDOMIZE_MEMORY) += kaslr.o +obj-$(CONFIG_KAISER) += kaiser.o obj-$(CONFIG_AMD_MEM_ENCRYPT) += mem_encrypt.o obj-$(CONFIG_AMD_MEM_ENCRYPT) += mem_encrypt_boot.o
arch/x86/mm/kaiser.c new file +444 -0
444 lines not on this page · raw message
arch/x86/mm/pageattr.c +1 -1
@@ -859,7 +859,7 @@ static void unmap_pmd_range(pud_t *pud, unsigned long start, unsigned long end)pud_clear (pud); } -static void unmap_pud_range (p4d_t *p4d,unsigned long start,unsigned long end) +void unmap_pud_range (p4d_t *p4d,unsigned long start,unsigned long end) {pud_t *pud =pud_offset (p4d, start);
arch/x86/mm/pgtable.c +14 -2
@@ -355,14 +355,26 @@ static inline void _pgd_free(pgd_t *pgd) kmem_cache_free(pgd_cache, pgd); }#else + +#ifdef CONFIG_KAISER +/* +* Instead of one pgd, we aquire two pgds. Being order-1, it is +* both 8k in size and 8k-aligned. That lets us just flip bit 12 +* in a pointer to swap between the two 4k halves. +*/ +#define PGD_ALLOCATION_ORDER 1 +#else +#define PGD_ALLOCATION_ORDER 0 +#endif +static inline pgd_t *_pgd_alloc (void ) { -return (pgd_t *)__get_free_page (PGALLOC_GFP ); +return (pgd_t *)__get_free_pages (PGALLOC_GFP ,PGD_ALLOCATION_ORDER ); }static inline void _pgd_free (pgd_t *pgd) { -free_page ((unsigned long )pgd); +free_pages ((unsigned long )pgd,PGD_ALLOCATION_ORDER ); }#endif /* CONFIG_X86_PAE */
include/linux/kaiser.h new file +29 -0
@@ -0,0 +1,29 @@ +#ifndef _INCLUDE_KAISER_H +#define _INCLUDE_KAISER_H + +#ifdef CONFIG_KAISER +#include <asm/kaiser.h> +#else + +/* +* These stubs are used whenever CONFIG_KAISER is off, which +* includes architectures that support KAISER, but have it +* disabled. +*/ + +static inline void kaiser_init (void ) +{ +} + +static inline void kaiser_remove_mapping (unsigned long start,unsigned long size) +{ +} + +static inline int kaiser_add_mapping (unsigned long addr,unsigned long size, +unsigned long flags) +{ +return 0 ; +} + +#endif /* !CONFIG_KAISER */ +#endif /* _INCLUDE_KAISER_H */
init/main.c +3 -0
@@ -76,6 +76,7 @@#include <linux/slab.h> #include <linux/perf_event.h> #include <linux/ptrace.h> +#include <linux/kaiser.h> #include <linux/blkdev.h> #include <linux/elevator.h> #include <linux/sched_clock.h>
@@ -505,6 +506,8 @@ static void __init mm_init(void)pgtable_init ();vmalloc_init ();ioremap_huge_init (); +/* This just needs to be done before we first run userspace: */ +kaiser_init (); } asmlinkage __visible void __init start_kernel(void)
kernel/fork.c +1 -0
@@ -70,6 +70,7 @@#include <linux/tsacct_kern.h> #include <linux/cn_proc.h> #include <linux/freezer.h> +#include <linux/kaiser.h> #include <linux/delayacct.h> #include <linux/taskstats_kern.h> #include <linux/random.h>
Signature · 1 line
2.14.1
Peter Zijlstra
maintainerRe: [PATCH 04/24] x86/mm/kaiser: Unmap kernel mappings from userspace page tables, core patch
So I had the problem that I could not tell if my shiny new kernel had this brand spanking awesome feature enabled or not.
Do we want something like so?
--- arch/x86/mm/kaiser.c | 2 ++ 1 file changed, 2 insertions(+)
arch/x86/mm/kaiser.c +2 -0
@@ -425,6 +425,8 @@ void __init kaiser_init(void)if (!kaiser_enabled)return ; +pr_info ("All your KAISER are belong to us.\n" ); +kaiser_init_all_pgds ();for_each_possible_cpu (cpu) {
Re: [PATCH 04/24] x86/mm/kaiser: Unmap kernel mappings from userspace page tables, core patch
Quoted 15 lines · Peter Zijlstra
So I had the problem that I could not tell if my shiny new kernel had this brand spanking awesome feature enabled or not.
Do we want something like so?
--- arch/x86/mm/kaiser.c | 2 ++ 1 file changed, 2 insertions(+)arch/x86/mm/kaiser.c +0
-0
arch/x86/mm/kaiser.c void __init kaiser_init(void) · line 432
Quoted 8 lines
arch/x86/mm/kaiser.c +2
-0@@ -425,6 +425,8 @@ void __init kaiser_init(void)if (!kaiser_enabled)return ; +pr_info ("All your KAISER are belong to us.\n" ); +kaiser_init_all_pgds ();for_each_possible_cpu (cpu) {
And yes, the whimsical formulation is a nice touch among all those serious dmesg spews.
:-)
Signature · 4 lines
Regards/Gruss,
Boris.
Good mailing practices for 400: avoid top-posting and trim the reply.Dave Hansen
maintainerRe: [PATCH 04/24] x86/mm/kaiser: Unmap kernel mappings from userspace page tables, core patch
In reply to Peter ZijlstraQuoted 4 lines · Peter Zijlstra
So I had the problem that I could not tell if my shiny new kernel had this brand spanking awesome feature enabled or not.
Do we want something like so?
I eventually shoved one of these in the (buggy) runtime enable/disable patch. But, yeah, we do.
Peter Zijlstra
maintainerRe: [PATCH 04/24] x86/mm/kaiser: Unmap kernel mappings from userspace page tables, core patch
In reply to Ingo MolnarQuoted 5 lines · Ingo Molnar
(quoted diff) +5
-0+/* + * Given a kernel address, @__start_addr, copy that mapping into + * the user (shadow) page tables. This may need to allocate page + * table pages. + */
Review
Quoted 10 lines
(quoted diff) +10
-0+int kaiser_add_user_map(const void *__start_addr, unsigned long size, + unsigned long flags) +{ +} + +int kaiser_add_user_map_ptrs(const void *__start_addr, + const void *__end_addr, + unsigned long flags) +{ +}
AFAICT these here can be static..
arch/x86/mm/kaiser.c +5 -5
@@ -260,8 +260,8 @@ static pte_t *kaiser_shadow_pagetable_walk(unsigned long address,* the user (shadow) page tables. This may need to allocate page * table pages. */ -int kaiser_add_user_map (const void *__start_addr,unsigned long size, -unsigned long flags) +static int kaiser_add_user_map (const void *__start_addr,unsigned long size, +unsigned long flags) {unsigned long start_addr = (unsigned long )__start_addr;unsigned long address = start_addr &PAGE_MASK ;
@@ -310,9 +310,9 @@ int kaiser_add_user_map(const void *__start_addr, unsigned long size,return 0 ; } -int kaiser_add_user_map_ptrs (const void *__start_addr, -const void *__end_addr, -unsigned long flags) +static int kaiser_add_user_map_ptrs (const void *__start_addr, +const void *__end_addr, +unsigned long flags) { return kaiser_add_user_map(__start_addr, __end_addr - __start_addr,
PATCH 5/24 x86/mm/kaiser: Allow NX poison to be set in p4d/pgd
In reply to Ingo MolnarFrom: Dave Hansen <[email protected]>
The user portion of the kernel page tables use the NX bit to poison them for userspace. But, that trips the p4d/pgd_bad() checks. Make sure it does not do that.
--- arch/x86/include/asm/pgtable.h | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-)
arch/x86/include/asm/pgtable.h +12 -2
@@ -846,7 +846,12 @@ static inline pud_t *pud_offset(p4d_t *p4d, unsigned long address)static inline int p4d_bad (p4d_t p4d) { -return (p4d_flags (p4d) & ~(_KERNPG_TABLE | _PAGE_USER)) !=0 ; +unsigned long ignore_flags = _KERNPG_TABLE | _PAGE_USER; + +if (IS_ENABLED (CONFIG_KAISER )) + ignore_flags |= _PAGE_NX; + +return (p4d_flags (p4d) & ~ignore_flags) !=0 ; }#endif /* CONFIG_PGTABLE_LEVELS > 3 */
@@ -880,7 +885,12 @@ static inline p4d_t *p4d_offset(pgd_t *pgd, unsigned long address)static inline int pgd_bad (pgd_t pgd) { -return (pgd_flags (pgd) & ~_PAGE_USER) != _KERNPG_TABLE; +unsigned long ignore_flags = _PAGE_USER; + +if (IS_ENABLED (CONFIG_KAISER )) + ignore_flags |= _PAGE_NX; + +return (pgd_flags (pgd) & ~ignore_flags) != _KERNPG_TABLE; }static inline int pgd_none (pgd_t pgd)
Signature · 1 line
2.14.1
PATCH 6/24 x86/mm/kaiser: Make sure the static PGDs are 8k in size
In reply to Ingo MolnarFrom: Dave Hansen <[email protected]>
A few PGDs come out of the kernel binary instead of being allocated dynamically. Before this patch, they are all 8k-aligned, but they must also be 8k in *size*.
The original KAISER patch did not do this. It probably just lucked out that it did not trample over data after the last PGD.
--- arch/x86/kernel/head_64.S | 16 ++++++++++++++++ 1 file changed, 16 insertions(+)
arch/x86/kernel/head_64.S +16 -0
@@ -342,11 +342,24 @@ GLOBAL(early_recursion_flag) GLOBAL(name) #ifdef CONFIG_KAISER +/* + * Each PGD needs to be 8k long and 8k aligned. We do not + * ever go out to userspace with these, so we do not + * strictly *need* the second page, but this allows us to + * have a single set_pgd() implementation that does not + * need to worry about whether it has 4k or 8k to work + * with. + * + * This ensures PGDs are 8k long: + */ +#define KAISER_USER_PGD_FILL 512 +/* This ensures they are 8k-aligned: */ #define NEXT_PGD_PAGE(name) \ .balign 2 * PAGE_SIZE; \ GLOBAL(name) #else #define NEXT_PGD_PAGE(name) NEXT_PAGE(name) +#define KAISER_USER_PGD_FILL 0 #endif /* Automate the creation of 1 to 1 mapping pmd entries */
@@ -365,6 +378,7 @@ NEXT_PGD_PAGE(early_top_pgt) #else .quad level3_kernel_pgt - __START_KERNEL_map + _PAGE_TABLE_NOENC #endif + .fill KAISER_USER_PGD_FILL,8,0 NEXT_PAGE(early_dynamic_pgts) .fill 512*EARLY_DYNAMIC_PAGE_TABLES,8,0
@@ -379,6 +393,7 @@ NEXT_PGD_PAGE(init_top_pgt) .org init_top_pgt + PGD_START_KERNEL*8, 0 /* (2^48-(2*1024*1024*1024))/(2^39) = 511 */ .quad level3_kernel_pgt - __START_KERNEL_map + _PAGE_TABLE_NOENC + .fill KAISER_USER_PGD_FILL,8,0 NEXT_PAGE(level3_ident_pgt) .quad level2_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE_NOENC
@@ -391,6 +406,7 @@ NEXT_PAGE(level2_ident_pgt) #else NEXT_PGD_PAGE(init_top_pgt) .fill 512,8,0 + .fill KAISER_USER_PGD_FILL,8,0 #endif #ifdef CONFIG_X86_5LEVEL
Signature · 1 line
2.14.1
PATCH 7/24 x86/mm/kaiser: Map the CPU entry area
In reply to Ingo MolnarFrom: Dave Hansen <[email protected]>
There is now a special 'struct cpu_entry_area' that contains all of the data needed to enter the kernel. It's mapped in the fixmap area and contains:
* The GDT (hardware segment descriptor)
* The TSS (thread information structure that points the hardware to the various stacks, and contains the entry stack).
* The entry trampoline code itself
* The exception stacks (aka IRQ stacks)
--- arch/x86/include/asm/kaiser.h | 6 ++++++ arch/x86/kernel/cpu/common.c | 4 ++++ arch/x86/mm/kaiser.c | 31 +++++++++++++++++++++++++++++++ include/linux/kaiser.h | 3 +++ 4 files changed, 44 insertions(+)
arch/x86/include/asm/kaiser.h +6 -0
@@ -33,6 +33,12 @@extern int kaiser_add_mapping (unsigned long addr,unsigned long size,unsigned long flags); +/** +* kaiser_add_mapping_cpu_entry - map the cpu entry area +* @cpu: the CPU for which the entry area is being mapped +*/ +extern void kaiser_add_mapping_cpu_entry (int cpu); +/** * kaiser_remove_mapping - remove a kernel mapping from the userpage tables * @addr: the start address of the range
arch/x86/kernel/cpu/common.c +4 -0
@@ -4,6 +4,7 @@#include <linux/kernel.h> #include <linux/export.h> #include <linux/percpu.h> +#include <linux/kaiser.h> #include <linux/string.h> #include <linux/ctype.h> #include <linux/delay.h>
@@ -584,6 +585,9 @@ static inline void setup_cpu_entry_area(int cpu)__set_fixmap (get_cpu_entry_area_index (cpu, entry_trampoline),__pa_symbol (_entry_trampoline),PAGE_KERNEL_RX );#endif +/* CPU 0's mapping is done in kaiser_init() */ +if (cpu) +kaiser_add_mapping_cpu_entry (cpu); }/* Load the original GDT from the per-cpu structure */
arch/x86/mm/kaiser.c +31 -0
@@ -353,6 +353,26 @@ static void __init kaiser_init_all_pgds(void)WARN_ON (__ret); \ }while (0 ) +void kaiser_add_mapping_cpu_entry(int cpu) +{ +kaiser_add_user_map_early (get_cpu_gdt_ro (cpu),PAGE_SIZE , + __PAGE_KERNEL_RO); + +/* includes the entry stack */ +kaiser_add_user_map_early (&get_cpu_entry_area (cpu)->tss, +sizeof (get_cpu_entry_area (cpu)->tss), + __PAGE_KERNEL | _PAGE_GLOBAL); + +/* Entry code, so needs to be EXEC */ +kaiser_add_user_map_early (&get_cpu_entry_area (cpu)->entry_trampoline, +sizeof (get_cpu_entry_area (cpu)->entry_trampoline), + __PAGE_KERNEL_RX | _PAGE_GLOBAL); + +kaiser_add_user_map_early (&get_cpu_entry_area (cpu)->exception_stacks, +sizeof (get_cpu_entry_area (cpu)->exception_stacks), + __PAGE_KERNEL | _PAGE_GLOBAL); +} +extern char __per_cpu_user_mapped_start[], __per_cpu_user_mapped_end[];/* * If anything in here fails, we will likely die on one of the
@@ -393,6 +413,17 @@ void __init kaiser_init(void)kaiser_add_user_map_early ((void *)idt_descr.address,sizeof (gate_desc) *NR_VECTORS , __PAGE_KERNEL_RO | _PAGE_GLOBAL); + +/* +* We delay CPU 0's mappings because these structures are +* created before the page allocator is up. Deferring it +* until here lets us use the plain page allocator +* unconditionally in the page table code above. +* +* This is OK because kaiser_init() is called long before +* we ever run userspace and need the KAISER mappings. +*/ +kaiser_add_mapping_cpu_entry (0 ); } int kaiser_add_mapping(unsigned long addr, unsigned long size,
include/linux/kaiser.h +3 -0
@@ -25,5 +25,8 @@ static inline int kaiser_add_mapping(unsigned long addr, unsigned long size,return 0 ; } +static inline void kaiser_add_mapping_cpu_entry (int cpu) +{ +}#endif /* !CONFIG_KAISER */ #endif /* _INCLUDE_KAISER_H */
Signature · 1 line
2.14.1
PATCH 8/24 x86/mm/kaiser: Map the dynamically-allocated LDTs
In reply to Ingo MolnarFrom: Dave Hansen <[email protected]>
Normally, a process has a NULL mm->context.ldt. But, there is a syscall for a process to set a new one. If a process does that, the LDT be mapped into the user page tables, just like the default copy.
The original KAISER patch missed this case.
--- arch/x86/kernel/ldt.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-)
arch/x86/kernel/ldt.c +20 -5
@@ -11,6 +11,7 @@#include <linux/gfp.h> #include <linux/sched.h> #include <linux/string.h> +#include <linux/kaiser.h> #include <linux/mm.h> #include <linux/smp.h> #include <linux/syscalls.h>
@@ -57,11 +58,21 @@ static void flush_ldt(void *__mm)refresh_ldt_segments (); } +static void __free_ldt_struct (struct ldt_struct *ldt) +{ +if (ldt->nr_entries *LDT_ENTRY_SIZE >PAGE_SIZE ) +vfree_atomic (ldt->entries); +else +free_page ((unsigned long )ldt->entries); +kfree (ldt); +} +/* The caller must call finalize_ldt_struct on the result. LDT starts zeroed. */ static struct ldt_struct *alloc_ldt_struct (unsigned int num_entries) {struct ldt_struct *new_ldt;unsigned int alloc_size; +int ret;if (num_entries >LDT_ENTRIES )return NULL ;
@@ -89,6 +100,12 @@ static struct ldt_struct *alloc_ldt_struct(unsigned int num_entries)return NULL ; } + ret =kaiser_add_mapping ((unsigned long )new_ldt->entries, alloc_size, + __PAGE_KERNEL | _PAGE_GLOBAL); +if (ret) { +__free_ldt_struct (new_ldt); +return NULL ; + } new_ldt->nr_entries = num_entries;return new_ldt; }
@@ -115,12 +132,10 @@ static void free_ldt_struct(struct ldt_struct *ldt)if (likely (!ldt))return ; +kaiser_remove_mapping ((unsigned long )ldt->entries, + ldt->nr_entries *LDT_ENTRY_SIZE );paravirt_free_ldt (ldt->entries, ldt->nr_entries); -if (ldt->nr_entries *LDT_ENTRY_SIZE >PAGE_SIZE ) -vfree_atomic (ldt->entries); -else -free_page ((unsigned long )ldt->entries); -kfree (ldt); +__free_ldt_struct (ldt); }/*
Signature · 1 line
2.14.1
Re: [08/24] x86/mm/kaiser: Map the dynamically-allocated LDTs
Quoted 33 lines · Ingo Molnar
From: Dave Hansen <[email protected]>
Normally, a process has a NULL
mm->context.ldt. But, there is a syscall for a process to set a new one. If a process does that, the LDT be mapped into the user page tables, just like the default copy.The original KAISER patch missed this case.
Signed-off-by Dave Hansen <[email protected]>Signed-off-by Thomas Gleixner <[email protected]>Cc Andy Lutomirski <[email protected]>Cc Borislav Petkov <[email protected]>Cc Brian Gerst <[email protected]>Cc Denys Vlasenko <[email protected]>Cc H. Peter Anvin <[email protected]>Cc Josh Poimboeuf <[email protected]>Cc Linus Torvalds <[email protected]>Cc Peter Zijlstra <[email protected]>Cc Rik van Riel <[email protected]>Signed-off-by Ingo Molnar <[email protected]>--- arch/x86/kernel/ldt.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-)
...
Quoted 11 lines
arch/x86/kernel/ldt.c +2
-0+/* The caller must call finalize_ldt_struct on the result. LDT starts zeroed. */ static struct ldt_struct *alloc_ldt_struct (unsigned int num_entries) {struct ldt_struct *new_ldt;unsigned int alloc_size; +int ret;if (num_entries >LDT_ENTRIES )return NULL ;
arch/x86/kernel/ldt.c static struct ldt_struct *alloc_ldt_struct(unsigned int num_entries) · line 104
Quoted 5 lines
arch/x86/kernel/ldt.c +2
-0@@ -89,6 +100,12 @@ static struct ldt_struct *alloc_ldt_struct(unsigned int num_entries)return NULL ; } + ret =kaiser_add_mapping ((unsigned long )new_ldt->entries, alloc_size, + __PAGE_KERNEL | _PAGE_GLOBAL);
This results in:
arch/x86/kernel/ldt.c: In function ‘alloc_ldt_struct’:arch/x86/kernel/ldt.c:104:6: warning: large integer implicitly truncated to unsigned type [-Woverflow]
__PAGE_KERNEL | _PAGE_GLOBAL);
^in ARCH=i386 builds with CONFIG_X86_PAE enabled. See
https://groups.google.com/forum/#!topic/cros-kernel-buildreports/8R41aX07daU
Guenter
PATCH 9/24 x86/mm/kaiser: Map the espfix structures
In reply to Ingo MolnarFrom: Dave Hansen <[email protected]>
There is some rather arcane code to help when an IRET returns to 16-bit segments. It is referred to as the "espfix" code. This consists of a few per-CPU variables:
espfix_stack: tells us where the stack is allocated (the bottom)
espfix_waddr: tells us to where %rsp may be pointed (the top)
These are in addition to the stack itself. All three things must be mapped for the espfix code to function.
Note: the espfix code runs with a kernel GSBASE, but user (shadow) page tables. A switch to the kernel page tables could be performed instead of mapping these structures, but mapping them is simpler and less likely to break the assembly. To switch over to the kernel copy, additional temporary storage would be required which is in short supply in this context.
The original KAISER patch missed this case.
--- arch/x86/kernel/espfix_64.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-)
arch/x86/kernel/espfix_64.c +9 -3
@@ -33,6 +33,7 @@#include <linux/init.h> #include <linux/init_task.h> +#include <linux/kaiser.h> #include <linux/kernel.h> #include <linux/percpu.h> #include <linux/gfp.h>
@@ -41,7 +42,6 @@#include <asm/pgalloc.h> #include <asm/setup.h> #include <asm/espfix.h> -#include <asm/kaiser.h> /* * Note: we only need 6*8 = 48 bytes for the espfix stack, but round
@@ -61,8 +61,8 @@#define PGALLOC_GFP (GFP_KERNEL | __GFP_NOTRACK | __GFP_ZERO)/* This contains the *bottom* address of the espfix stack */ -DEFINE_PER_CPU_READ_MOSTLY(unsigned long, espfix_stack); -DEFINE_PER_CPU_READ_MOSTLY(unsigned long, espfix_waddr); +DEFINE_PER_CPU_USER_MAPPED(unsigned long, espfix_stack); +DEFINE_PER_CPU_USER_MAPPED(unsigned long, espfix_waddr);/* Initialization mutex - should this be a spinlock? */ static DEFINE_MUTEX (espfix_init_mutex);
@@ -226,4 +226,10 @@ void init_espfix_ap(int cpu)per_cpu (espfix_stack, cpu) = addr;per_cpu (espfix_waddr, cpu) = (unsigned long )stack_page + (addr & ~PAGE_MASK ); +/* +* _PAGE_GLOBAL is not really required. This is not a hot +* path, but we do it here for consistency. +*/ +kaiser_add_mapping ((unsigned long )stack_page,PAGE_SIZE , + __PAGE_KERNEL | _PAGE_GLOBAL); }
Signature · 1 line
2.14.1
PATCH 10/24 x86/mm/kaiser: Map the entry stack variables
In reply to Ingo MolnarFrom: Dave Hansen <[email protected]>
There are times where the kernel is entered but there is not a safe stack, like at SYSCALL entry. To obtain a safe stack, the per-CPU variables 'rsp_scratch' and 'cpu_current_top_of_stack' are used to save the old %rsp value and to find where the kernel stack should start.
You can not directly manipulate the CR3 register. You can only 'MOV' to it from another register, which means a register must be clobbered in order to do any CR3 manipulation. User-mapping these variables allows us to obtain a safe stack and use it for temporary storage *before* CR3 is switched.
--- arch/x86/kernel/cpu/common.c | 2 +- arch/x86/kernel/process_64.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-)
arch/x86/kernel/cpu/common.c +1 -1
@@ -1515,7 +1515,7 @@ EXPORT_PER_CPU_SYMBOL(__preempt_count);* the top of the kernel stack. Use an extra percpu variable to track the * top of the kernel stack directly. */ -DEFINE_PER_CPU(unsigned long, cpu_current_top_of_stack) = +DEFINE_PER_CPU_USER_MAPPED(unsigned long, cpu_current_top_of_stack) = (unsigned long )&init_thread_union +THREAD_SIZE ;EXPORT_PER_CPU_SYMBOL (cpu_current_top_of_stack);
arch/x86/kernel/process_64.c +1 -1
@@ -59,7 +59,7 @@#include <asm/unistd_32_ia32.h> #endif -__visible DEFINE_PER_CPU (unsigned long ,rsp_scratch ); +__visible DEFINE_PER_CPU_USER_MAPPED (unsigned long ,rsp_scratch );/* Prints also some state that isn't saved in the pt_regs */ void __show_regs (struct pt_regs *regs,int all)
Signature · 1 line
2.14.1
Peter Zijlstra
maintainerRe: [PATCH 10/24] x86/mm/kaiser: Map the entry stack variables
arch/x86/kernel/process_64.c line 65
Quoted 13 lines · Ingo Molnar
arch/x86/kernel/process_64.c +1
-1@@ -59,7 +59,7 @@#include <asm/unistd_32_ia32.h> #endif -__visible DEFINE_PER_CPU (unsigned long ,rsp_scratch ); +__visible DEFINE_PER_CPU_USER_MAPPED (unsigned long ,rsp_scratch );/* Prints also some state that isn't saved in the pt_regs */ void __show_regs (struct pt_regs *regs,int all)
Do we still need this one? It appears to me we'll never actually execute that part of entry_SYSCALL_64 anymore, due to entry_SYSCALL_64_trampoline.
Re: [PATCH 10/24] x86/mm/kaiser: Map the entry stack variables
Quoted 12 lines · Peter Zijlstra
Quoted 11 lines · Ingo Molnar
arch/x86/kernel/process_64.c +1
-1@@ -59,7 +59,7 @@#include <asm/unistd_32_ia32.h> #endif -__visible DEFINE_PER_CPU (unsigned long ,rsp_scratch ); +__visible DEFINE_PER_CPU_USER_MAPPED (unsigned long ,rsp_scratch );
Quoted 6 lines
arch/x86/kernel/process_64.c line 65
Quoted 2 lines
arch/x86/kernel/process_64.c +0
-0/* Prints also some state that isn't saved in the pt_regs */ void __show_regs (struct pt_regs *regs,int all)Do we still need this one? It appears to me we'll never actually execute that part of
entry_SYSCALL_64anymore, due toentry_SYSCALL_64_trampoline.
Unless we use entry_SYSCALL_64 when kaiser is disabled at boottime
Thanks,
tglx
Peter Zijlstra
maintainerRe: [PATCH 10/24] x86/mm/kaiser: Map the entry stack variables
Quoted 14 lines · Thomas Gleixner
Quoted 12 lines · Peter Zijlstra
Quoted 11 lines · Ingo Molnar
arch/x86/kernel/process_64.c +1
-1@@ -59,7 +59,7 @@#include <asm/unistd_32_ia32.h> #endif -__visible DEFINE_PER_CPU (unsigned long ,rsp_scratch ); +__visible DEFINE_PER_CPU_USER_MAPPED (unsigned long ,rsp_scratch );
Quoted 8 lines
Quoted 6 lines
arch/x86/kernel/process_64.c line 65
Quoted 2 lines
arch/x86/kernel/process_64.c +0
-0/* Prints also some state that isn't saved in the pt_regs */ void __show_regs (struct pt_regs *regs,int all)Do we still need this one? It appears to me we'll never actually execute that part of
entry_SYSCALL_64anymore, due toentry_SYSCALL_64_trampoline.Unless we use
entry_SYSCALL_64when kaiser is disabled at boottime
Right for which you need that patchlet I send earlier today. The patches as they are will never ever reach that code.
Peter Zijlstra
maintainerRe: [PATCH 10/24] x86/mm/kaiser: Map the entry stack variables
In reply to Ingo Molnararch/x86/kernel/cpu/common.c EXPORT_PER_CPU_SYMBOL(__preempt_count); · line 1520
Quoted 12 lines · Ingo Molnar
arch/x86/kernel/cpu/common.c +1
-1@@ -1515,7 +1515,7 @@ EXPORT_PER_CPU_SYMBOL(__preempt_count);* the top of the kernel stack. Use an extra percpu variable to track the * top of the kernel stack directly. */ -DEFINE_PER_CPU(unsigned long, cpu_current_top_of_stack) = +DEFINE_PER_CPU_USER_MAPPED(unsigned long, cpu_current_top_of_stack) = (unsigned long )&init_thread_union +THREAD_SIZE ;EXPORT_PER_CPU_SYMBOL (cpu_current_top_of_stack);
I can't find where we would access this one without already having switched to kernel CR3.
A kernel with this entire patch reverted seems to boot for me.
Re: [PATCH 10/24] x86/mm/kaiser: Map the entry stack variables
Quoted 17 lines · Peter Zijlstra
arch/x86/kernel/cpu/common.c EXPORT_PER_CPU_SYMBOL(__preempt_count); · line 1520
Quoted 12 lines · Ingo Molnar
arch/x86/kernel/cpu/common.c +1
-1@@ -1515,7 +1515,7 @@ EXPORT_PER_CPU_SYMBOL(__preempt_count);* the top of the kernel stack. Use an extra percpu variable to track the * top of the kernel stack directly. */ -DEFINE_PER_CPU(unsigned long, cpu_current_top_of_stack) = +DEFINE_PER_CPU_USER_MAPPED(unsigned long, cpu_current_top_of_stack) = (unsigned long )&init_thread_union +THREAD_SIZE ;EXPORT_PER_CPU_SYMBOL (cpu_current_top_of_stack);I can't find where we would access this one without already having switched to kernel CR3.
Quoted 1 line
A kernel with this entire patch reverted seems to boot for me.
Yes, it's not longer required.
PATCH 11/24 x86/mm/kaiser: Map virtually-addressed performance monitoring buffers
In reply to Ingo MolnarFrom: Hugh Dickins <[email protected]>
The BTS and PEBS buffers both have their virtual addresses programmed into the hardware. This means that any access to them is performed via the page tables. The times that the hardware accesses these are entirely dependent on how the performance monitoring hardware events are set up. In other words, there is no way for the kernel to tell when the hardware might access these buffers.
To avoid perf crashes, place 'debug_store' in the user-mapped per-CPU area instead of dynamically allocating. Also use the page allocator plus kaiser_add_mapping() to keep the BTS and PEBS buffers user-mapped (that is, present in the user mapping, though visible only to kernel and hardware). The PEBS fixup buffer does not need this treatment.
The need for a user-mapped struct debug_store showed up before doing any conscious perf testing: in a couple of kernel paging oopses on Westmere, implicating the debug_store offset of the per-CPU area.
[Dave] Added explicit _PAGE_GLOBAL
[Dave] Removed KAISER #ifdefs by moving kmalloc() to plain page allocator [Dave] Reworded the commit message a bit to be consistent with other patches
--- arch/x86/events/intel/ds.c | 49 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 37 insertions(+), 12 deletions(-)
arch/x86/events/intel/ds.c +37 -12
@@ -1,6 +1,7 @@// SPDX-License-Identifier: GPL-2.0 #include <linux/bitops.h> #include <linux/types.h> +#include <linux/kaiser.h> #include <linux/slab.h> #include <asm/perf_event.h>
@@ -8,6 +9,9 @@#include "../perf_event.h" +static +DEFINE_PER_CPU_SHARED_ALIGNED_USER_MAPPED(struct debug_store, cpu_debug_store); +/* The size of a BTS record in bytes: */ #define BTS_RECORD_SIZE 24
@@ -279,6 +283,31 @@ void fini_debug_store_on_cpu(int cpu) static DEFINE_PER_CPU(void *, insn_buffer); +static void *dsalloc (size_t size,gfp_t flags,int node) +{ +unsigned int order =get_order (size); +struct page *page; +unsigned long addr; + + page =__alloc_pages_node (node, flags | __GFP_ZERO, order); +if (!page) +return NULL ; + addr = (unsigned long )page_address (page); +if (kaiser_add_mapping (addr, size, __PAGE_KERNEL | _PAGE_GLOBAL) <0 ) { +__free_pages (page, order); + addr =0 ; + } +return (void *)addr; +} + +static void dsfree (const void *buffer,size_t size) +{ +if (!buffer) +return ; +kaiser_remove_mapping ((unsigned long )buffer, size); +free_pages ((unsigned long )buffer,get_order (size)); +} +static int alloc_pebs_buffer (int cpu) {struct debug_store *ds =per_cpu (cpu_hw_events, cpu).ds;
@@ -289,7 +318,7 @@ static int alloc_pebs_buffer(int cpu)if (!x86_pmu.pebs)return 0 ; - buffer =kzalloc_node (x86_pmu.pebs_buffer_size,GFP_KERNEL , node); + buffer =dsalloc (x86_pmu.pebs_buffer_size,GFP_KERNEL , node);if (unlikely (!buffer))return -ENOMEM ;
@@ -300,7 +329,7 @@ static int alloc_pebs_buffer(int cpu)if (x86_pmu.intel_cap.pebs_format <2 ) { ibuffer =kzalloc_node (PEBS_FIXUP_SIZE ,GFP_KERNEL , node);if (!ibuffer) { -kfree (buffer); +dsfree (buffer, x86_pmu.pebs_buffer_size);return -ENOMEM ; }per_cpu (insn_buffer, cpu) = ibuffer;
@@ -326,7 +355,8 @@ static void release_pebs_buffer(int cpu)kfree (per_cpu (insn_buffer, cpu));per_cpu (insn_buffer, cpu) =NULL ; -kfree ((void *)(unsigned long )ds->pebs_buffer_base); +dsfree ((void *)(unsigned long )ds->pebs_buffer_base, + x86_pmu.pebs_buffer_size); ds->pebs_buffer_base =0 ; }
@@ -340,7 +370,7 @@ static int alloc_bts_buffer(int cpu)if (!x86_pmu.bts)return 0 ; - buffer =kzalloc_node (BTS_BUFFER_SIZE ,GFP_KERNEL | __GFP_NOWARN, node); + buffer =dsalloc (BTS_BUFFER_SIZE ,GFP_KERNEL | __GFP_NOWARN, node);if (unlikely (!buffer)) {WARN_ONCE (1 ,"%s: BTS buffer allocation failure\n" , __func__);return -ENOMEM ;
@@ -366,19 +396,15 @@ static void release_bts_buffer(int cpu)if (!ds || !x86_pmu.bts)return ; -kfree ((void *)(unsigned long )ds->bts_buffer_base); +dsfree ((void *)(unsigned long )ds->bts_buffer_base,BTS_BUFFER_SIZE ); ds->bts_buffer_base =0 ; }static int alloc_ds_buffer (int cpu) { -int node =cpu_to_node (cpu); -struct debug_store *ds; - - ds =kzalloc_node (sizeof (*ds),GFP_KERNEL , node); -if (unlikely (!ds)) -return -ENOMEM ; +struct debug_store *ds =per_cpu_ptr (&cpu_debug_store, cpu); +memset (ds,0 ,sizeof (*ds));per_cpu (cpu_hw_events, cpu).ds = ds;return 0 ;
@@ -392,7 +418,6 @@ static void release_ds_buffer(int cpu)return ;per_cpu (cpu_hw_events, cpu).ds =NULL ; -kfree (ds); }void release_ds_buffers (void )
Signature · 1 line
2.14.1
PATCH 12/24 x86/mm: Move the CR3 construction functions to tlbflush.h
In reply to Ingo MolnarFrom: Dave Hansen <[email protected]>
For flushing the TLB, the ASID which has been programmed into the hardware must be known. That differs from what is in 'cpu_tlbstate'.
Add functions to transform the 'cpu_tlbstate' values into to the one programmed into the hardware (CR3).
It's not easy to include mmu_context.h into tlbflush.h, so just move the CR3 building over to tlbflush.h.
--- arch/x86/include/asm/mmu_context.h | 29 +---------------------------- arch/x86/include/asm/tlbflush.h | 27 +++++++++++++++++++++++++++ arch/x86/mm/tlb.c | 8 ++++---- 3 files changed, 32 insertions(+), 32 deletions(-)
arch/x86/include/asm/mmu_context.h +1 -28
@@ -281,33 +281,6 @@ static inline bool arch_vma_access_permitted(struct vm_area_struct *vma,return __pkru_allows_pkey (vma_pkey (vma), write); } -/* -* If PCID is on, ASID-aware code paths put the ASID+1 into the PCID -* bits. This serves two purposes. It prevents a nasty situation in -* which PCID-unaware code saves CR3, loads some other value (with PCID -* == 0), and then restores CR3, thus corrupting the TLB for ASID 0 if -* the saved ASID was nonzero. It also means that any bugs involving -* loading a PCID-enabled CR3 with CR4.PCIDE off will trigger -* deterministically. -*/ - -static inline unsigned long build_cr3 (struct mm_struct *mm,u16 asid) -{ -if (static_cpu_has (X86_FEATURE_PCID )) { -VM_WARN_ON_ONCE (asid >4094 ); -return __sme_pa (mm->pgd) | (asid +1 ); - }else { -VM_WARN_ON_ONCE (asid !=0 ); -return __sme_pa (mm->pgd); - } -} - -static inline unsigned long build_cr3_noflush (struct mm_struct *mm,u16 asid) -{ -VM_WARN_ON_ONCE (asid >4094 ); -return __sme_pa (mm->pgd) | (asid +1 ) |CR3_NOFLUSH ; -} -/* * This can be used from process context to figure out what the value of * CR3 is without needing to do a (slow) __read_cr3().
@@ -317,7 +290,7 @@ static inline unsigned long build_cr3_noflush(struct mm_struct *mm, u16 asid)*/ static inline unsigned long __get_current_cr3_fast (void ) { -unsigned long cr3 =build_cr3 (this_cpu_read (cpu_tlbstate.loaded_mm), +unsigned long cr3 =build_cr3 (this_cpu_read (cpu_tlbstate.loaded_mm)->pgd,this_cpu_read (cpu_tlbstate.loaded_mm_asid));/* For now, be very restrictive about when this can be called. */
arch/x86/include/asm/tlbflush.h +27 -0
@@ -75,6 +75,33 @@ static inline u64 inc_mm_tlb_gen(struct mm_struct *mm)return new_tlb_gen; } +/* +* If PCID is on, ASID-aware code paths put the ASID+1 into the PCID +* bits. This serves two purposes. It prevents a nasty situation in +* which PCID-unaware code saves CR3, loads some other value (with PCID +* == 0), and then restores CR3, thus corrupting the TLB for ASID 0 if +* the saved ASID was nonzero. It also means that any bugs involving +* loading a PCID-enabled CR3 with CR4.PCIDE off will trigger +* deterministically. +*/ +struct pgd_t ; +static inline unsigned long build_cr3 (pgd_t *pgd,u16 asid) +{ +if (static_cpu_has (X86_FEATURE_PCID )) { +VM_WARN_ON_ONCE (asid >4094 ); +return __sme_pa (pgd) | (asid +1 ); + }else { +VM_WARN_ON_ONCE (asid !=0 ); +return __sme_pa (pgd); + } +} + +static inline unsigned long build_cr3_noflush (pgd_t *pgd,u16 asid) +{ +VM_WARN_ON_ONCE (asid >4094 ); +return __sme_pa (pgd) | (asid +1 ) |CR3_NOFLUSH ; +} +#ifdef CONFIG_PARAVIRT #include <asm/paravirt.h> #else
arch/x86/mm/tlb.c +4 -4
@@ -128,7 +128,7 @@ void switch_mm_irqs_off(struct mm_struct *prev, struct mm_struct *next,* isn't free. */ #ifdef CONFIG_DEBUG_VM -if (WARN_ON_ONCE (__read_cr3 () !=build_cr3 (real_prev, prev_asid))) { +if (WARN_ON_ONCE (__read_cr3 () !=build_cr3 (real_prev->pgd, prev_asid))) {/* * If we were to BUG here, we'd be very likely to kill * the system so hard that we don't see the call trace.
@@ -195,7 +195,7 @@ void switch_mm_irqs_off(struct mm_struct *prev, struct mm_struct *next,if (need_flush) {this_cpu_write (cpu_tlbstate.ctxs[new_asid].ctx_id, next->context.ctx_id);this_cpu_write (cpu_tlbstate.ctxs[new_asid].tlb_gen, next_tlb_gen); -write_cr3 (build_cr3 (next, new_asid)); +write_cr3 (build_cr3 (next->pgd, new_asid));/* * NB: This gets called via leave_mm() in the idle path
@@ -208,7 +208,7 @@ void switch_mm_irqs_off(struct mm_struct *prev, struct mm_struct *next,trace_tlb_flush_rcuidle (TLB_FLUSH_ON_TASK_SWITCH ,TLB_FLUSH_ALL ); }else {/* The new ASID is already up to date. */ -write_cr3 (build_cr3_noflush (next, new_asid)); +write_cr3 (build_cr3_noflush (next->pgd, new_asid));/* See above wrt _rcuidle. */ trace_tlb_flush_rcuidle (TLB_FLUSH_ON_TASK_SWITCH ,0 );
@@ -288,7 +288,7 @@ void initialize_tlbstate_and_flush(void) !(cr4_read_shadow() & X86_CR4_PCIDE));/* Force ASID 0 and force a TLB flush. */ -write_cr3 (build_cr3 (mm,0 )); +write_cr3 (build_cr3 (mm->pgd,0 ));/* Reinitialize tlbstate. */ this_cpu_write (cpu_tlbstate.loaded_mm_asid,0 );
Signature · 1 line
2.14.1
PATCH 13/24 x86/mm: Remove hard-coded ASID limit checks
In reply to Ingo MolnarFrom: Dave Hansen <[email protected]>
First, it's nice to remove the magic numbers.
Second, KAISER is going to consume half of the available ASID space. The space is currently unused, but add a comment to spell out this new restriction.
--- arch/x86/include/asm/tlbflush.h | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-)
arch/x86/include/asm/tlbflush.h +15 -2
@@ -75,6 +75,19 @@ static inline u64 inc_mm_tlb_gen(struct mm_struct *mm)return new_tlb_gen; } +/* There are 12 bits of space for ASIDS in CR3 */ +#define CR3_HW_ASID_BITS 12 +/* When enabled, KAISER consumes a single bit for user/kernel switches */ +#define KAISER_CONSUMED_ASID_BITS 0 + +#define CR3_AVAIL_ASID_BITS (CR3_HW_ASID_BITS - KAISER_CONSUMED_ASID_BITS) +/* +* ASIDs are zero-based: 0->MAX_AVAIL_ASID are valid. -1 below +* to account for them being zero-based. Another -1 is because ASID 0 +* is reserved for use by non-PCID-aware users. +*/ +#define MAX_ASID_AVAILABLE ((1<<CR3_AVAIL_ASID_BITS) - 2) +/* * If PCID is on, ASID-aware code paths put the ASID+1 into the PCID * bits. This serves two purposes. It prevents a nasty situation in
@@ -88,7 +101,7 @@ struct pgd_t;static inline unsigned long build_cr3 (pgd_t *pgd,u16 asid) {if (static_cpu_has (X86_FEATURE_PCID )) { -VM_WARN_ON_ONCE (asid >4094 ); +VM_WARN_ON_ONCE (asid >MAX_ASID_AVAILABLE );return __sme_pa (pgd) | (asid +1 ); }else {VM_WARN_ON_ONCE (asid !=0 );
@@ -98,7 +111,7 @@ static inline unsigned long build_cr3(pgd_t *pgd, u16 asid)static inline unsigned long build_cr3_noflush (pgd_t *pgd,u16 asid) { -VM_WARN_ON_ONCE (asid >4094 ); +VM_WARN_ON_ONCE (asid >MAX_ASID_AVAILABLE );return __sme_pa (pgd) | (asid +1 ) |CR3_NOFLUSH ; }
Signature · 1 line
2.14.1
PATCH 14/24 x86/mm: Put MMU-to-h/w ASID translation in one place
In reply to Ingo MolnarFrom: Dave Hansen <[email protected]>
There are effectively two ASID types:
1. The one stored in the mmu_context that goes from 0..5
2. The one programmed into the hardware that goes from 1..6
This consolidates the locations where converting beween the two (by doing +1) to a single place which gives us a nice place to comment. KAISER will also need to, given an ASID, know which hardware ASID to flush for the userspace mapping.
--- arch/x86/include/asm/tlbflush.h | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-)
arch/x86/include/asm/tlbflush.h +18 -12
@@ -88,21 +88,26 @@ static inline u64 inc_mm_tlb_gen(struct mm_struct *mm)*/ #define MAX_ASID_AVAILABLE ((1<<CR3_AVAIL_ASID_BITS) - 2) -/* -* If PCID is on, ASID-aware code paths put the ASID+1 into the PCID -* bits. This serves two purposes. It prevents a nasty situation in -* which PCID-unaware code saves CR3, loads some other value (with PCID -* == 0), and then restores CR3, thus corrupting the TLB for ASID 0 if -* the saved ASID was nonzero. It also means that any bugs involving -* loading a PCID-enabled CR3 with CR4.PCIDE off will trigger -* deterministically. -*/ +static inline u16 kern_asid (u16 asid) +{ +VM_WARN_ON_ONCE (asid >MAX_ASID_AVAILABLE ); +/* +* If PCID is on, ASID-aware code paths put the ASID+1 into the PCID +* bits. This serves two purposes. It prevents a nasty situation in +* which PCID-unaware code saves CR3, loads some other value (with PCID +* == 0), and then restores CR3, thus corrupting the TLB for ASID 0 if +* the saved ASID was nonzero. It also means that any bugs involving +* loading a PCID-enabled CR3 with CR4.PCIDE off will trigger +* deterministically. +*/ +return asid +1 ; +} +struct pgd_t ;static inline unsigned long build_cr3 (pgd_t *pgd,u16 asid) {if (static_cpu_has (X86_FEATURE_PCID )) { -VM_WARN_ON_ONCE (asid >MAX_ASID_AVAILABLE ); -return __sme_pa (pgd) | (asid +1 ); +return __sme_pa (pgd) |kern_asid (asid); }else {VM_WARN_ON_ONCE (asid !=0 );return __sme_pa (pgd);
@@ -112,7 +117,8 @@ static inline unsigned long build_cr3(pgd_t *pgd, u16 asid)static inline unsigned long build_cr3_noflush (pgd_t *pgd,u16 asid) {VM_WARN_ON_ONCE (asid >MAX_ASID_AVAILABLE ); -return __sme_pa (pgd) | (asid +1 ) |CR3_NOFLUSH ; +VM_WARN_ON_ONCE (!this_cpu_has (X86_FEATURE_PCID )); +return __sme_pa (pgd) |kern_asid (asid) |CR3_NOFLUSH ; }#ifdef CONFIG_PARAVIRT
Signature · 1 line
2.14.1
PATCH 15/24 x86/mm: Allow flushing for future ASID switches
In reply to Ingo MolnarFrom: Dave Hansen <[email protected]>
If changing the page tables in such a way that an invalidation of all contexts (aka. PCIDs / ASIDs) is required, they can be actively invalidated by:
1. INVPCID for each PCID (works for single pages too).
2. Load CR3 with each PCID without the NOFLUSH bit set
3. Load CR3 with the NOFLUSH bit set for each and do INVLPG for each address.
But, none of these are really feasible since there are ~6 ASIDs (12 with KAISER) at the time that invalidation is required. Instead of actively invalidating them, invalidate the *current* context and also mark the cpu_tlbstate _quickly_ to indicate future invalidation to be required.
At the next context-switch, look for this indicator ('all_other_ctxs_invalid' being set) invalidate all of the cpu_tlbstate.ctxs[] entries.
This ensures that any future context switches will do a full flush of the TLB, picking up the previous changes.
--- arch/x86/include/asm/tlbflush.h | 47 ++++++++++++++++++++++++++++++++--------- arch/x86/mm/tlb.c | 35 ++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+), 10 deletions(-)
arch/x86/include/asm/tlbflush.h +37 -10
@@ -184,6 +184,17 @@ struct tlb_state {*/ bool is_lazy; +/* +* If set we changed the page tables in such a way that we +* needed an invalidation of all contexts (aka. PCIDs / ASIDs). +* This tells us to go invalidate all the non-loaded ctxs[] +* on the next context switch. +* +* The current ctx was kept up-to-date as it ran and does not +* need to be invalidated. +*/ +bool all_other_ctxs_invalid; +/* * Access to this CR4 shadow and to H/W CR4 is protected by * disabling interrupts when modifying either one.
@@ -264,6 +275,19 @@ static inline unsigned long cr4_read_shadow(void)return this_cpu_read (cpu_tlbstate.cr4); } +static inline void tlb_flush_shared_nonglobals (void ) +{ +/* +* With global pages, all of the shared kenel page tables +* are set as _PAGE_GLOBAL. We have no shared nonglobals +* and nothing to do here. +*/ +if (IS_ENABLED (CONFIG_X86_GLOBAL_PAGES )) +return ; + +this_cpu_write (cpu_tlbstate.all_other_ctxs_invalid, true); +} +/* * Save some of cr4 feature set we're using (e.g. Pentium 4MB * enable and PPro Global page enable), so that any CPU's that boot
@@ -293,6 +317,10 @@ static inline void __native_flush_tlb(void)preempt_disable ();native_write_cr3 (__native_read_cr3 ());preempt_enable (); +/* +* Does not need tlb_flush_shared_nonglobals() since the CR3 write +* without PCIDs flushes all non-globals. +*/ }static inline void __native_flush_tlb_global_irq_disabled (void )
@@ -338,24 +366,23 @@ static inline void __native_flush_tlb_single(unsigned long addr)static inline void __flush_tlb_all (void ) { -if (boot_cpu_has (X86_FEATURE_PGE )) +if (boot_cpu_has (X86_FEATURE_PGE )) {__flush_tlb_global (); -else + }else {__flush_tlb (); - -/* -* Note: if we somehow had PCID but not PGE, then this wouldn't work -- -* we'd end up flushing kernel translations for the current ASID but -* we might fail to flush kernel translations for other cached ASIDs. -* -* To avoid this issue, we force PCID off if PGE is off. -*/ +tlb_flush_shared_nonglobals (); + } }static inline void __flush_tlb_one (unsigned long addr) {count_vm_tlb_event (NR_TLB_LOCAL_FLUSH_ONE );__flush_tlb_single (addr); +/* +* Invalidate other address spaces inaccessible to single-page +* invalidation: +*/ +tlb_flush_shared_nonglobals (); }#define TLB_FLUSH_ALL -1UL
arch/x86/mm/tlb.c +35 -0
@@ -28,6 +28,38 @@* Implement flush IPI by CALL_FUNCTION_VECTOR, Alex Shi */ +/* +* We get here when we do something requiring a TLB invalidation +* but could not go invalidate all of the contexts. We do the +* necessary invalidation by clearing out the 'ctx_id' which +* forces a TLB flush when the context is loaded. +*/ +void clear_non_loaded_ctxs (void ) +{ +u16 asid; + +/* +* This is only expected to be set if we have disabled +* kernel _PAGE_GLOBAL pages. +*/ +if (IS_ENABLED (CONFIG_X86_GLOBAL_PAGES )) { +WARN_ON_ONCE (1 ); +return ; + } + +for (asid =0 ; asid <TLB_NR_DYN_ASIDS ; asid++) { +/* Do not need to flush the current asid */ +if (asid ==this_cpu_read (cpu_tlbstate.loaded_mm_asid)) +continue ; +/* +* Make sure the next time we go to switch to +* this asid, we do a flush: +*/ +this_cpu_write (cpu_tlbstate.ctxs[asid].ctx_id,0 ); + } +this_cpu_write (cpu_tlbstate.all_other_ctxs_invalid, false); +} +atomic64_t last_mm_ctx_id =ATOMIC64_INIT (1 );
@@ -42,6 +74,9 @@ static void choose_new_asid(struct mm_struct *next, u64 next_tlb_gen,return ; } +if (this_cpu_read (cpu_tlbstate.all_other_ctxs_invalid)) +clear_non_loaded_ctxs (); +for (asid =0 ; asid <TLB_NR_DYN_ASIDS ; asid++) {if (this_cpu_read (cpu_tlbstate.ctxs[asid].ctx_id) != next->context.ctx_id)
Signature · 1 line
2.14.1
Andy Lutomirski
NAKRe: [PATCH 15/24] x86/mm: Allow flushing for future ASID switches
Quoted 18 lines · Ingo Molnar
From: Dave Hansen <[email protected]>
If changing the page tables in such a way that an invalidation of all contexts (aka. PCIDs / ASIDs) is required, they can be actively invalidated by:
1. INVPCID for each PCID (works for single pages too).
2. Load CR3 with each PCID without the NOFLUSH bit set
3. Load CR3 with the NOFLUSH bit set for each and do INVLPG for each address.
But, none of these are really feasible since there are ~6 ASIDs (12 with KAISER) at the time that invalidation is required. Instead of actively invalidating them, invalidate the *current* context and also mark the
cpu_tlbstate_quickly_ to indicate future invalidation to be required.
Quoted 6 lines
At the next context-switch, look for this indicator ('
all_other_ctxs_invalid' being set) invalidate all of the cpu_tlbstate.ctxs[] entries.This ensures that any future context switches will do a full flush of the TLB, picking up the previous changes.
NAK.
We need to split up __flush_tlb_one() into __flush_tlb_one() and __flush_tlb_one_kernel(). We've gotten away with having a single function for both this long because we've never had PCID on and nonglobal kernel mappings around. So we're busted starting with "x86/mm/kaiser: Disable global pages by default with KAISER", which means that we have a potential corruption issue affecting anyone who tries to bisect the series.
Then we need to make the kernel variant do something sane (presumably just call __flush_tlb_all if we have PCID && !PGE). And, for the user variant, we need a straightforward, clean, efficient way to mark a given address space on a given CPU as needing a usermode PCID flush when its usermode tables are next loaded. This patch isn't it.
--Andy
Dave Hansen
maintainerRe: [PATCH 15/24] x86/mm: Allow flushing for future ASID switches
Quoted 7 lines · Andy Lutomirski
We need to split up
__flush_tlb_one()into__flush_tlb_one()and__flush_tlb_one_kernel(). We've gotten away with having a single function for both this long because we've never had PCID on and nonglobal kernel mappings around. So we're busted starting with "x86/mm/kaiser: Disable global pages by default with KAISER", which means that we have a potential corruption issue affecting anyone who tries to bisect the series.
There's no way this thing works with CONFIG_KAISER=y in the middle of the series, that's why the Kconfig patch was stuck at the end. Is there breaking without the Kconfig option enabled?
Quoted 2 lines
Then we need to make the kernel variant do something sane (presumably just call
__flush_tlb_allif we have PCID && !PGE).
Yes, auditing all the callers and figuring out what they're flushing is a good exercise.
BTW, one reason I've avoided falling back to __flush_tlb_all() in the "single" invalidate cases is that it hides bugs. TLB invalidation bugs are hard enough to find as it stands, but silently turning every "little hammer" single flush into an implicit "big hammer" full flush shouldn't be something that we do lightly.
Quoted 4 lines
and, for the user
variant, we need a straightforward, clean, efficient way to mark a given address space on a given CPU as needing a usermode PCID flush when its usermode tables are next loaded. This patch isn't it.
Right now, the kernel and user ASIDs are pretty joined at the hip. We always flush them together. We don't _need_ a mechanism to specifically mark a user ASID because it doesn't get managed separately.
I assume you want to go this route so that we can eventually separate out the user and kernel flushing because we can get the kernel flushing for "free" at context switch time and then the user flushing for "free" at the return to userspace.
That's all fine and good, but it *is* more complicated than what's there right now. Is there something that I'm missing here that it simplifies?
Peter Zijlstra
maintainerRe: [PATCH 15/24] x86/mm: Allow flushing for future ASID switches
In reply to Andy LutomirskiQuoted 7 lines · Andy Lutomirski
We need to split up
__flush_tlb_one()into__flush_tlb_one()and__flush_tlb_one_kernel(). We've gotten away with having a single function for both this long because we've never had PCID on and nonglobal kernel mappings around. So we're busted starting with "x86/mm/kaiser: Disable global pages by default with KAISER", which means that we have a potential corruption issue affecting anyone who tries to bisect the series.
Didn't do that..
Quoted 5 lines
Then we need to make the kernel variant do something sane (presumably just call
__flush_tlb_allif we have PCID && !PGE). And, for the user variant, we need a straightforward, clean, efficient way to mark a given address space on a given CPU as needing a usermode PCID flush when its usermode tables are next loaded. This patch isn't it.
Did give this a try, mostly also to get PCID + !INVPCID working for my IVB.
The below is fairly ugly but it does boot and build a kernel so its not immensely broken.
---
arch/x86/entry/calling.h +16 -1
@@ -4,6 +4,7 @@#include <asm/cpufeatures.h> #include <asm/page_types.h> #include <asm/pgtable_types.h> +#include <asm/percpu.h> /*
@@ -220,7 +221,21 @@ For 32-bit we have the following conventions - kernel is built with .macro SWITCH_TO_USER_CR3 scratch_reg:req STATIC_JUMP_IF_FALSE .Lend_\@, kaiser_enabled_key, def=1 mov %cr3, \scratch_reg - ADJUST_USER_CR3 \scratch_reg + push \scratch_reg + andq $(0x7FF), \scratch_reg + bt \scratch_reg, PER_CPU_VAR(__asid_flush) + jnc .Lnoflush_\@ + + btr \scratch_reg, PER_CPU_VAR(__asid_flush) + pop \scratch_reg + jmp .Ldo_\@ + +.Lnoflush_\@: + pop \scratch_reg + ALTERNATIVE "", "bts $63, \scratch_reg", X86_FEATURE_PCID + +.Ldo_\@: + orq $(KAISER_SWITCH_MASK), \scratch_reg mov \scratch_reg, %cr3 .Lend_\@: .endm
arch/x86/include/asm/tlbflush.h +31 -3
@@ -9,6 +9,7 @@#include <asm/cpufeature.h> #include <asm/special_insns.h> #include <asm/smp.h> +#include <asm/kaiser.h> static inline void __invpcid (unsigned long pcid,unsigned long addr,unsigned long type)
@@ -347,9 +348,33 @@ static inline void cr4_set_bits_and_update_boot(unsigned long mask)extern void initialize_tlbstate_and_flush (void ); +DECLARE_PER_CPU(unsigned long, __asid_flush); + +/* +* Given an asid, flush the corresponding KAISER user ASID. +*/ +static inline void flush_user_asid (u16 asid) +{ +/* There is no user ASID if KAISER is off */ +if (!IS_ENABLED (CONFIG_KAISER )) +return ; +/* +* We only have a single ASID if PCID is off and the CR3 +* write will have flushed it. +*/ +if (!cpu_feature_enabled (X86_FEATURE_PCID )) +return ; + +if (!kaiser_enabled) +return ; + +__set_bit (kern_asid (asid),this_cpu_ptr (&__asid_flush)); +} +static inline void __native_flush_tlb (void ) {if (!cpu_feature_enabled (X86_FEATURE_INVPCID )) { +#if 0 /* * native_write_cr3() only clears the current PCID if * CR4 has X86_CR4_PCIDE set. In other words, this does
@@ -358,9 +383,10 @@ static inline void __native_flush_tlb(void)* With KAISER and PCIDs, the means that we did not * flush the user PCID. Warn if it gets called. */ -if (IS_ENABLED (CONFIG_KAISER )) -WARN_ON_ONCE (this_cpu_read (cpu_tlbstate.cr4) & -X86_CR4_PCIDE ); +if (IS_ENABLED (CONFIG_KAISER ) && kaiser_enabled) +WARN_ON_ONCE (this_cpu_read (cpu_tlbstate.cr4) &X86_CR4_PCIDE ); +#endif +flush_user_asid (this_cpu_read (cpu_tlbstate.loaded_mm_asid));/* * If current->mm == NULL then we borrow a mm * which may change during a task switch and
@@ -435,6 +461,8 @@ static inline void __native_flush_tlb_single(unsigned long addr)* early. */ if (!this_cpu_has (X86_FEATURE_INVPCID_SINGLE )) { +flush_user_asid (loaded_mm_asid); + asmvolatile ("invlpg (%0)" ::"r" (addr) :"memory" );return ; }
arch/x86/mm/init.c +3 -1
@@ -218,11 +218,13 @@ static void setup_pcid(void)* INVPCID. Just avoid using PCIDs at all if we * have KAISER and do not have INVPCID. */ +#if 0 if (!IS_ENABLED (CONFIG_X86_GLOBAL_PAGES ) && - !boot_cpu_has (X86_FEATURE_INVPCID )) { + kaiser_enabled && !boot_cpu_has (X86_FEATURE_INVPCID )) {setup_clear_cpu_cap (X86_FEATURE_PCID );return ; } +#endif /* * This can't be cr4_set_bits_and_update_boot() -- * the trampoline code can't handle CR4.PCIDE and
arch/x86/mm/tlb.c +2 -43
57 lines not on this page · raw message
Peter Zijlstra
maintainerRe: [PATCH 15/24] x86/mm: Allow flushing for future ASID switches
Quoted 13 lines · Peter Zijlstra
arch/x86/entry/calling.h +8
-1@@ -220,7 +221,21 @@ For 32-bit we have the following conventions - kernel is built with .macro SWITCH_TO_USER_CR3 scratch_reg:req STATIC_JUMP_IF_FALSE .Lend_\@, kaiser_enabled_key, def=1 mov %cr3, \scratch_reg - ADJUST_USER_CR3 \scratch_reg + push \scratch_reg + andq $(0x7FF), \scratch_reg + bt \scratch_reg, PER_CPU_VAR(__asid_flush) + jnc .Lnoflush_\@ + + btr \scratch_reg, PER_CPU_VAR(__asid_flush) + pop \scratch_reg + jmp .Ldo_\@
arch/x86/entry/calling.h For 32-bit we have the following conventions - kernel is built with · line 241
Quoted 10 lines
arch/x86/entry/calling.h +7
-0+ +.Lnoflush_\@: + pop \scratch_reg + ALTERNATIVE "", "bts $63, \scratch_reg", X86_FEATURE_PCID + +.Ldo_\@: + orq $(KAISER_SWITCH_MASK), \scratch_reg mov \scratch_reg, %cr3 .Lend_\@: .endm
Ah, I suppose I should also deal with RESTORE_CR3...
Dave Hansen
maintainerRe: [PATCH 15/24] x86/mm: Allow flushing for future ASID switches
In reply to Peter ZijlstraThanks for looking at this, Peter. I've been resisting doing this for a bit and it's an embarrassingly small amount of code.
arch/x86/entry/calling.h For 32-bit we have the following conventions - kernel is built with · line 224
Quoted 6 lines · Peter Zijlstra
arch/x86/entry/calling.h +1
-1@@ -220,7 +221,21 @@ For 32-bit we have the following conventions - kernel is built with .macro SWITCH_TO_USER_CR3 scratch_reg:req STATIC_JUMP_IF_FALSE .Lend_\@, kaiser_enabled_key, def=1 mov %cr3, \scratch_reg - ADJUST_USER_CR3 \scratch_reg + push \scratch_reg
Do we have a good stack in all the spots that we need to do this? It may have changed with the trampoline stack, but I'm 100% sure that it wasn't so in the recent past.
Let me see if I'm reading the assembly right.
Load the kernel's ASID from CR3 into \scratch_reg:
arch/x86/entry/calling.h For 32-bit we have the following conventions - kernel is built with · line 225
Quoted 1 line
arch/x86/entry/calling.h +1
-0+ andq $(0x7FF), \scratch_reg
See if that ASID needs a flush by checking its bit in __asid_flush. Store value of the bit in CF:
arch/x86/entry/calling.h For 32-bit we have the following conventions - kernel is built with · line 226
Quoted 1 line
arch/x86/entry/calling.h +1
-0+ bt \scratch_reg, PER_CPU_VAR(__asid_flush)
Jump if CF bit is clear:
arch/x86/entry/calling.h For 32-bit we have the following conventions - kernel is built with · line 227
Quoted 1 line
arch/x86/entry/calling.h +1
-0+ jnc .Lnoflush_\@
Clear the ASID bit from __asid_flush since we are about to do the flush:
arch/x86/entry/calling.h For 32-bit we have the following conventions - kernel is built with · line 229
Quoted 1 line
arch/x86/entry/calling.h +1
-0+ btr \scratch_reg, PER_CPU_VAR(__asid_flush)
Restore CR3 back to what it was:
Review For 32-bit we have the following conventions - kernel is built with · line 229
Quoted 1 line
(quoted diff) +1
-0+ pop \scratch_reg
Jump past the code that sets the no-flush bit (63), forcing a flush:
Quoted 27 lines
arch/x86/entry/calling.h +8
-0+ jmp .Ldo_\@ + +.Lnoflush_\@: + pop \scratch_reg + ALTERNATIVE "", "bts $63, \scratch_reg", X86_FEATURE_PCID + +.Ldo_\@: + orq $(KAISER_SWITCH_MASK), \scratch_reg mov \scratch_reg, %cr3 .Lend_\@: .endmarch/x86/include/asm/tlbflush.h +1
-0@@ -9,6 +9,7 @@#include <asm/cpufeature.h> #include <asm/special_insns.h> #include <asm/smp.h> +#include <asm/kaiser.h> static inline void __invpcid (unsigned long pcid,unsigned long addr,unsigned long type)
arch/x86/include/asm/tlbflush.h static inline void cr4_set_bits_and_update_boot(unsigned long mask) · line 351
Quoted 4 lines
arch/x86/include/asm/tlbflush.h +1
-0@@ -347,9 +348,33 @@ static inline void cr4_set_bits_and_update_boot(unsigned long mask)extern void initialize_tlbstate_and_flush (void ); +DECLARE_PER_CPU(unsigned long, __asid_flush);
Could we spare enough space to make this something like user_asid_flush_pending_mask?
It took me a minute to realize that it was a mask. Also, since we only have 6 asids, should we bit a bit more stingy with the type?
Quoted 10 lines
arch/x86/include/asm/tlbflush.h +10
-0+/* +* Given an asid, flush the corresponding KAISER user ASID. +*/ +static inline void flush_user_asid (u16 asid) +{ +/* There is no user ASID if KAISER is off */ +if (!IS_ENABLED (CONFIG_KAISER )) +return ; +/* +* We only have a single ASID if PCID is off and the CR3
arch/x86/include/asm/tlbflush.h static inline void cr4_set_bits_and_update_boot(unsigned long mask) · line 372
Quoted 10 lines
arch/x86/include/asm/tlbflush.h +10
-0+* write will have flushed it. +*/ +if (!cpu_feature_enabled (X86_FEATURE_PCID )) +return ; + +if (!kaiser_enabled) +return ; + +__set_bit (kern_asid (asid),this_cpu_ptr (&__asid_flush)); +}
We flush_user_asid() and thus set bits in __asid_flush in two cases:
1. When we flush the TLB explicitly
2. When we re-use an ASID for a new mm
It took me a minute to realize that mixing these is still OK, even if the mm associated with the ASID changes. It's because once the ASID is stale, it doesn't matter *why* it is stale. Just that the next guy who *uses* it needs to do the flush. You can do 1,000 tlb flushes, a context switch, a tlb flush and another context switch, but if you only go out to userspace once, you only need 1 ASID flush. That fits perfectly with this bit that gets set a bunch of times and only cleared once at exit to userspace.
IOW, this all seems sane, but it took me a few minutes of staring at it to come to that conclusion.
Peter Zijlstra
maintainerRe: [PATCH 15/24] x86/mm: Allow flushing for future ASID switches
Quoted 2 lines · Dave Hansen
Thanks for looking at this, Peter. I've been resisting doing this for a bit and it's an embarrassingly small amount of code.
Right, well, its not complete yet, and it might be complete crap :-)
Quoted 11 lines · Peter Zijlstra
arch/x86/entry/calling.h For 32-bit we have the following conventions - kernel is built with · line 224
Quoted 6 lines
arch/x86/entry/calling.h +1
-1@@ -220,7 +221,21 @@ For 32-bit we have the following conventions - kernel is built with .macro SWITCH_TO_USER_CR3 scratch_reg:req STATIC_JUMP_IF_FALSE .Lend_\@, kaiser_enabled_key, def=1 mov %cr3, \scratch_reg - ADJUST_USER_CR3 \scratch_reg + push \scratch_regDo we have a good stack in all the spots that we need to do this? It may have changed with the trampoline stack, but I'm 100% sure that it wasn't so in the recent past.
Dunno really. I figured I'd give it a go and see what happens. So far the machine still works. But I was hoping Andy would have an opinion on this.
Quoted 1 line
Let me see if I'm reading the assembly right.
Yep, seems you can read asm :-)
Quoted 4 lines
arch/x86/include/asm/tlbflush.h static inline void cr4_set_bits_and_update_boot(unsigned long mask) · line 351
Quoted 1 line
arch/x86/include/asm/tlbflush.h +1
-0+DECLARE_PER_CPU(unsigned long, __asid_flush);Could we spare enough space to make this something like
user_asid_flush_pending_mask?
Yeah, if I can get it all working we'll bikeshed on a name ;-)
Quoted 2 lines
It took me a minute to realize that it was a mask. Also, since we only have 6 asids, should we bit a bit more stingy with the type?
I picked unsigned long because our bitops (__set_bit in this case, use it), and I know we're LE and could simply use a shorter type, but meh.
Quoted 8 lines
It took me a minute to realize that mixing these is still OK, even if the mm associated with the ASID changes. It's because once the ASID is stale, it doesn't matter *why* it is stale. Just that the next guy who *uses* it needs to do the flush. You can do 1,000 tlb flushes, a context switch, a tlb flush and another context switch, but if you only go out to userspace once, you only need 1 ASID flush. That fits perfectly with this bit that gets set a bunch of times and only cleared once at exit to userspace.
Just so.
I'm now staring at the RESTORE_CR3 stuff, and that appears to be called in the NMI handling where the stack is not to be used (if I read it right), so that's going to be a little more tricky.
Let me prod at that..
Peter Zijlstra
maintainerRe: [PATCH 15/24] x86/mm: Allow flushing for future ASID switches
Quoted 3 lines · Peter Zijlstra
I'm now staring at the
RESTORE_CR3stuff, and that appears to be called in the NMI handling where the stack is not to be used (if I read it right), so that's going to be a little more tricky.
As I just mentioned on IRC; I just realized that RESTORE_CR3 is always flushing. So what I just wrote is effectively an optimization that allows a nonflush.
Re: [PATCH 15/24] x86/mm: Allow flushing for future ASID switches
In reply to Peter ZijlstraQuoted 18 lines · Peter Zijlstra
Quoted 2 lines · Dave Hansen
Thanks for looking at this, Peter. I've been resisting doing this for a bit and it's an embarrassingly small amount of code.
Right, well, its not complete yet, and it might be complete crap :-)
Quoted 11 lines · Peter Zijlstra
arch/x86/entry/calling.h For 32-bit we have the following conventions - kernel is built with · line 224
Quoted 6 lines
arch/x86/entry/calling.h +1
-1@@ -220,7 +221,21 @@ For 32-bit we have the following conventions - kernel is built with .macro SWITCH_TO_USER_CR3 scratch_reg:req STATIC_JUMP_IF_FALSE .Lend_\@, kaiser_enabled_key, def=1 mov %cr3, \scratch_reg - ADJUST_USER_CR3 \scratch_reg + push \scratch_regDo we have a good stack in all the spots that we need to do this? It may have changed with the trampoline stack, but I'm 100% sure that it wasn't so in the recent past.
Quoted 3 lines
Dunno really. I figured I'd give it a go and see what happens. So far the machine still works. But I was hoping Andy would have an opinion on this.
I thought we had a stack in all these places even before the trampoline. There was an issue with *entry*, but I think exit has always been okay.
Quoted 28 lines
Quoted 2 lines
Let me see if I'm reading the assembly right.
Yep, seems you can read asm :-)
Quoted 4 lines
arch/x86/include/asm/tlbflush.h static inline void cr4_set_bits_and_update_boot(unsigned long mask) · line 351
Quoted 1 line
arch/x86/include/asm/tlbflush.h +1
-0+DECLARE_PER_CPU(unsigned long, __asid_flush);Could we spare enough space to make this something like
user_asid_flush_pending_mask?Yeah, if I can get it all working we'll bikeshed on a name ;-)
Quoted 2 lines
It took me a minute to realize that it was a mask. Also, since we only have 6 asids, should we bit a bit more stingy with the type?
I picked unsigned long because our bitops (
__set_bitin this case, use it), and I know we're LE and could simply use a shorter type, but meh.Quoted 8 lines
It took me a minute to realize that mixing these is still OK, even if the mm associated with the ASID changes. It's because once the ASID is stale, it doesn't matter *why* it is stale. Just that the next guy who *uses* it needs to do the flush. You can do 1,000 tlb flushes, a context switch, a tlb flush and another context switch, but if you only go out to userspace once, you only need 1 ASID flush. That fits perfectly with this bit that gets set a bunch of times and only cleared once at exit to userspace.
Quoted 5 lines
Just so.
I'm now staring at the
RESTORE_CR3stuff, and that appears to be called in the NMI handling where the stack is not to be used (if I read it right), so that's going to be a little more tricky.
I think it should be fine. A very old version of the patches had that problem, but, in -tip, the nmi RESTORE_CR3 is in the fancy recursion-protected region, and the stack is okay. The idea is that we're already on the old (possibly user) CR3 before we do the crazy recursion-checking bits. But that's fine, since all that's accessed there is the IST stack, and that's in the cpu_entry_area and thus safe regardless of CR3.
Side question: on extremely quick read, you're doing bt then btr. Why not just do a single btr and be done with it? Are you trying to avoid getting exclusive access to the cacheline when not needed?
Peter Zijlstra
maintainerRe: [PATCH 15/24] x86/mm: Allow flushing for future ASID switches
Quoted 3 lines · Andy Lutomirski
Side question: on extremely quick read, you're doing bt then btr. Why not just do a single btr and be done with it? Are you trying to avoid getting exclusive access to the cacheline when not needed?
Yes, avoids the M in the common !flush case.
Peter Zijlstra
maintainerRe: [PATCH 15/24] x86/mm: Allow flushing for future ASID switches
In reply to Andy LutomirskiQuoted 7 lines · Andy Lutomirski
I think it should be fine. A very old version of the patches had that problem, but, in -tip, the nmi
RESTORE_CR3is in the fancy recursion-protected region, and the stack is okay. The idea is that we're already on the old (possibly user) CR3 before we do the crazy recursion-checking bits. But that's fine, since all that's accessed there is the IST stack, and that's in thecpu_entry_areaand thus safe regardless of CR3.
Turns out there's a gob of spare registers to be had on RESTORE_CR3, we do POP_EXTRA_REGS right after both call-sites. So I just picked something from there.
arch/x86/entry/calling.h +48 -8
@@ -4,6 +4,7 @@#include <asm/cpufeatures.h> #include <asm/page_types.h> #include <asm/pgtable_types.h> +#include <asm/percpu.h> /*
@@ -220,15 +221,29 @@ For 32-bit we have the following conventions - kernel is built with .macro SWITCH_TO_USER_CR3 scratch_reg:req STATIC_JUMP_IF_FALSE .Lend_\@, kaiser_enabled_key, def=1 mov %cr3, \scratch_reg - ADJUST_USER_CR3 \scratch_reg + push \scratch_reg + andq $(0x7FF), \scratch_reg + bt \scratch_reg, PER_CPU_VAR(__asid_flush) + jnc .Lnoflush_\@ + + btr \scratch_reg, PER_CPU_VAR(__asid_flush) + pop \scratch_reg + jmp .Ldo_\@ + +.Lnoflush_\@: + pop \scratch_reg + ALTERNATIVE "", "bts $63, \scratch_reg", X86_FEATURE_PCID + +.Ldo_\@: + orq $(KAISER_SWITCH_MASK), \scratch_reg mov \scratch_reg, %cr3 .Lend_\@: .endm .macro SAVE_AND_SWITCH_TO_KERNEL_CR3 scratch_reg:req save_reg:req STATIC_JUMP_IF_FALSE .Ldone_\@, kaiser_enabled_key, def=1 - movq %cr3, %r\scratch_reg - movq %r\scratch_reg, \save_reg + movq %cr3, \scratch_reg + movq \scratch_reg, \save_reg/* * Is the "switch mask" all zero? That means that both of * these are zero:
@@ -239,17 +254,42 @@ For 32-bit we have the following conventions - kernel is built with* * That indicates a kernel CR3 value, not user/shadow. */ - testq $(KAISER_SWITCH_MASK), %r\scratch_reg + testq $(KAISER_SWITCH_MASK), \scratch_reg jz .Ldone_\@ - ADJUST_KERNEL_CR3 %r\scratch_reg - movq %r\scratch_reg, %cr3 + ADJUST_KERNEL_CR3 \scratch_reg + movq \scratch_reg, %cr3 .Ldone_\@: .endm -.macro RESTORE_CR3 save_reg:req +.macro RESTORE_CR3 scratch_reg:req save_reg:req STATIC_JUMP_IF_FALSE .Lend_\@, kaiser_enabled_key, def=1 + + /* ASID bit 11 is for USER */ + bt $11, \save_reg + /* + * KERNEL pages can always resume with NOFLUSH as we do + * explicit flushes. + */ + jnc .Lnoflush_\@ + + /* + * Check if there's a pending flush for the USER ASID we're + * about to set. + */ + movq \save_reg, \scratch_reg + andq $(0x7FF), \scratch_reg + bt \scratch_reg, PER_CPU_VAR(__asid_flush) + jnc .Lnoflush_\@ + + btr \scratch_reg, PER_CPU_VAR(__asid_flush) + jmp .Ldo_\@ + +.Lnoflush_\@: + ALTERNATIVE "", "bts $63, \save_reg", X86_FEATURE_PCID + +.Ldo_\@: /* * The CR3 write could be avoided when not changing its value, * but would require a CR3 read *and* a scratch register.
@@ -266,7 +306,7 @@ For 32-bit we have the following conventions - kernel is built with .endm .macro SAVE_AND_SWITCH_TO_KERNEL_CR3 scratch_reg:req save_reg:req .endm -.macro RESTORE_CR3 save_reg:req +.macro RESTORE_CR3 scratch_reg:req save_reg:req .endm#endif
arch/x86/entry/entry_64.S +3 -3
@@ -1257,7 +1254,7 @@ ENTRY(paranoid_entry) xorl %ebx, %ebx 1: - SAVE_AND_SWITCH_TO_KERNEL_CR3 scratch_reg=ax save_reg=%r14 + SAVE_AND_SWITCH_TO_KERNEL_CR3 scratch_reg=%rax save_reg=%r14 ret END(paranoid_entry)
@@ -1281,7 +1278,7 @@ ENTRY(paranoid_exit) testl %ebx, %ebx /* swapgs needed? */ jnz .Lparanoid_exit_no_swapgs TRACE_IRQS_IRETQ - RESTORE_CR3 save_reg=%r14 + RESTORE_CR3 scratch_reg=%rbx save_reg=%r14 SWAPGS_UNSAFE_STACK jmp .Lparanoid_exit_restore .Lparanoid_exit_no_swapgs:
@@ -1723,7 +1720,7 @@ end_repeat_nmi: movq $-1, %rsi call do_nmi - RESTORE_CR3 save_reg=%r14 + RESTORE_CR3 scratch_reg=%r15 save_reg=%r14 testl %ebx, %ebx /* swapgs needed? */ jnz nmi_restore
arch/x86/include/asm/tlbflush.h +31 -3
@@ -9,6 +9,7 @@#include <asm/cpufeature.h> #include <asm/special_insns.h> #include <asm/smp.h> +#include <asm/kaiser.h> static inline void __invpcid (unsigned long pcid,unsigned long addr,unsigned long type)
@@ -347,9 +348,33 @@ static inline void cr4_set_bits_and_update_boot(unsigned long mask)extern void initialize_tlbstate_and_flush (void ); +DECLARE_PER_CPU(unsigned long, __asid_flush); + +/* +* Given an asid, flush the corresponding KAISER user ASID. +*/ +static inline void flush_user_asid (u16 asid) +{ +/* There is no user ASID if KAISER is off */ +if (!IS_ENABLED (CONFIG_KAISER )) +return ; +/* +* We only have a single ASID if PCID is off and the CR3 +* write will have flushed it. +*/ +if (!cpu_feature_enabled (X86_FEATURE_PCID )) +return ; + +if (!kaiser_enabled) +return ; + +__set_bit (kern_asid (asid),this_cpu_ptr (&__asid_flush)); +} +static inline void __native_flush_tlb (void ) {if (!cpu_feature_enabled (X86_FEATURE_INVPCID )) { +#if 0 /* * native_write_cr3() only clears the current PCID if * CR4 has X86_CR4_PCIDE set. In other words, this does
@@ -358,9 +383,10 @@ static inline void __native_flush_tlb(void)* With KAISER and PCIDs, the means that we did not * flush the user PCID. Warn if it gets called. */ -if (IS_ENABLED (CONFIG_KAISER )) -WARN_ON_ONCE (this_cpu_read (cpu_tlbstate.cr4) & -X86_CR4_PCIDE ); +if (IS_ENABLED (CONFIG_KAISER ) && kaiser_enabled) +WARN_ON_ONCE (this_cpu_read (cpu_tlbstate.cr4) &X86_CR4_PCIDE ); +#endif +flush_user_asid (this_cpu_read (cpu_tlbstate.loaded_mm_asid));/* * If current->mm == NULL then we borrow a mm * which may change during a task switch and
@@ -435,6 +461,8 @@ static inline void __native_flush_tlb_single(unsigned long addr)* early. */ if (!this_cpu_has (X86_FEATURE_INVPCID_SINGLE )) { +flush_user_asid (loaded_mm_asid); + asmvolatile ("invlpg (%0)" ::"r" (addr) :"memory" );return ; }
arch/x86/mm/init.c +3 -1
@@ -218,11 +218,13 @@ static void setup_pcid(void)* INVPCID. Just avoid using PCIDs at all if we * have KAISER and do not have INVPCID. */ +#if 0 if (!IS_ENABLED (CONFIG_X86_GLOBAL_PAGES ) && - !boot_cpu_has (X86_FEATURE_INVPCID )) { + kaiser_enabled && !boot_cpu_has (X86_FEATURE_INVPCID )) {setup_clear_cpu_cap (X86_FEATURE_PCID );return ; } +#endif /* * This can't be cr4_set_bits_and_update_boot() -- * the trampoline code can't handle CR4.PCIDE and
arch/x86/mm/tlb.c +2 -43
57 lines not on this page · raw message
Peter Zijlstra
maintainerRe: [PATCH 15/24] x86/mm: Allow flushing for future ASID switches
In reply to Andy LutomirskiQuoted 19 lines · Andy Lutomirski
Quoted 18 lines · Ingo Molnar
From: Dave Hansen <[email protected]>
If changing the page tables in such a way that an invalidation of all contexts (aka. PCIDs / ASIDs) is required, they can be actively invalidated by:
1. INVPCID for each PCID (works for single pages too).
2. Load CR3 with each PCID without the NOFLUSH bit set
3. Load CR3 with the NOFLUSH bit set for each and do INVLPG for each address.
But, none of these are really feasible since there are ~6 ASIDs (12 with KAISER) at the time that invalidation is required. Instead of actively invalidating them, invalidate the *current* context and also mark the
cpu_tlbstate_quickly_ to indicate future invalidation to be required.
Quoted 8 lines
Quoted 6 lines
At the next context-switch, look for this indicator ('
all_other_ctxs_invalid' being set) invalidate all of the cpu_tlbstate.ctxs[] entries.This ensures that any future context switches will do a full flush of the TLB, picking up the previous changes.
NAK.
So I can't say I'm a fan of this patch either, but I tried really hard to get rid of it, I can't really come up with anything better, see below.
Quoted 2 lines
We need to split up
__flush_tlb_one()into__flush_tlb_one()and__flush_tlb_one_kernel().
I prefer __flush_tlb_kernel_one() -- given we already flush_tlb_kernel_range().
So both __set_pte_vaddr() and __early_set_fixmap() are about setting up fixmap and would need to flush world. But this seems to be mostly __init code.
The kmmio one confuses me, I don't see how that is correct to just flush the local CPU map.
tlb_uv appears to be about user mappings.
The rest is about pure kernel maps afaict.
Quoted 9 lines
We've gotten away with having a single
function for both this long because we've never had PCID on and nonglobal kernel mappings around. So we're busted starting with "x86/mm/kaiser: Disable global pages by default with KAISER", which means that we have a potential corruption issue affecting anyone who tries to bisect the series.Then we need to make the kernel variant do something sane (presumably just call
__flush_tlb_allif we have PCID && !PGE).
(We don't support PCID && !PGE)
__flush_tlb_all() if PCID, because it needs to flush the thing from all kernel ASIDs, which this patch -- however nasty -- achieves best.
---
arch/x86/include/asm/pgtable_32.h +1 -1
@@ -61,7 +61,7 @@ void paging_init(void);#define kpte_clear_flush (ptep, vaddr) \ do { \ pte_clear(&init_mm, (vaddr), (ptep)); \ - __flush_tlb_one((vaddr)); \ + __flush_tlb_kernel_one((vaddr)); \ } while (0)#endif /* !__ASSEMBLY__ */
arch/x86/kernel/acpi/apei.c +1 -1
@@ -55,5 +55,5 @@ void arch_apei_report_mem_error(int sev, struct cper_sec_mem_err *mem_err)void arch_apei_flush_tlb_one (unsigned long addr) { -__flush_tlb_one (addr); +__flush_tlb_kernel_one (addr); }
arch/x86/mm/kmemcheck/kmemcheck.c +4 -4
@@ -101,7 +101,7 @@ int kmemcheck_show_addr(unsigned long address)return 0 ;set_pte (pte,__pte (pte_val (*pte) | _PAGE_PRESENT)); -__flush_tlb_one (address); +__flush_tlb_kernel_one (address);return 1 ; }
@@ -114,7 +114,7 @@ int kmemcheck_hide_addr(unsigned long address)return 0 ;set_pte (pte,__pte (pte_val (*pte) & ~_PAGE_PRESENT)); -__flush_tlb_one (address); +__flush_tlb_kernel_one (address);return 1 ; }
@@ -277,7 +277,7 @@ void kmemcheck_show_pages(struct page *p, unsigned int n)set_pte (pte,__pte (pte_val (*pte) | _PAGE_PRESENT));set_pte (pte,__pte (pte_val (*pte) & ~_PAGE_HIDDEN)); -__flush_tlb_one (address); +__flush_tlb_kernel_one (address); } }
@@ -303,7 +303,7 @@ void kmemcheck_hide_pages(struct page *p, unsigned int n)set_pte (pte,__pte (pte_val (*pte) & ~_PAGE_PRESENT));set_pte (pte,__pte (pte_val (*pte) | _PAGE_HIDDEN)); -__flush_tlb_one (address); +__flush_tlb_kernel_one (address); } }
Re: [PATCH 15/24] x86/mm: Allow flushing for future ASID switches
Quoted 8 lines · Peter Zijlstra
Quoted 7 lines · Andy Lutomirski
We've gotten away with having a single
function for both this long because we've never had PCID on and nonglobal kernel mappings around. So we're busted starting with "x86/mm/kaiser: Disable global pages by default with KAISER", which means that we have a potential corruption issue affecting anyone who tries to bisect the series.
Quoted 9 lines
Quoted 2 lines
Then we need to make the kernel variant do something sane (presumably just call
__flush_tlb_allif we have PCID && !PGE).(We don't support PCID && !PGE)
__flush_tlb_all()if PCID, because it needs to flush the thing from all kernel ASIDs, which this patch -- however nasty -- achieves best.
Brain fart there. What I meant was: the old code was wrong if PCID was on and the page being flushed wasn't GLOBAL. Which is what KAISER dies.
Peter Zijlstra
maintainerRe: [PATCH 15/24] x86/mm: Allow flushing for future ASID switches
In reply to Ingo Molnararch/x86/include/asm/tlbflush.h static inline void __native_flush_tlb_single(unsigned long addr) · line 373
Quoted 9 lines · Ingo Molnar
arch/x86/include/asm/tlbflush.h +3
-0@@ -338,24 +366,23 @@ static inline void __native_flush_tlb_single(unsigned long addr)static inline void __flush_tlb_all (void ) { +if (boot_cpu_has (X86_FEATURE_PGE )) {__flush_tlb_global (); + }else {__flush_tlb (); +tlb_flush_shared_nonglobals ();
I do however think this one is superfluous; if we do not have PGE we also do not have PCID and every CR3 switch flushes everything.
Quoted 2 lines
arch/x86/include/asm/tlbflush.h +1
-0+ } }
Dave Hansen
maintainerRe: [PATCH 15/24] x86/mm: Allow flushing for future ASID switches
Quoted 12 lines · Peter Zijlstra
arch/x86/include/asm/tlbflush.h static inline void __native_flush_tlb_single(unsigned long addr) · line 373
Quoted 9 lines · Ingo Molnar
arch/x86/include/asm/tlbflush.h +3
-0@@ -338,24 +366,23 @@ static inline void __native_flush_tlb_single(unsigned long addr)static inline void __flush_tlb_all (void ) { +if (boot_cpu_has (X86_FEATURE_PGE )) {__flush_tlb_global (); + }else {__flush_tlb (); +tlb_flush_shared_nonglobals ();I do however think this one is superfluous; if we do not have PGE we also do not have PCID and every CR3 switch flushes everything.
I tried to sprinkle these around at all the sites that did non-global kernel flushes. In the case that it's superfluous !KAISER, it's a noop anyway. In the (currently unsupported) case that we *do* need it, well, we need it.
It also makes it a bit more self-documenting that __flush_tlb() does not flush shared non-globals.
Peter Zijlstra
maintainerRe: [PATCH 15/24] x86/mm: Allow flushing for future ASID switches
Quoted 14 lines · Dave Hansen
Quoted 12 lines · Peter Zijlstra
arch/x86/include/asm/tlbflush.h static inline void __native_flush_tlb_single(unsigned long addr) · line 373
Quoted 9 lines · Ingo Molnar
arch/x86/include/asm/tlbflush.h +3
-0@@ -338,24 +366,23 @@ static inline void __native_flush_tlb_single(unsigned long addr)static inline void __flush_tlb_all (void ) { +if (boot_cpu_has (X86_FEATURE_PGE )) {__flush_tlb_global (); + }else {__flush_tlb (); +tlb_flush_shared_nonglobals ();I do however think this one is superfluous; if we do not have PGE we also do not have PCID and every CR3 switch flushes everything.
Quoted 4 lines
I tried to sprinkle these around at all the sites that did non-global kernel flushes. In the case that it's superfluous !KAISER, it's a noop anyway. In the (currently unsupported) case that we *do* need it, well, we need it.
I'm confused. When would we need it there?
Dave Hansen
maintainerRe: [PATCH 15/24] x86/mm: Allow flushing for future ASID switches
Quoted 15 lines · Peter Zijlstra
Quoted 14 lines · Dave Hansen
Quoted 12 lines · Peter Zijlstra
arch/x86/include/asm/tlbflush.h static inline void __native_flush_tlb_single(unsigned long addr) · line 373
Quoted 9 lines · Ingo Molnar
arch/x86/include/asm/tlbflush.h +3
-0@@ -338,24 +366,23 @@ static inline void __native_flush_tlb_single(unsigned long addr)static inline void __flush_tlb_all (void ) { +if (boot_cpu_has (X86_FEATURE_PGE )) {__flush_tlb_global (); + }else {__flush_tlb (); +tlb_flush_shared_nonglobals ();I do however think this one is superfluous; if we do not have PGE we also do not have PCID and every CR3 switch flushes everything.
Quoted 6 lines
Quoted 4 lines
I tried to sprinkle these around at all the sites that did non-global kernel flushes. In the case that it's superfluous !KAISER, it's a noop anyway. In the (currently unsupported) case that we *do* need it, well, we need it.
I'm confused. When would we need it there?
__flush_tlb() does a flushing CR3 write that flushes the current PCID. If we need other PCIDs flushed, we have to do it via the tlb_flush_shared_nonglobals() mechanism.
Does it matter today in practice? Nope, we never have that situation. But, it also doesn't _hurt_ to have that line there in any way.
Re: [PATCH 15/24] x86/mm: Allow flushing for future ASID switches
Quoted 21 lines · Dave Hansen
Quoted 20 lines · Peter Zijlstra
Quoted 18 lines · Dave Hansen
Quoted 12 lines · Peter Zijlstra
arch/x86/include/asm/tlbflush.h static inline void __native_flush_tlb_single(unsigned long addr) · line 373
Quoted 9 lines · Ingo Molnar
arch/x86/include/asm/tlbflush.h +3
-0@@ -338,24 +366,23 @@ static inline void __native_flush_tlb_single(unsigned long addr)static inline void __flush_tlb_all (void ) { +if (boot_cpu_has (X86_FEATURE_PGE )) {__flush_tlb_global (); + }else {__flush_tlb (); +tlb_flush_shared_nonglobals ();I do however think this one is superfluous; if we do not have PGE we also do not have PCID and every CR3 switch flushes everything.
I tried to sprinkle these around at all the sites that did non-global kernel flushes. In the case that it's superfluous !KAISER, it's a noop anyway. In the (currently unsupported) case that we *do* need it, well, we need it.
Quoted 8 lines
Quoted 1 line
I'm confused. When would we need it there?
__flush_tlb()does a flushing CR3 write that flushes the current PCID. If we need other PCIDs flushed, we have to do it via thetlb_flush_shared_nonglobals()mechanism.Does it matter today in practice? Nope, we never have that situation. But, it also doesn't _hurt_ to have that line there in any way.
Should it be tlb_flush_shared_nonglobals_if_kernel_and_user_pagetables_are_separate()?
The whole idea that we can get away with ambiguous functions like __flush_tlb() seems to be much less true with KAISER. I think we should maybe start getting rid of overly vague functions like this.
Dave Hansen
maintainerRe: [PATCH 15/24] x86/mm: Allow flushing for future ASID switches
Quoted 7 lines · Andy Lutomirski
Quoted 6 lines
__flush_tlb()does a flushing CR3 write that flushes the current PCID. If we need other PCIDs flushed, we have to do it via thetlb_flush_shared_nonglobals()mechanism.Does it matter today in practice? Nope, we never have that situation. But, it also doesn't _hurt_ to have that line there in any way.
Should it be
tlb_flush_shared_nonglobals_if_kernel_and_user_pagetables_are_separate()?
The separate page tables doesn't play into it as far as I can tell. the important thing is that you have "stuff" in some other *kernel* address space that you didn't flush.
Quoted 3 lines
The whole idea that we can get away with ambiguous functions like
__flush_tlb()seems to be much less true with KAISER. I think we should maybe start getting rid of overly vague functions like this.
Yeah, making the intent more explicit would be highly welcome.
Peter Zijlstra
maintainerRe: [PATCH 15/24] x86/mm: Allow flushing for future ASID switches
In reply to Andy LutomirskiQuoted 1 line · Andy Lutomirski
Should it be
tlb_flush_shared_nonglobals_if_kernel_and_user_pagetables_are_separate()?
Its effectively invpcid_flush_all_other() or something like that. Of course, its not invpcid based, so we should not name it such.
flush_asid_other() ?
Quoted 3 lines
The whole idea that we can get away with ambiguous functions like
__flush_tlb()seems to be much less true with KAISER. I think we should maybe start getting rid of overly vague functions like this.
There is a lot of cleanup to be done for sure. I had to actually draw pictures to untangle this stuff.
Re: [PATCH 15/24] x86/mm: Allow flushing for future ASID switches
Quoted 7 lines · Peter Zijlstra
Quoted 1 line · Andy Lutomirski
Should it be
tlb_flush_shared_nonglobals_if_kernel_and_user_pagetables_are_separate()?Its effectively
invpcid_flush_all_other()or something like that. Of course, its not invpcid based, so we should not name it such.
flush_asid_other()?
How about mark_other_asids_invalid()? It doesn't actually flush anything. And the caller could be:
if (!kernel_ptes_are_global()) {
/* nothing to do. INVLPG flushes global mappings for all ASIDs. */
} else {
/* There is no efficient way to invalidate a given VA for all ASIDs
simultaneously. */
mark_other_asids_invalid();
}
Peter Zijlstra
maintainerRe: [PATCH 15/24] x86/mm: Allow flushing for future ASID switches
In reply to Dave HansenQuoted 21 lines · Dave Hansen
Quoted 20 lines · Peter Zijlstra
Quoted 18 lines · Dave Hansen
Quoted 12 lines · Peter Zijlstra
arch/x86/include/asm/tlbflush.h static inline void __native_flush_tlb_single(unsigned long addr) · line 373
Quoted 9 lines · Ingo Molnar
arch/x86/include/asm/tlbflush.h +3
-0@@ -338,24 +366,23 @@ static inline void __native_flush_tlb_single(unsigned long addr)static inline void __flush_tlb_all (void ) { +if (boot_cpu_has (X86_FEATURE_PGE )) {__flush_tlb_global (); + }else {__flush_tlb (); +tlb_flush_shared_nonglobals ();I do however think this one is superfluous; if we do not have PGE we also do not have PCID and every CR3 switch flushes everything.
I tried to sprinkle these around at all the sites that did non-global kernel flushes. In the case that it's superfluous !KAISER, it's a noop anyway. In the (currently unsupported) case that we *do* need it, well, we need it.
Quoted 5 lines
Quoted 1 line
I'm confused. When would we need it there?
__flush_tlb()does a flushing CR3 write that flushes the current PCID. If we need other PCIDs flushed, we have to do it via thetlb_flush_shared_nonglobals()mechanism.
But the thing is, you _cannot_ have PCID enabled in that branch.
Quoted 2 lines
Does it matter today in practice? Nope, we never have that situation. But, it also doesn't _hurt_ to have that line there in any way.
Well, it confused the heck out of me.
Dave Hansen
maintainerRe: [PATCH 15/24] x86/mm: Allow flushing for future ASID switches
Quoted 4 lines · Peter Zijlstra
Quoted 3 lines
__flush_tlb()does a flushing CR3 write that flushes the current PCID. If we need other PCIDs flushed, we have to do it via thetlb_flush_shared_nonglobals()mechanism.But the thing is, you _cannot_ have PCID enabled in that branch.
Is there some hardware limitation that I'm missing?
Peter Zijlstra
maintainerRe: [PATCH 15/24] x86/mm: Allow flushing for future ASID switches
Quoted 7 lines · Dave Hansen
Quoted 4 lines · Peter Zijlstra
Quoted 3 lines
__flush_tlb()does a flushing CR3 write that flushes the current PCID. If we need other PCIDs flushed, we have to do it via thetlb_flush_shared_nonglobals()mechanism.But the thing is, you _cannot_ have PCID enabled in that branch.
Is there some hardware limitation that I'm missing?
No, but in setup_pcid() we explicit clear PCID if !PGE.
And as you said, there isn't actually any real hardware that has this combination, so who cares.
PATCH 16/24 x86/mm/kaiser: Use PCID feature to make user and kernel switches faster
In reply to Ingo MolnarFrom: Dave Hansen <[email protected]>
Short summary: Use x86 PCID feature to avoid flushing the TLB at all interrupts and syscalls. Speed them up. Makes context switches and TLB flushing slower.
Background:
KAISER keeps two copies of the page tables. Switches between the copies are performed by writing to the CR3 register. But, CR3 was really designed for context switches and writes to it also flush the entire TLB (modulo global pages). This TLB flush increases the cost of interrupts and context switches. For syscall-heavy microbenchmarks it can cut the rate of syscalls by 2/3.
The kernel recently gained support for and Intel CPU feature called Process Context IDentifiers (PCID) thanks to Andy Lutomirski. This feature is intended to allow you to switch between contexts without flushing the TLB.
Implementation:
PCIDs can be used to avoid flushing the TLB at kernel entry/exit. This is speeds up both interrupts and syscalls.
First, the kernel and userspace must be assigned different ASIDs. On entry from userspace, move over to the kernel page tables *and* ASID. On exit, restore the user page tables and ASID. Fortunately, the ASID is programmed via CR3, which is already being used to switch between the user and kernel page tables. This gives us convenient, one-stop shopping.
The CR3 write which is used to switch between processes provides all the TLB flushing normally required at context switch time. But, with KAISER, that CR3 write only flushes the current (kernel) ASID. An extra TLB flush operation is now required in order to flush the user ASID. This new instruction (INVPCID) is probably ~100 cycles, but this is done with the assumption that the time lost in context switches is more than made up for by lower cost of interrupts and syscalls.
Support:
PCIDs are generally available on Sandybridge and newer CPUs. However, the accompanying INVPCID instruction did not become available until Haswell (the ones with "v4", or called fourth-generation Core). This instruction allows non-current-PCID TLB entries to be flushed without switching CR3 and global pages to be flushed without a double MOV-to-CR4.
Without INVPCID, PCIDs are much harder to use. TLB invalidation gets much more onerous:
1. Every kernel TLB flush (even for a single page) requires an interrupts-off MOV-to-CR4 which is very expensive. This is because there is no way to flush a kernel address that might be loaded in *EVERY* PCID. Right now, there are "only" ~12 of these per-CPU, but that's too painful to use the MOV-to-CR3 to flush them. That leaves only the MOV-to-CR4.
2. Every userspace flush (even for a single page requires one of the following:
a. A pair of flushing (bit 63 clear) CR3 writes: one for
the kernel ASID and another for userspace.
b. A pair of non-flushing CR3 writes (bit 63 set) with the
flush done for each. For instance, what is currently a
single instruction without KAISER:
invpcid_flush_one(current_pcid, addr);
becomes this with KAISER:
invpcid_flush_one(current_kern_pcid, addr);
invpcid_flush_one(current_user_pcid, addr);
and this without INVPCID:
__native_flush_tlb_single(addr);
write_cr3(mm->pgd | current_user_pcid | NOFLUSH);
__native_flush_tlb_single(addr);
write_cr3(mm->pgd | current_kern_pcid | NOFLUSH);So, for now, fully disable PCIDs with KAISER when INVPCID is not available. This is fixable, but it's an optimization that can be performed later.
Hugh Dickins also points out that PCIDs really have two distinct use-cases in the context of KAISER. The first way they can be used is as "TLB preservation across context-switch", which is what Andy Lutomirksi's 4.14 PCID code does. They can also be used as a "KAISER syscall/interrupt accelerator". If we just use them to speed up syscall/interrupts (and ignore the context-switch TLB preservation), then the deficiency of not having INVPCID becomes much less onerous.
--- arch/x86/entry/calling.h | 25 +++-- arch/x86/include/asm/cpufeatures.h | 1 + arch/x86/include/asm/pgtable_types.h | 11 +++ arch/x86/include/asm/tlbflush.h | 137 +++++++++++++++++++++++----- arch/x86/include/uapi/asm/processor-flags.h | 3 +- arch/x86/kvm/x86.c | 3 +- arch/x86/mm/init.c | 75 ++++++++++----- arch/x86/mm/tlb.c | 66 +++++++++++++- 8 files changed, 261 insertions(+), 60 deletions(-)
arch/x86/entry/calling.h +18 -7
@@ -3,6 +3,7 @@#include <asm/unwind_hints.h> #include <asm/cpufeatures.h> #include <asm/page_types.h> +#include <asm/pgtable_types.h> /*
@@ -192,16 +193,20 @@ For 32-bit we have the following conventions - kernel is built with#ifdef CONFIG_KAISER /* KAISER PGDs are 8k. Flip bit 12 to switch between the two halves: */ -#define KAISER_SWITCH_MASK (1<<PAGE_SHIFT) +#define KAISER_SWITCH_PGTABLES_MASK (1<<PAGE_SHIFT) +#define KAISER_SWITCH_MASK (KAISER_SWITCH_PGTABLES_MASK|\ + (1<<X86_CR3_KAISER_SWITCH_BIT)) .macro ADJUST_KERNEL_CR3 reg:req -/* Clear "KAISER bit", point CR3 at kernel pagetables: */ - andq $(~KAISER_SWITCH_MASK), \reg + ALTERNATIVE "", "bts $63, \reg", X86_FEATURE_PCID + /* Clear PCID and "KAISER bit", point CR3 at kernel pagetables: */ + andq $(~KAISER_SWITCH_MASK), \reg .endm .macro ADJUST_USER_CR3 reg:req -/* Move CR3 up a page to the user page tables: */ - orq $(KAISER_SWITCH_MASK), \reg + ALTERNATIVE "", "bts $63, \reg", X86_FEATURE_PCID + /* Set user PCID bit, and move CR3 up a page to the user page tables: */ + orq $(KAISER_SWITCH_MASK), \reg .endm .macro SWITCH_TO_KERNEL_CR3 scratch_reg:req
@@ -220,8 +225,14 @@ For 32-bit we have the following conventions - kernel is built with movq %cr3, %r\scratch_reg movq %r\scratch_reg, \save_reg/* - * Is the switch bit zero? This means the address is - * up in real KAISER patches in a moment. +* Is the "switch mask" all zero? That means that both of +* these are zero: +* +* 1. The user/kernel PCID bit, and +* 2. The user/kernel "bit" that points CR3 to the +* bottom half of the 8k PGD +* +* That indicates a kernel CR3 value, not user/shadow. */ testq $(KAISER_SWITCH_MASK), %r\scratch_reg jz .Ldone_\@
arch/x86/include/asm/cpufeatures.h +1 -0
@@ -197,6 +197,7 @@#define X86_FEATURE_CAT_L3 ( 7*32+ 4)/* Cache Allocation Technology L3 */ #define X86_FEATURE_CAT_L2 ( 7*32+ 5)/* Cache Allocation Technology L2 */ #define X86_FEATURE_CDP_L3 ( 7*32+ 6)/* Code and Data Prioritization L3 */ +#define X86_FEATURE_INVPCID_SINGLE ( 7*32+ 7)/* Effectively INVPCID && CR4.PCIDE=1 */ #define X86_FEATURE_HW_PSTATE ( 7*32+ 8)/* AMD HW-PState */ #define X86_FEATURE_PROC_FEEDBACK ( 7*32+ 9)/* AMD ProcFeedbackInterface */
arch/x86/include/asm/pgtable_types.h +11 -0
@@ -140,6 +140,17 @@ _PAGE_SOFT_DIRTY)#define _HPAGE_CHG_MASK (_PAGE_CHG_MASK | _PAGE_PSE) +/* The ASID is the lower 12 bits of CR3 */ +#define X86_CR3_PCID_ASID_MASK (_AC((1<<12)-1, UL)) + +/* Mask for all the PCID-related bits in CR3: */ +#define X86_CR3_PCID_MASK (X86_CR3_PCID_NOFLUSH | X86_CR3_PCID_ASID_MASK) + +/* Make sure this is only usable in KAISER #ifdef'd code: */ +#ifdef CONFIG_KAISER +#define X86_CR3_KAISER_SWITCH_BIT 11 +#endif +/* * The cache modes defined here are used to translate between pure SW usage * and the HW defined cache mode bits and/or PAT entries.
arch/x86/include/asm/tlbflush.h +113 -24
184 lines not on this page · raw message
arch/x86/include/uapi/asm/processor-flags.h +2 -1
@@ -78,7 +78,8 @@#define X86_CR3_PWT _BITUL(X86_CR3_PWT_BIT)#define X86_CR3_PCD_BIT 4/* Page Cache Disable */ #define X86_CR3_PCD _BITUL(X86_CR3_PCD_BIT) -#define X86_CR3_PCID_MASK _AC(0x00000fff,UL)/* PCID Mask */ +#define X86_CR3_PCID_NOFLUSH_BIT 63/* Preserve old PCID */ +#define X86_CR3_PCID_NOFLUSH _BITULL(X86_CR3_PCID_NOFLUSH_BIT)/* * Intel CPU features in CR4
arch/x86/kvm/x86.c +2 -1
@@ -805,7 +805,8 @@ int kvm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)return 1 ;/* PCID can not be enabled when cr3[11:0]!=000H or EFER.LMA=0 */ -if ((kvm_read_cr3 (vcpu) &X86_CR3_PCID_MASK ) || !is_long_mode (vcpu)) +if ((kvm_read_cr3 (vcpu) &X86_CR3_PCID_ASID_MASK ) || + !is_long_mode (vcpu))return 1 ; }
arch/x86/mm/init.c +50 -25
84 lines not on this page · raw message
arch/x86/mm/tlb.c +64 -2
84 lines not on this page · raw message
Signature · 1 line
2.14.1
Re: [PATCH 16/24] x86/mm/kaiser: Use PCID feature to make user and kernel switches faster
Quoted 5 lines · Ingo Molnar
From: Dave Hansen <[email protected]>
Short summary: Use x86 PCID feature to avoid flushing the TLB at all interrupts and syscalls. Speed them up. Makes context switches and TLB flushing slower.
I suspect that, if we actually did it right (by doing a deferred usermode flush when we switch CR3), it wouldn't make context switches or TLB flushing slower.
arch/x86/mm/tlb.c static void choose_new_asid(struct mm_struct *next, u64 next_tlb_gen, · line 137
Quoted 9 lines
arch/x86/mm/tlb.c +9
-0+/* +* On systems with PCIDs, but no INVPCID, the only +* way to flush a PCID is a CR3 write. Note that +* we use the kernel page tables with the *user* +* ASID here. +*/ +unsigned long user_asid_flush_cr3; + user_asid_flush_cr3 =build_cr3 (pgd,user_asid (kern_asid)); +write_cr3 (user_asid_flush_cr3);
This is wrong. If we could atomically switch CR3 and switch it back without any speculative fills in the mean time, we might be okay, but that's not what's happening. We could be filling the TLB with usermode-tagged kernel entries, which is a big no-no.
(And I'm ignoring the fact that this code seems to have forgotten the "switch back" part.)
arch/x86/mm/tlb.c static void choose_new_asid(struct mm_struct *next, u64 next_tlb_gen, · line 142
Quoted 5 lines
arch/x86/mm/tlb.c +5
-0+/* +* We do not use PCIDs with KAISER unless we also +* have INVPCID. Getting here is unexpected. +*/ +WARN_ON_ONCE (1 );
Well that's a bummer.
Dave Hansen
maintainerRe: [PATCH 16/24] x86/mm/kaiser: Use PCID feature to make user and kernel switches faster
Quoted 10 lines · Andy Lutomirski
Quoted 5 lines · Ingo Molnar
From: Dave Hansen <[email protected]>
Short summary: Use x86 PCID feature to avoid flushing the TLB at all interrupts and syscalls. Speed them up. Makes context switches and TLB flushing slower.
I suspect that, if we actually did it right (by doing a deferred usermode flush when we switch CR3), it wouldn't make context switches or TLB flushing slower.
Totally agree.
Quoted 10 lines
arch/x86/mm/tlb.c static void choose_new_asid(struct mm_struct *next, u64 next_tlb_gen, · line 137
Quoted 9 lines
arch/x86/mm/tlb.c +9
-0+/* +* On systems with PCIDs, but no INVPCID, the only +* way to flush a PCID is a CR3 write. Note that +* we use the kernel page tables with the *user* +* ASID here. +*/ +unsigned long user_asid_flush_cr3; + user_asid_flush_cr3 =build_cr3 (pgd,user_asid (kern_asid)); +write_cr3 (user_asid_flush_cr3);
Quoted 4 lines
This is wrong. If we could atomically switch CR3 and switch it back without any speculative fills in the mean time, we might be okay, but that's not what's happening. We could be filling the TLB with usermode-tagged kernel entries, which is a big no-no.
This hunk should disappear. It was an attempt to support PCIDs without INVPCID. But, as you point out, that needs even more infrastructure to
support perfectly. It's yet another reason not to support that
configuration for now.
Just to make sure I understand your concern (because I'm sure we'll get back to this soon): this code is functionally correct: it will ensure that TLB entries in the user ASID _are_ flushed.
But, I think what you're saying is that any TLB fills between this and the reload of the kernel ASID might fill parts of the kernel page tables into the TLB (with the user ASID), and _those_ could be used to weaken KASLR. I agree, that's theoretically problematic.
Am I missing anything?
PATCH 17/24 x86/mm/kaiser: Disable native VSYSCALL
In reply to Ingo MolnarFrom: Dave Hansen <[email protected]>
The KAISER code attempts to "poison" the user portion of the kernel page tables. It detects entries that it wants that it wants to poison in two ways:
* Looking for addresses >= PAGE_OFFSET
* Looking for entries without _PAGE_USER set
But, to allow the _PAGE_USER check to work, it must never be set on init_mm entries, and an earlier patch in this series ensured that it will never be set.
The VDSO is at a address >= PAGE_OFFSET and it is also mapped by init_mm. Because of the earlier, KAISER-enforced restriction, _PAGE_USER is never set which makes the VDSO unreadable to userspace.
This makes the "NATIVE" case totally unusable since userspace can not even see the memory any more. Disable it whenever KAISER is enabled.
Also add some help text about how KAISER might affect the emulation case as well.
--- arch/x86/Kconfig | 8 ++++++++ 1 file changed, 8 insertions(+)
arch/x86/Kconfig +8 -0
@@ -2249,6 +2249,9 @@ choice config LEGACY_VSYSCALL_NATIVE bool "Native" + # The VSYSCALL page comes from the kernel page tables + # and is not available when KAISER is enabled. + depends on ! KAISER help Actual executable code is located in the fixed vsyscall address mapping, implementing time() efficiently. Since
@@ -2266,6 +2269,11 @@ choice exploits. This configuration is recommended when userspace still uses the vsyscall area. + When KAISER is enabled, the vsyscall area will become + unreadable. This emulation option still works, but KAISER + will make it harder to do things like trace code using the + emulation. + config LEGACY_VSYSCALL_NONE bool "None" help
Signature · 1 line
2.14.1
PATCH 18/24 x86/mm/kaiser: Add Kconfig
In reply to Ingo MolnarFrom: Dave Hansen <[email protected]>
Finally allow CONFIG_KAISER to be enabled.
PARAVIRT generally requires that the kernel not manage its own page tables. It also means that the hypervisor and kernel must agree wholeheartedly about what format the page tables are in and what they contain. KAISER, unfortunately, changes the rules and they can not be used together.
I've seen conflicting feedback from maintainers lately about whether they want the Kconfig magic to go first or last in a patch series. It's going last here because the partially-applied series leads to kernels that can not boot in a bunch of cases. I did a run through the entire series with CONFIG_KAISER=y to look for build errors, though.
Note from Hugh Dickins on why it depends on SMP:
It is absurd that KAISER should depend on SMP, but apparently nobody has tried a UP build before: which breaks on implicit declaration of function 'per_cpu_offset' in arch/x86/mm/kaiser.c.
Now, you would expect that to be trivially fixed up; but looking at the System.map when that block is #ifdef'ed out of kaiser_init(), I see that in a UP build __per_cpu_user_mapped_end is precisely at __per_cpu_user_mapped_start, and the items carefully gathered into that section for user-mapping on SMP, dispersed elsewhere on UP.
--- security/Kconfig | 10 ++++++++++ 1 file changed, 10 insertions(+)
security/Kconfig +10 -0
@@ -54,6 +54,16 @@ config SECURITY_NETWORK implement socket and networking access controls. If you are unsure how to answer this question, answer N. +config KAISER + bool "Remove the kernel mapping in user mode" + depends on X86_64 && SMP && !PARAVIRT + help + This feature reduces the number of hardware side channels by + ensuring that the majority of kernel addresses are not mapped + into userspace. + + See Documentation/x86/kaiser.txt for more details. + config SECURITY_INFINIBAND bool "Infiniband Security Hooks" depends on SECURITY && INFINIBAND
Signature · 1 line
2.14.1
PATCH 19/24 x86/mm/kaiser: Respect disabled CPU features
In reply to Ingo MolnarFrom: Thomas Gleixner <[email protected]>
PAGE_NX and PAGE_GLOBAL might not be supported, or migth be disabled on the command line, but Kaiser sets them unconditionally.
Add proper protection against that.
--- arch/x86/include/asm/pgtable_64.h | 3 ++- arch/x86/mm/kaiser.c | 12 +++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-)
arch/x86/include/asm/pgtable_64.h +2 -1
@@ -222,7 +222,8 @@ static inline pgd_t kaiser_set_shadow_pgd(pgd_t *pgdp, pgd_t pgd)* wrong CR3 value, userspace will crash * instead of running. */ - pgd.pgd |= _PAGE_NX; +if (__supported_pte_mask & _PAGE_NX) + pgd.pgd |= _PAGE_NX; } }else if (pgd_userspace_access (*pgdp)) {/*
arch/x86/mm/kaiser.c +11 -1
@@ -42,6 +42,8 @@#define KAISER_WALK_ATOMIC 0x1 +static pteval_t kaiser_pte_mask__ro_after_init = ~(_PAGE_NX | _PAGE_GLOBAL); +/* * At runtime, the only things we map are some things for CPU * hotplug, and stacks for new processes. No two CPUs will ever
@@ -244,11 +246,14 @@ static pte_t *kaiser_shadow_pagetable_walk(unsigned long address,int kaiser_add_user_map (const void *__start_addr,unsigned long size,unsigned long flags) { -pte_t *pte;unsigned long start_addr = (unsigned long )__start_addr;unsigned long address = start_addr &PAGE_MASK ;unsigned long end_addr =PAGE_ALIGN (start_addr + size);unsigned long target_address; +pte_t *pte; + +/* Clear not supported bits */ + flags &= kaiser_pte_mask;for (; address < end_addr; address +=PAGE_SIZE ) { target_address =get_pa_from_kernel_map (address);
@@ -308,6 +313,11 @@ static void __init kaiser_init_all_pgds(void)pgd_t *pgd;int i; +if (__supported_pte_mask & _PAGE_NX) + kaiser_pte_mask |= _PAGE_NX; +if (boot_cpu_has (X86_FEATURE_PGE )) + kaiser_pte_mask |= _PAGE_GLOBAL; + pgd =kernel_to_shadow_pgdp (pgd_offset_k (0UL ));for (i =PTRS_PER_PGD /2 ; i <PTRS_PER_PGD ; i++) {/*
Signature · 1 line
2.14.1
PATCH 20/24 x86/mm/kaiser: Simplify disabling of global pages
In reply to Ingo MolnarFrom: Thomas Gleixner <[email protected]>
The current way of disabling global pages at compile time prevents boot time disabling of Kaiser and creates unnecessary indirections.
Global pages can be supressed by __supported_pte_mask as well. The shadow mappings set PAGE_GLOBAL for the minimal kernel mappings which are required for entry/exit. These mappings are set up manually so the filtering does not take place.
--- arch/x86/include/asm/pgtable_types.h | 16 +--------------- arch/x86/mm/init.c | 13 ++++++++++--- arch/x86/mm/pageattr.c | 16 ++++++++-------- 3 files changed, 19 insertions(+), 26 deletions(-)
arch/x86/include/asm/pgtable_types.h +1 -15
@@ -191,23 +191,9 @@ enum page_cache_mode {#define PAGE_READONLY_EXEC __pgprot(_PAGE_PRESENT | _PAGE_USER | \ _PAGE_ACCESSED) -/* -* Disable global pages for anything using the default -* __PAGE_KERNEL* macros. -* -* PGE will still be enabled and _PAGE_GLOBAL may still be used carefully -* for a few selected kernel mappings which must be visible to userspace, -* when KAISER is enabled, like the entry/exit code and data. -*/ -#ifdef CONFIG_KAISER -#define __PAGE_KERNEL_GLOBAL 0 -#else -#define __PAGE_KERNEL_GLOBAL _PAGE_GLOBAL -#endif -#define __PAGE_KERNEL_EXEC \ (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED | \ - __PAGE_KERNEL_GLOBAL) + _PAGE_GLOBAL)#define __PAGE_KERNEL (__PAGE_KERNEL_EXEC | _PAGE_NX)#define __PAGE_KERNEL_RO (__PAGE_KERNEL & ~_PAGE_RW)
arch/x86/mm/init.c +10 -3
@@ -161,6 +161,13 @@ struct map_range {static int page_size_mask; +static void enable_global_pages (void ) +{ +#ifndef CONFIG_KAISER + __supported_pte_mask |= _PAGE_GLOBAL; +#endif +} +static void __init probe_page_size_mask (void ) {/*
@@ -179,11 +186,11 @@ static void __init probe_page_size_mask(void)cr4_set_bits_and_update_boot (X86_CR4_PSE );/* Enable PGE if available */ + __supported_pte_mask |= _PAGE_GLOBAL;if (boot_cpu_has (X86_FEATURE_PGE )) {cr4_set_bits_and_update_boot (X86_CR4_PGE ); - __supported_pte_mask |= _PAGE_GLOBAL; - }else - __supported_pte_mask &= ~_PAGE_GLOBAL; +enable_global_pages (); + }/* Enable 1 GB linear kernel mappings if available: */ if (direct_gbpages &&boot_cpu_has (X86_FEATURE_GBPAGES )) {
arch/x86/mm/pageattr.c +8 -8
@@ -585,9 +585,9 @@ try_preserve_large_page(pte_t *kpte, unsigned long address,* for the ancient hardware that doesn't support it. */ if (pgprot_val (req_prot) & _PAGE_PRESENT) -pgprot_val (req_prot) |= _PAGE_PSE | __PAGE_KERNEL_GLOBAL; +pgprot_val (req_prot) |= _PAGE_PSE | _PAGE_GLOBAL;else -pgprot_val (req_prot) &= ~(_PAGE_PSE | __PAGE_KERNEL_GLOBAL); +pgprot_val (req_prot) &= ~(_PAGE_PSE | _PAGE_GLOBAL); req_prot =canon_pgprot (req_prot);
@@ -705,9 +705,9 @@ __split_large_page(struct cpa_data *cpa, pte_t *kpte, unsigned long address,* for the ancient hardware that doesn't support it. */ if (pgprot_val (ref_prot) & _PAGE_PRESENT) -pgprot_val (ref_prot) |= __PAGE_KERNEL_GLOBAL; +pgprot_val (ref_prot) |= _PAGE_GLOBAL;else -pgprot_val (ref_prot) &= ~__PAGE_KERNEL_GLOBAL; +pgprot_val (ref_prot) &= ~_PAGE_GLOBAL;/* * Get the target pfn from the original entry:
@@ -938,9 +938,9 @@ static void populate_pte(struct cpa_data *cpa,* support it. */ if (pgprot_val (pgprot) & _PAGE_PRESENT) -pgprot_val (pgprot) |= __PAGE_KERNEL_GLOBAL; +pgprot_val (pgprot) |= _PAGE_GLOBAL;else -pgprot_val (pgprot) &= ~__PAGE_KERNEL_GLOBAL; +pgprot_val (pgprot) &= ~_PAGE_GLOBAL; pgprot =canon_pgprot (pgprot);
@@ -1242,9 +1242,9 @@ static int __change_page_attr(struct cpa_data *cpa, int primary)* support it. */ if (pgprot_val (new_prot) & _PAGE_PRESENT) -pgprot_val (new_prot) |= __PAGE_KERNEL_GLOBAL; +pgprot_val (new_prot) |= _PAGE_GLOBAL;else -pgprot_val (new_prot) &= ~__PAGE_KERNEL_GLOBAL; +pgprot_val (new_prot) &= ~_PAGE_GLOBAL;/* * We need to keep the pfn from the existing PTE,
Signature · 1 line
2.14.1
PATCH 21/24 x86/mm/dump_pagetables: Check Kaiser shadow page table for WX pages
In reply to Ingo MolnarFrom: Thomas Gleixner <[email protected]>
ptdump_walk_pgd_level_checkwx() checks the kernel page table for WX pages, but does not check the Kaiser shadow page table.
Restructure the code so that dmesg output is selected by an explicit argument and not implicit via checking the pgd argument for !NULL. Add the check for the shadow page table.
--- arch/x86/include/asm/pgtable.h | 1 + arch/x86/mm/debug_pagetables.c | 2 +- arch/x86/mm/dump_pagetables.c | 27 ++++++++++++++++++++++----- 3 files changed, 24 insertions(+), 6 deletions(-)
arch/x86/include/asm/pgtable.h +1 -0
@@ -28,6 +28,7 @@ extern pgd_t early_top_pgt[PTRS_PER_PGD];int __init __early_make_pgtable (unsigned long address,pmdval_t pmd);void ptdump_walk_pgd_level (struct seq_file *m,pgd_t *pgd); +void ptdump_walk_pgd_level_debugfs (struct seq_file *m,pgd_t *pgd);void ptdump_walk_pgd_level_checkwx (void );#ifdef CONFIG_DEBUG_WX
arch/x86/mm/debug_pagetables.c +1 -1
@@ -5,7 +5,7 @@static int ptdump_show (struct seq_file *m,void *v) { -ptdump_walk_pgd_level (m,NULL ); +ptdump_walk_pgd_level_debugfs (m,NULL );return 0 ; }
arch/x86/mm/dump_pagetables.c +22 -5
@@ -447,7 +447,7 @@ static inline bool is_hypervisor_range(int idx) }static void ptdump_walk_pgd_level_core (struct seq_file *m,pgd_t *pgd, -bool checkwx) +bool checkwx,bool dmesg) {#ifdef CONFIG_X86_64 pgd_t *start = (pgd_t *) &init_top_pgt;
@@ -460,7 +460,7 @@ static void ptdump_walk_pgd_level_core(struct seq_file *m, pgd_t *pgd,if (pgd) { start = pgd; - st.to_dmesg = true; + st.to_dmesg = dmesg; } st.check_wx = checkwx;
@@ -498,13 +498,30 @@ static void ptdump_walk_pgd_level_core(struct seq_file *m, pgd_t *pgd,void ptdump_walk_pgd_level (struct seq_file *m,pgd_t *pgd) { -ptdump_walk_pgd_level_core (m, pgd, false); +ptdump_walk_pgd_level_core (m, pgd, false, true); +} + +void ptdump_walk_pgd_level_debugfs (struct seq_file *m,pgd_t *pgd) +{ +ptdump_walk_pgd_level_core (m, pgd, false, false); +} +EXPORT_SYMBOL_GPL (ptdump_walk_pgd_level_debugfs); + +void ptdump_walk_shadow_pgd_level_checkwx (void ) +{ +#ifdef CONFIG_KAISER +pgd_t *pgd = (pgd_t *) &init_top_pgt; + +pr_info ("x86/mm: Checking shadow page tables\n" ); + pgd +=PTRS_PER_PGD ; +ptdump_walk_pgd_level_core (NULL , pgd, true, false); +#endif } -EXPORT_SYMBOL_GPL (ptdump_walk_pgd_level);void ptdump_walk_pgd_level_checkwx (void ) { -ptdump_walk_pgd_level_core (NULL ,NULL , true); +ptdump_walk_pgd_level_core (NULL ,NULL , true, false); +ptdump_walk_shadow_pgd_level_checkwx (); }static int __init pt_dump_init (void )
Signature · 1 line
2.14.1
PATCH 22/24 x86/mm/debug_pagetables: Allow dumping current pagetables
In reply to Ingo MolnarFrom: Thomas Gleixner <[email protected]>
Add two debugfs files which allow to dump the pagetable of the current task.
current_page_tables_knl dumps the regular page table. This is the page table which is normally shared between kernel and user space. If Kaiser is enabled this is the kernel space mapping.
If Kaiser is enabled the second file, current_page_tables_usr, dumps the user space page table.
These files allow to verify the resulting page tables for Kaiser, but even in the non Kaiser case its useful to be able to inspect user space page tables of current for debugging purposes.
--- arch/x86/include/asm/pgtable.h | 2 +- arch/x86/mm/debug_pagetables.c | 81 ++++++++++++++++++++++++++++++++++++++---- arch/x86/mm/dump_pagetables.c | 4 ++- 3 files changed, 79 insertions(+), 8 deletions(-)
arch/x86/include/asm/pgtable.h +1 -1
@@ -28,7 +28,7 @@ extern pgd_t early_top_pgt[PTRS_PER_PGD];int __init __early_make_pgtable (unsigned long address,pmdval_t pmd);void ptdump_walk_pgd_level (struct seq_file *m,pgd_t *pgd); -void ptdump_walk_pgd_level_debugfs (struct seq_file *m,pgd_t *pgd); +void ptdump_walk_pgd_level_debugfs (struct seq_file *m,pgd_t *pgd,bool shadow);void ptdump_walk_pgd_level_checkwx (void );#ifdef CONFIG_DEBUG_WX
arch/x86/mm/debug_pagetables.c +75 -6
103 lines not on this page · raw message
arch/x86/mm/dump_pagetables.c +3 -1
@@ -501,8 +501,10 @@ void ptdump_walk_pgd_level(struct seq_file *m, pgd_t *pgd)ptdump_walk_pgd_level_core (m, pgd, false, true); } -void ptdump_walk_pgd_level_debugfs (struct seq_file *m,pgd_t *pgd) +void ptdump_walk_pgd_level_debugfs (struct seq_file *m,pgd_t *pgd,bool shadow) { +if (shadow) + pgd +=PTRS_PER_PGD ;ptdump_walk_pgd_level_core (m, pgd, false, false); }EXPORT_SYMBOL_GPL (ptdump_walk_pgd_level_debugfs);
Signature · 1 line
2.14.1
PATCH 23/24 x86/mm/kaiser: Add boot time disable switch
In reply to Ingo MolnarFrom: Thomas Gleixner <[email protected]>
Kaiser comes with overhead. The most expensive part is the CR3 switching in the entry code.
Add a command line parameter which allows to disable Kaiser at boot time.
Most code paths simply check a variable, but the entry code uses a static branch. The other code paths cannot use a static branch because they are used before jump label patching is possible. Not an issue as the code paths are not so performance sensitive as the entry/exit code.
This makes Kaiser depend on JUMP_LABEL and on a GCC which supports it, but that's a resonable requirement.
The PGD allocation is still 8k when CONFIG_KAISER is enabled. This can be addressed on top of this.
--- arch/x86/entry/calling.h | 7 +++++++ arch/x86/include/asm/kaiser.h | 10 ++++++++++ arch/x86/include/asm/pgtable_64.h | 6 ++++++ arch/x86/mm/dump_pagetables.c | 5 ++++- arch/x86/mm/init.c | 7 ++++--- arch/x86/mm/kaiser.c | 30 ++++++++++++++++++++++++++++++ security/Kconfig | 2 +- 7 files changed, 62 insertions(+), 5 deletions(-)
arch/x86/entry/calling.h +7 -0
@@ -210,18 +210,23 @@ For 32-bit we have the following conventions - kernel is built with .endm .macro SWITCH_TO_KERNEL_CR3 scratch_reg:req + STATIC_JUMP_IF_FALSE .Lend_\@, kaiser_enabled_key, def=1 mov %cr3, \scratch_reg ADJUST_KERNEL_CR3 \scratch_reg mov \scratch_reg, %cr3 +.Lend_\@: .endm .macro SWITCH_TO_USER_CR3 scratch_reg:req + STATIC_JUMP_IF_FALSE .Lend_\@, kaiser_enabled_key, def=1 mov %cr3, \scratch_reg ADJUST_USER_CR3 \scratch_reg mov \scratch_reg, %cr3 +.Lend_\@: .endm .macro SAVE_AND_SWITCH_TO_KERNEL_CR3 scratch_reg:req save_reg:req + STATIC_JUMP_IF_FALSE .Ldone_\@, kaiser_enabled_key, def=1 movq %cr3, %r\scratch_reg movq %r\scratch_reg, \save_reg/*
@@ -244,11 +249,13 @@ For 32-bit we have the following conventions - kernel is built with .endm .macro RESTORE_CR3 save_reg:req + STATIC_JUMP_IF_FALSE .Lend_\@, kaiser_enabled_key, def=1/* * The CR3 write could be avoided when not changing its value, * but would require a CR3 read *and* a scratch register. */ movq \save_reg, %cr3 +.Lend_\@: .endm #else /* CONFIG_KAISER=n: */
arch/x86/include/asm/kaiser.h +10 -0
@@ -56,6 +56,16 @@ extern void kaiser_remove_mapping(unsigned long start, unsigned long size);*/ extern void kaiser_init (void ); +/* True if kaiser is enabled at boot time */ +extern struct static_key_true kaiser_enabled_key; +extern bool kaiser_enabled; +extern void kaiser_check_cmdline (void ); + +#else /* CONFIG_KAISER */ + +#define kaiser_enabled (false) +static inline void kaiser_check_cmdline (void ) { } +#endif #endif /* __ASSEMBLY__ */
arch/x86/include/asm/pgtable_64.h +6 -0
@@ -175,6 +175,9 @@ static inline p4d_t *shadow_to_kernel_p4dp(p4d_t *p4dp) {return ptr_clear_bit (p4dp,KAISER_PGTABLE_SWITCH_BIT ); } + +extern bool kaiser_enabled; +#endif /* CONFIG_KAISER */ /*
@@ -208,6 +211,9 @@ static inline bool pgd_userspace_access(pgd_t pgd)static inline pgd_t kaiser_set_shadow_pgd (pgd_t *pgdp,pgd_t pgd) {#ifdef CONFIG_KAISER +if (!kaiser_enabled) +return pgd; +if (pgd_userspace_access (pgd)) {if (pgdp_maps_userspace (pgdp)) {/*
arch/x86/mm/dump_pagetables.c +4 -1
@@ -20,6 +20,7 @@#include <linux/seq_file.h> #include <asm/pgtable.h> +#include <asm/kaiser.h> /* * The dumper groups pagetable entries of the same type into one, and for
@@ -503,7 +504,7 @@ void ptdump_walk_pgd_level(struct seq_file *m, pgd_t *pgd)void ptdump_walk_pgd_level_debugfs (struct seq_file *m,pgd_t *pgd,bool shadow) { -if (shadow) +if (shadow && kaiser_enabled) pgd +=PTRS_PER_PGD ;ptdump_walk_pgd_level_core (m, pgd, false, false); }
@@ -514,6 +515,8 @@ void ptdump_walk_shadow_pgd_level_checkwx(void)#ifdef CONFIG_KAISER pgd_t *pgd = (pgd_t *) &init_top_pgt; +if (!kaiser_enabled) +return ;pr_info ("x86/mm: Checking shadow page tables\n" ); pgd +=PTRS_PER_PGD ;ptdump_walk_pgd_level_core (NULL , pgd, true, false);
arch/x86/mm/init.c +4 -3
@@ -20,6 +20,7 @@#include <asm/kaslr.h> #include <asm/hypervisor.h> #include <asm/cpufeature.h> +#include <asm/kaiser.h> /* * We need to define the tracepoints somewhere, and tlb.c
@@ -163,9 +164,8 @@ static int page_size_mask;static void enable_global_pages (void ) { -#ifndef CONFIG_KAISER - __supported_pte_mask |= _PAGE_GLOBAL; -#endif +if (!kaiser_enabled) + __supported_pte_mask |= _PAGE_GLOBAL; }static void __init probe_page_size_mask (void )
@@ -656,6 +656,7 @@ void __init init_mem_mapping(void) {unsigned long end; +kaiser_check_cmdline ();probe_page_size_mask ();setup_pcid ();
arch/x86/mm/kaiser.c +30 -0
@@ -34,6 +34,7 @@#include <linux/mm.h> #include <linux/uaccess.h> +#include <asm/cmdline.h> #include <asm/kaiser.h> #include <asm/pgtable.h> #include <asm/pgalloc.h>
@@ -44,6 +45,16 @@static pteval_t kaiser_pte_mask__ro_after_init = ~(_PAGE_NX | _PAGE_GLOBAL); +/* Global flag for boot time kaiser enable/disable */ +bool kaiser_enabled__ro_after_init = true; +DEFINE_STATIC_KEY_TRUE (kaiser_enabled_key); + +void __init kaiser_check_cmdline (void ) +{ +if (cmdline_find_option_bool (boot_command_line,"nokaiser" )) + kaiser_enabled = false; +} +/* * At runtime, the only things we map are some things for CPU * hotplug, and stacks for new processes. No two CPUs will ever
@@ -252,6 +263,9 @@ int kaiser_add_user_map(const void *__start_addr, unsigned long size,unsigned long target_address;pte_t *pte; +if (!kaiser_enabled) +return 0 ; +/* Clear not supported bits */ flags &= kaiser_pte_mask;
@@ -402,6 +416,9 @@ void __init kaiser_init(void) {int cpu; +if (!kaiser_enabled) +return ; +kaiser_init_all_pgds ();for_each_possible_cpu (cpu) {
@@ -436,6 +453,16 @@ void __init kaiser_init(void)kaiser_add_mapping_cpu_entry (0 ); } +static int __init kaiser_boottime_control (void ) +{ +if (!kaiser_enabled) { +static_branch_disable (&kaiser_enabled_key); +pr_info ("kaiser: Disabled on command line\n" ); + } +return 0 ; +} +subsys_initcall (kaiser_boottime_control); +int kaiser_add_mapping (unsigned long addr,unsigned long size,unsigned long flags) {
@@ -446,6 +473,9 @@ void kaiser_remove_mapping(unsigned long start, unsigned long size) {unsigned long addr; +if (!kaiser_enabled) +return ; +/* The shadow page tables always use small pages: */ for (addr = start; addr < start + size; addr +=PAGE_SIZE ) {/*
security/Kconfig +1 -1
@@ -56,7 +56,7 @@ config SECURITY_NETWORK config KAISER bool "Remove the kernel mapping in user mode" - depends on X86_64 && SMP && !PARAVIRT + depends on X86_64 && SMP && !PARAVIRT && JUMP_LABEL help This feature reduces the number of hardware side channels by ensuring that the majority of kernel addresses are not mapped
Signature · 1 line
2.14.1
PATCH 24/24 x86/mm/kaiser: Use the other page_table_lock pattern
In reply to Ingo MolnarFrom: Peter Zijlstra <[email protected]>
Use the other page_table_lock pattern; this removes the free from under the lock, reducing worst case hold times and makes it a leaf lock.
--- arch/x86/mm/kaiser.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-)
arch/x86/mm/kaiser.c +15 -9
@@ -196,11 +196,13 @@ static pte_t *kaiser_shadow_pagetable_walk(unsigned long address,return NULL ;spin_lock (&shadow_table_allocation_lock); -if (p4d_none (*p4d)) +if (p4d_none (*p4d)) {set_p4d (p4d,__p4d (_KERNPG_TABLE |__pa (new_pud_page))); -else -free_page (new_pud_page); + new_pud_page =0 ; + }spin_unlock (&shadow_table_allocation_lock); +if (new_pud_page) +free_page (new_pud_page); } pud =pud_offset (p4d, address);
@@ -215,11 +217,13 @@ static pte_t *kaiser_shadow_pagetable_walk(unsigned long address,return NULL ;spin_lock (&shadow_table_allocation_lock); -if (pud_none (*pud)) +if (pud_none (*pud)) {set_pud (pud,__pud (_KERNPG_TABLE |__pa (new_pmd_page))); -else -free_page (new_pmd_page); + new_pmd_page =0 ; + }spin_unlock (&shadow_table_allocation_lock); +if (new_pmd_page) +free_page (new_pmd_page); } pmd =pmd_offset (pud, address);
@@ -234,11 +238,13 @@ static pte_t *kaiser_shadow_pagetable_walk(unsigned long address,return NULL ;spin_lock (&shadow_table_allocation_lock); -if (pmd_none (*pmd)) +if (pmd_none (*pmd)) {set_pmd (pmd,__pmd (_KERNPG_TABLE |__pa (new_pte_page))); -else -free_page (new_pte_page); + new_pte_page =0 ; + }spin_unlock (&shadow_table_allocation_lock); +if (new_pte_page) +free_page (new_pte_page); } pte =pte_offset_kernel (pmd, address);
Signature · 1 line
2.14.1
Borislav Petkov
maintainerQuoted 7 lines · Ingo Molnar
Sending this out for another round of review.
These are the main KAISER patches, on top of the preparatory series I just sent. This includes KAISER support plus enhancements on top, all the latest code.
( All review feedback so far is incorporated - if anything is missing please
let me know. )
Something's missing:
arch/x86/boot/compressed/pagetable.o: In function `kernel_ident_mapping_init':
pagetable.c:(.text+0x3cc): undefined reference to kaiser_enabled' pagetable.c:(.text+0x400): undefined reference to __supported_pte_mask' pagetable.c:(.text+0x473): undefined reference to `system_state' make[2]: *** [arch/x86/boot/compressed/vmlinux] Error 1
make[1]: *** [arch/x86/boot/compressed/vmlinux] Error 2
make: *** [bzImage] Error 2
make: *** Waiting for unfinished jobs....
I suspect it is that core patch but need to stare at it more. .config attached.
Signature · 4 lines
Regards/Gruss,
Boris.
Good mailing practices for 400: avoid top-posting and trim the reply.Quoted 20 lines · Borislav Petkov
Quoted 7 lines · Ingo Molnar
Sending this out for another round of review.
These are the main KAISER patches, on top of the preparatory series I just sent. This includes KAISER support plus enhancements on top, all the latest code.
( All review feedback so far is incorporated - if anything is missing please
let me know. )Something's missing:
arch/x86/boot/compressed/pagetable.o: In function `kernel_ident_mapping_init':
pagetable.c:(.text+0x3cc): undefined reference tokaiser_enabled' pagetable.c:(.text+0x400): undefined reference to__supported_pte_mask' pagetable.c:(.text+0x473): undefined reference to `system_state' make[2]: *** [arch/x86/boot/compressed/vmlinux] Error 1
make[1]: *** [arch/x86/boot/compressed/vmlinux] Error 2
make: *** [bzImage] Error 2
make: *** Waiting for unfinished jobs....
Quoted 2 lines
I suspect it is that core patch but need to stare at it more. .config attached.
That's the core patch plus the run time enablement I did.
Thanks,
tglx
Borislav Petkov
maintainerQuoted 21 lines · Thomas Gleixner
Quoted 20 lines · Borislav Petkov
Quoted 7 lines · Ingo Molnar
Sending this out for another round of review.
These are the main KAISER patches, on top of the preparatory series I just sent. This includes KAISER support plus enhancements on top, all the latest code.
( All review feedback so far is incorporated - if anything is missing please
let me know. )Something's missing:
arch/x86/boot/compressed/pagetable.o: In function `kernel_ident_mapping_init':
pagetable.c:(.text+0x3cc): undefined reference tokaiser_enabled' pagetable.c:(.text+0x400): undefined reference to__supported_pte_mask' pagetable.c:(.text+0x473): undefined reference to `system_state' make[2]: *** [arch/x86/boot/compressed/vmlinux] Error 1
make[1]: *** [arch/x86/boot/compressed/vmlinux] Error 2
make: *** [bzImage] Error 2
make: *** Waiting for unfinished jobs....
Quoted 4 lines
Quoted 2 lines
I suspect it is that core patch but need to stare at it more. .config attached.
That's the core patch plus the run time enablement I did.
Right, and I think the fix is as simple as this because we don't care about kaiser in the bootstrap kernel:
---
arch/x86/boot/compressed/pagetable.c +1 -0
@@ -22,6 +22,7 @@* the SME support to avoid any compile and link errors. */ #undef CONFIG_AMD_MEM_ENCRYPT +#undef CONFIG_KAISER#include "misc.h"
Signature · 4 lines
Regards/Gruss,
Boris.
Good mailing practices for 400: avoid top-posting and trim the reply.Quoted 36 lines · Borislav Petkov
Quoted 21 lines · Thomas Gleixner
Quoted 20 lines · Borislav Petkov
Quoted 7 lines · Ingo Molnar
Sending this out for another round of review.
These are the main KAISER patches, on top of the preparatory series I just sent. This includes KAISER support plus enhancements on top, all the latest code.
( All review feedback so far is incorporated - if anything is missing please
let me know. )Something's missing:
arch/x86/boot/compressed/pagetable.o: In function `kernel_ident_mapping_init':
pagetable.c:(.text+0x3cc): undefined reference tokaiser_enabled' pagetable.c:(.text+0x400): undefined reference to__supported_pte_mask' pagetable.c:(.text+0x473): undefined reference to `system_state' make[2]: *** [arch/x86/boot/compressed/vmlinux] Error 1
make[1]: *** [arch/x86/boot/compressed/vmlinux] Error 2
make: *** [bzImage] Error 2
make: *** Waiting for unfinished jobs....Quoted 4 lines
Quoted 2 lines
I suspect it is that core patch but need to stare at it more. .config attached.
That's the core patch plus the run time enablement I did.
Right, and I think the fix is as simple as this because we don't care about kaiser in the bootstrap kernel:
---
arch/x86/boot/compressed/pagetable.c +0
-0
arch/x86/boot/compressed/pagetable.c line 27
Quoted 6 lines
arch/x86/boot/compressed/pagetable.c +1
-0@@ -22,6 +22,7 @@* the SME support to avoid any compile and link errors. */ #undef CONFIG_AMD_MEM_ENCRYPT +#undef CONFIG_KAISER#include "misc.h"
Yeah - will use one with a bit more explanation:
arch/x86/boot/compressed/pagetable.c | 5 +++++ 1 file changed, 5 insertions(+)
arch/x86/boot/compressed/pagetable.c +5 -0
@@ -23,6 +23,11 @@*/ #undef CONFIG_AMD_MEM_ENCRYPT +/* +* No KAISER support needed either: +*/ +#undef CONFIG_KAISER +#include "misc.h" /* These actually do the work of building the kernel identity maps. */
Thanks,
Ingo
Quoted 23 lines · Ingo Molnar
arch/x86/boot/compressed/pagetable.c line 27
Quoted 11 lines
arch/x86/boot/compressed/pagetable.c +1
-0@@ -22,6 +22,7 @@* the SME support to avoid any compile and link errors. */ #undef CONFIG_AMD_MEM_ENCRYPT +#undef CONFIG_KAISER#include "misc.h" Yeah - will use one with a bit more explanation:
arch/x86/boot/compressed/pagetable.c | 5 +++++ 1 file changed, 5 insertions(+)arch/x86/boot/compressed/pagetable.c +0
-0@@ -23,6 +23,11 @@*/
arch/x86/boot/compressed/pagetable.c line 33
Quoted 10 lines
arch/x86/boot/compressed/pagetable.c +5
-0#undef CONFIG_AMD_MEM_ENCRYPT +/* +* No KAISER support needed either: +*/ +#undef CONFIG_KAISER +#include "misc.h" /* These actually do the work of building the kernel identity maps. */
Ok, have refreshed the -tip branches with this fix as well.
Thanks,
Ingo
Quoted 1 line · Ingo Molnar
Sending this out for another round of review.
Ok, I have tried to go through the patches, and I don't see anything horrible, but honestly, at this point I'd rather leave it for 4.16.
We're presumably going to have to back-port these things anyway for the LTS releases, and they're still getting comments and small fixes after the merge window is over. I'd rather have people feel like they can take the time to just get it all clean and finished (and as much testing as possible) than start merging things aggressively.
I'll happily take some of the cleanup and prep patches if people want those to go in separately. The unwinder and stack overflow patches seem to be entirely unrelated to the actual changes that are introduced, for example, and came out of debugging them. And the sysenter stack patch seems a nice cleanup that actually removes special cases.
Comments?
Linus
Quoted 3 lines · Linus Torvalds
I'll happily take some of the cleanup and prep patches if people want those to go in separately.
Actually, perhaps we should not strive to do that.
Because particularly if we expect that this will want to be back-ported into at least 4.14, maybe the right thing to do is to make _that_ as easy as possible, and make the whole series be based on 4.14 (so that back-porting is literally just "merge the branch").
If I start taking this piece-meal, it is just going to make the back-porting messier.
Linus