@@ -169,25 +169,103 @@ IoDisconnectInterrupt(PKINTERRUPT InterruptObject)
169169 ExFreePoolWithTag (IoInterrupt , TAG_IO_INTERRUPT );
170170}
171171
172+ static PCM_PARTIAL_RESOURCE_DESCRIPTOR
173+ IopFindMessageInterruptDescriptor (
174+ _In_ PDEVICE_OBJECT PhysicalDeviceObject );
175+ static PCM_PARTIAL_RESOURCE_DESCRIPTOR
176+ IopFindMessageInterruptDescriptorEx (
177+ _In_ PDEVICE_OBJECT PhysicalDeviceObject ,
178+ _In_ BOOLEAN Translated );
179+
172180NTSTATUS
173181IopConnectInterruptExFullySpecific (
174182 _Inout_ PIO_CONNECT_INTERRUPT_PARAMETERS Parameters )
175183{
176184 NTSTATUS Status ;
185+ ULONG Vector = Parameters -> FullySpecified .Vector ;
186+ KIRQL Irql = Parameters -> FullySpecified .Irql ;
187+ KIRQL SynchronizeIrql = Parameters -> FullySpecified .SynchronizeIrql ;
188+ KINTERRUPT_MODE Mode = Parameters -> FullySpecified .InterruptMode ;
189+ KAFFINITY Affinity = Parameters -> FullySpecified .ProcessorEnableMask ;
190+ PCM_PARTIAL_RESOURCE_DESCRIPTOR RawDesc ;
177191
178192 PAGED_CODE ();
179193
180- /* Fallback to standard IoConnectInterrupt */
194+ /*
195+ * If the device was granted a message-signalled interrupt (MSI/MSI-X), the
196+ * caller passes the *translated* system vector, but the LAPIC actually
197+ * delivers the *raw* message vector that the bus driver programmed into the
198+ * device's MSI/MSI-X capability. IoConnectInterrupt() arms the IDT at the
199+ * vector it is given, so without remapping the IDT entry would never match
200+ * the delivered vector and the ISR would never run. Remap to the raw vector
201+ * (with its message IRQL and edge-triggered mode) before connecting.
202+ *
203+ * Win8's IoConnectInterruptEx resolves the same thing via the device's
204+ * interrupt connection data; we derive it from the raw/translated resource
205+ * lists the PnP manager assigned.
206+ */
207+ RawDesc = IopFindMessageInterruptDescriptor (Parameters -> FullySpecified .PhysicalDeviceObject );
208+ if (RawDesc != NULL )
209+ {
210+ ULONG RawBase = RawDesc -> u .MessageInterrupt .Raw .Vector ;
211+ ULONG Count = RawDesc -> u .MessageInterrupt .Raw .MessageCount ;
212+ BOOLEAN Remap = FALSE;
213+
214+ if (Count == 0 )
215+ Count = 1 ;
216+
217+ if (Count == 1 )
218+ {
219+ /*
220+ * Single message: the device delivers exactly one vector - the raw
221+ * message vector the bus driver programmed into the MSI/MSI-X
222+ * capability. The caller's translated vector belongs to a different
223+ * HAL domain and would arm the wrong IDT entry, so use the raw one.
224+ */
225+ Vector = RawBase ;
226+ Remap = TRUE;
227+ }
228+ else
229+ {
230+ /*
231+ * Multiple messages: map the caller's translated vector to the raw
232+ * message vector by its offset within the translated block.
233+ */
234+ PCM_PARTIAL_RESOURCE_DESCRIPTOR TransDesc =
235+ IopFindMessageInterruptDescriptorEx (Parameters -> FullySpecified .PhysicalDeviceObject , TRUE);
236+ if (TransDesc != NULL )
237+ {
238+ ULONG TransBase = TransDesc -> u .MessageInterrupt .Translated .Vector ;
239+ if (Vector >= TransBase && Vector < TransBase + Count )
240+ {
241+ Vector = RawBase + (Vector - TransBase );
242+ Remap = TRUE;
243+ }
244+ }
245+ }
246+
247+ if (Remap )
248+ {
249+ Irql = HalGetMessageVectorIrql ((UCHAR )Vector );
250+ Mode = Latched ; /* MSI/MSI-X are edge-triggered */
251+ Affinity = RawDesc -> u .MessageInterrupt .Raw .Affinity ;
252+ }
253+ }
254+
255+ /* KeInitializeInterrupt requires SynchronizeIrql >= the interrupt IRQL */
256+ if (SynchronizeIrql < Irql )
257+ SynchronizeIrql = Irql ;
258+
181259 Status = IoConnectInterrupt (Parameters -> FullySpecified .InterruptObject ,
182260 Parameters -> FullySpecified .ServiceRoutine ,
183261 Parameters -> FullySpecified .ServiceContext ,
184262 Parameters -> FullySpecified .SpinLock ,
185- Parameters -> FullySpecified . Vector ,
186- Parameters -> FullySpecified . Irql ,
187- Parameters -> FullySpecified . SynchronizeIrql ,
188- Parameters -> FullySpecified . InterruptMode ,
263+ Vector ,
264+ Irql ,
265+ SynchronizeIrql ,
266+ Mode ,
189267 Parameters -> FullySpecified .ShareVector ,
190- Parameters -> FullySpecified . ProcessorEnableMask ,
268+ Affinity ,
191269 Parameters -> FullySpecified .FloatingSave );
192270 if (!NT_SUCCESS (Status ))
193271 DPRINT1 ("IopConnectInterruptExFullySpecific() failed: 0x%lx\n" , Status );
@@ -249,20 +327,27 @@ IopFreeMsiInterrupts(
249327 */
250328static
251329PCM_PARTIAL_RESOURCE_DESCRIPTOR
252- IopFindMessageInterruptDescriptor (
253- _In_ PDEVICE_OBJECT PhysicalDeviceObject )
330+ IopFindMessageInterruptDescriptorEx (
331+ _In_ PDEVICE_OBJECT PhysicalDeviceObject ,
332+ _In_ BOOLEAN Translated )
254333{
255334 PDEVICE_NODE DeviceNode ;
256335 PCM_RESOURCE_LIST ResourceList ;
257336 PCM_FULL_RESOURCE_DESCRIPTOR FullDescriptor ;
258337 ULONG i , j ;
259338
260339 DeviceNode = IopGetDeviceNode (PhysicalDeviceObject );
261- if (!DeviceNode || !DeviceNode -> ResourceList )
340+ if (!DeviceNode )
341+ return NULL ;
342+
343+ /*
344+ * The raw list carries the MessageInterrupt.Raw form (base vector + count);
345+ * the translated list carries MessageInterrupt.Translated (system vector).
346+ */
347+ ResourceList = Translated ? DeviceNode -> ResourceListTranslated : DeviceNode -> ResourceList ;
348+ if (!ResourceList )
262349 return NULL ;
263350
264- /* The raw list carries the MessageInterrupt.Raw form (base vector + count) */
265- ResourceList = DeviceNode -> ResourceList ;
266351 FullDescriptor = & ResourceList -> List [0 ];
267352
268353 for (i = 0 ; i < ResourceList -> Count ; i ++ )
@@ -286,6 +371,14 @@ IopFindMessageInterruptDescriptor(
286371 return NULL ;
287372}
288373
374+ static
375+ PCM_PARTIAL_RESOURCE_DESCRIPTOR
376+ IopFindMessageInterruptDescriptor (
377+ _In_ PDEVICE_OBJECT PhysicalDeviceObject )
378+ {
379+ return IopFindMessageInterruptDescriptorEx (PhysicalDeviceObject , FALSE);
380+ }
381+
289382NTSTATUS
290383IopConnectInterruptExMessageBased (
291384 _Inout_ PIO_CONNECT_INTERRUPT_PARAMETERS Parameters )
0 commit comments