]> git.hungrycats.org Git - linux/commitdiff
kaiser: enhanced by kernel and user PCIDs
authorDave Hansen <dave.hansen@linux.intel.com>
Wed, 30 Aug 2017 23:23:00 +0000 (16:23 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 5 Jan 2018 14:44:25 +0000 (15:44 +0100)
Merged performance improvements to Kaiser, using distinct kernel
and user Process Context Identifiers to minimize the TLB flushing.

Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
Signed-off-by: Hugh Dickins <hughd@google.com>
Acked-by: Jiri Kosina <jkosina@suse.cz>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
arch/x86/entry/entry_64.S
arch/x86/entry/entry_64_compat.S
arch/x86/include/asm/cpufeature.h
arch/x86/include/asm/kaiser.h
arch/x86/include/asm/pgtable_types.h
arch/x86/include/asm/tlbflush.h
arch/x86/include/uapi/asm/processor-flags.h
arch/x86/kernel/cpu/common.c
arch/x86/kvm/x86.c
arch/x86/mm/kaiser.c
arch/x86/mm/tlb.c

index a058e0fd99e3a9fbc4704e8696c2af87abfa32af..6a18d787aed434419eb9323e4b6bd420ccab8a88 100644 (file)
@@ -1291,7 +1291,10 @@ ENTRY(nmi)
        /* %rax is saved above, so OK to clobber here */
        movq    %cr3, %rax
        pushq   %rax
-       andq    $(~KAISER_SHADOW_PGD_OFFSET), %rax
+       /* mask off "user" bit of pgd address and 12 PCID bits: */
+       andq    $(~(X86_CR3_PCID_ASID_MASK | KAISER_SHADOW_PGD_OFFSET)), %rax
+       /* Add back kernel PCID and "no flush" bit */
+       orq     X86_CR3_PCID_KERN_VAR, %rax
        movq    %rax, %cr3
 #endif
        call    do_nmi
@@ -1532,7 +1535,10 @@ end_repeat_nmi:
        /* %rax is saved above, so OK to clobber here */
        movq    %cr3, %rax
        pushq   %rax
-       andq    $(~KAISER_SHADOW_PGD_OFFSET), %rax
+       /* mask off "user" bit of pgd address and 12 PCID bits: */
+       andq    $(~(X86_CR3_PCID_ASID_MASK | KAISER_SHADOW_PGD_OFFSET)), %rax
+       /* Add back kernel PCID and "no flush" bit */
+       orq     X86_CR3_PCID_KERN_VAR, %rax
        movq    %rax, %cr3
 #endif
 
index fe1911930b52c93fd3df1998f98d50ea21bf1d97..d03bf0e28b8b36569873ee98e6c3b86da42f2e57 100644 (file)
@@ -13,6 +13,7 @@
 #include <asm/irqflags.h>
 #include <asm/asm.h>
 #include <asm/smap.h>
+#include <asm/pgtable_types.h>
 #include <asm/kaiser.h>
 #include <linux/linkage.h>
 #include <linux/err.h>
index f7ba9fbf12eeb8770280823b6030d09d044deb66..72a4343b774f47ce40db377d39122e171219acc5 100644 (file)
 #define X86_FEATURE_ARAT       ( 7*32+ 1) /* Always Running APIC Timer */
 #define X86_FEATURE_CPB                ( 7*32+ 2) /* AMD Core Performance Boost */
 #define X86_FEATURE_EPB                ( 7*32+ 3) /* IA32_ENERGY_PERF_BIAS support */
+#define X86_FEATURE_INVPCID_SINGLE ( 7*32+ 4) /* Effectively INVPCID && CR4.PCIDE=1 */
 #define X86_FEATURE_PLN                ( 7*32+ 5) /* Intel Power Limit Notification */
 #define X86_FEATURE_PTS                ( 7*32+ 6) /* Intel Package Thermal Status */
 #define X86_FEATURE_DTHERM     ( 7*32+ 7) /* Digital Thermal Sensor */
index e0fc45e77aeeb4bab9d88f624a365f459498ca06..360ff3bc44a97286320b1a09de3e1a5734011331 100644 (file)
@@ -1,5 +1,8 @@
 #ifndef _ASM_X86_KAISER_H
 #define _ASM_X86_KAISER_H
+
+#include <uapi/asm/processor-flags.h> /* For PCID constants */
+
 /*
  * This file includes the definitions for the KAISER feature.
  * KAISER is a counter measure against x86_64 side channel attacks on
 
 .macro _SWITCH_TO_KERNEL_CR3 reg
 movq %cr3, \reg
-andq $(~KAISER_SHADOW_PGD_OFFSET), \reg
+andq $(~(X86_CR3_PCID_ASID_MASK | KAISER_SHADOW_PGD_OFFSET)), \reg
+orq  X86_CR3_PCID_KERN_VAR, \reg
 movq \reg, %cr3
 .endm
 
 .macro _SWITCH_TO_USER_CR3 reg
 movq %cr3, \reg
-orq $(KAISER_SHADOW_PGD_OFFSET), \reg
+andq $(~(X86_CR3_PCID_ASID_MASK | KAISER_SHADOW_PGD_OFFSET)), \reg
+/*
+ * This can obviously be one instruction by putting the
+ * KAISER_SHADOW_PGD_OFFSET bit in the X86_CR3_PCID_USER_VAR.
+ * But, just leave it now for simplicity.
+ */
+orq  X86_CR3_PCID_USER_VAR, \reg
+orq  $(KAISER_SHADOW_PGD_OFFSET), \reg
 movq \reg, %cr3
 .endm
 
index a70d6100b3dfefc5b471ea07abbb161ea2c6a553..79319174e27b28ff5b3a35c468e1c6fa546da27b 100644 (file)
                         _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)
