PCI配置空間の概要


一、PCI配置空間の紹介
PCIには、デバイスメモリアドレス空間、I/Oアドレス空間、構成空間の3つの物理アドレス空間があります.配置空間はPCI特有の物理空間である.PCIはデバイスのプラグアンドプレイをサポートするため、PCIデバイスは固定メモリアドレス空間やI/Oアドレス空間を占有するのではなく、オペレーティングシステムによってマッピングのベースアドレスを決定する.
システムの電源投入時、BIOSはPCIバスを検出し、PCIバスに接続されている全ての設備及びそれらの配置要求を確定し、システム配置を行う.従って、すべてのPCIデバイスは構成空間を実現しなければならず、パラメータの自動配置を実現し、真のプラグアンドプレイを実現することができる.
PCIバス仕様で定義された配置空間の全長は256バイトであり、配置情報は一定の順序と大きさで順次格納される.最初の64バイトの配置空間を配置ヘッダと呼び、すべてのデバイスについて同じように、配置ヘッダの主な機能は、デバイスを識別し、ホストがPCIカードにアクセスする方法(I/Oアクセスまたはメモリアクセス、割り込み情報)を定義することである.残りの192バイトはローカル構成空間と呼ばれ、主にカード上のローカルバスの特性、ローカル空間ベースアドレス、範囲などを定義する.
PPCIデバイスには、メモリアドレス空間、IOアドレス空間、構成空間の3つの空間がある.PCIはプラグアンドプレイをサポートするため、PCIデバイスは固定メモリアドレス空間やI/Oアドレス空間を占有するのではなく、オペレーティングシステムによってマッピングのベースアドレスを決定することができる.どのように配置しますか?これが空間を構成する役割です.
		DW |    Byte3    |    Byte2    |    Byte1    |     Byte0     | Addr
		---+---------------------------------------------------------+-----
		 0 |     Device ID     |     Vendor ID      | 00
		---+---------------------------------------------------------+-----
		 1 |      Status     |      Command      | 04
		---+---------------------------------------------------------+-----
		 2 |        Class Code        | Revision ID | 08
		---+---------------------------------------------------------+-----
		 3 |   BIST  | Header Type | Latency Timer | Cache Line  | 0C
		---+---------------------------------------------------------+-----
		 4 |           Base Address 0           | 10
		---+---------------------------------------------------------+-----
		 5 |           Base Address 1           | 14
		---+---------------------------------------------------------+-----
		 6 |           Base Address 2           | 18
		---+---------------------------------------------------------+-----
		 7 |           Base Address 3           | 1C
		---+---------------------------------------------------------+-----
		 8 |           Base Address 4           | 20
		---+---------------------------------------------------------+-----
		 9 |           Base Address 5           | 24
		---+---------------------------------------------------------+-----
		10 |          CardBus CIS pointer          | 28
		---+---------------------------------------------------------+-----
		11 |  Subsystem Device ID  |   Subsystem Vendor ID   | 2C
		---+---------------------------------------------------------+-----
		12 |        Expansion ROM Base Address        | 30
		---+---------------------------------------------------------+-----
		13 |        Reserved(Capability List)         | 34
		---+---------------------------------------------------------+-----
		14 |            Reserved             | 38
		---+---------------------------------------------------------+-----
		15 |  Max_Lat  |  Min_Gnt  |  IRQ Pin  |  IRQ Line  | 3C
		-------------------------------------------------------------------


構成スペースで最も重要なものは次のとおりです.
	Vendor  ID:  ID。        ID。FFFFh       ID,     PCI      。
	Device  ID:  ID。         ID。         Vendor ID Device ID          。
	Class Code:   。    ,       、    、    。             ,         ,              。
	IRQ   Line:IRQ  。PC       8259     16     。            ,  APIC(          ),     24   。
	IRQ    Pin:    。PCI 4     ,                 。

二、構成スペースへのアクセス方法
           ?     CF8h、CFCh     。
    CF8h: CONFIG_ADDRESS。PCI        。
    CFCh: CONFIG_DATA。PCI        。
  CONFIG_ADDRESS     :
         31  :Enabled 。
        23:16  :    。
        15:11  :    。
        10: 8  :    。
         7: 2  :         。
         1: 0  :  “00”。    CF8h、CFCh   32   。

