[FREELDR] Limit the usage of DiskStopFloppyMotor() in hardware/platform-specific...
[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 ChainLoadBiosBootSectorCode(0 /*DriveNumber*/, 0 /*PartitionNumber*/);
122 /* Must not return! */
123 return ESUCCESS;
124 }
125
126 static ARC_STATUS
127 LoadAndBootPartitionOrDrive(
128 IN UCHAR DriveNumber,
129 IN ULONG PartitionNumber OPTIONAL,
130 IN PCSTR BootPath OPTIONAL)
131 {
132 ARC_STATUS Status;
133 ULONG FileId;
134 ULONG BytesRead;
135 CHAR ArcPath[MAX_PATH];
136
137 /*
138 * If the user specifies an ARC "BootPath" value, it takes precedence
139 * over both the DriveNumber and PartitionNumber options.
140 */
141 if (BootPath && *BootPath)
142 {
143 PCSTR FileName = NULL;
144
145 /*
146 * Retrieve the BIOS drive and partition numbers; verify also that the
147 * path is "valid" in the sense that it must not contain any file name.
148 */
149 if (!DissectArcPath(BootPath, &FileName, &DriveNumber, &PartitionNumber) ||
150 (FileName && *FileName))
151 {
152 return EINVAL;
153 }
154 }
155 else
156 {
157 /* We don't have one, so construct the corresponding ARC path */
158 ConstructArcPath(ArcPath, "", DriveNumber, PartitionNumber);
159 *strrchr(ArcPath, '\\') = ANSI_NULL; // Trim the trailing path separator.
160
161 BootPath = ArcPath;
162 }
163
164 /* Open the volume */
165 Status = ArcOpen((PSTR)BootPath, OpenReadOnly, &FileId);
166 if (Status != ESUCCESS)
167 {
168 UiMessageBox("Unable to open %s", BootPath);
169 return Status;
170 }
171
172 /*
173 * Now try to load the partition boot sector or the MBR (when PartitionNumber == 0).
174 * If this fails then abort.
175 */
176 Status = ArcRead(FileId, (PVOID)0x7c00, 512, &BytesRead);
177 ArcClose(FileId);
178 if ((Status != ESUCCESS) || (BytesRead != 512))
179 {
180 if (PartitionNumber != 0)
181 UiMessageBox("Unable to load partition's boot sector.");
182 else
183 UiMessageBox("Unable to load MBR boot sector.");
184 return EIO;
185 }
186
187 /* Check for validity */
188 if (*((USHORT*)(0x7c00 + 0x1fe)) != 0xaa55)
189 {
190 UiMessageBox("Invalid boot sector magic (0xaa55)");
191 return ENOEXEC;
192 }
193
194 UiUnInitialize("Booting...");
195 IniCleanup();
196
197 ChainLoadBiosBootSectorCode(DriveNumber, PartitionNumber);
198 /* Must not return! */
199 return ESUCCESS;
200 }
201
202 ARC_STATUS
203 LoadAndBootPartition(
204 IN ULONG Argc,
205 IN PCHAR Argv[],
206 IN PCHAR Envp[])
207 {
208 PCSTR ArgValue;
209 PCSTR BootPath;
210 UCHAR DriveNumber = 0;
211 ULONG PartitionNumber = 0;
212
213 /* Find all the message box settings and run them */
214 UiShowMessageBoxesInArgv(Argc, Argv);
215
216 /*
217 * Check whether we have a "BootPath" value (takes precedence
218 * over both "BootDrive" and "BootPartition").
219 */
220 BootPath = GetArgumentValue(Argc, Argv, "BootPath");
221 if (!BootPath || !*BootPath)
222 {
223 /* We don't have one */
224
225 /* Retrieve the boot drive */
226 ArgValue = GetArgumentValue(Argc, Argv, "BootDrive");
227 if (!ArgValue || !*ArgValue)
228 {
229 UiMessageBox("Boot drive not specified for selected OS!");
230 return EINVAL;
231 }
232 DriveNumber = DriveMapGetBiosDriveNumber(ArgValue);
233
234 /* Retrieve the boot partition (optional, fall back to zero otherwise) */
235 PartitionNumber = 0;
236 ArgValue = GetArgumentValue(Argc, Argv, "BootPartition");
237 if (ArgValue && *ArgValue)
238 PartitionNumber = atoi(ArgValue);
239 }
240
241 return LoadAndBootPartitionOrDrive(DriveNumber, PartitionNumber, BootPath);
242 }
243
244 ARC_STATUS
245 LoadAndBootDrive(
246 IN ULONG Argc,
247 IN PCHAR Argv[],
248 IN PCHAR Envp[])
249 {
250 PCSTR ArgValue;
251 PCSTR BootPath;
252 UCHAR DriveNumber = 0;
253
254 /* Find all the message box settings and run them */
255 UiShowMessageBoxesInArgv(Argc, Argv);
256
257 /* Check whether we have a "BootPath" value (takes precedence over "BootDrive") */
258 BootPath = GetArgumentValue(Argc, Argv, "BootPath");
259 if (BootPath && *BootPath)
260 {
261 /*
262 * We have one, check that it does not contain any
263 * "partition()" specification, and fail if so.
264 */
265 if (strstr(BootPath, ")partition("))
266 {
267 UiMessageBox("Invalid 'BootPath' value!");
268 return EINVAL;
269 }
270 }
271 else
272 {
273 /* We don't, retrieve the boot drive value instead */
274 ArgValue = GetArgumentValue(Argc, Argv, "BootDrive");
275 if (!ArgValue || !*ArgValue)
276 {
277 UiMessageBox("Boot drive not specified for selected OS!");
278 return EINVAL;
279 }
280 DriveNumber = DriveMapGetBiosDriveNumber(ArgValue);
281 }
282
283 return LoadAndBootPartitionOrDrive(DriveNumber, 0, BootPath);
284 }
285
286 #endif // _M_IX86