PCIe에 대해서 조금 더 자세히 공부해 보고자 한다.
BDF에 대해서 간략히 설명하겠다.
Bus -> 도시
Device -> 건물
Function -> 층
으로 간단하게 이해하면 된다.
Bus는 총 256개, 버스당 최대 Device 32개, 디바이스당 최대 8개의 Function을 가질 수 있다.
Function마다 Configuration Space가 존재한다. 따라서 BDF를 통해서 찾아갈 수 있다.
예시 사진은 아래와 같다.

Bus -> Device -> Function 순으로 나열되어 있는 것을 확인할 수 있다.
PCIe 하드웨어의 Config Space를 확인하기 위해서 설치했다. 위 홈페이지에서 Download하면 된다.

위 사진처럼 구성이 된다고 한다. RWEverything을 통해서 확인해보면 좋을 것 같다.
아래 사진은 RWEverything으로 읽은 실제 Google Coral TPU PCIE의 Configuration Space이다.

개발한 npu driver에서는 BAR2를 Device Context에 저장해놓고 사용한다. 실제 PA 값을 비교해 보기 위해서 WinDbg를 활용해 보겠다.
case CmResourceTypeMemory:
// save BAR2
if (descriptor->u.Memory.Length == 0x100000) {
DbgPrint(" (Memory) Start=0x%llx Length=0x%lx\n",
descriptor->u.Memory.Start.QuadPart,
descriptor->u.Memory.Length);
deviceContext->Bar2Length = descriptor->u.Memory.Length;
deviceContext->Bar2BaseAddress = MmMapIoSpace(
descriptor->u.Memory.Start,
descriptor->u.Memory.Length,
MmNonCached
);
}
Length를 통해서 BAR2를 얻어온다. 이때, 찍히는 로그를 확인해 보겠다.

위처럼 0xa0000000으로 확인이 되었다. RWEverything으로 확인을 할 수 있다.

BAR 레지스터의 bit4~31이 Base Address 필드이며, 0xA00000C에서 하위 4비트를 마스킹 하면 실제 물리 주소 0xA0000000을 얻을 수 있다. B0 = 0 이므로 Memory Space, 즉 MMIO로 접근하는 영역임을 알 수 있다.
추가로 PCIe의 Configuration Space에서 Vendor ID, Device ID 등 여러 정보가 있고 필요하면 직접 확인할 수 있을 것 같다.
정확히 모르는 부분을 계속 공부해야겠다.