diff options
Diffstat (limited to 'contrib/syslinux-4.02/com32/modules/ifcpu64.c')
-rw-r--r-- | contrib/syslinux-4.02/com32/modules/ifcpu64.c | 125 |
1 files changed, 125 insertions, 0 deletions
diff --git a/contrib/syslinux-4.02/com32/modules/ifcpu64.c b/contrib/syslinux-4.02/com32/modules/ifcpu64.c new file mode 100644 index 0000000..e123922 --- /dev/null +++ b/contrib/syslinux-4.02/com32/modules/ifcpu64.c @@ -0,0 +1,125 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2008 H. Peter Anvin - All Rights Reserved + * + * 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, Inc., 51 Franklin St, Fifth Floor, + * Boston MA 02110-1301, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +/* + * ifcpu64.c + * + * Run one command if the CPU has 64-bit support, and another if it doesn't. + * Eventually this and other features should get folded into some kind + * of scripting engine. + * + * Usage: + * + * label boot_kernel + * com32 ifcpu64.c32 + * append boot_kernel_64 [-- boot_kernel_32pae] -- boot_kernel_32 + * label boot_kernel_32 + * kernel vmlinuz_32 + * append ... + * label boot_kernel_64 + * kernel vmlinuz_64 + * append ... + */ + +#include <alloca.h> +#include <stdlib.h> +#include <string.h> +#include <cpuid.h> +#include <syslinux/boot.h> + +static bool __constfunc cpu_has_cpuid(void) +{ + return cpu_has_eflag(X86_EFLAGS_ID); +} + +static bool __constfunc cpu_has_level(uint32_t level) +{ + uint32_t group; + uint32_t limit; + + if (!cpu_has_cpuid()) + return false; + + group = level & 0xffff0000; + limit = cpuid_eax(group); + + if ((limit & 0xffff0000) != group) + return false; + + if (level > limit) + return false; + + return true; +} + +/* This only supports feature groups 0 and 1, corresponding to the + Intel and AMD EDX bit vectors. We can add more later if need be. */ +static bool __constfunc cpu_has_feature(int x) +{ + uint32_t level = ((x & 1) << 31) | 1; + + return cpu_has_level(level) && ((cpuid_edx(level) >> (x & 31) & 1)); +} + +/* XXX: this really should be librarized */ +static void boot_args(char **args) +{ + int len = 0, a = 0; + char **pp; + const char *p; + char c, *q, *str; + + for (pp = args; *pp; pp++) + len += strlen(*pp) + 1; + + q = str = alloca(len); + for (pp = args; *pp; pp++) { + p = *pp; + while ((c = *p++)) + *q++ = c; + *q++ = ' '; + a = 1; + } + q -= a; + *q = '\0'; + + if (!str[0]) + syslinux_run_default(); + else + syslinux_run_command(str); +} + +int main(int argc, char *argv[]) +{ + char **args[3]; + int i; + int n; + + args[0] = &argv[1]; + n = 1; + for (i = 1; i < argc; i++) { + if (!strcmp(argv[i], "--")) { + argv[i] = NULL; + args[n++] = &argv[i + 1]; + } + if (n >= 3) + break; + } + while (n < 3) { + args[n] = args[n - 1]; + n++; + } + + boot_args(cpu_has_feature(X86_FEATURE_LM) ? args[0] : + cpu_has_feature(X86_FEATURE_PAE) ? args[1] : args[2]); + return -1; +} |