What is the Base Address Register (BAR) in PCIe?

tollin jose picture tollin jose · May 12, 2015 · Viewed 56.3k times · Source

After going through some basics documents what I understood is, Base Address Register is Address space which can be accessed by PCIe IP. PCIe IP can either transmit data in Base Address Register or it can write received data on to it.

Am I right? Or missing anything?

Answer

Linux kernel point of view

A good way to learn something is to interact with it, so let's use the Linux kernel for that.

Here is a minimal PCI example on a QEMU emulated device: https://github.com/cirosantilli/linux-kernel-module-cheat/blob/366b1c1af269f56d6a7e6464f2862ba2bc368062/kernel_module/pci.c

The first 64 bytes of the PCI configuration are standardized as:

enter image description here

Image from LDD3.

So we can see that there are 6 BARs. The wiki page then shows the contents of each BAR:

enter image description here

The region width requires a magic write however: How is a PCI / PCIe BAR size determined?

This memory is setup by the PCI device, and gives information to the kernel.

Each BAR corresponds to an address range that serves as a separate communication channel to the PCI device.

The length of each region is defined by the hardware, and communicated to software via the configuration registers.

Each region also has further hardware defined properties besides length, notably the memory type:

  • IORESOURCE_IO: must be accessed with inX and outX
  • IORESOURCE_MEM: must be accessed with ioreadX and iowriteX

Several Linux kernel PCI functions take the BAR as a parameter to identify which communication channel is to be used, e.g.:

mmio = pci_iomap(pdev, BAR, pci_resource_len(pdev, BAR));
pci_resource_flags(dev, BAR);
pci_resource_start(pdev, BAR);
pci_resource_end(pdev, BAR);

By looking into the QEMU device source code, we see that QEMU devices register those regions with:

memory_region_init_io(&edu->mmio, OBJECT(edu), &edu_mmio_ops, edu,
                "edu-mmio", 1 << 20);
pci_register_bar(pdev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &edu->mmio);

and it is clear that properties of the BAR are hardware defined, e.g. the BAR number 0, has type memory PCI_BASE_ADDRESS_SPACE_MEMORY, and the memory region is 1MiB long 1 << 20.

See also: http://wiki.osdev.org/PCI#Base_Address_Registers of course.