If you read my previous articles you will learn that x86 processors are able to access memory and IO space. For memory space, you need to check processor EDS to get how many physical address space the processor supports. For example, 46 bits. the physical address space from 0x0 – 2^46.
For IO space, x64 processors are able to support 64K IO space. (i.e. from 0x0000 to 0xFFFF)
Back to how to read/write PCI configuration space in Legacy way. you can read this from PCI Spec. For easy to read, I just put it out here in my words.
If you read processor EDS or PCH EDS, you will find most of registers are list as PCI devices. These registers will mark as Bus:Device:Function:Offset. I will abbreviate to Bus:Dev:Fuc:Off.
Based on PCI spec, we will use IO access way to read/write PCI configuration space. For example, there is a register locate at. Bus 1, Dev 16, Fuc 7, Off 0xD0. Here are steps.
- We should translate Bus:Dev:Fuc:Off to a 32bit (1DW) address.
A DW address will like this: XXXX XXXX
I like to use X to represent a hexdecima number. it will be 0x0 to 0xF, and we can use 4 bits binary to represent. so total will be 8 x 4 = 32 bits.- The bit31 should be 1, and bit30 to bit24 will be reserved, so XXXX XXXX will be 0x80XX XXXX.
- Bit23 to Bit16 will be Bus number. You may still remember that Bus 1 is not 0x1, unless you checked CPUBUSNO registers. As usual, we will set BUS1 to 0xFF if you have only one processor in a system. We will talk about this topic in the feature. so 0x80XX XXXX will be 0x80FF XXXX after this step.
- Bit15 to Bit11 will be Device number and Bit10 to Bit8 will be Function number.
We get Device number 16, change to hexdecima will be 0x10
and change to binary will be 1 0000b
We get Function number 7, it is the same as hexdecima and the binary will be 111b
Combine 5bits device binary and 3bits function binary, we will get a 8bit value: 1000 0111
Translate 8bits binary back to hexdecima – 0x87
so 0x80FF XXXX will be 0x80FF 87XX after this step.- Bit7 to Bit0 will be Offset. we can directly put the offset value to last XX
so 0x80FF 87XX will be 0x80FF 87D0
After these 5 Steps, we get a DW address 0x80FF 87D0. Next, we will try to access PCI configuration sapce.
- We will write this address to IO space 0xCF8
For example if you use assembly code to access IO space.
out 0xCF8, 0x80FF87D0- Then we can read PCI configuration space through IO space 0xCFC
In eax, 0xCFC- You can write 0x1 to it through IO space 0xCFC also.
out 0xCFC, 0x1Done.
机器翻译正文如下:
如果您阅读我之前的文章,您将了解到 x86 处理器能够访问内存和 IO 空间。对于内存空间,您需要查看处理器 EDS 以获取处理器支持多少物理地址空间。例如,46 位。物理地址空间从 0x0 – 2^46。对于 IO 空间,x64 处理器能够支持 64K IO 空间。 (即从 0x0000 到 0xFFFF)回到如何以 Legacy 方式读/写 PCI 配置空间。您可以从 PCI Spec 中阅读此内容。为了便于阅读,我只是把它用我的话放在这里。如果您阅读处理器 EDS 或 PCH EDS,您会发现大多数寄存器都被列为 PCI 设备。这些寄存器将标记为 Bus:Device:Function:Offset。我将缩写为 Bus:Dev:Fuc:Off。基于 PCI 规范,我们将使用 IO 访问方式来读/写 PCI 配置空间。例如,有一个寄存器位于。总线 1,开发 16,Fuc 7,关闭 0xD0。下面是步骤。 1. 我们应该将 Bus:Dev:Fuc:Off 转换为 32 位 (1DW) 地址。 DW 地址会是这样的: XXXX XXXX 我喜欢用 X 来表示一个十六进制数。它将是 0x0 到 0xF,我们可以用 4 位二进制来表示。所以总共将是 8 x 4 = 32 位。 2. bit31应该是1,bit30到bit24会被保留,所以XXXX XXXX就是0x80XX XXXX。 3. Bit23 至 Bit16 将是总线编号。您可能还记得总线 1 不是 0x1,除非您检查了 CPUBUSNO 寄存器。通常,如果系统中只有一个处理器,我们会将 BUS1 设置为 0xFF。我们将在功能中讨论这个话题。所以在这一步之后 0x80XX XXXX 将是 0x80FF XXXX。 4. Bit15 至 Bit11 为设备编号,Bit10 至 Bit8 为功能编号。我们得到Device number 16,改成hexdecima 是0x10,改成binary 是1 0000b 我们得到Function number 7,它和hexdecima 一样,二进制是111b 结合5bits device binary和3bits function binary,我们会得到一个 8 位值:1000 0111 将 8 位二进制转换回十六进制 – 0x87 所以在这一步之后 0x80FF XXXX 将是 0x80FF 87XX。 5. Bit7 到 Bit0 将是偏移量。我们可以直接把偏移值放到最后一个XX所以0x80FF 87XX就是0x80FF 87D0 经过这5步,我们得到了一个DW地址0x80FF 87D0。接下来,我们将尝试访问 PCI 配置空间。 1.我们会将此地址写入IO空间0xCF8例如如果您使用汇编代码访问IO空间。 out 0xCF8, 0x80FF87D0 2. 然后我们可以通过IO空间0xCFC读取PCI配置空间 在eax, 0xCFC 3. 也可以通过IO空间0xCFC向其写入0x1。输出 0xCFC,0x1 完成。
没有回复内容