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.

576 lines
15 KiB

  1. #include "spsim.h"
  2. #define rgzMultiFunctionAdapter L"\\Registry\\Machine\\Hardware\\Description\\System\\MultifunctionAdapter"
  3. #define rgzAcpiConfigurationData L"Configuration Data"
  4. #define rgzAcpiIdentifier L"Identifier"
  5. #define rgzBIOSIdentifier L"ACPI BIOS"
  6. typedef struct {
  7. ULONGLONG Base;
  8. ULONGLONG Length;
  9. ULONGLONG Type;
  10. } ACPI_E820_ENTRY, *PACPI_E820_ENTRY;
  11. typedef struct _ACPI_BIOS_MULTI_NODE {
  12. PHYSICAL_ADDRESS RsdtAddress; // 64-bit physical address of RSDT
  13. ULONGLONG Count;
  14. ACPI_E820_ENTRY E820Entry[1];
  15. } ACPI_BIOS_MULTI_NODE, *PACPI_BIOS_MULTI_NODE;
  16. typedef enum {
  17. AcpiAddressRangeMemory = 1,
  18. AcpiAddressRangeReserved,
  19. AcpiAddressRangeACPI,
  20. AcpiAddressRangeNVS,
  21. AcpiAddressRangeMaximum,
  22. } ACPI_BIOS_E820_TYPE, *PACPI_BIOS_E820_TYPE;
  23. NTSTATUS
  24. SpSimGetRegistryValue(
  25. IN HANDLE KeyHandle,
  26. IN PWSTR ValueName,
  27. OUT PKEY_VALUE_PARTIAL_INFORMATION *Information
  28. )
  29. /*++
  30. Routine Description:
  31. This routine is invoked to retrieve the data for a registry key's value.
  32. This is done by querying the value of the key with a zero-length buffer
  33. to determine the size of the value, and then allocating a buffer and
  34. actually querying the value into the buffer.
  35. It is the responsibility of the caller to free the buffer.
  36. Arguments:
  37. KeyHandle - Supplies the key handle whose value is to be queried
  38. ValueName - Supplies the null-terminated Unicode name of the value.
  39. Information - Returns a pointer to the allocated data buffer.
  40. Return Value:
  41. The function value is the final status of the query operation.
  42. --*/
  43. {
  44. UNICODE_STRING unicodeString;
  45. NTSTATUS status;
  46. PKEY_VALUE_PARTIAL_INFORMATION infoBuffer;
  47. ULONG keyValueLength;
  48. PAGED_CODE();
  49. RtlInitUnicodeString( &unicodeString, ValueName );
  50. //
  51. // Figure out how big the data value is so that a buffer of the
  52. // appropriate size can be allocated.
  53. //
  54. status = ZwQueryValueKey( KeyHandle,
  55. &unicodeString,
  56. KeyValuePartialInformation,
  57. (PVOID) NULL,
  58. 0,
  59. &keyValueLength );
  60. if (status != STATUS_BUFFER_OVERFLOW &&
  61. status != STATUS_BUFFER_TOO_SMALL) {
  62. return status;
  63. }
  64. //
  65. // Allocate a buffer large enough to contain the entire key data value.
  66. //
  67. infoBuffer = ExAllocatePool(NonPagedPool,
  68. keyValueLength);
  69. if (!infoBuffer) {
  70. return STATUS_INSUFFICIENT_RESOURCES;
  71. }
  72. //
  73. // Query the data for the key value.
  74. //
  75. status = ZwQueryValueKey( KeyHandle,
  76. &unicodeString,
  77. KeyValuePartialInformation,
  78. infoBuffer,
  79. keyValueLength,
  80. &keyValueLength );
  81. if (!NT_SUCCESS( status )) {
  82. ExFreePool( infoBuffer );
  83. return status;
  84. }
  85. //
  86. // Everything worked, so simply return the address of the allocated
  87. // buffer to the caller, who is now responsible for freeing it.
  88. //
  89. *Information = infoBuffer;
  90. return STATUS_SUCCESS;
  91. }
  92. // insert pragmas here
  93. NTSTATUS
  94. SpSimRetrieveE820Data(
  95. OUT PACPI_BIOS_MULTI_NODE *AcpiMulti
  96. )
  97. /*++
  98. Routine Description:
  99. This function looks into the registry to find the ACPI RSDT,
  100. which was stored there by ntdetect.com.
  101. Arguments:
  102. AcpiMulti - ...
  103. Return Value:
  104. A NTSTATUS code to indicate the result of the initialization.
  105. --*/
  106. {
  107. UNICODE_STRING unicodeString, unicodeValueName, biosId;
  108. OBJECT_ATTRIBUTES objectAttributes;
  109. HANDLE hMFunc, hBus;
  110. WCHAR wbuffer[10];
  111. ULONG i, length;
  112. PWSTR p;
  113. PKEY_VALUE_PARTIAL_INFORMATION valueInfo;
  114. NTSTATUS status;
  115. BOOLEAN same;
  116. PCM_PARTIAL_RESOURCE_LIST prl;
  117. PCM_PARTIAL_RESOURCE_DESCRIPTOR prd;
  118. PACPI_BIOS_MULTI_NODE multiNode;
  119. ULONG multiNodeSize;
  120. PAGED_CODE();
  121. //
  122. // Look in the registry for the "ACPI BIOS bus" data
  123. //
  124. RtlInitUnicodeString (&unicodeString, rgzMultiFunctionAdapter);
  125. InitializeObjectAttributes (&objectAttributes,
  126. &unicodeString,
  127. OBJ_CASE_INSENSITIVE,
  128. NULL, // handle
  129. NULL);
  130. status = ZwOpenKey (&hMFunc, KEY_READ, &objectAttributes);
  131. if (!NT_SUCCESS(status)) {
  132. DbgPrint("AcpiBios:Can not open MultifunctionAdapter registry key.\n");
  133. return status;
  134. }
  135. unicodeString.Buffer = wbuffer;
  136. unicodeString.MaximumLength = sizeof(wbuffer);
  137. RtlInitUnicodeString(&biosId, rgzBIOSIdentifier);
  138. for (i = 0; TRUE; i++) {
  139. RtlIntegerToUnicodeString (i, 10, &unicodeString);
  140. InitializeObjectAttributes (
  141. &objectAttributes,
  142. &unicodeString,
  143. OBJ_CASE_INSENSITIVE,
  144. hMFunc,
  145. NULL);
  146. status = ZwOpenKey (&hBus, KEY_READ, &objectAttributes);
  147. if (!NT_SUCCESS(status)) {
  148. //
  149. // Out of Multifunction adapter entries...
  150. //
  151. DbgPrint("AcpiBios: ACPI BIOS MultifunctionAdapter registry key not found.\n");
  152. ZwClose (hMFunc);
  153. return STATUS_UNSUCCESSFUL;
  154. }
  155. //
  156. // Check the Indentifier to see if this is an ACPI BIOS entry
  157. //
  158. status = SpSimGetRegistryValue (hBus, rgzAcpiIdentifier, &valueInfo);
  159. if (!NT_SUCCESS (status)) {
  160. ZwClose (hBus);
  161. continue;
  162. }
  163. p = (PWSTR) ((PUCHAR) valueInfo->Data);
  164. unicodeValueName.Buffer = p;
  165. unicodeValueName.MaximumLength = (USHORT)valueInfo->DataLength;
  166. length = valueInfo->DataLength;
  167. //
  168. // Determine the real length of the ID string
  169. //
  170. while (length) {
  171. if (p[length / sizeof(WCHAR) - 1] == UNICODE_NULL) {
  172. length -= 2;
  173. } else {
  174. break;
  175. }
  176. }
  177. unicodeValueName.Length = (USHORT)length;
  178. same = RtlEqualUnicodeString(&biosId, &unicodeValueName, TRUE);
  179. ExFreePool(valueInfo);
  180. if (!same) {
  181. ZwClose (hBus);
  182. continue;
  183. }
  184. status = SpSimGetRegistryValue(hBus, rgzAcpiConfigurationData, &valueInfo);
  185. ZwClose (hBus);
  186. if (!NT_SUCCESS(status)) {
  187. continue ;
  188. }
  189. prl = (PCM_PARTIAL_RESOURCE_LIST)(valueInfo->Data);
  190. prd = &prl->PartialDescriptors[0];
  191. multiNode = (PACPI_BIOS_MULTI_NODE)((PCHAR) prd + sizeof(CM_PARTIAL_RESOURCE_LIST));
  192. break;
  193. }
  194. multiNodeSize = sizeof(ACPI_BIOS_MULTI_NODE) +
  195. ((ULONG)(multiNode->Count - 1) * sizeof(ACPI_E820_ENTRY));
  196. *AcpiMulti = (PACPI_BIOS_MULTI_NODE)
  197. ExAllocatePool(NonPagedPool,
  198. multiNodeSize);
  199. if (*AcpiMulti == NULL) {
  200. ExFreePool(valueInfo);
  201. return STATUS_INSUFFICIENT_RESOURCES;
  202. }
  203. RtlCopyMemory(*AcpiMulti, multiNode, multiNodeSize);
  204. ExFreePool(valueInfo);
  205. return STATUS_SUCCESS;
  206. }
  207. VOID
  208. SpSimFillMemoryDescs(
  209. PACPI_BIOS_MULTI_NODE E820Data,
  210. ULONGLONG memUnit,
  211. PMEM_REGION_DESCRIPTOR MemRegions
  212. )
  213. {
  214. ULONG i, descCount;
  215. #undef min
  216. #define min(a,b) (a < b ? a : b)
  217. descCount = 0;
  218. for (i = 0; i < E820Data->Count; i++) {
  219. if (E820Data->E820Entry[i].Type != AcpiAddressRangeMemory) {
  220. continue;
  221. }
  222. if (E820Data->E820Entry[i].Length > memUnit) {
  223. ULONGLONG remains, base, extra;
  224. extra = E820Data->E820Entry[i].Length & (PAGE_SIZE - 1);
  225. remains = E820Data->E820Entry[i].Length - extra;
  226. base = (E820Data->E820Entry[i].Base + (PAGE_SIZE - 1)) &
  227. ~(PAGE_SIZE - 1);
  228. while (remains) {
  229. MemRegions[descCount].Addr = (ULONG) base;
  230. MemRegions[descCount].Length = (ULONG) min(remains, memUnit);
  231. descCount++;
  232. base += min(remains, memUnit);
  233. remains -= min(remains, memUnit);
  234. }
  235. } else {
  236. MemRegions[descCount].Addr = (ULONG) E820Data->E820Entry[i].Base;
  237. MemRegions[descCount].Length = (ULONG) E820Data->E820Entry[i].Length;
  238. descCount++;
  239. }
  240. }
  241. }
  242. ULONG
  243. SpSimCalculateMemoryDescCount(
  244. PACPI_BIOS_MULTI_NODE E820Data,
  245. ULONGLONG memUnit
  246. )
  247. {
  248. ULONG i, descCount;
  249. descCount = 0;
  250. for (i = 0; i < E820Data->Count; i++) {
  251. if (E820Data->E820Entry[i].Type != AcpiAddressRangeMemory) {
  252. continue;
  253. }
  254. ASSERT((0xFFFFFFFF00000000 & E820Data->E820Entry[i].Base) == 0);
  255. if (E820Data->E820Entry[i].Length > memUnit) {
  256. descCount += (ULONG) (E820Data->E820Entry[i].Length / memUnit);
  257. if ((E820Data->E820Entry[i].Length % memUnit) != 0) {
  258. descCount++;
  259. }
  260. } else {
  261. descCount++;
  262. }
  263. }
  264. return descCount;
  265. }
  266. NTSTATUS
  267. SpSimCreateMemOpRegion(
  268. IN PSPSIM_EXTENSION SpSim
  269. )
  270. {
  271. PACPI_BIOS_MULTI_NODE E820Data;
  272. ULONG i, descCount, memUnit = MIN_LARGE_DESC;
  273. NTSTATUS status;
  274. status = SpSimRetrieveE820Data(&E820Data);
  275. if (!NT_SUCCESS(status)) {
  276. SpSim->MemOpRegionValues = NULL;
  277. return status;
  278. }
  279. ASSERT(E820Data);
  280. descCount = descCount = SpSimCalculateMemoryDescCount(E820Data, memUnit);
  281. while (descCount > (MAX_MEMORY_OBJ * MAX_MEMORY_DESC_PER_OBJ)) {
  282. memUnit = memUnit << 1;
  283. descCount = SpSimCalculateMemoryDescCount(E820Data, memUnit);
  284. }
  285. SpSim->MemOpRegionValues =
  286. ExAllocatePool(NonPagedPool,
  287. sizeof(MEM_REGION_DESCRIPTOR) * descCount);
  288. if (SpSim->MemOpRegionValues == NULL) {
  289. status = STATUS_INSUFFICIENT_RESOURCES;
  290. goto out;
  291. }
  292. RtlZeroMemory(SpSim->MemOpRegionValues,
  293. sizeof(MEM_REGION_DESCRIPTOR) * descCount);
  294. SpSimFillMemoryDescs(E820Data, memUnit, SpSim->MemOpRegionValues);
  295. SpSim->MemCount = descCount;
  296. out:
  297. ExFreePool(E820Data);
  298. if (!NT_SUCCESS(status)) {
  299. if (SpSim->MemOpRegionValues) {
  300. ExFreePool(SpSim->MemOpRegionValues);
  301. SpSim->MemOpRegionValues = NULL;
  302. }
  303. SpSim->MemCount = 0;
  304. }
  305. return status;
  306. }
  307. VOID
  308. SpSimDeleteMemOpRegion(
  309. IN PSPSIM_EXTENSION SpSim
  310. )
  311. {
  312. if (SpSim->MemOpRegionValues) {
  313. ExFreePool(SpSim->MemOpRegionValues);
  314. SpSim->MemOpRegionValues = NULL;
  315. }
  316. }
  317. NTSTATUS
  318. SpSimMemOpRegionReadWrite(
  319. PSPSIM_EXTENSION SpSim,
  320. ULONG AccessType,
  321. ULONG Offset,
  322. ULONG Size,
  323. PUCHAR Data
  324. )
  325. {
  326. ULONG i, limit;
  327. PUCHAR current;
  328. ASSERT((Offset & 3) == 0);
  329. ASSERT((Size & 3) == 0);
  330. if (SpSim->MemOpRegionValues == NULL) {
  331. return STATUS_INVALID_PARAMETER;
  332. }
  333. limit = sizeof(MEM_REGION_DESCRIPTOR)*SpSim->MemCount;
  334. // We're going to define this op region to return all zeros if you
  335. // access beyond that which we've been able to initialize using
  336. // the E820 data.
  337. if (Offset >= limit) {
  338. RtlZeroMemory(Data, Size);
  339. return STATUS_SUCCESS;
  340. }
  341. if (Offset + Size > limit) {
  342. return STATUS_INVALID_PARAMETER;
  343. }
  344. ASSERT(Offset < limit);
  345. /// XXX if the asserts hold then this should get fixed.
  346. current = ((PUCHAR) (SpSim->MemOpRegionValues)) + Offset;
  347. if (AccessType & ACPI_OPREGION_WRITE) {
  348. for (i = 0 ; i < Size; i++) {
  349. *current++ = *Data++;
  350. }
  351. } else {
  352. for (i = 0 ; i < Size; i++) {
  353. *Data++ = *current++;
  354. }
  355. }
  356. return STATUS_SUCCESS;
  357. }
  358. NTSTATUS
  359. EXPORT
  360. SpSimMemOpRegionHandler (
  361. ULONG AccessType,
  362. PVOID OpRegion,
  363. ULONG Address,
  364. ULONG Size,
  365. PULONG Data,
  366. ULONG_PTR Context,
  367. PACPI_OPREGION_CALLBACK CompletionHandler,
  368. PVOID CompletionContext
  369. )
  370. /*++
  371. Routine Description:
  372. This routine handles requests to service the
  373. SPSIM operation region contained within this driver
  374. Arguments:
  375. AccessType - Read or Write data
  376. OpRegion - Operation region object
  377. Address - Address within the EC address space
  378. Size - Number of bytes to transfer
  379. Data - Data buffer to transfer to/from
  380. Context - SpSim
  381. CompletionHandler - AMLI handler to call when operation is complete
  382. CompletionContext - Context to pass to the AMLI handler
  383. Return Value:
  384. Status
  385. --*/
  386. {
  387. NTSTATUS status;
  388. status = SpSimMemOpRegionReadWrite((PSPSIM_EXTENSION) Context,
  389. AccessType,
  390. Address,
  391. Size,
  392. (PUCHAR)Data);
  393. return status;
  394. }
  395. NTSTATUS
  396. SpSimInstallMemOpRegionHandler(
  397. IN OUT PSPSIM_EXTENSION SpSim
  398. )
  399. /*++
  400. Routine Description:
  401. This calls the ACPI driver to install itself as the op region
  402. handler for the Mem region. It also allocates the memory for the
  403. opregion itself.
  404. Arguments:
  405. pSpSimData - Pointer to the SpSim extension
  406. Return Value:
  407. Status
  408. --*/
  409. {
  410. NTSTATUS status;
  411. status=RegisterOpRegionHandler (
  412. SpSim->AttachedDevice,
  413. ACPI_OPREGION_ACCESS_AS_COOKED,
  414. MEM_OPREGION,
  415. SpSimMemOpRegionHandler,
  416. SpSim,
  417. 0,
  418. &SpSim->MemOpRegion
  419. );
  420. //
  421. // Check the status code
  422. //
  423. if(!NT_SUCCESS(status)) {
  424. SpSim->MemOpRegion = NULL;
  425. DbgPrint("Not successful in installing:=%x\n", status);
  426. return status;
  427. }
  428. // XXXX
  429. return STATUS_SUCCESS;
  430. }
  431. NTSTATUS
  432. SpSimRemoveMemOpRegionHandler (
  433. IN OUT PSPSIM_EXTENSION SpSim
  434. )
  435. /*++
  436. Routine Description:
  437. Uninstalls itself as the opregion handler.
  438. Arguments:
  439. SpSim - Pointer to the SpSim extension
  440. Return Value:
  441. Status
  442. --*/
  443. {
  444. NTSTATUS status;
  445. PIRP irp;
  446. if (SpSim->MemOpRegion != NULL) {
  447. status = DeRegisterOpRegionHandler (
  448. SpSim->AttachedDevice,
  449. SpSim->MemOpRegion
  450. );
  451. SpSim->MemOpRegion = NULL;
  452. } else {
  453. status = STATUS_SUCCESS;
  454. }
  455. return status;
  456. }