Zugriff auf PCI-Speicher durch den Spielekernel - Linux, Betriebssystem, x86, Kernel, x86-64

Ich schreibe einen Spielzeug-Kernel auf der x86_64-Plattform. Ich plane, meinen Kernel zu erhöhen, um VGA und andere Geräte zu verwenden. Bis zu diesem Punkt habe ich meinen Spielzeugkern mit nur Tastatur und UART verbunden. Jetzt denke ich, dass es reif genug ist, einige Basisgeräte zu verwenden.

Ich finde es jedoch schwer zu findenDokumentation über die PCI-Schnittstelle bei früher Boot-Zeit. Ich finde Dokumentation über Linux-PCI-Treiber, aber nicht etwas, was ich wirklich brauche. Ich muss den Spaziergang alleine machen. Ich bin immer noch verwirrt, wenn das BIOS irgendwo PCI-Platz abbildet.

Kann jemand etwas Licht darauf werfen oder auf eine Dokumentation zeigen?

Vielen Dank

Antworten:

0 für die Antwort № 1

Das erste, was Sie tun wollen, istFühren Sie die PCI-Aufzählung durch. Es gibt grundsätzlich zwei Möglichkeiten, eine PCI-Enumeration durchzuführen, entweder portbasiert oder speicherabgebildet. Der portbasierte ist der ältere Weg und der Speicherkarten-PCI-Konfigurationsraum wurde mit PCI Express eingeführt. Der Port-basierte Ansatz funktioniert immer noch mit neueren Maschinen und funktioniert auch mit Emulatoren / virtuellen Maschinen für die Abwärtskompatibilität. Deshalb werde ich diesen Ansatz im Rest meiner Erklärung verwenden. Dies funktioniert auch, da es ein wenig komplizierter ist und wenn Sie verstehen, wie Port-basierte Enumeration durchzuführen ist die Speicher-Mapping-Enumeration ziemlich einfach. Ich sollte hinzufügen, dass einige nicht PC-kompatible x86-Boards keine Port-basierte PCI-Enumeration unterstützen.

Um über Ports auf den PCI-Konfigurationsbereich zuzugreifen (um eine Aufzählung durchzuführen), müssen Sie zwei spezifische Ports kennen:

  1. CONFIG_ADDRESS - Port 0xCF8

  2. CONFIG_DATA - Port 0xCFC

Im Grunde, was du tust, schreibst du eine Adresse an CONFIG_ADDRESS und lese oder schreibe den Wert an diese Adresse mit CONFIG_DATA. Die Adresse wurde geschrieben CONFIG_ADDRESS hat die Form:

31          30 - 24     23 - 16     15 - 11         10 - 8          7 - 2           1 - 0
Enable Bit  Reserved    Bus Number  Device Number   Function Number Register Number 00

Das Freigabebit sollte grundsätzlich immer auf 1 gesetzt sein, vorausgesetzt, Sie verwenden es CONFIG_DATA um einen Wert zu lesen oder zu schreiben.

Wenn Sie beispielsweise das erste Register für das erste Gerät in der Konfiguration lesen möchten, würden Sie Folgendes tun:

outl(CONFIG_ADDRESS, 1 << 31);
uint32_t result = inl(CONFIG_DATA)

Um zu bestimmen, was jedes Register ist, können Sie diese Tabelle ansehen:

PCI-Konfigurationsraumtabelle

Im ersten Beispiel enthält das erste Register also sowohl die Geräte-ID als auch die Hersteller-ID.

Jetzt wissen Sie, wie man ein Register liestDer PCI-Konfigurationsbereich, den Sie wissen müssen, wenn Sie ein Gerät gefunden haben. Wenn das erste Register 0xFFFFFFFF ist, ist bei dieser Gerätenummer kein Gerät an diesen Bus angeschlossen. Die brutale Methode besteht darin, alle Busse und Geräte zu scannen und dann die Funktionen zu scannen, wenn Sie ein Gerät finden. Auf ausgeklügeltere Weise wird der Header-Typ des ersten Geräts auf dem ersten Bus betrachtet, um zu bestimmen, welche Busse überprüft werden müssen. Sie finden weitere Informationen zur komplexeren Aufzählung Hier.

Um den speicherbasierten Ansatz zu verwenden, müssen Sie die MCFG-Tabelle finden, die in angegeben ist ACPI (auch im einfacheren enthalten SFI). Dadurch erhalten Sie die physische Adresse, die Sie für die PCI-Enumeration verwenden können. Alle Speicheradressen sind ein Offset von dieser Adresse. Einer der Hauptunterschiede besteht auch darin, dass der Konfigurationsbereich erweitert wurde, so dass die Adressbitfelder nicht mit den portbasierten Aufzählungsbitfeldern übereinstimmen. Adressen für PCI Express verwenden das folgende Format:

31 - 28   27 - 20     19 - 15        14 - 12          11 - 8                    7 - 2            1 - 0
ZEROS     bus number  device number  function number  extended register number  register number  offset

Dies ist der Offset von der physikalischen Adresse, die von der MCFG-Tabelle erhalten wird. Sie können mehr Informationen über PCI Express finden Hier.

Schließlich, während es gerätespezifisch am meisten istNützliche Informationen, die Sie aus dem PCI-Konfigurationsraum erhalten können, sind typischerweise die Basisadressregister. Dies sind typischerweise die physikalischen Adressen, denen das Gerät zugeordnet ist, vorausgesetzt, es ist Speicher zugeordnet oder die Portadresse ist angenommen, dass es portbasiert ist. Natürlich sind der Interrupt Pin und die Leitung auch nützlich.


Am beliebtesten