Author: kib
Date: Sat Apr  7 17:06:13 2018
New Revision: 332182
URL: https://svnweb.freebsd.org/changeset/base/332182

Log:
  Handle Skylake-X errata SKZ63.
  
  SKZ63 Processor May Hang When Executing Code In an HLE Transaction
  Region
  
  Problem: Under certain conditions, if the processor acquires an HLE
  (Hardware Lock Elision) lock via the XACQUIRE instruction in the Host
  Physical Address range between 40000000H and 403FFFFFH, it may hang
  with an internal timeout error (MCACOD 0400H) logged into
  IA32_MCi_STATUS.
  
  Move the pages from the range into the blacklist.  Add a tunable to
  not waste 4M if local DoS is not the issue.
  
  Reviewed by:  markj
  Sponsored by: The FreeBSD Foundation
  MFC after:    1 week
  Differential revision:        https://reviews.freebsd.org/D15001

Modified:
  head/sys/amd64/amd64/pmap.c
  head/sys/vm/vm_page.c
  head/sys/vm/vm_page.h

Modified: head/sys/amd64/amd64/pmap.c
==============================================================================
--- head/sys/amd64/amd64/pmap.c Sat Apr  7 15:40:00 2018        (r332181)
+++ head/sys/amd64/amd64/pmap.c Sat Apr  7 17:06:13 2018        (r332182)
@@ -1290,7 +1290,35 @@ pmap_init(void)
        struct pmap_preinit_mapping *ppim;
        vm_page_t mpte;
        vm_size_t s;
-       int error, i, pv_npg;
+       int error, i, pv_npg, ret, skz63;
+
+       /* Detect bare-metal Skylake Server and Skylake-X. */
+       if (vm_guest == VM_GUEST_NO && cpu_vendor_id == CPU_VENDOR_INTEL &&
+           CPUID_TO_FAMILY(cpu_id) == 0x6 && CPUID_TO_MODEL(cpu_id) == 0x55) {
+               /*
+                * Skylake-X errata SKZ63. Processor May Hang When
+                * Executing Code In an HLE Transaction Region between
+                * 40000000H and 403FFFFFH.
+                *
+                * Mark the pages in the range as preallocated.  It
+                * seems to be impossible to distinguish between
+                * Skylake Server and Skylake X.
+                */
+               skz63 = 1;
+               TUNABLE_INT_FETCH("hw.skz63_enable", &skz63);
+               if (skz63 != 0) {
+                       if (bootverbose)
+                               printf("SKZ63: skipping 4M RAM starting "
+                                   "at physical 1G\n");
+                       for (i = 0; i < atop(0x400000); i++) {
+                               ret = vm_page_blacklist_add(0x40000000 +
+                                   ptoa(i), FALSE);
+                               if (!ret && bootverbose)
+                                       printf("page at %#lx already used\n",
+                                           0x40000000 + ptoa(i));
+                       }
+               }
+       }
 
        /*
         * Initialize the vm page array entries for the kernel pmap's

Modified: head/sys/vm/vm_page.c
==============================================================================
--- head/sys/vm/vm_page.c       Sat Apr  7 15:40:00 2018        (r332181)
+++ head/sys/vm/vm_page.c       Sat Apr  7 17:06:13 2018        (r332182)
@@ -341,6 +341,29 @@ vm_page_blacklist_next(char **list, char *end)
        return (0);
 }
 
+bool
+vm_page_blacklist_add(vm_paddr_t pa, bool verbose)
+{
+       struct vm_domain *vmd;
+       vm_page_t m;
+       int ret;
+
+       m = vm_phys_paddr_to_vm_page(pa);
+       if (m == NULL)
+               return (true); /* page does not exist, no failure */
+
+       vmd = vm_pagequeue_domain(m);
+       vm_domain_free_lock(vmd);
+       ret = vm_phys_unfree_page(m);
+       vm_domain_free_unlock(vmd);
+       if (ret) {
+               TAILQ_INSERT_TAIL(&blacklist_head, m, listq);
+               if (verbose)
+                       printf("Skipping page with pa 0x%jx\n", (uintmax_t)pa);
+       }
+       return (ret);
+}
+
 /*
  *     vm_page_blacklist_check:
  *
@@ -351,29 +374,14 @@ vm_page_blacklist_next(char **list, char *end)
 static void
 vm_page_blacklist_check(char *list, char *end)
 {
-       struct vm_domain *vmd;
        vm_paddr_t pa;
-       vm_page_t m;
        char *next;
-       int ret;
 
        next = list;
        while (next != NULL) {
                if ((pa = vm_page_blacklist_next(&next, end)) == 0)
                        continue;
-               m = vm_phys_paddr_to_vm_page(pa);
-               if (m == NULL)
-                       continue;
-               vmd = vm_pagequeue_domain(m);
-               vm_domain_free_lock(vmd);
-               ret = vm_phys_unfree_page(m);
-               vm_domain_free_unlock(vmd);
-               if (ret == TRUE) {
-                       TAILQ_INSERT_TAIL(&blacklist_head, m, listq);
-                       if (bootverbose)
-                               printf("Skipping page with pa 0x%jx\n",
-                                   (uintmax_t)pa);
-               }
+               vm_page_blacklist_add(pa, bootverbose);
        }
 }
 

Modified: head/sys/vm/vm_page.h
==============================================================================
--- head/sys/vm/vm_page.h       Sat Apr  7 15:40:00 2018        (r332181)
+++ head/sys/vm/vm_page.h       Sat Apr  7 17:06:13 2018        (r332182)
@@ -476,6 +476,7 @@ vm_page_t vm_page_alloc_contig_domain(vm_object_t obje
     vm_memattr_t memattr);
 vm_page_t vm_page_alloc_freelist(int, int);
 vm_page_t vm_page_alloc_freelist_domain(int, int, int);
+bool vm_page_blacklist_add(vm_paddr_t pa, bool verbose);
 void vm_page_change_lock(vm_page_t m, struct mtx **mtx);
 vm_page_t vm_page_grab (vm_object_t, vm_pindex_t, int);
 int vm_page_grab_pages(vm_object_t object, vm_pindex_t pindex, int allocflags,
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to