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 
39 static bool __constfunc cpu_has_cpuid(void)
40 {
41     return cpu_has_eflag(X86_EFLAGS_ID);
42 }
43 
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. */
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 */
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 
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