Home | History | Annotate | Download | only in modules
      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