Print this page
8956 Implement KPTI
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Reviewed by: Robert Mustacchi <rm@joyent.com>

@@ -21,11 +21,11 @@
 
 /*
  * Copyright (c) 1993, 2010, Oracle and/or its affiliates. All rights reserved.
  * Copyright 2012 DEY Storage Systems, Inc.  All rights reserved.
  * Copyright 2017 Nexenta Systems, Inc.
- * Copyright 2015 Joyent, Inc.
+ * Copyright (c) 2018 Joyent, Inc.
  * Copyright (c) 2015 by Delphix. All rights reserved.
  */
 /*
  * Copyright (c) 2010, Intel Corporation.
  * All rights reserved.

@@ -444,12 +444,14 @@
  *                      +-----------------------+
  *                      |      Kernel Data      |
  * 0xFFFFFFFF.FBC00000  |-----------------------|
  *                      |      Kernel Text      |
  * 0xFFFFFFFF.FB800000  |-----------------------|- KERNEL_TEXT
- *                      |---       GDT       ---|- GDT page (GDT_VA)
  *                      |---    debug info   ---|- debug info (DEBUG_INFO_VA)
+ *                      |---       GDT       ---|- GDT page (GDT_VA)
+ *                      |---       IDT       ---|- IDT page (IDT_VA)
+ *                      |---       LDT       ---|- LDT pages (LDT_VA)
  *                      |                       |
  *                      |      Core heap        | (used for loadable modules)
  * 0xFFFFFFFF.C0000000  |-----------------------|- core_base / ekernelheap
  *                      |        Kernel         |
  *                      |         heap          |

@@ -949,10 +951,21 @@
 
         if (segkpm_create(segkpm, (caddr_t)&b) != 0)
                 panic("segkpm_create segkpm");
 
         rw_exit(&kas.a_lock);
+
+        kpm_enable = 1;
+
+        /*
+         * As the KPM was disabled while setting up the system, go back and fix
+         * CPU zero's access to its user page table. This is a bit gross, but
+         * we have a chicken and egg problem otherwise.
+         */
+        ASSERT(CPU->cpu_hat_info->hci_user_l3ptes == NULL);
+        CPU->cpu_hat_info->hci_user_l3ptes =
+            (x86pte_t *)hat_kpm_mapin_pfn(CPU->cpu_hat_info->hci_user_l3pfn);
 }
 
 /*
  * The debug info page provides enough information to allow external
  * inspectors (e.g. when running under a hypervisor) to bootstrap

@@ -1412,10 +1425,13 @@
  */
 static void
 startup_kmem(void)
 {
         extern void page_set_colorequiv_arr(void);
+#if !defined(__xpv)
+        extern uint64_t kpti_kbase;
+#endif
 
         PRM_POINT("startup_kmem() starting...");
 
 #if defined(__amd64)
         if (eprom_kernelbase && eprom_kernelbase != KERNELBASE)

@@ -1474,17 +1490,23 @@
 
         *(uintptr_t *)&_kernelbase = kernelbase;
         *(uintptr_t *)&_userlimit = kernelbase;
 #if defined(__amd64)
         *(uintptr_t *)&_userlimit -= KERNELBASE - USERLIMIT;
+#if !defined(__xpv)
+        kpti_kbase = kernelbase;
+#endif
 #else
         *(uintptr_t *)&_userlimit32 = _userlimit;
 #endif
         PRM_DEBUG(_kernelbase);
         PRM_DEBUG(_userlimit);
         PRM_DEBUG(_userlimit32);
 
+        /* We have to re-do this now that we've modified _userlimit. */
+        mmu_calc_user_slots();
+
         layout_kernel_va();
 
 #if defined(__i386)
         /*
          * If segmap is too large we can push the bottom of the kernel heap

@@ -2119,36 +2141,10 @@
          * it, tell the debugger.
          */
         if (boothowto & RB_DEBUG)
                 kdi_dvec_memavail();
 
-        /*
-         * The following code installs a special page fault handler (#pf)
-         * to work around a pentium bug.
-         */
-#if !defined(__amd64) && !defined(__xpv)
-        if (x86_type == X86_TYPE_P5) {
-                desctbr_t idtr;
-                gate_desc_t *newidt;
-
-                if ((newidt = kmem_zalloc(MMU_PAGESIZE, KM_NOSLEEP)) == NULL)
-                        panic("failed to install pentium_pftrap");
-
-                bcopy(idt0, newidt, NIDT * sizeof (*idt0));
-                set_gatesegd(&newidt[T_PGFLT], &pentium_pftrap,
-                    KCS_SEL, SDT_SYSIGT, TRP_KPL, 0);
-
-                (void) as_setprot(&kas, (caddr_t)newidt, MMU_PAGESIZE,
-                    PROT_READ | PROT_EXEC);
-
-                CPU->cpu_idt = newidt;
-                idtr.dtr_base = (uintptr_t)CPU->cpu_idt;
-                idtr.dtr_limit = (NIDT * sizeof (*idt0)) - 1;
-                wr_idtr(&idtr);
-        }
-#endif  /* !__amd64 */
-
 #if !defined(__xpv)
         /*
          * Map page pfn=0 for drivers, such as kd, that need to pick up
          * parameters left there by controllers/BIOS.
          */

@@ -2207,14 +2203,12 @@
 
         /*
          * kpm segment
          */
         segmap_kpm = 0;
-        if (kpm_desired) {
+        if (kpm_desired)
                 kpm_init();
-                kpm_enable = 1;
-        }
 
         /*
          * Now create segmap segment.
          */
         rw_enter(&kas.a_lock, RW_WRITER);

@@ -2333,16 +2327,22 @@
 #if defined(__xpv)
         ec_init_debug_irq();
         xs_domu_init();
 #endif
 
-#if defined(__amd64) && !defined(__xpv)
+#if !defined(__xpv)
         /*
          * Intel IOMMU has been setup/initialized in ddi_impl.c
          * Start it up now.
          */
         immu_startup();
+
+        /*
+         * Now that we're no longer going to drop into real mode for a BIOS call
+         * via bootops, we can enable PCID (which requires CR0.PG).
+         */
+        enable_pcid();
 #endif
 
         PRM_POINT("Enabling interrupts");
         (*picinitf)();
         sti();