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.

365 lines
9.3 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. acpidtct.c
  5. Abstract:
  6. This file pulls the ACPI Root Ssytem Description
  7. Pointer out of the registry. It was put there
  8. either by ntdetect.com or by one ARC firmware or
  9. another.
  10. Author:
  11. Jake Oshins (jakeo) 6-Feb-1997
  12. Environment:
  13. Kernel mode only.
  14. Revision History:
  15. --*/
  16. #include "halp.h"
  17. #include "ntacpi.h"
  18. #define rgzMultiFunctionAdapter L"\\Registry\\Machine\\Hardware\\Description\\System\\MultifunctionAdapter"
  19. #define rgzAcpiConfigurationData L"Configuration Data"
  20. #define rgzAcpiIdentifier L"Identifier"
  21. #define rgzBIOSIdentifier L"ACPI BIOS"
  22. PHYSICAL_ADDRESS HalpAcpiRsdt;
  23. // from ntrtl.h
  24. NTSYSAPI
  25. BOOLEAN
  26. NTAPI
  27. RtlEqualUnicodeString(
  28. PUNICODE_STRING String1,
  29. PUNICODE_STRING String2,
  30. BOOLEAN CaseInSensitive
  31. );
  32. // internal definitions
  33. NTSTATUS
  34. HalpAcpiGetRegistryValue(
  35. IN HANDLE KeyHandle,
  36. IN PWSTR ValueName,
  37. OUT PKEY_VALUE_PARTIAL_INFORMATION *Information
  38. );
  39. #ifdef ALLOC_PRAGMA
  40. #pragma alloc_text(INIT,HalpAcpiFindRsdtPhase0)
  41. #pragma alloc_text(PAGELK,HalpAcpiGetRegistryValue)
  42. #pragma alloc_text(PAGELK,HalpAcpiFindRsdt)
  43. #endif
  44. NTSTATUS
  45. HalpAcpiFindRsdtPhase0(
  46. IN PLOADER_PARAMETER_BLOCK LoaderBlock
  47. )
  48. /*++
  49. Routine Description:
  50. This function reads the Root System Description Pointer from
  51. the ACPI BIOS node in the arc tree. It puts whatever it finds
  52. into HalpAcpiRsdt.
  53. This function is suitable for being called during Phase 0 or
  54. Phase 1 only. The LoaderBlock is destroyed after that.
  55. Arguments:
  56. IN PLOADER_PARAMETER_BLOCK LoaderBlock
  57. Return Value:
  58. status
  59. --*/
  60. {
  61. PCONFIGURATION_COMPONENT_DATA RsdtComponent = NULL;
  62. PCONFIGURATION_COMPONENT_DATA Component = NULL;
  63. PCONFIGURATION_COMPONENT_DATA Resume = NULL;
  64. PCM_PARTIAL_RESOURCE_LIST Prl;
  65. PCM_PARTIAL_RESOURCE_DESCRIPTOR Prd;
  66. ACPI_BIOS_MULTI_NODE UNALIGNED *Rsdp;
  67. while (Component = KeFindConfigurationNextEntry(LoaderBlock->ConfigurationRoot,AdapterClass,
  68. MultiFunctionAdapter,NULL,&Resume)) {
  69. if (!(strcmp(Component->ComponentEntry.Identifier,"ACPI BIOS"))) {
  70. RsdtComponent = Component;
  71. break;
  72. }
  73. Resume = Component;
  74. }
  75. //if RsdtComponent is still NULL, we didn't find node
  76. if (!RsdtComponent) {
  77. DbgPrint("**** HalpAcpiFindRsdtPhase0: did NOT find RSDT\n");
  78. return STATUS_NOT_FOUND;
  79. }
  80. Prl = (PCM_PARTIAL_RESOURCE_LIST)(RsdtComponent->ConfigurationData);
  81. Prd = &Prl->PartialDescriptors[0];
  82. Rsdp = (PACPI_BIOS_MULTI_NODE)((PCHAR) Prd + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
  83. HalpAcpiRsdt.QuadPart = Rsdp->RsdtAddress.QuadPart;
  84. return STATUS_SUCCESS;
  85. }
  86. NTSTATUS
  87. HalpAcpiFindRsdt (
  88. OUT PACPI_BIOS_MULTI_NODE *AcpiMulti
  89. )
  90. /*++
  91. Routine Description:
  92. This function looks into the registry to find the ACPI RSDT,
  93. which was stored there by ntdetect.com.
  94. Arguments:
  95. RsdtPtr - Pointer to a buffer that contains the ACPI
  96. Root System Description Pointer Structure.
  97. The caller is responsible for freeing this
  98. buffer. Note: This is returned in non-paged
  99. pool.
  100. Return Value:
  101. A NTSTATUS code to indicate the result of the initialization.
  102. --*/
  103. {
  104. UNICODE_STRING unicodeString, unicodeValueName, biosId;
  105. OBJECT_ATTRIBUTES objectAttributes;
  106. HANDLE hMFunc, hBus;
  107. WCHAR wbuffer[10];
  108. ULONG i, length;
  109. PWSTR p;
  110. PKEY_VALUE_PARTIAL_INFORMATION valueInfo;
  111. NTSTATUS status;
  112. BOOLEAN same;
  113. PCM_PARTIAL_RESOURCE_LIST prl;
  114. PCM_PARTIAL_RESOURCE_DESCRIPTOR prd;
  115. PACPI_BIOS_MULTI_NODE multiNode;
  116. ULONG multiNodeSize;
  117. PAGED_CODE();
  118. //
  119. // Look in the registry for the "ACPI BIOS bus" data
  120. //
  121. RtlInitUnicodeString (&unicodeString, rgzMultiFunctionAdapter);
  122. InitializeObjectAttributes (&objectAttributes,
  123. &unicodeString,
  124. OBJ_CASE_INSENSITIVE,
  125. NULL, // handle
  126. NULL);
  127. status = ZwOpenKey (&hMFunc, KEY_READ, &objectAttributes);
  128. if (!NT_SUCCESS(status)) {
  129. DbgPrint("AcpiBios:Can not open MultifunctionAdapter registry key.\n");
  130. return status;
  131. }
  132. unicodeString.Buffer = wbuffer;
  133. unicodeString.MaximumLength = sizeof(wbuffer);
  134. RtlInitUnicodeString(&biosId, rgzBIOSIdentifier);
  135. for (i = 0; TRUE; i++) {
  136. RtlIntegerToUnicodeString (i, 10, &unicodeString);
  137. InitializeObjectAttributes (
  138. &objectAttributes,
  139. &unicodeString,
  140. OBJ_CASE_INSENSITIVE,
  141. hMFunc,
  142. NULL);
  143. status = ZwOpenKey (&hBus, KEY_READ, &objectAttributes);
  144. if (!NT_SUCCESS(status)) {
  145. //
  146. // Out of Multifunction adapter entries...
  147. //
  148. DbgPrint("AcpiBios: ACPI BIOS MultifunctionAdapter registry key not found.\n");
  149. ZwClose (hMFunc);
  150. return STATUS_UNSUCCESSFUL;
  151. }
  152. //
  153. // Check the Indentifier to see if this is an ACPI BIOS entry
  154. //
  155. status = HalpAcpiGetRegistryValue (hBus, rgzAcpiIdentifier, &valueInfo);
  156. if (!NT_SUCCESS (status)) {
  157. ZwClose (hBus);
  158. continue;
  159. }
  160. p = (PWSTR) ((PUCHAR) valueInfo->Data);
  161. unicodeValueName.Buffer = p;
  162. unicodeValueName.MaximumLength = (USHORT)valueInfo->DataLength;
  163. length = valueInfo->DataLength;
  164. //
  165. // Determine the real length of the ID string
  166. //
  167. while (length) {
  168. if (p[length / sizeof(WCHAR) - 1] == UNICODE_NULL) {
  169. length -= 2;
  170. } else {
  171. break;
  172. }
  173. }
  174. unicodeValueName.Length = (USHORT)length;
  175. same = RtlEqualUnicodeString(&biosId, &unicodeValueName, TRUE);
  176. ExFreePool(valueInfo);
  177. if (!same) {
  178. ZwClose (hBus);
  179. continue;
  180. }
  181. status = HalpAcpiGetRegistryValue(hBus, rgzAcpiConfigurationData, &valueInfo);
  182. ZwClose (hBus);
  183. if (!NT_SUCCESS(status)) {
  184. continue ;
  185. }
  186. prl = (PCM_PARTIAL_RESOURCE_LIST)(valueInfo->Data);
  187. prd = &prl->PartialDescriptors[0];
  188. multiNode = (PACPI_BIOS_MULTI_NODE)((PCHAR) prd + sizeof(CM_PARTIAL_RESOURCE_LIST));
  189. break;
  190. }
  191. multiNodeSize = sizeof(ACPI_BIOS_MULTI_NODE) +
  192. ((ULONG)(multiNode->Count - 1) * sizeof(ACPI_E820_ENTRY));
  193. *AcpiMulti = (PACPI_BIOS_MULTI_NODE)
  194. ExAllocatePoolWithTag(NonPagedPool,
  195. multiNodeSize,
  196. 'IPCA');
  197. if (*AcpiMulti == NULL) {
  198. ExFreePool(valueInfo);
  199. return STATUS_INSUFFICIENT_RESOURCES;
  200. }
  201. RtlCopyMemory(*AcpiMulti, multiNode, multiNodeSize);
  202. ExFreePool(valueInfo);
  203. return STATUS_SUCCESS;
  204. }
  205. NTSTATUS
  206. HalpAcpiGetRegistryValue(
  207. IN HANDLE KeyHandle,
  208. IN PWSTR ValueName,
  209. OUT PKEY_VALUE_PARTIAL_INFORMATION *Information
  210. )
  211. /*++
  212. Routine Description:
  213. This routine is invoked to retrieve the data for a registry key's value.
  214. This is done by querying the value of the key with a zero-length buffer
  215. to determine the size of the value, and then allocating a buffer and
  216. actually querying the value into the buffer.
  217. It is the responsibility of the caller to free the buffer.
  218. Arguments:
  219. KeyHandle - Supplies the key handle whose value is to be queried
  220. ValueName - Supplies the null-terminated Unicode name of the value.
  221. Information - Returns a pointer to the allocated data buffer.
  222. Return Value:
  223. The function value is the final status of the query operation.
  224. --*/
  225. {
  226. UNICODE_STRING unicodeString;
  227. NTSTATUS status;
  228. PKEY_VALUE_PARTIAL_INFORMATION infoBuffer;
  229. ULONG keyValueLength;
  230. PAGED_CODE();
  231. RtlInitUnicodeString( &unicodeString, ValueName );
  232. //
  233. // Figure out how big the data value is so that a buffer of the
  234. // appropriate size can be allocated.
  235. //
  236. status = ZwQueryValueKey( KeyHandle,
  237. &unicodeString,
  238. KeyValuePartialInformation,
  239. (PVOID) NULL,
  240. 0,
  241. &keyValueLength );
  242. if (status != STATUS_BUFFER_OVERFLOW &&
  243. status != STATUS_BUFFER_TOO_SMALL) {
  244. return status;
  245. }
  246. //
  247. // Allocate a buffer large enough to contain the entire key data value.
  248. //
  249. infoBuffer = ExAllocatePoolWithTag(NonPagedPool,
  250. keyValueLength,
  251. 'IPCA');
  252. if (!infoBuffer) {
  253. return STATUS_INSUFFICIENT_RESOURCES;
  254. }
  255. //
  256. // Query the data for the key value.
  257. //
  258. status = ZwQueryValueKey( KeyHandle,
  259. &unicodeString,
  260. KeyValuePartialInformation,
  261. infoBuffer,
  262. keyValueLength,
  263. &keyValueLength );
  264. if (!NT_SUCCESS( status )) {
  265. ExFreePool( infoBuffer );
  266. return status;
  267. }
  268. //
  269. // Everything worked, so simply return the address of the allocated
  270. // buffer to the caller, who is now responsible for freeing it.
  271. //
  272. *Information = infoBuffer;
  273. return STATUS_SUCCESS;
  274. }