+#if defined(CONFIG_KAISER) && defined(CONFIG_X86_64)
+#define X86_CR3_PCID_ASID_KERN  (_AC(0x4,UL))
+#define X86_CR3_PCID_ASID_USER  (_AC(0x6,UL))
+
+#define X86_CR3_PCID_KERN_FLUSH                (X86_CR3_PCID_ASID_KERN)
+#define X86_CR3_PCID_USER_FLUSH                (X86_CR3_PCID_ASID_USER)
+#define X86_CR3_PCID_KERN_NOFLUSH      (X86_CR3_PCID_NOFLUSH | X86_CR3_PCID_ASID_KERN)
+#define X86_CR3_PCID_USER_NOFLUSH      (X86_CR3_PCID_NOFLUSH | X86_CR3_PCID_ASID_USER)
+#else
+#define X86_CR3_PCID_ASID_KERN  (_AC(0x0,UL))
+#define X86_CR3_PCID_ASID_USER  (_AC(0x0,UL))
+/*
+ * PCIDs are unsupported on 32-bit and none of these bits can be
+ * set in CR3:
+ */
+#define X86_CR3_PCID_KERN_FLUSH                (0)
+#define X86_CR3_PCID_USER_FLUSH                (0)
+#define X86_CR3_PCID_KERN_NOFLUSH      (0)
+#define X86_CR3_PCID_USER_NOFLUSH      (0)
+#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.
index 9fc5968da8208b7f2176c28c09e750b71948cc4f..48ef37079bc2a7426d849e6cf02d0e930a702c6e 100644 (file)
@@ -12,7 +12,6 @@ static inline void __invpcid(unsigned long pcid, unsigned long addr,
                             unsigned long type)
 {
        struct { u64 d[2]; } desc = { { pcid, addr } };
-
        /*
         * The memory clobber is because the whole point is to invalidate
         * stale TLB entries and, especially if we're flushing global
@@ -133,14 +132,25 @@ static inline void cr4_set_bits_and_update_boot(unsigned long mask)
 
 static inline void __native_flush_tlb(void)
 {
+       if (!cpu_feature_enabled(X86_FEATURE_INVPCID)) {
+               /*
+                * If current->mm == NULL then we borrow a mm which may change during a
+                * task switch and therefore we must not be preempted while we write CR3
+                * back:
+                */
+               preempt_disable();
+               native_write_cr3(native_read_cr3());
+               preempt_enable();
+               return;
+       }
        /*
-        * If current->mm == NULL then we borrow a mm which may change during a
-        * task switch and therefore we must not be preempted while we write CR3
-        * back:
+        * We are no longer using globals with KAISER, so a
+        * "nonglobals" flush would work too. But, this is more
+        * conservative.
+        *
+        * Note, this works with CR4.PCIDE=0 or 1.
         */
-       preempt_disable();
-       native_write_cr3(native_read_cr3());
-       preempt_enable();
+       invpcid_flush_all();
 }
 
 static inline void __native_flush_tlb_global_irq_disabled(void)
