expand.c revision a5602e1bdcf9570fa24684b54cf57a3f22e05ae1
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 1999,2000,2001,2002,2003,2004 Free Software Foundation, Inc.
* Copyright (c) 2013 Joyent, Inc. All rights reserved.
*
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <expand.h>
#include <shared.h>
#ifdef SUPPORT_NETBOOT
#include <grub.h>
#endif
#include <cpu.h>
#define EVF_DEFINED 0x01
#define EVF_VALUESET 0x02
typedef struct variable {
char v_name[EV_NAMELEN];
unsigned int v_flags;
} variable_t;
static const unsigned int nexpvars = 32;
int
{
unsigned int i;
return (ERR_WONT_FIT);
return (ERR_WONT_FIT);
for (i = 0; i < nexpvars; i++) {
break;
} else if (i < avail) {
avail = i;
}
}
if (i == nexpvars) {
return (ERR_WONT_FIT);
i = avail;
}
} else {
}
return (0);
}
const char *
get_variable(const char *name)
{
unsigned int i;
for (i = 0; i < nexpvars; i++) {
continue;
return ("");
}
}
return (NULL);
}
static int
{
/*
* This function returns 16 bits. The upper 8 are the value of %ah
* after calling int 15/ec00. The lower 8 bits are zero if the BIOS
* call left CF clear, nonzero otherwise.
*/
ret >>= 8;
grub_printf("[BIOS 'Detect Target Operating Mode' "
"callback unsupported on this platform]\n");
return (1); /* unsupported, ignore */
}
grub_printf("[BIOS accepted mixed-mode target setting!]\n");
return (1); /* told the bios what we're up to */
}
grub_printf("fatal: BIOS reports this machine CANNOT run in "
"mixed 32/64-bit mode!\n");
return (0);
}
grub_printf("warning: BIOS Detect Target Operating Mode callback "
return (1);
}
static int
amd64_config_cpu(void)
{
char vendor[13];
int isamd64 = 0;
/*
* This check may seem silly, but if the C preprocesor symbol __amd64
* is #defined during compilation, something that may outwardly seem
* like a good idea, uts/common/sys/isa_defs.h will #define _LP64,
* which will cause uts/common/sys/int_types.h to typedef uint64_t as
* an unsigned long - which is only 4 bytes in size when using a 32-bit
* compiler.
*
* If that happens, all the page table translation routines will fail
* horribly, so check the size of uint64_t just to insure some degree
* of sanity in future operations.
*/
/*LINTED [sizeof result is invarient]*/
if (sizeof (uint64_t) != 8)
prom_panic("grub compiled improperly, unable to boot "
"64-bit AMD64 executables");
/*
* If the CPU doesn't support the CPUID instruction, it's definitely
* not an AMD64.
*/
if (amd64_cpuid_supported() == 0)
return (0);
amd64_cpuid_insn(0, vcr);
{
/*LINTED [vendor string from cpuid data]*/
}
if (maxeax > max_maxeax) {
grub_printf("cpu: warning, maxeax was 0x%x -> 0x%x\n",
maxeax, max_maxeax);
maxeax = max_maxeax;
}
if (maxeax < 1)
return (0); /* no additional functions, not an AMD64 */
else {
/*
* themselves as being in family 0xf, but for some reason
* Simics doesn't, and this may change in the future, so
* don't error out if it's not true.
*/
grub_printf("cpu: '%s' family %d model %d step %d\n",
}
if (xmaxeax > max_xmaxeax) {
grub_printf("amd64: warning, xmaxeax was "
}
if (xmaxeax >= 0x80000001) {
}
}
isamd64++;
else
grub_printf("amd64: CPU does NOT support long mode\n");
if (!BITX(stdfeatures, 0, 0)) {
grub_printf("amd64: CPU does NOT support FPU\n");
isamd64--;
}
grub_printf("amd64: CPU does NOT support TSC\n");
isamd64--;
}
grub_printf("amd64: CPU does NOT support MSRs\n");
isamd64--;
}
grub_printf("amd64: CPU does NOT support PAE\n");
isamd64--;
}
grub_printf("amd64: CPU does NOT support CX8\n");
isamd64--;
}
grub_printf("amd64: CPU does NOT support PGE\n");
isamd64--;
}
grub_printf("amd64: CPU does NOT support CLFSH\n");
isamd64--;
}
grub_printf("amd64: CPU does NOT support MMX\n");
isamd64--;
}
grub_printf("amd64: CPU does NOT support FXSR\n");
isamd64--;
}
grub_printf("amd64: CPU does NOT support SSE\n");
isamd64--;
}
grub_printf("amd64: CPU does NOT support SSE2\n");
isamd64--;
}
if (isamd64 < 1) {
grub_printf("amd64: CPU does not support amd64 executables.\n");
return (0);
}
if (efer & AMD_EFER_SCE)
grub_printf("amd64: EFER_SCE (syscall/sysret) already "
"enabled\n");
if (efer & AMD_EFER_NXE)
grub_printf("amd64: EFER_NXE (no-exec prot) already enabled\n");
if (efer & AMD_EFER_LME)
grub_printf("amd64: EFER_LME (long mode) already enabled\n");
return (detect_target_operating_mode());
}
static int
isamd64()
{
static int ret = -1;
if (ret == -1)
ret = amd64_config_cpu();
return (ret);
}
static int
check_min_mem64(void)
{
if (min_mem64 == 0)
return (1);
return (1);
return (0);
}
/*
* Given the nul-terminated input string s, expand all variable references
* within that string into the buffer pointed to by d, which must be of length
* not less than len bytes.
*
* We also expand the special case tokens "$ISADIR" and "$ZFS-BOOTFS" here.
*
* If the string will not fit, returns ERR_WONT_FIT.
* If a nonexistent variable is referenced, returns ERR_NOVAR.
* Otherwise, returns 0. The resulting string is nul-terminated. On error,
* the contents of the destination buffer are undefined.
*/
int
expand_string(const char *s, char *d, unsigned int len)
{
unsigned int i;
int vlen;
const char *p;
char *q;
const char *start;
char name[EV_NAMELEN];
const char *val;
for (p = s, q = d; *p != '\0' && q < d + len; ) {
/* Special case: $ISADIR */
if (isamd64() && check_min_mem64()) {
if (q + 5 >= d + len)
return (ERR_WONT_FIT);
q += 5; /* amd64 */
}
p += 7; /* $ISADIR */
continue;
}
/* Special case: $ZFS-BOOTFS */
is_zfs_mount != 0) {
if (current_bootpath[0] == '\0' &&
current_devid[0] == '\0') {
return (ERR_NO_BOOTPATH);
}
/* zfs-bootfs=%s/%u */
vlen += 11;
/* ,bootpath=\"%s\" */
if (current_bootpath[0] != '\0')
/* ,diskdevid=\"%s\" */
if (current_devid[0] != '\0')
return (ERR_WONT_FIT);
if (current_bootfs_obj > 0) {
q += grub_sprintf(q, "zfs-bootfs=%s/%u",
} else {
q += grub_sprintf(q, "zfs-bootfs=%s",
}
if (current_bootpath[0] != '\0') {
q += grub_sprintf(q, ",bootpath=\"%s\"",
}
if (current_devid[0] != '\0') {
q += grub_sprintf(q, ",diskdevid=\"%s\"",
}
p += 11; /* $ZFS-BOOTFS */
continue;
}
if (*p == '$' && *(p + 1) == '{') {
start = p + 2;
}
/*
* Unterminated reference. Copy verbatim.
*/
p = start;
*q++ = '$';
*q++ = '{';
continue;
}
return (ERR_NOVAR);
return (ERR_WONT_FIT);
q += vlen;
p++;
} else {
*q++ = *p++;
}
}
if (q >= d + len)
return (ERR_WONT_FIT);
*q = '\0';
return (0);
}
void
dump_variables(void)
{
unsigned int i;
for (i = 0; i < nexpvars; i++) {
continue;
}
}