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.

716 lines
17 KiB

  1. /*++
  2. Copyright (c) 1996-2000 Microsoft Corporation
  3. Module Name:
  4. hookhal.c
  5. Abstract:
  6. The module overrides the Hal functions that are now controlled by the
  7. PCI driver.
  8. Author:
  9. Andrew Thornton (andrewth) 11-Sept-1998
  10. Revision History:
  11. --*/
  12. #include "pcip.h"
  13. pHalAssignSlotResources PcipSavedAssignSlotResources = NULL;
  14. pHalTranslateBusAddress PcipSavedTranslateBusAddress = NULL;
  15. BOOLEAN
  16. PciTranslateBusAddress(
  17. IN INTERFACE_TYPE InterfaceType,
  18. IN ULONG BusNumber,
  19. IN PHYSICAL_ADDRESS BusAddress,
  20. IN OUT PULONG AddressSpace,
  21. OUT PPHYSICAL_ADDRESS TranslatedAddress
  22. );
  23. VOID
  24. PciHookHal(
  25. VOID
  26. )
  27. /*++
  28. Routine Description:
  29. This is called when the PCI driver is loaded and it takes over the functions
  30. that have traditionally been in the HAL.
  31. Arguments:
  32. None
  33. Return Value:
  34. None
  35. --*/
  36. {
  37. ASSERT(PcipSavedAssignSlotResources == NULL);
  38. ASSERT(PcipSavedTranslateBusAddress == NULL);
  39. //
  40. // Override the handlers for AssignSlotResources and
  41. // TranslateBusAddress. (But only modify the HAL dispatch
  42. // table once.)
  43. //
  44. PcipSavedAssignSlotResources = HALPDISPATCH->HalPciAssignSlotResources;
  45. HALPDISPATCH->HalPciAssignSlotResources = PciAssignSlotResources;
  46. PcipSavedTranslateBusAddress = HALPDISPATCH->HalPciTranslateBusAddress;
  47. HALPDISPATCH->HalPciTranslateBusAddress = PciTranslateBusAddress;
  48. }
  49. VOID
  50. PciUnhookHal(
  51. VOID
  52. )
  53. /*++
  54. Routine Description:
  55. This reverses the changed made by PciHookHal. It is called as part of
  56. unloading the PCI driver which seems like a really bad idea...
  57. Arguments:
  58. None
  59. Return Value:
  60. None
  61. --*/
  62. {
  63. ASSERT(PcipSavedAssignSlotResources != NULL);
  64. ASSERT(PcipSavedTranslateBusAddress != NULL);
  65. //
  66. // Override the handlers for AssignSlotResources and
  67. // TranslateBusAddress. (But only modify the HAL dispatch
  68. // table once.)
  69. //
  70. HALPDISPATCH->HalPciAssignSlotResources = PcipSavedAssignSlotResources;
  71. HALPDISPATCH->HalPciTranslateBusAddress = PcipSavedTranslateBusAddress;
  72. PcipSavedAssignSlotResources = NULL;
  73. PcipSavedTranslateBusAddress = NULL;
  74. }
  75. PPCI_PDO_EXTENSION
  76. PciFindPdoByLocation(
  77. IN ULONG BusNumber,
  78. IN PCI_SLOT_NUMBER Slot
  79. )
  80. /*++
  81. Routine Description:
  82. Arguments:
  83. BusNumber - the bus number of the bus the device is on
  84. Slot - the device/function of the device
  85. Return Value:
  86. The PDO or NULL if one can not be found
  87. --*/
  88. {
  89. PSINGLE_LIST_ENTRY nextEntry;
  90. PPCI_FDO_EXTENSION fdoExtension;
  91. PPCI_PDO_EXTENSION pdoExtension = NULL;
  92. ExAcquireFastMutex(&PciGlobalLock);
  93. //
  94. // Find the bus FDO.
  95. //
  96. for ( nextEntry = PciFdoExtensionListHead.Next;
  97. nextEntry != NULL;
  98. nextEntry = nextEntry->Next ) {
  99. fdoExtension = CONTAINING_RECORD(nextEntry,
  100. PCI_FDO_EXTENSION,
  101. List);
  102. if (fdoExtension->BaseBus == BusNumber) {
  103. break;
  104. }
  105. }
  106. ExReleaseFastMutex(&PciGlobalLock);
  107. if (nextEntry == NULL) {
  108. //
  109. // This is bad.
  110. //
  111. PciDebugPrint(PciDbgAlways, "Pci: Could not find PCI bus FDO. Bus Number = 0x%x\n", BusNumber);
  112. goto cleanup;
  113. }
  114. //
  115. // Now find the pdo for the device in this slot
  116. //
  117. ExAcquireFastMutex(&fdoExtension->ChildListMutex);
  118. for (pdoExtension = fdoExtension->ChildPdoList;
  119. pdoExtension;
  120. pdoExtension = pdoExtension->Next) {
  121. //
  122. // People probably don't clear the unused bits in a PCI_SLOT_NUMBER so
  123. // ignore them in the main build but assert checked so we can get this
  124. // fixed
  125. //
  126. if (pdoExtension->Slot.u.bits.DeviceNumber == Slot.u.bits.DeviceNumber
  127. && pdoExtension->Slot.u.bits.FunctionNumber == Slot.u.bits.FunctionNumber) {
  128. ASSERT(pdoExtension->Slot.u.AsULONG == Slot.u.AsULONG);
  129. //
  130. // This is our guy!
  131. //
  132. break;
  133. }
  134. }
  135. ExReleaseFastMutex(&fdoExtension->ChildListMutex);
  136. if (pdoExtension == NULL) {
  137. //
  138. // This is bad.
  139. //
  140. PciDebugPrint(PciDbgAlways,
  141. "Pci: Could not find PDO for device @ %x.%x.%x\n",
  142. BusNumber,
  143. Slot.u.bits.DeviceNumber,
  144. Slot.u.bits.FunctionNumber
  145. );
  146. goto cleanup;
  147. }
  148. return pdoExtension;
  149. cleanup:
  150. return NULL;
  151. }
  152. NTSTATUS
  153. PciAssignSlotResources (
  154. IN PUNICODE_STRING RegistryPath,
  155. IN PUNICODE_STRING DriverClassName OPTIONAL,
  156. IN PDRIVER_OBJECT DriverObject,
  157. IN PDEVICE_OBJECT DeviceObject OPTIONAL,
  158. IN INTERFACE_TYPE BusType,
  159. IN ULONG BusNumber,
  160. IN ULONG Slot,
  161. IN OUT PCM_RESOURCE_LIST *AllocatedResources
  162. )
  163. /*++
  164. Routine Description:
  165. This subsumes the the functinality of HalAssignSlotResources for PCI devices.
  166. This function builds some bookkeeping information about legacy
  167. PCI device so that we know how to route interrupts for these
  168. PCI devices. We build this here because this is the only place
  169. we see the legacy device object associated with proper bus, slot,
  170. function information.
  171. Arguments:
  172. As HalAssignSlotResources
  173. Return Value:
  174. STATUS_SUCCESS or error
  175. --*/
  176. {
  177. NTSTATUS status;
  178. PPCI_PDO_EXTENSION pdoExtension;
  179. PPCI_SLOT_NUMBER slotNumber = (PPCI_SLOT_NUMBER) &Slot;
  180. PCI_COMMON_HEADER buffer;
  181. PPCI_COMMON_CONFIG commonConfig = (PPCI_COMMON_CONFIG) &buffer;
  182. PIO_RESOURCE_REQUIREMENTS_LIST requirements = NULL;
  183. PCM_RESOURCE_LIST resources = NULL;
  184. ULONG readIndex, writeIndex;
  185. PCM_PARTIAL_RESOURCE_LIST partialList;
  186. PCM_PARTIAL_RESOURCE_DESCRIPTOR descriptors;
  187. ULONG descriptorCount;
  188. PDEVICE_OBJECT oldDO;
  189. PAGED_CODE();
  190. ASSERT(PcipSavedAssignSlotResources);
  191. ASSERT(BusType == PCIBus);
  192. *AllocatedResources = NULL;
  193. pdoExtension = PciFindPdoByLocation(BusNumber, *slotNumber);
  194. if (!pdoExtension) {
  195. return STATUS_DEVICE_DOES_NOT_EXIST;
  196. }
  197. //
  198. // Grab the PciGlobalLock since we will modify the legacy cache.
  199. //
  200. ExAcquireFastMutex(&PciGlobalLock);
  201. //
  202. // Make sure that they didn't pass us in our PDO
  203. //
  204. ASSERT(DeviceObject != pdoExtension->PhysicalDeviceObject);
  205. PciReadDeviceConfig(
  206. pdoExtension,
  207. commonConfig,
  208. 0,
  209. PCI_COMMON_HDR_LENGTH
  210. );
  211. //
  212. // Cache everything we have now learned about this
  213. // device object provided that they gave us one so that we can regurgitate
  214. // it when the IRQ arbiter needs to know.
  215. //
  216. //
  217. // NTRAID #62644 - 4/20/2000 - andrewth
  218. //
  219. // This should go away when we return the real PCI pdo
  220. // from IoReportDetectedDevice
  221. //
  222. status = PciCacheLegacyDeviceRouting(
  223. DeviceObject,
  224. BusNumber,
  225. Slot,
  226. commonConfig->u.type0.InterruptLine,
  227. commonConfig->u.type0.InterruptPin,
  228. commonConfig->BaseClass,
  229. commonConfig->SubClass,
  230. PCI_PARENT_FDOX(pdoExtension)->PhysicalDeviceObject,
  231. pdoExtension,
  232. &oldDO
  233. );
  234. if (!NT_SUCCESS(status)) {
  235. //
  236. // We failed to allocate memory while trying to cache this legacy DO.
  237. //
  238. goto ExitWithoutUpdatingCache;
  239. }
  240. //
  241. // Build a requirements list for this device
  242. //
  243. status = PciBuildRequirementsList(pdoExtension,
  244. commonConfig,
  245. &requirements
  246. );
  247. pdoExtension->LegacyDriver = TRUE;
  248. if (!NT_SUCCESS(status)) {
  249. goto ExitWithCacheRestoreOnFailure;
  250. }
  251. //
  252. // Call the legacy API to get the resources
  253. //
  254. status = IoAssignResources(RegistryPath,
  255. DriverClassName,
  256. DriverObject,
  257. DeviceObject,
  258. requirements,
  259. &resources
  260. );
  261. if (!NT_SUCCESS(status)) {
  262. ASSERT(resources == NULL);
  263. goto ExitWithCacheRestoreOnFailure;
  264. }
  265. //
  266. // Enable the decodes
  267. //
  268. pdoExtension->CommandEnables |= (PCI_ENABLE_IO_SPACE
  269. | PCI_ENABLE_MEMORY_SPACE
  270. | PCI_ENABLE_BUS_MASTER);
  271. //
  272. // Set up the extension
  273. //
  274. PciComputeNewCurrentSettings(pdoExtension,
  275. resources
  276. );
  277. //
  278. // Program the hardware
  279. //
  280. status = PciSetResources(pdoExtension,
  281. TRUE, // power on
  282. TRUE // pretend its from a start irp
  283. );
  284. if (!NT_SUCCESS(status)) {
  285. goto ExitWithCacheRestoreOnFailure;
  286. }
  287. //
  288. // Remove the device privates from the list - yes this means that we will
  289. // have allocated a little more pool than required.
  290. //
  291. ASSERT(resources->Count == 1);
  292. partialList = &resources->List[0].PartialResourceList;
  293. descriptorCount = resources->List[0].PartialResourceList.Count;
  294. descriptors = &resources->List[0].PartialResourceList.PartialDescriptors[0];
  295. readIndex = 0;
  296. writeIndex = 0;
  297. while (readIndex < descriptorCount) {
  298. if (descriptors[readIndex].Type != CmResourceTypeDevicePrivate) {
  299. if (writeIndex < readIndex) {
  300. //
  301. // Shuffle the descriptor up
  302. //
  303. RtlCopyMemory(&descriptors[writeIndex],
  304. &descriptors[readIndex],
  305. sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR)
  306. );
  307. }
  308. writeIndex++;
  309. } else {
  310. //
  311. // Skip the device private, don't increment writeCount so we will
  312. // overwrite it
  313. //
  314. ASSERT(partialList->Count > 0);
  315. partialList->Count--;
  316. }
  317. readIndex++;
  318. }
  319. ASSERT(partialList->Count > 0);
  320. *AllocatedResources = resources;
  321. resources = NULL;
  322. status = STATUS_SUCCESS;
  323. ExitWithCacheRestoreOnFailure:
  324. //
  325. // On failure, restore the old legacy DO in our cache.
  326. //
  327. if (!NT_SUCCESS(status)) {
  328. PciCacheLegacyDeviceRouting(
  329. oldDO,
  330. BusNumber,
  331. Slot,
  332. commonConfig->u.type0.InterruptLine,
  333. commonConfig->u.type0.InterruptPin,
  334. commonConfig->BaseClass,
  335. commonConfig->SubClass,
  336. PCI_PARENT_FDOX(pdoExtension)->PhysicalDeviceObject,
  337. pdoExtension,
  338. NULL
  339. );
  340. }
  341. ExitWithoutUpdatingCache:
  342. ExReleaseFastMutex(&PciGlobalLock);
  343. if (requirements) {
  344. ExFreePool(requirements);
  345. }
  346. if (resources) {
  347. ExFreePool(resources);
  348. }
  349. return status;
  350. }
  351. BOOLEAN
  352. PciTranslateBusAddress(
  353. IN INTERFACE_TYPE InterfaceType,
  354. IN ULONG BusNumber,
  355. IN PHYSICAL_ADDRESS BusAddress,
  356. IN OUT PULONG AddressSpace,
  357. OUT PPHYSICAL_ADDRESS TranslatedAddress
  358. )
  359. /*++
  360. Routine Description:
  361. This subsumes the the functinality of HalTranslateBusAddress for PCI devices.
  362. Arguments:
  363. As HalTranslateBusAddress
  364. Return Value:
  365. TRUE if translation succeeded, FALSE otherwise.
  366. --*/
  367. {
  368. PPCI_FDO_EXTENSION fdoExtension;
  369. PSINGLE_LIST_ENTRY nextEntry;
  370. ULONG savedAddressSpace;
  371. PPCI_PDO_EXTENSION pdoExtension = NULL;
  372. BOOLEAN subtractive = FALSE, translatesOk = TRUE;
  373. PPCI_ARBITER_INSTANCE pciArbiter;
  374. PCI_SIGNATURE arbiterType;
  375. PARBITER_INSTANCE arbiter;
  376. RTL_RANGE_LIST_ITERATOR iterator;
  377. PRTL_RANGE current;
  378. ULONGLONG address = (ULONGLONG) BusAddress.QuadPart;
  379. //
  380. // HalTranslateBusAddress can be called at high IRQL (the DDK says
  381. // <= DISPATCH_LEVEL) but crash dump seems to be at HIGH_LEVEL. Either way
  382. // touching pageable data and code is a no no. If we are calling at high
  383. // IRQL then just skip the validation that the range is on the bus as we are
  384. // crashing/hibernating at the time anyway... We still need to call the
  385. // original hal function to perform the translation magic.
  386. //
  387. if (KeGetCurrentIrql() < DISPATCH_LEVEL) {
  388. //
  389. // Find the FDO for this bus
  390. //
  391. ExAcquireFastMutex(&PciGlobalLock);
  392. for ( nextEntry = PciFdoExtensionListHead.Next;
  393. nextEntry != NULL;
  394. nextEntry = nextEntry->Next ) {
  395. fdoExtension = CONTAINING_RECORD(nextEntry,
  396. PCI_FDO_EXTENSION,
  397. List);
  398. if (fdoExtension->BaseBus == BusNumber) {
  399. break;
  400. }
  401. }
  402. if (nextEntry == NULL) {
  403. //
  404. // This is bad.
  405. //
  406. PciDebugPrint(PciDbgAlways, "Pci: Could not find PCI bus FDO. Bus Number = 0x%x\n", BusNumber);
  407. ExReleaseFastMutex(&PciGlobalLock);
  408. return FALSE;
  409. }
  410. for (;;) {
  411. if (!PCI_IS_ROOT_FDO(fdoExtension)) {
  412. pdoExtension = PCI_BRIDGE_PDO(fdoExtension);
  413. if (pdoExtension->Dependent.type1.SubtractiveDecode) {
  414. //
  415. // It is subtractive go up a level, rinse and repeat
  416. //
  417. fdoExtension = PCI_PARENT_FDOX(pdoExtension);
  418. continue;
  419. }
  420. }
  421. break;
  422. }
  423. ExReleaseFastMutex(&PciGlobalLock);
  424. ASSERT(fdoExtension);
  425. //
  426. // Find the appropriate arbiter
  427. //
  428. switch (*AddressSpace) {
  429. case 0: // Memory space
  430. case 2: // UserMode view of memory space (Alpha)
  431. case 4: // Dense memory space (Alpha)
  432. case 6: // UserMode view of dense memory space (Alpha)
  433. arbiterType = PciArb_Memory;
  434. break;
  435. case 1: // Port space
  436. case 3: // UserMode view of port space (Alpha)
  437. arbiterType = PciArb_Io;
  438. break;
  439. default:
  440. ASSERT(FALSE);
  441. return FALSE;
  442. }
  443. pciArbiter = PciFindSecondaryExtension(fdoExtension,arbiterType);
  444. if (!pciArbiter) {
  445. ASSERT(FALSE);
  446. return FALSE;
  447. }
  448. arbiter = &pciArbiter->CommonInstance;
  449. //
  450. // Lock it
  451. //
  452. ArbAcquireArbiterLock(arbiter);
  453. //
  454. // If the range is not owned by NULL then it should translate
  455. //
  456. FOR_ALL_RANGES(arbiter->Allocation, &iterator, current) {
  457. if (address < current->Start) {
  458. //
  459. // We have passed all possible intersections
  460. //
  461. break;
  462. }
  463. if (INTERSECT(current->Start, current->End, address, address)
  464. && current->Owner == NULL) {
  465. //
  466. // This guy is not on our bus so he doesn't translate!
  467. //
  468. translatesOk = FALSE;
  469. break;
  470. }
  471. }
  472. ArbReleaseArbiterLock(arbiter);
  473. }
  474. //
  475. // Call the original HAL function to perform the translation magic
  476. //
  477. if (translatesOk) {
  478. savedAddressSpace = *AddressSpace;
  479. translatesOk = PcipSavedTranslateBusAddress(
  480. InterfaceType,
  481. BusNumber,
  482. BusAddress,
  483. AddressSpace,
  484. TranslatedAddress
  485. );
  486. }
  487. #if defined(_X86_) && defined(PCI_NT50_BETA1_HACKS)
  488. if (!translatesOk) {
  489. //
  490. // HalTranslateBusAddress failed, figure out if we want to
  491. // pretend it succeeded.
  492. //
  493. //
  494. // GROSS HACK: If we failed to translate in the range 0xa0000
  495. // thru 0xbffff on an X86 machine, just go ahead and allow it.
  496. // It is probably because the BIOS is buggy.
  497. //
  498. // Same for 0x400 thru 0x4ff
  499. //
  500. if (BusAddress.HighPart == 0) {
  501. ULONG lowPart = BusAddress.LowPart; // improve code generation
  502. if (((savedAddressSpace == ADDRESS_SPACE_MEMORY) &&
  503. (((lowPart >= 0xa0000) && // HACK broken MPS BIOS
  504. (lowPart <= 0xbffff)) || //
  505. ((lowPart >= 0x400) && // HACK MGA
  506. (lowPart <= 0x4ff)) || //
  507. (lowPart == 0x70) )) || // HACK Trident
  508. ((savedAddressSpace == ADDRESS_SPACE_PORT) &&
  509. ((lowPart >= 0xcf8) && // HACK MGA
  510. (lowPart <= 0xcff)))) {
  511. translatesOk = TRUE;
  512. *TranslatedAddress = BusAddress;
  513. *AddressSpace = savedAddressSpace;
  514. }
  515. }
  516. }
  517. #endif
  518. return translatesOk;
  519. }