6a9cb569e299d38d7d2d6ea2c28d3833d842aeb9
[reactos.git] / boot / freeldr / freeldr / bootmgr.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 /* INCLUDES *******************************************************************/
21
22 #include <freeldr.h>
23 #include <debug.h>
24
25 DBG_DEFAULT_CHANNEL(INIFILE);
26
27 /* GLOBALS ********************************************************************/
28
29 static const struct
30 {
31 PCSTR BootType;
32 ARC_ENTRY_POINT OsLoader;
33 } OSLoadingMethods[] =
34 {
35 {"ReactOSSetup", LoadReactOSSetup },
36
37 #ifdef _M_IX86
38 {"BootSector" , LoadAndBootBootSector},
39 {"Drive" , LoadAndBootDrive },
40 {"Partition" , LoadAndBootPartition },
41
42 {"Linux" , LoadAndBootLinux },
43
44 {"Windows" , LoadAndBootWindows },
45 {"WindowsNT40" , LoadAndBootWindows },
46 #endif
47 {"Windows2003" , LoadAndBootWindows },
48 };
49
50 /* FUNCTIONS ******************************************************************/
51
52 PCHAR*
53 BuildArgvForOsLoader(
54 IN PCSTR LoadIdentifier,
55 IN ULONG_PTR SectionId,
56 OUT PULONG pArgc)
57 {
58 SIZE_T Size;
59 ULONG Count;
60 ULONG i;
61 ULONG Argc;
62 PCHAR* Argv;
63 PCHAR* Args;
64 PCHAR SettingName, SettingValue;
65
66 /*
67 * Convert the list of key=value options in the given operating system section
68 * into a ARC-compatible argument vector.
69 */
70
71 *pArgc = 0;
72
73 /* Validate the LoadIdentifier (to make tests simpler later) */
74 if (LoadIdentifier && !*LoadIdentifier)
75 LoadIdentifier = NULL;
76
77 /* Count the number of operating systems in the section */
78 Count = IniGetNumSectionItems(SectionId);
79
80 /* The argument vector contains the program name, the LoadIdentifier (optional), and the items in the OS section */
81 Argc = 1 + Count;
82 if (LoadIdentifier)
83 ++Argc;
84
85 /* Calculate the total size needed for the string buffer of the argument vector */
86 Size = 0;
87 /* i == 0: Program name */
88 /* i == 1: LoadIdentifier */
89 if (LoadIdentifier)
90 {
91 Size += (strlen("LoadIdentifier=") + strlen(LoadIdentifier) + 1) * sizeof(CHAR);
92 }
93 for (i = 0; i < Count; ++i)
94 {
95 Size += IniGetSectionSettingNameSize(SectionId, i); // Counts also the NULL-terminator, that we transform into the '=' sign separator.
96 Size += IniGetSectionSettingValueSize(SectionId, i); // Counts also the NULL-terminator.
97 }
98 Size += sizeof(ANSI_NULL); // Final NULL-terminator.
99
100 /* Allocate memory to hold the argument vector: pointers and string buffer */
101 Argv = FrLdrHeapAlloc(Argc * sizeof(PCHAR) + Size, TAG_STRING);
102 if (!Argv)
103 return NULL;
104
105 /* Initialize the argument vector: loop through the section and copy the key=value options */
106 SettingName = (PCHAR)((ULONG_PTR)Argv + (Argc * sizeof(PCHAR)));
107 Args = Argv;
108 /* i == 0: Program name */
109 *Args++ = NULL;
110 /* i == 1: LoadIdentifier */
111 if (LoadIdentifier)
112 {
113 strcpy(SettingName, "LoadIdentifier=");
114 strcat(SettingName, LoadIdentifier);
115
116 *Args++ = SettingName;
117 SettingName += (strlen(SettingName) + 1);
118 }
119 for (i = 0; i < Count; ++i)
120 {
121 Size = IniGetSectionSettingNameSize(SectionId, i);
122 SettingValue = SettingName + Size;
123 IniReadSettingByNumber(SectionId, i,
124 SettingName, Size,
125 SettingValue, IniGetSectionSettingValueSize(SectionId, i));
126 SettingName[Size - 1] = '=';
127
128 *Args++ = SettingName;
129 SettingName += (strlen(SettingName) + 1);
130 }
131
132 #if DBG
133 /* Dump the argument vector for debugging */
134 for (i = 0; i < Argc; ++i)
135 {
136 TRACE("Argv[%lu]: '%s'\n", i, Argv[i]);
137 }
138 #endif
139
140 *pArgc = Argc;
141 return Argv;
142 }
143
144 VOID LoadOperatingSystem(IN OperatingSystemItem* OperatingSystem)
145 {
146 ULONG_PTR SectionId;
147 PCSTR SectionName = OperatingSystem->SectionName;
148 ULONG i;
149 ULONG Argc;
150 PCHAR* Argv;
151 CHAR BootType[80];
152
153 /* Try to open the operating system section in the .ini file */
154 if (!IniOpenSection(SectionName, &SectionId))
155 {
156 UiMessageBox("Section [%s] not found in freeldr.ini.", SectionName);
157 return;
158 }
159
160 /* Try to read the boot type */
161 *BootType = ANSI_NULL;
162 IniReadSettingByName(SectionId, "BootType", BootType, sizeof(BootType));
163
164 /* We must have the "BootType" value (it has been possibly added by InitOperatingSystemList()) */
165 ASSERT(*BootType);
166
167 #ifdef _M_IX86
168 /* Install the drive mapper according to this section drive mappings */
169 DriveMapMapDrivesInSection(SectionName);
170 #endif
171
172 /* Loop through the OS loading method table and find a suitable OS to boot */
173 for (i = 0; i < sizeof(OSLoadingMethods) / sizeof(OSLoadingMethods[0]); ++i)
174 {
175 if (_stricmp(BootType, OSLoadingMethods[i].BootType) == 0)
176 {
177 Argv = BuildArgvForOsLoader(OperatingSystem->LoadIdentifier, SectionId, &Argc);
178 if (Argv)
179 {
180 OSLoadingMethods[i].OsLoader(Argc, Argv, NULL);
181 FrLdrHeapFree(Argv, TAG_STRING);
182 }
183 return;
184 }
185 }
186 }
187
188 LONG GetTimeOut(VOID)
189 {
190 CHAR TimeOutText[20];
191 LONG TimeOut;
192 ULONG_PTR SectionId;
193
194 TimeOut = CmdLineGetTimeOut();
195 if (TimeOut >= 0)
196 return TimeOut;
197
198 if (!IniOpenSection("FreeLoader", &SectionId))
199 return -1;
200
201 if (IniReadSettingByName(SectionId, "TimeOut", TimeOutText, sizeof(TimeOutText)))
202 TimeOut = atoi(TimeOutText);
203 else
204 TimeOut = -1;
205
206 return TimeOut;
207 }
208
209 BOOLEAN MainBootMenuKeyPressFilter(ULONG KeyPress)
210 {
211 if (KeyPress == KEY_F8)
212 {
213 DoOptionsMenu();
214 return TRUE;
215 }
216
217 /* We didn't handle the key */
218 return FALSE;
219 }
220
221 VOID RunLoader(VOID)
222 {
223 ULONG_PTR SectionId;
224 LONG TimeOut;
225 ULONG OperatingSystemCount;
226 OperatingSystemItem* OperatingSystemList;
227 PCSTR* OperatingSystemDisplayNames;
228 ULONG DefaultOperatingSystem;
229 ULONG SelectedOperatingSystem;
230 ULONG i;
231
232 if (!MachInitializeBootDevices())
233 {
234 UiMessageBoxCritical("Error when detecting hardware.");
235 return;
236 }
237
238 #ifdef _M_IX86
239 /* Load additional SCSI driver (if any) */
240 if (LoadBootDeviceDriver() != ESUCCESS)
241 {
242 UiMessageBoxCritical("Unable to load additional boot device drivers.");
243 }
244 #endif
245
246 if (!IniFileInitialize())
247 {
248 UiMessageBoxCritical("Error initializing .ini file.");
249 return;
250 }
251
252 /* Debugger main initialization */
253 DebugInit(TRUE);
254
255 if (!IniOpenSection("FreeLoader", &SectionId))
256 {
257 UiMessageBoxCritical("Section [FreeLoader] not found in freeldr.ini.");
258 return;
259 }
260
261 TimeOut = GetTimeOut();
262
263 /* UI main initialization */
264 if (!UiInitialize(TRUE))
265 {
266 UiMessageBoxCritical("Unable to initialize UI.");
267 return;
268 }
269
270 OperatingSystemList = InitOperatingSystemList(&OperatingSystemCount,
271 &DefaultOperatingSystem);
272 if (!OperatingSystemList)
273 {
274 UiMessageBox("Unable to read operating systems section in freeldr.ini.\nPress ENTER to reboot.");
275 goto Reboot;
276 }
277 if (OperatingSystemCount == 0)
278 {
279 UiMessageBox("There were no operating systems listed in freeldr.ini.\nPress ENTER to reboot.");
280 goto Reboot;
281 }
282
283 /* Create list of display names */
284 OperatingSystemDisplayNames = FrLdrTempAlloc(sizeof(PCSTR) * OperatingSystemCount, 'mNSO');
285 if (!OperatingSystemDisplayNames)
286 goto Reboot;
287
288 for (i = 0; i < OperatingSystemCount; i++)
289 {
290 OperatingSystemDisplayNames[i] = OperatingSystemList[i].LoadIdentifier;
291 }
292
293 /* Find all the message box settings and run them */
294 UiShowMessageBoxesInSection("FreeLoader");
295
296 for (;;)
297 {
298 /* Redraw the backdrop */
299 UiDrawBackdrop();
300
301 /* Show the operating system list menu */
302 if (!UiDisplayMenu("Please select the operating system to start:",
303 "For troubleshooting and advanced startup options for "
304 "ReactOS, press F8.",
305 TRUE,
306 OperatingSystemDisplayNames,
307 OperatingSystemCount,
308 DefaultOperatingSystem,
309 TimeOut,
310 &SelectedOperatingSystem,
311 FALSE,
312 MainBootMenuKeyPressFilter))
313 {
314 UiMessageBox("Press ENTER to reboot.");
315 goto Reboot;
316 }
317
318 TimeOut = -1;
319
320 /* Load the chosen operating system */
321 LoadOperatingSystem(&OperatingSystemList[SelectedOperatingSystem]);
322 }
323
324 Reboot:
325 UiUnInitialize("Rebooting...");
326 IniCleanup();
327 return;
328 }