2007-05-18 Robert Millan * i386/cpuid.c: New module. * DISTLIST: Add it. * conf/i386-efi.rmk: Enable cpuid.mod. * conf/i386-pc.rmk: Likewise. diff -x i386-efi.mk -x i386-pc.mk -Nur grub2-1.95+20070515.old/conf/i386-efi.rmk grub2-1.95+20070515/conf/i386-efi.rmk --- grub2-1.95+20070515.old/conf/i386-efi.rmk 2007-05-18 13:07:26.000000000 +0200 +++ grub2-1.95+20070515/conf/i386-efi.rmk 2007-05-18 13:44:49.000000000 +0200 @@ -70,7 +70,7 @@ # Modules. pkgdata_MODULES = kernel.mod normal.mod _chain.mod chain.mod \ - _linux.mod linux.mod + _linux.mod linux.mod cpuid.mod # For kernel.mod. kernel_mod_EXPORTS = no @@ -129,4 +129,9 @@ linux_mod_CFLAGS = $(COMMON_CFLAGS) linux_mod_LDFLAGS = $(COMMON_LDFLAGS) +# For cpuid.mod. +cpuid_mod_SOURCES = i386/cpuid.c +cpuid_mod_CFLAGS = $(COMMON_CFLAGS) +cpuid_mod_LDFLAGS = $(COMMON_LDFLAGS) + include $(srcdir)/conf/common.mk diff -x i386-efi.mk -x i386-pc.mk -Nur grub2-1.95+20070515.old/conf/i386-pc.rmk grub2-1.95+20070515/conf/i386-pc.rmk --- grub2-1.95+20070515.old/conf/i386-pc.rmk 2007-05-05 01:00:56.000000000 +0200 +++ grub2-1.95+20070515/conf/i386-pc.rmk 2007-05-18 13:41:07.000000000 +0200 @@ -120,7 +120,7 @@ pkgdata_MODULES = _chain.mod _linux.mod linux.mod normal.mod \ _multiboot.mod chain.mod multiboot.mod reboot.mod halt.mod \ vbe.mod vbetest.mod vbeinfo.mod video.mod gfxterm.mod \ - videotest.mod play.mod bitmap.mod tga.mod + videotest.mod play.mod bitmap.mod tga.mod cpuid.mod # For _chain.mod. _chain_mod_SOURCES = loader/i386/pc/chainloader.c @@ -224,4 +224,9 @@ tga_mod_CFLAGS = $(COMMON_CFLAGS) tga_mod_LDFLAGS = $(COMMON_LDFLAGS) +# For cpuid.mod. +cpuid_mod_SOURCES = i386/cpuid.c +cpuid_mod_CFLAGS = $(COMMON_CFLAGS) +cpuid_mod_LDFLAGS = $(COMMON_LDFLAGS) + include $(srcdir)/conf/common.mk diff -x i386-efi.mk -x i386-pc.mk -Nur grub2-1.95+20070515.old/DISTLIST grub2-1.95+20070515/DISTLIST --- grub2-1.95+20070515.old/DISTLIST 2007-05-04 09:11:44.000000000 +0200 +++ grub2-1.95+20070515/DISTLIST 2007-05-18 13:37:05.000000000 +0200 @@ -81,6 +81,7 @@ fs/xfs.c fs/hfsplus.c hello/hello.c +i386/cpuid.c include/grub/acorn_filecore.h include/grub/arg.h include/grub/bitmap.h diff -x i386-efi.mk -x i386-pc.mk -Nur grub2-1.95+20070515.old/i386/cpuid.c grub2-1.95+20070515/i386/cpuid.c --- grub2-1.95+20070515.old/i386/cpuid.c 1970-01-01 01:00:00.000000000 +0100 +++ grub2-1.95+20070515/i386/cpuid.c 2007-05-18 13:33:35.000000000 +0200 @@ -0,0 +1,73 @@ +/* cpuid.c - test for CPU features */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2006, 2007 Free Software Foundation, Inc. + * Based on gcc/gcc/config/i386/driver-i386.c + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include + +#define cpuid(num,a,b,c,d) \ + asm volatile ("xchgl %%ebx, %1; cpuid; xchgl %%ebx, %1" \ + : "=a" (a), "=r" (b), "=c" (c), "=d" (d) \ + : "0" (num)) + +#define bit_LM (1 << 29) + +GRUB_MOD_INIT(cpuid) +{ + unsigned int eax, ebx, ecx, edx; + unsigned int max_level; + unsigned int ext_level; + unsigned char has_longmode = 0; + + /* See if we can use cpuid. */ + asm volatile ("pushfl; pushfl; popl %0; movl %0,%1; xorl %2,%0;" + "pushl %0; popfl; pushfl; popl %0; popfl" + : "=&r" (eax), "=&r" (ebx) + : "i" (0x00200000)); + if (((eax ^ ebx) & 0x00200000) == 0) + goto done; + + /* Check the highest input value for eax. */ + cpuid (0, eax, ebx, ecx, edx); + /* We only look at the first four characters. */ + max_level = eax; + if (max_level == 0) + goto done; + + cpuid (0x80000000, eax, ebx, ecx, edx); + ext_level = eax; + if (ext_level < 0x80000000) + goto done; + + cpuid (0x80000001, eax, ebx, ecx, edx); + has_longmode = !!(edx & bit_LM); + +done: + grub_env_set ("cpuid_long_mode", has_longmode ? "1" : "0"); +} + +GRUB_MOD_FINI(cpuid) +{ + grub_env_unset ("cpuid_long_mode"); +}