[FREELDR] Other enhancements.
[reactos.git] / boot / freeldr / freeldr / miscboot.c
1 /*
2 * FreeLoader
3 * Copyright (C) 1998-2003 Brian Palmer <brianp@sginet.com>
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; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #ifdef _M_IX86
21
22 /* INCLUDES *******************************************************************/
23
24 #include <freeldr.h>
25
26 /* FUNCTIONS ******************************************************************/
27
28 ARC_STATUS
29 LoadAndBootBootSector(
30 IN ULONG Argc,
31 IN PCHAR Argv[],
32 IN PCHAR Envp[])
33 {
34 ARC_STATUS Status;
35 PCSTR ArgValue;
36 PCSTR BootPath;
37 PCSTR FileName;
38 UCHAR DriveNumber = 0;
39 ULONG PartitionNumber = 0;
40 ULONG FileId;
41 ULONG BytesRead;
42 CHAR ArcPath[MAX_PATH];
43
44 /* Find all the message box settings and run them */
45 UiShowMessageBoxesInArgv(Argc, Argv);
46
47 /*
48 * Check whether we have a "BootPath" value (takes precedence
49 * over both "BootDrive" and "BootPartition").
50 */
51 BootPath = GetArgumentValue(Argc, Argv, "BootPath");
52 if (!BootPath || !*BootPath)
53 {
54 /* We don't have one, check whether we use "BootDrive" and "BootPartition" */
55
56 /* Retrieve the boot drive (optional, fall back to using default path otherwise) */
57 ArgValue = GetArgumentValue(Argc, Argv, "BootDrive");
58 if (ArgValue && *ArgValue)
59 {
60 DriveNumber = DriveMapGetBiosDriveNumber(ArgValue);
61
62 /* Retrieve the boot partition (not optional and cannot be zero) */
63 PartitionNumber = 0;
64 ArgValue = GetArgumentValue(Argc, Argv, "BootPartition");
65 if (ArgValue && *ArgValue)
66 PartitionNumber = atoi(ArgValue);
67 if (PartitionNumber == 0)
68 {
69 UiMessageBox("Boot partition cannot be 0!");
70 return EINVAL;
71 }
72
73 /* Construct the corresponding ARC path */
74 ConstructArcPath(ArcPath, "", DriveNumber, PartitionNumber);
75 *strrchr(ArcPath, '\\') = ANSI_NULL; // Trim the trailing path separator.
76
77 BootPath = ArcPath;
78 }
79 else
80 {
81 /* Fall back to using the system partition as default path */
82 BootPath = GetArgumentValue(Argc, Argv, "SystemPartition");
83 }
84 }
85
86 /* Retrieve the file name */
87 FileName = GetArgumentValue(Argc, Argv, "BootSectorFile");
88 if (!FileName || !*FileName)
89 {
90 UiMessageBox("Boot sector file not specified for selected OS!");
91 return EINVAL;
92 }
93
94 /* Open the boot sector file */
95 Status = FsOpenFile(FileName, BootPath, OpenReadOnly, &FileId);
96 if (Status != ESUCCESS)
97 {
98 UiMessageBox("Unable to open %s", FileName);
99 return Status;
100 }
101
102 /* Now try to load the boot sector. If this fails then abort. */
103 Status = ArcRead(FileId, (PVOID)0x7c00, 512, &BytesRead);
104 ArcClose(FileId);
105 if ((Status != ESUCCESS) || (BytesRead != 512))
106 {
107 UiMessageBox("Unable to load boot sector.");
108 return EIO;
109 }
110
111 /* Check for validity */
112 if (*((USHORT*)(0x7c00 + 0x1fe)) != 0xaa55)
113 {
114 UiMessageBox("Invalid boot sector magic (0xaa55)");
115 return ENOEXEC;
116 }
117
118 UiUnInitialize("Booting...");
119 IniCleanup();
120
121 /*
122 * Don't stop the floppy drive motor when we
123 * are just booting a bootsector, or drive, or partition.
124 * If we were to stop the floppy motor then
125 * the BIOS wouldn't be informed and if the
126 * next read is to a floppy then the BIOS will
127 * still think the motor is on and this will
128 * result in a read error.
129 */
130 // DiskStopFloppyMotor();
131 ChainLoadBiosBootSectorCode(0 /*DriveNumber*/, 0 /*PartitionNumber*/);
132 /* Must not return! */
133 return ESUCCESS;
134 }
135
136 static ARC_STATUS
137 LoadAndBootPartitionOrDrive(
138 IN UCHAR DriveNumber,
139 IN ULONG PartitionNumber OPTIONAL,
140 IN PCSTR BootPath OPTIONAL)
141 {
142 ARC_STATUS Status;
143 ULONG FileId;
144 ULONG BytesRead;
145 CHAR ArcPath[MAX_PATH];
146
147 /*
148 * If the user specifies an ARC "BootPath" value, it takes precedence
149 * over both the DriveNumber and PartitionNumber options.
150 */
151 if (BootPath && *BootPath)
152 {
153 PCSTR FileName = NULL;
154
155 /*
156 * Retrieve the BIOS drive and partition numbers; verify also that the
157 * path is "valid" in the sense that it must not contain any file name.
158 */
159 if (!DissectArcPath(BootPath, &FileName, &DriveNumber, &PartitionNumber) ||
160 (FileName && *FileName))
161 {
162 return EINVAL;
163 }
164 }
165 else
166 {
167 /* We don't have one, so construct the corresponding ARC path */
168 ConstructArcPath(ArcPath, "", DriveNumber, PartitionNumber);
169 *strrchr(ArcPath, '\\') = ANSI_NULL; // Trim the trailing path separator.
170
171 BootPath = ArcPath;
172 }
173
174 /* Open the volume */
175 Status = ArcOpen((PSTR)BootPath, OpenReadOnly, &FileId);
176 if (Status != ESUCCESS)
177 {
178 UiMessageBox("Unable to open %s", BootPath);
179 return Status;
180 }
181
182 /*
183 * Now try to load the partition boot sector or the MBR (when PartitionNumber == 0).
184 * If this fails then abort.
185 */
186 Status = ArcRead(FileId, (PVOID)0x7c00, 512, &BytesRead);
187 ArcClose(FileId);
188 if ((Status != ESUCCESS) || (BytesRead != 512))
189 {
190 if (PartitionNumber != 0)
191 UiMessageBox("Unable to load partition's boot sector.");
192 else
193 UiMessageBox("Unable to load MBR boot sector.");
194 return EIO;
195 }
196
197 /* Check for validity */
198 if (*((USHORT*)(0x7c00 + 0x1fe)) != 0xaa55)
199 {
200 UiMessageBox("Invalid boot sector magic (0xaa55)");
201 return ENOEXEC;
202 }
203
204 UiUnInitialize("Booting...");
205 IniCleanup();
206
207 /*
208 * Don't stop the floppy drive motor when we
209 * are just booting a bootsector, or drive, or partition.
210 * If we were to stop the floppy motor then
211 * the BIOS wouldn't be informed and if the
212 * next read is to a floppy then the BIOS will
213 * still think the motor is on and this will
214 * result in a read error.
215 */
216 // DiskStopFloppyMotor();
217 ChainLoadBiosBootSectorCode(DriveNumber, PartitionNumber);
218 /* Must not return! */
219 return ESUCCESS;
220 }
221
222 ARC_STATUS
223 LoadAndBootPartition(
224 IN ULONG Argc,
225 IN PCHAR Argv[],
226 IN PCHAR Envp[])
227 {
228 PCSTR ArgValue;
229 PCSTR BootPath;
230 UCHAR DriveNumber = 0;
231 ULONG PartitionNumber = 0;
232
233 /* Find all the message box settings and run them */
234 UiShowMessageBoxesInArgv(Argc, Argv);
235
236 /*
237 * Check whether we have a "BootPath" value (takes precedence
238 * over both "BootDrive" and "BootPartition").
239 */
240 BootPath = GetArgumentValue(Argc, Argv, "BootPath");
241 if (!BootPath || !*BootPath)
242 {
243 /* We don't have one */
244
245 /* Retrieve the boot drive */
246 ArgValue = GetArgumentValue(Argc, Argv, "BootDrive");
247 if (!ArgValue || !*ArgValue)
248 {
249 UiMessageBox("Boot drive not specified for selected OS!");
250 return EINVAL;
251 }
252 DriveNumber = DriveMapGetBiosDriveNumber(ArgValue);
253
254 /* Retrieve the boot partition (optional, fall back to zero otherwise) */
255 PartitionNumber = 0;
256 ArgValue = GetArgumentValue(Argc, Argv, "BootPartition");
257 if (ArgValue && *ArgValue)
258 PartitionNumber = atoi(ArgValue);
259 }
260
261 return LoadAndBootPartitionOrDrive(DriveNumber, PartitionNumber, BootPath);
262 }
263
264 ARC_STATUS
265 LoadAndBootDrive(
266 IN ULONG Argc,
267 IN PCHAR Argv[],
268 IN PCHAR Envp[])
269 {
270 PCSTR ArgValue;
271 PCSTR BootPath;
272 UCHAR DriveNumber = 0;
273
274 /* Find all the message box settings and run them */
275 UiShowMessageBoxesInArgv(Argc, Argv);
276
277 /* Check whether we have a "BootPath" value (takes precedence over "BootDrive") */
278 BootPath = GetArgumentValue(Argc, Argv, "BootPath");
279 if (BootPath && *BootPath)
280 {
281 /*
282 * We have one, check that it does not contain any
283 * "partition()" specification, and fail if so.
284 */
285 if (strstr(BootPath, ")partition("))
286 {
287 UiMessageBox("Invalid 'BootPath' value!");
288 return EINVAL;
289 }
290 }
291 else
292 {
293 /* We don't, retrieve the boot drive value instead */
294 ArgValue = GetArgumentValue(Argc, Argv, "BootDrive");
295 if (!ArgValue || !*ArgValue)
296 {
297 UiMessageBox("Boot drive not specified for selected OS!");
298 return EINVAL;
299 }
300 DriveNumber = DriveMapGetBiosDriveNumber(ArgValue);
301 }
302
303 return LoadAndBootPartitionOrDrive(DriveNumber, 0, BootPath);
304 }
305
306 #endif // _M_IX86