Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 9 Mar 2017 12:09:07 +0000 (UTC)
From:      Dexuan Cui <dexuan@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r314956 - head/sys/boot/efi/loader
Message-ID:  <201703091209.v29C97Jd029975@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: dexuan
Date: Thu Mar  9 12:09:07 2017
New Revision: 314956
URL: https://svnweb.freebsd.org/changeset/base/314956

Log:
  loader.efi: only reduce the size of the staging area on Hyper-V
  
  Doing this on physical hosts turns out to be problematic, e.g. see comment
  24 and 28 in https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=211746.
  
  To fix the real underlying issue correctly & thoroughly, IMO we need
  a relocatable kernel, but that would require a lot of complicated long
  term work:  https://reviews.freebsd.org/D9686?id=25414#inline-56969
  
  For now, let's only apply efi_verify_staging_size() to VMs running on
  Hyper-V, and restore the old behavior on physical machines since that
  has been working for people for a long period of time, though that's
  potentially unsafe...
  
  MFC after:	2 weeks
  Sponsored by:	Microsoft

Modified:
  head/sys/boot/efi/loader/copy.c

Modified: head/sys/boot/efi/loader/copy.c
==============================================================================
--- head/sys/boot/efi/loader/copy.c	Thu Mar  9 09:54:23 2017	(r314955)
+++ head/sys/boot/efi/loader/copy.c	Thu Mar  9 12:09:07 2017	(r314956)
@@ -30,6 +30,8 @@
 __FBSDID("$FreeBSD$");
 
 #include <sys/param.h>
+#include <machine/cpufunc.h>
+#include <machine/specialreg.h>
 
 #include <stand.h>
 #include <bootstrap.h>
@@ -41,6 +43,47 @@ __FBSDID("$FreeBSD$");
 
 #if defined(__i386__) || defined(__amd64__)
 
+/*
+ * The code is excerpted from sys/x86/x86/identcpu.c: identify_cpu(),
+ * identify_hypervisor(), and dev/hyperv/vmbus/hyperv.c: hyperv_identify().
+ */
+#define CPUID_LEAF_HV_MAXLEAF		0x40000000
+#define CPUID_LEAF_HV_INTERFACE		0x40000001
+#define CPUID_LEAF_HV_FEATURES		0x40000003
+#define CPUID_LEAF_HV_LIMITS		0x40000005
+#define CPUID_HV_IFACE_HYPERV		0x31237648	/* HV#1 */
+#define CPUID_HV_MSR_HYPERCALL		0x0020
+static int running_on_hyperv(void)
+{
+	char hv_vendor[16];
+	uint32_t regs[4];
+
+	do_cpuid(1, regs);
+	if ((regs[2] & CPUID2_HV) == 0)
+		return (0);
+
+	do_cpuid(CPUID_LEAF_HV_MAXLEAF, regs);
+	if (regs[0] < CPUID_LEAF_HV_LIMITS)
+		return (0);
+
+	((uint32_t *)&hv_vendor)[0] = regs[1];
+	((uint32_t *)&hv_vendor)[1] = regs[2];
+	((uint32_t *)&hv_vendor)[2] = regs[3];
+	hv_vendor[12] = '\0';
+	if (strcmp(hv_vendor, "Microsoft Hv") != 0)
+		return (0);
+
+	do_cpuid(CPUID_LEAF_HV_INTERFACE, regs);
+	if (regs[0] != CPUID_HV_IFACE_HYPERV)
+		return (0);
+
+	do_cpuid(CPUID_LEAF_HV_FEATURES, regs);
+	if ((regs[0] & CPUID_HV_MSR_HYPERCALL) == 0)
+		return (0);
+
+	return (1);
+}
+
 #define KERNEL_PHYSICAL_BASE (2*1024*1024)
 
 static void
@@ -134,8 +177,13 @@ efi_copy_init(void)
 	nr_pages = EFI_SIZE_TO_PAGES((EFI_STAGING_SIZE) * 1024 * 1024);
 
 #if defined(__i386__) || defined(__amd64__)
-	/* We'll decrease nr_pages, if it's too big. */
-	efi_verify_staging_size(&nr_pages);
+	/*
+	 * We'll decrease nr_pages, if it's too big. Currently we only
+	 * apply this to FreeBSD VM running on Hyper-V. Why? Please see
+	 * https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=211746#c28
+	 */
+	if (running_on_hyperv())
+		efi_verify_staging_size(&nr_pages);
 
 	/*
 	 * The staging area must reside in the the first 1GB physical



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201703091209.v29C97Jd029975>