diff options
author | jhb <jhb@FreeBSD.org> | 2008-10-07 14:05:42 +0000 |
---|---|---|
committer | jhb <jhb@FreeBSD.org> | 2008-10-07 14:05:42 +0000 |
commit | 2ac32d531613345918554d962ea346c9b3afa78b (patch) | |
tree | 2c513771069e88df6ac6ec7ff267ed9fc9dc3e13 | |
parent | a9a8df42d11fa8fcb89948c073db7b2e4319a8f6 (diff) | |
download | FreeBSD-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
-rw-r--r-- | sys/boot/i386/libi386/bootinfo64.c | 48 |
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); /* |