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.

719 lines
20 KiB

  1. /*++
  2. Copyright (c) 1990, 1991 Microsoft Corporation
  3. Module Name:
  4. cmconfig.c
  5. Abstract:
  6. This module is responsible to build the hardware tree of the
  7. registry data base.
  8. Author:
  9. Shie-Lin Tzong (shielint) 23-Jan-1992
  10. Environment:
  11. Kernel mode.
  12. Revision History:
  13. --*/
  14. #include "cmp.h"
  15. //
  16. // Title Index - Never used for Product 1, set to 0 for now.
  17. //
  18. #define TITLE_INDEX_VALUE 0
  19. extern ULONG CmpTypeCount[];
  20. #define EISA_ADAPTER_INDEX EisaAdapter
  21. #define TURBOCHANNEL_ADAPTER_INDEX TcAdapter
  22. //
  23. // The following variables are used to cross-reference multifunction
  24. // adapters to their corresponding NT interface type.
  25. //
  26. extern struct {
  27. PUCHAR AscString;
  28. USHORT InterfaceType;
  29. USHORT Count;
  30. } CmpMultifunctionTypes[];
  31. extern USHORT CmpUnknownBusCount;
  32. //
  33. // CmpConfigurationData - A pointer to the area reserved for the purpose
  34. // of reconstructing Configuration Data.
  35. //
  36. // CmpConfigurationAreaSize - Record the size of the Configuration Data
  37. // area.
  38. extern ULONG CmpConfigurationAreaSize;
  39. extern PCM_FULL_RESOURCE_DESCRIPTOR CmpConfigurationData;
  40. //
  41. // Function prototypes for internal erferences
  42. //
  43. NTSTATUS
  44. CmpSetupConfigurationTree(
  45. IN PCONFIGURATION_COMPONENT_DATA CurrentEntry,
  46. IN HANDLE ParentHandle,
  47. IN INTERFACE_TYPE InterfaceType,
  48. IN ULONG BusNumber
  49. );
  50. #ifdef ALLOC_PRAGMA
  51. #pragma alloc_text(INIT,CmpInitializeHardwareConfiguration)
  52. #pragma alloc_text(INIT,CmpSetupConfigurationTree)
  53. #pragma alloc_text(INIT,CmpInitializeRegistryNode)
  54. #endif
  55. NTSTATUS
  56. CmpInitializeHardwareConfiguration(
  57. IN PLOADER_PARAMETER_BLOCK LoaderBlock
  58. )
  59. /*++
  60. Routine Description:
  61. This routine creates \\Registry\Machine\Hardware node in
  62. the registry and calls SetupTree routine to put the hardware
  63. information to the registry.
  64. Arguments:
  65. LoaderBlock - supplies a pointer to the LoaderBlock passed in from the
  66. OS Loader.
  67. Returns:
  68. NTSTATUS code for sucess or reason of failure.
  69. --*/
  70. {
  71. NTSTATUS Status;
  72. OBJECT_ATTRIBUTES ObjectAttributes;
  73. HANDLE BaseHandle;
  74. PCONFIGURATION_COMPONENT_DATA ConfigurationRoot;
  75. ULONG Disposition;
  76. ConfigurationRoot = (PCONFIGURATION_COMPONENT_DATA)LoaderBlock->ConfigurationRoot;
  77. //
  78. // Create \\Registry\Machine\Hardware\DeviceMap
  79. //
  80. InitializeObjectAttributes(
  81. &ObjectAttributes,
  82. &CmRegistryMachineHardwareDeviceMapName,
  83. 0,
  84. (HANDLE)NULL,
  85. NULL
  86. );
  87. ObjectAttributes.Attributes |= OBJ_CASE_INSENSITIVE;
  88. Status = NtCreateKey( // Paht may already exist
  89. &BaseHandle,
  90. KEY_READ | KEY_WRITE,
  91. &ObjectAttributes,
  92. TITLE_INDEX_VALUE,
  93. NULL,
  94. 0,
  95. &Disposition
  96. );
  97. if (!NT_SUCCESS(Status)) {
  98. return(Status);
  99. }
  100. NtClose(BaseHandle);
  101. ASSERT(Disposition == REG_CREATED_NEW_KEY);
  102. //
  103. // Create \\Registry\Machine\Hardware\Description and use the
  104. // returned handle as the BaseHandle to build the hardware tree.
  105. //
  106. InitializeObjectAttributes(
  107. &ObjectAttributes,
  108. &CmRegistryMachineHardwareDescriptionName,
  109. 0,
  110. (HANDLE)NULL,
  111. NULL
  112. );
  113. ObjectAttributes.Attributes |= OBJ_CASE_INSENSITIVE;
  114. Status = NtCreateKey( // Path may already exist
  115. &BaseHandle,
  116. KEY_READ | KEY_WRITE,
  117. &ObjectAttributes,
  118. TITLE_INDEX_VALUE,
  119. NULL,
  120. 0,
  121. &Disposition
  122. );
  123. if (!NT_SUCCESS(Status)) {
  124. return(Status);
  125. }
  126. ASSERT(Disposition == REG_CREATED_NEW_KEY);
  127. //
  128. // Allocate 16K bytes memory from paged pool for constructing
  129. // configuration data for controller component.
  130. // NOTE: The configuration Data for controller component
  131. // usually takes less than 100 bytes. But on EISA machine, the
  132. // EISA configuration information takes more than 10K and up to
  133. // 64K. I believe 16K is the reasonable number to handler 99.9%
  134. // of the machines. Therefore, 16K is the initial value.
  135. //
  136. CmpConfigurationData = (PCM_FULL_RESOURCE_DESCRIPTOR)ExAllocatePool(
  137. PagedPool,
  138. CmpConfigurationAreaSize
  139. );
  140. if (CmpConfigurationData == NULL) {
  141. return(STATUS_INSUFFICIENT_RESOURCES);
  142. }
  143. //
  144. // Call SetupConfigurationTree routine to go over each component
  145. // of the tree and add component information to registry database.
  146. //
  147. if (ConfigurationRoot) {
  148. Status = CmpSetupConfigurationTree(ConfigurationRoot,
  149. BaseHandle,
  150. -1,
  151. (ULONG)-1);
  152. } else {
  153. Status = STATUS_SUCCESS;
  154. }
  155. ExFreePool((PVOID)CmpConfigurationData);
  156. NtClose(BaseHandle);
  157. return(Status);
  158. }
  159. NTSTATUS
  160. CmpSetupConfigurationTree(
  161. IN PCONFIGURATION_COMPONENT_DATA CurrentEntry,
  162. IN HANDLE ParentHandle,
  163. IN INTERFACE_TYPE InterfaceType,
  164. IN ULONG BusNumber
  165. )
  166. /*++
  167. Routine Description:
  168. This routine traverses loader configuration tree and register
  169. the hardware information to the registry data base.
  170. Note to reduce the stack usage on machines with large number of PCI buses,
  171. we do not recursively process the sibling nodes. We only recursively
  172. process the child trees.
  173. Arguments:
  174. CurrentEntry - Supplies a pointer to a loader configuration
  175. tree or subtree.
  176. ParentHandle - Supplies the parent handle of CurrentEntry node.
  177. InterfaceType - Specify the Interface type of the bus that the
  178. CurrentEntry component resides.
  179. BusNumber - Specify the Bus Number of the bus that the CurrentEntry
  180. component resides. If Bus number is -1, it means InterfaceType
  181. and BusNumber are meaningless for this component.
  182. Returns:
  183. None.
  184. --*/
  185. {
  186. NTSTATUS Status;
  187. HANDLE NewHandle;
  188. USHORT i;
  189. CONFIGURATION_COMPONENT *Component;
  190. INTERFACE_TYPE LocalInterfaceType = InterfaceType;
  191. ULONG LocalBusNumber = BusNumber;
  192. USHORT DeviceIndexTable[NUMBER_TYPES];
  193. for (i = 0; i < NUMBER_TYPES; i++) {
  194. DeviceIndexTable[i] = 0;
  195. }
  196. //
  197. // Process current entry and its siblings
  198. //
  199. while (CurrentEntry) {
  200. //
  201. // Register current entry first before going down to its children
  202. //
  203. Component = &CurrentEntry->ComponentEntry;
  204. //
  205. // If the current component is a bus component, we will set up
  206. // its bus number and Interface type and use them to initialize
  207. // its subtree.
  208. //
  209. if (Component->Class == AdapterClass &&
  210. CurrentEntry->Parent->ComponentEntry.Class == SystemClass) {
  211. switch (Component->Type) {
  212. case EisaAdapter:
  213. LocalInterfaceType = Eisa;
  214. LocalBusNumber = CmpTypeCount[EISA_ADAPTER_INDEX]++;
  215. break;
  216. case TcAdapter:
  217. LocalInterfaceType = TurboChannel;
  218. LocalBusNumber = CmpTypeCount[TURBOCHANNEL_ADAPTER_INDEX]++;
  219. break;
  220. case MultiFunctionAdapter:
  221. //
  222. // Here we try to distinguish if the Multifunction adapter is
  223. // Isa, Mca, Internal bus and assign BusNumber based on
  224. // its interface type (bus type.)
  225. //
  226. if (Component->Identifier) {
  227. for (i=0; CmpMultifunctionTypes[i].AscString; i++) {
  228. if (_stricmp((PCHAR)CmpMultifunctionTypes[i].AscString,
  229. Component->Identifier) == 0) {
  230. break;
  231. }
  232. }
  233. LocalInterfaceType = CmpMultifunctionTypes[i].InterfaceType;
  234. LocalBusNumber = CmpMultifunctionTypes[i].Count++;
  235. }
  236. break;
  237. case ScsiAdapter:
  238. //
  239. // Set the bus type to internal.
  240. //
  241. LocalInterfaceType = Internal;
  242. LocalBusNumber = CmpTypeCount[ScsiAdapter]++;
  243. break;
  244. default:
  245. LocalInterfaceType = -1;
  246. LocalBusNumber = CmpUnknownBusCount++;
  247. break;
  248. }
  249. }
  250. //
  251. // Initialize and copy current component to hardware registry
  252. //
  253. Status = CmpInitializeRegistryNode(
  254. CurrentEntry,
  255. ParentHandle,
  256. &NewHandle,
  257. LocalInterfaceType,
  258. LocalBusNumber,
  259. DeviceIndexTable
  260. );
  261. if (!NT_SUCCESS(Status)) {
  262. return(Status);
  263. }
  264. //
  265. // Once we are going one level down, we need to clear the TypeCount
  266. // table for everything under the current component class ...
  267. //
  268. if (CurrentEntry->Child) {
  269. //
  270. // Process the child entry of current entry
  271. //
  272. Status = CmpSetupConfigurationTree(CurrentEntry->Child,
  273. NewHandle,
  274. LocalInterfaceType,
  275. LocalBusNumber
  276. );
  277. if (!NT_SUCCESS(Status)) {
  278. NtClose(NewHandle);
  279. return(Status);
  280. }
  281. }
  282. NtClose(NewHandle);
  283. CurrentEntry = CurrentEntry->Sibling;
  284. }
  285. return(STATUS_SUCCESS);
  286. }
  287. NTSTATUS
  288. CmpInitializeRegistryNode(
  289. IN PCONFIGURATION_COMPONENT_DATA CurrentEntry,
  290. IN HANDLE ParentHandle,
  291. OUT PHANDLE NewHandle,
  292. IN INTERFACE_TYPE InterfaceType,
  293. IN ULONG BusNumber,
  294. IN PUSHORT DeviceIndexTable
  295. )
  296. /*++
  297. Routine Description:
  298. This routine creates a node for the current firmware component
  299. and puts component data to the data part of the node.
  300. Arguments:
  301. CurrentEntry - Supplies a pointer to a configuration component.
  302. Handle - Supplies the parent handle of CurrentEntry node.
  303. NewHandle - Suppiles a pointer to a HANDLE to receive the handle of
  304. the newly created node.
  305. InterfaceType - Specify the Interface type of the bus that the
  306. CurrentEntry component resides. (See BusNumber also)
  307. BusNumber - Specify the Bus Number of the bus that the CurrentEntry
  308. component resides on. If Bus number is -1, it means InterfaceType
  309. and BusNumber are meaningless for this component.
  310. Returns:
  311. None.
  312. --*/
  313. {
  314. NTSTATUS Status;
  315. OBJECT_ATTRIBUTES ObjectAttributes;
  316. UNICODE_STRING KeyName;
  317. UNICODE_STRING ValueName;
  318. UNICODE_STRING ValueData;
  319. HANDLE Handle;
  320. HANDLE OldHandle;
  321. ANSI_STRING AnsiString;
  322. CHAR Buffer[12];
  323. WCHAR UnicodeBuffer[12];
  324. CONFIGURATION_COMPONENT *Component;
  325. ULONG Disposition;
  326. ULONG ConfigurationDataLength = 0;
  327. PCM_FULL_RESOURCE_DESCRIPTOR NewArea;
  328. Component = &CurrentEntry->ComponentEntry;
  329. //
  330. // If the component class is SystemClass, we set its Type to be
  331. // ArcSystem. The reason is because the detection code sets
  332. // its type to MaximumType to indicate it is NOT ARC compatible.
  333. // Here, we are only interested in building a System Node. So we
  334. // change its Type to ArcSystem to ease the setup.
  335. //
  336. if (Component->Class == SystemClass) {
  337. Component->Type = ArcSystem;
  338. }
  339. //
  340. // Create a new key to describe the Component.
  341. //
  342. // The type of the component will be used as the keyname of the
  343. // registry node. The class is the class of the component.
  344. //
  345. InitializeObjectAttributes(
  346. &ObjectAttributes,
  347. &(CmTypeName[Component->Type]),
  348. 0,
  349. ParentHandle,
  350. NULL
  351. );
  352. ObjectAttributes.Attributes |= OBJ_CASE_INSENSITIVE;
  353. Status = NtCreateKey( // Paht may already exist
  354. &Handle,
  355. KEY_READ | KEY_WRITE,
  356. &ObjectAttributes,
  357. 0,
  358. NULL,
  359. 0,
  360. &Disposition
  361. );
  362. if (!NT_SUCCESS(Status)) {
  363. return(Status);
  364. }
  365. //
  366. // If this component is NOT a SystemClass component, we will
  367. // create a subkey to identify the component's ordering.
  368. //
  369. if (Component->Class != SystemClass) {
  370. RtlIntegerToChar(
  371. DeviceIndexTable[Component->Type]++,
  372. 10,
  373. 12,
  374. Buffer
  375. );
  376. RtlInitAnsiString(
  377. &AnsiString,
  378. Buffer
  379. );
  380. KeyName.Buffer = (PWSTR)UnicodeBuffer;
  381. KeyName.Length = 0;
  382. KeyName.MaximumLength = sizeof(UnicodeBuffer);
  383. RtlAnsiStringToUnicodeString(
  384. &KeyName,
  385. &AnsiString,
  386. FALSE
  387. );
  388. OldHandle = Handle;
  389. InitializeObjectAttributes(
  390. &ObjectAttributes,
  391. &KeyName,
  392. 0,
  393. OldHandle,
  394. NULL
  395. );
  396. ObjectAttributes.Attributes |= OBJ_CASE_INSENSITIVE;
  397. Status = NtCreateKey(
  398. &Handle,
  399. KEY_READ | KEY_WRITE,
  400. &ObjectAttributes,
  401. 0,
  402. NULL,
  403. 0,
  404. &Disposition
  405. );
  406. NtClose(OldHandle);
  407. if (!NT_SUCCESS(Status)) {
  408. return(Status);
  409. }
  410. ASSERT(Disposition == REG_CREATED_NEW_KEY);
  411. }
  412. //
  413. // Create a value which describes the following component information:
  414. // Flags, Cersion, Key, AffinityMask.
  415. //
  416. RtlInitUnicodeString(
  417. &ValueName,
  418. L"Component Information"
  419. );
  420. Status = NtSetValueKey(
  421. Handle,
  422. &ValueName,
  423. TITLE_INDEX_VALUE,
  424. REG_BINARY,
  425. &Component->Flags,
  426. FIELD_OFFSET(CONFIGURATION_COMPONENT, ConfigurationDataLength) -
  427. FIELD_OFFSET(CONFIGURATION_COMPONENT, Flags)
  428. );
  429. if (!NT_SUCCESS(Status)) {
  430. NtClose(Handle);
  431. return(Status);
  432. }
  433. //
  434. // Create a value which describes the component identifier, if any.
  435. //
  436. if (Component->IdentifierLength) {
  437. RtlInitUnicodeString(
  438. &ValueName,
  439. L"Identifier"
  440. );
  441. RtlInitAnsiString(
  442. &AnsiString,
  443. Component->Identifier
  444. );
  445. Status = RtlAnsiStringToUnicodeString(
  446. &ValueData,
  447. &AnsiString,
  448. TRUE
  449. );
  450. if( NT_SUCCESS(Status) ) {
  451. Status = NtSetValueKey(
  452. Handle,
  453. &ValueName,
  454. TITLE_INDEX_VALUE,
  455. REG_SZ,
  456. ValueData.Buffer,
  457. ValueData.Length + sizeof( UNICODE_NULL )
  458. );
  459. RtlFreeUnicodeString(&ValueData);
  460. }
  461. if (!NT_SUCCESS(Status)) {
  462. NtClose(Handle);
  463. return(Status);
  464. }
  465. }
  466. //
  467. // Create a value entry for component configuration data.
  468. //
  469. RtlInitUnicodeString(
  470. &ValueName,
  471. L"Configuration Data"
  472. );
  473. //
  474. // Create the configuration data based on CM_FULL_RESOURCE_DESCRIPTOR.
  475. //
  476. // Note the configuration data in firmware tree may be in the form of
  477. // CM_PARTIAL_RESOURCE_LIST or nothing. In both cases, we need to
  478. // set up the registry configuration data to be in the form of
  479. // CM_FULL_RESOURCE_DESCRIPTOR.
  480. //
  481. if (CurrentEntry->ConfigurationData) {
  482. //
  483. // This component has configuration data, we copy the data
  484. // to our work area, add some more data items and copy the new
  485. // configuration data to the registry.
  486. //
  487. ConfigurationDataLength = Component->ConfigurationDataLength +
  488. FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR,
  489. PartialResourceList);
  490. //
  491. // Make sure our reserved area is big enough to hold the data.
  492. //
  493. if (ConfigurationDataLength > CmpConfigurationAreaSize) {
  494. //
  495. // If reserved area is not big enough, we resize our reserved
  496. // area. If, unfortunately, the reallocation fails, we simply
  497. // loss the configuration data of this particular component.
  498. //
  499. NewArea = (PCM_FULL_RESOURCE_DESCRIPTOR)ExAllocatePool(
  500. PagedPool,
  501. ConfigurationDataLength
  502. );
  503. if (NewArea) {
  504. CmpConfigurationAreaSize = ConfigurationDataLength;
  505. ExFreePool(CmpConfigurationData);
  506. CmpConfigurationData = NewArea;
  507. RtlCopyMemory(
  508. (PUCHAR)&CmpConfigurationData->PartialResourceList.Version,
  509. CurrentEntry->ConfigurationData,
  510. Component->ConfigurationDataLength
  511. );
  512. } else {
  513. Component->ConfigurationDataLength = 0;
  514. CurrentEntry->ConfigurationData = NULL;
  515. }
  516. } else {
  517. RtlCopyMemory(
  518. (PUCHAR)&CmpConfigurationData->PartialResourceList.Version,
  519. CurrentEntry->ConfigurationData,
  520. Component->ConfigurationDataLength
  521. );
  522. }
  523. }
  524. if (CurrentEntry->ConfigurationData == NULL) {
  525. //
  526. // This component has NO configuration data (or we can't resize
  527. // our reserved area to hold the data), we simple add whatever
  528. // is required to set up a CM_FULL_RESOURCE_LIST.
  529. //
  530. CmpConfigurationData->PartialResourceList.Version = 0;
  531. CmpConfigurationData->PartialResourceList.Revision = 0;
  532. CmpConfigurationData->PartialResourceList.Count = 0;
  533. ConfigurationDataLength = FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR,
  534. PartialResourceList) +
  535. FIELD_OFFSET(CM_PARTIAL_RESOURCE_LIST,
  536. PartialDescriptors);
  537. }
  538. //
  539. // Set up InterfaceType and BusNumber for the component.
  540. //
  541. CmpConfigurationData->InterfaceType = InterfaceType;
  542. CmpConfigurationData->BusNumber = BusNumber;
  543. //
  544. // Write the newly constructed configuration data to the hardware registry
  545. //
  546. Status = NtSetValueKey(
  547. Handle,
  548. &ValueName,
  549. TITLE_INDEX_VALUE,
  550. REG_FULL_RESOURCE_DESCRIPTOR,
  551. CmpConfigurationData,
  552. ConfigurationDataLength
  553. );
  554. if (!NT_SUCCESS(Status)) {
  555. NtClose(Handle);
  556. return(Status);
  557. }
  558. *NewHandle = Handle;
  559. return(STATUS_SUCCESS);
  560. }