[SETUPLIB] Add two hacks in partlist.c for temporarily setting consistently the disk...
[reactos.git] / boot / freeldr / freeldr / ntldr / setupldr.c
1 /*
2 * PROJECT: FreeLoader
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * PURPOSE: Windows-compatible NT OS Setup Loader.
5 * COPYRIGHT: Copyright 2009-2019 Aleksey Bragin <aleksey@reactos.org>
6 */
7
8 #include <freeldr.h>
9 #include <ndk/ldrtypes.h>
10 #include <arc/setupblk.h>
11 #include "winldr.h"
12 #include "inffile.h"
13 #include "ntldropts.h"
14
15 #include <debug.h>
16 DBG_DEFAULT_CHANNEL(WINDOWS);
17
18 // TODO: Move to .h
19 VOID
20 AllocateAndInitLPB(
21 IN USHORT VersionToBoot,
22 OUT PLOADER_PARAMETER_BLOCK* OutLoaderBlock);
23
24 static VOID
25 SetupLdrLoadNlsData(PLOADER_PARAMETER_BLOCK LoaderBlock, HINF InfHandle, PCSTR SearchPath)
26 {
27 INFCONTEXT InfContext;
28 PCSTR AnsiName, OemName, LangName;
29
30 /* Get ANSI codepage file */
31 if (!InfFindFirstLine(InfHandle, "NLS", "AnsiCodepage", &InfContext))
32 {
33 ERR("Failed to find 'NLS/AnsiCodepage'\n");
34 return;
35 }
36 if (!InfGetDataField(&InfContext, 1, &AnsiName))
37 {
38 ERR("Failed to get load options\n");
39 return;
40 }
41
42 /* Get OEM codepage file */
43 if (!InfFindFirstLine(InfHandle, "NLS", "OemCodepage", &InfContext))
44 {
45 ERR("Failed to find 'NLS/AnsiCodepage'\n");
46 return;
47 }
48 if (!InfGetDataField(&InfContext, 1, &OemName))
49 {
50 ERR("Failed to get load options\n");
51 return;
52 }
53
54 if (!InfFindFirstLine(InfHandle, "NLS", "UnicodeCasetable", &InfContext))
55 {
56 ERR("Failed to find 'NLS/AnsiCodepage'\n");
57 return;
58 }
59 if (!InfGetDataField(&InfContext, 1, &LangName))
60 {
61 ERR("Failed to get load options\n");
62 return;
63 }
64
65 TRACE("NLS data '%s' '%s' '%s'\n", AnsiName, OemName, LangName);
66
67 #if DBG
68 {
69 BOOLEAN Success = WinLdrLoadNLSData(LoaderBlock, SearchPath, AnsiName, OemName, LangName);
70 (VOID)Success;
71 TRACE("NLS data loading %s\n", Success ? "successful" : "failed");
72 }
73 #else
74 WinLdrLoadNLSData(LoaderBlock, SearchPath, AnsiName, OemName, LangName);
75 #endif
76
77 /* TODO: Load OEM HAL font */
78 // Value "OemHalFont"
79 }
80
81 static
82 BOOLEAN
83 SetupLdrInitErrataInf(
84 IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock,
85 IN HINF InfHandle,
86 IN PCSTR SystemRoot)
87 {
88 INFCONTEXT InfContext;
89 PCSTR FileName;
90 ULONG FileSize;
91 PVOID PhysicalBase;
92 CHAR ErrataFilePath[MAX_PATH];
93
94 /* Retrieve the INF file name value */
95 if (!InfFindFirstLine(InfHandle, "BiosInfo", "InfName", &InfContext))
96 {
97 WARN("Failed to find 'BiosInfo/InfName'\n");
98 return FALSE;
99 }
100 if (!InfGetDataField(&InfContext, 1, &FileName))
101 {
102 WARN("Failed to read 'InfName' value\n");
103 return FALSE;
104 }
105
106 RtlStringCbCopyA(ErrataFilePath, sizeof(ErrataFilePath), SystemRoot);
107 RtlStringCbCatA(ErrataFilePath, sizeof(ErrataFilePath), FileName);
108
109 /* Load the INF file */
110 PhysicalBase = WinLdrLoadModule(ErrataFilePath, &FileSize, LoaderRegistryData);
111 if (!PhysicalBase)
112 {
113 WARN("Could not load '%s'\n", ErrataFilePath);
114 return FALSE;
115 }
116
117 LoaderBlock->Extension->EmInfFileImage = PaToVa(PhysicalBase);
118 LoaderBlock->Extension->EmInfFileSize = FileSize;
119
120 return TRUE;
121 }
122
123 static VOID
124 SetupLdrScanBootDrivers(PLIST_ENTRY BootDriverListHead, HINF InfHandle, PCSTR SearchPath)
125 {
126 INFCONTEXT InfContext, dirContext;
127 BOOLEAN Success;
128 PCSTR Media, DriverName, dirIndex, ImagePath;
129 WCHAR ServiceName[256];
130 WCHAR ImagePathW[256];
131
132 /* Open inf section */
133 if (!InfFindFirstLine(InfHandle, "SourceDisksFiles", NULL, &InfContext))
134 return;
135
136 /* Load all listed boot drivers */
137 do
138 {
139 if (InfGetDataField(&InfContext, 7, &Media) &&
140 InfGetDataField(&InfContext, 0, &DriverName) &&
141 InfGetDataField(&InfContext, 13, &dirIndex))
142 {
143 if ((strcmp(Media, "x") == 0) &&
144 InfFindFirstLine(InfHandle, "Directories", dirIndex, &dirContext) &&
145 InfGetDataField(&dirContext, 1, &ImagePath))
146 {
147 /* Convert name to widechar */
148 swprintf(ServiceName, L"%S", DriverName);
149
150 /* Prepare image path */
151 swprintf(ImagePathW, L"%S", ImagePath);
152 wcscat(ImagePathW, L"\\");
153 wcscat(ImagePathW, ServiceName);
154
155 /* Remove .sys extension */
156 ServiceName[wcslen(ServiceName) - 4] = 0;
157
158 /* Add it to the list */
159 Success = WinLdrAddDriverToList(BootDriverListHead,
160 L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\",
161 ImagePathW,
162 ServiceName);
163 if (!Success)
164 {
165 ERR("Could not add boot driver '%s', '%s'\n", SearchPath, DriverName);
166 return;
167 }
168 }
169 }
170 } while (InfFindNextLine(&InfContext, &InfContext));
171 }
172
173
174 /* SETUP STARTER **************************************************************/
175
176 /*
177 * Update the options in the buffer pointed by LoadOptions, of maximum size
178 * BufferSize, by first removing any specified options, and then adding any
179 * other ones.
180 *
181 * OptionsToAdd is a NULL-terminated array of string buffer pointers that
182 * specify the options to be added into LoadOptions. Whether they are
183 * prepended or appended to LoadOptions is controlled via the Append
184 * parameter. The options are added in the order specified by the array.
185 *
186 * OptionsToRemove is a NULL-terminated array of string buffer pointers that
187 * specify the options to remove from LoadOptions. Specifying also there
188 * any options to add, has the effect of removing from LoadOptions any
189 * duplicates of the options to be added, before adding them later into
190 * LoadOptions. The options are removed in the order specified by the array.
191 *
192 * The options string buffers in the OptionsToRemove array have the format:
193 * "/option1 /option2[=] ..."
194 *
195 * An option in the OptionsToRemove list with a trailing '=' or ':' designates
196 * an option in LoadOptions with user-specific data appended after the sign.
197 * When such an option is being removed from LoadOptions, all the appended
198 * data is also removed until the next option.
199 */
200 VOID
201 NtLdrUpdateLoadOptions(
202 IN OUT PSTR LoadOptions,
203 IN ULONG BufferSize,
204 IN BOOLEAN Append,
205 IN PCSTR OptionsToAdd[] OPTIONAL,
206 IN PCSTR OptionsToRemove[] OPTIONAL)
207 {
208 PCSTR NextOptions, NextOpt;
209 PSTR Options, Option;
210 ULONG NextOptLength;
211 ULONG OptionLength;
212
213 if (!LoadOptions || (BufferSize == 0))
214 return;
215 // ASSERT(strlen(LoadOptions) + 1 <= BufferSize);
216
217 /* Loop over the options to remove */
218 for (; OptionsToRemove && *OptionsToRemove; ++OptionsToRemove)
219 {
220 NextOptions = *OptionsToRemove;
221 while ((NextOpt = NtLdrGetNextOption(&NextOptions, &NextOptLength)))
222 {
223 /* Scan the load options */
224 Options = LoadOptions;
225 while ((Option = (PSTR)NtLdrGetNextOption((PCSTR*)&Options, &OptionLength)))
226 {
227 /*
228 * Check whether the option to find exactly matches the current
229 * load option, or is a prefix thereof if this is an option with
230 * appended data.
231 */
232 if ((OptionLength >= NextOptLength) &&
233 (_strnicmp(Option, NextOpt, NextOptLength) == 0))
234 {
235 if ((OptionLength == NextOptLength) ||
236 (NextOpt[NextOptLength-1] == '=') ||
237 (NextOpt[NextOptLength-1] == ':'))
238 {
239 /* Eat any skipped option or whitespace separators */
240 while ((Option > LoadOptions) &&
241 (Option[-1] == '/' ||
242 Option[-1] == ' ' ||
243 Option[-1] == '\t'))
244 {
245 --Option;
246 }
247
248 /* If the option was not preceded by a whitespace
249 * separator, insert one and advance the pointer. */
250 if ((Option > LoadOptions) &&
251 (Option[-1] != ' ') &&
252 (Option[-1] != '\t') &&
253 (*Options != '\0') /* &&
254 ** Not necessary since NtLdrGetNextOption() **
255 ** stripped any leading separators. **
256 (*Options != ' ') &&
257 (*Options != '\t') */)
258 {
259 *Option++ = ' ';
260 }
261
262 /* Move the remaining options back, erasing the current one */
263 ASSERT(Option <= Options);
264 RtlMoveMemory(Option,
265 Options,
266 (strlen(Options) + 1) * sizeof(CHAR));
267
268 /* Reset the iterator */
269 Options = Option;
270 }
271 }
272 }
273 }
274 }
275
276 /* Now loop over the options to add */
277 for (; OptionsToAdd && *OptionsToAdd; ++OptionsToAdd)
278 {
279 NtLdrAddOptions(LoadOptions,
280 BufferSize,
281 Append,
282 *OptionsToAdd);
283 }
284 }
285
286
287 /*
288 * List of options and their corresponding higher priority ones,
289 * that are either checked before any other ones, or whose name
290 * includes another option name as a subset (e.g. NODEBUG vs. DEBUG).
291 * See also https://geoffchappell.com/notes/windows/boot/editoptions.htm
292 */
293 static const struct
294 {
295 PCSTR Options;
296 PCSTR ExtraOptions;
297 PCSTR HigherPriorOptions;
298 } HighPriorOptionsMap[] =
299 {
300 /* NODEBUG has a higher precedence than DEBUG */
301 {"/DEBUG/DEBUG=", NULL, "/NODEBUG"},
302
303 /* When using SCREEN debug port, we need boot video */
304 {"/DEBUGPORT=SCREEN", NULL, "/NOGUIBOOT"},
305
306 /* DETECTHAL has a higher precedence than HAL= or KERNEL= */
307 {"/HAL=/KERNEL=", NULL, "/DETECTHAL"},
308
309 /* NOPAE has a higher precedence than PAE */
310 {"/PAE", NULL, "/NOPAE"},
311
312 /* NOEXECUTE(=) has a higher precedence than EXECUTE */
313 {"/EXECUTE", "/NOEXECUTE=ALWAYSOFF", "/NOEXECUTE/NOEXECUTE="},
314 /* NOEXECUTE(=) options are self-excluding and
315 * some have higher precedence than others. */
316 {"/NOEXECUTE/NOEXECUTE=", NULL, "/NOEXECUTE/NOEXECUTE="},
317
318 /* SAFEBOOT(:) options are self-excluding */
319 {"/SAFEBOOT/SAFEBOOT:", NULL, "/SAFEBOOT/SAFEBOOT:"},
320 };
321
322 #define TAG_BOOT_OPTIONS 'pOtB'
323
324 VOID
325 NtLdrGetHigherPriorityOptions(
326 IN PCSTR BootOptions,
327 OUT PSTR* ExtraOptions,
328 OUT PSTR* HigherPriorityOptions)
329 {
330 ULONG i;
331 PCSTR NextOptions, NextOpt;
332 ULONG NextOptLength;
333 SIZE_T ExtraOptsSize = 0;
334 SIZE_T HighPriorOptsSize = 0;
335
336 /* Masks specifying the presence (TRUE) or absence (FALSE) of the options */
337 BOOLEAN Masks[RTL_NUMBER_OF(HighPriorOptionsMap)];
338
339 /* Just return if we cannot return anything */
340 if (!ExtraOptions && !HigherPriorityOptions)
341 return;
342
343 if (ExtraOptions)
344 *ExtraOptions = NULL;
345 if (HigherPriorityOptions)
346 *HigherPriorityOptions = NULL;
347
348 /* Just return if no initial options were given */
349 if (!BootOptions || !*BootOptions)
350 return;
351
352 /* Determine the presence of the colliding options, and the
353 * maximum necessary sizes for the pointers to be allocated. */
354 RtlZeroMemory(Masks, sizeof(Masks));
355 for (i = 0; i < RTL_NUMBER_OF(HighPriorOptionsMap); ++i)
356 {
357 /* Loop over the given options to search for */
358 NextOptions = HighPriorOptionsMap[i].Options;
359 while ((NextOpt = NtLdrGetNextOption(&NextOptions, &NextOptLength)))
360 {
361 /* If any of these options are present... */
362 if (NtLdrGetOptionExN(BootOptions, NextOpt, NextOptLength, NULL))
363 {
364 /* ... set the mask, retrieve the sizes and stop looking for these options */
365 Masks[i] = TRUE;
366 if (ExtraOptions && HighPriorOptionsMap[i].ExtraOptions)
367 {
368 ExtraOptsSize += strlen(HighPriorOptionsMap[i].ExtraOptions) * sizeof(CHAR);
369 }
370 if (HigherPriorityOptions && HighPriorOptionsMap[i].HigherPriorOptions)
371 {
372 HighPriorOptsSize += strlen(HighPriorOptionsMap[i].HigherPriorOptions) * sizeof(CHAR);
373 }
374 break;
375 }
376 }
377 }
378 /* Count the NULL-terminator */
379 if (ExtraOptions)
380 ExtraOptsSize += sizeof(ANSI_NULL);
381 if (HigherPriorityOptions)
382 HighPriorOptsSize += sizeof(ANSI_NULL);
383
384 /* Allocate the string pointers */
385 if (ExtraOptions)
386 {
387 *ExtraOptions = FrLdrHeapAlloc(ExtraOptsSize, TAG_BOOT_OPTIONS);
388 if (!*ExtraOptions)
389 return;
390 }
391 if (HigherPriorityOptions)
392 {
393 *HigherPriorityOptions = FrLdrHeapAlloc(HighPriorOptsSize, TAG_BOOT_OPTIONS);
394 if (!*HigherPriorityOptions)
395 {
396 if (ExtraOptions)
397 {
398 FrLdrHeapFree(*ExtraOptions, TAG_BOOT_OPTIONS);
399 *ExtraOptions = NULL;
400 }
401 return;
402 }
403 }
404
405 /* Initialize the strings */
406 if (ExtraOptions)
407 *(*ExtraOptions) = '\0';
408 if (HigherPriorityOptions)
409 *(*HigherPriorityOptions) = '\0';
410
411 /* Go through the masks that determine the options to check */
412 for (i = 0; i < RTL_NUMBER_OF(HighPriorOptionsMap); ++i)
413 {
414 if (Masks[i])
415 {
416 /* Retrieve the strings */
417 if (ExtraOptions && HighPriorOptionsMap[i].ExtraOptions)
418 {
419 RtlStringCbCatA(*ExtraOptions,
420 ExtraOptsSize,
421 HighPriorOptionsMap[i].ExtraOptions);
422 }
423 if (HigherPriorityOptions && HighPriorOptionsMap[i].HigherPriorOptions)
424 {
425 RtlStringCbCatA(*HigherPriorityOptions,
426 HighPriorOptsSize,
427 HighPriorOptionsMap[i].HigherPriorOptions);
428 }
429 }
430 }
431 }
432
433
434 ARC_STATUS
435 LoadReactOSSetup(
436 IN ULONG Argc,
437 IN PCHAR Argv[],
438 IN PCHAR Envp[])
439 {
440 ARC_STATUS Status;
441 PCSTR ArgValue;
442 PCSTR SystemPartition;
443 PCSTR SystemPath;
444 PSTR FileName;
445 ULONG FileNameLength;
446 BOOLEAN BootFromFloppy;
447 BOOLEAN Success;
448 HINF InfHandle;
449 INFCONTEXT InfContext;
450 ULONG i, ErrorLine;
451 PLOADER_PARAMETER_BLOCK LoaderBlock;
452 PSETUP_LOADER_BLOCK SetupBlock;
453 CHAR BootPath[MAX_PATH];
454 CHAR FilePath[MAX_PATH];
455 CHAR UserBootOptions[256];
456 PCSTR BootOptions;
457
458 static PCSTR SourcePaths[] =
459 {
460 "", /* Only for floppy boot */
461 #if defined(_M_IX86)
462 "I386\\",
463 #elif defined(_M_MPPC)
464 "PPC\\",
465 #elif defined(_M_MRX000)
466 "MIPS\\",
467 #endif
468 "reactos\\",
469 NULL
470 };
471
472 /* Retrieve the (mandatory) boot type */
473 ArgValue = GetArgumentValue(Argc, Argv, "BootType");
474 if (!ArgValue || !*ArgValue)
475 {
476 ERR("No 'BootType' value, aborting!\n");
477 return EINVAL;
478 }
479 if (_stricmp(ArgValue, "ReactOSSetup") != 0)
480 {
481 ERR("Unknown 'BootType' value '%s', aborting!\n", ArgValue);
482 return EINVAL;
483 }
484
485 /* Retrieve the (mandatory) system partition */
486 SystemPartition = GetArgumentValue(Argc, Argv, "SystemPartition");
487 if (!SystemPartition || !*SystemPartition)
488 {
489 ERR("No 'SystemPartition' specified, aborting!\n");
490 return EINVAL;
491 }
492
493 UiDrawStatusText("Setup is loading...");
494
495 UiDrawBackdrop();
496 UiDrawProgressBarCenter(1, 100, "Loading ReactOS Setup...");
497
498 /* Retrieve the system path */
499 *BootPath = ANSI_NULL;
500 ArgValue = GetArgumentValue(Argc, Argv, "SystemPath");
501 if (ArgValue)
502 {
503 RtlStringCbCopyA(BootPath, sizeof(BootPath), ArgValue);
504 }
505 else
506 {
507 /*
508 * IMPROVE: I don't want to use the SystemPartition here as a
509 * default choice because I can do it after (see few lines below).
510 * Instead I reset BootPath here so that we can build the full path
511 * using the general code from below.
512 */
513 // RtlStringCbCopyA(BootPath, sizeof(BootPath), SystemPartition);
514 *BootPath = ANSI_NULL;
515 }
516
517 /*
518 * Check whether BootPath is a full path
519 * and if not, create a full boot path.
520 *
521 * See FsOpenFile for the technique used.
522 */
523 if (strrchr(BootPath, ')') == NULL)
524 {
525 /* Temporarily save the boot path */
526 RtlStringCbCopyA(FilePath, sizeof(FilePath), BootPath);
527
528 /* This is not a full path: prepend the SystemPartition */
529 RtlStringCbCopyA(BootPath, sizeof(BootPath), SystemPartition);
530
531 /* Append a path separator if needed */
532 if (*FilePath != '\\' && *FilePath != '/')
533 RtlStringCbCatA(BootPath, sizeof(BootPath), "\\");
534
535 /* Append the remaining path */
536 RtlStringCbCatA(BootPath, sizeof(BootPath), FilePath);
537 }
538
539 /* Append a path separator if needed */
540 if (!*BootPath || BootPath[strlen(BootPath) - 1] != '\\')
541 RtlStringCbCatA(BootPath, sizeof(BootPath), "\\");
542
543 TRACE("BootPath: '%s'\n", BootPath);
544
545 /*
546 * Retrieve the boot options. Any options present here will supplement or
547 * override those that will be specified in TXTSETUP.SIF's OsLoadOptions.
548 */
549 BootOptions = GetArgumentValue(Argc, Argv, "Options");
550 if (!BootOptions)
551 BootOptions = "";
552
553 TRACE("BootOptions: '%s'\n", BootOptions);
554
555 /* Check if a RAM disk file was given */
556 FileName = (PSTR)NtLdrGetOptionEx(BootOptions, "RDPATH=", &FileNameLength);
557 if (FileName && (FileNameLength > 7))
558 {
559 /* Load the RAM disk */
560 Status = RamDiskInitialize(FALSE, BootOptions, SystemPartition);
561 if (Status != ESUCCESS)
562 {
563 FileName += 7; FileNameLength -= 7;
564 UiMessageBox("Failed to load RAM disk file '%.*s'",
565 FileNameLength, FileName);
566 return Status;
567 }
568 }
569
570 /* Check if we booted from floppy */
571 BootFromFloppy = strstr(BootPath, "fdisk") != NULL;
572
573 /* Open 'txtsetup.sif' from any of the source paths */
574 FileName = BootPath + strlen(BootPath);
575 for (i = BootFromFloppy ? 0 : 1; ; i++)
576 {
577 SystemPath = SourcePaths[i];
578 if (!SystemPath)
579 {
580 UiMessageBox("Failed to open txtsetup.sif");
581 return ENOENT;
582 }
583 FileNameLength = (ULONG)(sizeof(BootPath) - (FileName - BootPath)*sizeof(CHAR));
584 RtlStringCbCopyA(FileName, FileNameLength, SystemPath);
585 RtlStringCbCopyA(FilePath, sizeof(FilePath), BootPath);
586 RtlStringCbCatA(FilePath, sizeof(FilePath), "txtsetup.sif");
587 if (InfOpenFile(&InfHandle, FilePath, &ErrorLine))
588 {
589 break;
590 }
591 }
592
593 TRACE("BootPath: '%s', SystemPath: '%s'\n", BootPath, SystemPath);
594
595 // UseLocalSif = NtLdrGetOption(BootOptions, "USELOCALSIF");
596
597 if (NtLdrGetOption(BootOptions, "SIFOPTIONSOVERRIDE"))
598 {
599 PCSTR OptionsToRemove[2] = {"SIFOPTIONSOVERRIDE", NULL};
600
601 /* Do not use any load options from TXTSETUP.SIF, but
602 * use instead those passed from the command line. */
603 RtlStringCbCopyA(UserBootOptions, sizeof(UserBootOptions), BootOptions);
604
605 /* Remove the private switch from the options */
606 NtLdrUpdateLoadOptions(UserBootOptions,
607 sizeof(UserBootOptions),
608 FALSE,
609 NULL,
610 OptionsToRemove);
611
612 BootOptions = UserBootOptions;
613 }
614 else // if (!*BootOptions || NtLdrGetOption(BootOptions, "SIFOPTIONSADD"))
615 {
616 PCSTR LoadOptions = NULL;
617 PCSTR DbgLoadOptions = NULL;
618 PSTR ExtraOptions, HigherPriorityOptions;
619 PSTR OptionsToAdd[3];
620 PSTR OptionsToRemove[4];
621
622 /* Load the options from TXTSETUP.SIF */
623 if (InfFindFirstLine(InfHandle, "SetupData", "OsLoadOptions", &InfContext))
624 {
625 if (!InfGetDataField(&InfContext, 1, &LoadOptions))
626 WARN("Failed to get load options\n");
627 }
628
629 #if !DBG
630 /* Non-debug mode: get the debug load options only if /DEBUG was specified
631 * in the Argv command-line options (was e.g. added to the options when
632 * the user selected "Debugging Mode" in the advanced boot menu). */
633 if (NtLdrGetOption(BootOptions, "DEBUG") ||
634 NtLdrGetOption(BootOptions, "DEBUG="))
635 {
636 #else
637 /* Debug mode: always get the debug load options */
638 #endif
639 if (InfFindFirstLine(InfHandle, "SetupData", "SetupDebugOptions", &InfContext))
640 {
641 if (!InfGetDataField(&InfContext, 1, &DbgLoadOptions))
642 WARN("Failed to get debug load options\n");
643 }
644 /* If none was found, default to enabling debugging */
645 if (!DbgLoadOptions)
646 DbgLoadOptions = "/DEBUG";
647 #if !DBG
648 }
649 #endif
650
651 /* Initialize the load options with those from TXTSETUP.SIF */
652 *UserBootOptions = ANSI_NULL;
653 if (LoadOptions && *LoadOptions)
654 RtlStringCbCopyA(UserBootOptions, sizeof(UserBootOptions), LoadOptions);
655
656 /* Merge the debug load options if any */
657 if (DbgLoadOptions)
658 {
659 RtlZeroMemory(OptionsToAdd, sizeof(OptionsToAdd));
660 RtlZeroMemory(OptionsToRemove, sizeof(OptionsToRemove));
661
662 /*
663 * Retrieve any option patterns that we should remove from the
664 * SIF load options because they are of higher precedence than
665 * those specified in the debug load options to be added.
666 * Also always remove NODEBUG (even if the debug load options
667 * do not contain explicitly the DEBUG option), since we want
668 * to have debugging enabled if possible.
669 */
670 OptionsToRemove[0] = "/NODEBUG";
671 NtLdrGetHigherPriorityOptions(DbgLoadOptions,
672 &ExtraOptions,
673 &HigherPriorityOptions);
674 OptionsToAdd[1] = (ExtraOptions ? ExtraOptions : "");
675 OptionsToRemove[1] = (HigherPriorityOptions ? HigherPriorityOptions : "");
676
677 /*
678 * Prepend the debug load options, so that in case it contains
679 * redundant options with respect to the SIF load options, the
680 * former can take precedence over the latter.
681 */
682 OptionsToAdd[0] = (PSTR)DbgLoadOptions;
683 OptionsToRemove[2] = (PSTR)DbgLoadOptions;
684 NtLdrUpdateLoadOptions(UserBootOptions,
685 sizeof(UserBootOptions),
686 FALSE,
687 (PCSTR*)OptionsToAdd,
688 (PCSTR*)OptionsToRemove);
689
690 if (ExtraOptions)
691 FrLdrHeapFree(ExtraOptions, TAG_BOOT_OPTIONS);
692 if (HigherPriorityOptions)
693 FrLdrHeapFree(HigherPriorityOptions, TAG_BOOT_OPTIONS);
694 }
695
696 RtlZeroMemory(OptionsToAdd, sizeof(OptionsToAdd));
697 RtlZeroMemory(OptionsToRemove, sizeof(OptionsToRemove));
698
699 /*
700 * Retrieve any option patterns that we should remove from the
701 * SIF load options because they are of higher precedence than
702 * those specified in the options to be added.
703 */
704 NtLdrGetHigherPriorityOptions(BootOptions,
705 &ExtraOptions,
706 &HigherPriorityOptions);
707 OptionsToAdd[1] = (ExtraOptions ? ExtraOptions : "");
708 OptionsToRemove[0] = (HigherPriorityOptions ? HigherPriorityOptions : "");
709
710 /* Finally, prepend the user-specified options that
711 * take precedence over those from TXTSETUP.SIF. */
712 OptionsToAdd[0] = (PSTR)BootOptions;
713 OptionsToRemove[1] = (PSTR)BootOptions;
714 NtLdrUpdateLoadOptions(UserBootOptions,
715 sizeof(UserBootOptions),
716 FALSE,
717 (PCSTR*)OptionsToAdd,
718 (PCSTR*)OptionsToRemove);
719
720 if (ExtraOptions)
721 FrLdrHeapFree(ExtraOptions, TAG_BOOT_OPTIONS);
722 if (HigherPriorityOptions)
723 FrLdrHeapFree(HigherPriorityOptions, TAG_BOOT_OPTIONS);
724
725 BootOptions = UserBootOptions;
726 }
727
728 TRACE("BootOptions: '%s'\n", BootOptions);
729
730 /* Allocate and minimally-initialize the Loader Parameter Block */
731 AllocateAndInitLPB(_WIN32_WINNT_WS03, &LoaderBlock);
732
733 /* Allocate and initialize the setup loader block */
734 SetupBlock = &WinLdrSystemBlock->SetupBlock;
735 LoaderBlock->SetupLdrBlock = SetupBlock;
736
737 /* Set textmode setup flag */
738 SetupBlock->Flags = SETUPLDR_TEXT_MODE;
739
740 /* Load the "setupreg.hiv" setup system hive */
741 UiDrawBackdrop();
742 UiDrawProgressBarCenter(15, 100, "Loading setup system hive...");
743 Success = WinLdrInitSystemHive(LoaderBlock, BootPath, TRUE);
744 TRACE("Setup SYSTEM hive %s\n", (Success ? "loaded" : "not loaded"));
745 /* Bail out if failure */
746 if (!Success)
747 return ENOEXEC;
748
749 /* Load NLS data, they are in the System32 directory of the installation medium */
750 RtlStringCbCopyA(FilePath, sizeof(FilePath), BootPath);
751 RtlStringCbCatA(FilePath, sizeof(FilePath), "system32\\");
752 SetupLdrLoadNlsData(LoaderBlock, InfHandle, FilePath);
753
754 /* Load the Firmware Errata file from the installation medium */
755 Success = SetupLdrInitErrataInf(LoaderBlock, InfHandle, BootPath);
756 TRACE("Firmware Errata file %s\n", (Success ? "loaded" : "not loaded"));
757 /* Not necessarily fatal if not found - carry on going */
758
759 // UiDrawStatusText("Press F6 if you need to install a 3rd-party SCSI or RAID driver...");
760
761 /* Get a list of boot drivers */
762 SetupLdrScanBootDrivers(&LoaderBlock->BootDriverListHead, InfHandle, BootPath);
763
764 /* Close the inf file */
765 InfCloseFile(InfHandle);
766
767 UiDrawStatusText("The Setup program is starting...");
768
769 /* Finish loading */
770 return LoadAndBootWindowsCommon(_WIN32_WINNT_WS03,
771 LoaderBlock,
772 BootOptions,
773 BootPath);
774 }