svn commit: r314956 - head/sys/boot/efi/loader
Dexuan Cui
dexuan at FreeBSD.org
Thu Mar 9 12:09:09 UTC 2017
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
More information about the svn-src-head
mailing list