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.

3171 lines
90 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation. All rights reserved.
  3. Module Name:
  4. pnpinit.c
  5. Abstract:
  6. This module contains the plug-and-play initialization
  7. subroutines for the I/O system.
  8. Author:
  9. Shie-Lin Tzong (shielint) 30-Jan-1995
  10. Environment:
  11. Kernel mode
  12. Revision History:
  13. --*/
  14. #include "pnpmgrp.h"
  15. #define _APPHELP_CACHE_INIT_
  16. #include "ahcache.h"
  17. #pragma hdrstop
  18. #define SYSTEM_HIVE_LOW 80
  19. #define SYSTEM_HIVE_HIGH 90
  20. #include <inbv.h>
  21. #include <hdlsblk.h>
  22. #include <hdlsterm.h>
  23. #include <initguid.h>
  24. #include <ntddramd.h>
  25. #ifdef POOL_TAGGING
  26. #undef ExAllocatePool
  27. #define ExAllocatePool(a,b) ExAllocatePoolWithTag(a,b,'nipP')
  28. #endif
  29. //
  30. // Define the type for driver group name entries in the group list so that
  31. // load order dependencies can be tracked.
  32. //
  33. typedef struct _TREE_ENTRY {
  34. struct _TREE_ENTRY *Left;
  35. struct _TREE_ENTRY *Right;
  36. struct _TREE_ENTRY *Sibling;
  37. ULONG DriversThisType;
  38. ULONG DriversLoaded;
  39. UNICODE_STRING GroupName;
  40. } TREE_ENTRY, *PTREE_ENTRY;
  41. typedef struct _DRIVER_INFORMATION {
  42. LIST_ENTRY Link;
  43. PDRIVER_OBJECT DriverObject;
  44. PBOOT_DRIVER_LIST_ENTRY DataTableEntry;
  45. HANDLE ServiceHandle;
  46. USHORT TagPosition;
  47. BOOLEAN Failed;
  48. BOOLEAN Processed;
  49. NTSTATUS Status;
  50. } DRIVER_INFORMATION, *PDRIVER_INFORMATION;
  51. PTREE_ENTRY IopGroupListHead;
  52. #define ALLOW_WORLD_READ_OF_ENUM 1
  53. PTREE_ENTRY
  54. PipCreateEntry(
  55. IN PUNICODE_STRING GroupName
  56. );
  57. VOID
  58. PipFreeGroupTree(
  59. IN PTREE_ENTRY TreeEntry
  60. );
  61. USHORT
  62. PipGetDriverTagPriority(
  63. IN HANDLE Servicehandle
  64. );
  65. NTSTATUS
  66. PipPnPDriverEntry(
  67. IN PDRIVER_OBJECT DriverObject,
  68. IN PUNICODE_STRING RegistryPath
  69. );
  70. NTSTATUS
  71. PipAddDevicesToBootDriver(
  72. IN PDRIVER_OBJECT DriverObject
  73. );
  74. BOOLEAN
  75. PipAddDevicesToBootDriverWorker(
  76. IN HANDLE DeviceInstanceHandle,
  77. IN PUNICODE_STRING DeviceInstancePath,
  78. IN OUT PVOID Context
  79. );
  80. BOOLEAN
  81. PipCheckDependencies(
  82. IN HANDLE KeyHandle
  83. );
  84. INTERFACE_TYPE
  85. PipDetermineDefaultInterfaceType(
  86. VOID
  87. );
  88. VOID
  89. PipInsertDriverList(
  90. IN PLIST_ENTRY ListHead,
  91. IN PDRIVER_INFORMATION DriverInfo
  92. );
  93. PTREE_ENTRY
  94. PipLookupGroupName(
  95. IN PUNICODE_STRING GroupName,
  96. IN BOOLEAN Insert
  97. );
  98. VOID
  99. PipNotifySetupDevices(
  100. PDEVICE_NODE DeviceNode
  101. );
  102. BOOLEAN
  103. PipWaitForBootDevicesDeleted(
  104. IN VOID
  105. );
  106. BOOLEAN
  107. PipWaitForBootDevicesStarted(
  108. IN VOID
  109. );
  110. BOOLEAN
  111. PiInitPhase0(
  112. VOID
  113. );
  114. BOOLEAN
  115. PiInitPhase1(
  116. VOID
  117. );
  118. NTSTATUS
  119. RawInitialize(
  120. IN PDRIVER_OBJECT DriverObject,
  121. IN PUNICODE_STRING RegistryPath
  122. );
  123. NTSTATUS
  124. PiInitCacheGroupInformation(
  125. VOID
  126. );
  127. VOID
  128. PiInitReleaseCachedGroupInformation(
  129. VOID
  130. );
  131. NTSTATUS
  132. IopStartRamdisk(
  133. PLOADER_PARAMETER_BLOCK LoaderBlock
  134. );
  135. //
  136. // Group order table
  137. //
  138. ULONG IopGroupIndex;
  139. PLIST_ENTRY IopGroupTable;
  140. //
  141. // Group order cache list.
  142. //
  143. UNICODE_STRING *PiInitGroupOrderTable = NULL;
  144. USHORT PiInitGroupOrderTableCount = 0;
  145. BOOLEAN PpDisableFirmwareMapper = FALSE;
  146. #ifdef ALLOC_PRAGMA
  147. #pragma alloc_text(INIT, IopInitializeBootDrivers)
  148. #pragma alloc_text(INIT, IopInitializePlugPlayServices)
  149. #pragma alloc_text(INIT, IopInitializeSystemDrivers)
  150. #pragma alloc_text(INIT, PipAddDevicesToBootDriver)
  151. #pragma alloc_text(INIT, PipAddDevicesToBootDriverWorker)
  152. #pragma alloc_text(INIT, PipCheckDependencies)
  153. #pragma alloc_text(INIT, PipCreateEntry)
  154. #pragma alloc_text(INIT, PipDetermineDefaultInterfaceType)
  155. #pragma alloc_text(INIT, PipFreeGroupTree)
  156. #pragma alloc_text(INIT, PipGetDriverTagPriority)
  157. #pragma alloc_text(INIT, PipInsertDriverList)
  158. #pragma alloc_text(INIT, PipLoadBootFilterDriver)
  159. #pragma alloc_text(INIT, PipLookupGroupName)
  160. #pragma alloc_text(INIT, PipNotifySetupDevices)
  161. #pragma alloc_text(INIT, PipPnPDriverEntry)
  162. #pragma alloc_text(INIT, PipWaitForBootDevicesDeleted)
  163. #pragma alloc_text(INIT, PipWaitForBootDevicesStarted)
  164. #pragma alloc_text(INIT, PiInitPhase0)
  165. #pragma alloc_text(INIT, PiInitPhase1)
  166. #pragma alloc_text(INIT, PpInitSystem)
  167. #pragma alloc_text(INIT, PiInitCacheGroupInformation)
  168. #pragma alloc_text(INIT, PiInitReleaseCachedGroupInformation)
  169. #pragma alloc_text(INIT, PpInitGetGroupOrderIndex)
  170. #pragma alloc_text(INIT, IopStartRamdisk)
  171. #endif
  172. NTSTATUS
  173. IopInitializePlugPlayServices(
  174. IN PLOADER_PARAMETER_BLOCK LoaderBlock,
  175. IN ULONG Phase
  176. )
  177. /*++
  178. Routine Description:
  179. This routine initializes kernel mode Plug and Play services.
  180. Arguments:
  181. LoaderBlock - supplies a pointer to the LoaderBlock passed in from the
  182. OS Loader.
  183. Returns:
  184. NTSTATUS code for sucess or reason of failure.
  185. --*/
  186. {
  187. NTSTATUS status;
  188. HANDLE hTreeHandle, parentHandle, handle, hCurrentControlSet = NULL;
  189. UNICODE_STRING unicodeName, previousDate, currentDate;
  190. PKEY_VALUE_FULL_INFORMATION detectionInfo, vetoHandleInfo;
  191. PDEVICE_OBJECT deviceObject;
  192. ULONG disposition;
  193. INTERFACE_TYPE interface;
  194. OBJECT_ATTRIBUTES objectAttributes;
  195. PKEY_VALUE_FULL_INFORMATION oldInformation, information;
  196. HANDLE systemInfoKey;
  197. if (Phase == 0) {
  198. PnPInitialized = FALSE;
  199. //
  200. // Register with CM so we get called when the system hive becomes too
  201. // large.
  202. //
  203. PpSystemHiveLimits.Low = SYSTEM_HIVE_LOW;
  204. PpSystemHiveLimits.High = SYSTEM_HIVE_HIGH;
  205. CmRegisterSystemHiveLimitCallback(
  206. SYSTEM_HIVE_LOW,
  207. SYSTEM_HIVE_HIGH,
  208. (PVOID)&PpSystemHiveLimits,
  209. (PCM_HYSTERESIS_CALLBACK)PpSystemHiveLimitCallback
  210. );
  211. PpSystemHiveTooLarge = FALSE;
  212. InitializeObjectAttributes(
  213. &objectAttributes,
  214. &CmRegistryMachineHardwareDescriptionSystemName,
  215. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
  216. NULL,
  217. NULL
  218. );
  219. status = ZwCreateKey(
  220. &systemInfoKey,
  221. KEY_ALL_ACCESS,
  222. &objectAttributes,
  223. 0,
  224. NULL,
  225. REG_OPTION_NON_VOLATILE,
  226. &disposition
  227. );
  228. if (NT_SUCCESS(status)) {
  229. //
  230. // Log an event if system firmware has been updated.
  231. //
  232. status = IopGetRegistryValue(
  233. systemInfoKey,
  234. L"OldSystemBiosDate",
  235. &oldInformation
  236. );
  237. if (NT_SUCCESS(status) && oldInformation) {
  238. status = IopGetRegistryValue(
  239. systemInfoKey,
  240. L"SystemBiosDate",
  241. &information
  242. );
  243. if (NT_SUCCESS(status) && information) {
  244. RtlInitUnicodeString(&previousDate, (PWCHAR)KEY_VALUE_DATA(oldInformation));
  245. RtlInitUnicodeString(&currentDate, (PWCHAR)KEY_VALUE_DATA(information));
  246. PpLogEvent(&previousDate, &currentDate, STATUS_FIRMWARE_UPDATED, NULL, 0);
  247. ExFreePool(information);
  248. }
  249. ExFreePool(oldInformation);
  250. }
  251. ZwClose(systemInfoKey);
  252. }
  253. //
  254. // Initialize the blocked driver database.
  255. //
  256. PpInitializeBootDDB(LoaderBlock);
  257. //
  258. // Build up the group order cache list. This is the MultiSz string that
  259. // tells us what order to start legacy drivers in. Drivers belonging to
  260. // an earlier group get started first (within the group Tag ordering is
  261. // used)
  262. //
  263. status = PiInitCacheGroupInformation();
  264. if (!NT_SUCCESS(status)) {
  265. return status;
  266. }
  267. //
  268. // Initialize the registry access semaphore.
  269. //
  270. KeInitializeSemaphore( &PpRegistrySemaphore, 1, 1 );
  271. //
  272. // Initialize the Legacy Bus information table.
  273. //
  274. for (interface = Internal; interface < MaximumInterfaceType; interface++) {
  275. InitializeListHead(&IopLegacyBusInformationTable[interface]);
  276. }
  277. //
  278. // Initialize the resource map
  279. //
  280. IopInitializeResourceMap (LoaderBlock);
  281. //
  282. // Allocate two one-page scratch buffers to be used by our
  283. // initialization code. This avoids constant pool allocations.
  284. //
  285. IopPnpScratchBuffer1 = ExAllocatePool(PagedPool, PNP_LARGE_SCRATCH_BUFFER_SIZE);
  286. if (!IopPnpScratchBuffer1) {
  287. return STATUS_INSUFFICIENT_RESOURCES;
  288. }
  289. IopInitReservedResourceList = NULL;
  290. IopAllocateBootResourcesRoutine = IopReportBootResources;
  291. //
  292. // Determine the PnpDefaultInterfaceType. For root enumerated devices if the Interface
  293. // type of their resource list or resource requirements list are undefined. We will use
  294. // the default type instead.
  295. //
  296. PnpDefaultInterfaceType = PipDetermineDefaultInterfaceType();
  297. //
  298. // Initialize root arbiters
  299. //
  300. status = IopPortInitialize();
  301. if (!NT_SUCCESS(status)) {
  302. goto init_Exit0;
  303. }
  304. status = IopMemInitialize();
  305. if (!NT_SUCCESS(status)) {
  306. goto init_Exit0;
  307. }
  308. status = IopDmaInitialize();
  309. if (!NT_SUCCESS(status)) {
  310. goto init_Exit0;
  311. }
  312. status = IopIrqInitialize();
  313. if (!NT_SUCCESS(status)) {
  314. goto init_Exit0;
  315. }
  316. status = IopBusNumberInitialize();
  317. if (!NT_SUCCESS(status)) {
  318. goto init_Exit0;
  319. }
  320. status = IopOpenRegistryKeyEx( &hCurrentControlSet,
  321. NULL,
  322. &CmRegistryMachineSystemCurrentControlSet,
  323. KEY_ALL_ACCESS
  324. );
  325. if (!NT_SUCCESS(status)) {
  326. hCurrentControlSet = NULL;
  327. goto init_Exit0;
  328. }
  329. //
  330. // Open HKLM\System\CurrentControlSet\Control\Pnp
  331. //
  332. PiWstrToUnicodeString(&unicodeName, REGSTR_PATH_CONTROL_PNP);
  333. status = IopCreateRegistryKeyEx( &handle,
  334. hCurrentControlSet,
  335. &unicodeName,
  336. KEY_ALL_ACCESS,
  337. REG_OPTION_NON_VOLATILE,
  338. NULL
  339. );
  340. if (NT_SUCCESS(status)) {
  341. //
  342. // HACK: Since it was too late to make the change in XP, we target
  343. // this behaviour at machines with MATROX G100. The inf sets this
  344. // flag in the registry.
  345. //
  346. // FUTURE: Rip this out in Longhorn.
  347. //
  348. status = IopGetRegistryValue(handle,
  349. REGSTR_VAL_WIN2000STARTORDER,
  350. &detectionInfo
  351. );
  352. if (NT_SUCCESS(status)) {
  353. if (detectionInfo->Type == REG_DWORD && detectionInfo->DataLength == sizeof(ULONG)) {
  354. //
  355. // KEY_VALUE_DATA returns a PUCHAR.
  356. //
  357. PpCallerInitializesRequestTable = (BOOLEAN) *(KEY_VALUE_DATA(detectionInfo));
  358. }
  359. ExFreePool(detectionInfo);
  360. }
  361. //
  362. // Read a flag that'll force us to dump handle information during
  363. // failed QueryRemoves to setupapi.log. This is only here for
  364. // debugging scenarios in which it's impossible to get the customer
  365. // up and running on a debugger under a checked build.
  366. //
  367. // FUTURE: Rip this out in Longhorn.
  368. //
  369. status = IopGetRegistryValue(handle,
  370. REGSTR_VAL_RETURNHANDLEINFO,
  371. &vetoHandleInfo
  372. );
  373. if (NT_SUCCESS(status)) {
  374. if (vetoHandleInfo->Type == REG_DWORD && vetoHandleInfo->DataLength == sizeof(ULONG)) {
  375. //
  376. // KEY_VALUE_DATA returns a PUCHAR.
  377. //
  378. PiCollectVetoedHandles = (LOGICAL) (BOOLEAN) *(KEY_VALUE_DATA(vetoHandleInfo));
  379. }
  380. ExFreePool(vetoHandleInfo);
  381. }
  382. //
  383. // Close the handle to the PnP control key now that we are done.
  384. //
  385. ZwClose(handle);
  386. }
  387. //
  388. // Next open/create System\CurrentControlSet\Enum\Root key.
  389. //
  390. PiWstrToUnicodeString(&unicodeName, REGSTR_KEY_ENUM);
  391. status = IopCreateRegistryKeyEx( &handle,
  392. hCurrentControlSet,
  393. &unicodeName,
  394. KEY_ALL_ACCESS,
  395. REG_OPTION_NON_VOLATILE,
  396. &disposition
  397. );
  398. if (!NT_SUCCESS(status)) {
  399. goto init_Exit0;
  400. }
  401. if (disposition == REG_CREATED_NEW_KEY) {
  402. SECURITY_DESCRIPTOR newSD;
  403. PACL newDacl;
  404. ULONG sizeDacl;
  405. status = RtlCreateSecurityDescriptor( &newSD,
  406. SECURITY_DESCRIPTOR_REVISION );
  407. ASSERT( NT_SUCCESS( status ) );
  408. //
  409. // calculate the size of the new DACL
  410. //
  411. sizeDacl = sizeof(ACL);
  412. sizeDacl += sizeof(ACCESS_ALLOWED_ACE) + RtlLengthSid(SeLocalSystemSid) - sizeof(ULONG);
  413. #if ALLOW_WORLD_READ_OF_ENUM
  414. sizeDacl += sizeof(ACCESS_ALLOWED_ACE) + RtlLengthSid(SeWorldSid) - sizeof(ULONG);
  415. #endif
  416. //
  417. // create and initialize the new DACL
  418. //
  419. newDacl = ExAllocatePool(PagedPool, sizeDacl);
  420. if (newDacl != NULL) {
  421. status = RtlCreateAcl(newDacl, sizeDacl, ACL_REVISION);
  422. ASSERT( NT_SUCCESS( status ) );
  423. //
  424. // Add just the local system full control ace to this new DACL
  425. //
  426. status = RtlAddAccessAllowedAceEx( newDacl,
  427. ACL_REVISION,
  428. CONTAINER_INHERIT_ACE,
  429. KEY_ALL_ACCESS,
  430. SeLocalSystemSid
  431. );
  432. ASSERT( NT_SUCCESS( status ) );
  433. #if ALLOW_WORLD_READ_OF_ENUM
  434. //
  435. // Add a world read control ace to this new DACL
  436. //
  437. status = RtlAddAccessAllowedAceEx( newDacl,
  438. ACL_REVISION,
  439. CONTAINER_INHERIT_ACE,
  440. KEY_READ,
  441. SeWorldSid
  442. );
  443. ASSERT( NT_SUCCESS( status ) );
  444. #endif
  445. //
  446. // Set the new DACL in the absolute security descriptor
  447. //
  448. status = RtlSetDaclSecurityDescriptor( (PSECURITY_DESCRIPTOR) &newSD,
  449. TRUE,
  450. newDacl,
  451. FALSE
  452. );
  453. ASSERT( NT_SUCCESS( status ) );
  454. //
  455. // validate the new security descriptor
  456. //
  457. status = RtlValidSecurityDescriptor(&newSD);
  458. ASSERT( NT_SUCCESS( status ) );
  459. status = ZwSetSecurityObject( handle,
  460. DACL_SECURITY_INFORMATION,
  461. &newSD
  462. );
  463. if (!NT_SUCCESS(status)) {
  464. IopDbgPrint(( IOP_ERROR_LEVEL,
  465. "IopInitializePlugPlayServices: ZwSetSecurityObject on Enum key failed, status = %8.8X\n", status));
  466. }
  467. ExFreePool(newDacl);
  468. } else {
  469. IopDbgPrint(( IOP_ERROR_LEVEL,
  470. "IopInitializePlugPlayServices: ExAllocatePool failed allocating DACL for Enum key\n"));
  471. }
  472. }
  473. parentHandle = handle;
  474. PiWstrToUnicodeString(&unicodeName, REGSTR_KEY_ROOTENUM);
  475. status = IopCreateRegistryKeyEx( &handle,
  476. parentHandle,
  477. &unicodeName,
  478. KEY_ALL_ACCESS,
  479. REG_OPTION_NON_VOLATILE,
  480. NULL
  481. );
  482. ZwClose(parentHandle);
  483. if (!NT_SUCCESS(status)) {
  484. goto init_Exit0;
  485. }
  486. ZwClose(handle);
  487. //
  488. // Create the registry entry for the root of the hardware tree (HTREE\ROOT\0).
  489. //
  490. status = IopOpenRegistryKeyEx( &handle,
  491. NULL,
  492. &CmRegistryMachineSystemCurrentControlSetEnumName,
  493. KEY_ALL_ACCESS
  494. );
  495. if (NT_SUCCESS(status)) {
  496. PiWstrToUnicodeString(&unicodeName, REGSTR_VAL_ROOT_DEVNODE);
  497. status = IopCreateRegistryKeyEx( &hTreeHandle,
  498. handle,
  499. &unicodeName,
  500. KEY_ALL_ACCESS,
  501. REG_OPTION_NON_VOLATILE,
  502. NULL
  503. );
  504. ZwClose(handle);
  505. if (NT_SUCCESS(status)) {
  506. ZwClose(hTreeHandle);
  507. }
  508. }
  509. //
  510. // Before creating device node tree, we need to initialize the device
  511. // tree lock.
  512. //
  513. InitializeListHead(&IopPendingEjects);
  514. InitializeListHead(&IopPendingSurpriseRemovals);
  515. InitializeListHead(&IopPnpEnumerationRequestList);
  516. ExInitializeResourceLite(&IopDeviceTreeLock);
  517. ExInitializeResourceLite(&IopSurpriseRemoveListLock);
  518. PiInitializeEngineLock();
  519. KeInitializeEvent(&PiEventQueueEmpty, NotificationEvent, TRUE );
  520. KeInitializeEvent(&PiEnumerationLock, NotificationEvent, TRUE );
  521. KeInitializeSpinLock(&IopPnPSpinLock);
  522. //
  523. // Initialize the hardware profile/docking support.
  524. //
  525. PpProfileInit();
  526. //
  527. // Initialize warm docking variables.
  528. //
  529. IopWarmEjectPdo = NULL;
  530. KeInitializeEvent(&IopWarmEjectLock, SynchronizationEvent, TRUE );
  531. //
  532. // Create a PnP manager's driver object to own all the detected PDOs.
  533. //
  534. PiWstrToUnicodeString(&unicodeName, PNPMGR_STR_PNP_DRIVER);
  535. status = IoCreateDriver (&unicodeName, PipPnPDriverEntry);
  536. if (NT_SUCCESS(status)) {
  537. //
  538. // Create empty device node tree, i.e., only contains only root device node
  539. // (No need to initialize Parent, Child and Sibling links.)
  540. status = IoCreateDevice( IoPnpDriverObject,
  541. sizeof(IOPNP_DEVICE_EXTENSION),
  542. NULL,
  543. FILE_DEVICE_CONTROLLER,
  544. 0,
  545. FALSE,
  546. &deviceObject );
  547. if (NT_SUCCESS(status)) {
  548. deviceObject->Flags |= DO_BUS_ENUMERATED_DEVICE;
  549. status = PipAllocateDeviceNode(
  550. deviceObject,
  551. &IopRootDeviceNode);
  552. if (!IopRootDeviceNode) {
  553. IoDeleteDevice(deviceObject);
  554. IoDeleteDriver(IoPnpDriverObject);
  555. } else {
  556. IopRootDeviceNode->Flags |= DNF_MADEUP |
  557. DNF_ENUMERATED |
  558. DNF_IDS_QUERIED |
  559. DNF_NO_RESOURCE_REQUIRED;
  560. IopRootDeviceNode->InstancePath.Buffer = ExAllocatePool( PagedPool,
  561. sizeof(REGSTR_VAL_ROOT_DEVNODE));
  562. if (IopRootDeviceNode->InstancePath.Buffer != NULL) {
  563. IopRootDeviceNode->InstancePath.MaximumLength = sizeof(REGSTR_VAL_ROOT_DEVNODE);
  564. IopRootDeviceNode->InstancePath.Length = sizeof(REGSTR_VAL_ROOT_DEVNODE) - sizeof(WCHAR);
  565. RtlCopyMemory( IopRootDeviceNode->InstancePath.Buffer,
  566. REGSTR_VAL_ROOT_DEVNODE,
  567. sizeof(REGSTR_VAL_ROOT_DEVNODE));
  568. } else {
  569. ASSERT(IopRootDeviceNode->InstancePath.Buffer);
  570. status = STATUS_INSUFFICIENT_RESOURCES;
  571. goto init_Exit0;
  572. }
  573. status = IopMapDeviceObjectToDeviceInstance(
  574. IopRootDeviceNode->PhysicalDeviceObject,
  575. &IopRootDeviceNode->InstancePath);
  576. if (!NT_SUCCESS(status)) {
  577. goto init_Exit0;
  578. }
  579. PipSetDevNodeState(IopRootDeviceNode, DeviceNodeStarted, NULL);
  580. }
  581. }
  582. }
  583. if (!NT_SUCCESS(status)) {
  584. goto init_Exit0;
  585. }
  586. //
  587. // Initialize the kernel mode pnp notification system
  588. //
  589. status = PpInitializeNotification();
  590. if (!NT_SUCCESS(status)) {
  591. goto init_Exit0;
  592. }
  593. IopInitializePlugPlayNotification();
  594. //
  595. // Initialize table for holding bus type guid list.
  596. //
  597. status = PpBusTypeGuidInitialize();
  598. if (!NT_SUCCESS(status)) {
  599. goto init_Exit0;
  600. }
  601. //
  602. // Enumerate the ROOT bus synchronously.
  603. //
  604. PipRequestDeviceAction( IopRootDeviceNode->PhysicalDeviceObject,
  605. ReenumerateRootDevices,
  606. FALSE,
  607. 0,
  608. NULL,
  609. NULL);
  610. init_Exit0:
  611. //
  612. // If we managed to open the Current Control Set close it
  613. //
  614. if (hCurrentControlSet) {
  615. ZwClose(hCurrentControlSet);
  616. }
  617. if (!NT_SUCCESS(status)) {
  618. ExFreePool(IopPnpScratchBuffer1);
  619. }
  620. } else if (Phase == 1) {
  621. //
  622. // Collect the necessary firmware tree information.
  623. //
  624. MapperProcessFirmwareTree(PpDisableFirmwareMapper);
  625. //
  626. // Map this into the root enumerator tree
  627. //
  628. MapperConstructRootEnumTree(PpDisableFirmwareMapper);
  629. #if defined(_X86_)
  630. if (!PpDisableFirmwareMapper) {
  631. //
  632. // Now do the PnP BIOS enumerated devnodes.
  633. //
  634. status = PnPBiosMapper();
  635. //
  636. // If the previous call succeeds, we have a PNPBios, turn any newly
  637. // created ntdetect COM ports into phantoms
  638. //
  639. if (NT_SUCCESS(status)) {
  640. MapperPhantomizeDetectedComPorts();
  641. }
  642. }
  643. EisaBuildEisaDeviceNode();
  644. #endif
  645. //
  646. // We're done with the firmware mapper device list.
  647. //
  648. MapperFreeList();
  649. //
  650. // Enumerate the ROOT bus synchronously.
  651. //
  652. PipRequestDeviceAction( IopRootDeviceNode->PhysicalDeviceObject,
  653. ReenumerateRootDevices,
  654. FALSE,
  655. 0,
  656. NULL,
  657. NULL);
  658. //
  659. // Free our scratch buffers and exit.
  660. //
  661. ExFreePool(IopPnpScratchBuffer1);
  662. ApphelpCacheInitialize(LoaderBlock, Phase);
  663. status = STATUS_SUCCESS;
  664. } else {
  665. status = STATUS_INVALID_PARAMETER_2;
  666. }
  667. return status;
  668. }
  669. NTSTATUS
  670. PipPnPDriverEntry(
  671. IN PDRIVER_OBJECT DriverObject,
  672. IN PUNICODE_STRING RegistryPath
  673. )
  674. /*++
  675. Routine Description:
  676. This is the callback function when we call IoCreateDriver to create a
  677. PnP Driver Object. In this function, we need to remember the DriverObject.
  678. Arguments:
  679. DriverObject - Pointer to the driver object created by the system.
  680. RegistryPath - is NULL.
  681. Return Value:
  682. STATUS_SUCCESS
  683. --*/
  684. {
  685. UNREFERENCED_PARAMETER( RegistryPath );
  686. //
  687. // File the pointer to our driver object away
  688. //
  689. IoPnpDriverObject = DriverObject;
  690. //
  691. // Fill in the driver object
  692. //
  693. DriverObject->DriverExtension->AddDevice = (PDRIVER_ADD_DEVICE)IopPnPAddDevice;
  694. DriverObject->MajorFunction[ IRP_MJ_PNP ] = IopPnPDispatch;
  695. DriverObject->MajorFunction[ IRP_MJ_POWER ] = IopPowerDispatch;
  696. DriverObject->MajorFunction[ IRP_MJ_SYSTEM_CONTROL ] = IopSystemControlDispatch;
  697. return STATUS_SUCCESS;
  698. }
  699. INTERFACE_TYPE
  700. PipDetermineDefaultInterfaceType (
  701. VOID
  702. )
  703. /*++
  704. Routine Description:
  705. This routine checks if detection flag is set to enable driver detection.
  706. The detection will be enabled if there is no PCI bus in the machine and only
  707. on ALPHA machine.
  708. FUTURE: Comment should make sense.
  709. Parameters:
  710. None.
  711. Return Value:
  712. BOOLEAN value to indicate if detection is enabled.
  713. --*/
  714. {
  715. NTSTATUS status;
  716. PVOID p;
  717. PHAL_BUS_INFORMATION pBusInfo;
  718. ULONG length, i;
  719. INTERFACE_TYPE interfaceType = Isa;
  720. pBusInfo = IopPnpScratchBuffer1;
  721. length = PNP_LARGE_SCRATCH_BUFFER_SIZE;
  722. status = HalQuerySystemInformation (
  723. HalInstalledBusInformation,
  724. length,
  725. pBusInfo,
  726. &length
  727. );
  728. if (!NT_SUCCESS(status)) {
  729. return interfaceType;
  730. }
  731. //
  732. // Check installed bus information to make sure there is no existing Pnp Isa
  733. // bus extender.
  734. //
  735. p = pBusInfo;
  736. for (i = 0; i < length / sizeof(HAL_BUS_INFORMATION); i++, pBusInfo++) {
  737. if (pBusInfo->BusType == Isa || pBusInfo->BusType == Eisa) {
  738. interfaceType = Isa;
  739. break;
  740. } else if (pBusInfo->BusType == MicroChannel) {
  741. interfaceType = MicroChannel;
  742. }
  743. }
  744. return interfaceType;
  745. }
  746. BOOLEAN
  747. PipCheckDependencies(
  748. IN HANDLE KeyHandle
  749. )
  750. /*++
  751. Routine Description:
  752. This routine gets the "DependOnGroup" field for the specified key node
  753. and determines whether any driver in the group(s) that this entry is
  754. dependent on has successfully loaded.
  755. Arguments:
  756. KeyHandle - Supplies a handle to the key representing the driver in
  757. question.
  758. Return Value:
  759. The function value is TRUE if the driver should be loaded, otherwise
  760. FALSE
  761. --*/
  762. {
  763. PKEY_VALUE_FULL_INFORMATION keyValueInformation;
  764. UNICODE_STRING groupName;
  765. BOOLEAN load;
  766. ULONG length;
  767. PWSTR source;
  768. PTREE_ENTRY treeEntry;
  769. //
  770. // Attempt to obtain the "DependOnGroup" key for the specified driver
  771. // entry. If one does not exist, then simply mark this driver as being
  772. // one to attempt to load. If it does exist, then check to see whether
  773. // or not any driver in the groups that it is dependent on has loaded
  774. // and allow it to load.
  775. //
  776. if (!NT_SUCCESS( IopGetRegistryValue( KeyHandle, L"DependOnGroup", &keyValueInformation ))) {
  777. return TRUE;
  778. }
  779. length = keyValueInformation->DataLength;
  780. source = (PWSTR) ((PUCHAR) keyValueInformation + keyValueInformation->DataOffset);
  781. load = TRUE;
  782. while (length) {
  783. RtlInitUnicodeString( &groupName, source );
  784. groupName.Length = groupName.MaximumLength;
  785. treeEntry = PipLookupGroupName( &groupName, FALSE );
  786. if (treeEntry) {
  787. if (!treeEntry->DriversLoaded) {
  788. load = FALSE;
  789. break;
  790. }
  791. }
  792. length -= groupName.MaximumLength;
  793. source = (PWSTR) ((PUCHAR) source + groupName.MaximumLength);
  794. }
  795. ExFreePool( keyValueInformation );
  796. return load;
  797. }
  798. PTREE_ENTRY
  799. PipCreateEntry(
  800. IN PUNICODE_STRING GroupName
  801. )
  802. /*++
  803. Routine Description:
  804. This routine creates an entry for the specified group name suitable for
  805. being inserted into the group name tree.
  806. Arguments:
  807. GroupName - Specifies the name of the group for the entry.
  808. Return Value:
  809. The function value is a pointer to the created entry.
  810. --*/
  811. {
  812. PTREE_ENTRY treeEntry;
  813. //
  814. // Allocate and initialize an entry suitable for placing into the group
  815. // name tree.
  816. //
  817. treeEntry = ExAllocatePool( PagedPool,
  818. sizeof( TREE_ENTRY ) + GroupName->Length );
  819. //
  820. // We return NULL here and what this really implies that
  821. // we won't be able to determine if drivers for this group
  822. // was loaded.
  823. //
  824. if (!treeEntry) {
  825. return NULL;
  826. }
  827. RtlZeroMemory( treeEntry, sizeof( TREE_ENTRY ) );
  828. treeEntry->GroupName.Length = GroupName->Length;
  829. treeEntry->GroupName.MaximumLength = GroupName->Length;
  830. treeEntry->GroupName.Buffer = (PWCHAR) (treeEntry + 1);
  831. RtlCopyMemory( treeEntry->GroupName.Buffer,
  832. GroupName->Buffer,
  833. GroupName->Length );
  834. return treeEntry;
  835. }
  836. VOID
  837. PipFreeGroupTree(
  838. PTREE_ENTRY TreeEntry
  839. )
  840. /*++
  841. Routine Description:
  842. This routine is invoked to free a node from the group dependency tree.
  843. It is invoked the first time with the root of the tree, and thereafter
  844. recursively to walk the tree and remove the nodes.
  845. Arguments:
  846. TreeEntry - Supplies a pointer to the node to be freed.
  847. Return Value:
  848. None.
  849. --*/
  850. {
  851. //
  852. // Simply walk the tree in ascending order from the bottom up and free
  853. // each node along the way.
  854. //
  855. if (TreeEntry->Left) {
  856. PipFreeGroupTree( TreeEntry->Left );
  857. }
  858. if (TreeEntry->Sibling) {
  859. PipFreeGroupTree( TreeEntry->Sibling );
  860. }
  861. if (TreeEntry->Right) {
  862. PipFreeGroupTree( TreeEntry->Right );
  863. }
  864. //
  865. // All of the children and siblings for this node have been freed, so
  866. // now free this node as well.
  867. //
  868. ExFreePool( TreeEntry );
  869. }
  870. BOOLEAN
  871. IopInitializeBootDrivers(
  872. IN PLOADER_PARAMETER_BLOCK LoaderBlock,
  873. OUT PDRIVER_OBJECT *PreviousDriver
  874. )
  875. /*++
  876. Routine Description:
  877. This routine is invoked to initialize the boot drivers that were loaded
  878. by the OS Loader. The list of drivers is provided as part of the loader
  879. parameter block.
  880. Arguments:
  881. LoaderBlock - Supplies a pointer to the loader parameter block, created
  882. by the OS Loader.
  883. Previous Driver - Supplies a variable to receive the address of the
  884. driver object chain created by initializing the drivers.
  885. Return Value:
  886. The function value is a BOOLEAN indicating whether or not the boot
  887. drivers were successfully initialized.
  888. --*/
  889. {
  890. UNICODE_STRING completeName;
  891. UNICODE_STRING rawFsName;
  892. NTSTATUS status;
  893. PLIST_ENTRY nextEntry;
  894. PBOOT_DRIVER_LIST_ENTRY bootDriver;
  895. HANDLE keyHandle;
  896. PKEY_VALUE_FULL_INFORMATION keyValueInformation;
  897. PDRIVER_OBJECT driverObject;
  898. USHORT i, j;
  899. PKLDR_DATA_TABLE_ENTRY driverEntry;
  900. PKLDR_DATA_TABLE_ENTRY dllEntry;
  901. UNICODE_STRING groupName;
  902. PTREE_ENTRY treeEntry;
  903. PDRIVER_INFORMATION driverInfo;
  904. BOOLEAN textModeSetup = FALSE;
  905. BOOLEAN bootReinitDriversFound;
  906. ULONG remotebootcount = 0;
  907. UNREFERENCED_PARAMETER( PreviousDriver );
  908. //
  909. // Initialize the built-in RAW file system driver.
  910. //
  911. PiWstrToUnicodeString( &rawFsName, L"\\FileSystem\\RAW" );
  912. PiWstrToUnicodeString( &completeName, L"" );
  913. IopInitializeBuiltinDriver(&rawFsName,
  914. &completeName,
  915. RawInitialize,
  916. NULL,
  917. FALSE,
  918. &driverObject);
  919. if (!driverObject) {
  920. #if DBG
  921. DbgPrint( "IOINIT: Failed to initialize RAW filsystem \n" );
  922. #endif
  923. return FALSE;
  924. }
  925. //
  926. // Determine number of group orders and build a list_entry array to link all the drivers
  927. // together based on their groups.
  928. //
  929. IopGroupIndex = PpInitGetGroupOrderIndex(NULL);
  930. if (IopGroupIndex == NO_MORE_GROUP) {
  931. HeadlessKernelAddLogEntry(HEADLESS_LOG_FIND_GROUPS_FAILED, NULL);
  932. return FALSE;
  933. }
  934. IopGroupTable = (PLIST_ENTRY) ExAllocatePool(PagedPool, IopGroupIndex * sizeof (LIST_ENTRY));
  935. if (IopGroupTable == NULL) {
  936. HeadlessKernelAddLogEntry(HEADLESS_LOG_OUT_OF_MEMORY, NULL);
  937. return FALSE;
  938. }
  939. for (i = 0; i < IopGroupIndex; i++) {
  940. InitializeListHead(&IopGroupTable[i]);
  941. }
  942. //
  943. // Call DllInitialize for driver dependent DLLs.
  944. //
  945. nextEntry = LoaderBlock->LoadOrderListHead.Flink;
  946. while (nextEntry != &LoaderBlock->LoadOrderListHead) {
  947. dllEntry = CONTAINING_RECORD(nextEntry, KLDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
  948. if (dllEntry->Flags & LDRP_DRIVER_DEPENDENT_DLL) {
  949. (VOID)MmCallDllInitialize(dllEntry, &LoaderBlock->LoadOrderListHead);
  950. }
  951. nextEntry = nextEntry->Flink;
  952. }
  953. //
  954. // Allocate pool to store driver's start information.
  955. // All the driver info records with the same group value will be linked into a list.
  956. //
  957. nextEntry = LoaderBlock->BootDriverListHead.Flink;
  958. while (nextEntry != &LoaderBlock->BootDriverListHead) {
  959. bootDriver = CONTAINING_RECORD( nextEntry,
  960. BOOT_DRIVER_LIST_ENTRY,
  961. Link );
  962. driverEntry = bootDriver->LdrEntry;
  963. driverInfo = (PDRIVER_INFORMATION) ExAllocatePool(
  964. PagedPool, sizeof(DRIVER_INFORMATION));
  965. if (driverInfo) {
  966. RtlZeroMemory(driverInfo, sizeof(DRIVER_INFORMATION));
  967. InitializeListHead(&driverInfo->Link);
  968. driverInfo->DataTableEntry = bootDriver;
  969. //
  970. // Open the driver's registry key to find out if this is a
  971. // filesystem or a driver.
  972. //
  973. status = IopOpenRegistryKeyEx( &keyHandle,
  974. (HANDLE)NULL,
  975. &bootDriver->RegistryPath,
  976. KEY_READ
  977. );
  978. if (!NT_SUCCESS( status )) {
  979. ExFreePool(driverInfo);
  980. } else {
  981. driverInfo->ServiceHandle = keyHandle;
  982. j = PpInitGetGroupOrderIndex(keyHandle);
  983. if (j == SETUP_RESERVED_GROUP) {
  984. textModeSetup = TRUE;
  985. //
  986. // Special handling for setupdd.sys
  987. //
  988. status = IopGetDriverNameFromKeyNode( keyHandle,
  989. &completeName );
  990. if (NT_SUCCESS(status)) {
  991. driverInfo->Status = IopInitializeBuiltinDriver(
  992. &completeName,
  993. &bootDriver->RegistryPath,
  994. (PDRIVER_INITIALIZE) (ULONG_PTR) driverEntry->EntryPoint,
  995. driverEntry,
  996. FALSE,
  997. &driverObject);
  998. ExFreePool( completeName.Buffer );
  999. ZwClose(keyHandle);
  1000. ExFreePool(driverInfo);
  1001. if (driverObject) {
  1002. //
  1003. // Once we successfully initialized the setupdd.sys, we are ready
  1004. // to notify it all the root enumerated devices.
  1005. //
  1006. PipNotifySetupDevices(IopRootDeviceNode);
  1007. } else {
  1008. ExFreePool(IopGroupTable);
  1009. return FALSE;
  1010. }
  1011. }
  1012. } else {
  1013. driverInfo->TagPosition = PipGetDriverTagPriority(keyHandle);
  1014. PipInsertDriverList(&IopGroupTable[j], driverInfo);
  1015. }
  1016. }
  1017. }
  1018. nextEntry = nextEntry->Flink;
  1019. }
  1020. //
  1021. // Process each driver base on its group. The group with lower index number (higher
  1022. // priority) is processed first.
  1023. //
  1024. for (i = 0; i < IopGroupIndex; i++) {
  1025. nextEntry = IopGroupTable[i].Flink;
  1026. while (nextEntry != &IopGroupTable[i]) {
  1027. driverInfo = CONTAINING_RECORD(nextEntry, DRIVER_INFORMATION, Link);
  1028. keyHandle = driverInfo->ServiceHandle;
  1029. bootDriver = driverInfo->DataTableEntry;
  1030. driverEntry = bootDriver->LdrEntry;
  1031. driverInfo->Processed = TRUE;
  1032. //
  1033. // call the driver's driver entry
  1034. //
  1035. // See if this driver has an ObjectName value. If so, this value
  1036. // overrides the default ("\Driver" or "\FileSystem").
  1037. //
  1038. status = IopGetDriverNameFromKeyNode( keyHandle,
  1039. &completeName );
  1040. if (!NT_SUCCESS( status )) {
  1041. #if DBG
  1042. DbgPrint( "IOINIT: Could not get driver name for %wZ\n",
  1043. &bootDriver->RegistryPath );
  1044. #endif // DBG
  1045. driverInfo->Failed = TRUE;
  1046. } else {
  1047. status = IopGetRegistryValue( keyHandle,
  1048. REGSTR_VALUE_GROUP,
  1049. &keyValueInformation );
  1050. if (NT_SUCCESS( status )) {
  1051. if (keyValueInformation->DataLength) {
  1052. groupName.Length = (USHORT) keyValueInformation->DataLength;
  1053. groupName.MaximumLength = groupName.Length;
  1054. groupName.Buffer = (PWSTR) ((PUCHAR) keyValueInformation + keyValueInformation->DataOffset);
  1055. treeEntry = PipLookupGroupName( &groupName, TRUE );
  1056. } else {
  1057. treeEntry = (PTREE_ENTRY) NULL;
  1058. }
  1059. ExFreePool( keyValueInformation );
  1060. } else {
  1061. treeEntry = (PTREE_ENTRY) NULL;
  1062. }
  1063. driverObject = NULL;
  1064. if (PipCheckDependencies( keyHandle )) {
  1065. //
  1066. // The driver may already be initialized by IopInitializeBootFilterDriver
  1067. // if it is boot filter driver.
  1068. // If not, initialize it.
  1069. //
  1070. driverObject = driverInfo->DriverObject;
  1071. if (driverObject == NULL && !driverInfo->Failed) {
  1072. driverInfo->Status = IopInitializeBuiltinDriver(
  1073. &completeName,
  1074. &bootDriver->RegistryPath,
  1075. (PDRIVER_INITIALIZE) (ULONG_PTR) driverEntry->EntryPoint,
  1076. driverEntry,
  1077. FALSE,
  1078. &driverObject);
  1079. //
  1080. // Pnp might unload the driver before we get a chance to look at this. So take an extra
  1081. // reference.
  1082. //
  1083. if (driverObject) {
  1084. ObReferenceObject(driverObject);
  1085. //
  1086. // If we load the driver because we think it is a legacy driver and
  1087. // it does not create any device object in its DriverEntry. We will
  1088. // unload this driver.
  1089. //
  1090. if (!IopIsLegacyDriver(driverObject)) {
  1091. if (driverObject->DeviceObject == NULL &&
  1092. driverObject->DriverExtension->ServiceKeyName.Buffer &&
  1093. !IopIsAnyDeviceInstanceEnabled(&driverObject->DriverExtension->ServiceKeyName, NULL, FALSE)) {
  1094. if (textModeSetup && !(driverObject->Flags & DRVO_REINIT_REGISTERED)) {
  1095. //
  1096. // Clean up but leave driver object. Because it may be needed later.
  1097. // After boot driver phase completes, we will process all the driver objects
  1098. // which still have no device to control.
  1099. //
  1100. IopDriverLoadingFailed(NULL, &driverObject->DriverExtension->ServiceKeyName);
  1101. }
  1102. } else {
  1103. //
  1104. // Start the devices controlled by the driver and enumerate them
  1105. // At this point, we know there is at least one device controlled by the driver.
  1106. //
  1107. IopDeleteLegacyKey(driverObject);
  1108. }
  1109. }
  1110. }
  1111. }
  1112. }
  1113. if (driverObject) {
  1114. if (treeEntry) {
  1115. treeEntry->DriversLoaded++;
  1116. }
  1117. driverInfo->DriverObject = driverObject;
  1118. } else {
  1119. driverInfo->Failed = TRUE;
  1120. }
  1121. ExFreePool( completeName.Buffer );
  1122. }
  1123. if (!driverInfo->Failed) {
  1124. PipAddDevicesToBootDriver(driverObject);
  1125. //
  1126. // Scan the hardware tree looking for devices which need
  1127. // resources or starting.
  1128. //
  1129. PipRequestDeviceAction( NULL,
  1130. ReenumerateBootDevices,
  1131. FALSE,
  1132. 0,
  1133. NULL,
  1134. NULL);
  1135. }
  1136. //
  1137. // Before processing next boot driver, wait for IoRequestDeviceRemoval complete.
  1138. // The driver to be processed may need the resources being released by
  1139. // IoRequestDeviceRemoval. (For drivers report detected BOOT device if they fail to
  1140. // get the resources in their DriverEntry. They will fail and we will bugcheck with
  1141. // inaccessible boot device.)
  1142. //
  1143. if (!PipWaitForBootDevicesDeleted()) {
  1144. HeadlessKernelAddLogEntry(HEADLESS_LOG_WAIT_BOOT_DEVICES_DELETE_FAILED, NULL);
  1145. return FALSE;
  1146. }
  1147. nextEntry = nextEntry->Flink;
  1148. }
  1149. //
  1150. // If we are done with Bus driver group, then it's time to reserved the Hal resources
  1151. // and reserve boot resources
  1152. //
  1153. if (i == BUS_DRIVER_GROUP) {
  1154. //
  1155. // Reserve BOOT configs on Internal bus 0.
  1156. //
  1157. IopAllocateLegacyBootResources(Internal, 0);
  1158. IopAllocateBootResourcesRoutine = IopAllocateBootResources;
  1159. ASSERT(IopInitHalResources == NULL);
  1160. ASSERT(IopInitReservedResourceList == NULL);
  1161. IopBootConfigsReserved = TRUE;
  1162. }
  1163. }
  1164. //
  1165. // If we started a network boot driver, then imitate what DHCP does
  1166. // in sending IOCTLs.
  1167. //
  1168. if (IoRemoteBootClient) {
  1169. //
  1170. // try a hack since TCPIP may not be initialized. (There is no
  1171. // guarantee that if a device is initialized that the protocols are
  1172. // finished binding.) So if the call fails, we just sleep for a bit
  1173. // and try again until it works or we fall out of this loop.
  1174. //
  1175. remotebootcount = 0;
  1176. status = IopStartTcpIpForRemoteBoot(LoaderBlock);
  1177. while ( status == STATUS_DEVICE_DOES_NOT_EXIST && remotebootcount < 20) {
  1178. LARGE_INTEGER Delay;
  1179. //
  1180. // sleep for a second and try again. (-1s in 10ns units)
  1181. //
  1182. Delay.LowPart = 0xff676980 ;
  1183. Delay.HighPart = 0xffffffff ;
  1184. ZwDelayExecution( FALSE, &Delay );
  1185. remotebootcount += 1;
  1186. status = IopStartTcpIpForRemoteBoot(LoaderBlock);
  1187. }
  1188. if (!NT_SUCCESS(status)) {
  1189. KeBugCheckEx( NETWORK_BOOT_INITIALIZATION_FAILED,
  1190. 3,
  1191. status,
  1192. 0,
  1193. 0 );
  1194. }
  1195. }
  1196. //
  1197. // Scan the hardware tree looking for devices which need
  1198. // resources or starting.
  1199. //
  1200. PnPBootDriversLoaded = TRUE;
  1201. PipRequestDeviceAction(NULL, AssignResources, FALSE, 0, NULL, NULL);
  1202. //
  1203. // If start irps are handled asynchronously, we need to make sure all the boot devices
  1204. // started before continue.
  1205. //
  1206. if (!PipWaitForBootDevicesStarted()) {
  1207. HeadlessKernelAddLogEntry(HEADLESS_LOG_WAIT_BOOT_DEVICES_START_FAILED, NULL);
  1208. return FALSE;
  1209. }
  1210. bootReinitDriversFound = IopCallBootDriverReinitializationRoutines();
  1211. //
  1212. // If there were any drivers that registered for boot reinitialization, then
  1213. // we need to wait one more time to make sure we catch any additional
  1214. // devices that were created in response to the reinitialization callback.
  1215. //
  1216. if (bootReinitDriversFound && !PipWaitForBootDevicesStarted()) {
  1217. HeadlessKernelAddLogEntry(HEADLESS_LOG_WAIT_BOOT_DEVICES_REINIT_FAILED, NULL);
  1218. return FALSE;
  1219. }
  1220. //
  1221. // Link NT device names to ARC names now that all of the boot drivers
  1222. // have intialized.
  1223. //
  1224. IopCreateArcNames( LoaderBlock );
  1225. //
  1226. // If we're booting from a RAM disk, initialize it now.
  1227. //
  1228. if ( _memicmp( LoaderBlock->ArcBootDeviceName, "ramdisk(0)", 10 ) == 0 ) {
  1229. status = IopStartRamdisk(LoaderBlock);
  1230. // IopStartRamdisk will bugcheck on any failure.
  1231. ASSERT( NT_SUCCESS(status) );
  1232. if (!PipWaitForBootDevicesStarted()) {
  1233. HeadlessKernelAddLogEntry(HEADLESS_LOG_WAIT_BOOT_DEVICES_START_FAILED, NULL);
  1234. return FALSE;
  1235. }
  1236. }
  1237. //
  1238. // Find and mark the boot partition device object so that if a subsequent
  1239. // access or mount of the device during initialization occurs, an more
  1240. // bugcheck can be produced that helps the user understand why the system
  1241. // is failing to boot and run properly. This occurs when either one of the
  1242. // device drivers or the file system fails to load, or when the file system
  1243. // cannot mount the device for some other reason.
  1244. //
  1245. if (!IopMarkBootPartition( LoaderBlock )) {
  1246. HeadlessKernelAddLogEntry(HEADLESS_LOG_MARK_BOOT_PARTITION_FAILED, NULL);
  1247. return FALSE;
  1248. }
  1249. PnPBootDriversInitialized = TRUE;
  1250. //
  1251. // Go thru every driver that we initialized. If it supports AddDevice yet
  1252. // did not create any device objects after we started it, we should unload
  1253. // it (this is the counterpart to the code in pnpenum that unloads
  1254. // unneccessary filters *after* the paging stack is online).
  1255. //
  1256. // We also mark it as failure so text mode setup knows this driver is not
  1257. // actually needed.
  1258. //
  1259. for (i = 0; i < IopGroupIndex; i++) {
  1260. while (IsListEmpty(&IopGroupTable[i]) == FALSE) {
  1261. nextEntry = RemoveHeadList(&IopGroupTable[i]);
  1262. driverInfo = CONTAINING_RECORD(nextEntry, DRIVER_INFORMATION, Link);
  1263. driverObject = driverInfo->DriverObject;
  1264. if (textModeSetup &&
  1265. (driverInfo->Failed == FALSE) &&
  1266. !IopIsLegacyDriver(driverObject) &&
  1267. (driverObject->DeviceObject == NULL) &&
  1268. !(driverObject->Flags & DRVO_REINIT_REGISTERED)) {
  1269. //
  1270. // If failed is not set and it's not a legacy driver and it has no device object
  1271. // tread it as failure case.
  1272. //
  1273. driverInfo->Failed = TRUE;
  1274. if (!(driverObject->Flags & DRVO_UNLOAD_INVOKED)) {
  1275. driverObject->Flags |= DRVO_UNLOAD_INVOKED;
  1276. if (driverObject->DriverUnload) {
  1277. driverObject->DriverUnload(driverObject);
  1278. }
  1279. ObMakeTemporaryObject( driverObject ); // Reference taken while inserting into the object table.
  1280. ObDereferenceObject(driverObject); // Reference taken when getting driver object pointer.
  1281. }
  1282. }
  1283. if (driverObject) {
  1284. ObDereferenceObject(driverObject); // Reference taken specifically for text mode setup.
  1285. }
  1286. if (driverInfo->Failed) {
  1287. driverInfo->DataTableEntry->LdrEntry->Flags |= LDRP_FAILED_BUILTIN_LOAD;
  1288. }
  1289. ZwClose(driverInfo->ServiceHandle);
  1290. ExFreePool(driverInfo);
  1291. }
  1292. }
  1293. ExFreePool(IopGroupTable);
  1294. //
  1295. // Initialize the drivers necessary to dump all of physical memory to the
  1296. // disk if the system is configured to do so.
  1297. //
  1298. return TRUE;
  1299. }
  1300. NTSTATUS
  1301. PipAddDevicesToBootDriver(
  1302. IN PDRIVER_OBJECT DriverObject
  1303. )
  1304. /*++
  1305. Routine Description:
  1306. This functions is used by Pnp manager to inform a boot device driver of
  1307. all the devices it can possibly control. This routine is for boot
  1308. drivers only.
  1309. Parameters:
  1310. DriverObject - Supplies a driver object to receive its boot devices.
  1311. Return Value:
  1312. NTSTATUS code.
  1313. --*/
  1314. {
  1315. NTSTATUS status;
  1316. //
  1317. // For each device instance in the driver's service/enum key, we will
  1318. // invoke the driver's AddDevice routine and perform enumeration on
  1319. // the device.
  1320. // Note, we don't acquire registry lock before calling IopApplyFunction
  1321. // routine. We know this code is for boot driver initialization. No
  1322. // one else would access the registry Enum key at this time and most
  1323. // important we need the registry lock in other down level routines.
  1324. //
  1325. status = PipApplyFunctionToServiceInstances(
  1326. NULL,
  1327. &DriverObject->DriverExtension->ServiceKeyName,
  1328. KEY_ALL_ACCESS,
  1329. TRUE,
  1330. PipAddDevicesToBootDriverWorker,
  1331. DriverObject,
  1332. NULL
  1333. );
  1334. return status;
  1335. }
  1336. BOOLEAN
  1337. PipAddDevicesToBootDriverWorker(
  1338. IN HANDLE DeviceInstanceHandle,
  1339. IN PUNICODE_STRING DeviceInstancePath,
  1340. IN OUT PVOID Context
  1341. )
  1342. /*++
  1343. Routine Description:
  1344. This routine is a callback function for PipApplyFunctionToServiceInstances.
  1345. It is called for each device instance key referenced by a service instance
  1346. value under the specified service's volatile Enum subkey. The purpose of this
  1347. routine is to invoke the AddDevice() entry of a boot driver with the device
  1348. object.
  1349. Note this routine is also used for the devices controlled by a legacy driver.
  1350. If the specified device instance is controlled by a legacy driver this routine
  1351. sets the device node flags.
  1352. Arguments:
  1353. DeviceInstanceHandle - Supplies a handle to the registry path (relative to
  1354. HKLM\CCS\System\Enum) to this device instance.
  1355. DeviceInstancePath - Supplies the registry path (relative to HKLM\CCS\System\Enum)
  1356. to this device instance.
  1357. Context - Supplies a pointer to a DRIVER_OBJECT structure.
  1358. Return Value:
  1359. TRUE to continue the enumeration.
  1360. FALSE to abort it.
  1361. --*/
  1362. {
  1363. // PDRIVER_OBJECT driverObject = (PDRIVER_OBJECT)Context;
  1364. PDEVICE_OBJECT physicalDevice;
  1365. UNREFERENCED_PARAMETER( Context );
  1366. UNREFERENCED_PARAMETER( DeviceInstanceHandle );
  1367. //
  1368. // Reference the physical device object associated with the device instance.
  1369. //
  1370. physicalDevice = IopDeviceObjectFromDeviceInstance(DeviceInstancePath);
  1371. if (!physicalDevice) {
  1372. return TRUE;
  1373. }
  1374. PipRequestDeviceAction( physicalDevice, AddBootDevices, FALSE, 0, NULL, NULL );
  1375. ObDereferenceObject(physicalDevice);
  1376. return TRUE;
  1377. }
  1378. BOOLEAN
  1379. IopInitializeSystemDrivers(
  1380. VOID
  1381. )
  1382. /*++
  1383. Routine Description:
  1384. This routine is invoked to load and initialize all of the drivers that
  1385. are supposed to be loaded during Phase 1 initialization of the I/O
  1386. system. This is accomplished by calling the Configuration Manager to
  1387. get a NULL-terminated array of handles to the open keys for each driver
  1388. that is to be loaded, and then loading and initializing the driver.
  1389. Arguments:
  1390. None.
  1391. Return Value:
  1392. The function value is a BOOLEAN indicating whether or not the drivers
  1393. were successfully loaded and initialized.
  1394. --*/
  1395. {
  1396. NTSTATUS status, driverEntryStatus;
  1397. PHANDLE driverList;
  1398. PHANDLE savedList;
  1399. HANDLE enumHandle;
  1400. PKEY_VALUE_FULL_INFORMATION keyValueInformation;
  1401. UNICODE_STRING groupName, enumName;
  1402. PTREE_ENTRY treeEntry;
  1403. UNICODE_STRING driverName;
  1404. PDRIVER_OBJECT driverObject;
  1405. KEVENT completionEvent;
  1406. // PpReleaseBootDDB();
  1407. KeInitializeEvent( &completionEvent, NotificationEvent, FALSE );
  1408. status = PipRequestDeviceAction( IopRootDeviceNode->PhysicalDeviceObject,
  1409. StartSystemDevices,
  1410. FALSE,
  1411. 0,
  1412. &completionEvent,
  1413. NULL);
  1414. if (NT_SUCCESS(status)) {
  1415. status = KeWaitForSingleObject( &completionEvent,
  1416. Executive,
  1417. KernelMode,
  1418. FALSE,
  1419. NULL);
  1420. }
  1421. //
  1422. // Walk thru the service list to load the remaining system start drivers.
  1423. // (Most likely these drivers are software drivers.)
  1424. //
  1425. //
  1426. // Get the list of drivers that are to be loaded during this phase of
  1427. // system initialization, and invoke each driver in turn. Ensure that
  1428. // the list really exists, otherwise get out now.
  1429. //
  1430. driverList = CmGetSystemDriverList();
  1431. if (driverList != NULL) {
  1432. //
  1433. // Walk the entire list, loading each of the drivers if not already loaded,
  1434. // until there are no more drivers in the list.
  1435. //
  1436. for (savedList = driverList; *driverList; driverList++) {
  1437. //
  1438. // Now check if the driver has been loaded already.
  1439. // get the name of the driver object first ...
  1440. //
  1441. status = IopGetDriverNameFromKeyNode( *driverList,
  1442. &driverName );
  1443. if (NT_SUCCESS( status )) {
  1444. driverObject = IopReferenceDriverObjectByName(&driverName);
  1445. RtlFreeUnicodeString(&driverName);
  1446. if (driverObject) {
  1447. //
  1448. // Driver was loaded already. Dereference the driver object
  1449. // and skip it.
  1450. //
  1451. ObDereferenceObject(driverObject);
  1452. ZwClose(*driverList);
  1453. continue;
  1454. }
  1455. }
  1456. //
  1457. // Open registry ServiceKeyName\Enum branch to check if the driver was
  1458. // loaded before but failed.
  1459. //
  1460. PiWstrToUnicodeString(&enumName, REGSTR_KEY_ENUM);
  1461. status = IopOpenRegistryKeyEx( &enumHandle,
  1462. *driverList,
  1463. &enumName,
  1464. KEY_READ
  1465. );
  1466. if (NT_SUCCESS( status )) {
  1467. ULONG startFailed = 0;
  1468. status = IopGetRegistryValue(enumHandle, L"INITSTARTFAILED", &keyValueInformation);
  1469. if (NT_SUCCESS( status )) {
  1470. if (keyValueInformation->DataLength == sizeof(ULONG)) {
  1471. startFailed = *(PULONG)KEY_VALUE_DATA(keyValueInformation);
  1472. }
  1473. ExFreePool( keyValueInformation );
  1474. }
  1475. ZwClose(enumHandle);
  1476. if (startFailed != 0) {
  1477. ZwClose(*driverList);
  1478. continue;
  1479. }
  1480. }
  1481. //
  1482. // The driver is not loaded yet. Load it ...
  1483. //
  1484. status = IopGetRegistryValue( *driverList,
  1485. REGSTR_VALUE_GROUP,
  1486. &keyValueInformation );
  1487. if (NT_SUCCESS( status )) {
  1488. if (keyValueInformation->DataLength) {
  1489. groupName.Length = (USHORT) keyValueInformation->DataLength;
  1490. groupName.MaximumLength = groupName.Length;
  1491. groupName.Buffer = (PWSTR) ((PUCHAR) keyValueInformation + keyValueInformation->DataOffset);
  1492. treeEntry = PipLookupGroupName( &groupName, TRUE );
  1493. } else {
  1494. treeEntry = (PTREE_ENTRY) NULL;
  1495. }
  1496. ExFreePool( keyValueInformation );
  1497. } else {
  1498. treeEntry = (PTREE_ENTRY) NULL;
  1499. }
  1500. if (PipCheckDependencies( *driverList )) {
  1501. if (NT_SUCCESS( IopLoadDriver( *driverList, TRUE, FALSE, &driverEntryStatus ) )) {
  1502. if (treeEntry) {
  1503. treeEntry->DriversLoaded++;
  1504. }
  1505. }
  1506. } else {
  1507. ZwClose(*driverList);
  1508. }
  1509. //
  1510. // The boot process takes a while loading drivers. Indicate that
  1511. // progress is being made.
  1512. //
  1513. InbvIndicateProgress();
  1514. }
  1515. //
  1516. // Finally, free the pool that was allocated for the list and return
  1517. // an indicator the load operation worked.
  1518. //
  1519. ExFreePool( (PVOID) savedList );
  1520. }
  1521. PipRequestDeviceAction( IopRootDeviceNode->PhysicalDeviceObject,
  1522. StartSystemDevices,
  1523. FALSE,
  1524. 0,
  1525. NULL,
  1526. NULL);
  1527. //
  1528. // Mark pnp has completed the driver loading for both system and
  1529. // autoload drivers.
  1530. //
  1531. PnPInitialized = TRUE;
  1532. //
  1533. // We don't need the group order list anymore. Release the cached data
  1534. // associated with it.
  1535. //
  1536. PiInitReleaseCachedGroupInformation();
  1537. //
  1538. // Release the Boot Driver Database information.
  1539. //
  1540. PpReleaseBootDDB();
  1541. //
  1542. // Free the memory allocated to contain the group dependency list.
  1543. //
  1544. if (IopGroupListHead) {
  1545. PipFreeGroupTree( IopGroupListHead );
  1546. }
  1547. return TRUE;
  1548. }
  1549. PTREE_ENTRY
  1550. PipLookupGroupName(
  1551. IN PUNICODE_STRING GroupName,
  1552. IN BOOLEAN Insert
  1553. )
  1554. /*++
  1555. Routine Description:
  1556. This routine looks up a group entry in the group load tree and either
  1557. returns a pointer to it, or optionally creates the entry and inserts
  1558. it into the tree.
  1559. Arguments:
  1560. GroupName - The name of the group to look up, or insert.
  1561. Insert - Indicates whether or not an entry is to be created and inserted
  1562. into the tree if the name does not already exist.
  1563. Return Value:
  1564. The function value is a pointer to the entry for the specified group
  1565. name, or NULL.
  1566. --*/
  1567. {
  1568. PTREE_ENTRY treeEntry;
  1569. PTREE_ENTRY previousEntry;
  1570. //
  1571. // Begin by determining whether or not there are any entries in the tree
  1572. // whatsoever. If not, and it is OK to insert, then insert this entry
  1573. // into the tree.
  1574. //
  1575. if (!IopGroupListHead) {
  1576. if (!Insert) {
  1577. return (PTREE_ENTRY) NULL;
  1578. } else {
  1579. IopGroupListHead = PipCreateEntry( GroupName );
  1580. return IopGroupListHead;
  1581. }
  1582. }
  1583. //
  1584. // The tree is not empty, so actually attempt to do a lookup.
  1585. //
  1586. treeEntry = IopGroupListHead;
  1587. for (;;) {
  1588. if (GroupName->Length < treeEntry->GroupName.Length) {
  1589. if (treeEntry->Left) {
  1590. treeEntry = treeEntry->Left;
  1591. } else {
  1592. if (!Insert) {
  1593. return (PTREE_ENTRY) NULL;
  1594. } else {
  1595. treeEntry->Left = PipCreateEntry( GroupName );
  1596. return treeEntry->Left;
  1597. }
  1598. }
  1599. } else if (GroupName->Length > treeEntry->GroupName.Length) {
  1600. if (treeEntry->Right) {
  1601. treeEntry = treeEntry->Right;
  1602. } else {
  1603. if (!Insert) {
  1604. return (PTREE_ENTRY) NULL;
  1605. } else {
  1606. treeEntry->Right = PipCreateEntry( GroupName );
  1607. return treeEntry->Right;
  1608. }
  1609. }
  1610. } else {
  1611. if (!RtlEqualUnicodeString( GroupName, &treeEntry->GroupName, TRUE )) {
  1612. previousEntry = treeEntry;
  1613. while (treeEntry->Sibling) {
  1614. treeEntry = treeEntry->Sibling;
  1615. if (RtlEqualUnicodeString( GroupName, &treeEntry->GroupName, TRUE )) {
  1616. return treeEntry;
  1617. }
  1618. previousEntry = previousEntry->Sibling;
  1619. }
  1620. if (!Insert) {
  1621. return (PTREE_ENTRY) NULL;
  1622. } else {
  1623. previousEntry->Sibling = PipCreateEntry( GroupName );
  1624. return previousEntry->Sibling;
  1625. }
  1626. } else {
  1627. return treeEntry;
  1628. }
  1629. }
  1630. }
  1631. }
  1632. USHORT
  1633. PipGetDriverTagPriority (
  1634. IN HANDLE ServiceHandle
  1635. )
  1636. /*++
  1637. Routine Description:
  1638. This routine reads the Tag value of a driver and determine the tag's priority
  1639. among its driver group.
  1640. Arguments:
  1641. ServiceHandle - specifies the handle of the driver's service key.
  1642. Return Value:
  1643. USHORT for priority.
  1644. --*/
  1645. {
  1646. NTSTATUS status;
  1647. PKEY_VALUE_FULL_INFORMATION keyValueInformationGroup;
  1648. PKEY_VALUE_FULL_INFORMATION keyValueInformationTag;
  1649. PKEY_VALUE_FULL_INFORMATION keyValueInformationGroupOrderList;
  1650. UNICODE_STRING groupName;
  1651. HANDLE handle;
  1652. USHORT index = (USHORT) -1;
  1653. PULONG groupOrder;
  1654. ULONG count, tag;
  1655. //
  1656. // Open System\CurrentControlSet\Control\GroupOrderList
  1657. //
  1658. PiWstrToUnicodeString(&groupName, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\GroupOrderList");
  1659. status = IopOpenRegistryKeyEx( &handle,
  1660. NULL,
  1661. &groupName,
  1662. KEY_READ
  1663. );
  1664. if (!NT_SUCCESS( status )) {
  1665. return index;
  1666. }
  1667. //
  1668. // Read service key's Group value
  1669. //
  1670. status = IopGetRegistryValue (ServiceHandle,
  1671. REGSTR_VALUE_GROUP,
  1672. &keyValueInformationGroup);
  1673. if (NT_SUCCESS(status)) {
  1674. //
  1675. // Try to read what caller wants.
  1676. //
  1677. if ((keyValueInformationGroup->Type == REG_SZ) &&
  1678. (keyValueInformationGroup->DataLength != 0)) {
  1679. IopRegistryDataToUnicodeString(&groupName,
  1680. (PWSTR)KEY_VALUE_DATA(keyValueInformationGroup),
  1681. keyValueInformationGroup->DataLength
  1682. );
  1683. }
  1684. } else {
  1685. //
  1686. // If we failed to read the Group value, or no Group value...
  1687. //
  1688. ZwClose(handle);
  1689. return index;
  1690. }
  1691. //
  1692. // Read service key's Tag value
  1693. //
  1694. tag = 0;
  1695. status = IopGetRegistryValue (ServiceHandle,
  1696. L"Tag",
  1697. &keyValueInformationTag);
  1698. if (NT_SUCCESS(status)) {
  1699. //
  1700. // Try to read what caller wants.
  1701. //
  1702. if ((keyValueInformationTag->Type == REG_DWORD) &&
  1703. (keyValueInformationTag->DataLength == sizeof(ULONG))) {
  1704. tag = *(PULONG)KEY_VALUE_DATA(keyValueInformationTag);
  1705. } else {
  1706. status = STATUS_UNSUCCESSFUL;
  1707. }
  1708. ExFreePool(keyValueInformationTag);
  1709. }
  1710. if (!NT_SUCCESS(status)) {
  1711. //
  1712. // If we failed to read the Group value, or no Group value...
  1713. //
  1714. ExFreePool(keyValueInformationGroup);
  1715. ZwClose(handle);
  1716. return index;
  1717. }
  1718. //
  1719. // Read group order list value for the driver's Group
  1720. //
  1721. status = IopGetRegistryValue (handle,
  1722. groupName.Buffer,
  1723. &keyValueInformationGroupOrderList);
  1724. ExFreePool(keyValueInformationGroup);
  1725. ZwClose(handle);
  1726. if (NT_SUCCESS(status)) {
  1727. //
  1728. // Try to read what caller wants.
  1729. //
  1730. if ((keyValueInformationGroupOrderList->Type == REG_BINARY) &&
  1731. (keyValueInformationGroupOrderList->DataLength >= sizeof(ULONG))) {
  1732. groupOrder = (PULONG)KEY_VALUE_DATA(keyValueInformationGroupOrderList);
  1733. count = *groupOrder;
  1734. ASSERT((count + 1) * sizeof(ULONG) <= keyValueInformationGroupOrderList->DataLength);
  1735. if ((count + 1) * sizeof(ULONG) <= keyValueInformationGroupOrderList->DataLength) {
  1736. groupOrder++;
  1737. for (index = 1; index <= count; index++) {
  1738. if (tag == *groupOrder) {
  1739. break;
  1740. } else {
  1741. groupOrder++;
  1742. }
  1743. }
  1744. }
  1745. }
  1746. ExFreePool(keyValueInformationGroupOrderList);
  1747. } else {
  1748. //
  1749. // If we failed to read the Group value, or no Group value...
  1750. //
  1751. return index;
  1752. }
  1753. return index;
  1754. }
  1755. VOID
  1756. PipInsertDriverList (
  1757. IN PLIST_ENTRY ListHead,
  1758. IN PDRIVER_INFORMATION DriverInfo
  1759. )
  1760. /*++
  1761. Routine Description:
  1762. This routine reads the Tag value of a driver and determine the tag's priority
  1763. among its driver group.
  1764. Arguments:
  1765. ServiceHandle - specifies the handle of the driver's service key.
  1766. Return Value:
  1767. USHORT for priority.
  1768. --*/
  1769. {
  1770. PLIST_ENTRY nextEntry;
  1771. PDRIVER_INFORMATION info;
  1772. nextEntry = ListHead->Flink;
  1773. while (nextEntry != ListHead) {
  1774. info = CONTAINING_RECORD(nextEntry, DRIVER_INFORMATION, Link);
  1775. //
  1776. // Scan the driver info list to find the driver whose priority is
  1777. // lower than current driver's.
  1778. // (Lower TagPosition value means higher Priority)
  1779. //
  1780. if (info->TagPosition > DriverInfo->TagPosition) {
  1781. break;
  1782. }
  1783. nextEntry = nextEntry->Flink;
  1784. }
  1785. //
  1786. // Insert the Driver info to the front of the nextEntry
  1787. //
  1788. nextEntry = nextEntry->Blink;
  1789. InsertHeadList(nextEntry, &DriverInfo->Link);
  1790. }
  1791. VOID
  1792. PipNotifySetupDevices (
  1793. PDEVICE_NODE DeviceNode
  1794. )
  1795. /*++
  1796. Routine Description:
  1797. This routine notifies setupdd.sys for all the enumerated devices whose
  1798. service have not been setup.
  1799. This routine only gets executed on textmode setup phase.
  1800. Parameters:
  1801. DeviceNode - specifies the root of the subtree to be processed.
  1802. Return Value:
  1803. None.
  1804. --*/
  1805. {
  1806. PDEVICE_NODE deviceNode = DeviceNode->Child;
  1807. PDEVICE_OBJECT deviceObject;
  1808. HANDLE handle;
  1809. UNICODE_STRING unicodeString;
  1810. NTSTATUS status;
  1811. while (deviceNode) {
  1812. PipNotifySetupDevices(deviceNode);
  1813. if (deviceNode->ServiceName.Length == 0) {
  1814. //
  1815. // We only notify setupdd the device nodes which do not have service setup yet.
  1816. // It is impossible that at this point, a device has a service setup and
  1817. // setupdd has to change it.
  1818. //
  1819. deviceObject = deviceNode->PhysicalDeviceObject;
  1820. status = IopDeviceObjectToDeviceInstance(deviceObject, &handle, KEY_ALL_ACCESS);
  1821. if (NT_SUCCESS(status)) {
  1822. //
  1823. // Notify setup about the device.
  1824. //
  1825. IopNotifySetupDeviceArrival(deviceObject, handle, TRUE);
  1826. //
  1827. // Finally register the device
  1828. //
  1829. status = PpDeviceRegistration(
  1830. &deviceNode->InstancePath,
  1831. TRUE,
  1832. &unicodeString // registered ServiceName
  1833. );
  1834. if (NT_SUCCESS(status)) {
  1835. deviceNode->ServiceName = unicodeString;
  1836. if (PipIsDevNodeProblem(deviceNode, CM_PROB_NOT_CONFIGURED)) {
  1837. PipClearDevNodeProblem(deviceNode);
  1838. }
  1839. }
  1840. ZwClose(handle);
  1841. }
  1842. }
  1843. deviceNode = deviceNode->Sibling;
  1844. }
  1845. }
  1846. BOOLEAN
  1847. PipWaitForBootDevicesStarted (
  1848. IN VOID
  1849. )
  1850. /*++
  1851. Routine Description:
  1852. This routine waits for enumeration lock to be released for ALL devices.
  1853. Arguments:
  1854. None.
  1855. Return Value:
  1856. BOOLEAN.
  1857. --*/
  1858. {
  1859. NTSTATUS status;
  1860. //
  1861. // Wait on IoInvalidateDeviceRelations event to make sure all the devcies are enumerated
  1862. // before progressing to mark boot partitions.
  1863. //
  1864. status = KeWaitForSingleObject( &PiEnumerationLock,
  1865. Executive,
  1866. KernelMode,
  1867. FALSE,
  1868. NULL );
  1869. if (!NT_SUCCESS(status)) {
  1870. return FALSE;
  1871. }
  1872. return TRUE;
  1873. }
  1874. BOOLEAN
  1875. PipWaitForBootDevicesDeleted (
  1876. IN VOID
  1877. )
  1878. /*++
  1879. Routine Description:
  1880. This routine waits for IoRequestDeviceRemoval to be completed.
  1881. Arguments:
  1882. None.
  1883. Return Value:
  1884. BOOLEAN.
  1885. --*/
  1886. {
  1887. NTSTATUS status;
  1888. //
  1889. // Wait on device removal event to make sure all the deleted devcies are processed
  1890. // before moving on to process next boot driver.
  1891. //
  1892. status = KeWaitForSingleObject( &PiEventQueueEmpty,
  1893. Executive,
  1894. KernelMode,
  1895. FALSE,
  1896. NULL );
  1897. return (BOOLEAN)NT_SUCCESS(status);
  1898. }
  1899. NTSTATUS
  1900. PipLoadBootFilterDriver (
  1901. IN PUNICODE_STRING DriverName,
  1902. IN ULONG GroupIndex,
  1903. OUT PDRIVER_OBJECT *LoadedFilter
  1904. )
  1905. /*++
  1906. Routine Description:
  1907. This initializes boot filter drivers.
  1908. Arguments:
  1909. DriverName - specifies the name of the driver to be initialized.
  1910. GroupIndex - specifies the Driver's group index (could be anything)
  1911. Return Value:
  1912. PDRIVER_OBJECT
  1913. --*/
  1914. {
  1915. PDRIVER_OBJECT driverObject;
  1916. PLIST_ENTRY nextEntry;
  1917. PDRIVER_INFORMATION driverInfo;
  1918. UNICODE_STRING completeName;
  1919. PBOOT_DRIVER_LIST_ENTRY bootDriver;
  1920. PKLDR_DATA_TABLE_ENTRY driverEntry;
  1921. HANDLE keyHandle;
  1922. NTSTATUS status, retStatus;
  1923. retStatus = STATUS_UNSUCCESSFUL;
  1924. *LoadedFilter = NULL;
  1925. if (IopGroupTable == NULL || GroupIndex >= IopGroupIndex) {
  1926. //
  1927. // If we have not reached the boot driver initialization phase or
  1928. // the filter driver is not a boot driver.
  1929. //
  1930. return retStatus;
  1931. }
  1932. //
  1933. // Go thru every driver that we initialized. If it supports AddDevice entry and
  1934. // did not create any device object after we start it. We mark it as failure so
  1935. // text mode setup knows this driver is not needed.
  1936. //
  1937. nextEntry = IopGroupTable[GroupIndex].Flink;
  1938. while (nextEntry != &IopGroupTable[GroupIndex]) {
  1939. driverInfo = CONTAINING_RECORD(nextEntry, DRIVER_INFORMATION, Link);
  1940. keyHandle = driverInfo->ServiceHandle;
  1941. status = IopGetDriverNameFromKeyNode(
  1942. keyHandle,
  1943. &completeName);
  1944. if (NT_SUCCESS(status)) {
  1945. if (RtlEqualUnicodeString(DriverName,
  1946. &completeName,
  1947. TRUE)) { // case-insensitive
  1948. if (driverInfo->Processed == FALSE) {
  1949. bootDriver = driverInfo->DataTableEntry;
  1950. driverEntry = bootDriver->LdrEntry;
  1951. driverInfo->Status = IopInitializeBuiltinDriver(
  1952. &completeName,
  1953. &bootDriver->RegistryPath,
  1954. (PDRIVER_INITIALIZE) (ULONG_PTR) driverEntry->EntryPoint,
  1955. driverEntry,
  1956. TRUE,
  1957. &driverObject);
  1958. retStatus = driverInfo->Status;
  1959. driverInfo->DriverObject = driverObject;
  1960. driverInfo->Processed = TRUE;
  1961. //
  1962. // Pnp might unload the driver before we get a chance to
  1963. // look at this. So take an extra reference.
  1964. //
  1965. if (driverObject) {
  1966. ObReferenceObject(driverObject);
  1967. *LoadedFilter = driverObject;
  1968. } else {
  1969. driverInfo->Failed = TRUE;
  1970. }
  1971. } else {
  1972. retStatus = driverInfo->Status;
  1973. }
  1974. ExFreePool(completeName.Buffer);
  1975. break;
  1976. }
  1977. ExFreePool(completeName.Buffer);
  1978. }
  1979. nextEntry = nextEntry->Flink;
  1980. }
  1981. return retStatus;
  1982. }
  1983. VOID
  1984. IopMarkHalDeviceNode(
  1985. VOID
  1986. )
  1987. {
  1988. PDEVICE_NODE deviceNode;
  1989. deviceNode = IopRootDeviceNode->Child;
  1990. while (deviceNode) {
  1991. if ((deviceNode->State == DeviceNodeStarted ||
  1992. deviceNode->State == DeviceNodeStartPostWork ) &&
  1993. !(deviceNode->Flags & DNF_LEGACY_DRIVER)) {
  1994. IopInitHalDeviceNode = deviceNode;
  1995. deviceNode->Flags |= DNF_HAL_NODE;
  1996. break;
  1997. }
  1998. deviceNode = deviceNode->Sibling;
  1999. }
  2000. }
  2001. NTSTATUS
  2002. IopPnpDriverStarted(
  2003. IN PDRIVER_OBJECT DriverObject,
  2004. IN HANDLE KeyHandle,
  2005. IN PUNICODE_STRING ServiceName
  2006. )
  2007. {
  2008. NTSTATUS status = STATUS_SUCCESS;
  2009. if (DriverObject->DeviceObject == NULL && ServiceName->Buffer &&
  2010. !IopIsAnyDeviceInstanceEnabled(ServiceName, NULL, FALSE) &&
  2011. !(DriverObject->Flags & DRVO_REINIT_REGISTERED)) {
  2012. IopDriverLoadingFailed(KeyHandle, NULL);
  2013. status = STATUS_PLUGPLAY_NO_DEVICE;
  2014. } else {
  2015. //
  2016. // Start the devices controlled by the driver and enumerate them
  2017. // At this point, we know there is at least one device controlled by the driver.
  2018. //
  2019. IopDeleteLegacyKey(DriverObject);
  2020. }
  2021. return status;
  2022. }
  2023. NTSTATUS
  2024. PiInitCacheGroupInformation(
  2025. VOID
  2026. )
  2027. /*++
  2028. Routine Description:
  2029. This routine caches the service group order list. We only need this list
  2030. while we are processing boot start and system start legacy drivers.
  2031. Parameters:
  2032. None.
  2033. Return Value:
  2034. NTSTATUS.
  2035. --*/
  2036. {
  2037. PKEY_VALUE_FULL_INFORMATION keyValueInformation;
  2038. UNICODE_STRING *groupTable, group;
  2039. NTSTATUS status;
  2040. HANDLE handle;
  2041. ULONG count = 0;
  2042. //
  2043. // Open System\CurrentControlSet\Control\ServiceOrderList
  2044. //
  2045. PiWstrToUnicodeString(
  2046. &group,
  2047. L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\ServiceGroupOrder"
  2048. );
  2049. status = IopOpenRegistryKeyEx(
  2050. &handle,
  2051. NULL,
  2052. &group,
  2053. KEY_READ
  2054. );
  2055. if (!NT_SUCCESS(status)) {
  2056. return status;
  2057. }
  2058. //
  2059. // Read and build a unicode string array containing all the group names.
  2060. //
  2061. status = IopGetRegistryValue(
  2062. handle,
  2063. L"List",
  2064. &keyValueInformation
  2065. );
  2066. ZwClose(handle);
  2067. groupTable = NULL;
  2068. if (NT_SUCCESS(status)) {
  2069. if ((keyValueInformation->Type == REG_MULTI_SZ) &&
  2070. (keyValueInformation->DataLength != 0)) {
  2071. status = PipRegMultiSzToUnicodeStrings(keyValueInformation, &groupTable, &count);
  2072. } else {
  2073. status = STATUS_UNSUCCESSFUL;
  2074. }
  2075. ExFreePool(keyValueInformation);
  2076. }
  2077. if (!NT_SUCCESS(status)) {
  2078. return status;
  2079. }
  2080. PiInitGroupOrderTable = groupTable;
  2081. PiInitGroupOrderTableCount = (USHORT) count;
  2082. return STATUS_SUCCESS;
  2083. }
  2084. VOID
  2085. PiInitReleaseCachedGroupInformation(
  2086. VOID
  2087. )
  2088. /*++
  2089. Routine Description:
  2090. This routine releases the service group order list cache. It should be
  2091. called just after the system start legacy drivers have been loaded.
  2092. Parameters:
  2093. None.
  2094. Return Value:
  2095. None.
  2096. --*/
  2097. {
  2098. ASSERT(PnPInitialized);
  2099. if (PiInitGroupOrderTable) {
  2100. PipFreeUnicodeStringList(
  2101. PiInitGroupOrderTable,
  2102. PiInitGroupOrderTableCount
  2103. );
  2104. PiInitGroupOrderTable = NULL;
  2105. PiInitGroupOrderTableCount = 0;
  2106. }
  2107. }
  2108. USHORT
  2109. PpInitGetGroupOrderIndex(
  2110. IN HANDLE ServiceHandle
  2111. )
  2112. /*++
  2113. Routine Description:
  2114. This routine reads the Group value of the service key, finds its position
  2115. in the ServiceOrderList. If ServiceHandle is NULL or unrecognized group
  2116. value, it returns a value with max group order + 1.
  2117. Parameters:
  2118. ServiceHandle - supplies a handle to the service key.
  2119. Return Value:
  2120. group order index.
  2121. --*/
  2122. {
  2123. NTSTATUS status;
  2124. PKEY_VALUE_FULL_INFORMATION keyValueInformation;
  2125. UNICODE_STRING group;
  2126. USHORT index;
  2127. PAGED_CODE();
  2128. ASSERT(!PnPInitialized);
  2129. if (PiInitGroupOrderTable == NULL) {
  2130. return NO_MORE_GROUP;
  2131. }
  2132. if (ServiceHandle == NULL) {
  2133. return PiInitGroupOrderTableCount + 1;
  2134. }
  2135. //
  2136. // Read service key's Group value
  2137. //
  2138. status = IopGetRegistryValue(
  2139. ServiceHandle,
  2140. REGSTR_VALUE_GROUP,
  2141. &keyValueInformation
  2142. );
  2143. if (!NT_SUCCESS(status)) {
  2144. //
  2145. // If we failed to read the Group value, or no Group value...
  2146. //
  2147. return PiInitGroupOrderTableCount;
  2148. }
  2149. //
  2150. // Verify type information
  2151. //
  2152. if ((keyValueInformation->Type != REG_SZ) ||
  2153. (keyValueInformation->DataLength == 0)) {
  2154. ASSERT(0);
  2155. ExFreePool(keyValueInformation);
  2156. return PiInitGroupOrderTableCount;
  2157. }
  2158. IopRegistryDataToUnicodeString(
  2159. &group,
  2160. (PWSTR)KEY_VALUE_DATA(keyValueInformation),
  2161. keyValueInformation->DataLength
  2162. );
  2163. for (index = 0; index < PiInitGroupOrderTableCount; index++) {
  2164. if (RtlEqualUnicodeString(&group, &PiInitGroupOrderTable[index], TRUE)) {
  2165. break;
  2166. }
  2167. }
  2168. ExFreePool(keyValueInformation);
  2169. return index;
  2170. }
  2171. BOOLEAN
  2172. PpInitSystem (
  2173. VOID
  2174. )
  2175. /*++
  2176. Routine Description:
  2177. This function performs initialization of the kernel-mode Plug and Play
  2178. Manager. It is called during phase 0 and phase 1 initialization. Its
  2179. function is to dispatch to the appropriate phase initialization routine.
  2180. Arguments:
  2181. None.
  2182. Return Value:
  2183. TRUE - Initialization succeeded.
  2184. FALSE - Initialization failed.
  2185. --*/
  2186. {
  2187. switch ( InitializationPhase ) {
  2188. case 0 :
  2189. return PiInitPhase0();
  2190. case 1 :
  2191. return PiInitPhase1();
  2192. default:
  2193. KeBugCheckEx(UNEXPECTED_INITIALIZATION_CALL, 2, InitializationPhase, 0, 0);
  2194. }
  2195. }
  2196. BOOLEAN
  2197. PiInitPhase0(
  2198. VOID
  2199. )
  2200. /*++
  2201. Routine Description:
  2202. This function performs Phase 0 initializaion of the Plug and Play Manager
  2203. component of the NT system. It initializes the PnP registry and bus list
  2204. resources, and initializes the bus list head to empty.
  2205. Arguments:
  2206. None.
  2207. Return Value:
  2208. TRUE - Initialization succeeded.
  2209. FALSE - Initialization failed.
  2210. --*/
  2211. {
  2212. //
  2213. // Initialize the device-specific, Plug and Play registry resource.
  2214. //
  2215. ExInitializeResourceLite( &PpRegistryDeviceResource );
  2216. PpInitializeDeviceReferenceTable();
  2217. return TRUE;
  2218. }
  2219. BOOLEAN
  2220. PiInitPhase1(
  2221. VOID
  2222. )
  2223. /*++
  2224. Routine Description:
  2225. This function performs Phase 0 initializaion of the Plug and Play Manager
  2226. component of the NT system. It initializes the PnP registry and bus list
  2227. resources, and initializes the bus list head to empty.
  2228. Arguments:
  2229. None.
  2230. Return Value:
  2231. TRUE - Initialization succeeded.
  2232. FALSE - Initialization failed.
  2233. --*/
  2234. {
  2235. NTSTATUS status;
  2236. HANDLE hCurrentControlSet, handle;
  2237. UNICODE_STRING unicodeName;
  2238. PKEY_VALUE_FULL_INFORMATION detectionInfo;
  2239. status = IopOpenRegistryKeyEx( &hCurrentControlSet,
  2240. NULL,
  2241. &CmRegistryMachineSystemCurrentControlSet,
  2242. KEY_ALL_ACCESS
  2243. );
  2244. if (NT_SUCCESS(status)) {
  2245. PiWstrToUnicodeString(&unicodeName, REGSTR_PATH_CONTROL_PNP);
  2246. status = IopCreateRegistryKeyEx( &handle,
  2247. hCurrentControlSet,
  2248. &unicodeName,
  2249. KEY_ALL_ACCESS,
  2250. REG_OPTION_NON_VOLATILE,
  2251. NULL);
  2252. if (NT_SUCCESS(status)) {
  2253. //
  2254. // Check the "DisableFirmwareMapper" value entry to see whether we
  2255. // should skip mapping ntdetect/firmware reported devices (except for
  2256. // COM ports, which we always map).
  2257. //
  2258. status = IopGetRegistryValue(handle,
  2259. REGSTR_VALUE_DISABLE_FIRMWARE_MAPPER,
  2260. &detectionInfo);
  2261. if (NT_SUCCESS(status)) {
  2262. if (detectionInfo->Type == REG_DWORD && detectionInfo->DataLength == sizeof(ULONG)) {
  2263. PpDisableFirmwareMapper = (BOOLEAN)*(KEY_VALUE_DATA(detectionInfo));
  2264. }
  2265. ExFreePool(detectionInfo);
  2266. }
  2267. ZwClose(handle);
  2268. }
  2269. ZwClose(hCurrentControlSet);
  2270. }
  2271. #if defined(_X86_)
  2272. if (!PpDisableFirmwareMapper) {
  2273. PnPBiosInitializePnPBios();
  2274. }
  2275. #endif
  2276. return TRUE;
  2277. }
  2278. NTSTATUS
  2279. IopStartRamdisk(
  2280. PLOADER_PARAMETER_BLOCK LoaderBlock
  2281. )
  2282. {
  2283. ULONG code;
  2284. NTSTATUS status;
  2285. WCHAR buffer[ RAMDISK_MAX_DEVICE_NAME ];
  2286. UNICODE_STRING guidString;
  2287. PLIST_ENTRY listEntry;
  2288. PMEMORY_ALLOCATION_DESCRIPTOR memoryDescriptor = NULL;
  2289. UNICODE_STRING ustring;
  2290. UNICODE_STRING ustring2;
  2291. UNICODE_STRING string;
  2292. RAMDISK_CREATE_INPUT create;
  2293. OBJECT_ATTRIBUTES obja;
  2294. IO_STATUS_BLOCK iosb;
  2295. HANDLE handle = NULL;
  2296. PCHAR options;
  2297. //
  2298. // Find the descriptor for the memory block into which the loader read the
  2299. // disk image.
  2300. //
  2301. for ( listEntry = LoaderBlock->MemoryDescriptorListHead.Flink;
  2302. listEntry != &LoaderBlock->MemoryDescriptorListHead;
  2303. listEntry = listEntry->Flink ) {
  2304. memoryDescriptor = CONTAINING_RECORD(listEntry,
  2305. MEMORY_ALLOCATION_DESCRIPTOR,
  2306. ListEntry);
  2307. if (memoryDescriptor->MemoryType == LoaderXIPRom) {
  2308. break;
  2309. }
  2310. }
  2311. if ( listEntry == &LoaderBlock->MemoryDescriptorListHead ) {
  2312. KdPrint(( "IopStartRamdisk: Couldn't find LoaderXIPRom descriptor\n" ));
  2313. code = 1;
  2314. status = STATUS_INVALID_PARAMETER;
  2315. goto failed;
  2316. }
  2317. //
  2318. // Build the IOCTL parameter block.
  2319. //
  2320. RtlZeroMemory( &create, sizeof(create) );
  2321. create.Version = sizeof(create);
  2322. create.DiskType = RAMDISK_TYPE_BOOT_DISK;
  2323. create.BasePage = memoryDescriptor->BasePage;
  2324. create.DriveLetter = L'C'; // ISSUE: Does this need to be configurable?
  2325. create.Options.Fixed = (BOOLEAN)TRUE;
  2326. create.Options.Readonly = (BOOLEAN)FALSE;
  2327. create.Options.NoDriveLetter = (BOOLEAN)FALSE;
  2328. create.Options.Hidden = (BOOLEAN)FALSE;
  2329. create.Options.NoDosDevice = (BOOLEAN)FALSE;
  2330. //
  2331. // Use the well-known boot disk GUID.
  2332. //
  2333. create.DiskGuid = RamdiskBootDiskGuid;
  2334. //
  2335. // Look for RDIMAGEOFFSET and RDIMAGELENGTH load options.
  2336. //
  2337. create.DiskOffset = 0;
  2338. create.DiskLength = memoryDescriptor->PageCount * PAGE_SIZE;
  2339. options = LoaderBlock->LoadOptions;
  2340. if ( options != NULL ) {
  2341. PCHAR option;
  2342. _strupr( options );
  2343. option = strstr( options, "RDIMAGEOFFSET" );
  2344. if ( option != NULL ) {
  2345. option = strstr( option, "=" );
  2346. if ( option != NULL ) {
  2347. create.DiskOffset = atol( option + 1 );
  2348. }
  2349. }
  2350. create.DiskLength -= create.DiskOffset;
  2351. option = strstr( options, "RDIMAGELENGTH" );
  2352. if ( option != NULL ) {
  2353. option = strstr( option, "=" );
  2354. if ( option != NULL ) {
  2355. ULONGLONG length = _atoi64( option + 1 );
  2356. ASSERT( length <= create.DiskLength );
  2357. create.DiskLength = length;
  2358. }
  2359. }
  2360. }
  2361. //
  2362. // Send an IOCTL to ramdisk.sys telling it to create the RAM disk.
  2363. //
  2364. PiWstrToUnicodeString( &string, RAMDISK_DEVICENAME );
  2365. InitializeObjectAttributes( &obja,
  2366. &string,
  2367. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
  2368. NULL,
  2369. NULL );
  2370. status = ZwOpenFile(
  2371. &handle,
  2372. GENERIC_READ | GENERIC_WRITE,
  2373. &obja,
  2374. &iosb,
  2375. FILE_SHARE_READ | FILE_SHARE_WRITE,
  2376. FILE_SYNCHRONOUS_IO_NONALERT
  2377. );
  2378. if ( NT_SUCCESS(status) ) {
  2379. status = iosb.Status;
  2380. }
  2381. if ( !NT_SUCCESS(status) ) {
  2382. KdPrint(( "IopStartRamdisk: Error opening %wZ. Error: %x\n", &string, status ));
  2383. code = 2;
  2384. goto failed;
  2385. }
  2386. status = ZwDeviceIoControlFile(
  2387. handle,
  2388. NULL,
  2389. NULL,
  2390. NULL,
  2391. &iosb,
  2392. FSCTL_CREATE_RAM_DISK,
  2393. &create,
  2394. sizeof(create),
  2395. NULL,
  2396. 0
  2397. );
  2398. ZwClose( handle );
  2399. if ( NT_SUCCESS(status) ) {
  2400. status = iosb.Status;
  2401. }
  2402. if ( !NT_SUCCESS(status) ) {
  2403. KdPrint(( "IopStartRamdisk: Error creating RAM disk: %x\n", status ));
  2404. code = 3;
  2405. goto failed;
  2406. }
  2407. //
  2408. // Create an ARC name pointing ramdisk(0) to the RAM disk.
  2409. //
  2410. status = RtlStringFromGUID( &create.DiskGuid, &guidString);
  2411. if ( !NT_SUCCESS(status) ) {
  2412. KdPrint(( "IopStartRamdisk: Error creating disk GUID string: %x\n", status ));
  2413. code = 4;
  2414. goto failed;
  2415. }
  2416. StringCbPrintfW(buffer, sizeof(buffer), L"\\Device\\Ramdisk%wZ", &guidString);
  2417. PiWstrToUnicodeString( &ustring, L"\\ArcName\\ramdisk(0)" );
  2418. RtlInitUnicodeString( &ustring2, buffer );
  2419. status = IoCreateSymbolicLink( &ustring, &ustring2 );
  2420. RtlFreeUnicodeString( &guidString );
  2421. if (!NT_SUCCESS(status)) {
  2422. KdPrint(( "IopStartRamdisk: Failed to create arcname symbolic link (%wZ --> %wZ). %x\n",
  2423. &ustring, &ustring2, status ));
  2424. code = 5;
  2425. goto failed;
  2426. }
  2427. return STATUS_SUCCESS;
  2428. failed:
  2429. KeBugCheckEx( RAMDISK_BOOT_INITIALIZATION_FAILED,
  2430. code,
  2431. status,
  2432. 0,
  2433. 0 );
  2434. } // IopStartRamdisk