2 Hardware info library with types and accessors to parse information about
5 Copyright 2021 - 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
6 SPDX-License-Identifier: BSD-2-Clause-Patent
10 #include <Library/DebugLib.h>
12 #include "HardwareInfoPciHostBridgeLib.h"
14 #define IS_RANGE_INVALID(Start, Size, MaxValue) (Start >= MaxValue || Size == 0)
17 Calculate the last (inclusive) address of a range.
19 @param[in] Start First address of the range
20 @param[in] Size Size of the range
21 @return Last address of the range
31 if (IS_RANGE_INVALID (Start
, Size
, MaxValue
)) {
35 return Start
+ Size
- 1;
39 Internal helper to update LastAddress if the Limit address
40 of the Mem aperture is higher than the provided value.
42 @param[in] Mem Pointer to aperture whose limit is
43 to be compared against accumulative
45 @param[out] LastAddress Pointer to accumulative last address
46 to be updated if Limit is higher
50 UpdateLastAddressIfHigher (
51 IN PCI_ROOT_BRIDGE_APERTURE
*Mem
,
52 OUT UINT64
*LastAddress
55 if (Mem
->Limit
> *LastAddress
) {
56 *LastAddress
= Mem
->Limit
;
61 HardwareInfoPciHostBridgeLastMmioAddress (
62 IN CONST HOST_BRIDGE_INFO
*HostBridge
,
65 OUT UINT64
*LastMmioAddress
69 PCI_ROOT_BRIDGE_APERTURE Mem
;
70 PCI_ROOT_BRIDGE_APERTURE MemAbove4G
;
71 PCI_ROOT_BRIDGE_APERTURE PMem
;
72 PCI_ROOT_BRIDGE_APERTURE PMemAbove4G
;
74 if (LastMmioAddress
== NULL
) {
75 return EFI_INVALID_PARAMETER
;
79 // Set the output to the lowest possible value so that if some step fails
80 // the overall outcome reflects no information found
84 Status
= HardwareInfoPciHostBridgeGetApertures (
96 // Forward error to caller but ignore warnings given that, very likely,
97 // the host bridge will have a PIO aperture we are explicitly
98 // ignoring here since we care only about MMIO resources.
100 if (EFI_ERROR (Status
)) {
105 UpdateLastAddressIfHigher (&MemAbove4G
, LastMmioAddress
);
106 UpdateLastAddressIfHigher (&PMemAbove4G
, LastMmioAddress
);
108 UpdateLastAddressIfHigher (&Mem
, LastMmioAddress
);
109 UpdateLastAddressIfHigher (&PMem
, LastMmioAddress
);
116 Set the boundaries of an aperture to invalid values having
117 size zero and start MaxValue (yields Start > Limit which
118 depicts an invalid range)
120 @param[in] MaxValue Max value of the aperture's range (depends
122 @param[out] Aperture Aperture object to invalidate
126 InvalidateRootBridgeAperture (
127 OUT PCI_ROOT_BRIDGE_APERTURE
*Aperture
130 if (Aperture
== NULL
) {
134 Aperture
->Base
= MAX_UINT64
;
139 Fill a PCI ROOT BRIDGE APERTURE with the proper values calculated
140 from the provided start and size.
142 @param[in] Start Start address of the aperture
143 @param[in] Size Size, in bytes, of the aperture
144 @param[in] MaxValue Max value a valid address could take and which
145 represents an invalid start address.
146 @param[out] Aperture Pointer to the aperture to be filled
148 @retval EFI_SUCCESS Aperture was filled successfully
149 @retval EFI_INVALID_PARAMETER Range depicted by Start and Size is
150 valid but ignored because aperture
152 @retval EFI_WARN_BUFFER_TOO_SMALL Aperture pointer is invalid but the
153 range also is so no harm.
157 FillHostBridgeAperture (
161 OUT PCI_ROOT_BRIDGE_APERTURE
*Aperture
166 End
= GetRangeEnd (Start
, Size
, MaxValue
);
168 if (Aperture
== NULL
) {
169 if (!IS_RANGE_INVALID (Start
, Size
, MaxValue
)) {
171 // Report an error to the caller since the range specified in
172 // the host bridge's resources is non-empty but the provided
173 // aperture pointer is null, thus the valid range is ignored.
175 return EFI_INVALID_PARAMETER
;
178 return EFI_WARN_BUFFER_TOO_SMALL
;
181 if (IS_RANGE_INVALID (Start
, Size
, MaxValue
)) {
183 // Fill Aperture with invalid range values to signal the
184 // absence of an address space (empty range)
186 InvalidateRootBridgeAperture (Aperture
);
188 Aperture
->Base
= Start
;
189 Aperture
->Limit
= End
;
196 Merge 2 ranges (normal and prefetchable) into a single aperture
197 comprehending the addresses encompassed by both of them. If both
198 ranges are not empty they must be contiguous for correctness.
200 @param[in] Start Range start address
201 @param[in] Size Range size in bytes
202 @param[in] PStart Prefetchable range start address
203 @param[in] PSize Prefetchable range size in bytes
204 @param[in] MaxValue Max value a valid address could take and which
205 represents an invalid start address.
206 @param[out] Aperture Pointer to the aperture to be filled
208 @retval EFI_SUCCESS Aperture was filled successfully
209 @retval EFI_INVALID_PARAMETER Either range depicted by Start, Size
210 or PStart, PSize or both are valid
211 but ignored because aperture pointer
213 @retval EFI_WARN_BUFFER_TOO_SMALL Aperture pointer is invalid but both
214 ranges are too so no harm.
218 MergeHostBridgeApertures (
224 OUT PCI_ROOT_BRIDGE_APERTURE
*Aperture
229 if (Aperture
== NULL
) {
230 if (!IS_RANGE_INVALID (Start
, Size
, MaxValue
) ||
231 !IS_RANGE_INVALID (PStart
, PSize
, MaxValue
))
234 // Report an error to the caller since the range specified in
235 // the host bridge's resources is non-empty but the provided
236 // aperture pointer is null, thus the valid range is ignored.
238 return EFI_INVALID_PARAMETER
;
241 return EFI_WARN_BUFFER_TOO_SMALL
;
245 // Start from an empty range (Limit < Base)
247 InvalidateRootBridgeAperture (Aperture
);
249 if (!IS_RANGE_INVALID (Start
, Size
, MaxValue
)) {
250 Aperture
->Base
= Start
;
251 Aperture
->Limit
= Start
+ Size
- 1;
254 if (!IS_RANGE_INVALID (PStart
, PSize
, MaxValue
)) {
255 PEnd
= PStart
+ PSize
- 1;
257 if (PStart
< Aperture
->Base
) {
258 Aperture
->Base
= PStart
;
261 if (PEnd
> Aperture
->Limit
) {
262 Aperture
->Limit
= PEnd
;
270 HardwareInfoPciHostBridgeGetBusNrRange (
271 IN CONST HOST_BRIDGE_INFO
*HostBridge
,
273 OUT UINTN
*BusNrStart
,
277 if ((HostBridge
== NULL
) || (DataSize
== 0) ||
278 (BusNrStart
== NULL
) || (BusNrLast
== NULL
))
280 return EFI_INVALID_PARAMETER
;
284 // For now only version 0 is supported
286 if (HostBridge
->Version
!= 0) {
287 return EFI_INCOMPATIBLE_VERSION
;
290 *BusNrStart
= HostBridge
->BusNrStart
;
291 *BusNrLast
= HostBridge
->BusNrLast
;
297 HardwareInfoPciHostBridgeGetApertures (
298 IN CONST HOST_BRIDGE_INFO
*HostBridge
,
300 OUT PCI_ROOT_BRIDGE_APERTURE
*Io
,
301 OUT PCI_ROOT_BRIDGE_APERTURE
*Mem
,
302 OUT PCI_ROOT_BRIDGE_APERTURE
*MemAbove4G
,
303 OUT PCI_ROOT_BRIDGE_APERTURE
*PMem
,
304 OUT PCI_ROOT_BRIDGE_APERTURE
*PMemAbove4G
,
305 OUT PCI_ROOT_BRIDGE_APERTURE
*PcieConfig
312 if ((HostBridge
== NULL
) || (DataSize
== 0)) {
313 return EFI_INVALID_PARAMETER
;
317 // For now only version 0 is supported
319 if (HostBridge
->Version
!= 0) {
320 return EFI_INCOMPATIBLE_VERSION
;
323 Status
= FillHostBridgeAperture (
329 StickyError
|= EFI_ERROR (Status
);
331 Status
= FillHostBridgeAperture (
332 HostBridge
->PcieConfigStart
,
333 HostBridge
->PcieConfigSize
,
337 StickyError
|= EFI_ERROR (Status
);
339 if (HostBridge
->Flags
.Bits
.CombineMemPMem
) {
340 Status
= MergeHostBridgeApertures (
341 HostBridge
->MemStart
,
343 HostBridge
->PMemStart
,
344 HostBridge
->PMemSize
,
348 StickyError
|= EFI_ERROR (Status
);
350 Status
= MergeHostBridgeApertures (
351 HostBridge
->MemAbove4GStart
,
352 HostBridge
->MemAbove4GSize
,
353 HostBridge
->PMemAbove4GStart
,
354 HostBridge
->PMemAbove4GSize
,
358 StickyError
|= EFI_ERROR (Status
);
361 // Invalidate unused apertures
363 InvalidateRootBridgeAperture (PMem
);
364 InvalidateRootBridgeAperture (PMemAbove4G
);
366 Status
= FillHostBridgeAperture (
367 HostBridge
->MemStart
,
372 StickyError
|= EFI_ERROR (Status
);
374 Status
= FillHostBridgeAperture (
375 HostBridge
->PMemStart
,
376 HostBridge
->PMemSize
,
380 StickyError
|= EFI_ERROR (Status
);
382 Status
= FillHostBridgeAperture (
383 HostBridge
->MemAbove4GStart
,
384 HostBridge
->MemAbove4GSize
,
388 StickyError
|= EFI_ERROR (Status
);
390 Status
= FillHostBridgeAperture (
391 HostBridge
->PMemAbove4GStart
,
392 HostBridge
->PMemAbove4GSize
,
396 StickyError
|= EFI_ERROR (Status
);
401 // If any function returned an error it is due to a valid range
402 // specified in the host bridge that was ignored due to a NULL
403 // pointer. Translate it to a warning to allow for calling with
404 // only a subset of the apertures.
406 return EFI_WARN_STALE_DATA
;
413 HardwareInfoPciHostBridgeGetFlags (
414 IN CONST HOST_BRIDGE_INFO
*HostBridge
,
416 OUT UINT64
*Attributes OPTIONAL
,
417 OUT BOOLEAN
*DmaAbove4G OPTIONAL
,
418 OUT BOOLEAN
*NoExtendedConfigSpace OPTIONAL
,
419 OUT BOOLEAN
*CombineMemPMem OPTIONAL
422 if ((HostBridge
== NULL
) || (DataSize
== 0)) {
423 return EFI_INVALID_PARAMETER
;
427 // For now only version 0 is supported
429 if (HostBridge
->Version
!= 0) {
430 return EFI_INCOMPATIBLE_VERSION
;
434 *Attributes
= HostBridge
->Attributes
;
438 *DmaAbove4G
= !!HostBridge
->Flags
.Bits
.DmaAbove4G
;
441 if (NoExtendedConfigSpace
) {
442 *NoExtendedConfigSpace
= !!HostBridge
->Flags
.Bits
.NoExtendedConfigSpace
;
445 if (CombineMemPMem
) {
446 *CombineMemPMem
= !!HostBridge
->Flags
.Bits
.CombineMemPMem
;
453 HardwareInfoPciHostBridgeGet (
454 IN CONST HOST_BRIDGE_INFO
*HostBridge
,
456 OUT UINTN
*BusNrStart
,
457 OUT UINTN
*BusNrLast
,
458 OUT UINT64
*Attributes OPTIONAL
,
459 OUT BOOLEAN
*DmaAbove4G OPTIONAL
,
460 OUT BOOLEAN
*NoExtendedConfigSpace OPTIONAL
,
461 OUT BOOLEAN
*CombineMemPMem OPTIONAL
,
462 OUT PCI_ROOT_BRIDGE_APERTURE
*Io OPTIONAL
,
463 OUT PCI_ROOT_BRIDGE_APERTURE
*Mem OPTIONAL
,
464 OUT PCI_ROOT_BRIDGE_APERTURE
*MemAbove4G OPTIONAL
,
465 OUT PCI_ROOT_BRIDGE_APERTURE
*PMem OPTIONAL
,
466 OUT PCI_ROOT_BRIDGE_APERTURE
*PMemAbove4G OPTIONAL
,
467 OUT PCI_ROOT_BRIDGE_APERTURE
*PcieConfig OPTIONAL
472 Status
= HardwareInfoPciHostBridgeGetBusNrRange (
479 if (EFI_ERROR (Status
)) {
483 Status
= HardwareInfoPciHostBridgeGetFlags (
488 NoExtendedConfigSpace
,
492 if (EFI_ERROR (Status
)) {
496 Status
= HardwareInfoPciHostBridgeGetApertures (