| /* ----------------------------------------------------------------------- * |
| * |
| * 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; |
| } |