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.

1004 lines
28 KiB

  1. /*++
  2. Copyright (c) 1999-2000 Microsoft Corporation
  3. Module Name:
  4. utils.c
  5. Abstract:
  6. This module contains misc functions that were stolen from PCI.SYS' Utils.c/Debug.c
  7. Author:
  8. Brandon Allsop (BranodnA) Feb, 2000
  9. Revision History:
  10. --*/
  11. #include "pch.h"
  12. #define IOSTART L"IoRangeStart"
  13. #define IOLENGTH L"IoRangeLength"
  14. #define MEMSTART L"MemRangeStart"
  15. #define MEMLENGTH L"MemRangeLength"
  16. #ifdef ALLOC_PRAGMA
  17. #ifdef SIMULATE_MSI
  18. #pragma alloc_text (PAGE, SoftPCISimulateMSI)
  19. #endif
  20. #endif
  21. BOOLEAN
  22. SoftPCIOpenKey(
  23. IN PWSTR KeyName,
  24. IN HANDLE ParentHandle,
  25. OUT PHANDLE Handle,
  26. OUT PNTSTATUS Status
  27. )
  28. /*++
  29. Description:
  30. Open a registry key.
  31. Arguments:
  32. KeyName Name of the key to be opened.
  33. ParentHandle Pointer to the parent handle (OPTIONAL)
  34. Handle Pointer to a handle to recieve the opened key.
  35. Return Value:
  36. TRUE is key successfully opened, FALSE otherwise.
  37. --*/
  38. {
  39. UNICODE_STRING nameString;
  40. OBJECT_ATTRIBUTES nameAttributes;
  41. NTSTATUS localStatus;
  42. PAGED_CODE();
  43. RtlInitUnicodeString(&nameString, KeyName);
  44. InitializeObjectAttributes(&nameAttributes,
  45. &nameString,
  46. OBJ_CASE_INSENSITIVE,
  47. ParentHandle,
  48. (PSECURITY_DESCRIPTOR)NULL
  49. );
  50. localStatus = ZwOpenKey(Handle,
  51. KEY_READ,
  52. &nameAttributes
  53. );
  54. if (Status != NULL) {
  55. //
  56. // Caller wants underlying status.
  57. //
  58. *Status = localStatus;
  59. }
  60. //
  61. // Return status converted to a boolean, TRUE if
  62. // successful.
  63. //
  64. return (BOOLEAN)(NT_SUCCESS(localStatus));
  65. }
  66. NTSTATUS
  67. SoftPCIGetRegistryValue(
  68. IN PWSTR ValueName,
  69. IN PWSTR KeyName,
  70. IN HANDLE ParentHandle,
  71. OUT PVOID *Buffer,
  72. OUT ULONG *Length
  73. )
  74. {
  75. NTSTATUS status;
  76. HANDLE keyHandle;
  77. ULONG neededLength;
  78. ULONG actualLength;
  79. UNICODE_STRING unicodeValueName;
  80. if (!SoftPCIOpenKey(KeyName, ParentHandle, &keyHandle, &status)) {
  81. return status;
  82. }
  83. unicodeValueName.Buffer = ValueName;
  84. unicodeValueName.MaximumLength = (USHORT)(wcslen(ValueName) + 1) * sizeof(WCHAR);
  85. unicodeValueName.Length = unicodeValueName.MaximumLength - sizeof(WCHAR);
  86. //
  87. // Find out how much memory we need for this.
  88. //
  89. status = ZwQueryValueKey(
  90. keyHandle,
  91. &unicodeValueName,
  92. KeyValuePartialInformation,
  93. NULL,
  94. 0,
  95. &neededLength
  96. );
  97. if (status == STATUS_BUFFER_TOO_SMALL) {
  98. PKEY_VALUE_PARTIAL_INFORMATION info;
  99. ASSERT(neededLength != 0);
  100. //
  101. // Get memory to return the data in. Note this includes
  102. // a header that we really don't want.
  103. //
  104. info = ExAllocatePool(
  105. PagedPool,
  106. neededLength);
  107. if (info == NULL) {
  108. ZwClose(keyHandle);
  109. return STATUS_INSUFFICIENT_RESOURCES;
  110. }
  111. //
  112. // Get the data.
  113. //
  114. status = ZwQueryValueKey(
  115. keyHandle,
  116. &unicodeValueName,
  117. KeyValuePartialInformation,
  118. info,
  119. neededLength,
  120. &actualLength
  121. );
  122. if (!NT_SUCCESS(status)) {
  123. ASSERT(NT_SUCCESS(status));
  124. ExFreePool(info);
  125. ZwClose(keyHandle);
  126. return status;
  127. }
  128. ASSERT(neededLength == actualLength);
  129. //
  130. // Subtract out the header size and get memory for just
  131. // the data we want.
  132. //
  133. neededLength -= FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data);
  134. *Buffer = ExAllocatePool(
  135. PagedPool,
  136. neededLength
  137. );
  138. if (*Buffer == NULL) {
  139. ExFreePool(info);
  140. ZwClose(keyHandle);
  141. return STATUS_INSUFFICIENT_RESOURCES;
  142. }
  143. //
  144. // Copy data sans header.
  145. //
  146. RtlCopyMemory(*Buffer, info->Data, neededLength);
  147. ExFreePool(info);
  148. if (Length) {
  149. *Length = neededLength;
  150. }
  151. } else {
  152. if (NT_SUCCESS(status)) {
  153. //
  154. // We don't want to report success when this happens.
  155. //
  156. status = STATUS_UNSUCCESSFUL;
  157. }
  158. }
  159. ZwClose(keyHandle);
  160. return status;
  161. }
  162. VOID
  163. SoftPCIInsertEntryAtTail(
  164. IN PSINGLE_LIST_ENTRY Entry
  165. )
  166. {
  167. PSINGLE_LIST_ENTRY previousEntry;
  168. //
  169. // Find the end of the list.
  170. //
  171. previousEntry = &SoftPciTree.RootPciBusDevExtList;
  172. while (previousEntry->Next) {
  173. previousEntry = previousEntry->Next;
  174. }
  175. //
  176. // Append the entry.
  177. //
  178. previousEntry->Next = Entry;
  179. }
  180. NTSTATUS
  181. SoftPCIProcessRootBus(
  182. IN PCM_RESOURCE_LIST ResList
  183. )
  184. {
  185. ULONG i,j;
  186. NTSTATUS status = STATUS_UNSUCCESSFUL;
  187. HANDLE spciHandle;
  188. WCHAR rootSlot[sizeof("XXXX")];
  189. PSOFTPCI_DEVICE rootBus = NULL;
  190. PCM_FULL_RESOURCE_DESCRIPTOR fullList;
  191. PCM_PARTIAL_RESOURCE_LIST partialList;
  192. PCM_PARTIAL_RESOURCE_DESCRIPTOR partialDesc;
  193. for (i = 0; i < ResList->Count; i++){
  194. fullList = ResList->List;
  195. partialList = &fullList->PartialResourceList;
  196. for (j = 0; j < partialList->Count; j++){
  197. partialDesc = &partialList->PartialDescriptors[j];
  198. switch (partialDesc->Type){
  199. case CmResourceTypeBusNumber:
  200. ASSERT(partialDesc->u.BusNumber.Start < 0xff);
  201. SoftPCIDbgPrint(
  202. SOFTPCI_INFO,
  203. "SOFTPCI: FilterStartDevice - Found root bus 0x%x-0x%x\n",
  204. partialDesc->u.BusNumber.Start,
  205. (partialDesc->u.BusNumber.Start + (partialDesc->u.BusNumber.Length-1))
  206. );
  207. //
  208. // Allocate pool for a place holder device. We need this so we can
  209. // place devices on any root bus desired.
  210. //
  211. rootBus = (PSOFTPCI_DEVICE) ExAllocatePool(NonPagedPool, sizeof(SOFTPCI_DEVICE));
  212. RtlZeroMemory(rootBus, sizeof(SOFTPCI_DEVICE));
  213. if (rootBus) {
  214. rootBus->Bus = (UCHAR)partialDesc->u.BusNumber.Start;
  215. rootBus->Config.PlaceHolder = TRUE;
  216. //
  217. // Pretend a little here...
  218. //
  219. rootBus->Config.Current.VendorID = 0xAAAA;
  220. rootBus->Config.Current.DeviceID = 0xBBBB;
  221. rootBus->Config.Current.HeaderType = 1;
  222. rootBus->Config.Current.u.type1.SecondaryBus = rootBus->Bus;
  223. rootBus->Config.Current.u.type1.SubordinateBus = (UCHAR)((partialDesc->u.BusNumber.Start +
  224. partialDesc->u.BusNumber.Length) - 1);
  225. //
  226. // Update our Slot information so we know which root this is when
  227. // we parse the tree via a path
  228. //
  229. rootBus->Slot.Device = 0xff;
  230. rootBus->Slot.Function = rootBus->Bus;
  231. status = SoftPCIAddNewDevice(rootBus);
  232. if (!NT_SUCCESS(status)){
  233. SoftPCIDbgPrint(
  234. SOFTPCI_ERROR,
  235. "SOFTPCI: FilterStartDevice - Failed add root node!\n"
  236. );
  237. ASSERT(NT_SUCCESS(status));
  238. }
  239. //
  240. // Device is now in our list, free this memory
  241. //
  242. ExFreePool(rootBus);
  243. if (!SoftPCIOpenKey(SOFTPCI_CONTROL, NULL, &spciHandle, &status)) {
  244. //
  245. // If we failed this then we probably havent ever run our cool user
  246. // mode app (SOFTPCI.EXE) to create any fake devices. Lets not fail
  247. // start
  248. //
  249. SoftPCIDbgPrint(
  250. SOFTPCI_ERROR,
  251. "SOFTPCI: FilterStartDevice - Failed to open SoftPCI registry key!! (%x)\n",
  252. status
  253. );
  254. status = STATUS_SUCCESS;
  255. }else{
  256. rootBus = SoftPCIFindDevice(
  257. (UCHAR)partialDesc->u.BusNumber.Start,
  258. (0xff00 + (UCHAR)partialDesc->u.BusNumber.Start),
  259. NULL,
  260. TRUE
  261. );
  262. ASSERT(rootBus != NULL);
  263. //
  264. // Now lets enumerate any children this root may have
  265. // in the registry
  266. //
  267. _snwprintf(rootSlot,
  268. (sizeof(rootSlot) / sizeof(rootSlot[0])),
  269. L"%04x",
  270. rootBus->Slot.AsUSHORT
  271. );
  272. SoftPCIEnumRegistryDevs(rootSlot, &spciHandle, rootBus);
  273. ZwClose(spciHandle);
  274. }
  275. }else{
  276. SoftPCIDbgPrint(
  277. SOFTPCI_ERROR,
  278. "SOFTPCI: FilterStartDevice - Failed to allocate memory for root node!\n"
  279. );
  280. status = STATUS_INSUFFICIENT_RESOURCES;
  281. }
  282. break;
  283. default:
  284. break;
  285. }
  286. }
  287. }
  288. return status;
  289. }
  290. NTSTATUS
  291. SoftPCIEnumRegistryDevs(
  292. IN PWSTR KeyName,
  293. IN PHANDLE ParentHandle,
  294. IN PSOFTPCI_DEVICE ParentDevice
  295. )
  296. /*++
  297. Routine Description:
  298. This routine searches the registry for SoftPCI devices. We start from
  299. \HLM\CCS\Control\SoftPCI and work our way through the devices. When we
  300. encounter a SoftPCI-PCI bridge device we will search for devices behind it
  301. recursively.
  302. Arguments:
  303. KeyName - Name of Key to search for devices.
  304. ParentHandle - Pointer to handle for KeyName.
  305. ParentDevice - Pointer to parent SoftPCI-PCI Bridge or RootBus
  306. Return Value:
  307. NTSTATUS.
  308. --*/
  309. {
  310. NTSTATUS status;
  311. HANDLE spciHandle;
  312. PSOFTPCI_DEVICE newDevice, currentChild;
  313. ULONG device, function, configLength;
  314. WCHAR buffer[sizeof(L"XXXX")];
  315. PSOFTPCI_CONFIG softConfig;
  316. //PPCI_COMMON_CONFIG commonConfig = NULL;
  317. PAGED_CODE();
  318. ASSERT(ParentDevice != NULL);
  319. if (!SoftPCIOpenKey(KeyName, *ParentHandle, &spciHandle, &status)) {
  320. return status;
  321. }
  322. //
  323. // Now that we have opened our key lets search for devices.
  324. //
  325. for (device=0; device < PCI_MAX_DEVICES; device++) {
  326. for (function=0; function < PCI_MAX_FUNCTION ; function++) {
  327. _snwprintf(
  328. buffer,
  329. (sizeof(buffer) / sizeof(buffer[0])),
  330. L"%02x%02x",
  331. device,
  332. function
  333. );
  334. status = SoftPCIGetRegistryValue(
  335. L"Config",
  336. buffer,
  337. spciHandle,
  338. &softConfig,
  339. &configLength
  340. );
  341. if (NT_SUCCESS(status)){
  342. SoftPCIDbgPrint(SOFTPCI_INFO,
  343. "SOFTPCI: EnumRegistryDevs found %ws in registry!\n",
  344. buffer);
  345. //
  346. // Lets allocate a new device
  347. //
  348. newDevice = ExAllocatePool(NonPagedPool, sizeof(SOFTPCI_DEVICE));
  349. if (!newDevice) {
  350. //
  351. // Better luck next time.
  352. //
  353. ZwClose(spciHandle);
  354. ExFreePool(softConfig);
  355. return STATUS_INSUFFICIENT_RESOURCES;
  356. }
  357. //
  358. // Until we determine its place in this world, zero everything out.
  359. //
  360. RtlZeroMemory(newDevice, sizeof(SOFTPCI_DEVICE));
  361. //
  362. // Copy the config from the registry to our new (NonPagedPool) device
  363. //
  364. RtlCopyMemory(&newDevice->Config, softConfig, configLength);
  365. //
  366. // Free the PagedPool
  367. //
  368. ExFreePool(softConfig);
  369. #if 0
  370. if (newDevice->Config.PlaceHolder) {
  371. commonConfig = &ParentDevice->Config.Current;
  372. //
  373. // We are on the bus our parent exposes.
  374. //
  375. newDevice->Bus = commonConfig->u.type1.SecondaryBus;
  376. }else{
  377. //
  378. // Let PCI sort it all out for us.
  379. //
  380. newDevice->Bus = 0;
  381. }
  382. #endif
  383. newDevice->Bus = ParentDevice->Config.Current.u.type1.SecondaryBus;
  384. newDevice->Slot.Device = (UCHAR) device;
  385. newDevice->Slot.Function = (UCHAR) function;
  386. //
  387. // Attach device to devicetree
  388. //
  389. currentChild = ParentDevice->Child;
  390. if (currentChild) {
  391. while (currentChild->Sibling) {
  392. currentChild=currentChild->Sibling;
  393. }
  394. currentChild->Sibling = newDevice;
  395. }else{
  396. ParentDevice->Child = newDevice;
  397. newDevice->Parent = ParentDevice;
  398. }
  399. SoftPciTree.DeviceCount++;
  400. if (IS_BRIDGE(newDevice)) {
  401. //
  402. // We found a SoftPCI-PCI bridge device. Guess we better
  403. // see if there are any devices "behind" it.
  404. //
  405. SoftPCIEnumRegistryDevs(buffer, &spciHandle, newDevice);
  406. }
  407. if (!PCI_MULTIFUNCTION_DEVICE(&newDevice->Config.Current)){
  408. //
  409. // This is not a multifunction device, skip the other functions.
  410. //
  411. break;
  412. }
  413. }else{
  414. if (function == 0) {
  415. //
  416. // No need to check the other functions of this one failed.
  417. //
  418. break;
  419. }
  420. }
  421. }
  422. }
  423. ZwClose(spciHandle);
  424. return status;
  425. }
  426. VOID
  427. SoftPCIEnumerateTree(
  428. VOID
  429. )
  430. {
  431. PSOFTPCI_DEVICE_EXTENSION deviceExtension;
  432. PSINGLE_LIST_ENTRY listEntry;
  433. listEntry = SoftPciTree.RootPciBusDevExtList.Next;
  434. while (listEntry) {
  435. deviceExtension = CONTAINING_RECORD(listEntry,
  436. SOFTPCI_DEVICE_EXTENSION,
  437. ListEntry);
  438. ASSERT(deviceExtension != NULL);
  439. IoInvalidateDeviceRelations(deviceExtension->PDO, BusRelations);
  440. listEntry = listEntry->Next;
  441. }
  442. }
  443. NTSTATUS
  444. SoftPCIQueryDeviceObjectType(
  445. IN PDEVICE_OBJECT DeviceObject,
  446. IN OUT PBOOLEAN IsFDO
  447. )
  448. /*++
  449. Routine Description:
  450. This routine sends a PCI_BUS_INTERFACE_STANDARD query down the stack. If we get one back
  451. then we are not an FDO. Since this routine is called from our AddDevice we have no worry
  452. of not sending this to the entire stack.
  453. Arguments:
  454. DeviceObject - Next Lower DeviceObject
  455. IsFDO - Set TRUE if we fail to get an interface.
  456. Return Value:
  457. NTSTATUS.
  458. --*/
  459. {
  460. NTSTATUS status;
  461. PPCI_BUS_INTERFACE_STANDARD interface;
  462. KEVENT irpCompleted;
  463. PIRP irp;
  464. PIO_STACK_LOCATION irpStack;
  465. IO_STATUS_BLOCK statusBlock;
  466. PAGED_CODE();
  467. SoftPCIDbgPrint(SOFTPCI_VERBOSE, "SOFTPCI: QueryDeviceObjectType ENTER\n");
  468. interface = ExAllocatePool(NonPagedPool,
  469. sizeof(PCI_BUS_INTERFACE_STANDARD));
  470. if (!interface) {
  471. return STATUS_INSUFFICIENT_RESOURCES;
  472. }
  473. //
  474. // Initialize our event
  475. //
  476. KeInitializeEvent(&irpCompleted, SynchronizationEvent, FALSE);
  477. //
  478. // Get an IRP
  479. //
  480. irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP,
  481. DeviceObject,
  482. NULL, // Buffer
  483. 0, // Length
  484. 0, // StartingOffset
  485. &irpCompleted,
  486. &statusBlock
  487. );
  488. if (!irp) {
  489. ExFreePool(interface);
  490. return STATUS_INSUFFICIENT_RESOURCES;
  491. }
  492. irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
  493. irp->IoStatus.Information = 0;
  494. //
  495. // Initialize the stack location
  496. //
  497. irpStack = IoGetNextIrpStackLocation(irp);
  498. ASSERT(irpStack->MajorFunction == IRP_MJ_PNP);
  499. irpStack->MinorFunction = IRP_MN_QUERY_INTERFACE;
  500. irpStack->Parameters.QueryInterface.InterfaceType = (PGUID) &GUID_PCI_BUS_INTERFACE_STANDARD;
  501. irpStack->Parameters.QueryInterface.Version = PCI_BUS_INTERFACE_STANDARD_VERSION;
  502. irpStack->Parameters.QueryInterface.Size = sizeof (PCI_BUS_INTERFACE_STANDARD);
  503. irpStack->Parameters.QueryInterface.Interface = (PINTERFACE) interface;
  504. irpStack->Parameters.QueryInterface.InterfaceSpecificData = NULL;
  505. //
  506. // Call the driver and wait for completion
  507. //
  508. status = IoCallDriver(DeviceObject, irp);
  509. if (status == STATUS_PENDING) {
  510. KeWaitForSingleObject(&irpCompleted, Executive, KernelMode, FALSE, NULL);
  511. status = statusBlock.Status;
  512. }
  513. if (NT_SUCCESS(status)) {
  514. //
  515. // We have and interface therefore we must load as a filter DO
  516. //
  517. *IsFDO = FALSE;
  518. SoftPCIDbgPrint(
  519. SOFTPCI_ADD_DEVICE,
  520. "SOFTPCI: QueryDeviceObjectType - found FilterDO\n"
  521. );
  522. }else if (status == STATUS_NOT_SUPPORTED) {
  523. //
  524. // We didnt get an interface therefore we must be an FDO
  525. //
  526. SoftPCIDbgPrint(
  527. SOFTPCI_ADD_DEVICE,
  528. "SOFTPCI: QueryDeviceObjectType - found FDO \n"
  529. );
  530. status = STATUS_SUCCESS;
  531. }
  532. //
  533. // Ok we're done with this stack
  534. //
  535. ExFreePool(interface);
  536. SoftPCIDbgPrint(
  537. SOFTPCI_VERBOSE,
  538. "SOFTPCI: QueryDeviceObjectType - EXIT\n"
  539. );
  540. return status;
  541. }
  542. BOOLEAN
  543. SoftPCIGetResourceValueFromRegistry(
  544. OUT PULONG MemRangeStart,
  545. OUT PULONG MemRangeLength,
  546. OUT PULONG IoRangeStart,
  547. OUT PULONG IoRangeLength
  548. )
  549. {
  550. ULONG keySize = 0;
  551. PULONG memRangeStart = NULL;
  552. PULONG memRangeLength = NULL;
  553. PULONG ioRangeStart = NULL;
  554. PULONG ioRangeLength = NULL;
  555. SoftPCIGetRegistryValue(MEMSTART,
  556. SOFTPCI_CONTROL,
  557. NULL,
  558. &memRangeStart,
  559. &keySize);
  560. if (memRangeStart) {
  561. *MemRangeStart = *memRangeStart;
  562. ExFreePool(memRangeStart);
  563. }
  564. SoftPCIGetRegistryValue(MEMLENGTH,
  565. SOFTPCI_CONTROL,
  566. NULL,
  567. &memRangeLength,
  568. &keySize);
  569. if (memRangeLength) {
  570. *MemRangeLength = *memRangeLength;
  571. ExFreePool(memRangeLength);
  572. }
  573. SoftPCIGetRegistryValue(IOSTART,
  574. SOFTPCI_CONTROL,
  575. NULL,
  576. &ioRangeStart,
  577. &keySize);
  578. if (ioRangeStart) {
  579. *IoRangeStart = *ioRangeStart;
  580. ExFreePool(ioRangeStart);
  581. }
  582. SoftPCIGetRegistryValue(IOLENGTH,
  583. SOFTPCI_CONTROL,
  584. NULL,
  585. &ioRangeLength,
  586. &keySize);
  587. if (ioRangeLength) {
  588. *IoRangeLength = *ioRangeLength;
  589. ExFreePool(ioRangeLength);
  590. }
  591. return TRUE;
  592. }
  593. #ifdef SIMULATE_MSI
  594. BOOLEAN
  595. SoftPCIMessageIsr(
  596. IN struct _KINTERRUPT *Interrupt,
  597. IN PVOID ServiceContext,
  598. IN ULONG MessageID
  599. )
  600. {
  601. UNREFERENCED_PARAMETER(Interrupt);
  602. UNREFERENCED_PARAMETER(ServiceContext);
  603. DbgPrint("SoftPCI: received interrupt message %x\n", MessageID);
  604. return TRUE;
  605. }
  606. VOID
  607. SoftPCISimulateMSI(
  608. IN PDEVICE_OBJECT DeviceObject,
  609. IN PVOID Context
  610. )
  611. {
  612. PSOFTPCI_DEVICE_EXTENSION deviceExtension;
  613. PCM_PARTIAL_RESOURCE_DESCRIPTOR tDesc, rDesc;
  614. ULONG buffSize, i;
  615. PIO_INTERRUPT_MESSAGE_INFO mInfo = NULL;
  616. BOOLEAN identityMappedMachine = TRUE;
  617. NTSTATUS status;
  618. LARGE_INTEGER waitLength;
  619. USHORT *vAddr;
  620. BOOLEAN msiEnabled = FALSE;
  621. PAGED_CODE();
  622. deviceExtension = DeviceObject->DeviceExtension;
  623. ASSERT(deviceExtension->RawResources);
  624. ASSERT(deviceExtension->TranslatedResources);
  625. //
  626. // First, see if any of the assigned resources were
  627. // for an MSI.
  628. //
  629. for (i = 0; i < deviceExtension->RawResources->List[0].PartialResourceList.Count; i++) {
  630. rDesc = &deviceExtension->RawResources->List[0].PartialResourceList.PartialDescriptors[i];
  631. tDesc = &deviceExtension->TranslatedResources->List[0].PartialResourceList.PartialDescriptors[i];
  632. ASSERT(rDesc->Type == tDesc->Type);
  633. switch (rDesc->Type) {
  634. case CmResourceTypePort:
  635. case CmResourceTypeMemory:
  636. DbgPrint("%s: %x-%x\n",
  637. rDesc->Type == CmResourceTypePort ? "Port" : "Memory",
  638. rDesc->u.Generic.Start.LowPart,
  639. rDesc->u.Generic.Start.LowPart + rDesc->u.Generic.Length - 1);
  640. if (rDesc->u.Generic.Start.QuadPart != tDesc->u.Generic.Start.QuadPart) {
  641. identityMappedMachine = FALSE;
  642. DbgPrint("%s: %x-%x - translated\n",
  643. tDesc->Type == CmResourceTypePort ? "Port" : "Memory",
  644. tDesc->u.Generic.Start.LowPart,
  645. tDesc->u.Generic.Start.LowPart + tDesc->u.Generic.Length - 1);
  646. }
  647. break;
  648. case CmResourceTypeInterrupt:
  649. DbgPrint("L:%x V:%x A:%p %s\n",
  650. rDesc->u.Interrupt.Level,
  651. rDesc->u.Interrupt.Vector,
  652. rDesc->u.Interrupt.Affinity,
  653. rDesc->Flags & CM_RESOURCE_INTERRUPT_MESSAGE ? "message signaled" : "");
  654. if (rDesc->Flags & CM_RESOURCE_INTERRUPT_MESSAGE) {
  655. DbgPrint("\tMessageCount: %x Payload: %04x TargetAddr: %p\n",
  656. rDesc->u.MessageInterrupt.Raw.MessageCount,
  657. rDesc->u.MessageInterrupt.Raw.DataPayload,
  658. rDesc->u.MessageInterrupt.Raw.MessageTargetAddress);
  659. msiEnabled = TRUE;
  660. }
  661. DbgPrint("L:%x V:%x A:%p %s\n",
  662. tDesc->u.Interrupt.Level,
  663. tDesc->u.Interrupt.Vector,
  664. tDesc->u.Interrupt.Affinity,
  665. tDesc->Flags & CM_RESOURCE_INTERRUPT_MESSAGE ? "message signaled" : "");
  666. if (tDesc->Flags & CM_RESOURCE_INTERRUPT_MESSAGE) {
  667. DbgPrint("\tIRQL:%x IDT:%x\n",
  668. tDesc->u.Interrupt.Level,
  669. tDesc->u.Interrupt.Vector);
  670. msiEnabled = TRUE;
  671. }
  672. break;
  673. default:
  674. DbgPrint("other\n");
  675. }
  676. }
  677. if (!msiEnabled) goto SoftPCISimulateMSIExit;
  678. //
  679. // Call IoConnectInterruptMessage to see what size buffer is necessary.
  680. //
  681. buffSize = 0;
  682. status = IoConnectInterruptMessage(NULL,
  683. &buffSize,
  684. deviceExtension->PDO,
  685. SoftPCIMessageIsr,
  686. deviceExtension,
  687. NULL,
  688. 0,
  689. FALSE,
  690. FALSE);
  691. ASSERT(!NT_SUCCESS(status));
  692. if (status != STATUS_BUFFER_TOO_SMALL) goto SoftPCISimulateMSIExit;
  693. ASSERT(buffSize >= sizeof(IO_INTERRUPT_MESSAGE_INFO));
  694. mInfo = (PIO_INTERRUPT_MESSAGE_INFO)ExAllocatePool(NonPagedPool,
  695. buffSize);
  696. if (!mInfo) goto SoftPCISimulateMSIExit;
  697. status = IoConnectInterruptMessage(mInfo,
  698. &buffSize,
  699. deviceExtension->PDO,
  700. SoftPCIMessageIsr,
  701. deviceExtension,
  702. NULL,
  703. 0,
  704. FALSE,
  705. FALSE);
  706. if (!NT_SUCCESS(status)) {
  707. ASSERT(!"Failed to connect the message handler.\n");
  708. goto SoftPCISimulateMSIExit;
  709. }
  710. //
  711. // Now simulate some interrupts.
  712. //
  713. if (!identityMappedMachine) goto SoftPCISimulateMSIExit;
  714. //
  715. // This machine's address-space resources are the same when raw and
  716. // translated, which probably means that the processor can generate
  717. // an MSI using the same write transaction that the device would
  718. // use, which is convenient when simulating.
  719. //
  720. waitLength.QuadPart = -20000; // 2 seconds, relative time
  721. while (TRUE) {
  722. //
  723. // Cycle through each of the messages, periodically triggering
  724. // them.
  725. //
  726. for (i = 0; i < mInfo->MessageCount; i++) {
  727. status = KeDelayExecutionThread(KernelMode,
  728. FALSE,
  729. &waitLength);
  730. ASSERT(NT_SUCCESS(status));
  731. //
  732. // Get a virtual address for the physical one listed
  733. // in the array of messages.
  734. //
  735. vAddr = MmMapIoSpace(mInfo->MessageInfo[i].MessageAddress,
  736. sizeof(ULONG),
  737. TRUE);
  738. WRITE_REGISTER_USHORT(vAddr, (USHORT)mInfo->MessageInfo[i].MessageData);
  739. MmUnmapIoSpace(vAddr, sizeof(ULONG));
  740. if (deviceExtension->StopMsiSimulation) goto SoftPCISimulateMSIExitDisconnectInterrupt;
  741. }
  742. }
  743. SoftPCISimulateMSIExitDisconnectInterrupt:
  744. IoDisconnectInterrupt(mInfo->InterruptObject);
  745. SoftPCISimulateMSIExit:
  746. if (mInfo) ExFreePool(mInfo);
  747. IoFreeWorkItem(Context);
  748. }
  749. #endif