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.

520 lines
14 KiB

  1. extern "C" {
  2. #include <ntosp.h>
  3. #include <zwapi.h>
  4. #include <ntacpi.h>
  5. #include <acpitabl.h>
  6. }
  7. #define KEY_MULTIFUNCTION L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultiFunctionAdapter"
  8. #define VALUE_IDENTIFIER L"Identifier"
  9. #define VALUE_CONFIGURATION_DATA L"Configuration Data"
  10. #define ACPI_BIOS_ID L"ACPI BIOS"
  11. BOOLEAN
  12. PciOpenKey(
  13. IN PWSTR KeyName,
  14. IN HANDLE ParentHandle,
  15. OUT PHANDLE Handle,
  16. OUT PNTSTATUS Status
  17. )
  18. /*++
  19. Description:
  20. Open a registry key.
  21. Arguments:
  22. KeyName Name of the key to be opened.
  23. ParentHandle Pointer to the parent handle (OPTIONAL)
  24. Handle Pointer to a handle to recieve the opened key.
  25. Return Value:
  26. TRUE is key successfully opened, FALSE otherwise.
  27. --*/
  28. {
  29. UNICODE_STRING nameString;
  30. OBJECT_ATTRIBUTES nameAttributes;
  31. NTSTATUS localStatus;
  32. PAGED_CODE();
  33. RtlInitUnicodeString(&nameString, KeyName);
  34. InitializeObjectAttributes(&nameAttributes,
  35. &nameString,
  36. OBJ_CASE_INSENSITIVE,
  37. ParentHandle,
  38. (PSECURITY_DESCRIPTOR)NULL
  39. );
  40. localStatus = ZwOpenKey(Handle,
  41. KEY_READ,
  42. &nameAttributes
  43. );
  44. if (Status != NULL) {
  45. //
  46. // Caller wants underlying status.
  47. //
  48. *Status = localStatus;
  49. }
  50. //
  51. // Return status converted to a boolean, TRUE if
  52. // successful.
  53. //
  54. return NT_SUCCESS(localStatus);
  55. }
  56. NTSTATUS
  57. PciGetRegistryValue(
  58. IN PWSTR ValueName,
  59. IN PWSTR KeyName,
  60. IN HANDLE ParentHandle,
  61. OUT PVOID *Buffer,
  62. OUT ULONG *Length
  63. )
  64. {
  65. NTSTATUS status;
  66. HANDLE keyHandle;
  67. ULONG neededLength;
  68. ULONG actualLength;
  69. UNICODE_STRING unicodeValueName;
  70. PKEY_VALUE_PARTIAL_INFORMATION info;
  71. if (!PciOpenKey(KeyName, ParentHandle, &keyHandle, &status)) {
  72. return status;
  73. }
  74. unicodeValueName.Buffer = ValueName;
  75. unicodeValueName.MaximumLength = (wcslen(ValueName) + 1) * sizeof(WCHAR);
  76. unicodeValueName.Length = unicodeValueName.MaximumLength - sizeof(WCHAR);
  77. //
  78. // Find out how much memory we need for this.
  79. //
  80. status = ZwQueryValueKey(
  81. keyHandle,
  82. &unicodeValueName,
  83. KeyValuePartialInformation,
  84. NULL,
  85. 0,
  86. &neededLength
  87. );
  88. if (status == STATUS_BUFFER_TOO_SMALL) {
  89. //
  90. // Get memory to return the data in. Note this includes
  91. // a header that we really don't want.
  92. //
  93. info = (PKEY_VALUE_PARTIAL_INFORMATION) ExAllocatePool( PagedPool, neededLength );
  94. if (info == NULL) {
  95. ZwClose(keyHandle);
  96. return STATUS_INSUFFICIENT_RESOURCES;
  97. }
  98. //
  99. // Get the data.
  100. //
  101. status = ZwQueryValueKey(
  102. keyHandle,
  103. &unicodeValueName,
  104. KeyValuePartialInformation,
  105. info,
  106. neededLength,
  107. &actualLength
  108. );
  109. if (!NT_SUCCESS(status)) {
  110. ExFreePool(info);
  111. ZwClose(keyHandle);
  112. return status;
  113. }
  114. //
  115. // Subtract out the header size and get memory for just
  116. // the data we want.
  117. //
  118. neededLength -= FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data);
  119. *Buffer = ExAllocatePool( PagedPool, neededLength );
  120. if (*Buffer == NULL) {
  121. ExFreePool(info);
  122. ZwClose(keyHandle);
  123. return STATUS_INSUFFICIENT_RESOURCES;
  124. }
  125. //
  126. // Copy data sans header.
  127. //
  128. RtlCopyMemory(*Buffer, info->Data, neededLength);
  129. ExFreePool(info);
  130. if (Length) {
  131. *Length = neededLength;
  132. }
  133. } else {
  134. if (NT_SUCCESS(status)) {
  135. //
  136. // We don't want to report success when this happens.
  137. //
  138. status = STATUS_UNSUCCESSFUL;
  139. }
  140. }
  141. ZwClose(keyHandle);
  142. return status;
  143. }
  144. NTSTATUS
  145. PciAcpiFindRsdt (
  146. OUT PACPI_BIOS_MULTI_NODE *AcpiMulti
  147. )
  148. {
  149. PKEY_FULL_INFORMATION multiKeyInformation = NULL;
  150. PKEY_BASIC_INFORMATION keyInfo = NULL;
  151. PKEY_VALUE_PARTIAL_INFORMATION identifierValueInfo = NULL;
  152. UNICODE_STRING unicodeString;
  153. HANDLE keyMultifunction = NULL, keyTable = NULL;
  154. PCM_PARTIAL_RESOURCE_LIST prl = NULL;
  155. PCM_PARTIAL_RESOURCE_DESCRIPTOR prd;
  156. PACPI_BIOS_MULTI_NODE multiNode;
  157. ULONG multiNodeSize;
  158. ULONG i, length, maxKeyLength, identifierValueLen;
  159. BOOLEAN result;
  160. NTSTATUS status;
  161. //
  162. // Open the multifunction key
  163. //
  164. result = PciOpenKey(KEY_MULTIFUNCTION,
  165. NULL,
  166. &keyMultifunction,
  167. &status);
  168. if (!result) {
  169. goto Cleanup;
  170. }
  171. //
  172. // Do allocation of buffers up front
  173. //
  174. //
  175. // Determine maximum size of a keyname under the multifunction key
  176. //
  177. status = ZwQueryKey(keyMultifunction,
  178. KeyFullInformation,
  179. NULL,
  180. sizeof(multiKeyInformation),
  181. &length);
  182. if (status != STATUS_BUFFER_TOO_SMALL) {
  183. goto Cleanup;
  184. }
  185. multiKeyInformation = (PKEY_FULL_INFORMATION)ExAllocatePool( PagedPool, length );
  186. if (multiKeyInformation == NULL) {
  187. status = STATUS_INSUFFICIENT_RESOURCES;
  188. goto Cleanup;
  189. }
  190. status = ZwQueryKey(keyMultifunction,
  191. KeyFullInformation,
  192. multiKeyInformation,
  193. length,
  194. &length);
  195. if (!NT_SUCCESS(status)) {
  196. goto Cleanup;
  197. }
  198. // includes space for a terminating null that will be added later.
  199. maxKeyLength = multiKeyInformation->MaxNameLen +
  200. sizeof(KEY_BASIC_INFORMATION) + sizeof(WCHAR);
  201. //
  202. // Allocate buffer used for storing subkeys that we are enumerated
  203. // under multifunction.
  204. //
  205. keyInfo = (PKEY_BASIC_INFORMATION)ExAllocatePool( PagedPool, maxKeyLength );
  206. if (keyInfo == NULL) {
  207. status = STATUS_INSUFFICIENT_RESOURCES;
  208. goto Cleanup;
  209. }
  210. //
  211. // Allocate buffer large enough to store a value containing REG_SZ
  212. // 'ACPI BIOS'. We hope to find such a value under one of the
  213. // multifunction subkeys
  214. //
  215. identifierValueLen = sizeof(ACPI_BIOS_ID) + sizeof(KEY_VALUE_PARTIAL_INFORMATION);
  216. identifierValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)ExAllocatePool( PagedPool, identifierValueLen );
  217. if (identifierValueInfo == NULL) {
  218. status = STATUS_INSUFFICIENT_RESOURCES;
  219. goto Cleanup;
  220. }
  221. //
  222. // Enumerate subkeys of multifunction key looking for keys with an
  223. // Identifier value of "ACPI BIOS". If we find one, look for the
  224. // irq routing table in the tree below.
  225. //
  226. i = 0;
  227. do {
  228. status = ZwEnumerateKey(keyMultifunction,
  229. i,
  230. KeyBasicInformation,
  231. keyInfo,
  232. maxKeyLength,
  233. &length);
  234. if (NT_SUCCESS(status)) {
  235. //
  236. // Found a key, now we need to open it and check the
  237. // 'Identifier' value to see if it is 'ACPI BIOS'
  238. //
  239. keyInfo->Name[keyInfo->NameLength / sizeof(WCHAR)] = UNICODE_NULL;
  240. result = PciOpenKey(keyInfo->Name,
  241. keyMultifunction,
  242. &keyTable,
  243. &status);
  244. if (result) {
  245. //
  246. // Checking 'Identifier' value to see if it contains 'ACPI BIOS'
  247. //
  248. RtlInitUnicodeString(&unicodeString, VALUE_IDENTIFIER);
  249. status = ZwQueryValueKey(keyTable,
  250. &unicodeString,
  251. KeyValuePartialInformation,
  252. identifierValueInfo,
  253. identifierValueLen,
  254. &length);
  255. if (NT_SUCCESS(status) &&
  256. RtlEqualMemory((PCHAR)identifierValueInfo->Data,
  257. ACPI_BIOS_ID,
  258. identifierValueInfo->DataLength))
  259. {
  260. //
  261. // This is the ACPI BIOS key. Try to get Configuration Data
  262. // This is the key we were looking
  263. // for so regardless of success, break out.
  264. //
  265. ZwClose(keyTable);
  266. status = PciGetRegistryValue(VALUE_CONFIGURATION_DATA,
  267. keyInfo->Name,
  268. keyMultifunction,
  269. (PVOID*)&prl,
  270. &length);
  271. break;
  272. }
  273. ZwClose(keyTable);
  274. }
  275. } else {
  276. //
  277. // If not NT_SUCCESS, only alowable value is
  278. // STATUS_NO_MORE_ENTRIES,... otherwise, someone
  279. // is playing with the keys as we enumerate
  280. //
  281. break;
  282. }
  283. i++;
  284. }
  285. while (status != STATUS_NO_MORE_ENTRIES);
  286. if (NT_SUCCESS(status) && prl) {
  287. prd = &prl->PartialDescriptors[0];
  288. multiNode = (PACPI_BIOS_MULTI_NODE)((PCHAR) prd + sizeof(CM_PARTIAL_RESOURCE_LIST));
  289. multiNodeSize = sizeof(ACPI_BIOS_MULTI_NODE) + ((ULONG)(multiNode->Count - 1) * sizeof(ACPI_E820_ENTRY));
  290. *AcpiMulti = (PACPI_BIOS_MULTI_NODE) ExAllocatePool( NonPagedPool, multiNodeSize );
  291. if (*AcpiMulti == NULL) {
  292. status = STATUS_INSUFFICIENT_RESOURCES;
  293. goto Cleanup;
  294. }
  295. RtlCopyMemory(*AcpiMulti, multiNode, multiNodeSize);
  296. }
  297. Cleanup:
  298. if (identifierValueInfo != NULL) {
  299. ExFreePool(identifierValueInfo);
  300. }
  301. if (keyInfo != NULL) {
  302. ExFreePool(keyInfo);
  303. }
  304. if (multiKeyInformation != NULL) {
  305. ExFreePool(multiKeyInformation);
  306. }
  307. if (keyMultifunction != NULL) {
  308. ZwClose(keyMultifunction);
  309. }
  310. if (prl) {
  311. ExFreePool(prl);
  312. }
  313. return status;
  314. }
  315. PVOID
  316. PciGetAcpiTable(
  317. void
  318. )
  319. /*++
  320. Routine Description:
  321. This routine will retrieve any table referenced in the ACPI
  322. RSDT.
  323. Arguments:
  324. Signature - Target table signature
  325. Return Value:
  326. pointer to a copy of the table, or NULL if not found
  327. --*/
  328. {
  329. PACPI_BIOS_MULTI_NODE multiNode;
  330. NTSTATUS status;
  331. ULONG entry, rsdtEntries;
  332. PDESCRIPTION_HEADER header;
  333. PHYSICAL_ADDRESS physicalAddr;
  334. PRSDT rsdt;
  335. ULONG rsdtSize;
  336. PVOID table = NULL;
  337. ULONG Signature = WDTT_SIGNATURE;
  338. //
  339. // Get the physical address of the RSDT from the Registry
  340. //
  341. status = PciAcpiFindRsdt(&multiNode);
  342. if (!NT_SUCCESS(status)) {
  343. DbgPrint("AcpiFindRsdt() Failed!\n");
  344. return NULL;
  345. }
  346. //
  347. // Map down header to get total RSDT table size
  348. //
  349. header = (PDESCRIPTION_HEADER) MmMapIoSpace(multiNode->RsdtAddress, sizeof(DESCRIPTION_HEADER), MmCached);
  350. if (!header) {
  351. return NULL;
  352. }
  353. rsdtSize = header->Length;
  354. MmUnmapIoSpace(header, sizeof(DESCRIPTION_HEADER));
  355. //
  356. // Map down entire RSDT table
  357. //
  358. rsdt = (PRSDT) MmMapIoSpace(multiNode->RsdtAddress, rsdtSize, MmCached);
  359. ExFreePool(multiNode);
  360. if (!rsdt) {
  361. return NULL;
  362. }
  363. //
  364. // Do a sanity check on the RSDT.
  365. //
  366. if ((rsdt->Header.Signature != RSDT_SIGNATURE) &&
  367. (rsdt->Header.Signature != XSDT_SIGNATURE)) {
  368. DbgPrint("RSDT table contains invalid signature\n");
  369. goto GetAcpiTableEnd;
  370. }
  371. //
  372. // Calculate the number of entries in the RSDT.
  373. //
  374. rsdtEntries = rsdt->Header.Signature == XSDT_SIGNATURE ?
  375. NumTableEntriesFromXSDTPointer(rsdt) :
  376. NumTableEntriesFromRSDTPointer(rsdt);
  377. //
  378. // Look down the pointer in each entry to see if it points to
  379. // the table we are looking for.
  380. //
  381. for (entry = 0; entry < rsdtEntries; entry++) {
  382. if (rsdt->Header.Signature == XSDT_SIGNATURE) {
  383. physicalAddr = ((PXSDT)rsdt)->Tables[entry];
  384. } else {
  385. physicalAddr.HighPart = 0;
  386. physicalAddr.LowPart = (ULONG)rsdt->Tables[entry];
  387. }
  388. //
  389. // Map down the header, check the signature
  390. //
  391. header = (PDESCRIPTION_HEADER) MmMapIoSpace(physicalAddr, sizeof(DESCRIPTION_HEADER), MmCached);
  392. if (!header) {
  393. goto GetAcpiTableEnd;
  394. }
  395. if (header->Signature == Signature) {
  396. table = ExAllocatePool( PagedPool, header->Length );
  397. if (table) {
  398. RtlCopyMemory(table, header, header->Length);
  399. }
  400. MmUnmapIoSpace(header, sizeof(DESCRIPTION_HEADER));
  401. break;
  402. }
  403. MmUnmapIoSpace(header, sizeof(DESCRIPTION_HEADER));
  404. }
  405. GetAcpiTableEnd:
  406. MmUnmapIoSpace(rsdt, rsdtSize);
  407. return table;
  408. }