Base Address Registers

A Base Address Register allows a PCI device to request that some on-device memory be mapped into the host address space.

The way that a device communicates the size of the requested region to the host is a bit of a funky dance. First of, the regions exposable through the BARs must be power of twos (i.e. 4 KiB, 2 MiB, 16 MiB) and the address that they are mapped at must be aligned according to the size (i.e. a 4 KiB area must be mapped at an address with the lower 12 bits cleared to zero and a 16 MiB area must be mapped at an address with the lower 24 bits cleared).

Why this alignment requirement? Well, that's the gist of the funky chicken dance.

The device guarantees that when reading from the register, the lower bits that must be cleared according to the alignement requirement, will be cleared to zero. Thus, at bootup, the host will write all ones (i.e. 0xffffffff for a 32 bit BAR) to the register and read back the result. Some of the ones will cleared to zero, say 0xfffff00f (note, the 4 least significant bits are reserved and contains information about the BAR, so ignore that and just tilt your head until the value reads 0xfffff000).

So, given 0xfffff000, what size is the device requesting? Well, since we know that the address at which the region is mapped must be aligned according to its size, the number of trailing zeroed bits tells us the size. The host inverts the value to get 0xfff and then adds 1, resulting in 0x1000 or in other words, the device is requesting that the host maps a 4096 byte region.

The final part of the dance is for the host to reserve space for that region in its address space and write the address of that region back to the register, aligned of course.