@@ -162,6 +172,8 @@ static inline void __native_flush_tlb_global(void)
                /*
                 * Using INVPCID is considerably faster than a pair of writes
                 * to CR4 sandwiched inside an IRQ flag save/restore.
+                *
+                * Note, this works with CR4.PCIDE=0 or 1.
                 */
                invpcid_flush_all();
                return;
@@ -181,7 +193,31 @@ static inline void __native_flush_tlb_global(void)
 
 static inline void __native_flush_tlb_single(unsigned long addr)
 {
-       asm volatile("invlpg (%0)" ::"r" (addr) : "memory");
+       /*
+        * SIMICS #GP's if you run INVPCID with type 2/3
+        * and X86_CR4_PCIDE clear.  Shame!
+        *
+        * The ASIDs used below are hard-coded.  But, we must not
+        * call invpcid(type=1/2) before CR4.PCIDE=1.  Just call
+        * invpcid in the case we are called early.
+        */
+       if (!this_cpu_has(X86_FEATURE_INVPCID_SINGLE)) {
+               asm volatile("invlpg (%0)" ::"r" (addr) : "memory");
+               return;
+       }
+       /* Flush the address out of both PCIDs. */
+       /*
+        * An optimization here might be to determine addresses
+        * that are only kernel-mapped and only flush the kernel
+        * ASID.  But, userspace flushes are probably much more
+        * important performance-wise.
+        *
+        * Make sure to do only a single invpcid when KAISER is
+        * disabled and we have only a single ASID.
+        */
+       if (X86_CR3_PCID_ASID_KERN != X86_CR3_PCID_ASID_USER)
+               invpcid_flush_one(X86_CR3_PCID_ASID_KERN, addr);
+       invpcid_flush_one(X86_CR3_PCID_ASID_USER, addr);
 }
 
 static inline void __flush_tlb_all(void)
index 79887abcb5e1fe1e45c08e94a3912fdd4ede9d4e..1361779f44fe1133d786331bd6e0d6db47ba8390 100644 (file)
@@ -77,7 +77,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
index e5ba9701ee6c27abc92b95355bda94f1b06dd07f..07b7f28165672a290cd5468b2e597cd68d138a06 100644 (file)
@@ -321,11 +321,45 @@ static __always_inline void setup_smap(struct cpuinfo_x86 *c)
        }
 }
 