現在、CF 8 h、CFChポートは32ビットポートであり、TurboCのような16ビットC言語コンパイラは32ビットポートアクセスをサポートしていないという難題がある.どうしよう?私たちは__を使うことができます.emit__プログラムにマシンコードを挿入します.毎回_emit__すぐには面倒なので、関数にカプセル化する必要があります.コードは以下の通りである(66 hは32ビット命令接頭辞であることに注意).
/*  32    */
DWORD inpd(int portid)
{
	DWORD dwRet;
	asm mov dx, portid;
	asm lea bx, dwRet;
	__emit__
	(0x66, 0x50,       // push EAX
	0x66, 0xED,        // in EAX,DX
	0x66, 0x89, 0x07,  // mov [BX],EAX
	0x66, 0x58);       // pop EAX
	return dwRet;
}
/*  32    */
void outpd(int portid, DWORD dwVal)
{
	asm mov dx, portid;
	asm lea bx, dwVal;
	__emit__
	(0x66, 0x50,       // push EAX
	0x66, 0x8B, 0x07,  // mov EAX,[BX]
	0x66, 0xEF,        // out DX,EAX
	0x66, 0x58);       // pop EAX
	return;
}

三、PCI設備の列挙
PCIデバイスをどのように列挙しますか?すべてのbus/dev/funcの組合せを試み,得られたメーカーIDがFFFFhであるか否かを判断することができる.以下のプログラムは,この方法を用いてPCIデバイスを列挙する.同時に、データの分析を容易にするために、各デバイスの構成空間情報をファイルに保存し、ゆっくりと分析することができます.
#include 
#include 

typedef unsigned char BYTE;
typedef unsigned int WORD;
typedef unsigned long DWORD;

/* PCI    。bus/dev/func  16 ,           WORD  */
#define PDI_BUS_SHIFT        8
#define PDI_BUS_SIZE         8
#define PDI_BUS_MAX          0xFF
#define PDI_BUS_MASK         0xFF00
#define PDI_DEVICE_SHIFT     3
#define PDI_DEVICE_SIZE      5
#define PDI_DEVICE_MAX       0x1F
#define PDI_DEVICE_MASK      0x00F8
#define PDI_FUNCTION_SHIFT   0
#define PDI_FUNCTION_SIZE    3
#define PDI_FUNCTION_MAX     0x7
#define PDI_FUNCTION_MASK    0x0007
#define MK_PDI(bus,dev,func) (WORD)((bus&PDI_BUS_MAX)<>16);
                    /* Class Code */
                    outpd(PCI_CONFIG_ADDRESS, dwAddr | 0x8);
                    dwData = inpd(PCI_CONFIG_DATA);
                    printf("%6.6lX\t", dwData>>8);
                    /* IRQ/intPin */
                    outpd(PCI_CONFIG_ADDRESS, dwAddr | 0x3C);
                    dwData = inpd(PCI_CONFIG_DATA);
                    printf("%d\t", (BYTE)dwData);
                    printf("%d", (BYTE)(dwData>>8));
                    printf("
"); /* */ sprintf(szFile, "PCI%2.2X%2.2X%X.bin", bus, dev, func); hF = fopen(szFile, "wb"); if (hF != NULL) { /* 256 PCI */ for (i = 0; i < 0x100; i += 4) { /* Read */ outpd(PCI_CONFIG_ADDRESS, dwAddr | i); dwData = inpd(PCI_CONFIG_DATA); /* Write */ fwrite(&dwData, sizeof(dwData), 1, hF); } fclose(hF); } } } } } return 0; }

バス番号が0のものはすべてマザーボードに固有のチップ(主に南ブリッジ)で、マザーボード以外のデバイスの典型はグラフィックスカードです.WindowsXPのデバイスマネージャにもPCI情報が表示されます.デバイスマネージャを起動し、表示方法を「接続によるデバイスの表示(V)」に設定したほうがいいです.私のグラフィックスカードを見つけて、ダブルクリックしてプロパティを表示します.≪詳細|Details|emdw≫ページに移動し、コンボ・ボックスが「≪ハードウェアId|Hardware Id|emdw≫」になります.いずれかの動作「PCI/VEN_10 DE&DEV_0110&CC_030000」が見られ、メーカーIDが「10 DE」、デバイスIDが「0110」、クラスコードが「030000」であり、プログラムの結果と一致する.