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.

729 lines
18 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. PCI_ASSERT(PcipSavedAssignSlotResources == NULL);
  38. PCI_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. PCI_ASSERT(PcipSavedAssignSlotResources != NULL);
  64. PCI_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 = NULL;
  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. PCI_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. PCI_ASSERT(PcipSavedAssignSlotResources);
  191. //
  192. // We should only ever get here if this is a request for a PCI device
  193. //
  194. if (BusType != PCIBus) {
  195. ASSERT(BusType == PCIBus);
  196. return STATUS_INVALID_PARAMETER;
  197. }
  198. *AllocatedResources = NULL;
  199. pdoExtension = PciFindPdoByLocation(BusNumber, *slotNumber);
  200. if (!pdoExtension) {
  201. return STATUS_DEVICE_DOES_NOT_EXIST;
  202. }
  203. if (pdoExtension->DeviceState != PciNotStarted) {
  204. return STATUS_INVALID_OWNER;
  205. }
  206. //
  207. // Grab the PciGlobalLock since we will modify the legacy cache.
  208. //
  209. ExAcquireFastMutex(&PciGlobalLock);
  210. //
  211. // Make sure that they didn't pass us in our PDO
  212. //
  213. PCI_ASSERT(DeviceObject != pdoExtension->PhysicalDeviceObject);
  214. PciReadDeviceConfig(
  215. pdoExtension,
  216. commonConfig,
  217. 0,
  218. PCI_COMMON_HDR_LENGTH
  219. );
  220. //
  221. // Cache everything we have now learned about this
  222. // device object provided that they gave us one so that we can regurgitate
  223. // it when the IRQ arbiter needs to know.
  224. //
  225. //
  226. // NTRAID #62644 - 4/20/2000 - andrewth
  227. //
  228. // This should go away when we return the real PCI pdo
  229. // from IoReportDetectedDevice
  230. //
  231. status = PciCacheLegacyDeviceRouting(
  232. DeviceObject,
  233. BusNumber,
  234. Slot,
  235. commonConfig->u.type0.InterruptLine,
  236. commonConfig->u.type0.InterruptPin,
  237. commonConfig->BaseClass,
  238. commonConfig->SubClass,
  239. PCI_PARENT_FDOX(pdoExtension)->PhysicalDeviceObject,
  240. pdoExtension,
  241. &oldDO
  242. );
  243. if (!NT_SUCCESS(status)) {
  244. //
  245. // We failed to allocate memory while trying to cache this legacy DO.
  246. //
  247. goto ExitWithoutUpdatingCache;
  248. }
  249. //
  250. // Build a requirements list for this device
  251. //
  252. status = PciBuildRequirementsList(pdoExtension,
  253. commonConfig,
  254. &requirements
  255. );
  256. pdoExtension->LegacyDriver = TRUE;
  257. if (!NT_SUCCESS(status)) {
  258. goto ExitWithCacheRestoreOnFailure;
  259. }
  260. //
  261. // Call the legacy API to get the resources
  262. //
  263. status = IoAssignResources(RegistryPath,
  264. DriverClassName,
  265. DriverObject,
  266. DeviceObject,
  267. requirements,
  268. &resources
  269. );
  270. if (!NT_SUCCESS(status)) {
  271. PCI_ASSERT(resources == NULL);
  272. goto ExitWithCacheRestoreOnFailure;
  273. }
  274. //
  275. // Enable the decodes
  276. //
  277. pdoExtension->CommandEnables |= (PCI_ENABLE_IO_SPACE
  278. | PCI_ENABLE_MEMORY_SPACE
  279. | PCI_ENABLE_BUS_MASTER);
  280. //
  281. // Set up the extension
  282. //
  283. PciComputeNewCurrentSettings(pdoExtension,
  284. resources
  285. );
  286. //
  287. // Program the hardware
  288. //
  289. status = PciSetResources(pdoExtension,
  290. TRUE, // power on
  291. TRUE // pretend its from a start irp
  292. );
  293. if (!NT_SUCCESS(status)) {
  294. goto ExitWithCacheRestoreOnFailure;
  295. }
  296. //
  297. // Remove the device privates from the list - yes this means that we will
  298. // have allocated a little more pool than required.
  299. //
  300. PCI_ASSERT(resources->Count == 1);
  301. partialList = &resources->List[0].PartialResourceList;
  302. descriptorCount = resources->List[0].PartialResourceList.Count;
  303. descriptors = &resources->List[0].PartialResourceList.PartialDescriptors[0];
  304. readIndex = 0;
  305. writeIndex = 0;
  306. while (readIndex < descriptorCount) {
  307. if (descriptors[readIndex].Type != CmResourceTypeDevicePrivate) {
  308. if (writeIndex < readIndex) {
  309. //
  310. // Shuffle the descriptor up
  311. //
  312. RtlCopyMemory(&descriptors[writeIndex],
  313. &descriptors[readIndex],
  314. sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR)
  315. );
  316. }
  317. writeIndex++;
  318. } else {
  319. //
  320. // Skip the device private, don't increment writeCount so we will
  321. // overwrite it
  322. //
  323. PCI_ASSERT(partialList->Count > 0);
  324. partialList->Count--;
  325. }
  326. readIndex++;
  327. }
  328. PCI_ASSERT(partialList->Count > 0);
  329. *AllocatedResources = resources;
  330. resources = NULL;
  331. status = STATUS_SUCCESS;
  332. ExitWithCacheRestoreOnFailure:
  333. //
  334. // On failure, restore the old legacy DO in our cache.
  335. //
  336. if (!NT_SUCCESS(status)) {
  337. PciCacheLegacyDeviceRouting(
  338. oldDO,
  339. BusNumber,
  340. Slot,
  341. commonConfig->u.type0.InterruptLine,
  342. commonConfig->u.type0.InterruptPin,
  343. commonConfig->BaseClass,
  344. commonConfig->SubClass,
  345. PCI_PARENT_FDOX(pdoExtension)->PhysicalDeviceObject,
  346. pdoExtension,
  347. NULL
  348. );
  349. }
  350. ExitWithoutUpdatingCache:
  351. ExReleaseFastMutex(&PciGlobalLock);
  352. if (requirements) {
  353. ExFreePool(requirements);
  354. }
  355. if (resources) {
  356. ExFreePool(resources);
  357. }
  358. return status;
  359. }
  360. BOOLEAN
  361. PciTranslateBusAddress(
  362. IN INTERFACE_TYPE InterfaceType,
  363. IN ULONG BusNumber,
  364. IN PHYSICAL_ADDRESS BusAddress,
  365. IN OUT PULONG AddressSpace,
  366. OUT PPHYSICAL_ADDRESS TranslatedAddress
  367. )
  368. /*++
  369. Routine Description:
  370. This subsumes the the functinality of HalTranslateBusAddress for PCI devices.
  371. Arguments:
  372. As HalTranslateBusAddress
  373. Return Value:
  374. TRUE if translation succeeded, FALSE otherwise.
  375. --*/
  376. {
  377. PPCI_FDO_EXTENSION fdoExtension = NULL;
  378. PSINGLE_LIST_ENTRY nextEntry;
  379. ULONG savedAddressSpace;
  380. PPCI_PDO_EXTENSION pdoExtension = NULL;
  381. BOOLEAN translatesOk = TRUE;
  382. PPCI_ARBITER_INSTANCE pciArbiter;
  383. PCI_SIGNATURE arbiterType;
  384. PARBITER_INSTANCE arbiter;
  385. RTL_RANGE_LIST_ITERATOR iterator;
  386. PRTL_RANGE current;
  387. ULONGLONG address = (ULONGLONG) BusAddress.QuadPart;
  388. //
  389. // HalTranslateBusAddress can be called at high IRQL (the DDK says
  390. // <= DISPATCH_LEVEL) but crash dump seems to be at HIGH_LEVEL. Either way
  391. // touching pageable data and code is a no no. If we are calling at high
  392. // IRQL then just skip the validation that the range is on the bus as we are
  393. // crashing/hibernating at the time anyway... We still need to call the
  394. // original hal function to perform the translation magic.
  395. //
  396. if (KeGetCurrentIrql() < DISPATCH_LEVEL) {
  397. //
  398. // Find the FDO for this bus
  399. //
  400. ExAcquireFastMutex(&PciGlobalLock);
  401. for ( nextEntry = PciFdoExtensionListHead.Next;
  402. nextEntry != NULL;
  403. nextEntry = nextEntry->Next ) {
  404. fdoExtension = CONTAINING_RECORD(nextEntry,
  405. PCI_FDO_EXTENSION,
  406. List);
  407. if (fdoExtension->BaseBus == BusNumber) {
  408. break;
  409. }
  410. }
  411. if (nextEntry == NULL) {
  412. //
  413. // This is bad.
  414. //
  415. PciDebugPrint(PciDbgAlways, "Pci: Could not find PCI bus FDO. Bus Number = 0x%x\n", BusNumber);
  416. ExReleaseFastMutex(&PciGlobalLock);
  417. return FALSE;
  418. }
  419. for (;;) {
  420. if (!PCI_IS_ROOT_FDO(fdoExtension)) {
  421. pdoExtension = PCI_BRIDGE_PDO(fdoExtension);
  422. if (pdoExtension->Dependent.type1.SubtractiveDecode) {
  423. //
  424. // It is subtractive go up a level, rinse and repeat
  425. //
  426. fdoExtension = PCI_PARENT_FDOX(pdoExtension);
  427. continue;
  428. }
  429. }
  430. break;
  431. }
  432. ExReleaseFastMutex(&PciGlobalLock);
  433. PCI_ASSERT(fdoExtension);
  434. //
  435. // Find the appropriate arbiter
  436. //
  437. switch (*AddressSpace) {
  438. case 0: // Memory space
  439. case 2: // UserMode view of memory space (Alpha)
  440. case 4: // Dense memory space (Alpha)
  441. case 6: // UserMode view of dense memory space (Alpha)
  442. arbiterType = PciArb_Memory;
  443. break;
  444. case 1: // Port space
  445. case 3: // UserMode view of port space (Alpha)
  446. arbiterType = PciArb_Io;
  447. break;
  448. default:
  449. PCI_ASSERT(FALSE);
  450. return FALSE;
  451. }
  452. pciArbiter = PciFindSecondaryExtension(fdoExtension,arbiterType);
  453. if (!pciArbiter) {
  454. PCI_ASSERT(FALSE);
  455. return FALSE;
  456. }
  457. arbiter = &pciArbiter->CommonInstance;
  458. //
  459. // Lock it
  460. //
  461. ArbAcquireArbiterLock(arbiter);
  462. //
  463. // If the range is not owned by NULL then it should translate
  464. //
  465. FOR_ALL_RANGES(arbiter->Allocation, &iterator, current) {
  466. if (address < current->Start) {
  467. //
  468. // We have passed all possible intersections
  469. //
  470. break;
  471. }
  472. if (INTERSECT(current->Start, current->End, address, address)
  473. && current->Owner == NULL) {
  474. //
  475. // This guy is not on our bus so he doesn't translate!
  476. //
  477. translatesOk = FALSE;
  478. break;
  479. }
  480. }
  481. ArbReleaseArbiterLock(arbiter);
  482. }
  483. //
  484. // Call the original HAL function to perform the translation magic
  485. //
  486. savedAddressSpace = *AddressSpace;
  487. if (translatesOk) {
  488. translatesOk = PcipSavedTranslateBusAddress(
  489. InterfaceType,
  490. BusNumber,
  491. BusAddress,
  492. AddressSpace,
  493. TranslatedAddress
  494. );
  495. }
  496. #if defined(_X86_) && defined(PCI_NT50_BETA1_HACKS)
  497. if (!translatesOk) {
  498. //
  499. // HalTranslateBusAddress failed, figure out if we want to
  500. // pretend it succeeded.
  501. //
  502. //
  503. // GROSS HACK: If we failed to translate in the range 0xa0000
  504. // thru 0xbffff on an X86 machine, just go ahead and allow it.
  505. // It is probably because the BIOS is buggy.
  506. //
  507. // Same for 0x400 thru 0x4ff
  508. //
  509. if (BusAddress.HighPart == 0) {
  510. ULONG lowPart = BusAddress.LowPart; // improve code generation
  511. if (((savedAddressSpace == ADDRESS_SPACE_MEMORY) &&
  512. (((lowPart >= 0xa0000) && // HACK broken MPS BIOS
  513. (lowPart <= 0xbffff)) || //
  514. ((lowPart >= 0x400) && // HACK MGA
  515. (lowPart <= 0x4ff)) || //
  516. (lowPart == 0x70) )) || // HACK Trident
  517. ((savedAddressSpace == ADDRESS_SPACE_PORT) &&
  518. ((lowPart >= 0xcf8) && // HACK MGA
  519. (lowPart <= 0xcff)))) {
  520. translatesOk = TRUE;
  521. *TranslatedAddress = BusAddress;
  522. *AddressSpace = savedAddressSpace;
  523. }
  524. }
  525. }
  526. #endif
  527. return translatesOk;
  528. }