+/*
+ * These can have bit 63 set, so we can not just use a plain "or"
+ * instruction to get their value or'd into CR3.  It would take
+ * another register.  So, we use a memory reference to these
+ * instead.
+ *
+ * This is also handy because systems that do not support
+ * PCIDs just end up or'ing a 0 into their CR3, which does
+ * no harm.
+ */
+__aligned(PAGE_SIZE) unsigned long X86_CR3_PCID_KERN_VAR = 0;
+__aligned(PAGE_SIZE) unsigned long X86_CR3_PCID_USER_VAR = 0;
+
 static void setup_pcid(struct cpuinfo_x86 *c)
 {
        if (cpu_has(c, X86_FEATURE_PCID)) {
                if (cpu_has(c, X86_FEATURE_PGE)) {
                        cr4_set_bits(X86_CR4_PCIDE);
+                       /*
+                        * These variables are used by the entry/exit
+                        * code to change PCIDs.
+                        */
+#ifdef CONFIG_KAISER
+                       X86_CR3_PCID_KERN_VAR = X86_CR3_PCID_KERN_NOFLUSH;
+                       X86_CR3_PCID_USER_VAR = X86_CR3_PCID_USER_NOFLUSH;
+#endif
+                       /*
+                        * INVPCID has two "groups" of types:
+                        * 1/2: Invalidate an individual address
+                        * 3/4: Invalidate all contexts
+                        *
+                        * 1/2 take a PCID, but 3/4 do not.  So, 3/4
+                        * ignore the PCID argument in the descriptor.
+                        * But, we have to be careful not to call 1/2
+                        * with an actual non-zero PCID in them before
+                        * we do the above cr4_set_bits().
+                        */
+                       if (cpu_has(c, X86_FEATURE_INVPCID))
+                               set_cpu_cap(c, X86_FEATURE_INVPCID_SINGLE);
                } else {
                        /*
                         * flush_tlb_all(), as currently implemented, won't
index 796f1ec67469ec00f339b7b36f7bf50dacd6caa5..ccf17dbfea097ddce25e2ef0fce4c5777d37d9d7 100644 (file)
@@ -759,7 +759,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;
        }
 
index bf48bf0df8c5f7d29a978fb7890dedc04ee300ba..290a52e6017d0dac3831bd3f4c02cd7e4f30141d 100644 (file)
@@ -240,6 +240,8 @@ static void __init kaiser_init_all_pgds(void)
 } while (0)
 
 extern char __per_cpu_user_mapped_start[], __per_cpu_user_mapped_end[];
+extern unsigned long X86_CR3_PCID_KERN_VAR;
+extern unsigned long X86_CR3_PCID_USER_VAR;
 /*
  * If anything in here fails, we will likely die on one of the
  * first kernel->user transitions and init will die.  But, we
@@ -290,6 +292,11 @@ void __init kaiser_init(void)
        kaiser_add_user_map_early(&debug_idt_table,
                                  sizeof(gate_desc) * NR_VECTORS,
                                  __PAGE_KERNEL);
+
+       kaiser_add_user_map_early(&X86_CR3_PCID_KERN_VAR, PAGE_SIZE,
+                                 __PAGE_KERNEL);
+       kaiser_add_user_map_early(&X86_CR3_PCID_USER_VAR, PAGE_SIZE,
+                                 __PAGE_KERNEL);
 }
 
 /* Add a mapping to the shadow mapping, and synchronize the mappings */
index 7a4cdb632508e2db18e6408baed55f36e5a5a1aa..aed0b704de3db619c3195b8de9fd1dd1a2bf0540 100644 (file)
@@ -34,6 +34,46 @@ struct flush_tlb_info {
        unsigned long flush_end;
 };
 
+static void load_new_mm_cr3(pgd_t *pgdir)
+{
+       unsigned long new_mm_cr3 = __pa(pgdir);
+
+       /*
+        * KAISER, plus PCIDs needs some extra work here.  But,
+        * if either of features is not present, we need no
+        * PCIDs here and just do a normal, full TLB flush with
+        * the write_cr3()
+        */
+       if (!IS_ENABLED(CONFIG_KAISER) ||
+           !cpu_feature_enabled(X86_FEATURE_PCID))
+               goto out_set_cr3;
+       /*
+        * We reuse the same PCID for different tasks, so we must
+        * flush all the entires for the PCID out when we change
+        * tasks.
+        */
+       new_mm_cr3 = X86_CR3_PCID_KERN_FLUSH | __pa(pgdir);
+
+       /*
+        * The flush from load_cr3() may leave old TLB entries
+        * for userspace in place.  We must flush that context
+        * separately.  We can theoretically delay doing this
+        * until we actually load up the userspace CR3, but
+        * that's a bit tricky.  We have to have the "need to
+        * flush userspace PCID" bit per-cpu and check it in the
+        * exit-to-userspace paths.
+        */
+       invpcid_flush_single_context(X86_CR3_PCID_ASID_USER);
+
+out_set_cr3:
+       /*
+        * Caution: many callers of this function expect
+        * that load_cr3() is serializing and orders TLB
+        * fills with respect to the mm_cpumask writes.
+        */
+       write_cr3(new_mm_cr3);
+}
+
 /*
  * We cannot call mmdrop() because we are in interrupt context,
  * instead update mm->cpu_vm_mask.
@@ -45,7 +85,7 @@ void leave_mm(int cpu)
                BUG();
        if (cpumask_test_cpu(cpu, mm_cpumask(active_mm))) {
                cpumask_clear_cpu(cpu, mm_cpumask(active_mm));
-               load_cr3(swapper_pg_dir);
+               load_new_mm_cr3(swapper_pg_dir);
                /*
                 * This gets called in the idle path where RCU
                 * functions differently.  Tracing normally
@@ -105,7 +145,7 @@ void switch_mm_irqs_off(struct mm_struct *prev, struct mm_struct *next,
                 * ordering guarantee we need.
                 *
                 */
-               load_cr3(next->pgd);
+               load_new_mm_cr3(next->pgd);
 
                trace_tlb_flush(TLB_FLUSH_ON_TASK_SWITCH, TLB_FLUSH_ALL);
 
@@ -152,7 +192,7 @@ void switch_mm_irqs_off(struct mm_struct *prev, struct mm_struct *next,
                         * As above, load_cr3() is serializing and orders TLB
                         * fills with respect to the mm_cpumask write.
                         */
-                       load_cr3(next->pgd);
+                       load_new_mm_cr3(next->pgd);
                        trace_tlb_flush(TLB_FLUSH_ON_TASK_SWITCH, TLB_FLUSH_ALL);
                        load_mm_cr4(next);
                        load_mm_ldt(next);