Run Nindent on com32/modules/sanboot.c
[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 }