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.

420 lines
10 KiB

  1. /*++
  2. Copyright (c) 1991 - 2001 Microsoft Corporation
  3. Module Name:
  4. ### #### ##### #### #### ##### #####
  5. ### ## # ## ## ## ## # ## ## ## ##
  6. ## ## ## ## ## ## ## ## ## ## ##
  7. ## ## ## ## ## ## ## ## ## ## ##
  8. ####### ## ##### ## ## ##### #####
  9. ## ## ## # ## ## ## ## # ## ##
  10. ## ## #### ## #### ## #### ## ##
  11. Abstract:
  12. ACPI functions for querying the fixed ACPI tables.
  13. Author:
  14. Wesley Witt (wesw) 22-April-2002
  15. Environment:
  16. Kernel mode only.
  17. Notes:
  18. This code was taken from the HAL.
  19. --*/
  20. #include "internal.h"
  21. #include <ntacpi.h>
  22. #define rgzMultiFunctionAdapter L"\\Registry\\Machine\\Hardware\\Description\\System\\MultifunctionAdapter"
  23. #define rgzAcpiConfigurationData L"Configuration Data"
  24. #define rgzAcpiIdentifier L"Identifier"
  25. #define rgzBIOSIdentifier L"ACPI BIOS"
  26. NTSTATUS
  27. WdAcpiGetRegistryValue(
  28. IN HANDLE KeyHandle,
  29. IN PWSTR ValueName,
  30. OUT PKEY_VALUE_PARTIAL_INFORMATION *Information
  31. )
  32. /*++
  33. Routine Description:
  34. This routine is invoked to retrieve the data for a registry key's value.
  35. This is done by querying the value of the key with a zero-length buffer
  36. to determine the size of the value, and then allocating a buffer and
  37. actually querying the value into the buffer.
  38. It is the responsibility of the caller to free the buffer.
  39. Arguments:
  40. KeyHandle - Supplies the key handle whose value is to be queried
  41. ValueName - Supplies the null-terminated Unicode name of the value.
  42. Information - Returns a pointer to the allocated data buffer.
  43. Return Value:
  44. The function value is the final status of the query operation.
  45. --*/
  46. {
  47. UNICODE_STRING unicodeString;
  48. NTSTATUS status;
  49. PKEY_VALUE_PARTIAL_INFORMATION infoBuffer;
  50. ULONG keyValueLength;
  51. RtlInitUnicodeString( &unicodeString, ValueName );
  52. //
  53. // Figure out how big the data value is so that a buffer of the
  54. // appropriate size can be allocated.
  55. //
  56. status = ZwQueryValueKey( KeyHandle,
  57. &unicodeString,
  58. KeyValuePartialInformation,
  59. (PVOID) NULL,
  60. 0,
  61. &keyValueLength );
  62. if (status != STATUS_BUFFER_OVERFLOW &&
  63. status != STATUS_BUFFER_TOO_SMALL) {
  64. return status;
  65. }
  66. //
  67. // Allocate a buffer large enough to contain the entire key data value.
  68. //
  69. infoBuffer = (PKEY_VALUE_PARTIAL_INFORMATION) ExAllocatePoolWithTag(NonPagedPool,
  70. keyValueLength,
  71. 'IPCA');
  72. if (!infoBuffer) {
  73. return STATUS_INSUFFICIENT_RESOURCES;
  74. }
  75. //
  76. // Query the data for the key value.
  77. //
  78. status = ZwQueryValueKey( KeyHandle,
  79. &unicodeString,
  80. KeyValuePartialInformation,
  81. infoBuffer,
  82. keyValueLength,
  83. &keyValueLength );
  84. if (!NT_SUCCESS( status )) {
  85. ExFreePool( infoBuffer );
  86. return status;
  87. }
  88. //
  89. // Everything worked, so simply return the address of the allocated
  90. // buffer to the caller, who is now responsible for freeing it.
  91. //
  92. *Information = infoBuffer;
  93. return STATUS_SUCCESS;
  94. }
  95. NTSTATUS
  96. WdAcpiFindRsdt (
  97. OUT PACPI_BIOS_MULTI_NODE *AcpiMulti
  98. )
  99. /*++
  100. Routine Description:
  101. This function looks into the registry to find the ACPI RSDT,
  102. which was stored there by ntdetect.com.
  103. Arguments:
  104. RsdtPtr - Pointer to a buffer that contains the ACPI
  105. Root System Description Pointer Structure.
  106. The caller is responsible for freeing this
  107. buffer. Note: This is returned in non-paged
  108. pool.
  109. Return Value:
  110. A NTSTATUS code to indicate the result of the initialization.
  111. --*/
  112. {
  113. UNICODE_STRING unicodeString, unicodeValueName, biosId;
  114. OBJECT_ATTRIBUTES objectAttributes;
  115. HANDLE hMFunc, hBus;
  116. WCHAR wbuffer[10];
  117. ULONG i, length;
  118. PWSTR p;
  119. PKEY_VALUE_PARTIAL_INFORMATION valueInfo;
  120. NTSTATUS status;
  121. BOOLEAN same;
  122. PCM_PARTIAL_RESOURCE_LIST prl;
  123. PCM_PARTIAL_RESOURCE_DESCRIPTOR prd;
  124. PACPI_BIOS_MULTI_NODE multiNode;
  125. ULONG multiNodeSize;
  126. //
  127. // Look in the registry for the "ACPI BIOS bus" data
  128. //
  129. RtlInitUnicodeString (&unicodeString, rgzMultiFunctionAdapter);
  130. InitializeObjectAttributes (&objectAttributes,
  131. &unicodeString,
  132. OBJ_CASE_INSENSITIVE,
  133. NULL, // handle
  134. NULL);
  135. status = ZwOpenKey (&hMFunc, KEY_READ, &objectAttributes);
  136. if (!NT_SUCCESS(status)) {
  137. return status;
  138. }
  139. unicodeString.Buffer = wbuffer;
  140. unicodeString.MaximumLength = sizeof(wbuffer);
  141. RtlInitUnicodeString(&biosId, rgzBIOSIdentifier);
  142. for (i = 0; TRUE; i++) {
  143. RtlIntegerToUnicodeString (i, 10, &unicodeString);
  144. InitializeObjectAttributes (
  145. &objectAttributes,
  146. &unicodeString,
  147. OBJ_CASE_INSENSITIVE,
  148. hMFunc,
  149. NULL);
  150. status = ZwOpenKey (&hBus, KEY_READ, &objectAttributes);
  151. if (!NT_SUCCESS(status)) {
  152. //
  153. // Out of Multifunction adapter entries...
  154. //
  155. ZwClose (hMFunc);
  156. return STATUS_UNSUCCESSFUL;
  157. }
  158. //
  159. // Check the Indentifier to see if this is an ACPI BIOS entry
  160. //
  161. status = WdAcpiGetRegistryValue (hBus, rgzAcpiIdentifier, &valueInfo);
  162. if (!NT_SUCCESS (status)) {
  163. ZwClose (hBus);
  164. continue;
  165. }
  166. p = (PWSTR) ((PUCHAR) valueInfo->Data);
  167. unicodeValueName.Buffer = p;
  168. unicodeValueName.MaximumLength = (USHORT)valueInfo->DataLength;
  169. length = valueInfo->DataLength;
  170. //
  171. // Determine the real length of the ID string
  172. //
  173. while (length) {
  174. if (p[length / sizeof(WCHAR) - 1] == UNICODE_NULL) {
  175. length -= 2;
  176. } else {
  177. break;
  178. }
  179. }
  180. unicodeValueName.Length = (USHORT)length;
  181. same = RtlEqualUnicodeString(&biosId, &unicodeValueName, TRUE);
  182. ExFreePool(valueInfo);
  183. if (!same) {
  184. ZwClose (hBus);
  185. continue;
  186. }
  187. status = WdAcpiGetRegistryValue(hBus, rgzAcpiConfigurationData, &valueInfo);
  188. ZwClose (hBus);
  189. if (!NT_SUCCESS(status)) {
  190. continue ;
  191. }
  192. prl = (PCM_PARTIAL_RESOURCE_LIST)(valueInfo->Data);
  193. prd = &prl->PartialDescriptors[0];
  194. multiNode = (PACPI_BIOS_MULTI_NODE)((PCHAR) prd + sizeof(CM_PARTIAL_RESOURCE_LIST));
  195. break;
  196. }
  197. multiNodeSize = sizeof(ACPI_BIOS_MULTI_NODE) +
  198. ((ULONG)(multiNode->Count - 1) * sizeof(ACPI_E820_ENTRY));
  199. *AcpiMulti = (PACPI_BIOS_MULTI_NODE)
  200. ExAllocatePoolWithTag(NonPagedPool,
  201. multiNodeSize,
  202. 'IPCA');
  203. if (*AcpiMulti == NULL) {
  204. ExFreePool(valueInfo);
  205. return STATUS_INSUFFICIENT_RESOURCES;
  206. }
  207. RtlCopyMemory(*AcpiMulti, multiNode, multiNodeSize);
  208. ExFreePool(valueInfo);
  209. return STATUS_SUCCESS;
  210. }
  211. PVOID
  212. WdGetAcpiTable(
  213. IN ULONG Signature
  214. )
  215. /*++
  216. Routine Description:
  217. This routine will retrieve any table referenced in the ACPI
  218. RSDT.
  219. Arguments:
  220. Signature - Target table signature
  221. Return Value:
  222. pointer to a copy of the table, or NULL if not found
  223. --*/
  224. {
  225. PACPI_BIOS_MULTI_NODE multiNode;
  226. NTSTATUS status;
  227. ULONG entry, rsdtEntries;
  228. PDESCRIPTION_HEADER header;
  229. PHYSICAL_ADDRESS physicalAddr;
  230. PRSDT rsdt;
  231. ULONG rsdtSize;
  232. PVOID table = NULL;
  233. //
  234. // Get the physical address of the RSDT from the Registry
  235. //
  236. status = WdAcpiFindRsdt(&multiNode);
  237. if (!NT_SUCCESS(status)) {
  238. return NULL;
  239. }
  240. //
  241. // Map down header to get total RSDT table size
  242. //
  243. header = (PDESCRIPTION_HEADER) MmMapIoSpace(multiNode->RsdtAddress, sizeof(DESCRIPTION_HEADER), MmNonCached);
  244. if (!header) {
  245. return NULL;
  246. }
  247. rsdtSize = header->Length;
  248. MmUnmapIoSpace(header, sizeof(DESCRIPTION_HEADER));
  249. //
  250. // Map down entire RSDT table
  251. //
  252. rsdt = (PRSDT) MmMapIoSpace(multiNode->RsdtAddress, rsdtSize, MmNonCached);
  253. ExFreePool(multiNode);
  254. if (!rsdt) {
  255. return NULL;
  256. }
  257. //
  258. // Do a sanity check on the RSDT.
  259. //
  260. if ((rsdt->Header.Signature != RSDT_SIGNATURE) &&
  261. (rsdt->Header.Signature != XSDT_SIGNATURE)) {
  262. goto GetAcpiTableEnd;
  263. }
  264. //
  265. // Calculate the number of entries in the RSDT.
  266. //
  267. rsdtEntries = rsdt->Header.Signature == XSDT_SIGNATURE ?
  268. NumTableEntriesFromXSDTPointer(rsdt) :
  269. NumTableEntriesFromRSDTPointer(rsdt);
  270. //
  271. // Look down the pointer in each entry to see if it points to
  272. // the table we are looking for.
  273. //
  274. for (entry = 0; entry < rsdtEntries; entry++) {
  275. if (rsdt->Header.Signature == XSDT_SIGNATURE) {
  276. physicalAddr = ((PXSDT)rsdt)->Tables[entry];
  277. } else {
  278. physicalAddr.HighPart = 0;
  279. physicalAddr.LowPart = (ULONG)rsdt->Tables[entry];
  280. }
  281. //
  282. // Map down the header, check the signature
  283. //
  284. header = (PDESCRIPTION_HEADER) MmMapIoSpace(physicalAddr, sizeof(DESCRIPTION_HEADER), MmNonCached);
  285. if (!header) {
  286. goto GetAcpiTableEnd;
  287. }
  288. if (header->Signature == Signature) {
  289. table = ExAllocatePoolWithTag(PagedPool, header->Length, 'IPCA');
  290. if (table) {
  291. RtlCopyMemory(table, header, header->Length);
  292. }
  293. MmUnmapIoSpace(header, sizeof(DESCRIPTION_HEADER));
  294. break;
  295. }
  296. MmUnmapIoSpace(header, sizeof(DESCRIPTION_HEADER));
  297. }
  298. GetAcpiTableEnd:
  299. MmUnmapIoSpace(rsdt, rsdtSize);
  300. return table;
  301. }