PCI - Peripheral Component Interconnect – интерфейс шины, присоединяющей периферийные устройства к материнской плате.
PCI состоит из 32 электрических линий, каждая из которых представляет бит информации: 0/1. PCI работает с частотой 33MHz. Это означает, что данные в линиях могут меняться 33 тысячи раз в секунду.
Устройства разделяют линии шины. Каждое устройство владеет доступом ко всей шине в течение некоторого времени.
Арбитраж шины – механизм, который определяет, которое устройство может владеть шиной в данный момент.
Устройства могут сообщаться со своим драйвером, который является частью программного обеспечения, работает в контексте операционной системы и управляет соответствующим устройством. Для каждой операционной системы должна быть специальная версия драйвера.
Для сообщения с драйвером устройство имеет линию прерывания (IRQ line), которая используется для сообщения процессору, что оно должно вызвать драйвер для обработки им события.
При обработке события драйверу может понадобиться прочитать данные с устройства (например, для чтения/записи принятого/передаваемого сетевого пакета или содержимого дисплея). Для передачи данных PCI устройство имеет две возможности: передача данных через некоторый порт ввода/вывода или через разделяемый, предварительно выделенный, регион памяти. Линия прерывания и регион памяти называются ресурсами периферийного устройства.
Регион памяти – это часть основной памяти компьютера RAM, так что драйвер просто копирует данные из этой памяти или в нее. Соответствие регионов памяти устройствам задается BIOS’ом.
BIOS (Basic Input and Output System) – отвечает за загрузку системы и обеспечивает ее некоторыми базовыми возможностями, например, поддержкой примитивного адаптера дисплея. Одна часть BIOS’а проходит по всем присоединенным PCI-устройствам и предоставляет им ресурсы памяти, которые им требуются, путем программирования регистров базового адреса. После этого BIOS грузит операционную систему, которая нумерует все PCI-устройства и существующие ресурсы памяти.
Каждое PCI-устройство идентифицируется device ID и vendor ID, которые содержатся в первых 64 битах конфигурационного пространства каждого PCI-устройства. После считывания этой информации операционная система ищет по ней подходящий драйвер устройства.
DMAC (Direct Memory Access Controller) – процессор, который знает, как копировать данные из одного места в другое. Используется драйверами для копирования данных без загрузки CPU.
PCI BAR (Base Address Register)
Адрес |
31 ... 24 |
23 ... 16 |
15 ... 8 |
7 ... 0 |
0x00 |
DeviceID |
VendorID |
||
0x04 |
Status |
Command |
||
0x08 |
Class Code |
Revision ID |
||
0x0C |
BIST |
Header Type |
Latency Timer |
Cash Line Size |
0x10 |
Base Address Register 1 |
|||
0x14 |
Base Address Register 2 |
|||
0x18 |
Base Address Register 3 |
|||
0x1C |
Base Address Register 4 |
|||
0x20 |
Base Address Register 5 |
|||
0x24 |
Base Address Register 6 |
|||
0x28 |
Card bus CIS pointer |
|||
0x2C |
SubsystemID |
Subsystem Vendor ID |
||
0x30 |
Expansion ROM Base Address |
|||
0x34 |
Reserved |
Capabilities |
||
0x38 |
Reserved |
|||
0x3C |
Max_Lat |
Min_Gnt |
Interrupt Pin |
Interrupt Line |
Таблица 1. Первые 64 байта конфигурационного адресного пространства PCI (в соответствии с PCI Local Bus Specification 2.2)
Три адресных пространства:
- память (LDR, STR – чтение/запись из памяти/в память)
- порты ввода вывода
- конфигурационное пространство PCI
I/O ports – определенные адреса (размер адреса 12 битов), на каждый адрес назначена определенная функция
0xcf8 - PCI CONFIG_ADDRESS
0xcfc - PCI CONFIG_DATA
При записи в конфиг.пр-во PCI сначала в I/O порт 0xcf8 записывается адрес регистра, а затем в I/O порт 0xcfc записываются данные, предназначенные для записи в заданный таким образом регистр конф.пр-ва PCI.
При чтении из конфиг.пр-во PCI сначала в I/O порт 0xcf8 записывается адрес регистра, а затем из I/O порт 0xcfc читаются данные, содержащиеся в заданном таким образом регистре конф.пр-ва PCI.
Формат CONFIG_ADDRESS:
0x80000000 | bus << 16 | device << 11 | function << 8 | offset Чтение/запись в порт: x=inb(addr), outb(addr, data), outw(), outl()