Skip to content

Commit 132a5f9

Browse files
authored
Merge pull request #87 from jstarks/fix_pci
MsvmPkg: Support multiple PCIe host bridges per segment
2 parents 029a6be + 541bb5f commit 132a5f9

2 files changed

Lines changed: 80 additions & 23 deletions

File tree

MsvmPkg/Library/PciHostBridgeLib/PciHostBridgeLib.c

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -144,26 +144,20 @@ PciHostBridgeGetRootBridges (
144144
UINT32 j;
145145

146146
//
147-
// Find the matching MCFG entry to get the ECAM base address
148-
// and validate that the aperture bus range fits within it.
147+
// Find the matching MCFG entry to get the ECAM base address.
148+
// Match by segment number AND bus range containment — multiple MCFG
149+
// entries per segment are allowed (PCI Firmware Spec §4.1.2) with
150+
// disjoint bus ranges.
149151
//
150152
BOOLEAN McfgFound = FALSE;
151153
UINT64 EcamBase = 0;
152154
for (j = 0; j < McfgEntryCount; j++) {
153-
if (McfgEntries[j].PciSegmentGroupNumber == Segment) {
155+
if (McfgEntries[j].PciSegmentGroupNumber == Segment &&
156+
StartBus >= McfgEntries[j].StartBusNumber &&
157+
EndBus <= McfgEntries[j].EndBusNumber) {
154158
McfgFound = TRUE;
155159
EcamBase = McfgEntries[j].BaseAddress
156160
+ (UINT64)McfgEntries[j].StartBusNumber * PCIE_ECAM_BYTES_PER_BUS;
157-
158-
if (StartBus < McfgEntries[j].StartBusNumber ||
159-
EndBus > McfgEntries[j].EndBusNumber) {
160-
DEBUG ((DEBUG_ERROR,
161-
"PCIe: Aperture bus range %u..%u exceeds MCFG range %u..%u for segment %u\n",
162-
StartBus, EndBus,
163-
McfgEntries[j].StartBusNumber, McfgEntries[j].EndBusNumber,
164-
Segment));
165-
goto Cleanup;
166-
}
167161
break;
168162
}
169163
}

MsvmPkg/Library/PciSegmentInfoLib/PciSegmentInfoLib.c

Lines changed: 73 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -67,29 +67,92 @@ GetPciSegmentInfo (
6767
return NULL;
6868
}
6969

70-
DEBUG ((DEBUG_INFO, "PCIe: PciSegmentInfoLib: %u segments from MCFG\n", EntryCount));
70+
DEBUG ((DEBUG_INFO, "PCIe: PciSegmentInfoLib: %u MCFG entries\n", EntryCount));
7171

72+
Entries = (MCFG_ALLOCATION_ENTRY *)(McfgHdr + 1);
73+
74+
//
75+
// Coalesce MCFG entries that share a PCI Segment Group Number into a single
76+
// PCI_SEGMENT_INFO. The upstream consumer (PciSegmentLibCommon.c) expects
77+
// exactly one entry per segment and matches by segment number alone, and
78+
// PCI_SEGMENT_INFO can hold only one ECAM base per segment.
79+
//
80+
// The PCI Firmware Spec (§4.1.1, §4.1.2 Table 4-3) DOES permit multiple
81+
// same-segment host bridges with distinct, discontinuous ECAM base
82+
// addresses. We do not support that here: this platform's VMM always lays
83+
// same-segment host bridges over a single contiguous ECAM, so every
84+
// same-segment entry carries the same bus-0-relative BaseAddress. We assert
85+
// that invariant and fail loudly if it is ever violated, rather than
86+
// silently dropping a distinct base we cannot represent.
87+
//
88+
// Allocate up to EntryCount slots (upper bound on unique segments).
89+
//
7290
mSegmentInfo = AllocateZeroPool (EntryCount * sizeof (PCI_SEGMENT_INFO));
7391
if (mSegmentInfo == NULL) {
7492
DEBUG ((DEBUG_ERROR, "PCIe: PciSegmentInfoLib: Failed to allocate segment info\n"));
7593
*Count = 0;
7694
return NULL;
7795
}
7896

79-
Entries = (MCFG_ALLOCATION_ENTRY *)(McfgHdr + 1);
80-
97+
//
98+
// Build coalesced entries in a single pass.
99+
//
100+
UINT32 SegIdx = 0;
81101
for (i = 0; i < EntryCount; i++) {
82-
mSegmentInfo[i].SegmentNumber = Entries[i].PciSegmentGroupNumber;
83-
mSegmentInfo[i].BaseAddress = Entries[i].BaseAddress;
84-
mSegmentInfo[i].StartBusNumber = Entries[i].StartBusNumber;
85-
mSegmentInfo[i].EndBusNumber = Entries[i].EndBusNumber;
102+
UINT32 k;
103+
BOOLEAN Found = FALSE;
104+
105+
//
106+
// Check if we already have an entry for this segment.
107+
//
108+
for (k = 0; k < SegIdx; k++) {
109+
if (mSegmentInfo[k].SegmentNumber == Entries[i].PciSegmentGroupNumber) {
110+
Found = TRUE;
111+
//
112+
// Validate that the BaseAddress matches the existing entry.
113+
//
114+
if (mSegmentInfo[k].BaseAddress != Entries[i].BaseAddress) {
115+
DEBUG ((DEBUG_ERROR,
116+
"PCIe: PciSegmentInfoLib: Segment %u has conflicting ECAM bases: "
117+
"%016lx vs %016lx\n",
118+
Entries[i].PciSegmentGroupNumber,
119+
mSegmentInfo[k].BaseAddress,
120+
Entries[i].BaseAddress));
121+
ASSERT (FALSE);
122+
FreePool (mSegmentInfo);
123+
mSegmentInfo = NULL;
124+
*Count = 0;
125+
return NULL;
126+
}
127+
//
128+
// Widen the bus range to encompass this entry.
129+
//
130+
if (Entries[i].StartBusNumber < mSegmentInfo[k].StartBusNumber) {
131+
mSegmentInfo[k].StartBusNumber = Entries[i].StartBusNumber;
132+
}
133+
if (Entries[i].EndBusNumber > mSegmentInfo[k].EndBusNumber) {
134+
mSegmentInfo[k].EndBusNumber = Entries[i].EndBusNumber;
135+
}
136+
break;
137+
}
138+
}
139+
140+
if (!Found) {
141+
mSegmentInfo[SegIdx].SegmentNumber = Entries[i].PciSegmentGroupNumber;
142+
mSegmentInfo[SegIdx].BaseAddress = Entries[i].BaseAddress;
143+
mSegmentInfo[SegIdx].StartBusNumber = Entries[i].StartBusNumber;
144+
mSegmentInfo[SegIdx].EndBusNumber = Entries[i].EndBusNumber;
145+
SegIdx++;
146+
}
147+
}
86148

149+
for (i = 0; i < SegIdx; i++) {
87150
DEBUG ((DEBUG_INFO, "PCIe: SegmentInfo[%u]: Seg=%u ECAM=%016lx Bus=%u..%u\n",
88-
i, Entries[i].PciSegmentGroupNumber, Entries[i].BaseAddress,
89-
Entries[i].StartBusNumber, Entries[i].EndBusNumber));
151+
i, mSegmentInfo[i].SegmentNumber, mSegmentInfo[i].BaseAddress,
152+
mSegmentInfo[i].StartBusNumber, mSegmentInfo[i].EndBusNumber));
90153
}
91154

92-
mSegmentCount = EntryCount;
155+
mSegmentCount = SegIdx;
93156
*Count = mSegmentCount;
94157
return mSegmentInfo;
95158
}

0 commit comments

Comments
 (0)