28.6 PCI Configuration Header 64-bit BAR

Another source of alignment faults is when 64-bit BAR values are accessed in a PCI configuration header. A PCI configuration header has room for up to six 32-bit BAR values or three 64-bit BAR values. A PCI configuration header may also contain a mix of both 32-bit BAR values and 64-bit BAR values. All 32-bit BAR values are guaranteed to be on a 32-bit boundary. However, 64-bit BAR values may be on a 32-bit boundary or a 64-bit boundary. As a result, every time a 64-bit BAR value is accessed, it must be assumed to be on a 32-bit boundary in order to guarantee that an alignment fault is not generated.

The following two methods can be used to prevent an alignment fault when a 64-bit BAR value is extracted from a PCI configuration header:

  • Use ReadUnaligned64() to read the BAR contents

  • Use CopyMem() to transfer the BAR contents into a 64-bit aligned location.

  • Collect the two 32-bit values that compose the 64-bit BAR, and combine them into a 64-bit value.

The example below shows the incorrect method of extracting a 64-bit BAR from a PCI configuration header, and then shows three correct methods.

Example 249-Accessing a 64-bit BAR in a PCI configuration header
#include <Uefi.h>
#include <IndustryStandard/Pci.h>
#include <Library/BaseMemoryLib.h>
#include <Library/BaseLib.h>

UINT64
EFIAPI
Get64BitBarValue (
   PCI_TYPE00  *PciConfigurationHeader,
   UINTN       BarOffset
  )

{
  UINT64  *BarPointer64;
  UINT32  *BarPointer32;
  UINT64  BarValue;

  BarPointer64 = (UINT64 *)((UINT8 *)PciConfigurationHeader + BarOffset);
  BarPointer32 = (UINT32 *)((UINT8 *)PciConfigurationHeader + BarOffset);

  //
  // Wrong. May cause an alignment fault.
  //
  BarValue = *BarPointer64;

  //
  // Correct. Guaranteed not to generate an alignment fault.
  //
  BarValue = ReadUnaligned64 (BarPointer64);

  //
  // Correct. Guaranteed not to generate an alignment fault.
  //
  CopyMem (&BarValue, BarPointer64, sizeof (UINT64));

  //
  // Correct. Guaranteed not to generate an alignment fault.
  //
  BarValue = (UINT64)(*BarPointer32 | LShiftU64 (*(BarPointer32 + 1), 32));

  return BarValue;
}