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.

677 lines
20 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation All Rights Reserved
  3. Module Name:
  4. config.c
  5. Abstract:
  6. This module controls access to the simulated configuration space
  7. of the SHPC.
  8. Config access is controlled in the following manner in this simulator:
  9. We assume that this simulator will be loaded on a bridge enumerated by
  10. the SoftPCI simulator. SoftPCI keeps an internal representation of the
  11. config space of the devices it controls. The function of this simulator,
  12. then, is to manage the SHPC register set and perform commands associated
  13. with writing the SHPC config space. However, the representation of config
  14. space is kept internal to SoftPCI.
  15. Environment:
  16. Kernel Mode
  17. Revision History:
  18. Davis Walker (dwalker) Sept 8 2000
  19. --*/
  20. #include "hpsp.h"
  21. NTSTATUS
  22. HpsInitConfigSpace(
  23. IN OUT PHPS_DEVICE_EXTENSION DeviceExtension
  24. )
  25. /*++
  26. Routine Description:
  27. This routine initializes the config space of this device, and
  28. is designed to simulate a ControllerReset event.
  29. Arguments:
  30. DeviceExtension - the device extension for the current devobj
  31. ReadFromRegistry - This indicates whether or not to read the HWINIT
  32. parameters from the registry.
  33. Return value:
  34. NT Status code
  35. --*/
  36. {
  37. NTSTATUS status;
  38. UCHAR offset;
  39. //
  40. // If we haven't gotten a PCI interface yet, something's broken.
  41. //
  42. ASSERT(DeviceExtension->InterfaceWrapper.PciContext != NULL);
  43. if (DeviceExtension->InterfaceWrapper.PciContext == NULL) {
  44. return STATUS_UNSUCCESSFUL;
  45. }
  46. //
  47. // Find out where Softpci put the SHPC capability and save it away.
  48. //
  49. status = HpsGetCapabilityOffset(DeviceExtension,
  50. SHPC_CAPABILITY_ID,
  51. &offset
  52. );
  53. if (!NT_SUCCESS(status)) {
  54. return status;
  55. }
  56. DeviceExtension->ConfigOffset = offset;
  57. DbgPrintEx(DPFLTR_HPS_ID,
  58. DPFLTR_INFO_LEVEL,
  59. "HPS-Config Space initialized at offset %d\n",
  60. offset
  61. );
  62. //
  63. // Also make sure Softpci gave us a HWINIT capability. We only support
  64. // this method of initialization for now, so it's a fatal error if not.
  65. //
  66. status = HpsGetCapabilityOffset(DeviceExtension,
  67. HPS_HWINIT_CAPABILITY_ID,
  68. &offset
  69. );
  70. if (!NT_SUCCESS(status)) {
  71. return status;
  72. }
  73. //
  74. // Read the Capability Header from PCI config space. Softpci should have faked this
  75. // up for us. Then initialize the rest of the SHPC config space
  76. //
  77. DeviceExtension->InterfaceWrapper.PciGetBusData(DeviceExtension->InterfaceWrapper.PciContext,
  78. PCI_WHICHSPACE_CONFIG,
  79. &DeviceExtension->ConfigSpace.Header,
  80. DeviceExtension->ConfigOffset,
  81. sizeof(PCI_CAPABILITIES_HEADER)
  82. );
  83. DeviceExtension->ConfigSpace.DwordSelect = 0x00;
  84. DeviceExtension->ConfigSpace.Pending.AsUCHAR = 0x0;
  85. DeviceExtension->ConfigSpace.Data = 0x0;
  86. //
  87. // We'd like to keep Softpci in the loop as far as config space access goes, so write
  88. // this out to the bus.
  89. //
  90. DeviceExtension->InterfaceWrapper.PciSetBusData(DeviceExtension->InterfaceWrapper.PciContext,
  91. PCI_WHICHSPACE_CONFIG,
  92. &DeviceExtension->ConfigSpace,
  93. DeviceExtension->ConfigOffset,
  94. sizeof(SHPC_CONFIG_SPACE)
  95. );
  96. //
  97. // Finally, initialize the register set.
  98. //
  99. status = HpsInitRegisters(DeviceExtension);
  100. if (!NT_SUCCESS(status)) {
  101. return status;
  102. }
  103. return STATUS_SUCCESS;
  104. }
  105. ULONG
  106. HpsHandleDirectReadConfig(
  107. IN PVOID Context,
  108. IN ULONG DataType,
  109. IN PVOID Buffer,
  110. IN ULONG Offset,
  111. IN ULONG Length
  112. )
  113. /*++
  114. Routine Description:
  115. This routine is provided in the BUS_INTERFACE_STANDARD to allow upper
  116. drivers direct access to config space without using a ReadConfig IRP.
  117. Since SoftPCI maintains the whole config space for the bridge, simply
  118. pass the request down. This function is kept as a stub in case more
  119. work needs to be done later on reads.
  120. Arguments:
  121. Context - context provided in the interface, in this case a
  122. PHPS_INTERFACE_WRAPPER.
  123. DataType - type of config space access
  124. Buffer - a buffer to read into
  125. Offset - offset into config space to read
  126. Length - length of read
  127. Return Value:
  128. The number of bytes read from config space
  129. --*/
  130. {
  131. PHPS_DEVICE_EXTENSION deviceExtension = (PHPS_DEVICE_EXTENSION) Context;
  132. PHPS_INTERFACE_WRAPPER wrapper = &deviceExtension->InterfaceWrapper;
  133. DbgPrintEx(DPFLTR_HPS_ID,
  134. DPFLTR_INFO_LEVEL,
  135. "HPS-Config Read at offset 0x%x for length 0x%x\n",
  136. Offset,
  137. Length
  138. );
  139. return wrapper->PciGetBusData(wrapper->PciContext,
  140. DataType,
  141. Buffer,
  142. Offset,
  143. Length
  144. );
  145. }
  146. ULONG
  147. HpsHandleDirectWriteConfig(
  148. IN PVOID Context,
  149. IN ULONG DataType,
  150. IN PVOID Buffer,
  151. IN ULONG Offset,
  152. IN ULONG Length
  153. )
  154. /*++
  155. Routine Description:
  156. This routine is provided in the BUS_INTERFACE_STANDARD to allow upper
  157. drivers direct access to config space without using a WriteConfig IRP.
  158. It needs check to see if this is our config space access. If so, handle
  159. it, if not, restore the PCI interface state and pass it down.
  160. Arguments:
  161. Context - context provided in the interface, in this case a
  162. PHPS_INTERFACE_WRAPPER.
  163. DataType - type of config space access
  164. Buffer - a buffer to write from
  165. Offset - offset into config space to write to
  166. Length - length of read
  167. Return Value:
  168. The number of bytes read from config space
  169. --*/
  170. {
  171. PHPS_DEVICE_EXTENSION deviceExtension = (PHPS_DEVICE_EXTENSION) Context;
  172. PHPS_INTERFACE_WRAPPER wrapper = &deviceExtension->InterfaceWrapper;
  173. ULONG pciLength;
  174. DbgPrintEx(DPFLTR_HPS_ID,
  175. DPFLTR_INFO_LEVEL,
  176. "HPS-Config Write at offset 0x%x for length 0x%x\n",
  177. Offset,
  178. Length
  179. );
  180. if ((DataType == PCI_WHICHSPACE_CONFIG) &&
  181. IS_SUBSET(Offset,
  182. Length,
  183. deviceExtension->ConfigOffset,
  184. sizeof(SHPC_CONFIG_SPACE)
  185. )) {
  186. HpsWriteConfig(deviceExtension,
  187. Buffer,
  188. Offset,
  189. Length
  190. );
  191. RtlCopyMemory(Buffer,
  192. (PUCHAR)&deviceExtension->ConfigSpace + Offset,
  193. Length
  194. );
  195. //
  196. // Even though we've internally handled the write, pass it down to PCI so that
  197. // SoftPCI stays in the loop. Since the write may have caused other fields
  198. // of config to be written, send the whole config to softpci.
  199. //
  200. pciLength = wrapper->PciSetBusData(wrapper->PciContext,
  201. DataType,
  202. &deviceExtension->ConfigSpace,
  203. deviceExtension->ConfigOffset,
  204. sizeof(SHPC_CONFIG_SPACE)
  205. );
  206. if (pciLength != sizeof(SHPC_CONFIG_SPACE)) {
  207. return 0;
  208. } else {
  209. return Length;
  210. }
  211. } else {
  212. return wrapper->PciSetBusData(wrapper->PciContext,
  213. DataType,
  214. Buffer,
  215. Offset,
  216. Length
  217. );
  218. }
  219. }
  220. VOID
  221. HpsResync(
  222. IN PHPS_DEVICE_EXTENSION DeviceExtension
  223. )
  224. {
  225. PSHPC_CONFIG_SPACE configSpace = &DeviceExtension->ConfigSpace;
  226. PSHPC_REGISTER_SET registerSet = &DeviceExtension->RegisterSet;
  227. if (DeviceExtension->UseConfig) {
  228. configSpace->Pending.Field.ControllerIntPending = (*(PULONG)&registerSet->WorkingRegisters.IntLocator) ? 1:0;
  229. configSpace->Pending.Field.ControllerSERRPending = (*(PULONG)&registerSet->WorkingRegisters.SERRLocator) ? 1:0;
  230. if (configSpace->DwordSelect < SHPC_NUM_REGISTERS) {
  231. DbgPrintEx(DPFLTR_HPS_ID,
  232. DPFLTR_INFO_LEVEL,
  233. "HPS-Getting Register %d\n",
  234. configSpace->DwordSelect
  235. );
  236. configSpace->Data = registerSet->AsULONGs[configSpace->DwordSelect];
  237. DbgPrintEx(DPFLTR_HPS_ID,
  238. DPFLTR_INFO_LEVEL,
  239. "HPS-Value: 0x%x\n",
  240. configSpace->Data
  241. );
  242. } else {
  243. //
  244. // Illegal register write
  245. //
  246. configSpace->Data = 0x12345678;
  247. }
  248. DeviceExtension->InterfaceWrapper.PciSetBusData(DeviceExtension->InterfaceWrapper.PciContext,
  249. PCI_WHICHSPACE_CONFIG,
  250. configSpace,
  251. DeviceExtension->ConfigOffset,
  252. sizeof(SHPC_CONFIG_SPACE)
  253. );
  254. } else {
  255. RtlCopyMemory((PUCHAR)DeviceExtension->HBRB + DeviceExtension->HBRBRegisterSetOffset,
  256. &DeviceExtension->RegisterSet,
  257. sizeof(SHPC_REGISTER_SET)
  258. );
  259. }
  260. }
  261. VOID
  262. HpsWriteConfig(
  263. IN PHPS_DEVICE_EXTENSION DeviceExtension,
  264. IN PVOID Buffer,
  265. IN ULONG Offset,
  266. IN ULONG Length
  267. )
  268. /*++
  269. Routine Description:
  270. This routine performs a write to the config space of the SHPC.
  271. Arguments:
  272. DeviceExtension - this device's device extension
  273. Buffer - a buffer to write the data from
  274. Offset - the offset in bytes into config space
  275. Length - the length in bytes into config space to be written
  276. Return Value:
  277. The number of bytes written
  278. --*/
  279. {
  280. ULONG internalOffset;
  281. ULONG regOffset, regLength;
  282. ULONG registerNum;
  283. ULONG i;
  284. UCHAR busNumberBuffer;
  285. ULONG bytesRead;
  286. SHPC_CONFIG_SPACE configWriteMask;
  287. NTSTATUS status;
  288. KIRQL irql;
  289. internalOffset = Offset - (DeviceExtension->ConfigOffset);
  290. HpsLockRegisterSet(DeviceExtension,
  291. &irql
  292. );
  293. //
  294. // This check should have already been done when we verified that this was an access
  295. // to the SHPC
  296. //
  297. ASSERT((internalOffset + Length)<= sizeof(SHPC_CONFIG_SPACE));
  298. DbgPrintEx(DPFLTR_HPS_ID,
  299. DPFLTR_INFO_LEVEL,
  300. "HPS-Internal Config Write at offset 0x%x for length 0x%x\n",
  301. internalOffset,
  302. Length
  303. );
  304. //
  305. // now overwrite the current config space, taking into account which bits were
  306. // written and the access mask for the config space
  307. //
  308. HpsWriteWithMask((PUCHAR)&DeviceExtension->ConfigSpace + internalOffset,
  309. ConfigWriteMask + internalOffset,
  310. (PUCHAR)Buffer,
  311. Length
  312. );
  313. if (IS_SUBSET(internalOffset,
  314. Length,
  315. FIELD_OFFSET(SHPC_CONFIG_SPACE,Data),
  316. sizeof(DeviceExtension->ConfigSpace.Data)
  317. )) {
  318. //
  319. // We've written the data register. Update the register set.
  320. //
  321. registerNum = DeviceExtension->ConfigSpace.DwordSelect;
  322. ASSERT(registerNum < SHPC_NUM_REGISTERS);
  323. DbgPrintEx(DPFLTR_HPS_ID,
  324. DPFLTR_INFO_LEVEL,
  325. "HPS-Writing Register %d\n",
  326. registerNum
  327. );
  328. if (registerNum < SHPC_NUM_REGISTERS) {
  329. //
  330. // Perform the register specific write
  331. //
  332. regOffset = (internalOffset > FIELD_OFFSET(SHPC_CONFIG_SPACE,Data))
  333. ? (internalOffset - FIELD_OFFSET(SHPC_CONFIG_SPACE,Data))
  334. : 0;
  335. regLength = (internalOffset+Length)-(regOffset+FIELD_OFFSET(SHPC_CONFIG_SPACE,Data));
  336. RegisterWriteCommands[registerNum](DeviceExtension,
  337. registerNum,
  338. &DeviceExtension->ConfigSpace.Data,
  339. HPS_ULONG_WRITE_MASK(regOffset,regLength)
  340. );
  341. }
  342. }
  343. //
  344. // Make sure the config space representation reflects what just happened to
  345. // the register set.
  346. //
  347. HpsResync(DeviceExtension);
  348. HpsUnlockRegisterSet(DeviceExtension,
  349. irql
  350. );
  351. return;
  352. }
  353. NTSTATUS
  354. HpsGetCapabilityOffset(
  355. IN PHPS_DEVICE_EXTENSION Extension,
  356. IN UCHAR CapabilityID,
  357. OUT PUCHAR Offset
  358. )
  359. /*++
  360. Routine Description:
  361. This routine searches through the config space of this device for a
  362. PCI capability on the list that matches the specified CapabilityID.
  363. Arguments:
  364. Extension - The device extension for the device. This allows us access
  365. to config space.
  366. CapabilityID - The capability identifier to search for.
  367. Offset - a pointer to a UCHAR which will contain the offset into config
  368. space of the matching capability.
  369. Return Value:
  370. STATUS_SUCCESS if the capability is found.
  371. STATUS_UNSUCCESSFUL otherwise.
  372. --*/
  373. {
  374. PHPS_INTERFACE_WRAPPER interfaceWrapper = &Extension->InterfaceWrapper;
  375. UCHAR statusReg, currentPtr;
  376. PCI_CAPABILITIES_HEADER capHeader;
  377. ASSERT(interfaceWrapper->PciContext != NULL);
  378. //
  379. // read the status register to see if we have a capabilities pointer
  380. //
  381. interfaceWrapper->PciGetBusData(interfaceWrapper->PciContext,
  382. PCI_WHICHSPACE_CONFIG,
  383. &statusReg,
  384. FIELD_OFFSET(PCI_COMMON_CONFIG,Status),
  385. sizeof(UCHAR));
  386. //
  387. // Capability exists bit is in the PCI status register
  388. //
  389. if (statusReg & PCI_STATUS_CAPABILITIES_LIST) {
  390. //
  391. // we have a capabilities pointer. go get the capabilities
  392. //
  393. interfaceWrapper->PciGetBusData(interfaceWrapper->PciContext,
  394. PCI_WHICHSPACE_CONFIG,
  395. &currentPtr,
  396. FIELD_OFFSET(PCI_COMMON_CONFIG,u.type0.CapabilitiesPtr),
  397. sizeof(UCHAR));
  398. //
  399. // now walk through the list looking for given capability ID
  400. // Loop until the next capability ptr is 0.
  401. //
  402. while (currentPtr != 0) {
  403. //
  404. // This gets us a capability pointer.
  405. //
  406. interfaceWrapper->PciGetBusData(interfaceWrapper->PciContext,
  407. PCI_WHICHSPACE_CONFIG,
  408. &capHeader,
  409. currentPtr,
  410. sizeof(PCI_CAPABILITIES_HEADER));
  411. if (capHeader.CapabilityID == CapabilityID) {
  412. *Offset = currentPtr;
  413. return STATUS_SUCCESS;
  414. } else {
  415. currentPtr = capHeader.Next;
  416. }
  417. }
  418. }
  419. return STATUS_UNSUCCESSFUL;
  420. }
  421. NTSTATUS
  422. HpsWriteWithMask(
  423. OUT PVOID Destination,
  424. IN PVOID BitMask,
  425. IN PVOID Source,
  426. IN ULONG Length
  427. )
  428. /*++
  429. Routine Description:
  430. This routine overwrites the Destination parameter with Source for
  431. Length bytes, but only the bits that are specified in the BitMask
  432. Destination, Source and BitMask are all aligned.
  433. Arguments:
  434. Destination - The destination of the write
  435. BitMask - A bitmask that indicates which bits of source to overwrite
  436. into Destination
  437. Source - Pointer to a buffer that will overwrite Destination
  438. Length - the number of bytes to write into Destination
  439. Return Value
  440. NT status code
  441. --*/
  442. {
  443. PUCHAR bitMask = (PUCHAR) BitMask;
  444. PUCHAR source = (PUCHAR) Source;
  445. PUCHAR destination = (PUCHAR) Destination;
  446. ULONG i;
  447. UCHAR temp;
  448. for (i=0; i < Length; i++){
  449. temp = source[i] & bitMask[i];
  450. destination[i] &= ~bitMask[i];
  451. destination[i] |= temp;
  452. }
  453. return STATUS_SUCCESS;
  454. }
  455. VOID
  456. HpsGetBridgeInfo(
  457. IN PHPS_DEVICE_EXTENSION Extension,
  458. OUT PHPTEST_BRIDGE_INFO BridgeInfo
  459. )
  460. /*++
  461. Routine Description:
  462. This routine fills in a HPTEST_BRIDGE_INFO structure with the
  463. bus/dev/func of this device.
  464. Arguments:
  465. Extension - the device extension associated with this device.
  466. BridgeInfo - a pointer to the HPTEST_BRIDGE_INFO structure to be
  467. filled in.
  468. Return Value:
  469. VOID
  470. --*/
  471. {
  472. UCHAR busNumber;
  473. UCHAR devSel;
  474. Extension->InterfaceWrapper.PciGetBusData(Extension->InterfaceWrapper.PciContext,
  475. PCI_WHICHSPACE_CONFIG,
  476. &busNumber,
  477. FIELD_OFFSET(PCI_COMMON_CONFIG,u.type1.PrimaryBus),
  478. sizeof(UCHAR)
  479. );
  480. BridgeInfo->PrimaryBus = busNumber;
  481. Extension->InterfaceWrapper.PciGetBusData(Extension->InterfaceWrapper.PciContext,
  482. PCI_WHICHSPACE_CONFIG,
  483. &busNumber,
  484. FIELD_OFFSET(PCI_COMMON_CONFIG,u.type1.SecondaryBus),
  485. sizeof(UCHAR)
  486. );
  487. BridgeInfo->SecondaryBus = busNumber;
  488. //
  489. // TODO: do this for real.
  490. //
  491. BridgeInfo->DeviceSelect = 2;
  492. BridgeInfo->FunctionNumber = 0;
  493. return;
  494. }
  495. VOID
  496. HpsLockRegisterSet(
  497. IN PHPS_DEVICE_EXTENSION Extension,
  498. OUT PKIRQL OldIrql
  499. )
  500. {
  501. KeRaiseIrql(HIGH_LEVEL,
  502. OldIrql
  503. );
  504. KeAcquireSpinLockAtDpcLevel(&Extension->RegisterLock);
  505. }
  506. VOID
  507. HpsUnlockRegisterSet(
  508. IN PHPS_DEVICE_EXTENSION Extension,
  509. IN KIRQL NewIrql
  510. )
  511. {
  512. KeReleaseSpinLockFromDpcLevel(&Extension->RegisterLock);
  513. KeLowerIrql(NewIrql);
  514. }