From: Alex Hornung Date: Wed, 29 Feb 2012 15:46:48 +0000 (+0000) Subject: boot/loader - test if CPU supports long mode X-Git-Tag: v3.2.0~1295 X-Git-Url: https://gitweb.dragonflybsd.org/dragonfly.git/commitdiff_plain/71920ddbfafa6ebd2812dc32ea61f7d69c05175b boot/loader - test if CPU supports long mode * Test if the CPU supports long mode (64 bits) before trying to load an x86_64 kernel. Obtained-from: FreeBSD Dragonfly-bug: http://bugs.dragonflybsd.org/issue1624 --- diff --git a/sys/boot/pc32/libi386/bootinfo64.c b/sys/boot/pc32/libi386/bootinfo64.c index 39b85be813..f31ad4420e 100644 --- a/sys/boot/pc32/libi386/bootinfo64.c +++ b/sys/boot/pc32/libi386/bootinfo64.c @@ -32,6 +32,9 @@ #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); /*