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.

362 lines
7.9 KiB

  1. /*++
  2. Copyright (c) 2001 Microsoft Corporation
  3. Module Name:
  4. pciverifier.c
  5. Abstract:
  6. This module implements routines used to catch BIOS, hardware, and driver
  7. bugs.
  8. Author:
  9. Adrian J. Oney (AdriaO) 02/20/2001
  10. Revision History:
  11. --*/
  12. #include "pcip.h"
  13. #include <initguid.h>
  14. #include <wdmguid.h>
  15. #ifdef ALLOC_PRAGMA
  16. #pragma alloc_text(INIT, PciVerifierInit)
  17. #pragma alloc_text(PAGE, PciVerifierUnload)
  18. //#pragma alloc_text(PAGEVRFY, PciVerifierProfileChangeCallback)
  19. //#pragma alloc_text(PAGEVRFY, PciVerifierEnsureTreeConsistancy)
  20. //#pragma alloc_text(PAGEVRFY, PciVerifierRetrieveFailureData)
  21. #endif
  22. BOOLEAN PciVerifierRegistered = FALSE;
  23. #ifdef ALLOC_DATA_PRAGMA
  24. //#pragma data_seg("PAGEVRFD")
  25. #endif
  26. PVOID PciVerifierNotificationHandle = NULL;
  27. //
  28. // This is the table of PCI verifier failures
  29. //
  30. VERIFIER_DATA PciVerifierFailureTable[] = {
  31. { PCI_VERIFIER_BRIDGE_REPROGRAMMED, VFFAILURE_FAIL_LOGO,
  32. 0,
  33. "The BIOS has reprogrammed the bus numbers of an active PCI device "
  34. "(!devstack %DevObj) during a dock or undock!" },
  35. { PCI_VERIFIER_PMCSR_TIMEOUT, VFFAILURE_FAIL_LOGO,
  36. 0,
  37. "A device in the system did not update it's PMCSR register in the spec "
  38. "mandated time (!devstack %DevObj, Power state D%Ulong)" },
  39. { PCI_VERIFIER_PROTECTED_CONFIGSPACE_ACCESS, VFFAILURE_FAIL_LOGO,
  40. 0,
  41. "A driver controlling a PCI device has tried to access OS controlled "
  42. "configuration space registers (!devstack %DevObj, Offset 0x%Ulong1, "
  43. "Length 0x%Ulong2)" },
  44. { PCI_VERIFIER_INVALID_WHICHSPACE, VFFAILURE_FAIL_UNDER_DEBUGGER,
  45. 0,
  46. "A driver controlling a PCI device has tried to read or write from "
  47. "an invalid space using IRP_MN_READ/WRITE_CONFIG or via BUS_INTERFACE_STANDARD. "
  48. "NB: These functions take WhichSpace parameters of the form PCI_WHICHSPACE_* "
  49. "and not a BUS_DATA_TYPE (!devstack %DevObj, WhichSpace 0x%Ulong1)" }
  50. };
  51. VOID
  52. PciVerifierInit(
  53. IN PDRIVER_OBJECT DriverObject
  54. )
  55. /*++
  56. Routine Description:
  57. This routine initializes the hardware verification support, enabling
  58. consistancy hooks and state checks where appropriate.
  59. Arguments:
  60. DriverObject - Pointer to our driver object.
  61. Return Value:
  62. None.
  63. --*/
  64. {
  65. NTSTATUS status;
  66. if (!VfIsVerificationEnabled(VFOBJTYPE_SYSTEM_BIOS, NULL)) {
  67. return;
  68. }
  69. status = IoRegisterPlugPlayNotification(
  70. EventCategoryHardwareProfileChange,
  71. 0,
  72. NULL,
  73. DriverObject,
  74. PciVerifierProfileChangeCallback,
  75. (PVOID) NULL,
  76. &PciVerifierNotificationHandle
  77. );
  78. if (NT_SUCCESS(status)) {
  79. PciVerifierRegistered = TRUE;
  80. }
  81. }
  82. VOID
  83. PciVerifierUnload(
  84. IN PDRIVER_OBJECT DriverObject
  85. )
  86. /*++
  87. Routine Description:
  88. This routine uninitializes the hardware verification support.
  89. Arguments:
  90. DriverObject - Pointer to our driver object.
  91. Return Value:
  92. None.
  93. --*/
  94. {
  95. NTSTATUS status;
  96. UNREFERENCED_PARAMETER(DriverObject);
  97. if (!PciVerifierRegistered) {
  98. return;
  99. }
  100. ASSERT(PciVerifierNotificationHandle);
  101. status = IoUnregisterPlugPlayNotification(PciVerifierNotificationHandle);
  102. ASSERT(NT_SUCCESS(status));
  103. PciVerifierRegistered = FALSE;
  104. }
  105. NTSTATUS
  106. PciVerifierProfileChangeCallback(
  107. IN PHWPROFILE_CHANGE_NOTIFICATION NotificationStructure,
  108. IN PVOID NotUsed
  109. )
  110. /*++
  111. Routine Description:
  112. This routine gets called back during hardware profile change events if
  113. hardware verification is enabled.
  114. Arguments:
  115. NotificationStructure - Describes the hardware profile event that occured.
  116. NotUsed - Not used
  117. Return Value:
  118. NTSTATUS.
  119. --*/
  120. {
  121. PAGED_CODE();
  122. UNREFERENCED_PARAMETER(NotUsed);
  123. if (IsEqualGUID((LPGUID) &NotificationStructure->Event,
  124. (LPGUID) &GUID_HWPROFILE_CHANGE_COMPLETE)) {
  125. //
  126. // This is a HW profile change complete message. Do some tests to
  127. // ensure our hardware hasn't been reprogrammed behind our back.
  128. //
  129. PciVerifierEnsureTreeConsistancy();
  130. }
  131. return STATUS_SUCCESS;
  132. }
  133. VOID
  134. PciVerifierEnsureTreeConsistancy(
  135. VOID
  136. )
  137. /*++
  138. Routine Description:
  139. This routine checks the device tree and ensures it's physical state matches
  140. the virtual state described by our structures. A deviation may mean someone
  141. has reprogrammed the hardware behind our back.
  142. Arguments:
  143. None.
  144. Return Value:
  145. None.
  146. --*/
  147. {
  148. PSINGLE_LIST_ENTRY nextEntry;
  149. PPCI_FDO_EXTENSION fdoExtension;
  150. PPCI_PDO_EXTENSION pdoExtension;
  151. PCI_COMMON_CONFIG commonConfig;
  152. PVERIFIER_DATA verifierData;
  153. //
  154. // Walk the list of FDO extensions and verifier the physical hardware
  155. // matches our virtual state. Owning the PciGlobalLock ensures the list
  156. // is locked.
  157. //
  158. ExAcquireFastMutex(&PciGlobalLock);
  159. //
  160. // Grab the bus renumbering lock. Note that this lock can be held when
  161. // child list locks are held.
  162. //
  163. ExAcquireFastMutex(&PciBusLock);
  164. for ( nextEntry = PciFdoExtensionListHead.Next;
  165. nextEntry != NULL;
  166. nextEntry = nextEntry->Next ) {
  167. fdoExtension = CONTAINING_RECORD(nextEntry, PCI_FDO_EXTENSION, List);
  168. if (PCI_IS_ROOT_FDO(fdoExtension)) {
  169. //
  170. // It's a root FDO, ignore it.
  171. //
  172. continue;
  173. }
  174. pdoExtension = PCI_BRIDGE_PDO(fdoExtension);
  175. if (pdoExtension->NotPresent ||
  176. (pdoExtension->PowerState.CurrentDeviceState == PowerDeviceD3)) {
  177. //
  178. // Don't touch.
  179. //
  180. continue;
  181. }
  182. if ((pdoExtension->HeaderType != PCI_BRIDGE_TYPE) &&
  183. (pdoExtension->HeaderType != PCI_CARDBUS_BRIDGE_TYPE)) {
  184. //
  185. // Nothing to verify - in fact, why are here, this is a bridge list!
  186. //
  187. ASSERT(0);
  188. continue;
  189. }
  190. //
  191. // Read in the common config (that should be enough)
  192. //
  193. PciReadDeviceConfig(
  194. pdoExtension,
  195. &commonConfig,
  196. 0,
  197. sizeof(PCI_COMMON_CONFIG)
  198. );
  199. //
  200. // Ensure bus numbers haven't changed. Note that P2P and Cardbus
  201. // bridges have their Primary, Secondary & Subordinate fields in the
  202. // same place.
  203. //
  204. if ((commonConfig.u.type1.PrimaryBus !=
  205. pdoExtension->Dependent.type1.PrimaryBus) ||
  206. (commonConfig.u.type1.SecondaryBus !=
  207. pdoExtension->Dependent.type1.SecondaryBus) ||
  208. (commonConfig.u.type1.SubordinateBus !=
  209. pdoExtension->Dependent.type1.SubordinateBus)) {
  210. verifierData = PciVerifierRetrieveFailureData(
  211. PCI_VERIFIER_BRIDGE_REPROGRAMMED
  212. );
  213. ASSERT(verifierData);
  214. VfFailSystemBIOS(
  215. PCI_VERIFIER_DETECTED_VIOLATION,
  216. PCI_VERIFIER_BRIDGE_REPROGRAMMED,
  217. verifierData->FailureClass,
  218. &verifierData->Flags,
  219. verifierData->FailureText,
  220. "%DevObj",
  221. pdoExtension->PhysicalDeviceObject
  222. );
  223. }
  224. }
  225. ExReleaseFastMutex(&PciBusLock);
  226. ExReleaseFastMutex(&PciGlobalLock);
  227. }
  228. PVERIFIER_DATA
  229. PciVerifierRetrieveFailureData(
  230. IN PCI_VFFAILURE VerifierFailure
  231. )
  232. /*++
  233. Routine Description:
  234. This routine retrieves the failure data corresponding to a particular PCI
  235. verifier failure event.
  236. Arguments:
  237. PCI Failure.
  238. Return Value:
  239. Verifier data corresponding to the failure.
  240. --*/
  241. {
  242. PVERIFIER_DATA verifierData;
  243. ULONG i;
  244. for(i=0;
  245. i<(sizeof(PciVerifierFailureTable)/sizeof(PciVerifierFailureTable[0]));
  246. i++) {
  247. verifierData = PciVerifierFailureTable + i;
  248. if (verifierData->VerifierFailure == VerifierFailure) {
  249. return verifierData;
  250. }
  251. }
  252. ASSERT(0);
  253. return NULL;
  254. }