1 /* ----------------------------------------------------------------------- *
2 *
3 * Copyright 2008 H. Peter Anvin - All Rights Reserved
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
8 * Boston MA 02110-1301, USA; either version 2 of the License, or
9 * (at your option) any later version; incorporated herein by reference.
10 *
11 * ----------------------------------------------------------------------- */
12
13 /*
14 * ifcpu64.c
15 *
16 * Run one command if the CPU has 64-bit support, and another if it doesn't.
17 * Eventually this and other features should get folded into some kind
18 * of scripting engine.
19 *
20 * Usage:
21 *
22 * label boot_kernel
23 * com32 ifcpu64.c32
24 * append boot_kernel_64 [-- boot_kernel_32pae] -- boot_kernel_32
25 * label boot_kernel_32
26 * kernel vmlinuz_32
27 * append ...
28 * label boot_kernel_64
29 * kernel vmlinuz_64
30 * append ...
31 */
32
33 #include <alloca.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <cpuid.h>
37 #include <syslinux/boot.h>
38
cpu_has_cpuid(void)39 static bool __constfunc cpu_has_cpuid(void)
40 {
41 return cpu_has_eflag(X86_EFLAGS_ID);
42 }
43
cpu_has_level(uint32_t level)44 static bool __constfunc cpu_has_level(uint32_t level)
45 {
46 uint32_t group;
47 uint32_t limit;
48
49 if (!cpu_has_cpuid())
50 return false;
51
52 group = level & 0xffff0000;
53 limit = cpuid_eax(group);
54
55 if ((limit & 0xffff0000) != group)
56 return false;
57
58 if (level > limit)
59 return false;
60
61 return true;
62 }
63
64 /* This only supports feature groups 0 and 1, corresponding to the
65 Intel and AMD EDX bit vectors. We can add more later if need be. */
cpu_has_feature(int x)66 static bool __constfunc cpu_has_feature(int x)
67 {
68 uint32_t level = ((x & 1) << 31) | 1;
69
70 return cpu_has_level(level) && ((cpuid_edx(level) >> (x & 31) & 1));
71 }
72
73 /* XXX: this really should be librarized */
boot_args(char ** args)74 static void boot_args(char **args)
75 {
76 int len = 0, a = 0;
77 char **pp;
78 const char *p;
79 char c, *q, *str;
80
81 for (pp = args; *pp; pp++)
82 len += strlen(*pp) + 1;
83
84 q = str = alloca(len);
85 for (pp = args; *pp; pp++) {
86 p = *pp;
87 while ((c = *p++))
88 *q++ = c;
89 *q++ = ' ';
90 a = 1;
91 }
92 q -= a;
93 *q = '\0';
94
95 if (!str[0])
96 syslinux_run_default();
97 else
98 syslinux_run_command(str);
99 }
100
main(int argc,char * argv[])101 int main(int argc, char *argv[])
102 {
103 char **args[3];
104 int i;
105 int n;
106
107 args[0] = &argv[1];
108 n = 1;
109 for (i = 1; i < argc; i++) {
110 if (!strcmp(argv[i], "--")) {
111 argv[i] = NULL;
112 args[n++] = &argv[i + 1];
113 }
114 if (n >= 3)
115 break;
116 }
117 while (n < 3) {
118 args[n] = args[n - 1];
119 n++;
120 }
121
122 boot_args(cpu_has_feature(X86_FEATURE_LM) ? args[0] :
123 cpu_has_feature(X86_FEATURE_PAE) ? args[1] : args[2]);
124 return -1;
125 }
126