1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
|
/* ----------------------------------------------------------------------- *
*
* 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.
*
* ----------------------------------------------------------------------- */
/*
* sanboot.c
*
* Invoke the gPXE "sanboot" command, if available.
*/
#include <alloca.h>
#include <inttypes.h>
#include <stdio.h>
#include <console.h>
#include <com32.h>
#include <stdbool.h>
#include <string.h>
#include <syslinux/config.h>
struct segoff16 {
uint16_t offs, seg;
};
struct s_PXENV_FILE_CHECK_API {
uint16_t Status;
uint16_t Size;
uint32_t Magic;
uint32_t Provider;
uint32_t APIMask;
uint32_t Flags;
};
static bool is_gpxe(void)
{
const struct syslinux_version *sv;
com32sys_t reg;
struct s_PXENV_FILE_CHECK_API *fca;
sv = syslinux_version();
if (sv->filesystem != SYSLINUX_FS_PXELINUX)
return false; /* Not PXELINUX */
fca = __com32.cs_bounce;
memset(fca, 0, sizeof *fca);
fca->Size = sizeof *fca;
fca->Magic = 0x91d447b2;
memset(®, 0, sizeof reg);
reg.eax.w[0] = 0x0009;
reg.ebx.w[0] = 0x00e6; /* PXENV_FILE_API_CHECK */
reg.edi.w[0] = OFFS(fca);
reg.es = SEG(fca);
__intcall(0x22, ®, ®);
if (reg.eflags.l & EFLAGS_CF)
return false; /* Cannot invoke PXE stack */
if (reg.eax.w[0] || fca->Status)
return false; /* PXE failure */
if (fca->Magic != 0xe9c17b20)
return false; /* Incorrect magic */
if (fca->Size < sizeof *fca)
return false; /* Short return */
if (!(fca->APIMask & (1 << 5)))
return false; /* No FILE EXEC */
return true;
}
struct s_PXENV_FILE_EXEC {
uint16_t Status;
struct segoff16 Command;
};
static void sanboot(const char **args)
{
char *q;
struct s_PXENV_FILE_EXEC *fx;
com32sys_t reg;
memset(®, 0, sizeof reg);
fx = __com32.cs_bounce;
q = (char *)(fx+1);
fx->Status = 1;
fx->Command.offs = OFFS(q);
fx->Command.seg = SEG(q);
q = stpcpy(q, "sanboot");
while (*args) {
*q++ = ' ';
q = stpcpy(q, *args);
args++;
}
memset(®, 0, sizeof reg);
reg.eax.w[0] = 0x0009;
reg.ebx.w[0] = 0x00e5; /* PXENV_FILE_EXEC */
reg.edi.w[0] = OFFS(fx);
reg.es = SEG(fx);
__intcall(0x22, ®, ®);
/* This should not return... */
}
int main(int argc, const char *argv[])
{
openconsole(&dev_null_r, &dev_stdcon_w);
if (argc < 2) {
printf("Usage: sanboot rootpath\n");
return 1;
}
if (!is_gpxe()) {
printf("sanboot: gPXE API not detected\n");
return 1;
}
sanboot(argv+1);
/* sanboot() should not return... */
printf("SAN boot failed.\n");
return 1;
}
|