1616
1717/* GLOBALS ********************************************************************/
1818
19- PUCHAR PciArbiterNames [] =
19+ PCHAR PciArbiterNames [] =
2020{
2121 "I/O Port" ,
2222 "Memory" ,
@@ -107,6 +107,22 @@ PciArbBuildAndCommitFromRequirements(
107107 if (!TargetArb ) continue ;
108108 AInst = & TargetArb -> CommonInstance ;
109109
110+ /*
111+ * Make sure the arbiter we looked up actually arbitrates this resource
112+ * type. If the secondary-extension list is mis-wired (e.g. the memory
113+ * slot resolving to the bus-number arbiter), feeding it the wrong
114+ * descriptor type would make PackResource fail and the arbiter library
115+ * assert. Skip rather than crash; the kernel root arbiters still
116+ * perform the real assignment.
117+ */
118+ if (AInst -> ResourceType != Type )
119+ {
120+ DPRINT1 ("PCI: %s arbiter has mismatched ResourceType %u (expected %u), skipping\n" ,
121+ (Type == CmResourceTypePort ) ? "I/O" : "Memory" ,
122+ AInst -> ResourceType , Type );
123+ continue ;
124+ }
125+
110126 /* Count how many alternative lists provide a descriptor of same type at this index */
111127 for (iAlt = 0 ; iAlt < AltCount ; iAlt ++ )
112128 {
@@ -162,6 +178,25 @@ PciArbBuildAndCommitFromRequirements(
162178 ArbEntry -> BusNumber = ReqList -> BusNumber ;
163179 ArbEntry -> Result = ArbiterResultUndefined ;
164180
181+ /*
182+ * The arbiter library packs the granted resource into Entry->Assignment
183+ * (via PackResource) but does not allocate that buffer itself - the
184+ * caller must provide it. Without this, PackResource receives a NULL
185+ * descriptor, returns STATUS_INVALID_PARAMETER, and ArbAllocateEntry
186+ * asserts.
187+ */
188+ ArbEntry -> Assignment = ExAllocatePoolWithTag (PagedPool ,
189+ sizeof (CM_PARTIAL_RESOURCE_DESCRIPTOR ),
190+ PCI_POOL_TAG );
191+ if (!ArbEntry -> Assignment )
192+ {
193+ RemoveEntryList (& ArbEntry -> ListEntry );
194+ ExFreePoolWithTag (ArbEntry , PCI_POOL_TAG );
195+ ExFreePoolWithTag (AltBuffer , PCI_POOL_TAG );
196+ continue ;
197+ }
198+ RtlZeroMemory (ArbEntry -> Assignment , sizeof (CM_PARTIAL_RESOURCE_DESCRIPTOR ));
199+
165200 if (AInst -> TestAllocation )
166201 {
167202 NTSTATUS St = AInst -> TestAllocation (AInst , & ArbHead );
@@ -178,6 +213,7 @@ PciArbBuildAndCommitFromRequirements(
178213
179214 /* Free temp structures; arbiter copied selected ranges internally */
180215 RemoveEntryList (& ArbEntry -> ListEntry );
216+ ExFreePoolWithTag (ArbEntry -> Assignment , PCI_POOL_TAG );
181217 ExFreePoolWithTag (ArbEntry , PCI_POOL_TAG );
182218 ExFreePoolWithTag (AltBuffer , PCI_POOL_TAG );
183219 }
@@ -231,7 +267,10 @@ PciInitializeArbiters(IN PPCI_FDO_EXTENSION FdoExtension)
231267 PPCI_INTERFACE CurrentInterface , * Interfaces ;
232268 PPCI_PDO_EXTENSION PdoExtension ;
233269 PPCI_ARBITER_INSTANCE ArbiterInterface ;
234- NTSTATUS Status ;
270+ /* Default to success: a subtractive-decode bridge (or a bus with no
271+ matching arbiter interfaces) creates no arbiters and skips every loop
272+ iteration, leaving Status otherwise unassigned. */
273+ NTSTATUS Status = STATUS_SUCCESS ;
235274 PCI_SIGNATURE ArbiterType ;
236275 ASSERT_FDO (FdoExtension );
237276
@@ -319,6 +358,82 @@ PciInitializeArbiters(IN PPCI_FDO_EXTENSION FdoExtension)
319358 return Status ;
320359}
321360
361+ /*
362+ * A single decode window [Base, End] of a PCI-PCI bridge, used to confine the
363+ * bridge's per-bus arbiters to the aperture (sub-arbitration).
364+ */
365+ typedef struct _PCI_ARB_WINDOW
366+ {
367+ ULONGLONG Base ;
368+ ULONGLONG End ;
369+ } PCI_ARB_WINDOW ;
370+
371+ /* Sort up to a handful of windows ascending by base (simple, n is tiny) */
372+ static
373+ VOID
374+ PciSortArbWindows (IN OUT PCI_ARB_WINDOW * Windows , IN ULONG Count )
375+ {
376+ ULONG i , j ;
377+ for (i = 0 ; (i + 1 ) < Count ; i ++ )
378+ {
379+ for (j = 0 ; (j + 1 ) < (Count - i ); j ++ )
380+ {
381+ if (Windows [j ].Base > Windows [j + 1 ].Base )
382+ {
383+ PCI_ARB_WINDOW Tmp = Windows [j ];
384+ Windows [j ] = Windows [j + 1 ];
385+ Windows [j + 1 ] = Tmp ;
386+ }
387+ }
388+ }
389+ }
390+
391+ /*
392+ * Reserve everything OUTSIDE the given (sorted, ascending) decode windows in a
393+ * bridge's per-bus arbiter, so child devices can only be allocated within the
394+ * bridge aperture. Reserving the complement (rather than the windows) keeps the
395+ * in-window child addresses free, so BIOS-assigned children are unaffected.
396+ */
397+ static
398+ VOID
399+ PciSeedBridgeArbiterComplement (IN PARBITER_INSTANCE Arb ,
400+ IN PCI_ARB_WINDOW * Windows ,
401+ IN ULONG Count ,
402+ IN ULONGLONG SpaceMax )
403+ {
404+ ULONGLONG Cursor = 0 ;
405+ ULONG i ;
406+
407+ if (!Arb || !Arb -> Allocation || (Count == 0 )) return ;
408+
409+ for (i = 0 ; i < Count ; i ++ )
410+ {
411+ ULONGLONG Base = Windows [i ].Base ;
412+ ULONGLONG End = Windows [i ].End ;
413+
414+ /* Ignore windows that fall outside the space this arbiter manages */
415+ if (Base > SpaceMax ) break ;
416+
417+ /* Reserve the gap below this window */
418+ if (Base > Cursor )
419+ {
420+ (VOID )RtlAddRange (Arb -> Allocation , Cursor , Base - 1 , 0 ,
421+ RTL_RANGE_LIST_ADD_IF_CONFLICT , NULL , NULL );
422+ }
423+
424+ /* The window itself stays free; advance past it (handles overlap) */
425+ if (End >= SpaceMax ) return ;
426+ if ((End + 1 ) > Cursor ) Cursor = End + 1 ;
427+ }
428+
429+ /* Reserve everything above the last window */
430+ if (Cursor <= SpaceMax )
431+ {
432+ (VOID )RtlAddRange (Arb -> Allocation , Cursor , SpaceMax , 0 ,
433+ RTL_RANGE_LIST_ADD_IF_CONFLICT , NULL , NULL );
434+ }
435+ }
436+
322437NTSTATUS
323438NTAPI
324439PciInitializeArbiterRanges (IN PPCI_FDO_EXTENSION DeviceExtension ,
@@ -328,8 +443,9 @@ PciInitializeArbiterRanges(IN PPCI_FDO_EXTENSION DeviceExtension,
328443 //CM_RESOURCE_TYPE DesiredType;
329444 PVOID Instance ;
330445 PCI_SIGNATURE ArbiterType ;
331-
332- UNREFERENCED_PARAMETER (Resources );
446+ /* Bridge decode windows gathered from the assigned (boot) resources */
447+ PCI_ARB_WINDOW IoWin [4 ], MemWin [4 ];
448+ ULONG IoWinCount = 0 , MemWinCount = 0 ;
333449
334450 /* If this is the root and we have boot resources not yet parsed, do a simple parse now.
335451 Later these will be used to add fixed allocations into the arbiter once implemented. */
@@ -403,6 +519,38 @@ PciInitializeArbiterRanges(IN PPCI_FDO_EXTENSION DeviceExtension,
403519 DPRINT1 ("PCI Skipping arbiter initialization for subtractive bridge FDOX %p\n" , DeviceExtension );
404520 return STATUS_SUCCESS ;
405521 }
522+
523+ /* Gather the bridge's decode window(s) from the assigned resources so the
524+ per-bus arbiters below can be confined to the aperture. The assigned
525+ resource list contains the bridge's I/O and memory (and prefetch
526+ memory) windows as Port/Memory partial descriptors. */
527+ if ((Resources ) && (Resources -> Count ))
528+ {
529+ PCM_PARTIAL_RESOURCE_LIST PartialList = & Resources -> List [0 ].PartialResourceList ;
530+ PCM_PARTIAL_RESOURCE_DESCRIPTOR Desc = PartialList -> PartialDescriptors ;
531+ ULONG k ;
532+
533+ for (k = 0 ; k < PartialList -> Count ; k ++ , Desc ++ )
534+ {
535+ if ((Desc -> Type == CmResourceTypePort ) && (Desc -> u .Port .Length ) &&
536+ (IoWinCount < RTL_NUMBER_OF (IoWin )))
537+ {
538+ IoWin [IoWinCount ].Base = (ULONGLONG )Desc -> u .Port .Start .QuadPart ;
539+ IoWin [IoWinCount ].End = IoWin [IoWinCount ].Base + Desc -> u .Port .Length - 1 ;
540+ IoWinCount ++ ;
541+ }
542+ else if ((Desc -> Type == CmResourceTypeMemory ) && (Desc -> u .Memory .Length ) &&
543+ (MemWinCount < RTL_NUMBER_OF (MemWin )))
544+ {
545+ MemWin [MemWinCount ].Base = (ULONGLONG )Desc -> u .Memory .Start .QuadPart ;
546+ MemWin [MemWinCount ].End = MemWin [MemWinCount ].Base + Desc -> u .Memory .Length - 1 ;
547+ MemWinCount ++ ;
548+ }
549+ }
550+
551+ PciSortArbWindows (IoWin , IoWinCount );
552+ PciSortArbWindows (MemWin , MemWinCount );
553+ }
406554 }
407555
408556 /* Loop all arbiters */
@@ -464,6 +612,26 @@ PciInitializeArbiterRanges(IN PPCI_FDO_EXTENSION DeviceExtension,
464612 if (DeviceExtension -> BootRangeSeedMask == 0x3 )
465613 DeviceExtension -> BootRangesSeeded = TRUE; /* both types seeded */
466614 }
615+ else if (!PCI_IS_ROOT_FDO (DeviceExtension ))
616+ {
617+ /* Non-root (PCI-PCI bridge) FDO: confine this arbiter to the
618+ bridge's decode window(s) by reserving everything outside
619+ them. I/O and memory are 32-bit on these bridges. */
620+ PARBITER_INSTANCE Arb = & ((PPCI_ARBITER_INSTANCE )Instance )-> CommonInstance ;
621+
622+ if ((ArbiterType == PciArb_Io ) && (IoWinCount ))
623+ {
624+ PciSeedBridgeArbiterComplement (Arb , IoWin , IoWinCount , 0xFFFFFFFFULL );
625+ DPRINT1 ("PCI: bridge FDO %p I/O arbiter confined to %lu window(s)\n" ,
626+ DeviceExtension , IoWinCount );
627+ }
628+ else if ((ArbiterType == PciArb_Memory ) && (MemWinCount ))
629+ {
630+ PciSeedBridgeArbiterComplement (Arb , MemWin , MemWinCount , 0xFFFFFFFFULL );
631+ DPRINT1 ("PCI: bridge FDO %p Memory arbiter confined to %lu window(s)\n" ,
632+ DeviceExtension , MemWinCount );
633+ }
634+ }
467635 }
468636 else
469637 {
0 commit comments