Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

7183 lines
218 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. setup.c
  5. Abstract:
  6. This module contains the code that implements the NT setup loader
  7. Author:
  8. John Vert (jvert) 6-Oct-1993
  9. Environment:
  10. ARC Environment
  11. Revision History:
  12. --*/
  13. #include <setupbat.h>
  14. #include "setupldr.h"
  15. #include "stdio.h"
  16. #include "string.h"
  17. #include "stdlib.h"
  18. #include <dockinfo.h>
  19. #include <netboot.h>
  20. #include <ramdisk.h>
  21. #include "acpitabl.h"
  22. #ifdef i386
  23. #include <bldrx86.h>
  24. #endif
  25. #if defined(_IA64_)
  26. #include "bldria64.h"
  27. #endif
  28. #if defined(EFI)
  29. #include "bootefi.h"
  30. #endif
  31. #if defined(_IA64_)
  32. UCHAR OsLoaderName[] = "setupldr.efi";
  33. #else
  34. UCHAR OsLoaderName[] = "setupldr.exe";
  35. #endif
  36. #if defined(_WIN64) && defined(_M_IA64)
  37. #pragma section(".base", long, read, write)
  38. __declspec(allocate(".base"))
  39. extern
  40. PVOID __ImageBase;
  41. #else
  42. extern
  43. PVOID __ImageBase;
  44. #endif
  45. #define BlDiagLoadMessage(x,y,z)
  46. #define DRIVER_DATABASE_FILENAME L"drvmain.sdb"
  47. #define KERNEL_UP_IMAGE_FILENAME LEGACY_KERNEL_NAME
  48. #define KERNEL_MP_IMAGE_FILENAME MP_KERNEL_NAME
  49. CHAR KernelImage[13];
  50. BOOLEAN UseCommandConsole = FALSE;
  51. BOOLEAN g_RollbackEnabled = FALSE;
  52. BOOLEAN TryASRViaNetwork = FALSE;
  53. CHAR KdFileName[8+1+3+1]="KDCOM.DLL";
  54. BOOLEAN UseAlternateKdDll = FALSE;
  55. #define KD_ALT_DLL_PREFIX_CHARS 2
  56. #define KD_ALT_DLL_REPLACE_CHARS 6
  57. #if defined(_X86_) && !defined(ALLOW_386)
  58. //
  59. // Disallow installation on a 386 or any processor which
  60. // does not support CPUID and CMPXCHG8B instructions.
  61. //
  62. extern BOOLEAN BlIs386(VOID);
  63. extern ULONG BlGetFeatureBits(VOID);
  64. #endif
  65. #define DBG_OUT(x)
  66. /*
  67. //
  68. // For debugging purposes
  69. // Example:
  70. //
  71. // DBG_OUT("Testing")
  72. //
  73. #define DBG_OUT(x) { \
  74. if (x) { \
  75. BlPositionCursor(5, 10); \
  76. BlPrint(" "); \
  77. BlPositionCursor(5, 10); \
  78. BlPrint(x); \
  79. while (!SlGetChar()); \
  80. } \
  81. }
  82. //
  83. // For debugging purposes
  84. // Example:
  85. //
  86. // DebugOutput("Calling SlDetectScsi(). Line = %d. %s\n",__LINE__,"")
  87. //
  88. //
  89. #define DebugOutput(X,Y,Z) { \
  90. if (ARC_CONSOLE_OUTPUT) { \
  91. CHAR _b[128]; \
  92. ULONG _c; \
  93. sprintf(&_b[0], X, Y, Z); \
  94. ArcWrite(ARC_CONSOLE_OUTPUT, &_b[0], strlen(&_b[0]), &_c); \
  95. SlGetChar(); \
  96. } \
  97. }
  98. */
  99. //
  100. // Define external static data.
  101. //
  102. ULONG BlConsoleOutDeviceId = ARC_CONSOLE_OUTPUT;
  103. ULONG BlConsoleInDeviceId = ARC_CONSOLE_INPUT;
  104. //
  105. // Global string constants.
  106. //
  107. PCHAR FilesSectionName = "SourceDisksFiles";
  108. PCHAR MediaSectionName = "SourceDisksNames";
  109. #if defined(_AXP64_)
  110. PCHAR PlatformExtension = ".axp64";
  111. #elif defined(_ALPHA_)
  112. PCHAR PlatformExtension = ".alpha";
  113. #elif defined(_IA64_)
  114. PCHAR PlatformExtension = ".ia64";
  115. #elif defined(_X86_)
  116. #define PlatformExtension (BlAmd64Setup(NULL) ? ".amd64" : ".x86")
  117. #endif
  118. //
  119. // Global data
  120. //
  121. ULONG BlDcacheFillSize = 32;
  122. ULONG BlVirtualBias = 0;
  123. //
  124. // Global setupldr control values
  125. //
  126. MEDIA_TYPE BootMedia;
  127. MEDIA_TYPE InstallMedia;
  128. PCHAR BootDevice;
  129. ULONG BootDeviceId;
  130. BOOLEAN BootDeviceIdValid = FALSE;
  131. PCHAR BootPath;
  132. ULONG BootDriveNumber;
  133. ULONG InstallDriveNumber;
  134. PCHAR HalName;
  135. PCHAR HalDescription;
  136. PCHAR AnsiCpName;
  137. PCHAR OemHalFontName;
  138. UNICODE_STRING AnsiCodepage;
  139. UNICODE_STRING OemCodepage;
  140. UNICODE_STRING UnicodeCaseTable;
  141. UNICODE_STRING OemHalFont;
  142. #ifdef _WANT_MACHINE_IDENTIFICATION
  143. UNICODE_STRING BiosInfo;
  144. #endif
  145. BOOLEAN LoadScsiMiniports;
  146. BOOLEAN LoadDiskClass;
  147. BOOLEAN LoadCdfs;
  148. BOOLEAN FixedBootMedia = FALSE;
  149. BOOLEAN FloppyBoot = FALSE;
  150. PVOID InfFile;
  151. PVOID WinntSifHandle;
  152. PVOID MigrateInfHandle;
  153. ULONG BootFontImageLength = 0;
  154. PVOID UnsupDriversInfHandle;
  155. BOOLEAN IgnoreMissingFiles;
  156. BOOLEAN BlUsePae;
  157. BOOLEAN UseRegularBackground = TRUE;
  158. BOOLEAN IsUpgrade = FALSE;
  159. //
  160. // OEM related variables
  161. //
  162. POEM_SOURCE_DEVICE OemSourceDevices = NULL;
  163. POEM_SOURCE_DEVICE DefaultOemSourceDevice = NULL;
  164. POEM_SOURCE_DEVICE AutoLoadOemHalDevice = NULL;
  165. BOOLEAN AutoLoadOemScsi = FALSE;
  166. //
  167. // Pre-install stuff
  168. //
  169. PCHAR OemTag = "OEM";
  170. PTCHAR _TOemTag = TEXT("OEM");
  171. BOOLEAN PreInstall = FALSE;
  172. PTCHAR ComputerType = NULL;
  173. BOOLEAN OemHal = FALSE;
  174. PPREINSTALL_DRIVER_INFO PreinstallDriverList = NULL;
  175. POEM_SOURCE_DEVICE PreInstallOemSourceDevice = NULL;
  176. PCHAR PreInstallSourcePath = NULL;
  177. //
  178. // Dynamic update variables
  179. //
  180. static BOOLEAN DynamicUpdate = FALSE;
  181. static PCSTR DynamicUpdateRootDir = NULL;
  182. static POEM_SOURCE_DEVICE DynamicUpdateSourceDevice = NULL;
  183. //
  184. // WinPE (aka MiniNT) global variables
  185. //
  186. BOOLEAN WinPEBoot = FALSE;
  187. BOOLEAN WinPEAutoBoot = FALSE;
  188. PCTSTR StartupMsg = NULL;
  189. //
  190. // Is used by HALACPI.DLL
  191. //
  192. BOOLEAN DisableACPI = FALSE;
  193. BOOLEAN isOSCHOICE = FALSE;
  194. //
  195. // Primarily used by floppy boot support to key track
  196. // of the last disk read
  197. //
  198. PCHAR LastDiskTag = NULL;
  199. //
  200. // TRUE if user pressed F8
  201. //
  202. BOOLEAN EnableDebugger = FALSE;
  203. //
  204. // TRUE if user presses F4.
  205. //
  206. BOOLEAN DisableVirtualOemDevices = FALSE;
  207. #if defined(ELTORITO)
  208. extern BOOLEAN ElToritoCDBoot;
  209. #endif
  210. //
  211. // Define transfer entry of loaded image.
  212. //
  213. typedef
  214. VOID
  215. (*PTRANSFER_ROUTINE) (
  216. PLOADER_PARAMETER_BLOCK LoaderBlock
  217. );
  218. #if defined(_IA64_)
  219. VOID
  220. BuildArcTree();
  221. #endif
  222. //
  223. // Local function prototypes
  224. //
  225. VOID
  226. SlGetSetupValuesBeforePrompt(
  227. IN PSETUP_LOADER_BLOCK SetupBlock
  228. );
  229. VOID
  230. SlGetSetupValuesAfterPrompt(
  231. IN PSETUP_LOADER_BLOCK SetupBlock
  232. );
  233. ARC_STATUS
  234. SlLoadDriver(
  235. IN PTCHAR DriverDescription,
  236. IN PCHAR DriverName,
  237. IN ULONG DriverFlags,
  238. IN BOOLEAN InsertIntoDriverList,
  239. IN BOOLEAN MigratedDriver,
  240. IN PCHAR ServiceName OPTIONAL
  241. );
  242. ARC_STATUS
  243. SlLoadOemDriver(
  244. IN PCHAR ExportDriver OPTIONAL,
  245. IN PCHAR DriverName,
  246. IN PVOID BaseAddress,
  247. IN PTCHAR LoadMessage
  248. );
  249. PBOOT_DRIVER_LIST_ENTRY
  250. SlpCreateDriverEntry(
  251. IN PCHAR DriverName,
  252. IN PCHAR ServiceName OPTIONAL
  253. );
  254. ARC_STATUS
  255. SlDetectMigratedScsiDrivers(
  256. IN PVOID Inf
  257. );
  258. ARC_STATUS
  259. SlGetMigratedHardwareIds(
  260. IN PSETUP_LOADER_BLOCK SetupBlock,
  261. IN PVOID Inf
  262. );
  263. BOOLEAN
  264. SlpIsDiskVacant(
  265. IN PARC_DISK_SIGNATURE DiskSignature
  266. );
  267. ARC_STATUS
  268. SlpStampFTSignature(
  269. IN PARC_DISK_SIGNATURE DiskSignature,
  270. IN BOOLEAN GenerateNewSignature
  271. );
  272. VOID
  273. SlpMarkDisks(
  274. IN BOOLEAN Reboot
  275. );
  276. VOID
  277. SlCheckOemKeypress(
  278. IN ULONG WaitTime
  279. );
  280. VOID
  281. SlCheckASRKeypress(
  282. VOID
  283. );
  284. ARC_STATUS
  285. SlLoadPnpDriversSection(
  286. IN PVOID Inf,
  287. IN PCHAR SectionName,
  288. IN OUT PDETECTED_DEVICE* DetectedDeviceList OPTIONAL
  289. );
  290. BOOLEAN
  291. SlIsUpgrade(
  292. IN PVOID SifHandle
  293. );
  294. BOOLEAN
  295. SlIsCdBootUpgrade(
  296. IN PCHAR InstallDirectory,
  297. IN PCHAR SetupFileName,
  298. IN ULONG MaxDisksToScan,
  299. IN ULONG MaxPartitionsPerDisk,
  300. OUT PCHAR SetupDevice
  301. );
  302. ARC_STATUS
  303. SlLoadBootFontFile(
  304. IN PSETUP_LOADER_BLOCK SetupLoaderBlock,
  305. IN ULONG DiskId,
  306. IN ULONG BootFontImageLength
  307. );
  308. //
  309. // Dynamic update function prototypes
  310. //
  311. BOOLEAN
  312. SlpIsDynamicUpdate(
  313. IN PVOID InfHandle,
  314. OUT PCSTR *DynamicUpdateRootDir
  315. );
  316. BOOLEAN
  317. SlModifyOsLoadOptions(
  318. IN OUT PSTR* LoadOptions,
  319. IN PCSTR OptionsToAdd OPTIONAL,
  320. IN PCSTR OptionsToRemove OPTIONAL
  321. );
  322. BOOLEAN
  323. SlIsVirtualOemDeviceDisabled(
  324. IN PVOID SifHandle,
  325. IN PPREINSTALL_DRIVER_INFO PreinstallDriverList
  326. );
  327. VOID
  328. SlDisableVirtualOemDevices(
  329. IN POEM_SOURCE_DEVICE OemDeviceList
  330. );
  331. ARC_STATUS
  332. SlInit(
  333. IN ULONG Argc,
  334. IN CHAR * FIRMWARE_PTR * FIRMWARE_PTR Argv,
  335. IN CHAR * FIRMWARE_PTR * FIRMWARE_PTR Envp
  336. )
  337. /*++
  338. Routine Description:
  339. The main startup routine for the NT Setup Loader. This is the entrypoint
  340. called by the ARC firmware.
  341. If successful, this routine will never return, it will start NT directly.
  342. Arguments:
  343. Argc - Supplies the number of arguments that were provided on the
  344. command that invoked this program.
  345. Argv - Supplies a pointer to a vector of pointers to null terminated
  346. argument strings.
  347. Envp - Supplies a pointer to a vector of pointers to null terminated
  348. environment variables.
  349. Return Value:
  350. ARC_STATUS if unsuccessful.
  351. --*/
  352. {
  353. //
  354. // if we use too much stack space the heap and stack can overlap and we can run into corruption problems
  355. // without any "stack overflow" exceptions; making large strings static helps prevent this
  356. //
  357. PCONFIGURATION_COMPONENT_DATA DataCache;
  358. ARC_STATUS Status;
  359. ULONG LinesPerBlock;
  360. ULONG CacheLineSize;
  361. static CHAR SetupDevice[128];
  362. static CHAR SetupDirectory[128];
  363. static CHAR BadFileName[128];
  364. static CHAR CanonicalName[128];
  365. static CHAR HalDirectoryPath[256];
  366. static CHAR KernelDirectoryPath[256];
  367. PCHAR NetSetupServerShare = NULL;
  368. PCHAR NetSetupPath = NULL;
  369. PCHAR p;
  370. ULONG ErrorLine=0;
  371. ULONG DontCare;
  372. PVOID SystemBase;
  373. PVOID HalBase;
  374. PVOID VideoBase;
  375. PCHAR FileName;
  376. PVOID KdDllBase;
  377. static CHAR KdDllName[256];
  378. ULONG i;
  379. PKLDR_DATA_TABLE_ENTRY SystemDataTableEntry;
  380. PKLDR_DATA_TABLE_ENTRY HalDataTableEntry;
  381. PKLDR_DATA_TABLE_ENTRY KdDataTableEntry;
  382. PTRANSFER_ROUTINE SystemEntry;
  383. PIMAGE_NT_HEADERS NtHeaders;
  384. PBOOT_DRIVER_LIST_ENTRY DriverEntry;
  385. PSETUP_LOADER_BLOCK SetupBlock;
  386. PDETECTED_DEVICE ScsiDevice;
  387. PCHAR VideoFileName;
  388. PTCHAR VideoDescription;
  389. POEMSCSIINFO OemScsiInfo = NULL;
  390. PCHAR OemVideoName;
  391. PVOID OemInfHandle = NULL;
  392. BOOLEAN LoadedAVideoDriver = FALSE;
  393. static CHAR NetbootCardDriverName[24];
  394. static CHAR NetbootUser[64];
  395. static CHAR NetbootDomain[64];
  396. static CHAR NetbootPassword[64];
  397. static CHAR NetbootAdministratorPassword[OSC_ADMIN_PASSWORD_LEN];
  398. static CHAR NetbootSifFile[128];
  399. DOCKING_STATION_INFO dockInfo = { 0, 0, 0, FW_DOCKINFO_DOCK_STATE_UNKNOWN };
  400. PCONFIGURATION_COMPONENT_DATA dockInfoData;
  401. extern ULONG BlProgressBarShowTimeOut;
  402. extern ULONG BlDisableProgressBar;
  403. #if defined (_X86_)
  404. extern BOOLEAN AllowGraphicsReset;
  405. #endif
  406. ULONG OemKeypressTimeout = 5; //secs
  407. #if defined(REMOTE_BOOT)
  408. BOOLEAN RemoteBootEnableIpsec = FALSE;
  409. #endif // defined(REMOTE_BOOT)
  410. #if defined(_X86_) || defined(_IA64_)
  411. BOOLEAN Win9xUnsupHdc = FALSE;
  412. #endif
  413. static FULL_PATH_SET PathSet;
  414. UNICODE_STRING DrvMainSdb;
  415. #if DBG
  416. ULONG StartTime = 0;
  417. #endif
  418. #if defined(_ALPHA_) || defined(ARCI386) || defined(_IA64_)
  419. PVOID LoaderBase;
  420. #endif
  421. UNREFERENCED_PARAMETER( Envp );
  422. //
  423. // Disable progress bar, by default.
  424. //
  425. BlDisableProgressBar = TRUE;
  426. #ifdef EFI
  427. //
  428. // set the efi watchdog timer to 20 minutes. the boot manager sets it to 5, but
  429. // setupldr could take longer than this, especially if installing over the
  430. // network
  431. //
  432. SetEFIWatchDog(EFI_WATCHDOG_TIMEOUT);
  433. #endif
  434. #if defined (_X86_)
  435. //
  436. // Do not allow display to be reset at the end of setupldr.
  437. // this would leave the screen blank for ~30 seconds, until
  438. // textmode setup reinitializes the display
  439. //
  440. AllowGraphicsReset = FALSE;
  441. #endif
  442. //
  443. // Initialize the boot debugger for platforms that directly load the
  444. // OS Loader.
  445. //
  446. // N.B. This must occur after the console input and output have been
  447. // initialized so debug messages can be printed on the console
  448. // output device.
  449. //
  450. #if defined(_ALPHA_) || defined(ARCI386) || defined(_IA64_)
  451. LoaderBase = &__ImageBase;
  452. //
  453. // Initialize traps and the boot debugger.
  454. //
  455. #if defined(ENABLE_LOADER_DEBUG)
  456. #if defined(_ALPHA_)
  457. BdInitializeTraps();
  458. #endif
  459. BdInitDebugger((PCHAR)OsLoaderName, LoaderBase, ENABLE_LOADER_DEBUG);
  460. #else
  461. BdInitDebugger((PCHAR)OsLoaderName, 0, NULL);
  462. #endif
  463. #endif
  464. #if 0 && !defined(_IA64_)
  465. //
  466. // AJR bugbug -- do we really need to do this twice? we already call in SuMain()
  467. //
  468. // ChuckL -- Turned this code off because it screws up remote boot, which
  469. // does some allocations before we get here.
  470. //
  471. //
  472. // Initialize the memory descriptor list, the OS loader heap, and the
  473. // OS loader parameter block.
  474. //
  475. Status = BlMemoryInitialize();
  476. if (Status != ESUCCESS) {
  477. BlDiagLoadMessage(LOAD_HW_MEM_CLASS,
  478. DIAG_BL_MEMORY_INIT,
  479. LOAD_HW_MEM_ACT);
  480. goto LoadFailed;
  481. }
  482. #endif
  483. #if defined(_IA64_)
  484. //
  485. // Build required portion of ARC tree since we are not doing NTDETECT
  486. // anymore.
  487. //
  488. BuildArcTree();
  489. #endif
  490. #ifdef EFI
  491. //
  492. // Establish SMBIOS information in the loader block
  493. //
  494. SetupSMBiosInLoaderBlock();
  495. #endif
  496. SetupBlock = BlAllocateHeap(sizeof(SETUP_LOADER_BLOCK));
  497. if (SetupBlock==NULL) {
  498. SlNoMemoryError();
  499. Status = ENOMEM;
  500. goto LoadFailed;
  501. }
  502. BlLoaderBlock->SetupLoaderBlock = SetupBlock;
  503. SetupBlock->ScsiDevices = NULL;
  504. SetupBlock->BootBusExtenders = NULL;
  505. SetupBlock->BusExtenders = NULL;
  506. SetupBlock->InputDevicesSupport = NULL;
  507. SetupBlock->Flags |= SETUPBLK_FLAGS_IS_TEXTMODE;
  508. SetupBlock->ScalarValues.SetupFromCdRom = FALSE;
  509. SetupBlock->ScalarValues.SetupOperation = SetupOperationSetup;
  510. SetupBlock->ScalarValues.LoadedScsi = 0;
  511. SetupBlock->ScalarValues.LoadedCdRomDrivers = 0;
  512. SetupBlock->ScalarValues.LoadedDiskDrivers = 0;
  513. SetupBlock->ScalarValues.LoadedFloppyDrivers = 0;
  514. SetupBlock->ScalarValues.LoadedFileSystems = 0;
  515. //
  516. // Initialize the NT configuration tree.
  517. //
  518. BlLoaderBlock->ConfigurationRoot = NULL;
  519. Status = BlConfigurationInitialize(NULL, NULL);
  520. if (Status != ESUCCESS) {
  521. BlDiagLoadMessage(LOAD_HW_FW_CFG_CLASS,
  522. DIAG_BL_CONFIG_INIT,
  523. LOAD_HW_FW_CFG_ACT);
  524. goto LoadFailed;
  525. }
  526. //
  527. // Compute the data cache fill size. This value is used to align
  528. // I/O buffers in case the host system does not support coherent
  529. // caches.
  530. //
  531. // If a combined secondary cache is present, then use the fill size
  532. // for that cache. Otherwise, if a secondary data cache is present,
  533. // then use the fill size for that cache. Otherwise, if a primary
  534. // data cache is present, then use the fill size for that cache.
  535. // Otherwise, use the default fill size.
  536. //
  537. DataCache = KeFindConfigurationEntry(BlLoaderBlock->ConfigurationRoot,
  538. CacheClass,
  539. SecondaryCache,
  540. NULL);
  541. if (DataCache == NULL) {
  542. DataCache = KeFindConfigurationEntry(BlLoaderBlock->ConfigurationRoot,
  543. CacheClass,
  544. SecondaryDcache,
  545. NULL);
  546. if (DataCache == NULL) {
  547. DataCache = KeFindConfigurationEntry(BlLoaderBlock->ConfigurationRoot,
  548. CacheClass,
  549. PrimaryDcache,
  550. NULL);
  551. }
  552. }
  553. if (DataCache != NULL) {
  554. LinesPerBlock = DataCache->ComponentEntry.Key >> 24;
  555. CacheLineSize = 1 << ((DataCache->ComponentEntry.Key >> 16) & 0xff);
  556. BlDcacheFillSize = LinesPerBlock * CacheLineSize;
  557. }
  558. //
  559. // Initialize the OS loader I/O system.
  560. //
  561. Status = BlIoInitialize();
  562. if (Status != ESUCCESS) {
  563. BlDiagLoadMessage(LOAD_HW_DISK_CLASS,
  564. DIAG_BL_IO_INIT,
  565. LOAD_HW_DISK_ACT);
  566. goto LoadFailed;
  567. }
  568. #if DBG
  569. StartTime = ArcGetRelativeTime();
  570. #endif
  571. SlPositionCursor(5,3);
  572. #if !defined(_IA64_)
  573. //
  574. // Initialize the message resources
  575. //
  576. Status = BlInitResources(Argv[0]);
  577. if (Status != ESUCCESS) {
  578. // if this fails, then we can't print out any messages,
  579. // so we just exit.
  580. return(Status);
  581. }
  582. #endif
  583. //
  584. // If there is an ImageType parameter, this is a command console or rollback.
  585. //
  586. p = BlGetArgumentValue(Argc, Argv, "ImageType");
  587. if (p) {
  588. if (!strcmp (p, "cmdcons")) {
  589. UseCommandConsole = TRUE;
  590. } else if (!strcmp (p, "rollback")) {
  591. g_RollbackEnabled = TRUE;
  592. }
  593. }
  594. #ifdef FORCE_CD_BOOT
  595. g_RollbackEnabled = FALSE;
  596. #endif
  597. //
  598. // See if we're redirecting.
  599. //
  600. if( LoaderRedirectionInformation.PortAddress ) {
  601. //
  602. // Yes, we are redirecting right now. Use these settings.
  603. //
  604. BlLoaderBlock->Extension->HeadlessLoaderBlock = BlAllocateHeap(sizeof(HEADLESS_LOADER_BLOCK));
  605. RtlCopyMemory( BlLoaderBlock->Extension->HeadlessLoaderBlock,
  606. &LoaderRedirectionInformation,
  607. sizeof(HEADLESS_LOADER_BLOCK) );
  608. } else {
  609. BlLoaderBlock->Extension->HeadlessLoaderBlock = NULL;
  610. }
  611. //
  612. // Initialize the display and announce ourselves
  613. //
  614. SlInitDisplay();
  615. #if defined(_X86_) && !defined(ALLOW_386)
  616. //
  617. // Disallow installation on a 386 or any processor which
  618. // does not support CPUID and CMPXCHG8B instructions.
  619. //
  620. {
  621. if(BlIs386()) {
  622. SlFatalError(SL_TEXT_REQUIRES_486);
  623. }
  624. //
  625. // CMPXCHG8B is required on Whistler and above. This
  626. // implies a requirement for CPUID which is used to
  627. // determine the presence of CMPXCHG8B.
  628. //
  629. if ((BlGetFeatureBits() & 0x100) == 0) {
  630. SlFatalError(SL_TEXT_REQUIRED_FEATURES_MISSING);
  631. }
  632. }
  633. #endif
  634. #ifdef _IA64_
  635. //
  636. // Is this automated WinPE boot?
  637. //
  638. p = BlGetArgumentValue(Argc, Argv, "systempartition");
  639. if (p && SlIsWinPEAutoBoot(p)) {
  640. WinPEAutoBoot = TRUE;
  641. //
  642. // get the WinPE device & directory
  643. //
  644. if (ESUCCESS != SlGetWinPEStartupParams(SetupDevice, SetupDirectory)) {
  645. SlFriendlyError(
  646. Status,
  647. "SETUPLDR:Cannot find WinPE installation",
  648. __LINE__,
  649. __FILE__
  650. );
  651. goto LoadFailed;
  652. }
  653. }
  654. #endif
  655. if (!WinPEAutoBoot) {
  656. //
  657. // If this is a winnt setup, then we want to behave as if
  658. // we were started from the location specified by the
  659. // OSLOADPARTITION and OSLOADFILENAME nv-ram variables.
  660. //
  661. p = BlGetArgumentValue(Argc,Argv,"osloadoptions");
  662. if(p && !_stricmp(p,"winnt32")) {
  663. p = BlGetArgumentValue(Argc,Argv,"osloadpartition");
  664. if(!p) {
  665. SlError(100);
  666. goto LoadFailed;
  667. }
  668. Status = BlGenerateDeviceNames(p,SetupDevice,NULL);
  669. if (Status != ESUCCESS) {
  670. SlError(110);
  671. goto LoadFailed;
  672. }
  673. p = BlGetArgumentValue(Argc,Argv,"osloadfilename");
  674. if(!p || !(*p)) {
  675. SlError(120);
  676. goto LoadFailed;
  677. }
  678. strcpy(SetupDirectory,p);
  679. //
  680. // Make sure directory is terminated with a \.
  681. //
  682. if(SetupDirectory[strlen(SetupDirectory)-1] != '\\') {
  683. strcat(SetupDirectory,"\\");
  684. }
  685. } else {
  686. //
  687. // extract device name from our startup path
  688. //
  689. p=strrchr(Argv[0],')');
  690. if (p==NULL) {
  691. SlError(0);
  692. goto LoadFailed;
  693. }
  694. strncpy(SetupDevice, Argv[0], (int)(p-Argv[0]+1));
  695. SetupDevice[p-Argv[0]+1] = '\0';
  696. Status = BlGenerateDeviceNames(SetupDevice,CanonicalName,NULL);
  697. if (Status != ESUCCESS) {
  698. SlFriendlyError(
  699. Status,
  700. SetupDevice,
  701. __LINE__,
  702. __FILE__
  703. );
  704. goto LoadFailed;
  705. }
  706. strcpy(SetupDevice,CanonicalName);
  707. //
  708. // If this is a remote boot, load winnt.sif. If we were passed
  709. // a path through the soft reboot use that, if not then look
  710. // in the same place that the loader was loaded from. Once we
  711. // have read winnt.sif we get the SetupSourceDevice path.
  712. //
  713. if (BlBootingFromNet) {
  714. NetGetRebootParameters(
  715. NULL,
  716. NULL,
  717. (PUCHAR) NetbootSifFile,
  718. (PUCHAR) NetbootUser,
  719. (PUCHAR) NetbootDomain,
  720. (PUCHAR) NetbootPassword,
  721. (PUCHAR) NetbootAdministratorPassword,
  722. TRUE);
  723. if (NetbootSifFile[0] != '\0') {
  724. strcpy(BadFileName, NetbootSifFile);
  725. } else {
  726. strcpy(BadFileName,NetBootPath);
  727. strcat(BadFileName,WINNT_SIF_FILE_A);
  728. }
  729. if (NetbootAdministratorPassword[0] != '\0') {
  730. //
  731. // It's possible that the string contained in NetbootAdministratorPassword
  732. // may not be terminated. Just block copy the entire 64-bytes into the loader
  733. // block, then we'll treat the data carefully in setupdd.sys when we read it
  734. // back out.
  735. //
  736. RtlMoveMemory(BlLoaderBlock->SetupLoaderBlock->NetBootAdministratorPassword,
  737. NetbootAdministratorPassword,
  738. OSC_ADMIN_PASSWORD_LEN );
  739. }
  740. BlLoaderBlock->SetupLoaderBlock->WinntSifFile = NULL;
  741. BlLoaderBlock->SetupLoaderBlock->WinntSifFileLength = 0;
  742. Status = SlInitIniFile(SetupDevice,
  743. 0,
  744. BadFileName,
  745. &WinntSifHandle,
  746. &BlLoaderBlock->SetupLoaderBlock->WinntSifFile,
  747. &BlLoaderBlock->SetupLoaderBlock->WinntSifFileLength,
  748. &DontCare);
  749. if(Status != ESUCCESS) {
  750. if (NetbootSifFile[0] != '\0') {
  751. SlFatalError(
  752. SL_BAD_INF_FILE,
  753. SlCopyStringAT(NetbootSifFile),
  754. Status);
  755. } else {
  756. SlFatalError(
  757. SL_BAD_INF_FILE,
  758. WINNT_SIF_FILE,
  759. Status);
  760. }
  761. goto LoadFailed;
  762. }
  763. //
  764. // Get the SetupSourceDevice parameter from winnt.sif.
  765. //
  766. // SetupSourceDevice is of the form "\Device\LanmanRedirector\server\share\setup\nt5".
  767. //
  768. NetSetupServerShare = SlGetSectionKeyIndex(WinntSifHandle,
  769. "SetupData",
  770. "SetupSourceDevice",
  771. 0);
  772. #if DBG
  773. if (((ULONG)strlen(NetSetupServerShare) + 1) > sizeof(SetupBlock->NetBootIMirrorFilePath)) {
  774. DbgPrint("The UNC name is too long!\n");
  775. goto LoadFailed;
  776. }
  777. #endif
  778. strcpy((PCHAR)SetupBlock->NetBootIMirrorFilePath, NetSetupServerShare);
  779. if(NetSetupServerShare != NULL) {
  780. // must start with '\'
  781. if (*NetSetupServerShare != '\\') {
  782. NetSetupServerShare = NULL;
  783. } else {
  784. // skip to '\' after Device
  785. NetSetupServerShare = strchr(NetSetupServerShare+1,'\\');
  786. if (NetSetupServerShare != NULL) {
  787. // skip to '\' after LanmanRedirector (before server)
  788. NetSetupServerShare = strchr(NetSetupServerShare+1,'\\');
  789. if (NetSetupServerShare != NULL) {
  790. // skip to '\' after server
  791. NetSetupPath = strchr(NetSetupServerShare+1,'\\');
  792. if (NetSetupPath != NULL) {
  793. // skip to '\' after share (path part)
  794. NetSetupPath = strchr(NetSetupPath+1,'\\');
  795. }
  796. }
  797. }
  798. }
  799. }
  800. if ((NetSetupServerShare == NULL) || (NetSetupPath == NULL)) {
  801. SlFatalError(SL_INF_ENTRY_MISSING,TEXT("SetupSourceDevice"),TEXT("SetupData"));
  802. goto LoadFailed;
  803. }
  804. *NetSetupPath = 0; // terminate server\share part
  805. NetSetupPath++; // remainder is path part
  806. //
  807. // If the TargetNtPartition parameter exists in winnt.sif, then
  808. // the target is remote, and this is a remote boot setup. Otherwise,
  809. // this is a remote installation setup.
  810. //
  811. if (SlGetSectionKeyIndex(WinntSifHandle,
  812. "SetupData",
  813. "TargetNtPartition",
  814. 0) == NULL) {
  815. PCHAR pTmp, pTmp2;
  816. pTmp = SlGetSectionKeyIndex(WinntSifHandle,
  817. "OSChooser",
  818. "ImageType",
  819. 0);
  820. if (pTmp != NULL) {
  821. pTmp2 = pTmp;
  822. while (*pTmp != '\0') {
  823. *pTmp = (UCHAR)toupper(*pTmp);
  824. pTmp++;
  825. }
  826. if (!strcmp(pTmp2, "SYSPREP")) {
  827. pTmp = SlGetSectionKeyIndex(WinntSifHandle,
  828. "SetupData",
  829. "SysPrepDevice",
  830. 0);
  831. if (pTmp != NULL) {
  832. strcpy((PCHAR)SetupBlock->NetBootIMirrorFilePath, pTmp);
  833. } else {
  834. memset(SetupBlock->NetBootIMirrorFilePath,
  835. 0x0,
  836. sizeof(SetupBlock->NetBootIMirrorFilePath)
  837. );
  838. }
  839. SetupBlock->Flags |= SETUPBLK_FLAGS_SYSPREP_INSTALL;
  840. } else {
  841. SetupBlock->Flags |= SETUPBLK_FLAGS_REMOTE_INSTALL;
  842. }
  843. } else {
  844. SetupBlock->Flags |= SETUPBLK_FLAGS_REMOTE_INSTALL;
  845. }
  846. }
  847. }
  848. //
  849. // extract directory from our startup path.
  850. //
  851. if (BlBootingFromNet) {
  852. strcpy(SetupDirectory, "\\");
  853. strcat(SetupDirectory, NetSetupPath);
  854. } else if (UseCommandConsole) {
  855. strcpy(SetupDirectory,"\\cmdcons");
  856. } else if(*(p+1) != '\\') {
  857. //
  858. // directory must begin at root
  859. //
  860. strcpy(SetupDirectory, "\\");
  861. } else {
  862. *SetupDirectory = '\0';
  863. }
  864. strcat(SetupDirectory, p+1);
  865. p=strrchr(SetupDirectory, '\\');
  866. *(p+1) = '\0';
  867. }
  868. }
  869. #ifndef _IA64_
  870. BlAmd64Setup(SetupDevice);
  871. #endif
  872. #if defined(ELTORITO)
  873. if (ElToritoCDBoot && !WinPEAutoBoot) {
  874. //
  875. // Use the i386 directory for setup files when we boot from an El Torito CD
  876. //
  877. PCHAR SetupDirectoryOnDisk = "\\$WIN_NT$.~BT";
  878. CHAR SetupBootDevice[128] = {0};
  879. ULONG MaxDisksToScan = 1; // on x86 only the first disk
  880. ULONG MaxPartitionsToScan = 4; // on x86 check only primary partitions
  881. BOOLEAN CheckUpgrades = TRUE;
  882. #if defined(_IA64_)
  883. strcat(SetupDirectory, "ia64\\");
  884. /*
  885. //
  886. // Values for IA64 installation, currently not used
  887. //
  888. SetupDirectoryOnDisk = "\\$WIN_NT$.~LS\\ia64";
  889. MaxDisksToScan = 4; // NOTE : arbitrary limit
  890. MaxPartitionsToScan = 4; // NOTE : arbitrary limit
  891. */
  892. CheckUpgrades = FALSE; // NOTE : Currently disabled on IA64
  893. #else
  894. strcat(SetupDirectory, BlAmd64Setup(NULL) ? "AMD64\\" : "I386\\" );
  895. #endif
  896. //
  897. // If WinPE boot then disable check for CD boot upgrade
  898. // NOTE: We check for the presence of system32\\drivers directory
  899. // rather than relying on /minint flag in txtsetup.sif since we
  900. // have not yet loaded txtsetup.sif file
  901. //
  902. if (CheckUpgrades) {
  903. CHAR DriversDir[128];
  904. ARC_STATUS DirStatus;
  905. ULONG DeviceId, DirId;
  906. strcat(DriversDir, SetupDirectory);
  907. strcat(DriversDir, "system32\\drivers");
  908. DirStatus = ArcOpen(SetupDevice, ArcOpenReadOnly, &DeviceId);
  909. if (ESUCCESS == DirStatus) {
  910. DirStatus = BlOpen(DeviceId, DriversDir, ArcOpenDirectory, &DirId);
  911. if (ESUCCESS == DirStatus) {
  912. CheckUpgrades = FALSE; // looks like a WinPE boot
  913. BlClose(DirId);
  914. }
  915. ArcClose(DeviceId);
  916. }
  917. }
  918. //
  919. // Figure out if user was already trying to upgrade
  920. // using winnt32.exe. If user confirms he is
  921. // wants to continue upgrading then switch to
  922. // harddisk
  923. //
  924. if (CheckUpgrades &&
  925. SlIsCdBootUpgrade(SetupDirectoryOnDisk,
  926. WINNT_SIF_FILE_A,
  927. MaxDisksToScan,
  928. MaxPartitionsToScan,
  929. SetupBootDevice)) {
  930. strcpy(SetupDevice, SetupBootDevice);
  931. strcpy(SetupDirectory, SetupDirectoryOnDisk);
  932. strcat(SetupDirectory, "\\");
  933. ElToritoCDBoot = FALSE;
  934. }
  935. }
  936. #endif
  937. //
  938. // Turn on ability to load compressed files.
  939. //
  940. DecompEnableDecompression(TRUE);
  941. #if defined(EFI)
  942. //
  943. // Now that all variables are set and we can load compressed files, load the fpswa.efi driver from the setup dir
  944. //
  945. BlLoadEFIImage(SetupDevice, SetupDirectory, "fpswa.efi", TRUE, NULL);
  946. #endif
  947. ///////////////////////////////////////////////////////////////////
  948. //
  949. // On x86, the files loaded from now on are on boot floppy #1
  950. // HALs may be on floppy #1 or floppy #2
  951. //
  952. ///////////////////////////////////////////////////////////////////
  953. strcpy(KernelDirectoryPath, SetupDirectory);
  954. strcat(KernelDirectoryPath, "txtsetup.sif");
  955. BlLoaderBlock->SetupLoaderBlock->IniFile = NULL;
  956. Status = SlInitIniFile(SetupDevice,
  957. 0,
  958. KernelDirectoryPath,
  959. &InfFile,
  960. &BlLoaderBlock->SetupLoaderBlock->IniFile,
  961. &BlLoaderBlock->SetupLoaderBlock->IniFileLength,
  962. &ErrorLine);
  963. if (Status != ESUCCESS) {
  964. //
  965. // See if we can get the txtsetup.sif out of the WinPE boot
  966. // directory.
  967. //
  968. if( (strcmp( SetupDirectory, "\\") == 0) &&
  969. (!ElToritoCDBoot) &&
  970. (!BlBootingFromNet) ) {
  971. //
  972. // We're not booting off CD and we're not booting off the
  973. // net and we're about to fail because we didn't find \txtsetup.sif
  974. // Try in the MiniNT directory...
  975. //
  976. Status = SlInitIniFile(SetupDevice,
  977. 0,
  978. "\\minint\\txtsetup.sif",
  979. &InfFile,
  980. &BlLoaderBlock->SetupLoaderBlock->IniFile,
  981. &BlLoaderBlock->SetupLoaderBlock->IniFileLength,
  982. &ErrorLine);
  983. }
  984. if( Status != ESUCCESS ) {
  985. SlFatalError(SL_BAD_INF_FILE,
  986. TEXT("txtsetup.sif"),
  987. Status);
  988. goto LoadFailed;
  989. }
  990. }
  991. SlGetSetupValuesBeforePrompt(SetupBlock);
  992. //
  993. // Find out if we are starting the MiniNT boot or rollback
  994. // (mutually exclusive options)
  995. //
  996. if (BlLoaderBlock->LoadOptions) {
  997. CHAR Option[256];
  998. PCHAR NextOption = strchr(BlLoaderBlock->LoadOptions, '/');
  999. PCHAR OptionEnd = NULL;
  1000. while (NextOption) {
  1001. OptionEnd = strchr(NextOption, ' ');
  1002. if (OptionEnd) {
  1003. strncpy(Option, NextOption, OptionEnd - NextOption);
  1004. Option[OptionEnd - NextOption] = 0;
  1005. } else {
  1006. strcpy(Option, NextOption);
  1007. }
  1008. if (!_stricmp(Option, "/minint")) {
  1009. WinPEBoot = TRUE;
  1010. }
  1011. //
  1012. // Pick up any headless settings in the boot options.
  1013. //
  1014. if (!_strnicmp(Option,"/redirect=",10)) {
  1015. PCHAR pOption = strchr(Option,'=');
  1016. if( pOption != NULL ) {
  1017. pOption++;
  1018. if (_strnicmp(pOption,"com",3) == 0) {
  1019. pOption +=3;
  1020. LoaderRedirectionInformation.PortNumber = atoi(pOption);
  1021. } else if (_strnicmp(pOption, "usebiossettings", 15) == 0) {
  1022. BlRetrieveBIOSRedirectionInformation();
  1023. } else {
  1024. //
  1025. // See if they gave us a hardcoded address.
  1026. //
  1027. LoaderRedirectionInformation.PortAddress = (PUCHAR)ULongToPtr(strtoul(pOption,NULL,16));
  1028. if( LoaderRedirectionInformation.PortAddress != (PUCHAR)NULL ) {
  1029. LoaderRedirectionInformation.PortNumber = 3;
  1030. }
  1031. }
  1032. }
  1033. }
  1034. if (!_strnicmp(Option,"/redirectbaudrate=",18)) {
  1035. PCHAR pOption = strchr(Option,'=');
  1036. if( pOption != NULL ) {
  1037. pOption++;
  1038. if( _strnicmp(pOption,"115200",6) == 0 ) {
  1039. LoaderRedirectionInformation.BaudRate = BD_115200;
  1040. } else if( _strnicmp(pOption,"57600",5) == 0 ) {
  1041. LoaderRedirectionInformation.BaudRate = BD_57600;
  1042. } else if( _strnicmp(pOption,"19200",5) == 0 ) {
  1043. LoaderRedirectionInformation.BaudRate = BD_19200;
  1044. } else {
  1045. LoaderRedirectionInformation.BaudRate = BD_9600;
  1046. }
  1047. }
  1048. }
  1049. NextOption++;
  1050. NextOption = strchr(NextOption, '/');
  1051. }
  1052. }
  1053. //
  1054. // Fix up the setup directory path to include system32 also
  1055. // if this is a MiniNT boot
  1056. //
  1057. if (WinPEBoot) {
  1058. strcat(SetupDirectory, "system32\\");
  1059. //
  1060. // find out if a different load message has been specified
  1061. //
  1062. #ifdef UNICODE
  1063. StartupMsg = SlGetIniValueW(InfFile,
  1064. #else
  1065. StartupMsg = (PCTSTR)SlGetIniValue(InfFile,
  1066. #endif
  1067. "setupdata",
  1068. "loaderprompt",
  1069. NULL);
  1070. //
  1071. // Reduce the OEM key press time out
  1072. //
  1073. OemKeypressTimeout = 2; // secs
  1074. }
  1075. //
  1076. // Now we know everything we should load, compute the ARC name to load
  1077. // from and start loading things.
  1078. //
  1079. if (BootDevice==NULL) {
  1080. //
  1081. // No device was explicitly specified, so use whatever device
  1082. // setupldr was started from.
  1083. //
  1084. BootDevice = SlCopyStringA(SetupDevice);
  1085. }
  1086. Status = ArcOpen(BootDevice, ArcOpenReadOnly, &BootDeviceId);
  1087. if (Status != ESUCCESS) {
  1088. SlFatalError(SL_IO_ERROR,SlCopyStringAT(BootDevice));
  1089. goto LoadFailed;
  1090. } else {
  1091. BootDeviceIdValid = TRUE;
  1092. }
  1093. #ifdef _X86_
  1094. //
  1095. // Load the bootfont.bin into memory
  1096. //
  1097. SlLoadBootFontFile(BlLoaderBlock->SetupLoaderBlock,
  1098. BootDeviceId,
  1099. BootFontImageLength);
  1100. #endif // _X86_
  1101. _strlwr(BootDevice);
  1102. FixedBootMedia = (BOOLEAN)(strstr(BootDevice,")rdisk(") != NULL);
  1103. FloppyBoot = (BOOLEAN)(strstr(BootDevice, ")fdisk(") != NULL);
  1104. //
  1105. // If we are booting from fixed media, we better load disk class drivers.
  1106. //
  1107. if(FixedBootMedia) {
  1108. LoadDiskClass = TRUE;
  1109. }
  1110. if(!BlGetPathMnemonicKey(BootDevice,"disk",&DontCare)
  1111. && !BlGetPathMnemonicKey(BootDevice,"fdisk",&BootDriveNumber))
  1112. {
  1113. //
  1114. // boot was from floppy, canonicalize the ARC name.
  1115. //
  1116. BlLoaderBlock->ArcBootDeviceName = BlAllocateHeap(80);
  1117. sprintf(BlLoaderBlock->ArcBootDeviceName, "multi(0)disk(0)fdisk(%d)",BootDriveNumber);
  1118. } else {
  1119. BlLoaderBlock->ArcBootDeviceName = BootDevice;
  1120. }
  1121. if (BootPath==NULL) {
  1122. //
  1123. // No explicit boot path given, default to the directory setupldr was started
  1124. // from.
  1125. //
  1126. #if defined(_X86_)
  1127. //
  1128. // Increadibly nauseating hack:
  1129. //
  1130. // If we are booting from hard drive on x86, we will assume this is
  1131. // the 'floppyless' winnt/winnt32 scenario, in which case the actual
  1132. // boot path is \$win_nt$.~bt.
  1133. //
  1134. // This lets us avoid having winnt and winnt32 attempt to modify
  1135. // the BootPath value in the [SetupData] section of txtsetup.sif.
  1136. //
  1137. // Enable booting WINPE from an LS-120 media.
  1138. //
  1139. if((FixedBootMedia)||(WinPEBoot && FloppyBoot)) {
  1140. CHAR SetupPath[256];
  1141. if( WinPEBoot ) {
  1142. strcpy(SetupPath, "\\minint\\system32\\");
  1143. } else if( UseCommandConsole ) {
  1144. strcpy(SetupPath, "\\CMDCONS\\");
  1145. } else {
  1146. strcpy(SetupPath, "\\$WIN_NT$.~BT\\");
  1147. }
  1148. BootPath = SlCopyStringA(SetupPath);
  1149. } else
  1150. #endif
  1151. BootPath = SlCopyStringA(SetupDirectory);
  1152. }
  1153. //
  1154. // Load the WinPE inf, if present.
  1155. //
  1156. if (WinPEBoot) {
  1157. CHAR FullPath[128];
  1158. strcpy(FullPath, BootPath);
  1159. strcat(FullPath, WINPE_OEM_FILENAME_A);
  1160. Status = SlInitIniFile(NULL,
  1161. BootDeviceId,
  1162. FullPath,
  1163. &OemInfHandle,
  1164. NULL,
  1165. 0,
  1166. &ErrorLine);
  1167. if (Status != ESUCCESS) {
  1168. OemInfHandle = NULL;
  1169. Status = ESUCCESS;
  1170. }
  1171. }
  1172. #ifdef _WANT_MACHINE_IDENTIFICATION
  1173. BlLoaderBlock->Extension->InfFileImage = NULL;
  1174. BlLoaderBlock->Extension->InfFileSize = 0;
  1175. if (BiosInfo.Buffer) {
  1176. if (Status == ESUCCESS) {
  1177. Status = BlLoadBiosinfoInf( BootDeviceId,
  1178. BlFindMessage(SL_BIOSINFO_NAME),
  1179. BootPath,
  1180. &BiosInfo,
  1181. &BlLoaderBlock->Extension->InfFileImage,
  1182. &BlLoaderBlock->Extension->InfFileSize,
  1183. BadFileName);
  1184. }
  1185. if (Status != ESUCCESS) {
  1186. SlFatalError(SL_FILE_LOAD_FAILED, SlCopyStringAT(BadFileName), Status);
  1187. goto LoadFailed;
  1188. }
  1189. }
  1190. #endif
  1191. //
  1192. // Let the kernel deal with failure to load this driver database.
  1193. //
  1194. BlLoaderBlock->Extension->DrvDBImage = NULL;
  1195. BlLoaderBlock->Extension->DrvDBSize = 0;
  1196. DrvMainSdb.Buffer = DRIVER_DATABASE_FILENAME;
  1197. DrvMainSdb.MaximumLength = sizeof(DRIVER_DATABASE_FILENAME); // MaxLength is size of buffer
  1198. DrvMainSdb.Length = sizeof(DRIVER_DATABASE_FILENAME) - sizeof(WCHAR); // Length does not include \0
  1199. BlLoadDrvDB( BootDeviceId,
  1200. NULL, // BlFindMessage(SL_DRVMAINSDB_NAME),
  1201. BootPath,
  1202. &DrvMainSdb,
  1203. &BlLoaderBlock->Extension->DrvDBImage,
  1204. &BlLoaderBlock->Extension->DrvDBSize,
  1205. BadFileName);
  1206. //
  1207. // Attempt to load winnt.sif from the path where we are
  1208. // loading setup files. Borrow the BadFileName buffer
  1209. // for temporary use.
  1210. //
  1211. if (!BlBootingFromNet) {
  1212. CHAR FloppyName[80];
  1213. ULONG FloppyId;
  1214. BOOLEAN FloppyUsed = FALSE;
  1215. if (SlpFindFloppy(0,FloppyName)) {
  1216. Status = ArcOpen(FloppyName,ArcOpenReadOnly,&FloppyId);
  1217. if (Status == ESUCCESS) {
  1218. strcpy(BadFileName,"\\");
  1219. strcat(BadFileName,WINNT_SIF_FILE_A);
  1220. BlLoaderBlock->SetupLoaderBlock->WinntSifFile = NULL;
  1221. BlLoaderBlock->SetupLoaderBlock->WinntSifFileLength = 0;
  1222. Status = SlInitIniFile(
  1223. NULL,
  1224. FloppyId,
  1225. BadFileName,
  1226. &WinntSifHandle,
  1227. &BlLoaderBlock->SetupLoaderBlock->WinntSifFile,
  1228. &BlLoaderBlock->SetupLoaderBlock->WinntSifFileLength,
  1229. &DontCare
  1230. );
  1231. if (Status == ESUCCESS) {
  1232. FloppyUsed = TRUE;
  1233. }
  1234. ArcClose(FloppyId);
  1235. }
  1236. }
  1237. if (!FloppyUsed) {
  1238. strcpy(BadFileName,BootPath);
  1239. strcat(BadFileName,WINNT_SIF_FILE_A);
  1240. BlLoaderBlock->SetupLoaderBlock->WinntSifFile = NULL;
  1241. BlLoaderBlock->SetupLoaderBlock->WinntSifFileLength = 0;
  1242. Status = SlInitIniFile(
  1243. NULL,
  1244. BootDeviceId,
  1245. BadFileName,
  1246. &WinntSifHandle,
  1247. &BlLoaderBlock->SetupLoaderBlock->WinntSifFile,
  1248. &BlLoaderBlock->SetupLoaderBlock->WinntSifFileLength,
  1249. &DontCare
  1250. );
  1251. }
  1252. }
  1253. IsUpgrade = SlIsUpgrade(WinntSifHandle);
  1254. UseRegularBackground = (UseCommandConsole || IsUpgrade || WinPEBoot);
  1255. //
  1256. // If the BIOS told us to redirect, we'd be doing it right now. However,
  1257. // the user may have told us some specific settings. If that's the case,
  1258. // override anything we're doing now with the settings from the user.
  1259. //
  1260. if( WinntSifHandle ) {
  1261. p = SlGetSectionKeyIndex(WinntSifHandle, WINNT_DATA_A, WINNT_U_HEADLESS_REDIRECT_A, 0);
  1262. if (p != NULL) {
  1263. if (!_strnicmp(p, "com", 3)) {
  1264. LoaderRedirectionInformation.PortNumber = (UCHAR)atoi( (PCHAR)(p+3) );
  1265. //
  1266. // See if they want to give us a baudrate.
  1267. //
  1268. p = SlGetSectionKeyIndex( WinntSifHandle, WINNT_DATA_A, WINNT_U_HEADLESS_REDIRECTBAUDRATE_A, 0 );
  1269. if( p ) {
  1270. if( _strnicmp(p,"115200",6) == 0 ) {
  1271. LoaderRedirectionInformation.BaudRate = BD_115200;
  1272. } else if( _strnicmp(p,"57600",5) == 0 ) {
  1273. LoaderRedirectionInformation.BaudRate = BD_57600;
  1274. } else if( _strnicmp(p,"19200",5) == 0 ) {
  1275. LoaderRedirectionInformation.BaudRate = BD_19200;
  1276. } else {
  1277. LoaderRedirectionInformation.BaudRate = BD_9600;
  1278. }
  1279. }
  1280. } else if( !_stricmp(p, "usebiossettings" ) ) {
  1281. //
  1282. // Now we get to dig up all the information from the
  1283. // ACPI table.
  1284. //
  1285. BlRetrieveBIOSRedirectionInformation();
  1286. } else if( !_stricmp(p, "noncomport" ) ) {
  1287. //
  1288. // It's something other than serial. Go load a file off the floppy
  1289. // and get the driver from there.
  1290. //
  1291. //
  1292. // Currently not implemented.
  1293. //
  1294. RtlZeroMemory( &LoaderRedirectionInformation, sizeof(HEADLESS_LOADER_BLOCK) );
  1295. } else {
  1296. //
  1297. // See if they gave us a hardcoded address.
  1298. //
  1299. LoaderRedirectionInformation.PortAddress = (PUCHAR)ULongToPtr(strtoul(p,NULL,16));
  1300. if( LoaderRedirectionInformation.PortAddress != (PUCHAR)NULL ) {
  1301. LoaderRedirectionInformation.PortNumber = 3;
  1302. }
  1303. }
  1304. }
  1305. }
  1306. //
  1307. // If we found any headless redirection settings, go initialize
  1308. // the port now.
  1309. //
  1310. if( (LoaderRedirectionInformation.PortNumber) || (LoaderRedirectionInformation.PortAddress) ) {
  1311. //
  1312. // Yes, we are redirecting right now. Use these settings.
  1313. //
  1314. BlInitializeHeadlessPort();
  1315. SlClearDisplay();
  1316. if( BlLoaderBlock->Extension->HeadlessLoaderBlock == NULL ) {
  1317. BlLoaderBlock->Extension->HeadlessLoaderBlock = BlAllocateHeap(sizeof(HEADLESS_LOADER_BLOCK));
  1318. if (BlLoaderBlock->Extension->HeadlessLoaderBlock == NULL) {
  1319. SlNoMemoryError();
  1320. goto LoadFailed;
  1321. }
  1322. }
  1323. RtlCopyMemory( BlLoaderBlock->Extension->HeadlessLoaderBlock,
  1324. &LoaderRedirectionInformation,
  1325. sizeof(HEADLESS_LOADER_BLOCK) );
  1326. } else {
  1327. BlLoaderBlock->Extension->HeadlessLoaderBlock = NULL;
  1328. }
  1329. if (UseRegularBackground) {
  1330. extern BOOLEAN BlOutputDots;
  1331. extern int BlMaxFilesToLoad;
  1332. SlSetCurrentAttribute(DEFATT);
  1333. SlSetStatusAttribute(DEFATT);
  1334. SlClearDisplay();
  1335. SlPositionCursor(0,0);
  1336. if (UseCommandConsole) {
  1337. SlPrint(BlFindMessage(SL_CMDCONS_MSG));
  1338. }
  1339. BlOutputDots = TRUE;
  1340. //
  1341. // To reset BlShowProgress bar correctly
  1342. //
  1343. BlDisableProgressBar = FALSE;
  1344. BlProgressBarShowTimeOut = 0;
  1345. //
  1346. // Note : We can compute the real number of drivers to be loaded
  1347. // from various INF sections and manually counting all the
  1348. // different SlLoadDriver(...) calls. But the code/effort required
  1349. // to do this is not worth the feature, since we just want to
  1350. // replace the old "..." with progress bar to make the recovery
  1351. // console starting look similar to windows starting. So we make
  1352. // an assumption here about the maximum files to be loaded.
  1353. //
  1354. BlMaxFilesToLoad = 80;
  1355. BlSetProgBarCharacteristics(SL_CMDCONS_PROGBAR_FRONT,
  1356. SL_CMDCONS_PROGBAR_BACK);
  1357. if (WinPEBoot) {
  1358. StartupMsg ? BlOutputStartupMsgStr(StartupMsg) :
  1359. BlOutputStartupMsg(SL_SETUP_STARTING_WINPE);
  1360. } else if (UseCommandConsole) {
  1361. BlOutputStartupMsg(SL_CMDCONS_STARTING);
  1362. } else if (g_RollbackEnabled) {
  1363. BlOutputStartupMsg(SL_ROLLBACK_STARTING);
  1364. } else if (IsUpgrade) {
  1365. BlOutputStartupMsg(SL_SETUP_STARTING);
  1366. }
  1367. } else {
  1368. SlSetCurrentAttribute(DEFATT);
  1369. SlSetStatusAttribute(DEFSTATTR);
  1370. SlClearDisplay();
  1371. SlWriteHeaderText(SL_WELCOME_HEADER);
  1372. SlClearClientArea();
  1373. }
  1374. //
  1375. // Figure out all the OEM drivers source devices
  1376. //
  1377. RamdiskInitialize(BlLoaderBlock->LoadOptions, FALSE);
  1378. SlInitOemSourceDevices(&OemSourceDevices, &DefaultOemSourceDevice);
  1379. //
  1380. // If we found at least one valid OEM source device with proper
  1381. // txtsetup.oem and no default driver then bump up the timeout to
  1382. // 20 secs
  1383. //
  1384. if (OemSourceDevices) {
  1385. POEM_SOURCE_DEVICE CurrDevice = OemSourceDevices;
  1386. while(CurrDevice) {
  1387. if (SL_OEM_SOURCE_MEDIA_TYPE(CurrDevice,
  1388. SL_OEM_SOURCE_MEDIA_HAS_DRIVERS) &&
  1389. !SL_OEM_SOURCE_MEDIA_TYPE(CurrDevice,
  1390. SL_OEM_SOURCE_MEDIA_HAS_DEFAULT)) {
  1391. OemKeypressTimeout = 20;
  1392. break;
  1393. }
  1394. CurrDevice = CurrDevice->Next;
  1395. }
  1396. }
  1397. //
  1398. // We need to check to see if the user pressed any keys to force OEM HAL,
  1399. // OEM SCSI, or both. Do this before getting the settings in the sif file,
  1400. // so that we won't try to detect the machine if OEM HAL is needed.
  1401. //
  1402. SlCheckOemKeypress(OemKeypressTimeout);
  1403. {
  1404. PCSTR szOptionsToAdd = NULL;
  1405. CHAR szOptionsToRemove[sizeof("/noguiboot/nodebug")];
  1406. szOptionsToRemove[0] = 0;
  1407. //
  1408. // If F8 was pressed, add the debug options
  1409. //
  1410. if(EnableDebugger) {
  1411. if(InfFile != NULL) {
  1412. szOptionsToAdd = SlGetSectionKeyIndex(InfFile, "SetupData", "SetupDebugOptions", 0);
  1413. }
  1414. if(NULL == szOptionsToAdd) {
  1415. szOptionsToAdd = "/debug";
  1416. }
  1417. strcat(szOptionsToRemove, "/nodebug");
  1418. }
  1419. //
  1420. // remove the /noguiboot option so what we show the logo
  1421. // and switch the video adapter into graphics mode
  1422. // early on during initialization
  1423. //
  1424. if (IsUpgrade) {
  1425. strcat(szOptionsToRemove, "/noguiboot");
  1426. }
  1427. if(szOptionsToAdd != NULL || szOptionsToRemove[0] != 0) {
  1428. SlModifyOsLoadOptions(&BlLoaderBlock->LoadOptions, szOptionsToAdd, szOptionsToRemove);
  1429. }
  1430. }
  1431. #if defined(_X86_) || defined(_IA64_)
  1432. //
  1433. // We need to check to see if the user pressed any keys to force loading,
  1434. // an ASR pnp repair disk. Only do this if the user didn't select
  1435. // anything in the SlCheckOemKeypress function.
  1436. //
  1437. if(!UseCommandConsole && !WinPEBoot && !IsUpgrade && !BlBootingFromNet) {
  1438. PCHAR pTmp;
  1439. pTmp = SlGetSectionKeyIndex(InfFile,
  1440. "SetupData",
  1441. "DisableAsr",
  1442. 0);
  1443. if ((pTmp == NULL) || (atoi(pTmp) == 0)) {
  1444. SlCheckASRKeypress();
  1445. }
  1446. }
  1447. if (BlBootingFromNet && TryASRViaNetwork) {
  1448. PVOID ASRPNPSifHandle = NULL;
  1449. ULONG c;
  1450. PCHAR FileNameFromSif;
  1451. FileNameFromSif = SlGetIniValue(
  1452. WinntSifHandle,
  1453. "OSChooser",
  1454. "ASRFile",
  1455. "generic.sif" );
  1456. Status = SlInitIniFile( SetupDevice,
  1457. 0,
  1458. FileNameFromSif,
  1459. &ASRPNPSifHandle,
  1460. &BlLoaderBlock->SetupLoaderBlock->ASRPnPSifFile,
  1461. &BlLoaderBlock->SetupLoaderBlock->ASRPnPSifFileLength,
  1462. &c );
  1463. if(Status != ESUCCESS) {
  1464. SlFatalError(SL_BAD_INF_FILE,SlCopyStringAT(FileNameFromSif),Status);
  1465. goto LoadFailed;
  1466. }
  1467. }
  1468. #endif
  1469. SlGetSetupValuesAfterPrompt(SetupBlock);
  1470. //
  1471. // Are there any dyamic update boot drivers which we need
  1472. // to process
  1473. //
  1474. DynamicUpdate = SlpIsDynamicUpdate(WinntSifHandle, &DynamicUpdateRootDir);
  1475. //
  1476. // Add the dynamic update source device as OEM source device since it could
  1477. // have F6
  1478. //
  1479. if (DynamicUpdate) {
  1480. DynamicUpdateSourceDevice = BlAllocateHeap(sizeof(OEM_SOURCE_DEVICE));
  1481. if (DynamicUpdateSourceDevice) {
  1482. memset(DynamicUpdateSourceDevice, 0, sizeof(OEM_SOURCE_DEVICE));
  1483. strcpy(DynamicUpdateSourceDevice->ArcDeviceName,
  1484. BootDevice);
  1485. DynamicUpdateSourceDevice->DriverDir = DynamicUpdateRootDir;
  1486. SL_OEM_SET_SOURCE_DEVICE_TYPE(DynamicUpdateSourceDevice,
  1487. (SL_OEM_SOURCE_DEVICE_TYPE_LOCAL |
  1488. SL_OEM_SOURCE_DEVICE_TYPE_FIXED |
  1489. SL_OEM_SOURCE_DEVICE_TYPE_DYN_UPDATE));
  1490. SL_OEM_SET_SOURCE_MEDIA_TYPE(DynamicUpdateSourceDevice,
  1491. (SL_OEM_SOURCE_MEDIA_PRESENT |
  1492. SL_OEM_SOURCE_MEDIA_HAS_DRIVERS |
  1493. SL_OEM_SOURCE_MEDIA_HAS_MSD |
  1494. SL_OEM_SOURCE_MEDIA_HAS_DEFAULT));
  1495. SL_OEM_SET_SOURCE_DEVICE_STATE(DynamicUpdateSourceDevice,
  1496. SL_OEM_SOURCE_DEVICE_NOT_PROCESSED);
  1497. DynamicUpdateSourceDevice->DeviceId = BootDeviceId;
  1498. //
  1499. // Insert it at the head of the linked list
  1500. //
  1501. DynamicUpdateSourceDevice->Next = OemSourceDevices;
  1502. OemSourceDevices = DynamicUpdateSourceDevice;
  1503. }
  1504. }
  1505. if (BlBootingFromNet || (Status == ESUCCESS)) {
  1506. //
  1507. // Find out if this is a pre-install, by looking at OemPreinstall key
  1508. // in [unattended] section of winnt.sif
  1509. //
  1510. p = SlGetSectionKeyIndex(WinntSifHandle,WINNT_UNATTENDED_A,WINNT_U_OEMPREINSTALL_A,0);
  1511. if(p && !_stricmp(p,"yes")) {
  1512. PreInstall = TRUE;
  1513. }
  1514. //
  1515. // If this is a pre-install, find out which hal to load, by looking
  1516. // at ComputerType key in [unattended] section of winnt.sif.
  1517. //
  1518. if( PreInstall && !DynamicUpdate) {
  1519. #ifdef UNICODE
  1520. ComputerType = (PTCHAR)SlGetSectionKeyIndexW(
  1521. #else
  1522. ComputerType = (PTCHAR)SlGetSectionKeyIndex(
  1523. #endif
  1524. WinntSifHandle,
  1525. WINNT_UNATTENDED_A,
  1526. WINNT_U_COMPUTERTYPE_A,
  1527. 0);
  1528. if(ComputerType) {
  1529. //
  1530. // If the hal to load is an OEM one, then set OemHal to TRUE
  1531. //
  1532. p = SlGetSectionKeyIndex(WinntSifHandle,WINNT_UNATTENDED_A,WINNT_U_COMPUTERTYPE_A,1);
  1533. if(p && !_stricmp(p, OemTag)) {
  1534. OemHal = TRUE;
  1535. } else {
  1536. OemHal = FALSE;
  1537. }
  1538. //
  1539. // In the pre-install mode, don't let the user specify
  1540. // an OEM hal, if one was specified in unattend.txt
  1541. //
  1542. PromptOemHal = FALSE;
  1543. }
  1544. //
  1545. // Find out which SCSI drivers to load, by looking at
  1546. // [MassStorageDrivers] in winnt.sif
  1547. //
  1548. if( SpSearchINFSection( WinntSifHandle, WINNT_OEMSCSIDRIVERS_A ) ) {
  1549. PPREINSTALL_DRIVER_INFO TempDriverInfo;
  1550. PTSTR pOem;
  1551. #ifdef UNICODE
  1552. CHAR DriverDescriptionA[100];
  1553. PCHAR pDriverDescriptionA;
  1554. UNICODE_STRING uString;
  1555. ANSI_STRING aString;
  1556. #endif
  1557. PreinstallDriverList = NULL;
  1558. for( i = 0;
  1559. #ifdef UNICODE
  1560. ((pOem = SlGetKeyNameW(
  1561. #else
  1562. ((pOem = SlGetKeyName(
  1563. #endif
  1564. WinntSifHandle,
  1565. WINNT_OEMSCSIDRIVERS_A,
  1566. i )) != NULL);
  1567. i++ ) {
  1568. TempDriverInfo = BlAllocateHeap(sizeof(PREINSTALL_DRIVER_INFO));
  1569. if (TempDriverInfo==NULL) {
  1570. SlNoMemoryError();
  1571. goto LoadFailed;
  1572. }
  1573. TempDriverInfo->DriverDescription = pOem;
  1574. #ifdef UNICODE
  1575. RtlInitUnicodeString( &uString, TempDriverInfo->DriverDescription);
  1576. //
  1577. // use the static buffer if possible
  1578. //
  1579. pDriverDescriptionA = DriverDescriptionA;
  1580. aString.MaximumLength = sizeof(DriverDescriptionA);
  1581. //
  1582. // if more memory is needed for the driver description
  1583. // allocate it
  1584. //
  1585. if (aString.MaximumLength < uString.Length/2 + 1 ) {
  1586. pDriverDescriptionA = BlAllocateHeap(uString.Length/2 + 1);
  1587. if (pDriverDescriptionA == NULL) {
  1588. SlNoMemoryError();
  1589. goto LoadFailed;
  1590. }
  1591. aString.MaximumLength = uString.Length/2 + 1;
  1592. }
  1593. aString.Buffer = pDriverDescriptionA;
  1594. Status = RtlUnicodeStringToAnsiString( &aString, &uString, FALSE );
  1595. pOem = (Status != ESUCCESS) ? NULL : SlGetIniValueW( WinntSifHandle,
  1596. WINNT_OEMSCSIDRIVERS_A,
  1597. pDriverDescriptionA,
  1598. NULL );
  1599. #else
  1600. pOem = SlGetIniValue(
  1601. WinntSifHandle,
  1602. WINNT_OEMSCSIDRIVERS_A,
  1603. TempDriverInfo->DriverDescription,
  1604. NULL );
  1605. #endif
  1606. TempDriverInfo->OemDriver = (pOem && !_tcsicmp(pOem, _TOemTag))? TRUE : FALSE;
  1607. TempDriverInfo->Next = PreinstallDriverList;
  1608. PreinstallDriverList = TempDriverInfo;
  1609. }
  1610. if( PreinstallDriverList != NULL ) {
  1611. //
  1612. // In the pre-install mode, don't let the user specify
  1613. // an OEM scsi, if at least one was specified in unattend.txt
  1614. //
  1615. PromptOemScsi = FALSE;
  1616. }
  1617. }
  1618. }
  1619. p = SlGetSectionKeyIndex(WinntSifHandle,WINNT_SETUPPARAMS_A,WINNT_S_SKIPMISSING_A,0);
  1620. if(p && (*p != '0')) {
  1621. IgnoreMissingFiles = TRUE;
  1622. }
  1623. #if defined(_X86_) || defined(_IA64_)
  1624. //
  1625. // Find out if this is a Win9x upgrade
  1626. //
  1627. Win9xUnsupHdc = FALSE;
  1628. p = SlGetSectionKeyIndex(WinntSifHandle,WINNT_DATA_A,WINNT_D_WIN95UPGRADE_A,0);
  1629. if(p && !_stricmp(p, WINNT_A_YES_A)) {
  1630. //
  1631. // If it is an Win9x upgrade, find out if winnt32 found an unsupported
  1632. // hard disk controller.
  1633. //
  1634. p = SlGetSectionKeyIndex(WinntSifHandle,WINNT_DATA_A,WINNT_D_WIN95UNSUPHDC_A,0);
  1635. if(p && (*p != '0')) {
  1636. Win9xUnsupHdc = TRUE;
  1637. }
  1638. }
  1639. #endif
  1640. //
  1641. // At this point, we know that we wre able to read winnt.sif.
  1642. // So attempt to read migrate.inf. Borrow the BadFileName buffer
  1643. // for temporary use.
  1644. //
  1645. strcpy(BadFileName,BootPath);
  1646. strcat(BadFileName,WINNT_MIGRATE_INF_FILE_A);
  1647. if( SlInitIniFile(NULL,
  1648. BootDeviceId,
  1649. BadFileName,
  1650. &MigrateInfHandle,
  1651. &BlLoaderBlock->SetupLoaderBlock->MigrateInfFile,
  1652. &BlLoaderBlock->SetupLoaderBlock->MigrateInfFileLength,
  1653. &DontCare) != ESUCCESS ) {
  1654. MigrateInfHandle = NULL;
  1655. BlLoaderBlock->SetupLoaderBlock->MigrateInfFile = NULL;
  1656. BlLoaderBlock->SetupLoaderBlock->MigrateInfFileLength = 0;
  1657. }
  1658. //
  1659. // Attempt also to read unsupdrv.inf. Borrow the BadFileName buffer
  1660. // for temporary use.
  1661. //
  1662. strcpy(BadFileName,BootPath);
  1663. strcat(BadFileName,WINNT_UNSUPDRV_INF_FILE_A);
  1664. if( SlInitIniFile(NULL,
  1665. BootDeviceId,
  1666. BadFileName,
  1667. &UnsupDriversInfHandle,
  1668. &BlLoaderBlock->SetupLoaderBlock->UnsupDriversInfFile,
  1669. &BlLoaderBlock->SetupLoaderBlock->UnsupDriversInfFileLength,
  1670. &DontCare) != ESUCCESS ) {
  1671. UnsupDriversInfHandle = NULL;
  1672. BlLoaderBlock->SetupLoaderBlock->UnsupDriversInfFile = NULL;
  1673. BlLoaderBlock->SetupLoaderBlock->UnsupDriversInfFileLength = 0;
  1674. }
  1675. SlGetMigratedHardwareIds(SetupBlock, UnsupDriversInfHandle);
  1676. } else {
  1677. WinntSifHandle = NULL;
  1678. //
  1679. // If winnt.sif doesn't exist, then we don't bother to read migrate.inf and unsupdrv.inf,
  1680. // since we are booting from the retail boot floppies or the CD, and in this
  1681. // case there is no migrate.inf or unsupdrv.inf.
  1682. //
  1683. MigrateInfHandle = NULL;
  1684. BlLoaderBlock->SetupLoaderBlock->MigrateInfFile = NULL;
  1685. BlLoaderBlock->SetupLoaderBlock->MigrateInfFileLength = 0;
  1686. UnsupDriversInfHandle = NULL;
  1687. BlLoaderBlock->SetupLoaderBlock->UnsupDriversInfFile = NULL;
  1688. BlLoaderBlock->SetupLoaderBlock->UnsupDriversInfFileLength = 0;
  1689. }
  1690. //
  1691. // Store the boot path in the loader block.
  1692. //
  1693. if (UseCommandConsole) {
  1694. SetupBlock->Flags |= SETUPBLK_FLAGS_CONSOLE;
  1695. }
  1696. if (g_RollbackEnabled) {
  1697. SetupBlock->Flags |= SETUPBLK_FLAGS_ROLLBACK;
  1698. }
  1699. if ( !BlBootingFromNet ) {
  1700. BlLoaderBlock->NtBootPathName = BootPath;
  1701. } else {
  1702. ANSI_STRING aString;
  1703. UNICODE_STRING uString;
  1704. ULONG length;
  1705. #if defined(REMOTE_BOOT)
  1706. PCHAR TempEnableIpsec;
  1707. #endif // defined(REMOTE_BOOT)
  1708. SetupBlock->Flags |= SETUPBLK_FLAGS_IS_REMOTE_BOOT;
  1709. BlLoaderBlock->NtBootPathName =
  1710. BlAllocateHeap( (ULONG)strlen(NetSetupServerShare) + (ULONG)strlen(BootPath) + 1 );
  1711. if ( BlLoaderBlock->NtBootPathName == NULL ) {
  1712. SlNoMemoryError();
  1713. goto LoadFailed;
  1714. }
  1715. strcpy( BlLoaderBlock->NtBootPathName, NetSetupServerShare );
  1716. strcat( BlLoaderBlock->NtBootPathName, BootPath );
  1717. //
  1718. // NetSetupServerShare is of the form \server\IMirror. NetBootPath
  1719. // is of the form Clients\machine\ (note trailing \). We need to
  1720. // insert a \ between the two and add BootDrive to yield
  1721. // \server\IMirror\Clients\machine\BootDrive.
  1722. //
  1723. length = (ULONG)strlen(NetSetupServerShare) +
  1724. sizeof(CHAR) + // '\'
  1725. (ULONG)strlen(NetBootPath) +
  1726. sizeof("BootDrive"); // sizeof includes the \0
  1727. SetupBlock->MachineDirectoryPath = BlAllocateHeap( length );
  1728. if ( SetupBlock->MachineDirectoryPath == NULL ) {
  1729. SlNoMemoryError();
  1730. goto LoadFailed;
  1731. }
  1732. strcpy( SetupBlock->MachineDirectoryPath, NetSetupServerShare );
  1733. SetupBlock->MachineDirectoryPath[strlen(NetSetupServerShare)] = '\\';
  1734. SetupBlock->MachineDirectoryPath[strlen(NetSetupServerShare) + 1] = 0;
  1735. strcat(SetupBlock->MachineDirectoryPath, NetBootPath);
  1736. strcat(SetupBlock->MachineDirectoryPath, "BootDrive");
  1737. //
  1738. // Save the path to the SIF file so it can be deleted later.
  1739. //
  1740. if (((SetupBlock->Flags & (SETUPBLK_FLAGS_REMOTE_INSTALL|SETUPBLK_FLAGS_SYSPREP_INSTALL)) != 0) &&
  1741. (NetbootSifFile[0] != '\0')) {
  1742. length = (ULONG)strlen(NetSetupServerShare) +
  1743. sizeof(CHAR) + // '\'
  1744. (ULONG)strlen(NetbootSifFile) +
  1745. sizeof(CHAR); // '\0'
  1746. SetupBlock->NetBootSifPath = BlAllocateHeap( length );
  1747. if ( SetupBlock->NetBootSifPath == NULL ) {
  1748. SlNoMemoryError();
  1749. goto LoadFailed;
  1750. }
  1751. strcpy( SetupBlock->NetBootSifPath, NetSetupServerShare );
  1752. SetupBlock->NetBootSifPath[strlen(NetSetupServerShare)] = '\\';
  1753. SetupBlock->NetBootSifPath[strlen(NetSetupServerShare) + 1] = 0;
  1754. strcat(SetupBlock->NetBootSifPath, NetbootSifFile);
  1755. }
  1756. //
  1757. // NetSetupServerShare was read from winnt.sif and we replaced
  1758. // the '\' at the end with a NULL -- put this back for when
  1759. // winnt.sif is re-parsed by the kernel (the only modification
  1760. // that the kernel parser can really accept is replacing a
  1761. // final " with a NULL, which SlInitIniFile does).
  1762. //
  1763. NetSetupServerShare[strlen(NetSetupServerShare)] = '\\';
  1764. //
  1765. // Get the computer name from winnt.sif.
  1766. //
  1767. p = SlGetSectionKeyIndex(WinntSifHandle,WINNT_USERDATA_A,WINNT_US_COMPNAME_A,0);
  1768. if(!p || (*p == 0)) {
  1769. SlFatalError(SL_INF_ENTRY_MISSING,WINNT_US_COMPNAME,WINNT_USERDATA);
  1770. goto LoadFailed;
  1771. }
  1772. RtlInitString( &aString, p );
  1773. uString.Buffer = SetupBlock->ComputerName;
  1774. uString.MaximumLength = 64 * sizeof(WCHAR);
  1775. RtlAnsiStringToUnicodeString( &uString, &aString, FALSE );
  1776. //
  1777. // Save these from the global variables.
  1778. //
  1779. #ifdef EFI
  1780. //
  1781. // Convert these back to Network Order.
  1782. //
  1783. SetupBlock->IpAddress = RtlUlongByteSwap(NetLocalIpAddress);
  1784. SetupBlock->SubnetMask = RtlUlongByteSwap(NetLocalSubnetMask);
  1785. SetupBlock->DefaultRouter = RtlUlongByteSwap(NetGatewayIpAddress);
  1786. SetupBlock->ServerIpAddress = RtlUlongByteSwap(NetServerIpAddress);
  1787. #else
  1788. SetupBlock->IpAddress = NetLocalIpAddress;
  1789. SetupBlock->SubnetMask = NetLocalSubnetMask;
  1790. SetupBlock->DefaultRouter = NetGatewayIpAddress;
  1791. SetupBlock->ServerIpAddress = NetServerIpAddress;
  1792. #endif
  1793. //
  1794. // Get information about the net card and do an exchange with the
  1795. // server to get information we need to load it properly.
  1796. //
  1797. SetupBlock->NetbootCardInfo = BlAllocateHeap(sizeof(NET_CARD_INFO));
  1798. if ( SetupBlock->NetbootCardInfo == NULL ) {
  1799. SlNoMemoryError();
  1800. goto LoadFailed;
  1801. }
  1802. SetupBlock->NetbootCardInfoLength = sizeof(NET_CARD_INFO);
  1803. Status = NetQueryCardInfo(
  1804. (PNET_CARD_INFO)SetupBlock->NetbootCardInfo
  1805. );
  1806. if (Status != STATUS_SUCCESS) {
  1807. SlFatalError(SL_NETBOOT_CARD_ERROR);
  1808. goto LoadFailed;
  1809. }
  1810. //
  1811. // This call may allocate SetupBlock->NetbootCardRegistry
  1812. //
  1813. Status = NetQueryDriverInfo(
  1814. (PNET_CARD_INFO)SetupBlock->NetbootCardInfo,
  1815. NetSetupServerShare,
  1816. NULL,
  1817. SetupBlock->NetbootCardHardwareId,
  1818. sizeof(SetupBlock->NetbootCardHardwareId),
  1819. SetupBlock->NetbootCardDriverName,
  1820. NetbootCardDriverName,
  1821. sizeof(SetupBlock->NetbootCardDriverName),
  1822. SetupBlock->NetbootCardServiceName,
  1823. sizeof(SetupBlock->NetbootCardServiceName),
  1824. &SetupBlock->NetbootCardRegistry,
  1825. &SetupBlock->NetbootCardRegistryLength);
  1826. if (Status == STATUS_INSUFFICIENT_RESOURCES) {
  1827. SlNoMemoryError();
  1828. goto LoadFailed;
  1829. } else if (Status != STATUS_SUCCESS) {
  1830. SlFatalError(SL_NETBOOT_SERVER_ERROR);
  1831. goto LoadFailed;
  1832. }
  1833. #if 0
  1834. DbgPrint("HardwareID is <%ws>, DriverName is <%ws>, Service <%ws>\n",
  1835. SetupBlock->NetbootCardHardwareId,
  1836. SetupBlock->NetbootCardDriverName,
  1837. SetupBlock->NetbootCardServiceName);
  1838. DbgPrint("NetbootCardRegistry at %lx, length %d\n",
  1839. SetupBlock->NetbootCardRegistry,
  1840. SetupBlock->NetbootCardRegistryLength);
  1841. DbgBreakPoint();
  1842. #endif
  1843. #if defined(REMOTE_BOOT)
  1844. //
  1845. // See if we should enable remote boot security (IPSEC).
  1846. //
  1847. TempEnableIpsec = SlGetSectionKeyIndex(WinntSifHandle,
  1848. "RemoteBoot",
  1849. "EnableIpSecurity",
  1850. 0);
  1851. if ((TempEnableIpsec != NULL) &&
  1852. ((TempEnableIpsec[0] == 'Y') ||
  1853. (TempEnableIpsec[0] == 'y'))) {
  1854. RemoteBootEnableIpsec = TRUE;
  1855. }
  1856. if ((SetupBlock->Flags & (SETUPBLK_FLAGS_REMOTE_INSTALL |
  1857. SETUPBLK_FLAGS_SYSPREP_INSTALL)) == 0) {
  1858. ARC_STATUS ArcStatus;
  1859. ULONG FileId;
  1860. //
  1861. // Read the secret off the disk, if there is one, and store it
  1862. // in the loader block.
  1863. //
  1864. ArcStatus = BlOpenRawDisk(&FileId);
  1865. if (ArcStatus == ESUCCESS) {
  1866. SetupBlock->NetBootSecret = BlAllocateHeap(sizeof(RI_SECRET));
  1867. if (SetupBlock->NetBootSecret == NULL) {
  1868. SlNoMemoryError();
  1869. BlCloseRawDisk(FileId);
  1870. goto LoadFailed;
  1871. }
  1872. ArcStatus = BlReadSecret(FileId, (PRI_SECRET)(SetupBlock->NetBootSecret));
  1873. if (ArcStatus != ESUCCESS) {
  1874. SlNoMemoryError();
  1875. BlCloseRawDisk(FileId);
  1876. goto LoadFailed;
  1877. }
  1878. ArcStatus = BlCloseRawDisk(FileId);
  1879. //
  1880. // By now we have TFTPed some files so this will be TRUE if it
  1881. // is ever going to be.
  1882. //
  1883. SetupBlock->NetBootUsePassword2 = NetBootTftpUsedPassword2;
  1884. }
  1885. } else
  1886. #endif // defined(REMOTE_BOOT)
  1887. {
  1888. //
  1889. // Construct a secret to pass to the redirector, based on what
  1890. // was passed to use across the reboot. For the moment only
  1891. // user/domain/password matters.
  1892. //
  1893. WCHAR UnicodePassword[64];
  1894. UNICODE_STRING TmpNtPassword;
  1895. CHAR LmOwfPassword[LM_OWF_PASSWORD_SIZE];
  1896. CHAR NtOwfPassword[NT_OWF_PASSWORD_SIZE];
  1897. CHAR GarbageSid[RI_SECRET_SID_SIZE];
  1898. SetupBlock->NetBootSecret = BlAllocateHeap(sizeof(RI_SECRET));
  1899. if (SetupBlock->NetBootSecret == NULL) {
  1900. SlNoMemoryError();
  1901. goto LoadFailed;
  1902. }
  1903. //
  1904. // Do a quick conversion of the password to Unicode.
  1905. //
  1906. TmpNtPassword.Length = (USHORT)strlen(NetbootPassword) * sizeof(WCHAR);
  1907. TmpNtPassword.MaximumLength = sizeof(UnicodePassword);
  1908. TmpNtPassword.Buffer = UnicodePassword;
  1909. for (i = 0; i < sizeof(NetbootPassword); i++) {
  1910. UnicodePassword[i] = (WCHAR)(NetbootPassword[i]);
  1911. }
  1912. BlOwfPassword((PUCHAR) NetbootPassword,
  1913. &TmpNtPassword,
  1914. (PUCHAR) LmOwfPassword,
  1915. (PUCHAR) NtOwfPassword);
  1916. BlInitializeSecret(
  1917. (PUCHAR) NetbootDomain,
  1918. (PUCHAR) NetbootUser,
  1919. (PUCHAR) LmOwfPassword,
  1920. (PUCHAR) NtOwfPassword,
  1921. #if defined(REMOTE_BOOT)
  1922. NULL, // no password2
  1923. NULL, // no password2
  1924. #endif // defined(REMOTE_BOOT)
  1925. (PUCHAR) GarbageSid,
  1926. SetupBlock->NetBootSecret);
  1927. }
  1928. }
  1929. //
  1930. // Initialize the debugging system.
  1931. //
  1932. BlLogInitialize(BootDeviceId);
  1933. //
  1934. // Do PPC-specific initialization.
  1935. //
  1936. #if defined(_PPC_)
  1937. Status = BlPpcInitialize();
  1938. if (Status != ESUCCESS) {
  1939. goto LoadFailed;
  1940. }
  1941. #endif // defined(_PPC_)
  1942. //
  1943. // Check for an alternate Kernel Debugger DLL, i.e.,
  1944. // /debugport=1394 (kd1394.dll), /debugport=usb (kdusb.dll), etc...
  1945. //
  1946. FileName = NULL;
  1947. if (BlLoaderBlock->LoadOptions != NULL) {
  1948. FileName = strstr(BlLoaderBlock->LoadOptions, "DEBUGPORT=");
  1949. if (FileName == NULL) {
  1950. FileName = strstr(BlLoaderBlock->LoadOptions, "debugport=");
  1951. }
  1952. }
  1953. if (FileName != NULL) {
  1954. _strupr(FileName);
  1955. if (strstr(FileName, "COM") == NULL) {
  1956. UseAlternateKdDll = TRUE;
  1957. FileName += strlen("DEBUGPORT=");
  1958. for (i = 0; i < KD_ALT_DLL_REPLACE_CHARS; i++) {
  1959. if (FileName[i] == ' ') {
  1960. break;
  1961. }
  1962. KdFileName[KD_ALT_DLL_PREFIX_CHARS + i] = FileName[i];
  1963. }
  1964. KdFileName[KD_ALT_DLL_PREFIX_CHARS + i] = '\0';
  1965. strcat(KdFileName, ".DLL");
  1966. }
  1967. }
  1968. //
  1969. // If this is a preinstall case then add another
  1970. // OEM source device
  1971. //
  1972. if (PreInstall || WinPEBoot) {
  1973. PreInstallOemSourceDevice = BlAllocateHeap(sizeof(OEM_SOURCE_DEVICE));
  1974. PreInstallSourcePath = BlAllocateHeap(256);
  1975. if (PreInstallOemSourceDevice && PreInstallSourcePath) {
  1976. strcpy(PreInstallOemSourceDevice->ArcDeviceName,
  1977. BootDevice);
  1978. strcpy(PreInstallSourcePath, BootPath);
  1979. strcat(PreInstallSourcePath, WINNT_OEM_DIR_A);
  1980. PreInstallOemSourceDevice->DriverDir = PreInstallSourcePath;
  1981. SL_OEM_SET_SOURCE_DEVICE_TYPE(PreInstallOemSourceDevice,
  1982. (SL_OEM_SOURCE_DEVICE_TYPE_LOCAL |
  1983. SL_OEM_SOURCE_DEVICE_TYPE_FIXED |
  1984. SL_OEM_SOURCE_DEVICE_TYPE_PREINSTALL));
  1985. //
  1986. // Mark the device as containing preinstall drivers only if they
  1987. // specified any F6 mass storage drivers
  1988. //
  1989. if (!WinPEBoot && PreinstallDriverList) {
  1990. SL_OEM_SET_SOURCE_MEDIA_TYPE(PreInstallOemSourceDevice,
  1991. (SL_OEM_SOURCE_MEDIA_PRESENT |
  1992. SL_OEM_SOURCE_MEDIA_HAS_DRIVERS |
  1993. SL_OEM_SOURCE_MEDIA_HAS_MSD |
  1994. SL_OEM_SOURCE_MEDIA_HAS_DEFAULT));
  1995. }
  1996. SL_OEM_SET_SOURCE_DEVICE_STATE(PreInstallOemSourceDevice,
  1997. SL_OEM_SOURCE_DEVICE_NOT_PROCESSED);
  1998. PreInstallOemSourceDevice->DeviceId = BootDeviceId;
  1999. //
  2000. // Insert it at the head of the linked list
  2001. //
  2002. PreInstallOemSourceDevice->Next = OemSourceDevices;
  2003. OemSourceDevices = PreInstallOemSourceDevice;
  2004. } else {
  2005. SlNoMemoryError();
  2006. goto LoadFailed;
  2007. }
  2008. }
  2009. if (!BlBootingFromNet) {
  2010. //
  2011. // Figure out if there are any OEM hal/drivers which need to
  2012. // be autoloaded.
  2013. // NOTE: We skip the dynamic update OEM source device since it's
  2014. // drivers will be autoloaded later.
  2015. //
  2016. POEM_SOURCE_DEVICE CurrDevice = OemSourceDevices;
  2017. while (CurrDevice && !(AutoLoadOemHalDevice && AutoLoadOemScsi)) {
  2018. if ((SL_OEM_SOURCE_MEDIA_TYPE(CurrDevice,
  2019. SL_OEM_SOURCE_MEDIA_HAS_DRIVERS) &&
  2020. SL_OEM_SOURCE_MEDIA_TYPE(CurrDevice,
  2021. SL_OEM_SOURCE_MEDIA_HAS_DEFAULT)) &&
  2022. !SL_OEM_SOURCE_DEVICE_TYPE(CurrDevice,
  2023. SL_OEM_SOURCE_DEVICE_TYPE_DYN_UPDATE)) {
  2024. if (!AutoLoadOemHalDevice &&
  2025. SL_OEM_SOURCE_MEDIA_TYPE(CurrDevice, SL_OEM_SOURCE_MEDIA_HAS_HAL)) {
  2026. AutoLoadOemHalDevice = CurrDevice;
  2027. }
  2028. if (!AutoLoadOemScsi &&
  2029. SL_OEM_SOURCE_MEDIA_TYPE(CurrDevice, SL_OEM_SOURCE_MEDIA_HAS_MSD)) {
  2030. AutoLoadOemScsi = TRUE;
  2031. }
  2032. }
  2033. CurrDevice = CurrDevice->Next;
  2034. }
  2035. //
  2036. // Set allocatable range to the kernel-specific range
  2037. //
  2038. BlUsableBase = BL_KERNEL_RANGE_LOW;
  2039. BlUsableLimit = BL_KERNEL_RANGE_HIGH;
  2040. //
  2041. // Load the kernel.
  2042. //
  2043. SlGetDisk(KERNEL_MP_IMAGE_FILENAME);
  2044. strcpy(KernelDirectoryPath, BootPath);
  2045. strcat(KernelDirectoryPath, KERNEL_MP_IMAGE_FILENAME);
  2046. //
  2047. // If AMD64 long mode is detected, the following call will set the
  2048. // global BlAmd64UseLongMode to TRUE.
  2049. //
  2050. #if defined(_X86_)
  2051. BlAmd64CheckForLongMode(BootDeviceId, KernelDirectoryPath, "");
  2052. #endif
  2053. strcpy(KernelImage, KERNEL_MP_IMAGE_FILENAME);
  2054. #ifdef i386
  2055. retrykernel:
  2056. #endif
  2057. BlOutputLoadMessage(BootDevice, KernelDirectoryPath, BlFindMessage(SL_KERNEL_NAME));
  2058. Status = BlLoadImage(BootDeviceId,
  2059. LoaderSystemCode,
  2060. KernelDirectoryPath,
  2061. TARGET_IMAGE,
  2062. &SystemBase);
  2063. //
  2064. // If the kernel didn't fit in the preferred range, reset the range to
  2065. // all of memory and try again.
  2066. //
  2067. #ifdef i386
  2068. if ((Status == ENOMEM) &&
  2069. ((BlUsableBase != 0) ||
  2070. (BlUsableLimit != _16MB))) {
  2071. BlUsableBase = 0;
  2072. BlUsableLimit = _16MB;
  2073. goto retrykernel;
  2074. }
  2075. #endif
  2076. if (Status != ESUCCESS) {
  2077. SlFatalError(SL_FILE_LOAD_FAILED,
  2078. SlCopyStringAT(KernelDirectoryPath),
  2079. Status);
  2080. goto LoadFailed;
  2081. }
  2082. BlUpdateBootStatus();
  2083. //
  2084. // Load the HAL.
  2085. //
  2086. strcpy(HalDirectoryPath, BootPath);
  2087. if (PromptOemHal || (PreInstall && (ComputerType != NULL))) {
  2088. if(PreInstall && OemHal) {
  2089. //
  2090. // This is a pre-install and an OEM hal was specified
  2091. //
  2092. strcat( HalDirectoryPath,
  2093. #if defined(_X86_) || defined(_IA64_)
  2094. WINNT_OEM_DIR_A
  2095. #else
  2096. WINNT_OEM_TEXTMODE_DIR_A
  2097. #endif
  2098. );
  2099. strcat( HalDirectoryPath, "\\" );
  2100. }
  2101. SlPromptOemHal((PreInstall ? PreInstallOemSourceDevice : DefaultOemSourceDevice),
  2102. (BOOLEAN) (!PreInstall || (ComputerType == NULL)),
  2103. &HalBase,
  2104. &HalName);
  2105. strcat(HalDirectoryPath,HalName);
  2106. //
  2107. // Reset the last disk tag for floopy boot
  2108. //
  2109. if (FloppyBoot) {
  2110. LastDiskTag = NULL;
  2111. }
  2112. } else {
  2113. if (AutoLoadOemHalDevice) {
  2114. SlPromptOemHal(AutoLoadOemHalDevice,
  2115. FALSE,
  2116. &HalBase,
  2117. &HalName);
  2118. } else {
  2119. //
  2120. // Note that on x86, the HAL may be on floppy #1 or floppy #2
  2121. //
  2122. strcat(HalDirectoryPath,HalName);
  2123. SlGetDisk(HalName);
  2124. BlOutputLoadMessage(BootDevice, HalDirectoryPath, BlFindMessage(SL_HAL_NAME));
  2125. #ifdef i386
  2126. retryhal:
  2127. #endif
  2128. Status = BlLoadImage(BootDeviceId,
  2129. LoaderHalCode,
  2130. HalDirectoryPath,
  2131. TARGET_IMAGE,
  2132. &HalBase);
  2133. #ifdef i386
  2134. //
  2135. // If the HAL didn't fit in the preferred range, reset the range to
  2136. // all of memory and try again.
  2137. //
  2138. if ((Status == ENOMEM) &&
  2139. ((BlUsableBase != 0) ||
  2140. (BlUsableLimit != _16MB))) {
  2141. BlUsableBase = 0;
  2142. BlUsableLimit = _16MB;
  2143. goto retryhal;
  2144. }
  2145. #endif
  2146. if (Status != ESUCCESS) {
  2147. SlFatalError(SL_FILE_LOAD_FAILED,
  2148. SlCopyStringAT(HalDirectoryPath),
  2149. Status);
  2150. goto LoadFailed;
  2151. }
  2152. }
  2153. BlUpdateBootStatus();
  2154. }
  2155. //
  2156. // Set allocatable range to the driver-specific range
  2157. //
  2158. BlUsableBase = BL_DRIVER_RANGE_LOW;
  2159. BlUsableLimit = BL_DRIVER_RANGE_HIGH;
  2160. } else {
  2161. #if !defined(_IA64_)
  2162. //
  2163. // don't need these variables for ia64
  2164. //
  2165. PCHAR id;
  2166. ULONG idLength;
  2167. #endif
  2168. //
  2169. // This is a remote boot setup. Load the HAL first, so that we
  2170. // can determine whether to load the UP or MP kernel.
  2171. //
  2172. // Note that we cannot load the HAL first on local boots
  2173. // because that would break floppy boot, where the kernel
  2174. // is on floppy #1 and the HALs are on floppy #2.
  2175. //
  2176. //
  2177. // Set allocatable range to the kernel-specific range
  2178. //
  2179. BlUsableBase = BL_KERNEL_RANGE_LOW;
  2180. BlUsableLimit = BL_KERNEL_RANGE_HIGH;
  2181. #if defined(_IA64_)
  2182. //
  2183. // ===============
  2184. // Load the kernel for IA64 systems.
  2185. //
  2186. // On IA64, load the kernel first, then hal. This helps ensure
  2187. // the kernel will go at 48Mb.
  2188. // ===============
  2189. //
  2190. strcpy( KernelImage, KERNEL_MP_IMAGE_FILENAME );
  2191. SlGetDisk(KernelImage);
  2192. strcpy(KernelDirectoryPath, BootPath);
  2193. strcat(KernelDirectoryPath,KernelImage);
  2194. BlOutputLoadMessage(BootDevice, KernelDirectoryPath, BlFindMessage(SL_KERNEL_NAME));
  2195. Status = BlLoadImage(BootDeviceId,
  2196. LoaderSystemCode,
  2197. KernelDirectoryPath,
  2198. TARGET_IMAGE,
  2199. &SystemBase);
  2200. if (Status != ESUCCESS) {
  2201. SlFatalError(SL_FILE_LOAD_FAILED,SlCopyStringAT(KernelDirectoryPath),Status);
  2202. goto LoadFailed;
  2203. }
  2204. BlUpdateBootStatus();
  2205. #endif
  2206. //
  2207. // ===============
  2208. // Load the hal.
  2209. // ===============
  2210. //
  2211. strcpy(HalDirectoryPath, BootPath);
  2212. if (PromptOemHal || (PreInstall && (ComputerType != NULL))) {
  2213. if(PreInstall && OemHal) {
  2214. //
  2215. // This is a pre-install and an OEM hal was specified
  2216. //
  2217. strcat( HalDirectoryPath,
  2218. #if defined(_X86_) || defined(_IA64_)
  2219. WINNT_OEM_DIR_A
  2220. #else
  2221. WINNT_OEM_TEXTMODE_DIR_A
  2222. #endif
  2223. );
  2224. strcat( HalDirectoryPath, "\\" );
  2225. }
  2226. SlPromptOemHal((PreInstall ? PreInstallOemSourceDevice : DefaultOemSourceDevice),
  2227. (BOOLEAN) (!PreInstall || (ComputerType == NULL)),
  2228. &HalBase,
  2229. &HalName);
  2230. strcat(HalDirectoryPath,HalName);
  2231. //
  2232. // Reset the last disk tag for floopy boot
  2233. //
  2234. if (FloppyBoot) {
  2235. LastDiskTag = NULL;
  2236. }
  2237. } else {
  2238. strcat(HalDirectoryPath,HalName);
  2239. BlOutputLoadMessage(BootDevice, HalDirectoryPath, BlFindMessage(SL_HAL_NAME));
  2240. #ifdef i386
  2241. netbootretryhal:
  2242. #endif
  2243. Status = BlLoadImage(BootDeviceId,
  2244. LoaderHalCode,
  2245. HalDirectoryPath,
  2246. TARGET_IMAGE,
  2247. &HalBase);
  2248. #ifdef i386
  2249. //
  2250. // If the HAL didn't fit in the preferred range, reset the range to
  2251. // all of memory and try again.
  2252. //
  2253. if ((Status == ENOMEM) &&
  2254. ((BlUsableBase != 0) ||
  2255. (BlUsableLimit != _16MB))) {
  2256. BlUsableBase = 0;
  2257. BlUsableLimit = _16MB;
  2258. goto netbootretryhal;
  2259. }
  2260. #endif
  2261. if (Status != ESUCCESS) {
  2262. SlFatalError(SL_FILE_LOAD_FAILED,SlCopyStringAT(HalDirectoryPath),Status);
  2263. goto LoadFailed;
  2264. }
  2265. BlUpdateBootStatus();
  2266. }
  2267. #if !defined(_IA64_)
  2268. //
  2269. // ===============
  2270. // Load the kernel for non-IA64 systems.
  2271. //
  2272. // Load the kernel, loading ntoskrnl.exe or ntkrnlmp.exe based on
  2273. // whether the HAL is UP or MP. This is important for remote boot
  2274. // because the networking code's spin lock usage pattern requires
  2275. // the kernel and HAL to be matched.
  2276. //
  2277. // If the computer ID string ends in "_mp", load the MP kernel.
  2278. // Otherwise, load the UP kernel. The code is modeled after similar
  2279. // code in setup\textmode\kernel\sphw.c\SpInstallingMp().
  2280. //
  2281. // ===============
  2282. //
  2283. id = SetupBlock->ComputerDevice.IdString;
  2284. idLength = strlen(id);
  2285. //
  2286. // load ntkrnlmp always in MiniNT network boot
  2287. //
  2288. if (WinPEBoot || ((idLength >= 3) && (_stricmp(id+idLength-3,"_mp") == 0))) {
  2289. strcpy(KernelImage,KERNEL_MP_IMAGE_FILENAME);
  2290. } else {
  2291. strcpy(KernelImage,KERNEL_UP_IMAGE_FILENAME);
  2292. }
  2293. #if defined(REMOTE_BOOT)
  2294. #if DBG
  2295. if ((strlen(id) + 1) > sizeof(SetupBlock->NetBootHalName)) {
  2296. DbgPrint("The KERNEL name is too long!\n");
  2297. goto LoadFailed;
  2298. }
  2299. #endif
  2300. strcpy(SetupBlock->NetBootHalName, id);
  2301. #endif // defined(REMOTE_BOOT)
  2302. SlGetDisk(KernelImage);
  2303. strcpy(KernelDirectoryPath, BootPath);
  2304. strcat(KernelDirectoryPath,KernelImage);
  2305. BlOutputLoadMessage(BootDevice, KernelDirectoryPath, BlFindMessage(SL_KERNEL_NAME));
  2306. #ifdef i386
  2307. netbootretrykernel:
  2308. #endif
  2309. Status = BlLoadImage(BootDeviceId,
  2310. LoaderSystemCode,
  2311. KernelDirectoryPath,
  2312. TARGET_IMAGE,
  2313. &SystemBase);
  2314. if (Status != ESUCCESS) {
  2315. #ifdef i386
  2316. //
  2317. // If the kernel didn't fit in the preferred range, reset the range to
  2318. // all of memory and try again.
  2319. //
  2320. if (Status == ENOMEM) {
  2321. if (BlUsableBase == BL_KERNEL_RANGE_LOW &&
  2322. BlUsableLimit == BL_KERNEL_RANGE_HIGH) {
  2323. //
  2324. // first we try all of memory below 16MB
  2325. //
  2326. BlUsableBase = 0;
  2327. BlUsableLimit = _16MB;
  2328. goto netbootretrykernel;
  2329. } else if (BlUsableBase == 0 &&
  2330. BlUsableLimit == _16MB) {
  2331. //
  2332. // then we try all of memory above 16MB
  2333. //
  2334. BlUsableBase = _16MB;
  2335. BlUsableLimit = BL_DRIVER_RANGE_HIGH;
  2336. goto netbootretrykernel;
  2337. }
  2338. }
  2339. #endif
  2340. SlFatalError(SL_FILE_LOAD_FAILED,SlCopyStringAT(KernelDirectoryPath),Status);
  2341. goto LoadFailed;
  2342. }
  2343. BlUpdateBootStatus();
  2344. #endif // if !defined(_IA64_)
  2345. //
  2346. // Set allocatable range to the driver-specific range
  2347. //
  2348. BlUsableBase = BL_DRIVER_RANGE_LOW;
  2349. BlUsableLimit = BL_DRIVER_RANGE_HIGH;
  2350. }
  2351. //
  2352. // Load Kernel Debugger DLL
  2353. //
  2354. strcpy(KdDllName, BootPath);
  2355. strcat(KdDllName, KdFileName);
  2356. SlGetDisk(KdFileName);
  2357. BlOutputLoadMessage(BootDevice, KdDllName, BlFindMessage(SL_KDDLL_NAME));
  2358. Status = BlLoadImage(BootDeviceId,
  2359. LoaderHalCode,
  2360. KdDllName,
  2361. TARGET_IMAGE,
  2362. &KdDllBase);
  2363. if ((Status != ESUCCESS) && (UseAlternateKdDll == TRUE)) {
  2364. UseAlternateKdDll = FALSE;
  2365. strcpy(KdDllName, BootPath);
  2366. strcpy(KdFileName, "KDCOM.DLL");
  2367. strcat(KdDllName, KdFileName);
  2368. Status = BlLoadImage(BootDeviceId,
  2369. LoaderHalCode,
  2370. KdDllName,
  2371. TARGET_IMAGE,
  2372. &KdDllBase);
  2373. }
  2374. if (Status != ESUCCESS) {
  2375. SlFatalError(SL_FILE_LOAD_FAILED, SlCopyStringAT(KdDllName), Status);
  2376. goto LoadFailed;
  2377. }
  2378. //
  2379. // Generate a loader data entry for the system image.
  2380. //
  2381. Status = BlAllocateDataTableEntry("ntoskrnl.exe",
  2382. KernelDirectoryPath,
  2383. SystemBase,
  2384. &SystemDataTableEntry);
  2385. if (Status != ESUCCESS) {
  2386. SlFatalError(SL_FILE_LOAD_FAILED,SlCopyStringAT(KernelDirectoryPath),Status);
  2387. goto LoadFailed;
  2388. }
  2389. //
  2390. // Generate a loader data entry for the HAL DLL.
  2391. //
  2392. Status = BlAllocateDataTableEntry("hal.dll",
  2393. HalDirectoryPath,
  2394. HalBase,
  2395. &HalDataTableEntry);
  2396. if (Status != ESUCCESS) {
  2397. SlFatalError(SL_FILE_LOAD_FAILED,SlCopyStringAT(HalDirectoryPath),Status);
  2398. goto LoadFailed;
  2399. }
  2400. //
  2401. // Generate a loader data entry for the Kernel Debugger DLL.
  2402. //
  2403. Status = BlAllocateDataTableEntry("kdcom.dll",
  2404. KdDllName,
  2405. KdDllBase,
  2406. &KdDataTableEntry);
  2407. if (Status != ESUCCESS) {
  2408. SlFatalError(SL_FILE_LOAD_FAILED, SlCopyStringAT(KdDllName), Status);
  2409. goto LoadFailed;
  2410. }
  2411. PathSet.PathCount = 1;
  2412. PathSet.AliasName = "\\SystemRoot";
  2413. PathSet.PathOffset[0] = '\0';
  2414. PathSet.Source[0].DeviceId = BootDeviceId;
  2415. PathSet.Source[0].DeviceName = BootDevice;
  2416. PathSet.Source[0].DirectoryPath = BootPath;
  2417. Status = BlScanImportDescriptorTable(&PathSet,
  2418. SystemDataTableEntry,
  2419. LoaderSystemCode
  2420. );
  2421. if (Status != ESUCCESS) {
  2422. SlFatalError(SL_FILE_LOAD_FAILED,SlCopyStringAT(KernelImage),Status);
  2423. }
  2424. //
  2425. // Scan the import table for the HAL DLL and load all referenced DLLs.
  2426. //
  2427. Status = BlScanImportDescriptorTable(&PathSet,
  2428. HalDataTableEntry,
  2429. LoaderHalCode);
  2430. if (Status != ESUCCESS) {
  2431. SlFatalError(SL_FILE_LOAD_FAILED,SlCopyStringAT("hal.dll"),Status);
  2432. goto LoadFailed;
  2433. }
  2434. //
  2435. // Scan the import table for the Kernel Debugger DLL and load all
  2436. // referenced DLLs.
  2437. //
  2438. Status = BlScanImportDescriptorTable(&PathSet,
  2439. KdDataTableEntry,
  2440. LoaderSystemCode);
  2441. if (Status != ESUCCESS) {
  2442. SlFatalError(SL_FILE_LOAD_FAILED, SlCopyStringAT(KdFileName), Status);
  2443. goto LoadFailed;
  2444. }
  2445. //
  2446. // Relocate the system entry point and set system specific information.
  2447. //
  2448. NtHeaders = RtlImageNtHeader(SystemBase);
  2449. SystemEntry = (PTRANSFER_ROUTINE)((ULONG_PTR)SystemBase +
  2450. NtHeaders->OptionalHeader.AddressOfEntryPoint);
  2451. #if defined(_IA64_)
  2452. BlLoaderBlock->u.Ia64.KernelVirtualBase = (ULONG_PTR)SystemBase;
  2453. BlLoaderBlock->u.Ia64.KernelPhysicalBase = (ULONG_PTR)SystemBase & 0x7fffffff;
  2454. #endif
  2455. ///////////////////////////////////////////////////////////////////
  2456. //
  2457. // On x86, the files loaded from now on are on boot floppy #2
  2458. //
  2459. ///////////////////////////////////////////////////////////////////
  2460. //
  2461. // Load registry's SYSTEM hive
  2462. //
  2463. SlGetDisk("SETUPREG.HIV");
  2464. Status = BlLoadSystemHive(BootDeviceId,
  2465. NULL, // BlFindMessage(SL_HIVE_NAME), UNREFERENCED_PARAMETER
  2466. BootPath,
  2467. "SETUPREG.HIV");
  2468. if (Status != ESUCCESS) {
  2469. SlFatalError(SL_FILE_LOAD_FAILED,SlCopyStringAT("SETUPREG.HIV"),Status);
  2470. goto LoadFailed;
  2471. }
  2472. //
  2473. // Pull the Docking information from the hardware tree.
  2474. //
  2475. dockInfoData = KeFindConfigurationEntry(BlLoaderBlock->ConfigurationRoot,
  2476. PeripheralClass,
  2477. DockingInformation,
  2478. NULL);
  2479. if (NULL == dockInfoData) {
  2480. BlLoaderBlock->Extension->Profile.Status = HW_PROFILE_STATUS_SUCCESS;
  2481. BlLoaderBlock->Extension->Profile.DockingState = HW_PROFILE_DOCKSTATE_UNKNOWN;
  2482. BlLoaderBlock->Extension->Profile.Capabilities = 0;
  2483. BlLoaderBlock->Extension->Profile.DockID = 0;
  2484. BlLoaderBlock->Extension->Profile.SerialNumber = 0;
  2485. } else if (sizeof (dockInfo) <=
  2486. dockInfoData->ComponentEntry.ConfigurationDataLength) {
  2487. RtlCopyMemory (
  2488. &dockInfo,
  2489. (PUCHAR) (dockInfoData->ConfigurationData) + sizeof(CM_PARTIAL_RESOURCE_LIST),
  2490. sizeof (dockInfo));
  2491. BlLoaderBlock->Extension->Profile.Status = HW_PROFILE_STATUS_FAILURE;
  2492. switch (dockInfo.ReturnCode) {
  2493. case FW_DOCKINFO_SUCCESS:
  2494. BlLoaderBlock->Extension->Profile.Status = HW_PROFILE_STATUS_SUCCESS;
  2495. BlLoaderBlock->Extension->Profile.DockingState = HW_PROFILE_DOCKSTATE_DOCKED;
  2496. BlLoaderBlock->Extension->Profile.Capabilities = dockInfo.Capabilities;
  2497. BlLoaderBlock->Extension->Profile.DockID = dockInfo.DockID;
  2498. BlLoaderBlock->Extension->Profile.SerialNumber = dockInfo.SerialNumber;
  2499. break;
  2500. case FW_DOCKINFO_SYSTEM_NOT_DOCKED:
  2501. BlLoaderBlock->Extension->Profile.Status = HW_PROFILE_STATUS_SUCCESS;
  2502. BlLoaderBlock->Extension->Profile.DockingState = HW_PROFILE_DOCKSTATE_UNDOCKED;
  2503. BlLoaderBlock->Extension->Profile.Capabilities = dockInfo.Capabilities;
  2504. BlLoaderBlock->Extension->Profile.DockID = dockInfo.DockID;
  2505. BlLoaderBlock->Extension->Profile.SerialNumber = dockInfo.SerialNumber;
  2506. break;
  2507. case FW_DOCKINFO_DOCK_STATE_UNKNOWN:
  2508. BlLoaderBlock->Extension->Profile.Status = HW_PROFILE_STATUS_SUCCESS;
  2509. BlLoaderBlock->Extension->Profile.DockingState = HW_PROFILE_DOCKSTATE_UNKNOWN;
  2510. BlLoaderBlock->Extension->Profile.Capabilities = dockInfo.Capabilities;
  2511. BlLoaderBlock->Extension->Profile.DockID = dockInfo.DockID;
  2512. BlLoaderBlock->Extension->Profile.SerialNumber = dockInfo.SerialNumber;
  2513. break;
  2514. case FW_DOCKINFO_FUNCTION_NOT_SUPPORTED:
  2515. case FW_DOCKINFO_BIOS_NOT_CALLED:
  2516. BlLoaderBlock->Extension->Profile.Status = HW_PROFILE_STATUS_SUCCESS;
  2517. default:
  2518. BlLoaderBlock->Extension->Profile.DockingState = HW_PROFILE_DOCKSTATE_UNSUPPORTED;
  2519. BlLoaderBlock->Extension->Profile.Capabilities = dockInfo.Capabilities;
  2520. BlLoaderBlock->Extension->Profile.DockID = dockInfo.DockID;
  2521. BlLoaderBlock->Extension->Profile.SerialNumber = dockInfo.SerialNumber;
  2522. break;
  2523. }
  2524. } else {
  2525. BlLoaderBlock->Extension->Profile.Status = HW_PROFILE_STATUS_SUCCESS;
  2526. BlLoaderBlock->Extension->Profile.Capabilities = 0;
  2527. BlLoaderBlock->Extension->Profile.DockID = 0;
  2528. BlLoaderBlock->Extension->Profile.SerialNumber = 0;
  2529. }
  2530. if (BlLoaderBlock->Extension->Profile.Status == HW_PROFILE_STATUS_SUCCESS) {
  2531. //
  2532. // We don't match profiles in textmode setup so just pretend that we did.
  2533. //
  2534. BlLoaderBlock->Extension->Profile.Status = HW_PROFILE_STATUS_TRUE_MATCH;
  2535. }
  2536. //
  2537. // Allocate structure for NLS data.
  2538. //
  2539. BlLoaderBlock->NlsData = BlAllocateHeap(sizeof(NLS_DATA_BLOCK));
  2540. if (BlLoaderBlock->NlsData == NULL) {
  2541. Status = ENOMEM;
  2542. SlNoMemoryError();
  2543. goto LoadFailed;
  2544. }
  2545. //
  2546. // Load the OEM font
  2547. //
  2548. SlGetDisk(OemHalFontName);
  2549. Status = BlLoadOemHalFont(BootDeviceId,
  2550. NULL, // BlFindMessage(SL_OEM_FONT_NAME), UNREFERENCED_PARAMETER
  2551. BootPath,
  2552. &OemHalFont,
  2553. BadFileName);
  2554. if(Status != ESUCCESS) {
  2555. SlFatalError(SL_FILE_LOAD_FAILED, SlCopyStringAT(BadFileName), Status);
  2556. goto LoadFailed;
  2557. }
  2558. //
  2559. // Load the NLS data.
  2560. //
  2561. // For now, we ensure that the disk containing the ansi
  2562. // codepage file is in the drive and hope that the rest of the
  2563. // nls files (oem codepage, unicode table) are on the same disk.
  2564. //
  2565. SlGetDisk(AnsiCpName);
  2566. Status = BlLoadNLSData(BootDeviceId,
  2567. NULL, // BlFindMessage(SL_NLS_NAME), UNREFERENCED_PARAMETER
  2568. BootPath,
  2569. &AnsiCodepage,
  2570. &OemCodepage,
  2571. &UnicodeCaseTable,
  2572. BadFileName);
  2573. if(Status != ESUCCESS) {
  2574. SlFatalError(SL_FILE_LOAD_FAILED, SlCopyStringAT(BadFileName), Status);
  2575. goto LoadFailed;
  2576. }
  2577. //
  2578. // Load the system drivers we will need here
  2579. //
  2580. InitializeListHead(&BlLoaderBlock->BootDriverListHead);
  2581. //
  2582. // Load setupdd.sys next. Setupdd.sys needs to be loaded before any other
  2583. // driver, because it will need to prep the rest of the system.
  2584. //
  2585. Status = SlLoadDriver(BlFindMessage(SL_SETUP_NAME),
  2586. "setupdd.sys",
  2587. 0,
  2588. TRUE,
  2589. FALSE,
  2590. NULL
  2591. );
  2592. if (Status != ESUCCESS) {
  2593. SlFatalError(SL_FILE_LOAD_FAILED,SlCopyStringAT("setupdd.sys"),Status);
  2594. goto LoadFailed;
  2595. }
  2596. //
  2597. // Fill in its registry key -- setupdd fills these in for all the other
  2598. // drivers (unless we do it here), but we have to do it here for setupdd
  2599. // itself.
  2600. //
  2601. DriverEntry = (PBOOT_DRIVER_LIST_ENTRY)(BlLoaderBlock->BootDriverListHead.Flink);
  2602. DriverEntry->RegistryPath.Buffer = BlAllocateHeap(256);
  2603. if (DriverEntry->RegistryPath.Buffer == NULL) {
  2604. SlNoMemoryError();
  2605. goto LoadFailed;
  2606. }
  2607. DriverEntry->RegistryPath.Length = 0;
  2608. DriverEntry->RegistryPath.MaximumLength = 256;
  2609. RtlAppendUnicodeToString(&DriverEntry->RegistryPath,
  2610. L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\setupdd");
  2611. #if 0
  2612. #ifdef i386
  2613. //
  2614. // Note that if pciide.sys, intelide.sys and pciidex.sys are on the same
  2615. // boot floppy (x86 only), then we don't need to load pciidex.sys.
  2616. // The driver will be automatically loaded when pciide.sys or intelide.sys
  2617. // (both listed on [BusExtenders.Load] is loaded.
  2618. //
  2619. Status = SlLoadDriver(BlFindMessage(SL_PCI_IDE_EXTENSIONS_NAME),
  2620. "PCIIDEX.SYS",
  2621. 0,
  2622. FALSE,
  2623. FALSE,
  2624. NULL
  2625. );
  2626. #endif
  2627. #endif
  2628. //
  2629. // Load boot bus extenders.
  2630. // It has to be done before scsiport.sys
  2631. //
  2632. Status = SlLoadPnpDriversSection( InfFile,
  2633. "BootBusExtenders",
  2634. &(SetupBlock->BootBusExtenders) );
  2635. if (Status!=ESUCCESS) {
  2636. goto LoadFailed;
  2637. }
  2638. //
  2639. // Load bus extenders.
  2640. // It has to be done before scsiport.sys
  2641. //
  2642. Status = SlLoadPnpDriversSection( InfFile,
  2643. "BusExtenders",
  2644. &(SetupBlock->BusExtenders) );
  2645. if (Status!=ESUCCESS) {
  2646. goto LoadFailed;
  2647. }
  2648. //
  2649. // Load input device related drivers.
  2650. //
  2651. Status = SlLoadPnpDriversSection( InfFile,
  2652. "InputDevicesSupport",
  2653. &(SetupBlock->InputDevicesSupport) );
  2654. if (Status!=ESUCCESS) {
  2655. goto LoadFailed;
  2656. }
  2657. //
  2658. // Detect video
  2659. //
  2660. SlDetectVideo(SetupBlock);
  2661. //
  2662. // On x86, the video type is always set to VGA in i386\x86dtect.c.
  2663. // On non-x86, the video type is either recognized, in which case
  2664. // we don't unconditionally need vga.sys (the Display.Load section
  2665. // tells us what to load), or it's not recognized,
  2666. // in which case we will prompt the user for an oem disk.
  2667. // If there is no display controller node at all, then PromptOemDisk
  2668. // will be false and there will be no video device. In this case
  2669. // we load vga.sys.
  2670. //
  2671. if (SetupBlock->VideoDevice.IdString != NULL) {
  2672. VideoFileName = SlGetSectionKeyIndex(InfFile,
  2673. "Display.Load",
  2674. SetupBlock->VideoDevice.IdString,
  2675. SIF_FILENAME_INDEX);
  2676. if (VideoFileName != NULL) {
  2677. #ifdef ARCI386
  2678. VideoDescription = SlGetIniValue(InfFile,
  2679. "Display",
  2680. SetupBlock->VideoDevice.IdString,
  2681. BlFindMessage(SL_VIDEO_NAME));
  2682. #else
  2683. //
  2684. // With the new video detection mechanism, the description
  2685. // for the video driver is likely to be something like
  2686. // "Windows NT Compatible" which looks funny when displayed
  2687. // in the status bar.
  2688. //
  2689. VideoDescription = BlFindMessage(SL_VIDEO_NAME);
  2690. #endif
  2691. if (!WinPEBoot) {
  2692. Status = SlLoadDriver(VideoDescription,
  2693. VideoFileName,
  2694. 0,
  2695. TRUE,
  2696. FALSE,
  2697. NULL
  2698. );
  2699. }
  2700. if (Status == ESUCCESS) {
  2701. SetupBlock->VideoDevice.BaseDllName = SlCopyStringA(VideoFileName);
  2702. } else {
  2703. SlFriendlyError(
  2704. Status,
  2705. VideoFileName,
  2706. __LINE__,
  2707. __FILE__
  2708. );
  2709. goto LoadFailed;
  2710. }
  2711. LoadedAVideoDriver = TRUE;
  2712. }
  2713. } else if (PromptOemVideo) {
  2714. SlPromptOemVideo(DefaultOemSourceDevice,
  2715. TRUE,
  2716. &VideoBase,
  2717. &OemVideoName);
  2718. Status = SlLoadOemDriver(
  2719. "VIDEOPRT.SYS",
  2720. OemVideoName,
  2721. VideoBase,
  2722. BlFindMessage(SL_VIDEO_NAME)
  2723. );
  2724. if(Status==ESUCCESS) {
  2725. LoadedAVideoDriver = TRUE;
  2726. SetupBlock->VideoDevice.BaseDllName = SlCopyStringA(OemVideoName);
  2727. }
  2728. //
  2729. // Reset the last disk tag for floopy boot
  2730. //
  2731. if (FloppyBoot) {
  2732. LastDiskTag = NULL;
  2733. }
  2734. }
  2735. if(!LoadedAVideoDriver) {
  2736. Status = SlLoadDriver(BlFindMessage(SL_VIDEO_NAME),
  2737. VGA_DRIVER_FILENAME,
  2738. 0,
  2739. TRUE,
  2740. FALSE,
  2741. NULL
  2742. );
  2743. if(Status == ESUCCESS) {
  2744. SetupBlock->VideoDevice.BaseDllName = SlCopyStringA(VGA_DRIVER_FILENAME);
  2745. } else {
  2746. SlFriendlyError(
  2747. Status,
  2748. VGA_DRIVER_FILENAME,
  2749. __LINE__,
  2750. __FILE__
  2751. );
  2752. goto LoadFailed;
  2753. }
  2754. }
  2755. if(SetupBlock->VideoDevice.IdString == NULL) {
  2756. SetupBlock->VideoDevice.IdString = SlCopyStringA(VIDEO_DEVICE_NAME);
  2757. }
  2758. //
  2759. // Load keyboard drivers.
  2760. //
  2761. Status = SlLoadPnpDriversSection( InfFile,
  2762. "Keyboard",
  2763. &(SetupBlock->KeyboardDevices) );
  2764. if (Status!=ESUCCESS) {
  2765. goto LoadFailed;
  2766. }
  2767. Status = SlLoadDriver(BlFindMessage(SL_KBD_NAME),
  2768. "kbdclass.sys",
  2769. 0,
  2770. TRUE,
  2771. FALSE,
  2772. NULL
  2773. );
  2774. if(Status != ESUCCESS) {
  2775. SlFriendlyError(
  2776. Status,
  2777. "kbdclass.sys",
  2778. __LINE__,
  2779. __FILE__
  2780. );
  2781. goto LoadFailed;
  2782. }
  2783. //
  2784. // We would need mouse support also in minint environment
  2785. //
  2786. if (WinPEBoot) {
  2787. Status = SlLoadSection(InfFile,
  2788. "MouseDrivers",
  2789. FALSE,
  2790. TRUE,
  2791. NULL);
  2792. if(Status != ESUCCESS) {
  2793. SlFriendlyError(
  2794. Status,
  2795. "MouseDrivers",
  2796. __LINE__,
  2797. __FILE__
  2798. );
  2799. goto LoadFailed;
  2800. }
  2801. }
  2802. ///////////////////////////////////////////////////////////////////
  2803. //
  2804. // On x86, the files loaded from now on are on boot floppy #3
  2805. //
  2806. ///////////////////////////////////////////////////////////////////
  2807. //
  2808. // Load scsiport.sys next, so it'll always be around for any scsi miniports we may load
  2809. //
  2810. Status = SlLoadDriver(BlFindMessage(SL_SCSIPORT_NAME),
  2811. "SCSIPORT.SYS",
  2812. 0,
  2813. FALSE,
  2814. FALSE,
  2815. NULL
  2816. );
  2817. //
  2818. // Detect scsi
  2819. //
  2820. // (If the user wants to select their own SCSI devices, we won't
  2821. // do any detection)
  2822. //
  2823. if(!PromptOemScsi && (PreinstallDriverList == NULL) ) {
  2824. SlDetectScsi(SetupBlock);
  2825. #if defined(_X86_) || defined(_IA64_)
  2826. if( Win9xUnsupHdc ) {
  2827. //
  2828. // If this is a Win9x upgrade and winnt32 detected an unsupported
  2829. // SCSI controller, then the user needs to be prompted for an OEM SCSI driver
  2830. //
  2831. PromptOemScsi = TRUE;
  2832. }
  2833. #endif
  2834. }
  2835. #if defined(ELTORITO) && !defined(ARCI386)
  2836. //
  2837. // If this is an El Torito CD-ROM install, then we want to load all SCSI miniports
  2838. // and disk class drivers.
  2839. // BUT we do not want to load all the disk class drivers for an ARC
  2840. // machine which knows what drivers it wants to install from its tree
  2841. //
  2842. if(ElToritoCDBoot) {
  2843. LoadScsiMiniports = TRUE;
  2844. }
  2845. #endif
  2846. //
  2847. // If the LoadScsi flag is set, enumerate all the known SCSI miniports and load each
  2848. // one.
  2849. //
  2850. if(LoadScsiMiniports && (PreinstallDriverList == NULL)) {
  2851. if (WinPEBoot && OemInfHandle) {
  2852. Status = SlLoadWinPESection(PreInstallOemSourceDevice,
  2853. OemInfHandle,
  2854. WINNT_OEMSCSIDRIVERS_A,
  2855. InfFile,
  2856. "Scsi",
  2857. TRUE,
  2858. &OemScsiInfo,
  2859. &BlLoaderBlock->SetupLoaderBlock->HardwareIdDatabase);
  2860. } else {
  2861. Status = SlLoadSection(InfFile,"Scsi",TRUE, TRUE, NULL);
  2862. }
  2863. if (Status!=ESUCCESS) {
  2864. goto LoadFailed;
  2865. }
  2866. SetupBlock->ScalarValues.LoadedScsi = 1;
  2867. }
  2868. //
  2869. // Pick the the dynamic update boot drivers, if any
  2870. //
  2871. if (DynamicUpdate) {
  2872. SlLoadOemScsiDriversUnattended(DynamicUpdateSourceDevice,
  2873. WinntSifHandle,
  2874. WINNT_SETUPPARAMS_A,
  2875. WINNT_SP_DYNUPDTBOOTDRIVERROOT_A,
  2876. WINNT_SP_DYNUPDTBOOTDRIVERS_A,
  2877. &OemScsiInfo,
  2878. &BlLoaderBlock->SetupLoaderBlock->HardwareIdDatabase);
  2879. }
  2880. //
  2881. // Allow the user to pick an OEM SCSI driver here
  2882. //
  2883. if (PromptOemScsi || (PreinstallDriverList != NULL)) {
  2884. POEMSCSIINFO DynUpdtScsiInfo = OemScsiInfo;
  2885. SlPromptOemScsi(((PreinstallDriverList == NULL) ?
  2886. DefaultOemSourceDevice : PreInstallOemSourceDevice),
  2887. (BOOLEAN) (!PreInstall || (PreinstallDriverList == NULL)),
  2888. &OemScsiInfo);
  2889. //
  2890. // Mark the default OEM source device as processed,
  2891. // if the user manually pressed F6
  2892. //
  2893. if (PromptOemScsi && DefaultOemSourceDevice) {
  2894. SL_OEM_SET_SOURCE_DEVICE_STATE(DefaultOemSourceDevice,
  2895. SL_OEM_SOURCE_DEVICE_PROCESSED);
  2896. }
  2897. //
  2898. // Reset the last disk tag for floopy boot
  2899. //
  2900. if (FloppyBoot) {
  2901. LastDiskTag = NULL;
  2902. }
  2903. //
  2904. // Merge the dynamic update SCSI driver list with oem SCSI
  2905. // driver list
  2906. //
  2907. if (DynUpdtScsiInfo) {
  2908. if (OemScsiInfo) {
  2909. POEMSCSIINFO CurrNode = DynUpdtScsiInfo;
  2910. while (CurrNode && CurrNode->Next) {
  2911. CurrNode = CurrNode->Next;
  2912. }
  2913. if (CurrNode) {
  2914. CurrNode->Next = OemScsiInfo;
  2915. OemScsiInfo = DynUpdtScsiInfo;
  2916. }
  2917. } else {
  2918. OemScsiInfo = DynUpdtScsiInfo;
  2919. }
  2920. }
  2921. // Cleanup here needed for all installation - ARCI386
  2922. if (UseRegularBackground) {
  2923. SlClearDisplay();
  2924. if (WinPEBoot) {
  2925. StartupMsg ? BlOutputStartupMsgStr(StartupMsg) :
  2926. BlOutputStartupMsg(SL_SETUP_STARTING_WINPE);
  2927. } else {
  2928. if (UseCommandConsole) {
  2929. BlOutputStartupMsg(SL_CMDCONS_STARTING);
  2930. } else if (g_RollbackEnabled) {
  2931. BlOutputStartupMsg(SL_ROLLBACK_STARTING);
  2932. } else {
  2933. BlOutputStartupMsg(SL_SETUP_STARTING);
  2934. }
  2935. }
  2936. BlRedrawProgressBar();
  2937. } else {
  2938. SlClearClientArea();
  2939. SlWriteStatusText(TEXT(""));
  2940. }
  2941. }
  2942. //
  2943. // If we found any valid txtsetup.oem with valid default MSD
  2944. // in any OEM source device which is not yet processed, then
  2945. // go and autoload the drivers from these devices.
  2946. //
  2947. if (OemSourceDevices && AutoLoadOemScsi) {
  2948. POEMSCSIINFO DeviceOemScsiInfo = NULL;
  2949. POEMSCSIINFO LastOemScsiNode = NULL;
  2950. //
  2951. // Determine if we need to disable the Virtual OEM devices.
  2952. // Disable OEM virtual Devices if we have been instructed by F4 in
  2953. // attended install, using the DisableOemVirtualDevices key in the unattend
  2954. // file or if Preinstall.
  2955. //
  2956. if (SlIsVirtualOemDeviceDisabled(WinntSifHandle,
  2957. PreinstallDriverList)) {
  2958. SlDisableVirtualOemDevices(OemSourceDevices);
  2959. }
  2960. SlLoadOemScsiDriversFromOemSources(OemSourceDevices,
  2961. &BlLoaderBlock->SetupLoaderBlock->HardwareIdDatabase,
  2962. &DeviceOemScsiInfo);
  2963. //
  2964. // Merge the full OEM source device list with the
  2965. // global OEM scsi information
  2966. //
  2967. if (DeviceOemScsiInfo) {
  2968. if (OemScsiInfo) {
  2969. LastOemScsiNode = OemScsiInfo;
  2970. while (LastOemScsiNode->Next) {
  2971. LastOemScsiNode = LastOemScsiNode->Next;
  2972. }
  2973. LastOemScsiNode->Next = DeviceOemScsiInfo;
  2974. } else {
  2975. OemScsiInfo = DeviceOemScsiInfo;
  2976. }
  2977. }
  2978. }
  2979. //
  2980. // Load all the disk images for the virtual devices
  2981. // into memory
  2982. //
  2983. if (OemSourceDevices) {
  2984. Status = SlInitVirtualOemSourceDevices(BlLoaderBlock->SetupLoaderBlock,
  2985. OemSourceDevices);
  2986. if (Status != ESUCCESS) {
  2987. SlFatalError(SL_OEM_FILE_LOAD_FAILED);
  2988. goto LoadFailed;
  2989. }
  2990. }
  2991. //
  2992. // Add unsupported SCSI drivers, if any, to the list
  2993. //
  2994. if( UnsupDriversInfHandle != NULL ) {
  2995. Status = SlDetectMigratedScsiDrivers( UnsupDriversInfHandle );
  2996. if (Status!=ESUCCESS) {
  2997. goto LoadFailed;
  2998. }
  2999. }
  3000. //
  3001. // Walk the list of detected SCSI miniports and load each one.
  3002. //
  3003. ScsiDevice = SetupBlock->ScsiDevices;
  3004. while (ScsiDevice != NULL) {
  3005. if(ScsiDevice->ThirdPartyOptionSelected) {
  3006. if(!OemScsiInfo) {
  3007. SlError(500);
  3008. goto LoadFailed;
  3009. }
  3010. Status = SlLoadOemDriver(
  3011. NULL,
  3012. OemScsiInfo->ScsiName,
  3013. OemScsiInfo->ScsiBase,
  3014. BlFindMessage(SL_SCSIPORT_NAME)
  3015. );
  3016. OemScsiInfo = OemScsiInfo->Next;
  3017. } else if(ScsiDevice->MigratedDriver) {
  3018. Status = SlLoadDriver(ScsiDevice->Description,
  3019. ScsiDevice->BaseDllName,
  3020. 0,
  3021. TRUE,
  3022. TRUE,
  3023. ScsiDevice->IdString
  3024. );
  3025. if( Status != ESUCCESS ) {
  3026. // DebugOutput("Status = %d %s \n",Status,"");
  3027. }
  3028. } else {
  3029. Status = SlLoadDriver(ScsiDevice->Description,
  3030. ScsiDevice->BaseDllName,
  3031. 0,
  3032. TRUE,
  3033. FALSE,
  3034. NULL
  3035. );
  3036. }
  3037. if((Status == ESUCCESS)
  3038. || ((Status == ENOENT) && IgnoreMissingFiles && !ScsiDevice->ThirdPartyOptionSelected)) {
  3039. SetupBlock->ScalarValues.LoadedScsi = 1;
  3040. } else {
  3041. SlFriendlyError(
  3042. Status,
  3043. ScsiDevice->BaseDllName,
  3044. __LINE__,
  3045. __FILE__
  3046. );
  3047. goto LoadFailed;
  3048. }
  3049. ScsiDevice = ScsiDevice->Next;
  3050. }
  3051. //
  3052. // If the LoadDiskClass flag is set, enumerate all the monolithic disk class drivers
  3053. // and load each one. Note that we also do this if we've "detected" any scsi drivers,
  3054. // so that we preserve the drive order.
  3055. //
  3056. if((LoadDiskClass) || (SetupBlock->ScalarValues.LoadedScsi == 1)) {
  3057. Status = SlLoadSection(InfFile, "DiskDrivers", FALSE, TRUE, NULL);
  3058. if (Status == ESUCCESS) {
  3059. SetupBlock->ScalarValues.LoadedDiskDrivers = 1;
  3060. } else {
  3061. goto LoadFailed;
  3062. }
  3063. }
  3064. #if !defined(_IA64_)
  3065. //
  3066. // There is currently no floppy support on IA64 systems.
  3067. //
  3068. //
  3069. // Load the floppy driver (flpydisk.sys)
  3070. //
  3071. #if !defined (ARCI386) && defined(_X86_)
  3072. Status=ESUCCESS;
  3073. //
  3074. // If there are only SFLOPPY devices (such as the LS-120 ATAPI super floppy)
  3075. // DON'T load flpydisk.sys on them. It will collide with SFLOPPY.SYS
  3076. //
  3077. if (!SlpIsOnlySuperFloppy()) {
  3078. #endif
  3079. Status = SlLoadDriver(BlFindMessage(SL_FLOPPY_NAME),
  3080. "flpydisk.sys",
  3081. 0,
  3082. TRUE,
  3083. FALSE,
  3084. NULL
  3085. );
  3086. #if !defined (ARCI386) && defined(_X86_)
  3087. }
  3088. #endif
  3089. if (Status == ESUCCESS) {
  3090. SetupBlock->ScalarValues.LoadedFloppyDrivers = 1;
  3091. }
  3092. #endif
  3093. #ifdef i386
  3094. else {
  3095. SlFriendlyError(
  3096. Status,
  3097. "flpydisk.sys",
  3098. __LINE__,
  3099. __FILE__
  3100. );
  3101. goto LoadFailed;
  3102. }
  3103. #endif
  3104. if(SetupBlock->ScalarValues.LoadedScsi == 1) {
  3105. //
  3106. // Enumerate the entries in the scsi class section and load each one.
  3107. //
  3108. Status = SlLoadSection(InfFile, "ScsiClass",FALSE, TRUE, NULL);
  3109. if (Status != ESUCCESS) {
  3110. goto LoadFailed;
  3111. }
  3112. }
  3113. if((LoadDiskClass) || (SetupBlock->ScalarValues.LoadedScsi == 1)) {
  3114. Status = SlLoadSection(InfFile, "FileSystems", FALSE, TRUE, NULL);
  3115. if (Status == ESUCCESS) {
  3116. SetupBlock->ScalarValues.LoadedFileSystems = 1;
  3117. } else {
  3118. goto LoadFailed;
  3119. }
  3120. } else {
  3121. //
  3122. // Load FAT
  3123. //
  3124. Status = SlLoadDriver(BlFindMessage(SL_FAT_NAME),
  3125. "fastfat.sys",
  3126. 0,
  3127. TRUE,
  3128. FALSE,
  3129. NULL
  3130. );
  3131. #ifdef i386
  3132. if(Status != ESUCCESS) {
  3133. SlFriendlyError(
  3134. Status,
  3135. "fastfat.sys",
  3136. __LINE__,
  3137. __FILE__
  3138. );
  3139. goto LoadFailed;
  3140. }
  3141. #endif
  3142. }
  3143. //
  3144. // Load CDFS if setupldr was started from a cdrom, or if ForceLoadCdfs is set.
  3145. //
  3146. if (LoadCdfs || (!BlGetPathMnemonicKey(SetupDevice,
  3147. "cdrom",
  3148. &BootDriveNumber))) {
  3149. Status = SlLoadSection(InfFile, "CdRomDrivers",FALSE, TRUE, NULL);
  3150. if (Status == ESUCCESS) {
  3151. SetupBlock->ScalarValues.LoadedCdRomDrivers = 1;
  3152. } else {
  3153. goto LoadFailed;
  3154. }
  3155. }
  3156. if (BlBootingFromNet || WinPEBoot) {
  3157. //
  3158. // Load the network stack.
  3159. //
  3160. Status = SlLoadDriver(BlFindMessage(SL_KSECDD_NAME),
  3161. "ksecdd.sys",
  3162. 0,
  3163. TRUE,
  3164. FALSE,
  3165. NULL
  3166. );
  3167. if(Status != ESUCCESS) {
  3168. SlFriendlyError(
  3169. Status,
  3170. "ksecdd.sys",
  3171. __LINE__,
  3172. __FILE__
  3173. );
  3174. goto LoadFailed;
  3175. }
  3176. Status = SlLoadDriver(BlFindMessage(SL_NDIS_NAME),
  3177. "ndis.sys",
  3178. 0,
  3179. TRUE,
  3180. FALSE,
  3181. NULL
  3182. );
  3183. if(Status != ESUCCESS) {
  3184. SlFriendlyError(
  3185. Status,
  3186. "ndis.sys",
  3187. __LINE__,
  3188. __FILE__
  3189. );
  3190. goto LoadFailed;
  3191. }
  3192. if (BlBootingFromNet) {
  3193. Status = SlLoadDriver(BlFindMessage(SL_IPSEC_NAME),
  3194. "ipsec.sys",
  3195. 0,
  3196. TRUE,
  3197. FALSE,
  3198. NULL
  3199. );
  3200. if(Status != ESUCCESS) {
  3201. SlFriendlyError(
  3202. Status,
  3203. "ipsec.sys",
  3204. __LINE__,
  3205. __FILE__
  3206. );
  3207. goto LoadFailed;
  3208. }
  3209. Status = SlLoadDriver(BlFindMessage(SL_TCPIP_NAME),
  3210. "tcpip.sys",
  3211. 0,
  3212. TRUE,
  3213. FALSE,
  3214. NULL
  3215. );
  3216. if(Status != ESUCCESS) {
  3217. SlFriendlyError(
  3218. Status,
  3219. "tcpip.sys",
  3220. __LINE__,
  3221. __FILE__
  3222. );
  3223. goto LoadFailed;
  3224. }
  3225. Status = SlLoadDriver(BlFindMessage(SL_NETBT_NAME),
  3226. "netbt.sys",
  3227. 0,
  3228. TRUE,
  3229. FALSE,
  3230. NULL
  3231. );
  3232. if(Status != ESUCCESS) {
  3233. SlFriendlyError(
  3234. Status,
  3235. "netbt.sys",
  3236. __LINE__,
  3237. __FILE__
  3238. );
  3239. goto LoadFailed;
  3240. }
  3241. Status = SlLoadDriver(BlFindMessage(SL_NETADAPTER_NAME),
  3242. NetbootCardDriverName,
  3243. 0,
  3244. TRUE,
  3245. FALSE,
  3246. NULL
  3247. );
  3248. if(Status != ESUCCESS) {
  3249. SlFriendlyError(
  3250. Status,
  3251. NetbootCardDriverName,
  3252. __LINE__,
  3253. __FILE__
  3254. );
  3255. goto LoadFailed;
  3256. }
  3257. //
  3258. // Fill in the registry key for the netboot card because its service name
  3259. // may be different from the driver name.
  3260. //
  3261. DriverEntry = (PBOOT_DRIVER_LIST_ENTRY)(BlLoaderBlock->BootDriverListHead.Blink); // SlLoadDriver inserts at the tail
  3262. DriverEntry->RegistryPath.Buffer = BlAllocateHeap(256);
  3263. if (DriverEntry->RegistryPath.Buffer == NULL) {
  3264. SlNoMemoryError();
  3265. goto LoadFailed;
  3266. }
  3267. DriverEntry->RegistryPath.Length = 0;
  3268. DriverEntry->RegistryPath.MaximumLength = 256;
  3269. RtlAppendUnicodeToString(&DriverEntry->RegistryPath,
  3270. L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
  3271. RtlAppendUnicodeToString(&DriverEntry->RegistryPath,
  3272. SetupBlock->NetbootCardServiceName);
  3273. Status = SlLoadDriver(BlFindMessage(SL_RDBSS_NAME),
  3274. "rdbss.sys",
  3275. 0,
  3276. TRUE,
  3277. FALSE,
  3278. NULL
  3279. );
  3280. if(Status != ESUCCESS) {
  3281. SlFriendlyError(
  3282. Status,
  3283. "rdbss.sys",
  3284. __LINE__,
  3285. __FILE__
  3286. );
  3287. goto LoadFailed;
  3288. }
  3289. }
  3290. Status = SlLoadDriver(BlFindMessage(SL_MUP_NAME),
  3291. "mup.sys",
  3292. 0,
  3293. TRUE,
  3294. FALSE,
  3295. NULL
  3296. );
  3297. if(Status != ESUCCESS) {
  3298. SlFriendlyError(
  3299. Status,
  3300. "mup.sys",
  3301. __LINE__,
  3302. __FILE__
  3303. );
  3304. goto LoadFailed;
  3305. }
  3306. if (BlBootingFromNet) {
  3307. Status = SlLoadDriver(BlFindMessage(SL_MRXSMB_NAME),
  3308. "mrxsmb.sys",
  3309. 0,
  3310. TRUE,
  3311. FALSE,
  3312. NULL
  3313. );
  3314. if(Status != ESUCCESS) {
  3315. SlFriendlyError(
  3316. Status,
  3317. "mrxsmb.sys",
  3318. __LINE__,
  3319. __FILE__
  3320. );
  3321. goto LoadFailed;
  3322. }
  3323. }
  3324. }
  3325. if( WinPEBoot && BlLoaderBlock->Extension->HeadlessLoaderBlock != NULL ) {
  3326. //
  3327. // Try and load the sacdriver.
  3328. //
  3329. Status = SlLoadDriver(BlFindMessage(SL_SACDRV_NAME),
  3330. "sacdrv.sys",
  3331. 0,
  3332. TRUE,
  3333. FALSE,
  3334. NULL
  3335. );
  3336. }
  3337. if (!UseRegularBackground) {
  3338. SlWriteStatusText (BlFindMessage (SL_KERNEL_TRANSITION));
  3339. }
  3340. //
  3341. // Finally, make sure the appropriate disk containing NTDLL.DLL is in
  3342. // the drive.
  3343. //
  3344. SlGetDisk("ntdll.dll");
  3345. //
  3346. // Fill in the SETUPLDR block with relevant information
  3347. //
  3348. SetupBlock->ArcSetupDeviceName = BlLoaderBlock->ArcBootDeviceName;
  3349. SetupBlock->ScalarValues.SetupFromCdRom = FALSE;
  3350. SetupBlock->ScalarValues.SetupOperation = SetupOperationSetup;
  3351. //
  3352. // Get the NTFT drive signatures to allow the kernel to create the
  3353. // correct ARC name <=> NT name mappings.
  3354. //
  3355. //
  3356. // X86Only : Go enumerate all the disks and record their ability to
  3357. // support xint13.
  3358. //
  3359. BlGetArcDiskInformation(TRUE);
  3360. //
  3361. // ntdetect has already run. Although it's awful to have
  3362. // 2 disks that look just alike, stamping a signature on one
  3363. // after ntdetect has run will also break us. Rather err on
  3364. // the side of caution and not write to the disks.
  3365. //
  3366. // This is much safer on x86 because we've ensured that the
  3367. // boot disk has a signature before we get here. On Alpha,
  3368. // we can't do that. So it's ugly, but call this guy for
  3369. // BIOS-based x86 machines.
  3370. //
  3371. // don't reboot after stamping signatures
  3372. // the first time
  3373. //
  3374. SlpMarkDisks(FALSE);
  3375. //
  3376. // If setup was started from a CD-ROM, generate an entry in the ARC disk
  3377. // information list describing the cd-rom.
  3378. //
  3379. if (!BlGetPathMnemonicKey(SetupDevice,
  3380. "cdrom",
  3381. &BootDriveNumber)) {
  3382. BlReadSignature(SetupDevice,TRUE);
  3383. }
  3384. //
  3385. // Close the ARC device.
  3386. //
  3387. ArcClose(BootDeviceId);
  3388. #if 0
  3389. {
  3390. ULONG EndTime = ArcGetRelativeTime();
  3391. char szTemp[256];
  3392. extern ULONG BlFilesOpened;
  3393. BlPositionCursor(1, 10);
  3394. sprintf(szTemp, "BootTime : %d secs, FilesOpened : %d\r\n",
  3395. EndTime - StartTime, BlFilesOpened );
  3396. BlPrint(szTemp);
  3397. }
  3398. #endif
  3399. if (UseRegularBackground) {
  3400. BlOutputStartupMsg(SL_PLEASE_WAIT);
  3401. BlUpdateProgressBar(100);
  3402. }
  3403. //
  3404. // Remove system32 from the boot path if we added it
  3405. //
  3406. if (WinPEBoot) {
  3407. PCHAR Sys32 = BlLoaderBlock->NtBootPathName +
  3408. strlen(BlLoaderBlock->NtBootPathName) -
  3409. strlen("system32\\");
  3410. if (Sys32 && !_stricmp(Sys32, "system32\\")) {
  3411. *Sys32 = 0;
  3412. }
  3413. }
  3414. //
  3415. // Close down the remote boot network file system.
  3416. //
  3417. // NOTE: If BlBootingFromNet, don't do anything after this point
  3418. // that would cause access to the boot ROM.
  3419. //
  3420. if ( BlBootingFromNet ) {
  3421. NetTerminate();
  3422. }
  3423. //
  3424. //
  3425. // Execute the architecture specific setup code.
  3426. //
  3427. // NOTE: If BlBootingFromNet, don't do anything after this point
  3428. // that would cause access to the boot ROM.
  3429. //
  3430. Status = BlSetupForNt(BlLoaderBlock);
  3431. if (Status != ESUCCESS) {
  3432. SlFriendlyError(
  3433. Status,
  3434. "\"Windows NT Executive\"",
  3435. __LINE__,
  3436. __FILE__
  3437. );
  3438. goto LoadFailed;
  3439. }
  3440. //
  3441. // Transfer to the kernel
  3442. //
  3443. // DbgBreakPoint();
  3444. BlTransferToKernel(SystemEntry, BlLoaderBlock);
  3445. //
  3446. // Any return from the system is an error.
  3447. //
  3448. Status = EBADF;
  3449. SlFriendlyError(
  3450. Status,
  3451. "\"Windows NT Executive\"",
  3452. __LINE__,
  3453. __FILE__
  3454. );
  3455. LoadFailed:
  3456. SlWriteStatusText(BlFindMessage(SL_TOTAL_SETUP_DEATH));
  3457. SlFlushConsoleBuffer();
  3458. SlGetChar();
  3459. ArcRestart();
  3460. return(Status);
  3461. }
  3462. VOID
  3463. SlpTruncateMemory(
  3464. IN ULONG MaxMemory
  3465. )
  3466. /*++
  3467. Routine Description:
  3468. Eliminates all the memory descriptors above a given boundary
  3469. Arguments:
  3470. MaxMemory - Supplies the maximum memory boundary in megabytes
  3471. Return Value:
  3472. None.
  3473. --*/
  3474. {
  3475. PLIST_ENTRY NextEntry;
  3476. PMEMORY_ALLOCATION_DESCRIPTOR MemoryDescriptor;
  3477. ULONG MaxPage = MaxMemory * 256; // Convert Mb to pages
  3478. if (MaxMemory == 0) {
  3479. return;
  3480. }
  3481. NextEntry = BlLoaderBlock->MemoryDescriptorListHead.Flink;
  3482. while ( NextEntry != &BlLoaderBlock->MemoryDescriptorListHead ) {
  3483. MemoryDescriptor = CONTAINING_RECORD(NextEntry,
  3484. MEMORY_ALLOCATION_DESCRIPTOR,
  3485. ListEntry);
  3486. NextEntry = NextEntry->Flink;
  3487. if ( (MemoryDescriptor->MemoryType != LoaderFree) &&
  3488. (MemoryDescriptor->MemoryType != LoaderFirmwareTemporary) ) {
  3489. continue;
  3490. }
  3491. if (MemoryDescriptor->BasePage >= MaxPage) {
  3492. //
  3493. // This memory descriptor lies entirely above the boundary,
  3494. // eliminate it.
  3495. //
  3496. BlRemoveDescriptor(MemoryDescriptor);
  3497. } else if (MemoryDescriptor->BasePage + MemoryDescriptor->PageCount > MaxPage) {
  3498. //
  3499. // This memory descriptor crosses the boundary, truncate it.
  3500. //
  3501. MemoryDescriptor->PageCount = MaxPage - MemoryDescriptor->BasePage;
  3502. }
  3503. }
  3504. }
  3505. VOID
  3506. SlGetSetupValuesBeforePrompt(
  3507. IN PSETUP_LOADER_BLOCK SetupBlock
  3508. )
  3509. /*++
  3510. Routine Description:
  3511. Reads the setup control values out of the given .INI file.
  3512. Also supplies reasonable defaults for values that don't exist.
  3513. Arguments:
  3514. SetupBlock - Supplies a pointer to the Setup loader block
  3515. Return Value:
  3516. None. Global variables are initialized to reflect the
  3517. contents of the INI file
  3518. --*/
  3519. {
  3520. PCHAR NlsName;
  3521. ANSI_STRING NlsString;
  3522. PCHAR Options="1";
  3523. ULONG MaxMemory;
  3524. if (BlBootingFromNet) {
  3525. BlLoaderBlock->LoadOptions = SlGetIniValue(WinntSifHandle,
  3526. "setupdata",
  3527. "osloadoptions",
  3528. NULL);
  3529. } else {
  3530. BlLoaderBlock->LoadOptions = NULL;
  3531. }
  3532. if (BlLoaderBlock->LoadOptions == NULL) {
  3533. BlLoaderBlock->LoadOptions = SlGetIniValue(InfFile,
  3534. "setupdata",
  3535. "osloadoptions",
  3536. NULL);
  3537. }
  3538. AnsiCpName = SlGetIniValue(InfFile,
  3539. "nls",
  3540. "AnsiCodepage",
  3541. "c_1252.nls");
  3542. //
  3543. // when assigning the length, do some checking to make sure we don't
  3544. // overflow. if we do overflow, assign the length value to 0
  3545. // make sure we don't overflow (USHORT)-1 / sizeof(WCHAR) - sizeof(CHAR))
  3546. // we check this value, since the maximum length of the unicode
  3547. // will include the null character, and be twice it's length
  3548. // or (USHORT) -1.
  3549. //
  3550. NlsString.Buffer = AnsiCpName;
  3551. NlsString.Length = (USHORT) RESET_SIZE_AT_VALUE(strlen(AnsiCpName),
  3552. (USHORT)-1 / sizeof(WCHAR) - sizeof(CHAR));
  3553. NlsString.MaximumLength = (NlsString.Length) ? NlsString.Length + sizeof(CHAR) : 0;
  3554. AnsiCodepage.MaximumLength = NlsString.MaximumLength * sizeof(WCHAR);
  3555. AnsiCodepage.Buffer = BlAllocateHeap(AnsiCodepage.MaximumLength);
  3556. if (AnsiCodepage.Buffer == NULL) {
  3557. SlNoMemoryError();
  3558. }
  3559. RtlAnsiStringToUnicodeString(&AnsiCodepage, &NlsString, FALSE);
  3560. NlsName = SlGetIniValue(InfFile,
  3561. "nls",
  3562. "OemCodepage",
  3563. "c_437.nls");
  3564. //
  3565. // when assigning the length, do some checking to make sure we don't
  3566. // overflow. if we do overflow, assign the length value to 0
  3567. // make sure we don't overflow (USHORT)-1 / sizeof(WCHAR) - sizeof(CHAR))
  3568. // we check this value, since the maximum length of the unicode
  3569. // will include the null character, and be twice it's length
  3570. // or (USHORT) -1.
  3571. //
  3572. NlsString.Buffer = NlsName;
  3573. NlsString.Length = (USHORT) RESET_SIZE_AT_VALUE(strlen(NlsName),
  3574. (USHORT)-1 / sizeof(WCHAR) - sizeof(CHAR));
  3575. NlsString.MaximumLength = (NlsString.Length) ? NlsString.Length + sizeof(CHAR) : 0;
  3576. OemCodepage.MaximumLength = NlsString.MaximumLength * sizeof(WCHAR);
  3577. OemCodepage.Buffer = BlAllocateHeap(OemCodepage.MaximumLength);
  3578. if (OemCodepage.Buffer == NULL) {
  3579. SlNoMemoryError();
  3580. }
  3581. RtlAnsiStringToUnicodeString(&OemCodepage, &NlsString, FALSE);
  3582. NlsName = SlGetIniValue(InfFile,
  3583. "nls",
  3584. "UnicodeCasetable",
  3585. "l_intl.nls");
  3586. //
  3587. // when assigning the length, do some checking to make sure we don't
  3588. // overflow. if we do overflow, assign the length value to 0
  3589. // make sure we don't overflow (USHORT)-1 / sizeof(WCHAR) - sizeof(CHAR))
  3590. // we check this value, since the maximum length of the unicode
  3591. // will include the null character, and be twice it's length
  3592. // or (USHORT) -1.
  3593. //
  3594. NlsString.Buffer = NlsName;
  3595. NlsString.Length = (USHORT) RESET_SIZE_AT_VALUE(strlen(NlsName),
  3596. (USHORT)-1 / sizeof(WCHAR) - sizeof(CHAR));
  3597. NlsString.MaximumLength = (NlsString.Length) ? NlsString.Length + sizeof(CHAR) : 0;
  3598. UnicodeCaseTable.MaximumLength = NlsString.MaximumLength*sizeof(WCHAR);
  3599. UnicodeCaseTable.Buffer = BlAllocateHeap(UnicodeCaseTable.MaximumLength);
  3600. if (UnicodeCaseTable.Buffer == NULL) {
  3601. SlNoMemoryError();
  3602. }
  3603. RtlAnsiStringToUnicodeString(&UnicodeCaseTable, &NlsString, FALSE);
  3604. OemHalFontName = SlGetIniValue(InfFile,
  3605. "nls",
  3606. "OemHalFont",
  3607. "vgaoem.fon");
  3608. //
  3609. // when assigning the length, do some checking to make sure we don't
  3610. // overflow. if we do overflow, assign the length value to 0
  3611. // make sure we don't overflow (USHORT)-1 / sizeof(WCHAR) - sizeof(CHAR))
  3612. // we check this value, since the maximum length of the unicode
  3613. // will include the null character, and be twice it's length
  3614. // or (USHORT) -1.
  3615. //
  3616. NlsString.Buffer = OemHalFontName;
  3617. NlsString.Length = (USHORT) RESET_SIZE_AT_VALUE(strlen(OemHalFontName),
  3618. (USHORT)-1 / sizeof(WCHAR) - sizeof(CHAR));
  3619. NlsString.MaximumLength = (NlsString.Length) ? NlsString.Length + sizeof(CHAR) : 0;
  3620. OemHalFont.MaximumLength = NlsString.MaximumLength*sizeof(WCHAR);
  3621. OemHalFont.Buffer = BlAllocateHeap(OemHalFont.MaximumLength);
  3622. if (OemHalFont.Buffer == NULL) {
  3623. SlNoMemoryError();
  3624. }
  3625. RtlAnsiStringToUnicodeString(&OemHalFont, &NlsString, FALSE);
  3626. #ifdef _WANT_MACHINE_IDENTIFICATION
  3627. BiosInfo.Buffer = NULL;
  3628. NlsString.Buffer = SlGetIniValue(InfFile,
  3629. "BiosInfo",
  3630. "InfName",
  3631. NULL);
  3632. if (NlsString.Buffer) {
  3633. //
  3634. // when assigning the length, do some checking to make sure we don't
  3635. // overflow. if we do overflow, assign the length value to 0
  3636. // make sure we don't overflow (USHORT)-1 / sizeof(WCHAR) - sizeof(CHAR))
  3637. // we check this value, since the maximum length of the unicode
  3638. // will include the null character, and be twice it's length
  3639. // or (USHORT) -1.
  3640. //
  3641. NlsString.Length = (USHORT) RESET_SIZE_AT_VALUE(strlen(NlsString.Buffer),
  3642. (USHORT)-1 / sizeof(WCHAR) - sizeof(CHAR));
  3643. NlsString.MaximumLength = (NlsString.Length) ? NlsString.Length + sizeof(CHAR) : 0;
  3644. BiosInfo.MaximumLength = NlsString.MaximumLength*sizeof(WCHAR);
  3645. BiosInfo.Buffer = BlAllocateHeap(BiosInfo.MaximumLength);
  3646. if (BiosInfo.Buffer == NULL) {
  3647. SlNoMemoryError();
  3648. }
  3649. RtlAnsiStringToUnicodeString(&BiosInfo, &NlsString, FALSE);
  3650. }
  3651. #endif
  3652. //
  3653. // Loading all the miniport will exhaust all free mem <16Mb - ArcSetup dies.
  3654. //
  3655. #ifndef ARCI386
  3656. LoadScsiMiniports = (BOOLEAN) (atoi(SlGetIniValue(InfFile,
  3657. "SetupData",
  3658. "ForceScsi",
  3659. "0")) == 1);
  3660. #endif
  3661. LoadDiskClass = (BOOLEAN) (atoi(SlGetIniValue(InfFile,
  3662. "setupdata",
  3663. "ForceDiskClass",
  3664. "0")) == 1);
  3665. LoadCdfs = (BOOLEAN) (atoi(SlGetIniValue(InfFile,
  3666. "setupdata",
  3667. "ForceCdRom",
  3668. "0")) == 1);
  3669. BootPath = SlGetIniValue(InfFile,
  3670. "setupdata",
  3671. "BootPath",
  3672. NULL);
  3673. BootDevice = SlGetIniValue(InfFile,
  3674. "setupdata",
  3675. "BootDevice",
  3676. NULL);
  3677. //
  3678. // Build a linked list with all the P&P hardware ids.
  3679. // listed on [HardwareIdsDatabase]. This list will be used
  3680. // during the initialization phase of setupdd.sys
  3681. //
  3682. SetupBlock->HardwareIdDatabase = NULL;
  3683. if( SpSearchINFSection( InfFile, "HardwareIdsDatabase" ) ) {
  3684. ULONG i;
  3685. PPNP_HARDWARE_ID TempHardwareId;
  3686. PCHAR p;
  3687. for( i = 0;
  3688. ((p = SlGetKeyName( InfFile, "HardwareIdsDatabase", i )) != NULL);
  3689. i++ ) {
  3690. TempHardwareId = BlAllocateHeap(sizeof(PNP_HARDWARE_ID));
  3691. if (TempHardwareId==NULL) {
  3692. SlNoMemoryError();
  3693. }
  3694. TempHardwareId->Id = p;
  3695. p = SlGetSectionKeyIndex( InfFile,
  3696. "HardwareIdsDatabase",
  3697. TempHardwareId->Id,
  3698. 0 );
  3699. TempHardwareId->DriverName = p;
  3700. p = SlGetSectionKeyIndex( InfFile,
  3701. "HardwareIdsDatabase",
  3702. TempHardwareId->Id,
  3703. 1 );
  3704. TempHardwareId->ClassGuid = p;
  3705. TempHardwareId->Next = SetupBlock->HardwareIdDatabase;
  3706. SetupBlock->HardwareIdDatabase = TempHardwareId;
  3707. }
  3708. }
  3709. if (BlLoaderBlock->LoadOptions) {
  3710. _strupr(BlLoaderBlock->LoadOptions);
  3711. if ( ( Options = strstr(BlLoaderBlock->LoadOptions,"/MAXMEM") ) != 0 ) {
  3712. MaxMemory = atoi(Options+8);
  3713. SlpTruncateMemory( MaxMemory );
  3714. }
  3715. }
  3716. }
  3717. VOID
  3718. SlGetSetupValuesAfterPrompt(
  3719. IN PSETUP_LOADER_BLOCK SetupBlock
  3720. )
  3721. /*++
  3722. Routine Description:
  3723. Reads the setup control values out of the given .INI file. Also supplies
  3724. reasonable defaults for values that don't exist.
  3725. Note : This is called after the user is prompted for F5,
  3726. F6 & F7 behavior.
  3727. Arguments:
  3728. SetupBlock - Supplies a pointer to the Setup loader block
  3729. Return Value:
  3730. None. Global variables are initialized to reflect the contents
  3731. of the INI file
  3732. --*/
  3733. {
  3734. PCHAR MachineName = NULL;
  3735. //
  3736. // Determine which HAL to load. If the appropriate HAL cannot be
  3737. // determined, or if we are to prompt for an OEM HAL, then set the
  3738. // 'PromptOemHal' flag (may have already been set by the user's
  3739. // keypress).
  3740. //
  3741. if(!PromptOemHal) {
  3742. PromptOemHal = (BOOLEAN) (atoi(SlGetIniValue(InfFile,
  3743. "setupdata",
  3744. "ForceOemHal",
  3745. "0")) == 1);
  3746. }
  3747. if(!PromptOemHal) {
  3748. MachineName = SlDetectHal();
  3749. }
  3750. SetupBlock->ComputerDevice.Files = 0;
  3751. SetupBlock->ComputerDevice.Next = NULL;
  3752. SetupBlock->ComputerDevice.Description = NULL;
  3753. SetupBlock->ComputerDevice.ThirdPartyOptionSelected = FALSE;
  3754. SetupBlock->ComputerDevice.FileTypeBits = 0;
  3755. SetupBlock->ComputerDevice.Files = 0;
  3756. SetupBlock->ComputerDevice.BaseDllName = SlCopyStringA("");
  3757. if(MachineName!=NULL) {
  3758. SetupBlock->ComputerDevice.IdString = SlCopyStringA(MachineName);
  3759. //
  3760. // Map the machine name to a HAL name. If we're doing a remote boot,
  3761. // look in the [Hal] section. Otherwise, look in the [Hal.Load]
  3762. // section. (Local setup has a separate section to minimize the
  3763. // number of HAL binaries that need to be on the boot floppies.)
  3764. //
  3765. HalName = SlGetIniValue(InfFile,
  3766. BlBootingFromNet ? "Hal" : "Hal.Load",
  3767. MachineName,
  3768. NULL);
  3769. HalDescription = SlGetIniValue(InfFile,
  3770. "Computer",
  3771. MachineName,
  3772. NULL);
  3773. }
  3774. if(!(MachineName && HalName && HalDescription)) {
  3775. PromptOemHal = TRUE;
  3776. }
  3777. //
  3778. // If we haven't already been instructed to prompt for an OEM SCSI disk (by
  3779. // the user's keypress), then get this value from the inf file.
  3780. //
  3781. if(!PromptOemScsi) {
  3782. PromptOemScsi = (BOOLEAN) (atoi(SlGetIniValue(InfFile,
  3783. "setupdata",
  3784. "ForceOemScsi",
  3785. "0")) == 1);
  3786. }
  3787. }
  3788. VOID
  3789. BlOutputLoadMessage (
  3790. IN PCHAR DeviceName,
  3791. IN PCHAR FileName,
  3792. IN PTCHAR FileDescription OPTIONAL
  3793. )
  3794. /*++
  3795. Routine Description:
  3796. This routine outputs a loading message on the status line
  3797. Arguments:
  3798. DeviceName - Supplies a pointer to a zero terminated device name.
  3799. FileName - Supplies a pointer to a zero terminated file name.
  3800. FileDescription - Friendly name of the file in question.
  3801. Return Value:
  3802. None.
  3803. --*/
  3804. {
  3805. static int dots = 0;
  3806. TCHAR OutputBuffer[256];
  3807. PTCHAR FormatString;
  3808. UNREFERENCED_PARAMETER( FileName );
  3809. UNREFERENCED_PARAMETER( DeviceName );
  3810. //
  3811. // Construct and output loading file message.
  3812. //
  3813. if (!UseRegularBackground) {
  3814. FormatString = BlFindMessage(SL_FILE_LOAD_MESSAGE);
  3815. if (FileDescription) {
  3816. _stprintf(OutputBuffer,FormatString,FileDescription);
  3817. SlWriteStatusText(OutputBuffer);
  3818. }
  3819. }
  3820. return;
  3821. }
  3822. ARC_STATUS
  3823. SlLoadDriver(
  3824. IN PTCHAR DriverDescription,
  3825. IN PCHAR DriverName,
  3826. IN ULONG DriverFlags,
  3827. IN BOOLEAN InsertIntoDriverList,
  3828. IN BOOLEAN MigratedDriver,
  3829. IN PCHAR ServiceName OPTIONAL
  3830. )
  3831. /*++
  3832. Routine Description:
  3833. Attempts to load a driver from the device identified by the global
  3834. variable BootDeviceId.
  3835. Arguments:
  3836. DriverDescription - Supplies a friendly description of the driver being
  3837. loaded.
  3838. DriverName - Supplies the name of the driver.
  3839. DriverFlags - Flags to set in the LDR_DATA_TABLE_ENTRY.
  3840. InsertIntoDriverList - Flag specifying whether this 'driver' should be
  3841. placed into the BootDriveListHead list (eg, scsiport.sys
  3842. is not a true driver, and should not be placed in this list)
  3843. MigratedDriver - Flag specifying whther this driver was migrated from an NT system.
  3844. ServiceName - The service name for this driver as it may be different from the driver name.
  3845. Return Value:
  3846. ESUCCESS - Driver successfully loaded
  3847. --*/
  3848. {
  3849. PBOOT_DRIVER_LIST_ENTRY DriverEntry;
  3850. NTSTATUS Status;
  3851. PKLDR_DATA_TABLE_ENTRY DataTableEntry;
  3852. FULL_PATH_SET PathSet;
  3853. if(BlCheckForLoadedDll(DriverName,&DataTableEntry)) {
  3854. return(ESUCCESS);
  3855. }
  3856. DriverEntry = SlpCreateDriverEntry(DriverName, ServiceName);
  3857. if(DriverEntry == NULL) {
  3858. SlNoMemoryError();
  3859. return(ENOMEM);
  3860. }
  3861. if( !WinPEBoot && !MigratedDriver ) {
  3862. SlGetDisk(DriverName);
  3863. }
  3864. PathSet.PathCount = 1;
  3865. PathSet.AliasName = "\\SystemRoot";
  3866. PathSet.PathOffset[0] = '\0';
  3867. PathSet.Source[0].DeviceId = BootDeviceId;
  3868. PathSet.Source[0].DeviceName = BootDevice;
  3869. if (WinPEBoot) {
  3870. static PCHAR Path = NULL;
  3871. if (!Path) {
  3872. CHAR Buffer[256];
  3873. strcpy(Buffer, BootPath);
  3874. strcat(Buffer, "drivers\\");
  3875. Path = SlCopyStringA(Buffer);
  3876. }
  3877. PathSet.Source[0].DirectoryPath = Path;
  3878. } else {
  3879. PathSet.Source[0].DirectoryPath = BootPath;
  3880. }
  3881. Status = BlLoadDeviceDriver(
  3882. &PathSet,
  3883. DriverName,
  3884. DriverDescription,
  3885. DriverFlags,
  3886. &DriverEntry->LdrEntry
  3887. );
  3888. if((Status == ESUCCESS) && InsertIntoDriverList) {
  3889. InsertTailList(&BlLoaderBlock->BootDriverListHead,&DriverEntry->Link);
  3890. }
  3891. return(Status);
  3892. }
  3893. ARC_STATUS
  3894. SlLoadOemDriver(
  3895. IN PCHAR ExportDriver OPTIONAL,
  3896. IN PCHAR DriverName,
  3897. IN PVOID BaseAddress,
  3898. IN PTCHAR LoadMessage
  3899. )
  3900. {
  3901. PBOOT_DRIVER_LIST_ENTRY DriverEntry;
  3902. ARC_STATUS Status;
  3903. PKLDR_DATA_TABLE_ENTRY DataTableEntry;
  3904. FULL_PATH_SET PathSet;
  3905. UNREFERENCED_PARAMETER(LoadMessage);
  3906. if(BlCheckForLoadedDll(DriverName,&DataTableEntry)) {
  3907. return(ESUCCESS);
  3908. }
  3909. if(ExportDriver) {
  3910. SlGetDisk(ExportDriver);
  3911. }
  3912. DriverEntry = SlpCreateDriverEntry(DriverName, NULL);
  3913. if (DriverEntry==NULL) {
  3914. return(ENOMEM);
  3915. }
  3916. Status = BlAllocateDataTableEntry(
  3917. DriverName,
  3918. DriverName,
  3919. BaseAddress,
  3920. &DriverEntry->LdrEntry
  3921. );
  3922. if (Status == ESUCCESS) {
  3923. PathSet.PathCount = 1;
  3924. PathSet.AliasName = "\\SystemRoot";
  3925. PathSet.PathOffset[0] = '\0';
  3926. PathSet.Source[0].DeviceId = BootDeviceId;
  3927. PathSet.Source[0].DeviceName = BootDevice;
  3928. PathSet.Source[0].DirectoryPath = BootPath;
  3929. Status = BlScanImportDescriptorTable(
  3930. &PathSet,
  3931. DriverEntry->LdrEntry,
  3932. LoaderBootDriver
  3933. );
  3934. if(Status == ESUCCESS) {
  3935. InsertTailList(&BlLoaderBlock->BootDriverListHead,&DriverEntry->Link);
  3936. }
  3937. }
  3938. return(Status);
  3939. }
  3940. PBOOT_DRIVER_LIST_ENTRY
  3941. SlpCreateDriverEntry(
  3942. IN PCHAR DriverName,
  3943. IN PCHAR ServiceName OPTIONAL
  3944. )
  3945. /*++
  3946. Routine Description:
  3947. Allocates and initializes a boot driver list entry structure.
  3948. Arguments:
  3949. DriverName - Supplies the name of the driver.
  3950. ServiceName - The service name for this driver as it may be different from the driver name.
  3951. Return Value:
  3952. Pointer to the initialized structure.
  3953. --*/
  3954. {
  3955. PBOOT_DRIVER_LIST_ENTRY DriverEntry;
  3956. ANSI_STRING String;
  3957. DriverEntry = BlAllocateHeap(sizeof(BOOT_DRIVER_LIST_ENTRY));
  3958. if (DriverEntry==NULL) {
  3959. SlNoMemoryError();
  3960. return(NULL);
  3961. }
  3962. //
  3963. // when assigning the length, do some checking to make sure we don't
  3964. // overflow. if we do overflow, assign the length value to 0
  3965. // make sure we don't overflow (USHORT)-1 / sizeof(WCHAR) - sizeof(CHAR))
  3966. // we check this value, since the maximum length of the unicode
  3967. // will include the null character, and be twice it's length
  3968. // or (USHORT) -1.
  3969. //
  3970. String.Buffer = DriverName;
  3971. String.Length = (USHORT) RESET_SIZE_AT_VALUE(strlen(DriverName),
  3972. (USHORT)-1 / sizeof(WCHAR) - sizeof(CHAR));
  3973. String.MaximumLength = (String.Length) ? String.Length + sizeof(CHAR) : 0;
  3974. DriverEntry->FilePath.MaximumLength = String.MaximumLength * sizeof(WCHAR);
  3975. DriverEntry->FilePath.Buffer = BlAllocateHeap(DriverEntry->FilePath.MaximumLength);
  3976. if (DriverEntry->FilePath.Buffer==NULL) {
  3977. SlNoMemoryError();
  3978. return(NULL);
  3979. }
  3980. RtlAnsiStringToUnicodeString(&DriverEntry->FilePath, &String, FALSE);
  3981. if(ServiceName != NULL && ServiceName[0] != 0) {
  3982. ANSI_STRING ansi;
  3983. UNICODE_STRING unicode;
  3984. RtlInitString(&ansi, ServiceName);
  3985. DriverEntry->RegistryPath.Length = (SL_REGKEY_SERVICES_LEN + ansi.Length) * sizeof(WCHAR);
  3986. DriverEntry->RegistryPath.MaximumLength = DriverEntry->RegistryPath.Length + sizeof(WCHAR);
  3987. DriverEntry->RegistryPath.Buffer = BlAllocateHeap(DriverEntry->RegistryPath.MaximumLength);
  3988. if(NULL == DriverEntry->RegistryPath.Buffer) {
  3989. SlNoMemoryError();
  3990. return(NULL);
  3991. }
  3992. RtlCopyMemory(DriverEntry->RegistryPath.Buffer, SL_REGKEY_SERVICES_W, SL_REGKEY_SERVICES_LEN * sizeof(WCHAR));
  3993. unicode.MaximumLength = ansi.MaximumLength * sizeof(WCHAR);
  3994. unicode.Buffer = DriverEntry->RegistryPath.Buffer + SL_REGKEY_SERVICES_LEN;
  3995. RtlAnsiStringToUnicodeString(&unicode, &ansi, FALSE);
  3996. DriverEntry->RegistryPath.Buffer[DriverEntry->RegistryPath.Length / sizeof(WCHAR)] = 0;
  3997. }
  3998. return(DriverEntry);
  3999. }
  4000. BOOLEAN
  4001. SlGetDisk(
  4002. IN PCHAR Filename
  4003. )
  4004. /*++
  4005. Routine Description:
  4006. Given a filename, this routine ensures that the correct disk is
  4007. in the drive identified by the global variables BootDevice and
  4008. BootDeviceId. The user may be prompted to change disks.
  4009. Arguments:
  4010. Filename - Supplies the name of the file to be loaded.
  4011. Return Value:
  4012. TRUE - Disk was successfully loaded.
  4013. FALSE - User has cancelled out of Setup.
  4014. --*/
  4015. {
  4016. PCHAR DiskNumber;
  4017. PTCHAR DiskName;
  4018. PCHAR DiskTag;
  4019. ULONG FileId;
  4020. CHAR PlatformSpecificSection[128];
  4021. PCHAR DiskTagSection = NULL;
  4022. //
  4023. // If the media is fixed, the user can't change disks.
  4024. // Just return TRUE indicating that the disk is in the drive.
  4025. //
  4026. if(FixedBootMedia || BlBootingFromNet) {
  4027. return(TRUE);
  4028. }
  4029. //
  4030. // Look up filename to get the disk number. Look in the platform-specific
  4031. // directory first.
  4032. //
  4033. strcpy(PlatformSpecificSection,FilesSectionName);
  4034. strcat(PlatformSpecificSection,PlatformExtension);
  4035. #if defined(ELTORITO)
  4036. if (ElToritoCDBoot) {
  4037. // for Cd boot we use the setup media path instead of a boot-media-specific path
  4038. DiskNumber = SlGetSectionKeyIndex(InfFile,PlatformSpecificSection,Filename,0);
  4039. } else {
  4040. #endif
  4041. DiskNumber = SlGetSectionKeyIndex(InfFile,PlatformSpecificSection,Filename,6);
  4042. #if defined(ELTORITO)
  4043. }
  4044. #endif
  4045. if(DiskNumber == NULL) {
  4046. #if defined(ELTORITO)
  4047. if (ElToritoCDBoot) {
  4048. // for Cd boot we use the setup media path instead of a boot-media-specific path
  4049. DiskNumber = SlGetSectionKeyIndex(InfFile,FilesSectionName,Filename,0);
  4050. } else {
  4051. #endif
  4052. DiskNumber = SlGetSectionKeyIndex(InfFile,FilesSectionName,Filename,6);
  4053. #if defined(ELTORITO)
  4054. }
  4055. #endif
  4056. }
  4057. if((DiskNumber==NULL) || !(*DiskNumber)) {
  4058. SlFatalError(SL_INF_ENTRY_MISSING,SlCopyStringAT(Filename),FilesSectionName);
  4059. return(FALSE);
  4060. }
  4061. //
  4062. // Look up disk number to get the diskname and tag.
  4063. // Look in platform-specific directory first.
  4064. //
  4065. strcpy(PlatformSpecificSection,MediaSectionName);
  4066. strcat(PlatformSpecificSection,PlatformExtension);
  4067. #ifdef UNICODE
  4068. if((DiskName = (PTCHAR)SlGetSectionKeyIndexW(
  4069. #else
  4070. if((DiskName = (PTCHAR)SlGetSectionKeyIndex(
  4071. #endif
  4072. InfFile,
  4073. PlatformSpecificSection,
  4074. DiskNumber,
  4075. 0)) != 0 ) {
  4076. DiskTag = SlGetSectionKeyIndex(InfFile,PlatformSpecificSection,DiskNumber,1);
  4077. DiskTagSection = PlatformSpecificSection;
  4078. } else {
  4079. #ifdef UNICODE
  4080. if((DiskName = (PTCHAR)SlGetSectionKeyIndexW(
  4081. #else
  4082. if((DiskName = (PTCHAR)SlGetSectionKeyIndex(
  4083. #endif
  4084. InfFile,
  4085. MediaSectionName,
  4086. DiskNumber,
  4087. 0)) != 0 ) {
  4088. DiskTag = SlGetSectionKeyIndex(InfFile,MediaSectionName,DiskNumber,1);
  4089. DiskTagSection = MediaSectionName;
  4090. } else {
  4091. SlFatalError(SL_INF_ENTRY_MISSING,SlCopyStringAT(DiskNumber),SlCopyStringAT(MediaSectionName));
  4092. return(FALSE);
  4093. }
  4094. }
  4095. if (!DiskTag) {
  4096. SlFatalError(SL_INF_ENTRY_MISSING,SlCopyStringAT(DiskNumber), SlCopyStringAT(DiskTagSection));
  4097. return FALSE;
  4098. }
  4099. //
  4100. // If this disk is known to be in the drive, don't look again
  4101. //
  4102. if ((LastDiskTag != NULL) && (!strcmp(DiskTag, LastDiskTag))) {
  4103. return(TRUE);
  4104. }
  4105. LastDiskTag = NULL;
  4106. while(1) {
  4107. //
  4108. // Open a new device id onto the disk.
  4109. //
  4110. if(BootDeviceIdValid) {
  4111. ArcClose(BootDeviceId);
  4112. BootDeviceIdValid = FALSE;
  4113. }
  4114. if(ArcOpen(BootDevice,ArcOpenReadOnly,&BootDeviceId) == ESUCCESS) {
  4115. BootDeviceIdValid = TRUE;
  4116. //
  4117. // Check for existence of the disk tag.
  4118. //
  4119. if(BlOpen(BootDeviceId,DiskTag,ArcOpenReadOnly,&FileId) == ESUCCESS) {
  4120. //
  4121. // Disk is in the drive. Return success.
  4122. // Leave BootDeviceId open onto the device.
  4123. //
  4124. BlClose(FileId);
  4125. LastDiskTag = DiskTag;
  4126. return(TRUE);
  4127. } else {
  4128. //
  4129. // Prompt for the user to change disks.
  4130. //
  4131. ArcClose(BootDeviceId);
  4132. BootDeviceIdValid = FALSE;
  4133. SlPromptForDisk(DiskName, FALSE);
  4134. }
  4135. } else {
  4136. //
  4137. // Can't open device. Prompt for the disk.
  4138. //
  4139. SlPromptForDisk(DiskName, FALSE);
  4140. }
  4141. }
  4142. }
  4143. PTCHAR
  4144. SlCopyString(
  4145. IN PTCHAR String
  4146. )
  4147. /*++
  4148. Routine Description:
  4149. Copies a tchar string into the loader heap so it can be passed to the
  4150. kernel.
  4151. Arguments:
  4152. String - Supplies the string to be copied.
  4153. Return Value:
  4154. PTCHAR - pointer into the loader heap where the string was copied to.
  4155. --*/
  4156. {
  4157. PTCHAR Buffer;
  4158. if (String==NULL) {
  4159. SlNoMemoryError();
  4160. return NULL;
  4161. }
  4162. Buffer = BlAllocateHeap(((ULONG)_tcslen(String)+1)*sizeof(TCHAR));
  4163. if (Buffer==NULL) {
  4164. SlNoMemoryError();
  4165. } else {
  4166. _tcscpy(Buffer, String);
  4167. }
  4168. return(Buffer);
  4169. }
  4170. PCHAR
  4171. SlCopyStringA(
  4172. IN PCSTR String
  4173. )
  4174. /*++
  4175. Routine Description:
  4176. Copies an ANSI string into the loader heap so it can be passed to the
  4177. kernel.
  4178. Arguments:
  4179. String - Supplies the string to be copied.
  4180. Return Value:
  4181. PCHAR - pointer into the loader heap where the string was copied to.
  4182. --*/
  4183. {
  4184. PCHAR Buffer;
  4185. if (String==NULL) {
  4186. SlNoMemoryError();
  4187. return NULL;
  4188. }
  4189. Buffer = BlAllocateHeap((ULONG)strlen(String)+1);
  4190. if (Buffer==NULL) {
  4191. SlNoMemoryError();
  4192. } else {
  4193. strcpy(Buffer, String);
  4194. }
  4195. return(Buffer);
  4196. }
  4197. ARC_STATUS
  4198. SlLoadSection(
  4199. IN PVOID Inf,
  4200. IN PCSTR SectionName,
  4201. IN BOOLEAN IsScsiSection,
  4202. IN BOOLEAN AppendLoadSuffix,
  4203. IN OUT PULONG StartingInsertIndex OPTIONAL
  4204. )
  4205. /*++
  4206. Routine Description:
  4207. Enumerates all the drivers in a section and loads them.
  4208. Arguments:
  4209. Inf - Supplies a handle to the INF file.
  4210. SectionName - Supplies the name of the section.
  4211. IsScsiSection - Flag specifying whether this is the Scsi.Load section.
  4212. If so, we create the DETECTED_DEVICE linked list, but
  4213. don't actually load the drivers.
  4214. AppendLoadSuffix - Indicates whether to append the ".load" suffix to the
  4215. section name or not.
  4216. StartingInsertIndex - The position index in the linked list at which
  4217. the device needs to be inserted. The output value
  4218. contains the next available index.
  4219. Return Value:
  4220. ESUCCESS if all drivers were loaded successfully/no errors encountered
  4221. --*/
  4222. {
  4223. ULONG i;
  4224. CHAR LoadSectionName[100];
  4225. PCHAR DriverFilename;
  4226. PCHAR DriverId;
  4227. PTCHAR DriverDescription;
  4228. PCHAR NoLoadSpec;
  4229. PCHAR p;
  4230. ARC_STATUS Status;
  4231. PDETECTED_DEVICE ScsiDevice;
  4232. SCSI_INSERT_STATUS sis;
  4233. ULONG InsertIndex;
  4234. ULONG LoadSectionNameLength = (AppendLoadSuffix) ? (ULONG)strlen(SectionName) + 1 :
  4235. (ULONG)strlen(SectionName) + sizeof(".Load"); // sizeof include \0
  4236. if (sizeof(LoadSectionName) < LoadSectionNameLength ) {
  4237. return ENOMEM;
  4238. }
  4239. strcpy(LoadSectionName, SectionName);
  4240. if (AppendLoadSuffix) {
  4241. strcat(LoadSectionName, ".Load");
  4242. }
  4243. //
  4244. // Use the specified insert index, if its valid
  4245. //
  4246. if (StartingInsertIndex && ((*StartingInsertIndex) != SL_OEM_DEVICE_ORDINAL)) {
  4247. InsertIndex = *StartingInsertIndex;
  4248. } else {
  4249. InsertIndex = 0;
  4250. }
  4251. i=0;
  4252. do {
  4253. DriverFilename = SlGetSectionLineIndex(Inf,LoadSectionName,i,SIF_FILENAME_INDEX);
  4254. NoLoadSpec = SlGetSectionLineIndex(Inf,LoadSectionName,i,2);
  4255. if(DriverFilename && ((NoLoadSpec == NULL) || _stricmp(NoLoadSpec,"noload"))) {
  4256. if(!IsScsiSection) {
  4257. //
  4258. // We only want to load the drivers if they aren't scsi miniports
  4259. //
  4260. DriverId = SlGetKeyName(Inf,LoadSectionName,i);
  4261. #ifdef UNICODE
  4262. DriverDescription = SlGetIniValueW(
  4263. Inf,
  4264. (PSTR)SectionName,
  4265. DriverId,
  4266. SlCopyStringAW(DriverId));
  4267. #else
  4268. DriverDescription = SlGetIniValue(
  4269. Inf,
  4270. (PSTR)SectionName,
  4271. DriverId,
  4272. DriverId);
  4273. #endif
  4274. Status = SlLoadDriver(DriverDescription,
  4275. DriverFilename,
  4276. 0,
  4277. TRUE,
  4278. FALSE,
  4279. NULL
  4280. );
  4281. if((Status == ENOENT) && IgnoreMissingFiles) {
  4282. Status = ESUCCESS;
  4283. }
  4284. } else {
  4285. Status = ESUCCESS;
  4286. }
  4287. if (Status == ESUCCESS) {
  4288. if(IsScsiSection) {
  4289. //
  4290. // Create a new detected device entry.
  4291. //
  4292. if((sis = SlInsertScsiDevice(InsertIndex, &ScsiDevice)) == ScsiInsertError) {
  4293. return(ENOMEM);
  4294. }
  4295. if(sis == ScsiInsertExisting) {
  4296. #if DBG
  4297. //
  4298. // Sanity check to make sure we're talking about the same driver
  4299. //
  4300. if(_stricmp(ScsiDevice->BaseDllName, DriverFilename)) {
  4301. SlError(400);
  4302. return EINVAL;
  4303. }
  4304. #endif
  4305. } else {
  4306. InsertIndex++;
  4307. p = SlGetKeyName(Inf,LoadSectionName,i);
  4308. //
  4309. // Find the driver description
  4310. //
  4311. if(p) {
  4312. #ifdef UNICODE
  4313. DriverDescription = SlGetIniValueW(
  4314. Inf,
  4315. (PSTR)SectionName,
  4316. p,
  4317. SlCopyStringAW(p));
  4318. #else
  4319. DriverDescription = SlGetIniValue(
  4320. Inf,
  4321. (PSTR)SectionName,
  4322. p,
  4323. p);
  4324. #endif
  4325. } else {
  4326. DriverDescription = SlCopyString(BlFindMessage(SL_TEXT_SCSI_UNNAMED));
  4327. }
  4328. ScsiDevice->IdString = p ? p : SlCopyStringA("");
  4329. ScsiDevice->Description = DriverDescription;
  4330. ScsiDevice->ThirdPartyOptionSelected = FALSE;
  4331. ScsiDevice->MigratedDriver = FALSE;
  4332. ScsiDevice->FileTypeBits = 0;
  4333. ScsiDevice->Files = NULL;
  4334. ScsiDevice->BaseDllName = DriverFilename;
  4335. }
  4336. }
  4337. } else {
  4338. SlFriendlyError(
  4339. Status,
  4340. DriverFilename,
  4341. __LINE__,
  4342. __FILE__
  4343. );
  4344. return(Status);
  4345. }
  4346. }
  4347. i++;
  4348. } while ( DriverFilename != NULL );
  4349. if (StartingInsertIndex) {
  4350. *StartingInsertIndex = InsertIndex;
  4351. }
  4352. return(ESUCCESS);
  4353. }
  4354. VOID
  4355. SlpMarkDisks(
  4356. IN BOOLEAN Reboot
  4357. )
  4358. /*++
  4359. Routine Description:
  4360. This routine ensures that there is not more than one disk with the
  4361. same checksum, a signature of zero, and a valid partition table.
  4362. If it finds a disk with a signature of zero, it searches the rest
  4363. of the list for any other disks with a zero signature and the same
  4364. checksum. If it finds one, it stamps a unique signature on the
  4365. first disk.
  4366. We also use a heuristic to determine if the disk is 'vacant', and if
  4367. so, we stamp a unique signature on it (unless it's the first one we
  4368. found).
  4369. Arguments:
  4370. Reboot - Indicates whether to reboot after stamping signatures
  4371. Return Value:
  4372. None.
  4373. --*/
  4374. {
  4375. PARC_DISK_INFORMATION DiskInfo;
  4376. PLIST_ENTRY Entry;
  4377. PLIST_ENTRY CheckEntry;
  4378. PARC_DISK_SIGNATURE DiskSignature;
  4379. PARC_DISK_SIGNATURE CheckDiskSignature;
  4380. ARC_STATUS Status = ESUCCESS;
  4381. BOOLEAN SignatureStamped = FALSE;
  4382. ULONG DiskCount = 0;
  4383. ULONG DisksStamped = 0;
  4384. DiskInfo = BlLoaderBlock->ArcDiskInformation;
  4385. Entry = DiskInfo->DiskSignatures.Flink;
  4386. while (Entry != &DiskInfo->DiskSignatures) {
  4387. DiskSignature = CONTAINING_RECORD(Entry,ARC_DISK_SIGNATURE,ListEntry);
  4388. //
  4389. // Make sure there are no other disks with this same
  4390. // signature.
  4391. //
  4392. CheckEntry = Entry->Flink;
  4393. while( CheckEntry != &DiskInfo->DiskSignatures ) {
  4394. CheckDiskSignature = CONTAINING_RECORD(CheckEntry,ARC_DISK_SIGNATURE,ListEntry);
  4395. if( (CheckDiskSignature->Signature == DiskSignature->Signature) ) {
  4396. //
  4397. // We found another disk with the same disk signature.
  4398. // Stamp a new signature on the disk.
  4399. //
  4400. Status = SlpStampFTSignature(CheckDiskSignature, TRUE);
  4401. SignatureStamped = TRUE;
  4402. DisksStamped++;
  4403. if (Status != ESUCCESS) {
  4404. SlError(Status);
  4405. }
  4406. }
  4407. CheckEntry = CheckEntry->Flink;
  4408. }
  4409. //
  4410. // Now look for disk with no signature.
  4411. //
  4412. if (DiskSignature->ValidPartitionTable) {
  4413. if (DiskSignature->Signature == 0) {
  4414. Status = SlpStampFTSignature(DiskSignature, TRUE);
  4415. SignatureStamped = TRUE;
  4416. DisksStamped++;
  4417. if (Status != ESUCCESS) {
  4418. SlError(Status);
  4419. }
  4420. }
  4421. } else {
  4422. //
  4423. // See if the disk is vacant.
  4424. //
  4425. if (SlpIsDiskVacant(DiskSignature)) {
  4426. //
  4427. // If disk has the signature then use it otherwise
  4428. // stamp a new signature
  4429. //
  4430. Status = SlpStampFTSignature(DiskSignature,
  4431. (BOOLEAN) (DiskSignature->Signature == 0));
  4432. SignatureStamped = TRUE;
  4433. DisksStamped++;
  4434. if (Status != ESUCCESS) {
  4435. SlError(Status);
  4436. }
  4437. }
  4438. }
  4439. DiskCount++;
  4440. Entry = Entry->Flink;
  4441. }
  4442. //
  4443. // We've just changed the signatures on a disk. It might be
  4444. // okay to continue with the boot, but may not. Lets not reboot
  4445. // as textmode setup will bugcheck if the signatures
  4446. // are not stamped correctly.
  4447. //
  4448. if( SignatureStamped) {
  4449. if (Reboot) {
  4450. SlFatalError(SIGNATURE_CHANGED);
  4451. } else {
  4452. //
  4453. // Don't bother rescanning the disks if there is only
  4454. // one disk or we just stamped only one disk
  4455. //
  4456. if ((DiskCount > 1) && (DisksStamped > 1)) {
  4457. Status = BlGetArcDiskInformation(TRUE);
  4458. if (Status != ESUCCESS) {
  4459. SlFatalError(SIGNATURE_CHANGED);
  4460. }else {
  4461. //
  4462. // Reboot if first time signature
  4463. // stamping failed to update the disks
  4464. // correctly
  4465. //
  4466. SlpMarkDisks(TRUE);
  4467. }
  4468. }
  4469. }
  4470. }
  4471. }
  4472. BOOLEAN
  4473. SlpIsDiskVacant(
  4474. IN PARC_DISK_SIGNATURE DiskSignature
  4475. )
  4476. /*++
  4477. Routine Description:
  4478. This routine attempts to determine if a disk is 'vacant' by
  4479. checking to see if the first half of its MBR has all bytes set
  4480. to the same value.
  4481. Arguments:
  4482. DiskSignature - Supplies a pointer to the existing disk
  4483. signature structure.
  4484. Return Value:
  4485. TRUE - The disk is vacant.
  4486. FALSE - The disk is not vacant (ie, we can't determine if it
  4487. is vacant using our heuristic)
  4488. --*/
  4489. {
  4490. UCHAR Partition[100];
  4491. ULONG DiskId;
  4492. ARC_STATUS Status;
  4493. UCHAR SectorBuffer[512+256];
  4494. PUCHAR Sector;
  4495. LARGE_INTEGER SeekValue;
  4496. ULONG Count, i;
  4497. BOOLEAN IsVacant;
  4498. //
  4499. // Open partition0.
  4500. //
  4501. strcpy((PCHAR)Partition, DiskSignature->ArcName);
  4502. strcat((PCHAR)Partition, "partition(0)");
  4503. Status = ArcOpen((PCHAR)Partition, ArcOpenReadOnly, &DiskId);
  4504. if (Status != ESUCCESS) {
  4505. return(FALSE);
  4506. }
  4507. //
  4508. // Read in the first sector
  4509. //
  4510. Sector = ALIGN_BUFFER(SectorBuffer);
  4511. SeekValue.QuadPart = 0;
  4512. Status = ArcSeek(DiskId, &SeekValue, SeekAbsolute);
  4513. if (Status == ESUCCESS) {
  4514. Status = ArcRead(DiskId, Sector, 512, &Count);
  4515. }
  4516. if (Status != ESUCCESS) {
  4517. ArcClose(DiskId);
  4518. return(FALSE);
  4519. }
  4520. //
  4521. // See if 1st 256 bytes are identical
  4522. //
  4523. for(i = 1, IsVacant = TRUE; i<256; i++) {
  4524. if(Sector[i] - *Sector) {
  4525. IsVacant = FALSE;
  4526. break;
  4527. }
  4528. }
  4529. ArcClose(DiskId);
  4530. return(IsVacant);
  4531. }
  4532. ARC_STATUS
  4533. SlpStampFTSignature(
  4534. IN PARC_DISK_SIGNATURE DiskSignature,
  4535. IN BOOLEAN GenerateNewSignature
  4536. )
  4537. /*++
  4538. Routine Description:
  4539. This routine stamps a given drive with a unique signature.
  4540. It traverses the list of disk signatures to ensure that it
  4541. stamps a signature that is not already present in the
  4542. disk list. Then it writes the new disk signature to the
  4543. disk and recomputes the checksum.
  4544. Arguments:
  4545. DiskSignature - Supplies a pointer to the existing disk
  4546. signature structure.
  4547. GenerateNewSignature - Indicates whether to generate a new
  4548. signature or use the one in DiskSignature. When TRUE
  4549. this will also disable the check of duplicate signatures.
  4550. This argument is ignored when the DiskSignature->Signature
  4551. field is 0, since 0 is not a valid signature
  4552. Return Value:
  4553. None.
  4554. --*/
  4555. {
  4556. ULONG NewSignature;
  4557. PLIST_ENTRY ListEntry;
  4558. UCHAR SectorBuffer[SECTOR_SIZE * 2];
  4559. PUCHAR Sector;
  4560. LARGE_INTEGER SeekValue;
  4561. UCHAR Partition[100];
  4562. PARC_DISK_SIGNATURE Signature;
  4563. ULONG DiskId;
  4564. ARC_STATUS Status;
  4565. ULONG i;
  4566. ULONG Sum;
  4567. ULONG Count;
  4568. if (GenerateNewSignature || (DiskSignature->Signature == 0)) {
  4569. //
  4570. // Get a reasonably unique seed to start with.
  4571. //
  4572. NewSignature = ArcGetRelativeTime();
  4573. NewSignature = (NewSignature & 0xFFFF) << 16;
  4574. NewSignature += ArcGetRelativeTime();
  4575. //
  4576. // Scan through the list to make sure it's unique.
  4577. //
  4578. ReScan:
  4579. ListEntry = BlLoaderBlock->ArcDiskInformation->DiskSignatures.Flink;
  4580. while (ListEntry != &BlLoaderBlock->ArcDiskInformation->DiskSignatures) {
  4581. Signature = CONTAINING_RECORD(ListEntry,ARC_DISK_SIGNATURE,ListEntry);
  4582. if (Signature->Signature == NewSignature) {
  4583. //
  4584. // Found a duplicate, pick a new number and
  4585. // try again.
  4586. //
  4587. if (++NewSignature == 0) {
  4588. //
  4589. // zero signatures are what we're trying to avoid
  4590. // (like this will ever happen)
  4591. //
  4592. NewSignature = 1;
  4593. }
  4594. goto ReScan;
  4595. }
  4596. ListEntry = ListEntry->Flink;
  4597. }
  4598. } else {
  4599. NewSignature = DiskSignature->Signature;
  4600. }
  4601. //
  4602. // Now we have a valid new signature to put on the disk.
  4603. // Read the sector off disk, put the new signature in,
  4604. // write the sector back, and recompute the checksum.
  4605. //
  4606. strcpy((PCHAR)Partition,DiskSignature->ArcName);
  4607. strcat((PCHAR)Partition,"partition(0)");
  4608. Status = ArcOpen((PCHAR)Partition, ArcOpenReadWrite, &DiskId);
  4609. if (Status != ESUCCESS) {
  4610. return(Status);
  4611. }
  4612. //
  4613. // Read in the first sector
  4614. //
  4615. Sector = ALIGN_BUFFER_WITH_SIZE(SectorBuffer, SECTOR_SIZE);
  4616. SeekValue.QuadPart = 0;
  4617. Status = ArcSeek(DiskId, &SeekValue, SeekAbsolute);
  4618. if (Status == ESUCCESS) {
  4619. Status = ArcRead(DiskId,Sector,512,&Count);
  4620. }
  4621. if (Status != ESUCCESS) {
  4622. ArcClose(DiskId);
  4623. return(Status);
  4624. }
  4625. //
  4626. // If partition table is not valid then initialize it with BOOT_RECORD_SIGNATURE and
  4627. // fill partition entries with zeros
  4628. //
  4629. if (((USHORT UNALIGNED *)Sector)[BOOT_SIGNATURE_OFFSET] != BOOT_RECORD_SIGNATURE) {
  4630. memset(Sector + (PARTITION_TABLE_OFFSET * 2),
  4631. 0,
  4632. SECTOR_SIZE - (PARTITION_TABLE_OFFSET * 2));
  4633. ((USHORT UNALIGNED *)Sector)[BOOT_SIGNATURE_OFFSET] = BOOT_RECORD_SIGNATURE;
  4634. }
  4635. ((ULONG UNALIGNED *)Sector)[PARTITION_TABLE_OFFSET/2-1] = NewSignature;
  4636. Status = ArcSeek(DiskId, &SeekValue, SeekAbsolute);
  4637. if (Status == ESUCCESS) {
  4638. Status = ArcWrite(DiskId,Sector,512,&Count);
  4639. }
  4640. ArcClose(DiskId);
  4641. if (Status != ESUCCESS) {
  4642. return(Status);
  4643. }
  4644. //
  4645. // We have successfully written back out the new signature,
  4646. // recompute the checksum.
  4647. //
  4648. DiskSignature->Signature = NewSignature;
  4649. DiskSignature->ValidPartitionTable = TRUE;
  4650. Sum = 0;
  4651. for (i=0;i<128;i++) {
  4652. Sum += ((PULONG)Sector)[i];
  4653. }
  4654. DiskSignature->CheckSum = 0-Sum;
  4655. return(ESUCCESS);
  4656. }
  4657. VOID
  4658. SlCheckOemKeypress(
  4659. IN ULONG WaitTime
  4660. )
  4661. {
  4662. ULONG StartTime;
  4663. ULONG EndTime;
  4664. ULONG c;
  4665. PTCHAR StatusText;
  4666. //
  4667. // For no particular reason some machines occasionally leave F7s
  4668. // in their keyboard buffer. Drain them out here.
  4669. //
  4670. #ifdef EFI
  4671. //
  4672. // disable EFI watchdog when draining keyboard buffer
  4673. //
  4674. DisableEFIWatchDog();
  4675. #endif
  4676. while (ArcGetReadStatus(ARC_CONSOLE_INPUT) == ESUCCESS) {
  4677. c = SlGetChar();
  4678. switch (c) {
  4679. case SL_KEY_F5: // Force OEM HAL prompt
  4680. PromptOemHal = TRUE;
  4681. break;
  4682. case SL_KEY_F6: // Force OEM SCSI prompt
  4683. PromptOemScsi = TRUE;
  4684. break;
  4685. }
  4686. }
  4687. #ifdef EFI
  4688. //
  4689. // reset EFI watchdog
  4690. //
  4691. SetEFIWatchDog(EFI_WATCHDOG_TIMEOUT);
  4692. #endif
  4693. //
  4694. // HACK alert: The oem hal and SCSI stuff doesn't make sense in an RIS
  4695. // environment. Instead, the administrator should put the oem drivers
  4696. // on the RIS server. So we don't display the OEM drivers prompt, instead
  4697. // we hide it with some bogus "please wait" text. We do this instead of
  4698. // just skipping the check altogether so that the user will still have a
  4699. // chance to press F7 to disable ACPI.
  4700. //
  4701. StatusText = BlFindMessage(
  4702. BlBootingFromNet
  4703. ? SL_PLEASE_WAIT
  4704. : SL_MSG_PRESS_F5_OR_F6);
  4705. if( StatusText != NULL ) {
  4706. SlWriteStatusText(StatusText);
  4707. }
  4708. StartTime = ArcGetRelativeTime();
  4709. if (WinPEBoot) {
  4710. EndTime = StartTime + WaitTime;
  4711. } else {
  4712. EndTime = StartTime + WaitTime;
  4713. }
  4714. do {
  4715. if(ArcGetReadStatus(ARC_CONSOLE_INPUT) == ESUCCESS) {
  4716. //
  4717. // There is a key pending, so see what it is.
  4718. //
  4719. c = SlGetChar();
  4720. switch(c) {
  4721. case SL_KEY_F4: // Disable OEM virtual devices.
  4722. DisableVirtualOemDevices = TRUE;
  4723. break;
  4724. case SL_KEY_F5: // Force OEM HAL prompt
  4725. PromptOemHal = TRUE;
  4726. break;
  4727. case SL_KEY_F6: // Force OEM SCSI prompt
  4728. PromptOemScsi = TRUE;
  4729. break;
  4730. case SL_KEY_F7:
  4731. DisableACPI = TRUE; // Force ACPI disabled
  4732. break;
  4733. case SL_KEY_F8: // Enable debugger
  4734. EnableDebugger = TRUE;
  4735. break;
  4736. case SL_KEY_F10:
  4737. UseCommandConsole = TRUE; // User wants to use cmdcons
  4738. break;
  4739. }
  4740. }
  4741. } while (EndTime > ArcGetRelativeTime());
  4742. //
  4743. // see comment above -- we reset these values back to FALSE in the RIS
  4744. // scenario because they don't make sense
  4745. //
  4746. if (BlBootingFromNet) {
  4747. PromptOemHal = FALSE;
  4748. PromptOemScsi = FALSE;
  4749. } else {
  4750. SlWriteStatusText(TEXT(""));
  4751. }
  4752. }
  4753. VOID
  4754. SlCheckASRKeypress(
  4755. VOID
  4756. )
  4757. /*++
  4758. Routine Description:
  4759. See if the user is doing an ASR. If so, see if he's got a floppy
  4760. with asrpnp.sif on it. We'll ask him to press F5 for this.
  4761. Arguments:
  4762. None.
  4763. Return Value:
  4764. None.
  4765. --*/
  4766. {
  4767. ARC_STATUS Status;
  4768. #define ASR_FILE "asrpnp.sif"
  4769. ULONG StartTime;
  4770. ULONG EndTime;
  4771. ULONG c;
  4772. PTCHAR StatusText;
  4773. CHAR FloppyName[80];
  4774. ULONG FloppyId;
  4775. CHAR FileName[128];
  4776. PVOID ASRPNPSifHandle = NULL;
  4777. BOOLEAN PromptASR = FALSE;
  4778. BOOLEAN Done = FALSE;
  4779. BOOLEAN FirstTry = TRUE;
  4780. #if defined(EFI)
  4781. //
  4782. // Turn off the EFI Watchdog
  4783. //
  4784. DisableEFIWatchDog();
  4785. #endif
  4786. do {
  4787. SlClearClientArea();
  4788. //
  4789. // Drain the keyboard buffer.
  4790. //
  4791. while (ArcGetReadStatus(ARC_CONSOLE_INPUT) == ESUCCESS) {
  4792. c = SlGetChar();
  4793. }
  4794. if (FirstTry) {
  4795. StatusText = BlFindMessage(SL_MSG_PRESS_ASR);
  4796. FirstTry = FALSE;
  4797. }
  4798. else {
  4799. StatusText = BlFindMessage(SL_MSG_PREPARING_ASR);
  4800. }
  4801. if( StatusText != NULL ) {
  4802. SlWriteStatusText(StatusText);
  4803. }
  4804. StartTime = ArcGetRelativeTime();
  4805. EndTime = StartTime + 5;
  4806. do {
  4807. if(ArcGetReadStatus(ARC_CONSOLE_INPUT) == ESUCCESS) {
  4808. //
  4809. // There is a key pending, so see what it is.
  4810. //
  4811. c = SlGetChar();
  4812. switch(c) {
  4813. case SL_KEY_F2: // Force ASR prompt
  4814. PromptASR = TRUE;
  4815. Done = TRUE;
  4816. break;
  4817. case ASCI_ESC:
  4818. PromptASR = FALSE;
  4819. Done = TRUE;
  4820. break;
  4821. }
  4822. }
  4823. } while( !Done && (EndTime > ArcGetRelativeTime()) );
  4824. SlWriteStatusText(TEXT(""));
  4825. if( PromptASR ) {
  4826. Done = FALSE;
  4827. StatusText = BlFindMessage(SL_MSG_ENTERING_ASR);
  4828. if( StatusText != NULL ) {
  4829. SlWriteStatusText(StatusText);
  4830. }
  4831. //
  4832. // Build the filename we're looking for.
  4833. //
  4834. strcpy( FileName, "\\" );
  4835. strcat( FileName, ASR_FILE );
  4836. //
  4837. // Initialize pointers in loader block.
  4838. //
  4839. BlLoaderBlock->SetupLoaderBlock->ASRPnPSifFile = NULL;
  4840. BlLoaderBlock->SetupLoaderBlock->ASRPnPSifFileLength = 0;
  4841. Status = ESUCCESS;
  4842. //
  4843. // Try checking the installation media for asrpnp.sif
  4844. //
  4845. Status = SlInitIniFile( NULL,
  4846. BootDeviceId,
  4847. FileName,
  4848. &ASRPNPSifHandle,
  4849. &BlLoaderBlock->SetupLoaderBlock->ASRPnPSifFile,
  4850. &BlLoaderBlock->SetupLoaderBlock->ASRPnPSifFileLength,
  4851. &c );
  4852. if (ESUCCESS != Status) {
  4853. //
  4854. // Installation media doesn't contain the ASR files, we're
  4855. // going to have to prompt for the ASR floppy.
  4856. //
  4857. // Build the path to the floppy.
  4858. //
  4859. if (SlpFindFloppy(0,FloppyName)) {
  4860. Status = ArcOpen(FloppyName,ArcOpenReadOnly,&FloppyId);
  4861. //
  4862. // We found the floppy and opened him. See if he's
  4863. // got our file.
  4864. //
  4865. if( Status == ESUCCESS ) {
  4866. ASRPNPSifHandle = NULL;
  4867. Status = SlInitIniFile( NULL,
  4868. FloppyId,
  4869. FileName,
  4870. &ASRPNPSifHandle,
  4871. &BlLoaderBlock->SetupLoaderBlock->ASRPnPSifFile,
  4872. &BlLoaderBlock->SetupLoaderBlock->ASRPnPSifFileLength,
  4873. &c );
  4874. ArcClose(FloppyId);
  4875. }
  4876. }
  4877. }
  4878. //
  4879. // See if we successfully loaded the file off the
  4880. // floppy.
  4881. //
  4882. SlWriteStatusText(TEXT(""));
  4883. if( (Status != ESUCCESS) ||
  4884. (BlLoaderBlock->SetupLoaderBlock->ASRPnPSifFile == NULL) ) {
  4885. //
  4886. // Missed. Inform the user and we'll try again.
  4887. //
  4888. SlMessageBox(SL_MSG_WARNING_ASR);
  4889. } else if (BlLoaderBlock->SetupLoaderBlock->ASRPnPSifFileLength == 0) {
  4890. //
  4891. // Invalid ASR file: inform user and we'll try again
  4892. //
  4893. StatusText = BlFindMessage(SL_MSG_INVALID_ASRPNP_FILE);
  4894. //
  4895. // First display the ASR insert floppy message
  4896. //
  4897. SlDisplayMessageBox(SL_MSG_WARNING_ASR);
  4898. //
  4899. // Populate status area with the error
  4900. //
  4901. if( StatusText != NULL ) {
  4902. SlWriteStatusText(StatusText);
  4903. }
  4904. //
  4905. // Now wait for user to hit a key
  4906. //
  4907. SlFlushConsoleBuffer();
  4908. SlGetChar();
  4909. //
  4910. // Clear status just in case ...
  4911. //
  4912. if( StatusText != NULL ) {
  4913. SlWriteStatusText(TEXT(""));
  4914. }
  4915. } else {
  4916. Done = TRUE;
  4917. }
  4918. }
  4919. } while( PromptASR && !Done );
  4920. #if defined(EFI)
  4921. //
  4922. // Turn EFI Watchdog back on
  4923. //
  4924. SetEFIWatchDog(EFI_WATCHDOG_TIMEOUT);
  4925. #endif
  4926. }
  4927. SCSI_INSERT_STATUS
  4928. SlInsertScsiDevice(
  4929. IN ULONG Ordinal,
  4930. OUT PDETECTED_DEVICE *pScsiDevice
  4931. )
  4932. /*++
  4933. Routine Description:
  4934. This routine
  4935. Arguments:
  4936. Ordinal - Supplies the 0-based ordinal of the Scsi device
  4937. to insert (based on order listed in [Scsi.Load]
  4938. section of txtsetup.sif). If the Scsi device is a third party
  4939. driver, then Ordinal is -1 (SL_OEM_DEVICE_ORDINAL).
  4940. pScsiDevice - Receives a pointer to the inserted DETECTED_DEVICE structure,
  4941. the existing structure, or NULL.
  4942. Return Value:
  4943. ScsiInsertError - Not enough memory to allocate a new DETECTED_DEVICE.
  4944. ScsiInsertNewEntry - A new entry was inserted into the DETECTED_DEVICE list.
  4945. ScsiInsertExisting - An existing entry was found that matched the specified
  4946. ordinal, so we returned this entry.
  4947. --*/
  4948. {
  4949. PDETECTED_DEVICE prev, cur;
  4950. if(Ordinal == SL_OEM_DEVICE_ORDINAL) {
  4951. //
  4952. // This is a third-party driver, so find the end of the linked list
  4953. // (we want to preserve the order in which the user specifies the drivers).
  4954. //
  4955. for(prev=BlLoaderBlock->SetupLoaderBlock->ScsiDevices, cur = NULL;
  4956. prev && prev->Next;
  4957. prev=prev->Next);
  4958. } else {
  4959. //
  4960. // Find the insertion point in the linked list for this driver,
  4961. // based on its ordinal. (Note that we will insert all supported drivers
  4962. // before any third-party ones, since (ULONG)-1 = maximum unsigned long value)
  4963. //
  4964. for(prev = NULL, cur = BlLoaderBlock->SetupLoaderBlock->ScsiDevices;
  4965. cur && (Ordinal > cur->Ordinal);
  4966. prev = cur, cur = cur->Next);
  4967. }
  4968. if(cur && (cur->Ordinal == Ordinal)) {
  4969. //
  4970. // We found an existing entry for this driver
  4971. //
  4972. *pScsiDevice = cur;
  4973. return ScsiInsertExisting;
  4974. }
  4975. if((*pScsiDevice = BlAllocateHeap(sizeof(DETECTED_DEVICE))) == 0) {
  4976. return ScsiInsertError;
  4977. }
  4978. (*pScsiDevice)->Next = cur;
  4979. if(prev) {
  4980. prev->Next = *pScsiDevice;
  4981. } else {
  4982. BlLoaderBlock->SetupLoaderBlock->ScsiDevices = *pScsiDevice;
  4983. }
  4984. (*pScsiDevice)->Ordinal = Ordinal;
  4985. return ScsiInsertNewEntry;
  4986. }
  4987. ARC_STATUS
  4988. SlLoadPnpDriversSection(
  4989. IN PVOID Inf,
  4990. IN PCHAR SectionName,
  4991. IN OUT PDETECTED_DEVICE* DetectedDeviceList OPTIONAL
  4992. )
  4993. /*++
  4994. Routine Description:
  4995. Enumerates all pnp drivers listed in [<section name>.Load], loads them, and puts
  4996. a list with all the the drivers loaded, in the setup loader block.
  4997. Arguments:
  4998. Inf - Supplies a handle to the INF file.
  4999. SectionName - Name of the section in the inf file that contains the list of
  5000. drivers to be loaded.
  5001. DetectedDeviceList - Address of the variable in Setup loader block that will contain
  5002. the list of drivers loaded. If this argument is NULL, then the list of
  5003. loaded devices will not be created.
  5004. Return Value:
  5005. ESUCCESS if all drivers were loaded successfully/no errors encountered
  5006. --*/
  5007. {
  5008. ULONG i;
  5009. CHAR LoadSectionName[100];
  5010. PCHAR DriverFilename;
  5011. PCHAR DriverId;
  5012. PTCHAR DriverDescription;
  5013. PCHAR NoLoadSpec;
  5014. ARC_STATUS Status;
  5015. PDETECTED_DEVICE TempDevice;
  5016. sprintf(LoadSectionName, "%s.Load",SectionName);
  5017. i=0;
  5018. do {
  5019. DriverFilename = SlGetSectionLineIndex(Inf,LoadSectionName,i,SIF_FILENAME_INDEX);
  5020. NoLoadSpec = SlGetSectionLineIndex(Inf,LoadSectionName,i,2);
  5021. if(DriverFilename && ((NoLoadSpec == NULL) || _stricmp(NoLoadSpec,"noload"))) {
  5022. DriverId = SlGetKeyName(Inf,LoadSectionName,i);
  5023. #ifdef UNICODE
  5024. DriverDescription = SlGetIniValueW(
  5025. Inf,
  5026. SectionName,
  5027. DriverId,
  5028. SlCopyStringAW(DriverId));
  5029. #else
  5030. DriverDescription = SlGetIniValue(
  5031. Inf,
  5032. SectionName,
  5033. DriverId,
  5034. DriverId);
  5035. #endif
  5036. Status = SlLoadDriver(DriverDescription,
  5037. DriverFilename,
  5038. 0,
  5039. TRUE,
  5040. FALSE,
  5041. NULL
  5042. );
  5043. // if((Status == ENOENT) && IgnoreMissingFiles) {
  5044. // Status = ESUCCESS;
  5045. // }
  5046. if (Status == ESUCCESS) {
  5047. if( DetectedDeviceList != NULL ) {
  5048. //
  5049. // if the enumerator loaded, then record DETECTED_DEVICE info
  5050. //
  5051. TempDevice = BlAllocateHeap(sizeof(DETECTED_DEVICE));
  5052. if(!TempDevice) {
  5053. SlNoMemoryError();
  5054. return ENOMEM;
  5055. }
  5056. TempDevice->IdString = SlCopyStringA(DriverId);
  5057. TempDevice->Description = DriverDescription;
  5058. TempDevice->ThirdPartyOptionSelected = FALSE;
  5059. TempDevice->MigratedDriver = FALSE;
  5060. TempDevice->FileTypeBits = 0;
  5061. TempDevice->BaseDllName = SlCopyStringA(DriverFilename);
  5062. TempDevice->Next = *DetectedDeviceList;
  5063. *DetectedDeviceList = TempDevice;
  5064. }
  5065. } else {
  5066. SlFriendlyError(
  5067. Status,
  5068. DriverFilename,
  5069. __LINE__,
  5070. __FILE__
  5071. );
  5072. return(Status);
  5073. }
  5074. }
  5075. i++;
  5076. } while ( DriverFilename != NULL );
  5077. return(ESUCCESS);
  5078. }
  5079. ARC_STATUS
  5080. SlDetectMigratedScsiDrivers(
  5081. IN PVOID Inf
  5082. )
  5083. /*++
  5084. Routine Description:
  5085. Create an entry in the ScsiDevice list for each migrated SCSI driver.
  5086. Arguments:
  5087. Inf - Supplies a handle to the INF file.
  5088. Return Value:
  5089. ESUCCESS if all drivers were added to the ScsiDevice list.
  5090. --*/
  5091. {
  5092. ULONG i;
  5093. CHAR LoadSectionName[100];
  5094. PCHAR DriverFilename;
  5095. PCHAR DriverId;
  5096. PTCHAR DriverDescription;
  5097. PDETECTED_DEVICE ScsiDevice;
  5098. SCSI_INSERT_STATUS sis;
  5099. i=0;
  5100. do {
  5101. DriverId = SlGetSectionLineIndex(Inf,"Devices",i,0);
  5102. if( DriverId ) {
  5103. sprintf(LoadSectionName, "Files.%s", DriverId);
  5104. DriverFilename = SlGetSectionLineIndex(Inf,LoadSectionName,0,0);
  5105. if(DriverFilename) {
  5106. //
  5107. // Remove inbox drivers with the same name as a winnt32-migrated OEM driver (if any)
  5108. //
  5109. SlRemoveInboxDriver (DriverFilename);
  5110. //
  5111. // Create a new detected device entry.
  5112. //
  5113. if((sis = SlInsertScsiDevice(SL_OEM_DEVICE_ORDINAL, &ScsiDevice)) == ScsiInsertError) {
  5114. return(ENOMEM);
  5115. }
  5116. if(sis == ScsiInsertExisting) {
  5117. #if DBG
  5118. //
  5119. // Sanity check to make sure we're talking about the same driver
  5120. //
  5121. if(_stricmp(ScsiDevice->BaseDllName, DriverFilename)) {
  5122. SlError(400);
  5123. return EINVAL;
  5124. }
  5125. #endif
  5126. } else {
  5127. DriverDescription = SlCopyString(BlFindMessage(SL_TEXT_SCSI_UNNAMED));
  5128. ScsiDevice->IdString = DriverId;
  5129. ScsiDevice->Description = DriverDescription;
  5130. ScsiDevice->ThirdPartyOptionSelected = FALSE;
  5131. ScsiDevice->MigratedDriver = TRUE;
  5132. ScsiDevice->FileTypeBits = 0;
  5133. ScsiDevice->Files = NULL;
  5134. ScsiDevice->BaseDllName = DriverFilename;
  5135. }
  5136. }
  5137. }
  5138. i++;
  5139. } while ( DriverId != NULL );
  5140. return(ESUCCESS);
  5141. }
  5142. ARC_STATUS
  5143. SlGetMigratedHardwareIds(
  5144. IN PSETUP_LOADER_BLOCK SetupBlock,
  5145. IN PVOID Inf
  5146. )
  5147. /*++
  5148. Routine Description:
  5149. Add the hardware ids for the migrated scsi drivers, to the hardware id list.
  5150. Arguments:
  5151. SetupBlock - Supplies a pointer to the Setup loader block
  5152. Return Value:
  5153. ESUCCESS if all hardware ids were added to the hardware id list
  5154. --*/
  5155. {
  5156. PCHAR DriverId;
  5157. ULONG i, j;
  5158. PPNP_HARDWARE_ID TempHardwareId;
  5159. PCHAR p;
  5160. for( j = 0;
  5161. (DriverId = SlGetSectionLineIndex(Inf,"Devices",j,0)) != NULL;
  5162. j++ ) {
  5163. CHAR SectionName[100];
  5164. sprintf(SectionName, "HardwareIds.%s", DriverId);
  5165. for( i = 0;
  5166. ((p = SlGetKeyName( Inf, SectionName, i )) != NULL);
  5167. i++ ) {
  5168. TempHardwareId = BlAllocateHeap(sizeof(PNP_HARDWARE_ID));
  5169. if (TempHardwareId==NULL) {
  5170. SlNoMemoryError();
  5171. return ENOMEM;
  5172. }
  5173. TempHardwareId->Id = p;
  5174. p = SlGetSectionKeyIndex( Inf,
  5175. SectionName,
  5176. TempHardwareId->Id,
  5177. 0 );
  5178. TempHardwareId->DriverName = p;
  5179. p = SlGetSectionKeyIndex( Inf,
  5180. SectionName,
  5181. TempHardwareId->Id,
  5182. 1 );
  5183. TempHardwareId->ClassGuid = p;
  5184. TempHardwareId->Next = SetupBlock->HardwareIdDatabase;
  5185. SetupBlock->HardwareIdDatabase = TempHardwareId;
  5186. }
  5187. }
  5188. return( ESUCCESS );
  5189. }
  5190. BOOLEAN
  5191. SlIsCdBootUpgrade(
  5192. IN PCHAR InstallDirectory,
  5193. IN PCHAR SetupFileName,
  5194. IN ULONG MaxDisksToScan,
  5195. IN ULONG MaxPartitionsPerDisk,
  5196. OUT PCHAR NewSetupDevice
  5197. )
  5198. /*++
  5199. Routine Description:
  5200. Finds out by looking into the hard disk if the specified
  5201. directory exists and if the the user was indeed
  5202. trying to uprgade
  5203. Arguments:
  5204. InstallDirectory - Directory used on the hard disk
  5205. for installation
  5206. SetupFileName - Inf file name which has the key which
  5207. indicates if upgrade was in progress or
  5208. not
  5209. MaxDisksToScan - Maximum number of disks to scan
  5210. MaxPartitionsPerDisk - Maximum partitions per disk to look into
  5211. for the install directory.
  5212. NewSetupDevice - Place holder for arc name for the device
  5213. if user wants to switch to harddisk boot.
  5214. Return Value:
  5215. TRUE if upgrade was in progress and user selected to continue on
  5216. otherwise FALSE.
  5217. --*/
  5218. {
  5219. BOOLEAN Result = FALSE;
  5220. CHAR DeviceName[128];
  5221. ARC_STATUS Status;
  5222. ULONG CurrentPartition;
  5223. ULONG CurrentDisk;
  5224. //
  5225. // Go through each disk
  5226. //
  5227. for (CurrentDisk = 0;
  5228. (!Result && (CurrentDisk < MaxDisksToScan));
  5229. CurrentDisk++) {
  5230. Status = ESUCCESS;
  5231. //
  5232. // Go through each valid partition
  5233. // for the current disk
  5234. //
  5235. for (CurrentPartition = 1;
  5236. (!Result && (Status == ESUCCESS));
  5237. CurrentPartition++) {
  5238. ULONG DiskId;
  5239. sprintf(DeviceName,
  5240. "multi(0)disk(0)rdisk(%d)partition(%d)",
  5241. CurrentDisk,
  5242. CurrentPartition);
  5243. Status = ArcOpen(DeviceName, ArcOpenReadOnly, &DiskId);
  5244. if (Status == ESUCCESS) {
  5245. CHAR FullName[128];
  5246. PVOID SifHandle = NULL;
  5247. ULONG ErrorLine = 0;
  5248. ARC_STATUS FileStatus;
  5249. //
  5250. // Function does not support the return of failures.
  5251. // so lets just truncate the string
  5252. //
  5253. _snprintf(FullName,
  5254. sizeof(FullName),
  5255. "%s\\%s",
  5256. InstallDirectory,
  5257. SetupFileName);
  5258. FullName[sizeof(FullName) - 1] = '\0';
  5259. FileStatus = SlInitIniFile(NULL,
  5260. DiskId,
  5261. FullName,
  5262. &SifHandle,
  5263. NULL,
  5264. NULL,
  5265. &ErrorLine);
  5266. if ((FileStatus == ESUCCESS) && SifHandle) {
  5267. Result = SlIsUpgrade(SifHandle);
  5268. }
  5269. ArcClose(DiskId);
  5270. } else {
  5271. //
  5272. // Ignore the error till the maximum number of
  5273. // partitions are searched for
  5274. //
  5275. if (CurrentPartition < MaxPartitionsPerDisk) {
  5276. Status = ESUCCESS;
  5277. }
  5278. }
  5279. }
  5280. }
  5281. if (Result) {
  5282. ULONG UserInput;
  5283. BOOLEAN OldStatus = SlGetStatusBarStatus();
  5284. //
  5285. // Reset the result based on user input
  5286. //
  5287. Result = FALSE;
  5288. SlEnableStatusBar(FALSE);
  5289. SlClearClientArea();
  5290. SlDisplayMessageBox(SL_UPGRADE_IN_PROGRESS);
  5291. #ifdef EFI
  5292. //
  5293. // disable watchdog timer for user input
  5294. //
  5295. DisableEFIWatchDog();
  5296. #endif
  5297. do {
  5298. SlFlushConsoleBuffer();
  5299. UserInput = SlGetChar();
  5300. }
  5301. while ((UserInput != ASCI_CR) &&
  5302. (UserInput != SL_KEY_F3) &&
  5303. (UserInput != SL_KEY_F10));
  5304. #ifdef EFI
  5305. //
  5306. // reset watchdog timer
  5307. //
  5308. SetEFIWatchDog(EFI_WATCHDOG_TIMEOUT);
  5309. #endif
  5310. SlClearClientArea();
  5311. if (UserInput == SL_KEY_F3) {
  5312. ArcRestart();
  5313. } else if (UserInput == ASCI_CR) {
  5314. Result = TRUE;
  5315. strcpy(NewSetupDevice, DeviceName);
  5316. }
  5317. SlEnableStatusBar(OldStatus);
  5318. }
  5319. return Result;
  5320. }
  5321. BOOLEAN
  5322. SlIsUpgrade(
  5323. IN PVOID SifHandle
  5324. )
  5325. /*++
  5326. Routine Description:
  5327. Finds out by looking into the SIF file if upgrade is
  5328. in progress or not
  5329. Arguments:
  5330. InfHandle - Handle to winnt.sif file
  5331. Return Value:
  5332. TRUE if upgrade is in progress otherwise FALSE
  5333. --*/
  5334. {
  5335. BOOLEAN Result = FALSE;
  5336. if (SifHandle) {
  5337. PCHAR NtUpgrade = SlGetSectionKeyIndex(SifHandle,
  5338. WINNT_DATA_A,
  5339. WINNT_D_NTUPGRADE_A,
  5340. 0);
  5341. if (NtUpgrade) {
  5342. Result = (BOOLEAN) (_stricmp(NtUpgrade, WINNT_A_YES_A) == 0);
  5343. }
  5344. if (!Result) {
  5345. PCHAR Win9xUpgrade = SlGetSectionKeyIndex(SifHandle,
  5346. WINNT_DATA_A,
  5347. WINNT_D_WIN95UPGRADE_A,
  5348. 0);
  5349. if (Win9xUpgrade) {
  5350. Result = (BOOLEAN) (_stricmp(Win9xUpgrade, WINNT_A_YES_A) == 0);
  5351. }
  5352. }
  5353. }
  5354. return Result;
  5355. }
  5356. BOOLEAN
  5357. SlIsVirtualOemDeviceDisabled(
  5358. IN PVOID SifHandle,
  5359. IN PPREINSTALL_DRIVER_INFO PreinstallDriverList
  5360. )
  5361. /*++
  5362. Routine Description:
  5363. Finds out if we need to enable or disable the loading of virtual OEM devices.
  5364. Arguments:
  5365. InfHandle - Handle to winnt.sif file
  5366. PreinstallDriverList - PreInstall Driver List
  5367. Return Value:
  5368. BOOLEAN, TRUE/FALSE
  5369. --*/
  5370. {
  5371. if((!DisableVirtualOemDevices) && (SifHandle)){
  5372. //
  5373. // Is Preinstall?
  5374. //
  5375. if (PreinstallDriverList != NULL){
  5376. DisableVirtualOemDevices = TRUE;
  5377. }else{
  5378. PCHAR p;
  5379. p = SlGetSectionKeyIndex(SifHandle,
  5380. WINNT_UNATTENDED_A,
  5381. WINNT_DISABLE_VIRTUAL_OEM_DEVICES_A,
  5382. 0);
  5383. //
  5384. // In case of unattended setup.
  5385. // if we have set the option in the unattend file DisableVirtualOemDevices = yes
  5386. // then disable the virtual oem source devices
  5387. //
  5388. if(p && (!_stricmp(p ,WINNT_A_YES_A))) {
  5389. DisableVirtualOemDevices = TRUE;
  5390. }
  5391. }
  5392. }
  5393. return DisableVirtualOemDevices;
  5394. }
  5395. VOID
  5396. SlDisableVirtualOemDevices(
  5397. IN POEM_SOURCE_DEVICE OemDeviceList
  5398. )
  5399. /*++
  5400. Routine Description:
  5401. Marks the Virtual Oem Devices as Skipped.
  5402. Arguments:
  5403. OemDeviceList - The list of OEM devices
  5404. Return Value:
  5405. None.
  5406. --*/
  5407. {
  5408. //
  5409. // If the DisableVirtualOemDevices is set to TRUE mark the Virtual OEM devices
  5410. // as skipped.
  5411. //
  5412. if ((DisableVirtualOemDevices) && (OemDeviceList)){
  5413. POEM_SOURCE_DEVICE CurrentDevice = OemDeviceList;
  5414. while (CurrentDevice) {
  5415. //
  5416. // If this is an OEM source device marked virtual then mark it as skipped.
  5417. //
  5418. if(SL_OEM_SOURCE_DEVICE_TYPE(CurrentDevice,
  5419. SL_OEM_SOURCE_DEVICE_TYPE_VIRTUAL)){
  5420. SL_OEM_SET_SOURCE_DEVICE_STATE( CurrentDevice,
  5421. SL_OEM_SOURCE_DEVICE_SKIPPED);
  5422. }
  5423. CurrentDevice = CurrentDevice->Next;
  5424. }
  5425. }
  5426. }
  5427. BOOLEAN
  5428. SlpIsDynamicUpdate(
  5429. IN PVOID InfHandle,
  5430. OUT PCSTR *DynamicUpdateRootDir
  5431. )
  5432. /*++
  5433. Routine Description:
  5434. Finds out whether there are any dynamic update boot drivers
  5435. to process or not.
  5436. Arguments:
  5437. InfHandle - Handle to winnt.sif file
  5438. DynamicUpdateRootDir - Receives the root directory under which all
  5439. the dynamic update boot driver packages are present.
  5440. Return Value:
  5441. TRUE, if there are dynamic update boot drivers otherwise
  5442. FALSE
  5443. --*/
  5444. {
  5445. BOOLEAN Result = FALSE;
  5446. if (InfHandle) {
  5447. PCHAR DynUpdateKey = SlGetSectionKeyIndex(InfHandle,
  5448. WINNT_SETUPPARAMS_A,
  5449. WINNT_SP_DYNUPDTBOOTDRIVERPRESENT_A,
  5450. 0);
  5451. PCHAR DynUpdateRoot = SlGetSectionKeyIndex(InfHandle,
  5452. WINNT_SETUPPARAMS_A,
  5453. WINNT_SP_DYNUPDTBOOTDRIVERROOT_A,
  5454. 0);
  5455. //
  5456. // DynamicUpdateBootDriverPresent and DynamicUpateBootDriverRoot
  5457. // should have valid values
  5458. //
  5459. Result = (BOOLEAN) (DynUpdateKey && DynUpdateRoot &&
  5460. !_stricmp(DynUpdateKey, "yes"));
  5461. if (Result && DynamicUpdateRootDir) {
  5462. *DynamicUpdateRootDir = SlCopyStringA(DynUpdateRoot);
  5463. }
  5464. }
  5465. return Result;
  5466. }
  5467. UCHAR
  5468. SlGetDefaultAttr(
  5469. VOID
  5470. )
  5471. {
  5472. return (UCHAR)((UseRegularBackground) ? (ATT_FG_WHITE | ATT_BG_BLACK) : (ATT_FG_WHITE | ATT_BG_BLUE));
  5473. }
  5474. UCHAR
  5475. SlGetDefaultInvAttr(
  5476. VOID
  5477. )
  5478. {
  5479. return (UCHAR)((UseRegularBackground) ? (ATT_FG_BLACK | ATT_BG_WHITE) : (ATT_FG_BLUE | ATT_BG_WHITE));
  5480. }
  5481. #ifdef _IA64_
  5482. BOOLEAN
  5483. SlIsWinPEAutoBoot(
  5484. IN PSTR LoaderDeviceName
  5485. )
  5486. /*++
  5487. Routine Description:
  5488. Determines if this is an automated WinPE boot.
  5489. NOTE : Automated WinPE boot is determined by the presence
  5490. of the $WINPE$.$$$ file at the same location where
  5491. setupldr.efi was started from.
  5492. Arguments:
  5493. LoaderDeviceName : Arcname of the device where setupldr
  5494. was started from.
  5495. Return Value:
  5496. TRUE if this is WinPE auto boot, otherwise FALSE.
  5497. --*/
  5498. {
  5499. BOOLEAN Result = FALSE;
  5500. if (LoaderDeviceName) {
  5501. ULONG DiskId;
  5502. ARC_STATUS Status;
  5503. //
  5504. // open the partition
  5505. //
  5506. Status = ArcOpen(LoaderDeviceName, ArcOpenReadOnly, &DiskId);
  5507. if (Status == ESUCCESS) {
  5508. CHAR FileName[128];
  5509. ARC_STATUS FileStatus;
  5510. ULONG FileId;
  5511. //
  5512. // check for the existence of \$WINPE$.$$$
  5513. //
  5514. strcpy(FileName, "\\");
  5515. strcat(FileName, WINPE_AUTOBOOT_FILENAME);
  5516. FileStatus = BlOpen(DiskId, FileName, ArcOpenReadOnly, &FileId);
  5517. if (FileStatus == ESUCCESS) {
  5518. BlClose(FileId);
  5519. Result = TRUE;
  5520. }
  5521. ArcClose(DiskId);
  5522. }
  5523. }
  5524. return Result;
  5525. }
  5526. ARC_STATUS
  5527. SlGetWinPEStartupParams(
  5528. IN OUT PSTR StartupDeviceName,
  5529. IN OUT PSTR StartupDirectory
  5530. )
  5531. /*++
  5532. Routine Description:
  5533. Searches for the WinPE installation on the available
  5534. partitions on the first 4 disks.
  5535. Arguments:
  5536. StartupDeviceName - place holder for receiving device name
  5537. where WinPE installation was found.
  5538. StartupDirectory - place holder for receiving WinPE installation
  5539. directory.
  5540. Return Value:
  5541. Appropriate ARC_STATUS error code.
  5542. --*/
  5543. {
  5544. ARC_STATUS Status = EINVAL;
  5545. //
  5546. // validate arguments
  5547. //
  5548. if (StartupDeviceName && StartupDirectory) {
  5549. BOOLEAN Found = FALSE;
  5550. CHAR DeviceName[128];
  5551. ULONG CurrentPartition;
  5552. ULONG CurrentDisk;
  5553. //
  5554. // Go through each disk (at the max 4)
  5555. //
  5556. for (CurrentDisk = 0;
  5557. (!Found && (CurrentDisk < 4));
  5558. CurrentDisk++) {
  5559. //
  5560. // Go through each valid partition
  5561. // for the current disk
  5562. //
  5563. for (CurrentPartition = 1, Status = ESUCCESS;
  5564. (!Found && (Status == ESUCCESS));
  5565. CurrentPartition++) {
  5566. ULONG DiskId;
  5567. sprintf(DeviceName,
  5568. "multi(0)disk(0)rdisk(%d)partition(%d)",
  5569. CurrentDisk,
  5570. CurrentPartition);
  5571. //
  5572. // open the disk
  5573. //
  5574. Status = ArcOpen(DeviceName, ArcOpenReadOnly, &DiskId);
  5575. if (Status == ESUCCESS) {
  5576. CHAR FullName[128];
  5577. ARC_STATUS FileStatus;
  5578. ULONG DirId;
  5579. //
  5580. // check for the existence of \\winpe\\ia64\\system32 directory
  5581. //
  5582. strcpy(FullName, "\\WINPE\\ia64\\system32");
  5583. FileStatus = BlOpen(DiskId, FullName, ArcOpenDirectory, &DirId);
  5584. if (FileStatus == ESUCCESS) {
  5585. BlClose(DirId);
  5586. Found = TRUE;
  5587. }
  5588. ArcClose(DiskId);
  5589. }
  5590. }
  5591. }
  5592. //
  5593. // update return arguments
  5594. //
  5595. if (Found && (ESUCCESS == Status)) {
  5596. strcpy(StartupDeviceName, DeviceName);
  5597. strcpy(StartupDirectory, "\\WINPE\\ia64\\");
  5598. }
  5599. if (!Found) {
  5600. Status = EBADF;
  5601. }
  5602. }
  5603. return Status;
  5604. }
  5605. #endif // _IA64_
  5606. #ifdef _X86_
  5607. ARC_STATUS
  5608. SlLoadBootFontFile(
  5609. IN PSETUP_LOADER_BLOCK SetupLoaderBlock,
  5610. IN ULONG DiskId,
  5611. IN ULONG BootFontImageLength
  5612. )
  5613. /*++
  5614. Routine Description:
  5615. Loads the bootfont.bin into memory and initializes
  5616. relevant fields in setup loader block.
  5617. Arguments:
  5618. SetupLoaderBlock - pointer to setup loader block.
  5619. DiskId - Disk ID where bootfont.bin resides on the root
  5620. BootFontImageLength - The length of the bootfont.bin file.
  5621. Return Value:
  5622. Appropriate ARC_STATUS error code.
  5623. --*/
  5624. {
  5625. ARC_STATUS Status = EINVAL;
  5626. //
  5627. // verify arguments
  5628. //
  5629. if (SetupLoaderBlock && BootFontImageLength) {
  5630. ULONG FileId;
  5631. PVOID Image = NULL;
  5632. //
  5633. // open the bootfont.bin file
  5634. //
  5635. if (BlBootingFromNet
  5636. #if defined(REMOTE_BOOT)
  5637. && NetworkBootRom
  5638. #endif // defined(REMOTE_BOOT)
  5639. ) {
  5640. CHAR Buffer[129];
  5641. strcpy(Buffer, NetBootPath);
  5642. strcat(Buffer, "BOOTFONT.BIN");
  5643. Status = BlOpen(DiskId,
  5644. Buffer,
  5645. ArcOpenReadOnly,
  5646. &FileId);
  5647. } else {
  5648. Status = BlOpen(DiskId,
  5649. "\\BOOTFONT.BIN",
  5650. ArcOpenReadOnly,
  5651. &FileId);
  5652. }
  5653. //
  5654. // allocate memory and read the contents of the file
  5655. // into memory
  5656. //
  5657. if (ESUCCESS == Status) {
  5658. Image = BlAllocateHeap(BootFontImageLength);
  5659. if (Image) {
  5660. ULONG BytesRead = 0;
  5661. Status = BlRead(FileId, Image, BootFontImageLength, &BytesRead);
  5662. if ((ESUCCESS == Status) && (BytesRead != BootFontImageLength)) {
  5663. Status = EIO;
  5664. }
  5665. } else {
  5666. Status = ENOMEM;
  5667. }
  5668. BlClose(FileId);
  5669. }
  5670. if (Image && (ESUCCESS == Status)) {
  5671. SetupLoaderBlock->BootFontFile = Image;
  5672. SetupLoaderBlock->BootFontFileLength = BootFontImageLength;
  5673. }
  5674. }
  5675. return Status;
  5676. }
  5677. #endif
  5678. BOOLEAN
  5679. SlGetNextOption(
  5680. IN OUT PCSTR* Options,
  5681. IN OUT ULONG_PTR* Length
  5682. )
  5683. /*++
  5684. Routine Description:
  5685. Scans and returns the next load option in the input string. Scanning stops at the
  5686. end of the string or at the first empty option (should not happen).
  5687. Arguments:
  5688. Options - On input, holds the pointer to the current load option, not including the starting slash.
  5689. On output, contains the start of the next load option, not including the starting slash.
  5690. Options cannot be NULL, but *Options can.
  5691. Length - On input, contains the length of the current load option (pointed to by *Options), not inlcuding
  5692. the starting slash.
  5693. On output, holds the length of the next load option (pointed to by the new *Options), not
  5694. including the starting slash.
  5695. Cannot be NULL.
  5696. Note: to get the first load option in the string, *Options must point to the start of the
  5697. string (before or at the first slash) and *Length must be zero.
  5698. Return Value:
  5699. TRUE if there is a non-empty load option retured in *Options; FALSE if no subsequent options in the string
  5700. or if the next option is empty (e.g. '//' - shouldn't happen).
  5701. --*/
  5702. {
  5703. BOOLEAN bFound = FALSE;
  5704. if(*Options != NULL) {
  5705. *Options = strchr(*Options + *Length, '/');
  5706. if(*Options != NULL) {
  5707. PCSTR szEnd = strchr(++(*Options), '/');
  5708. if(NULL == szEnd) {
  5709. szEnd = *Options + strlen(*Options);
  5710. }
  5711. while(szEnd != *Options && ' ' == szEnd[-1]) {
  5712. --szEnd;
  5713. }
  5714. *Length = szEnd - *Options;
  5715. bFound = (BOOLEAN) (*Length != 0);
  5716. }
  5717. }
  5718. return bFound;
  5719. }
  5720. BOOLEAN
  5721. SlModifyOsLoadOptions(
  5722. IN OUT PSTR* LoadOptions,
  5723. IN PCSTR OptionsToAdd OPTIONAL,
  5724. IN PCSTR OptionsToRemove OPTIONAL
  5725. )
  5726. /*++
  5727. Routine Description:
  5728. Modifies the string containing the load options by adding and/or removing options to/from the string.
  5729. First, the options to remove are removed from the options string, and then the options to add are added.
  5730. This function does not check if OptionsToAdd and OptionsToRemove have common options; if this happens,
  5731. those options will be removed and then added back.
  5732. Arguments:
  5733. LoadOptions - On input, holds the pointer to the current load options string, which must be allocated on the heap.
  5734. On output, holds the new options string (if modified), also allocated on the heap (can be empty).
  5735. OptionsToAdd - Contains the string of options to add to the *LoadOptions string. All options must be
  5736. preceded by a slash. Can be NULL or empty.
  5737. OptionsToRemove - Contains the string of options to remove from the *LoadOptions string. All options must be
  5738. preceded by a slash. Can be NULL or empty.
  5739. Return Value:
  5740. TRUE if the *LoadOptions string was modified and thus reallocated; FALSE if *LoadOptions was left alone.
  5741. --*/
  5742. {
  5743. BOOLEAN bChanged = FALSE;
  5744. PSTR szOption = *LoadOptions;
  5745. ULONG_PTR Length = 0;
  5746. PCSTR szSearch;
  5747. ULONG_PTR Length2;
  5748. ULONG_PTR TotalLength = 0;
  5749. ULONG_PTR Count = 0;
  5750. ULONG_PTR i;
  5751. static struct {
  5752. PCSTR szOption;
  5753. ULONG_PTR Length;
  5754. } Options[50];
  5755. const ULONG_PTR MaxOptions = sizeof(Options) / sizeof(Options[0]);
  5756. while(Count < MaxOptions && SlGetNextOption(&szOption, &Length)) {
  5757. BOOLEAN bRemove = FALSE;
  5758. szSearch = OptionsToRemove;
  5759. Length2 = 0;
  5760. while(SlGetNextOption(&szSearch, &Length2)) {
  5761. if(Length == Length2 && 0 == _strnicmp(szOption, szSearch, Length)) {
  5762. //
  5763. // Need to remove this option
  5764. //
  5765. bChanged = bRemove = TRUE;
  5766. break;
  5767. }
  5768. }
  5769. if(!bRemove) {
  5770. //
  5771. // Add the option to the list. We'll prepend '/' and append a space so we'll need 2 extra chars.
  5772. // The space will become the terminator for the last option.
  5773. //
  5774. Options[Count].szOption = szOption;
  5775. Options[Count].Length = Length;
  5776. TotalLength += Options[Count].Length + 2;
  5777. ++Count;
  5778. }
  5779. }
  5780. //
  5781. // Add the new options if they are not already present
  5782. //
  5783. szSearch = OptionsToAdd;
  5784. Length2 = 0;
  5785. while(Count < MaxOptions && SlGetNextOption(&szSearch, &Length2)) {
  5786. BOOLEAN bAdd = TRUE;
  5787. for(i = 0; i < Count; ++i) {
  5788. if(Options[i].Length == Length2 && 0 == _strnicmp(Options[i].szOption, szSearch, Length2)) {
  5789. bAdd = FALSE;
  5790. break;
  5791. }
  5792. }
  5793. if(bAdd) {
  5794. Options[Count].szOption = szSearch;
  5795. Options[Count].Length = Length2;
  5796. TotalLength += Options[Count].Length + 2;
  5797. ++Count;
  5798. bChanged = TRUE;
  5799. }
  5800. }
  5801. if(bChanged) {
  5802. //
  5803. // Need to create a new options string
  5804. //
  5805. PSTR szNewOptions;
  5806. if(0 == Count) {
  5807. //
  5808. // We'll allocate an empty string
  5809. //
  5810. TotalLength = 1;
  5811. }
  5812. ASSERT(TotalLength != 0);
  5813. szNewOptions = (LPSTR) BlAllocateHeap((ULONG) TotalLength);
  5814. if(NULL == szNewOptions) {
  5815. SlNoMemoryError();
  5816. } else {
  5817. szNewOptions[0] = 0;
  5818. if(Count != 0) {
  5819. szOption = szNewOptions;
  5820. for(i = 0; i < Count; ++i) {
  5821. *szOption++ = '/';
  5822. RtlCopyMemory(szOption, Options[i].szOption, Options[i].Length);
  5823. szOption += Options[i].Length;
  5824. *szOption++ = ' ';
  5825. }
  5826. szOption[-1] = 0;
  5827. }
  5828. }
  5829. *LoadOptions = szNewOptions;
  5830. }
  5831. return bChanged;
  5832. }