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