summaryrefslogtreecommitdiffstats
path: root/sys/boot
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2008-10-07 14:05:42 +0000
committerjhb <jhb@FreeBSD.org>2008-10-07 14:05:42 +0000
commit2ac32d531613345918554d962ea346c9b3afa78b (patch)
tree2c513771069e88df6ac6ec7ff267ed9fc9dc3e13 /sys/boot
parenta9a8df42d11fa8fcb89948c073db7b2e4319a8f6 (diff)
downloadFreeBSD-src-2ac32d531613345918554d962ea346c9b3afa78b.zip
FreeBSD-src-2ac32d531613345918554d962ea346c9b3afa78b.tar.gz
Use CPUID to see if the current CPU supports long mode when attemping to
boot an amd64 kernel. If not, then fail the boot request with an error message. Otherwise, the boot attempt will fail with a BTX fault when trying to read the EFER MSR. MFC after: 3 days
Diffstat (limited to 'sys/boot')
-rw-r--r--sys/boot/i386/libi386/bootinfo64.c48
1 files changed, 47 insertions, 1 deletions
diff --git a/sys/boot/i386/libi386/bootinfo64.c b/sys/boot/i386/libi386/bootinfo64.c
index 17963ce..5b2228c 100644
--- a/sys/boot/i386/libi386/bootinfo64.c
+++ b/sys/boot/i386/libi386/bootinfo64.c
@@ -32,6 +32,9 @@ __FBSDID("$FreeBSD$");
#include <sys/reboot.h>
#include <sys/linker.h>
#include <machine/bootinfo.h>
+#include <machine/cpufunc.h>
+#include <machine/psl.h>
+#include <machine/specialreg.h>
#include "bootstrap.h"
#include "libi386.h"
#include "btxv86.h"
@@ -124,7 +127,45 @@ bi_copymodules64(vm_offset_t addr)
}
/*
- * Load the information expected by an i386 kernel.
+ * Check to see if this CPU supports long mode.
+ */
+static int
+bi_checkcpu(void)
+{
+ char *cpu_vendor;
+ int vendor[3];
+ int eflags, regs[4];
+
+ /* Check for presence of "cpuid". */
+ eflags = read_eflags();
+ write_eflags(eflags ^ PSL_ID);
+ if (!((eflags ^ read_eflags()) & PSL_ID))
+ return (0);
+
+ /* Fetch the vendor string. */
+ do_cpuid(0, regs);
+ vendor[0] = regs[1];
+ vendor[1] = regs[3];
+ vendor[2] = regs[2];
+ cpu_vendor = (char *)vendor;
+
+ /* Check for vendors that support AMD features. */
+ if (strncmp(cpu_vendor, "GenuineIntel", 12) != 0 &&
+ strncmp(cpu_vendor, "AuthenticAMD", 12) != 0)
+ return (0);
+
+ /* Has to support AMD features. */
+ do_cpuid(0x80000000, regs);
+ if (!(regs[0] >= 0x80000001))
+ return (0);
+
+ /* Check for long mode. */
+ do_cpuid(0x80000001, regs);
+ return (regs[3] & AMDID_LM);
+}
+
+/*
+ * Load the information expected by an amd64 kernel.
*
* - The 'boothowto' argument is constructed
* - The 'bootdev' argument is constructed
@@ -145,6 +186,11 @@ bi_load64(char *args, vm_offset_t *modulep, vm_offset_t *kernendp)
char *rootdevname;
int howto;
+ if (!bi_checkcpu()) {
+ printf("CPU doesn't support long mode\n");
+ return (EINVAL);
+ }
+
howto = bi_getboothowto(args);
/*
OpenPOWER on IntegriCloud