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.

695 lines
20 KiB

  1. /*++
  2. Copyright (c) 1991-2000 Microsoft Corporation
  3. Module Name:
  4. ixinfo.c
  5. Abstract:
  6. Author:
  7. Ken Reneris (kenr) 08-Aug-1994
  8. Environment:
  9. Kernel mode only.
  10. Revision History:
  11. --*/
  12. #include "halp.h"
  13. #include "pci.h"
  14. #include "pcip.h"
  15. #ifdef _PNP_POWER_
  16. HAL_CALLBACKS HalCallback;
  17. extern WCHAR rgzSuspendCallbackName[];
  18. VOID
  19. HalInitSystemPhase2 (
  20. VOID
  21. );
  22. VOID
  23. HalpLockSuspendCode (
  24. IN PVOID CallbackContext,
  25. IN PVOID Argument1,
  26. IN PVOID Argument2
  27. );
  28. #endif
  29. NTSTATUS
  30. HalpQueryInstalledBusInformation (
  31. OUT PVOID Buffer,
  32. IN ULONG BufferLength,
  33. OUT PULONG ReturnedLength
  34. );
  35. #ifdef ALLOC_PRAGMA
  36. #pragma alloc_text(PAGE,HaliQuerySystemInformation)
  37. #pragma alloc_text(PAGE,HaliSetSystemInformation)
  38. #pragma alloc_text(INIT,HalInitSystemPhase2)
  39. #ifdef _PNP_POWER_
  40. #pragma alloc_text(PAGE,HalpLockSuspendCode)
  41. #endif
  42. #endif
  43. //
  44. // HalQueryMcaInterface
  45. //
  46. VOID
  47. HalpMcaLockInterface(
  48. VOID
  49. );
  50. VOID
  51. HalpMcaUnlockInterface(
  52. VOID
  53. );
  54. NTSTATUS
  55. HalpMcaReadRegisterInterface(
  56. IN UCHAR BankNumber,
  57. IN OUT PMCA_EXCEPTION Exception
  58. );
  59. #ifdef ACPI_HAL
  60. extern PHYSICAL_ADDRESS HalpMaxHotPlugMemoryAddress;
  61. #endif
  62. #if defined(ACPI_HAL) && defined(_HALPAE_) && !defined(NT_UP)
  63. extern PVOID HalpAcpiSrat;
  64. NTSTATUS
  65. HalpGetAcpiStaticNumaTopology(
  66. HAL_NUMA_TOPOLOGY_INTERFACE * NumaInfo
  67. );
  68. #endif
  69. VOID
  70. HalInitSystemPhase2 (
  71. VOID
  72. )
  73. {
  74. #ifdef _PNP_POWER_
  75. OBJECT_ATTRIBUTES ObjectAttributes;
  76. NTSTATUS Status;
  77. UNICODE_STRING unicodeString;
  78. PCALLBACK_OBJECT CallbackObject;
  79. //
  80. // Create hal callbacks
  81. //
  82. InitializeObjectAttributes(
  83. &ObjectAttributes,
  84. NULL,
  85. OBJ_CASE_INSENSITIVE,
  86. NULL,
  87. NULL
  88. );
  89. ExCreateCallback (&HalCallback.SetSystemInformation, &ObjectAttributes, TRUE, TRUE);
  90. ExCreateCallback (&HalCallback.BusCheck, &ObjectAttributes, TRUE, TRUE);
  91. //
  92. // Connect to suspend callback to lock hal hibaration code
  93. //
  94. RtlInitUnicodeString(&unicodeString, rgzSuspendCallbackName);
  95. InitializeObjectAttributes(
  96. &ObjectAttributes,
  97. &unicodeString,
  98. OBJ_CASE_INSENSITIVE,
  99. NULL,
  100. NULL
  101. );
  102. Status = ExCreateCallback (&CallbackObject, &ObjectAttributes, FALSE, FALSE);
  103. if (NT_SUCCESS(Status)) {
  104. ExRegisterCallback (
  105. CallbackObject,
  106. HalpLockSuspendCode,
  107. NULL
  108. );
  109. ObDereferenceObject (CallbackObject);
  110. }
  111. #endif
  112. }
  113. #if defined(_HALPAE_) && !defined(NT_UP)
  114. NTSTATUS
  115. HalpGetApicIdByProcessorNumber(
  116. IN UCHAR Processor,
  117. IN OUT USHORT *ApicId
  118. );
  119. ULONG HalpFakeNumaNodes;
  120. ULONG HalpFakeNumaAffinity;
  121. ULONG HalpFakeNumaAffinityShift;
  122. ULONG HalpFakeNumaPageMask;
  123. ULONG HalpFakeNumaPageShift;
  124. ULONG
  125. HalpFakeNumaQueryPageToNode(
  126. IN ULONG_PTR PhysicalPageNumber
  127. )
  128. {
  129. ULONG Node;
  130. Node = (ULONG)PhysicalPageNumber >> HalpFakeNumaPageShift;
  131. Node &= HalpFakeNumaPageMask;
  132. return Node;
  133. }
  134. NTSTATUS
  135. HalpFakeNumaQueryProcessorNode(
  136. IN ULONG ProcessorNumber,
  137. OUT PUSHORT ProcessorId,
  138. OUT PUCHAR NodeNumber
  139. )
  140. {
  141. NTSTATUS Status;
  142. KAFFINITY ProcessorMask;
  143. KAFFINITY Mask;
  144. UCHAR Node;
  145. USHORT ApicId;
  146. #if defined(APIC_HAL) && !defined(NT_UP)
  147. Status = HalpGetApicIdByProcessorNumber((UCHAR)ProcessorNumber, &ApicId);
  148. if (!NT_SUCCESS(Status)) {
  149. return Status;
  150. }
  151. *ProcessorId = ApicId;
  152. #else
  153. *ProcessorId = (USHORT)ProcessorNumber;
  154. Status = STATUS_SUCCESS;
  155. #endif
  156. ProcessorMask = 1 << ProcessorNumber;
  157. for (Node = 0; Node < HalpFakeNumaNodes; Node++) {
  158. Mask = HalpFakeNumaAffinity << (Node * HalpFakeNumaAffinityShift);
  159. if ((Mask & ProcessorMask) != 0) {
  160. *NodeNumber = Node;
  161. break;
  162. }
  163. }
  164. return Status;
  165. }
  166. #endif
  167. NTSTATUS
  168. HaliQuerySystemInformation(
  169. IN HAL_QUERY_INFORMATION_CLASS InformationClass,
  170. IN ULONG BufferSize,
  171. OUT PVOID Buffer,
  172. OUT PULONG ReturnedLength
  173. )
  174. {
  175. NTSTATUS Status;
  176. PVOID InternalBuffer;
  177. ULONG Length;
  178. union {
  179. HAL_POWER_INFORMATION PowerInf;
  180. HAL_PROCESSOR_SPEED_INFORMATION ProcessorInf;
  181. MCA_EXCEPTION McaException;
  182. HAL_DISPLAY_BIOS_INFORMATION DisplayBiosInf;
  183. } U;
  184. BOOLEAN bUseFrameBufferCaching;
  185. PAGED_CODE();
  186. Status = STATUS_SUCCESS;
  187. *ReturnedLength = 0;
  188. Length = 0;
  189. switch (InformationClass) {
  190. #ifndef ACPI_HAL
  191. case HalInstalledBusInformation:
  192. Status = HalpQueryInstalledBusInformation (
  193. Buffer,
  194. BufferSize,
  195. ReturnedLength
  196. );
  197. break;
  198. #endif
  199. case HalFrameBufferCachingInformation:
  200. // Note - we want to return TRUE here to enable USWC in all
  201. // cases except in a "Shared Memory Cluster" machine.
  202. bUseFrameBufferCaching = TRUE;
  203. InternalBuffer = &bUseFrameBufferCaching;
  204. Length = sizeof (BOOLEAN);
  205. break;
  206. case HalMcaLogInformation:
  207. InternalBuffer = &U.McaException;
  208. Status = HalpGetMcaLog ((PMCA_EXCEPTION)Buffer,
  209. BufferSize,
  210. ReturnedLength);
  211. break;
  212. #if !defined(_WIN64)
  213. case HalDisplayBiosInformation:
  214. InternalBuffer = &U.DisplayBiosInf;
  215. Length = sizeof(U.DisplayBiosInf);
  216. U.DisplayBiosInf = HalpGetDisplayBiosInformation ();
  217. break;
  218. #endif
  219. #ifdef _PNP_POWER_
  220. case HalPowerInformation:
  221. RtlZeroMemory (&U.PowerInf, sizeof(HAL_POWER_INFORMATION));
  222. InternalBuffer = &U.PowerInf;
  223. Length = sizeof (HAL_POWER_INFORMATION);
  224. break;
  225. case HalProcessorSpeedInformation:
  226. RtlZeroMemory (&U.ProcessorInf, sizeof(HAL_POWER_INFORMATION));
  227. U.ProcessorInf.MaximumProcessorSpeed = 100;
  228. U.ProcessorInf.CurrentAvailableSpeed = 100;
  229. U.ProcessorInf.ConfiguredSpeedLimit = 100;
  230. InternalBuffer = &U.PowerInf;
  231. Length = sizeof (HAL_PROCESSOR_SPEED_INFORMATION);
  232. break;
  233. case HalCallbackInformation:
  234. InternalBuffer = &HalCallback;
  235. Length = sizeof (HAL_CALLBACKS);
  236. break;
  237. #endif
  238. #if defined(_HALPAE_) && !defined(NT_UP)
  239. case HalNumaTopologyInterface:
  240. if ((BufferSize == sizeof(HAL_NUMA_TOPOLOGY_INTERFACE)) &&
  241. (HalPaeEnabled() == TRUE)) {
  242. Status = STATUS_INVALID_LEVEL;
  243. #if defined(ACPI_HAL)
  244. if (HalpAcpiSrat) {
  245. Status = HalpGetAcpiStaticNumaTopology(Buffer);
  246. if (NT_SUCCESS(Status)) {
  247. *ReturnedLength = sizeof(HAL_NUMA_TOPOLOGY_INTERFACE);
  248. }
  249. break;
  250. }
  251. #endif
  252. //
  253. // Mega Kludge:
  254. //
  255. // Testing Testing Testing. MM may supply a
  256. // fake NUMA configuration for testing purposes.
  257. // In this case information is passed IN to the
  258. // HAL using this query only interface by passing
  259. // information in the output buffer and in the
  260. // returned length field.
  261. //
  262. // The returned length field will have been
  263. // initialized to the special value 'NUMA', in
  264. // this case, the incoming information buffer
  265. // contains the NUMA configuration.
  266. //
  267. if (HalpFakeNumaNodes == 0) {
  268. struct {
  269. ULONG Nodes:3;
  270. ULONG AffinityShift:6;
  271. ULONG PageShift:6;
  272. ULONG Signature:17;
  273. ULONG Affinity;
  274. ULONG Mask;
  275. } Fake;
  276. ULONG ValidateNodes;
  277. ULONG ValidateAffinity1;
  278. ULONG ValidateAffinity2;
  279. RtlCopyMemory(&Fake, Buffer, sizeof(Fake));
  280. //
  281. // Do a little validation.
  282. //
  283. if ((Fake.Signature != 0x15a5a) ||
  284. (Fake.Nodes == 0) ||
  285. ((Fake.AffinityShift | Fake.PageShift) & 0x20) ||
  286. (Fake.Affinity == 0) ||
  287. (Fake.Mask == 0) ||
  288. (Fake.Mask >= Fake.Nodes)) {
  289. Status = STATUS_INVALID_LEVEL;
  290. break;
  291. }
  292. HalpFakeNumaAffinity = Fake.Affinity;
  293. HalpFakeNumaAffinityShift = Fake.AffinityShift;
  294. HalpFakeNumaPageMask = Fake.Mask;
  295. HalpFakeNumaPageShift = Fake.PageShift;
  296. //
  297. // Generate the affinity mask for each node and
  298. // make sure there's no overlapping affinity masks.
  299. //
  300. ValidateNodes = Fake.Nodes;
  301. ValidateAffinity1 = 0;
  302. ValidateAffinity2 = 0;
  303. while (ValidateNodes) {
  304. ValidateNodes--;
  305. ValidateAffinity1 = HalpFakeNumaAffinity <<
  306. (HalpFakeNumaAffinityShift * ValidateNodes);
  307. if (ValidateAffinity1 == 0) {
  308. break;
  309. }
  310. if ((ValidateAffinity1 & ValidateAffinity2) != 0) {
  311. ValidateAffinity1 = 0;
  312. break;
  313. }
  314. ValidateAffinity2 |= ValidateAffinity1;
  315. }
  316. if (!ValidateAffinity1) {
  317. Status = STATUS_INVALID_LEVEL;
  318. break;
  319. }
  320. HalpFakeNumaNodes = Fake.Nodes;
  321. }
  322. //
  323. // End Mega Kludge.
  324. //
  325. if ((HalPaeEnabled() == TRUE) &&
  326. (HalpFakeNumaNodes != 0) &&
  327. (HalpFakeNumaAffinity != 0) &&
  328. (HalpFakeNumaAffinityShift != 0) &&
  329. (HalpFakeNumaPageMask != 0) &&
  330. (HalpFakeNumaPageShift != 0) ) {
  331. //
  332. // Pretend we have a numa configuration,...
  333. // for testing purposes only.
  334. //
  335. HAL_NUMA_TOPOLOGY_INTERFACE * NumaInfo;
  336. NumaInfo = (HAL_NUMA_TOPOLOGY_INTERFACE *)Buffer;
  337. NumaInfo->NumberOfNodes = HalpFakeNumaNodes;
  338. NumaInfo->QueryProcessorNode = HalpFakeNumaQueryProcessorNode;
  339. NumaInfo->PageToNode = HalpFakeNumaQueryPageToNode;
  340. *ReturnedLength = sizeof(HAL_NUMA_TOPOLOGY_INTERFACE);
  341. Status = STATUS_SUCCESS;
  342. }
  343. } else {
  344. //
  345. // Buffer size is wrong, we could return valid data
  346. // if the buffer is too big,.... but instead we will
  347. // use this as an indication that we're not compatible
  348. // with the kernel.
  349. //
  350. Status = STATUS_INFO_LENGTH_MISMATCH;
  351. }
  352. break;
  353. #endif
  354. case HalQueryMcaInterface:
  355. if (BufferSize == sizeof(HAL_MCA_INTERFACE)) {
  356. HAL_MCA_INTERFACE *McaInterface;
  357. McaInterface = (HAL_MCA_INTERFACE *)Buffer;
  358. McaInterface->Lock = HalpMcaLockInterface;
  359. McaInterface->Unlock = HalpMcaUnlockInterface;
  360. McaInterface->ReadRegister = HalpMcaReadRegisterInterface;
  361. *ReturnedLength = sizeof(HAL_MCA_INTERFACE);
  362. Status = STATUS_SUCCESS;
  363. } else {
  364. Status = STATUS_INFO_LENGTH_MISMATCH;
  365. }
  366. break;
  367. case HalQueryMaxHotPlugMemoryAddress:
  368. if (BufferSize == sizeof(PHYSICAL_ADDRESS)) {
  369. #ifdef ACPI_HAL
  370. *((PPHYSICAL_ADDRESS) Buffer) = HalpMaxHotPlugMemoryAddress;
  371. *ReturnedLength = sizeof(PHYSICAL_ADDRESS);
  372. Status = STATUS_SUCCESS;
  373. #else
  374. Status = STATUS_NOT_IMPLEMENTED;
  375. #endif
  376. } else {
  377. Status = STATUS_INFO_LENGTH_MISMATCH;
  378. }
  379. break;
  380. case HalQueryAMLIIllegalIOPortAddresses:
  381. {
  382. HAL_AMLI_BAD_IO_ADDRESS_LIST BadIOAddrList[] =
  383. {
  384. {0x000, 0x10, 0x1, NULL }, // ISA DMA
  385. {0x020, 0x2, 0x0, NULL }, // PIC
  386. {0x040, 0x4, 0x1, NULL }, // Timer1, Referesh, Speaker, Control Word
  387. {0x048, 0x4, 0x1, NULL }, // Timer2, Failsafe
  388. {0x070, 0x2, 0x1, NULL }, // Cmos/NMI enable
  389. {0x074, 0x3, 0x1, NULL }, // Extended Cmos
  390. {0x081, 0x3, 0x1, NULL }, // DMA
  391. {0x087, 0x1, 0x1, NULL }, // DMA
  392. {0x089, 0x1, 0x1, NULL }, // DMA
  393. {0x08a, 0x2, 0x1, NULL }, // DMA
  394. {0x08f, 0x1, 0x1, NULL }, // DMA
  395. {0x090, 0x2, 0x1, NULL }, // Arbritration Control Port, Card Select Feedback
  396. {0x093, 0x2, 0x1, NULL }, // Reserved, System board setup
  397. {0x096, 0x2, 0x1, NULL }, // POS channel select
  398. {0x0A0, 0x2, 0x0, NULL }, // Cascaded PIC
  399. {0x0C0, 0x20, 0x1, NULL }, // ISA DMA
  400. {0x4D0, 0x2, 0x0, NULL }, // Edge, level control registers for PIC
  401. {0xCF8, 0x8, 0x1, &HaliHandlePCIConfigSpaceAccess}, // PCI Config Space Access Pair
  402. {0x0, 0x0, 0x0, NULL }
  403. };
  404. if(BufferSize < sizeof(BadIOAddrList))
  405. {
  406. *ReturnedLength = sizeof(BadIOAddrList);
  407. Status = STATUS_INFO_LENGTH_MISMATCH;
  408. }
  409. else
  410. {
  411. Length = sizeof(BadIOAddrList);
  412. InternalBuffer = BadIOAddrList;
  413. Status = STATUS_SUCCESS;
  414. }
  415. break;
  416. }
  417. default:
  418. Status = STATUS_INVALID_LEVEL;
  419. break;
  420. }
  421. //
  422. // If non-zero Length copy data to callers buffer
  423. //
  424. if (Length) {
  425. if (BufferSize < Length) {
  426. Length = BufferSize;
  427. }
  428. *ReturnedLength = Length;
  429. RtlCopyMemory (Buffer, InternalBuffer, Length);
  430. }
  431. return Status;
  432. }
  433. NTSTATUS
  434. HaliSetSystemInformation (
  435. IN HAL_SET_INFORMATION_CLASS InformationClass,
  436. IN ULONG BufferSize,
  437. IN PVOID Buffer
  438. )
  439. {
  440. NTSTATUS Status;
  441. PAGED_CODE();
  442. Status = STATUS_SUCCESS;
  443. switch (InformationClass) {
  444. case HalMcaRegisterDriver:
  445. Status = HalpMcaRegisterDriver(
  446. (PMCA_DRIVER_INFO) Buffer // Info about registering driver
  447. );
  448. break;
  449. default:
  450. Status = STATUS_INVALID_LEVEL;
  451. break;
  452. }
  453. return Status;
  454. }
  455. #ifdef _PNP_POWER_
  456. VOID
  457. HalpLockSuspendCode (
  458. IN PVOID CallbackContext,
  459. IN PVOID Argument1,
  460. IN PVOID Argument2
  461. )
  462. {
  463. static PVOID CodeLock;
  464. switch ((ULONG) Argument1) {
  465. case 0:
  466. //
  467. // Lock code down which might be needed to perform a suspend
  468. //
  469. ASSERT (CodeLock == NULL);
  470. CodeLock = MmLockPagableCodeSection (&HaliSuspendHibernateSystem);
  471. break;
  472. case 1:
  473. //
  474. // Release the code lock
  475. //
  476. MmUnlockPagableImageSection (CodeLock);
  477. CodeLock = NULL;
  478. break;
  479. }
  480. }
  481. #endif
  482. /*** HaliHandlePCIConfigSpaceAccess - Check to see if the Firmware is attempting to
  483. * access to PCI Config space. If so, intercept
  484. * the read/write call and do it using HAL API's.
  485. * This way we can make these calls sync.
  486. *
  487. * ENTRY
  488. * BOOLEAN Read - TRUE iff read
  489. * ULONG Addr - Address to do the operation on
  490. * ULONG Size - Size of data
  491. * PULONG pData - Pointer to the data buffer.
  492. *
  493. * EXIT
  494. * STATUS_SUCCESS if we do the PCI config space access.
  495. */
  496. NTSTATUS HaliHandlePCIConfigSpaceAccess( BOOLEAN Read,
  497. ULONG Addr,
  498. ULONG Size,
  499. PULONG pData
  500. )
  501. {
  502. static PCI_TYPE1_CFG_BITS CF8_Data = {0};
  503. static BOOLEAN CF8_Called = FALSE;
  504. NTSTATUS Status = STATUS_SUCCESS;
  505. if(Addr == 0xCF8)
  506. {
  507. CF8_Data.u.AsULONG = *pData;
  508. CF8_Called = TRUE;
  509. }
  510. else if(Addr >= 0xCFC && Addr <= 0xCFF)
  511. {
  512. if(CF8_Called)
  513. {
  514. ULONG Offset = 0;
  515. ULONG Return = 0;
  516. PCI_SLOT_NUMBER SlotNumber = {0};
  517. Offset = (CF8_Data.u.bits.RegisterNumber << 2) + (Addr - 0xCFC);
  518. SlotNumber.u.bits.FunctionNumber = CF8_Data.u.bits.FunctionNumber;
  519. SlotNumber.u.bits.DeviceNumber = CF8_Data.u.bits.DeviceNumber;
  520. if (Read)
  521. {
  522. //
  523. // Do PCI config space read through HAL
  524. //
  525. Return = HaliPciInterfaceReadConfig( NULL,
  526. (UCHAR)CF8_Data.u.bits.BusNumber,
  527. SlotNumber.u.AsULONG,
  528. pData,
  529. Offset,
  530. Size
  531. );
  532. }
  533. else
  534. {
  535. //
  536. // Do PCI config space write through HAL
  537. //
  538. Return = HaliPciInterfaceWriteConfig( NULL,
  539. (UCHAR)CF8_Data.u.bits.BusNumber,
  540. SlotNumber.u.AsULONG,
  541. pData,
  542. Offset,
  543. Size
  544. );
  545. }
  546. }
  547. else
  548. {
  549. Status = STATUS_UNSUCCESSFUL;
  550. }
  551. }
  552. else
  553. {
  554. Status = STATUS_UNSUCCESSFUL;
  555. }
  556. return Status;
  557. }