From 2ac32d531613345918554d962ea346c9b3afa78b Mon Sep 17 00:00:00 2001 From: jhb Date: Tue, 7 Oct 2008 14:05:42 +0000 Subject: 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 --- sys/boot/i386/libi386/bootinfo64.c | 48 +++++++++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) (limited to 'sys/boot') 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 #include #include +#include +#include +#include #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); /* -- cgit v1.1