2018年9月20日 星期四

[轉貼 | 備份] PCI Read/Write 0xcf8 0xcfc

出處
http://blog.xuite.net/huaanvgs/blog/137026031-PCI+Read%2FWrite


20204PCI
    BIOS入門的第一課大部分都會遇到PCI的作業,前輩們往往都會出個簡單的作業,要求我們去讀寫PCI configuaration space,到底我們該如何去做呢?
    根據PCI Local Bus Specification 3.0有提到,"Every device, other than host bus bridges, must implement Configuration Address Space. Host bus bridges may optionally implement Configuration Address Space. In the Configuration Address Space, each function is assigned a unique 256-byte space that is accessed differently than I/O or Memory Address Spaces"
    也就是說讀寫PCI的方式有兩種,一種是透過I/O(CF8/CFC)而另一種則是利用MMIO的方式來去讀寫PCI configuration space.
    在介紹這兩種讀寫方法以前,我們先來看PCI spec.如何定義Configuration commands。為了支援階層式的PCI buses,在此使用兩種類型的configuration transactions,如Figure 1所示。

Figure 1
在Figure 1中我們可以看到兩種不同的configuration commands,分別為Type0Type1,其中
    Type0: A Type 0 configuration transaction (when AD[1::0] = “00”) is used to select a device on the bus where the transaction is being run.
    Type1: A Type 1 configuration transaction (when AD[1::0] = “01”) is used to pass a configuration request to another bus segment.
    而IDSEL(Initialization Device Select)是指"it used as a chip select during configuration
read and write transactions." 這部分會連接到PCI AD[31:11],是由硬體拉線所決定的。
    其中IDSEL可以辨別PCI的身分,當硬體解出來的configuration cycle為Type0時,會做以下兩件事:1.遮罩[31:11],2.解碼Device number。相反的,當硬體解出的configuration cycle為Type1時,他會做以下的事:1.當bus number和secondary bus number一致時,會將Type1轉成Type0,也就是Bit0設為1,並做Type0該做的事;當bus number和secondary bus number不一致時,則會往下一層送。
    透過IDSEL辨別Type0和Type1的方式,我們可以完成PCI的Scan,但在Type0的configuration transactions中好像沒有定義Bus number與Devce number,那麼如何去做transactions呢?還記得Type0的定義,他是在相同的bus下去選擇device,而device number我們又可以透過解碼的方式去獲得,因此就不會有找不到的問題。

Software Generation of Configuration Transactions
    系統必須提供一種機制來讓軟體有辦法去Access PCI configuration space,前面有提到可以透過I/O space及MMIO space的方式去存取,但PCI device還沒分配resource之前,還是只能透過I/O space的方式去access。
 "Two DWORD I/O locations are used to generate configuration transactions for PC-AT compatible systems. The first DWORD location (CF8h) references a read/write register that is named CONFIG_ADDRESS. The second DWORD address (CFCh) references a read/write register named CONFIG_DATA."
    Figure 2為針對CONFIG_ADDRESS所定義的Layout,其中:

Figure 2 
where
Bit[31]: It is an enable flag for determining when accesses to CONFIG_DATA are to be translated to configuration transactions on the PCI bus.
Bit[30:24]: Reserved
Bit[23:16]: Bits 23 through 16 choose a specific PCI bus in the system.
Bit[15:11]: Bits 15 through 11 choose a specific device on the bus.
Bit[10:8]: Bits 10 through 8 choose a specific function in a device.
Bit[7:2]: Bits 7 through 2 choose a DWORD in the device's Configuration Space.
Bit[1:0]: Bits 1 and 0 are read-only and must return 0's when read.

    由上面定義可以得知最多支援的Bus number為256(2的8次方),最多支援的device number為32(2的5次方),最多支援的function number為8(2的3次方),可以讀取的configuration space為256(2的8次方),速記為8538
    看到這邊,或許會對configuration space有疑問,在Figure 2不是只有用Bit[7:2]去定義嗎,為什麼可以讀到256個呢?這是因為上面定義Bit[1:0]在Read的時候必須是0,所以如果我們要去Read/Write的space剛好在Bit[1:0]不為0的時候只能利用偏移的方式去做讀取,我們之後會有一個小小的範例做說明。
    接著我們看這兩種Type的configuration commands如何與SW做結合。

Figure 3

     自Figure 3我們可以看到,假設IDSEL辨別為Type0,自然就知道Bus number,而device number可以透過解碼方式獲得,並填到Bit[31:11]中的其中一個,剩下的Function number和Register number則複製到PCI AD BUS當中。
    如果IDSEL辨別為Type1,則是將CONFIG_ADDRESS全部複製到PCI AD line當中,當然Bit0也必須是1。

PCI R/W sample:
參考Figure 4,如下:

Figure 4
    如圖Figure 所示,假設我們要讀取Bus00, Dev1B,Fun00的Offset3C(Interrupt Line),那麼我們應該如何做呢?步驟描述如下:
Step1:
          我們知道透過I/O space(CF8/CFC)可以Read/Write Configuration space,其中把要讀取該Space的PFA填入Config_Address(CF8)後,在Config_Data(CFC)就可以得到該資料。
Step2:
          有了步驟1的知識後,我們要先計算出PFA,回顧Figure 2所示,我們必須將要讀取的BUS,Dev,Fun及Offset填入Config_Address所對應的Layout,其中Bit31必須為1,Bit[1:0]必須為0(如果剛好不為0可以用偏移方式讀取),其分析如下:
31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2   1  0
 1  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  1  1  0  1  1  0  0  0  0  0  1  1  1  1  0  0

PFA = 8000D83C h
    以Tool RW來示範的話就是利用I/O CF8填入PFA,然後在CFC的Offset 00h可以得到Interrupt Line的值16h,如圖Figure 5所示。

Figure 5

如果用組合語言來表示我們可以描述如下:
mov dx, cf8h
mov eax, 8000d83ch (PFA)
out dx, eax
mov dx, cfch
in eax, dx
如此,我們可以在EAX的Offset 00h得到我們要讀取的值。

沒有留言:

張貼留言