Source code of Windows XP (NT5)
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.

3144 lines
87 KiB

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