PCI-Scan
-
Bis auf das einige meiner DeviceIDs (z.B. 0x07D7, 0x07D8) noch nirgendwo verzeichnet sind, scheint der PCI-Scan zu funktionieren.
Allerdings gibt es ein kleines Problem (zumindest eines für Erbsenzähler):
// http://wiki.osdev.org/PCI#Configuration_Mechanism_.231 |31 |30 24|23 16|15 11|10 8|7 2[b]|1|0|[/b] |Enable Bit|Reserved| Bus |Device|Funktion|Register[b]|0|0|[/b]
Wenn dieser Aufbau so stimmt, dann muß folgende Funktion überarbeitet werden:
// pci.c version 108 static ULONG pci_config_read(ULONG bus, ULONG device, ULONG func, ULONG reg) { outportl(PCI_CONFIGURATION_ADDRESS, 0x80000000 | (bus << 16) | (device << 11) | (func << 8) // | (reg )); // <- ! | (reg << 2 )); // <- ! return inportl(PCI_CONFIGURATION_DATA); }
Dadurch ändert sich auch die "Zählweise" der Register:
Register Nummer : 0x00 0x01 0x02 0x03 ... entspricht Offset im "Config-Space" : 0x00 0x04 0x08 0x0C ...
-
Ja, das stimmt mit Offset = 4 * Register-Nummer, aber siehe hier:
http://wiki.osdev.org/PCI#PCI_Device_Structure
register bits 31-24 bits 23-16 bits 15-8 bits 7-0 00 Device ID Vendor ID 04 Status Command 08 Class code Subclass Prog IF Revision ID 0C BIST Header type Latency Timer Cache Line Size 10 Base address #0 (BAR0) ...
Da steht Register als Überschrift, unten folgen aber die Offsets.
http://lowlevel.brainsware.org/wiki/index.php/PCI#Header_Type_0x00
Das gleiche Spiel.Wahrscheinlich ist es so mit offset als Parameter und offset&0xFC (11111100) am klarsten:
int pci_config_readd(int bus,int dev,int func,int offset) { int val; int address = 0x80000000|(bus<<16)|(dev<<11)|(func<<8)|(offset&0xFC); outl(PCI_CONFIG_ADDRESS,address); val = inl(PCI_CONFIG_DATA); return val; }
-
Bis auf das einige meiner DeviceIDs (z.B. 0x07D7, 0x07D8) noch nirgendwo verzeichnet sind
Bus/Device/Function von Mainboard Chipsatz nVIDIA nForce 7100-630i bei lspci?
devvID: 0x07D8 ergibt nForce 7100-630i (MCP73PV) von NVIDIA Corporation (0x10DE )
bei 0x07D7 gibt die Datenbank keinen Wert zurück.scheint der PCI-Scan zu funktionieren.
schon wieder "scheint".
-
Erhard Henkes schrieb:
Wahrscheinlich ist es so mit offset als Parameter und offset&0xFC (11111100) am klarsten
Aber warum "offset & 0xFC"? Das ist unlogisch wenn "Registernummer" bit 7-0 sein soll.
Bit 1+0 sind gewissermaßen "reserviert". Wenn z.B. Bit 0 gesetzt ist, dann wird der Aufruf an den nächsten PCI-Bus weitergeleitet (wo auch immer der sich auch befinden mag)*.
Siehe "Type 1 Configuration"
* Das ist auch der Grund für "scheint". Eigentlich kenne ich meine eigenen Geräte nur nicht.
-
Dein Register-Zähler-Ansatz mit dem doppelten Linksshift gefällt mir inzwischen auch am besten, aufgeführt werden aber nicht die von Dir vorgeschlagenen Laufzahlen für die Register 0 ... 15, sondern die jeweils auf vier abgerundeten Offsets 0x0 ... 0x3C (siehe angegebe Links). Dein Ansatz wäre also sehr unüblich.
Vielleicht wird der Mainboard Chipsatz nicht angezeigt, weil er wahrscheinlich 0:00.0 ist. Der wurde vielleicht nach oben aus dem Bild gescrollt, passiert mir bei meinem vollgestopften Arbeits-PC auch. Da könntest Du zum Überprüfen eine Wartepause - sleepSeconds(...) - in der Ausgabeschleife einbauen, damit Dir nichts entgeht.
Alte Kisten haben da weniger zu bieten. USB-Erkennung hat bisher bei den von mir getesteten PCs geklappt.
Man kann übrigens auch in Windows im Arbeitsplatz - Gerätemanager - Ressourcenzusammenfassung - IRQ-Verwendungszusammenfassung nachschauen. Dort werden die ISA- und PCI-Devices aufgeführt (letztere teilweise mit Device-ID).
-
http://wiki.osdev.org/PCI#Configuration_Mechanism_.231
Register Number Bit 7-2http://lowlevel.brainsware.org/wiki/index.php/PCI#Aufbau_des_Adress-I.2FO-Ports
Registernummer Bit 7-0 <--- sollte als 4-aligned angegeben werden
Ich habe da mal "bit0 u. bit1 sind 0" darunter geschrieben im wiki.(offset & 0xFC) ==> Register Number Bit 7-2 mit Bit 0 und 1 auf 0 gesetzt macht also absolut Sinn, wenn es auch unschön ist.
-
Der PCI-Scan von PrettyOS, eine eigens selbst geschriebene Schleife, ein drittes Programm (Dr. Hardware) und die "Windows Vista Computerverwaltung" liefern allesamt das gleiche Ergebnis:
B D F DeviceID ("Gerät") VendorID ------------------------------------------------ 0h 0h 0h 07C1 Host Bridge 10DE 0h 0h 1h 07CB RAM RAM-Contr. 10DE (...) 0h 4h 0h 07FE USB Serial Bus 10DE (OHCI) 0h 4h 1h 056A USB Serial Bus 10DE (EHCI) (kein UHCI) :( (...) 2h 0h 0h 06E6 VGA Video 10DE 4h 0h 0h 3403 Firewire Serial Bus 1106
Damit hat es sich ausge"scheint".
Nochwas zum Erbsenzählen:
Wenn in einer Schleife Bit 7-0 hochgezählt werden (ohne das unschöne (xxx & 0xFC)), dann ergibt das folgendes:
Bit 7-0 0x00 0x01 0x02 0x03 0x04 0x05 0x06 ... entspricht Register Nr. 0x00 0x00 0x00 0x00 0x01 0x01 0x01 ... und [i]liefert 32 bit[/i] ab Offset 0x00 0x00 0x00 0x00 0x04 0x04 0x04 ... [i]im "Config-Space"[/i]
Ein Zugriff auf z.B. Offset (oder Register lt. diversen wikis) 0x02 im "Config-Space" ist nicht möglich. Vorerst ist es besser, bit 1 und bit 0 dieser Struktur im Tutorial als "z.Zt. undokumentiert :(" zu bezeichnen.
-
Der PCI-Scan von PrettyOS, eine eigens selbst geschriebene Schleife, ein drittes Programm (Dr. Hardware) und die "Windows Vista Computerverwaltung" liefern allesamt das gleiche Ergebnis
Danke!
-
+gjm+ schrieb:
Vorerst ist es besser, bit 1 und bit 0 dieser Struktur im Tutorial als "z.Zt. undokumentiert " zu bezeichnen.
Die sind nicht undefiniert. Es ist - soweit ich weiß - festgelegt, dass ein PCI-Gerät beim Zugriff auf den Konfigurationsadressraum diese beiden Bits nicht überprüfen muss, da sie immer 0 sind. Und, btw, laut dieser Quelle ("PC-Hardwarebuch - Aufbau, Funktionsweise, Programmierung") handelt es sich nicht um eine Registernummer in den Bits 2 bis 7, sondern um einen Offset in diesem Konfigurationsraum, der aber eben an vier ausgerichtet sein muss (der Konfigurationsraum ist laut diesem Buch nur ein anderer Adressraum neben dem I/O- und dem Speicheradressraum).
-
@+gjm+: Eines habe ich bei deiner Argumentation noch nicht verstanden:
So wie es aussieht ist "Register-Nummer" und "Offset" zahlenmäßig das Gleiche. Das sieht bei Dir irgendwie anders aus. Dein Argument mit ...&FC verstehe ich allerdings.Ich lasse es zunächst mal bei dieser "schönen" statischen Funktion:
static uint32_t pci_config_read(uint32_t bus, uint32_t device, uint32_t func, uint32_t reg) { outportl(PCI_CONFIGURATION_ADDRESS, 0x80000000 | (bus << 16) | (device << 11) | (func << 8) | (reg )); return inportl(PCI_CONFIGURATION_DATA); }
Parameter reg wird dann eben der korrekte Offset sein. Das kann man durch eine entsprechende Schleife oder durch saubere Parameterübergabe erreichen. Außerhalb des Moduls wird diese Funktion ja nicht benötigt.
-
XanClic schrieb:
Es ist - soweit ich weiß - festgelegt, dass ein PCI-Gerät beim Zugriff auf den Konfigurationsadressraum diese beiden Bits nicht überprüfen muss, da sie immer 0 sind.
Entweder muß das Gerät diese beiden Bits nicht überprüfen -> dann sind sie undefiniert. Oder sie müssen beide Null sein -> dann fehlt die Dokumentation. Aber davon mal abgesehen gibt es spätestens hier Abschnitt 6.5.2, Figur 6.4 ein Problem: Entweder einigt man sich auf die Register-Zählweise, oder man definiert, je nach Bedarf, immer wieder eine neue Struktur.
Erhard Henkes schrieb:
So wie es aussieht ist "Register-Nummer" und "Offset" zahlenmäßig das Gleiche.
Das ist so weil ein Register genau 32 Bit breit ist. Den Offset kann man ja nicht "beliebig" wählen. Es ist ähnlich wie das Auslesen vom CMOS.
-
+gjm+ schrieb:
Entweder muß das Gerät diese beiden Bits nicht überprüfen -> dann sind sie undefiniert. Oder sie müssen beide Null sein -> dann fehlt die Dokumentation.
Nicht entweder-oder. Beides. Da sie beide Null sein müssen, darf sich das Gerät die Überprüfung sparen. Wenn sie ungleich Null sind, dann ist das nicht korrekt.
-
Also jetzt will ich es genau wissen. Wozu sind diese beiden Bits überhaupt da? Was passiert, wenn Bit 0 bzw. Bit 1 bzw. beide auf 1 gesetzt werden?
-
Wenn ich mir den QEMU-Quellcode ansehe, dann ist es nicht empfehlenswert, die auf einen anderen Wert als 0 zu setzen, weil QEMU die Adresse so nimmt, wie sie ist (also nicht selbst die Bits 0 und 1 auf 0 setzt). Es scheint aber auch das Lesen von Bytes und Words anstellen von DWords zu erlauben.
Also, ich zitiere mal aus dem besagten Buch:
Konfiguration-Lesezugriff: [...] Die Adressbits AD7-AD2 geben die Adresse des zu lesenden Doppelworts im Konfigurationsadressraum der Einheit an, AD1 und AD0 sind gleich 0. [...]
Somit habe ich da Mist erzählt mit "das Gerät muss das nicht prüfen". Ich bitte dafür um Entschuldigung.
Aber wie man sieht, ist es einfach eine Adresse in einem speziellen Adressraum und keine Registernummer. Die Adressbits 0 und 1 müssen 0 sein, sonst bekommt man auf QEMU wohl andere Ergebnisse als auf echter Hardware (sind sie auf echter Hardware ungleich 0, dann werden sie anscheinend einfach auf 0 gesetzt; sind sie bei QEMU ungleich 0, dann werden diese Bits mit berücksichtigt).
-
sind sie auf echter Hardware ungleich 0, dann werden sie anscheinend einfach auf 0 gesetzt
Interessanter Hinweis. Das können wir experimentell prüfen. Simulatoren sollten die Hardware entsprechend nachbilden. Schwächen dieser Programme müssen wir in einem OS nicht zwingend berücksichtigen, wir könnten es aber dennoch machen. Somit ist der ...&FC Ansatz nicht notwendig, zielt aber dennoch in die richtige Richtung. Wenn man ihn bringt, muss man genau erklären, warum man das macht, z.B. für reale HW nicht notwendig, aber wegen Simulationsprogramm ... sinnvoll.
-
@Erhard Henkes:
Wie tief soll fürs PrettyOS in die Untiefen von "PCI" eingestiegen werden? Bit 1 und Bit 0 sind reserviert und m.E. nur für die/eine PCI-Bridge interessant.
Wenn z.B. eine angeforderte Busnummer nicht von der/einer PCI-Bridge "verwaltet" (oder "erreicht") wird, dann setzt sie Bit 0 und gibt die Anforderung an die nächste PCI-Bridge weiter.
Für den PCI-Scan sind beide Bits ohne Bedeutung (da reserviert!). Sie können gesetzt sein oder auch nicht. (Genauso wie bei Bit 30-24).
-
Wie tief soll fürs PrettyOS in die Untiefen von "..." eingestiegen werden?
Diese Frage gilt grundsätzlich an vielen Stellen. Bisher habe ich einen didaktischen und zielorientierten Ansatz gewählt. Für PCI bedeutet dies, dass wir im ersten Ansatz die USB Devices mit ihren Program Interfaces sowie ihren BAR feststellen wollen.
-
sind sie auf echter Hardware ungleich 0, dann werden sie anscheinend einfach auf 0 gesetzt
Tests auf echter Hardware (PC):
- (reg ));
- (reg + 1 ));
- (reg + 2 ));
- (reg + 3 ));
---> in allen vier Fällen folgendes Bild:
http://www.henkessoft.de/OS_Dev/Bilder/PCI-Scan2.JPGObige Aussage trifft demnach zu und wir können uns das überflüssige und nicht verständlich ... & 0xFC bei entsprechender Dokumentation sparen.
Daher folgender Vorschlag für die Funktion im Sourcecode mit entsprechendem Kommentar:
static uint32_t pci_config_read(uint32_t bus, uint32_t device, uint32_t func, uint32_t reg) { outportl(PCI_CONFIGURATION_ADDRESS, 0x80000000 | (bus << 16) | (device << 11) | (func << 8) | (reg )); // Bit 0 and Bit 1 is reserved and is automatically set to 0. // Therefore, we do not need & 0xFC, but this mask should be used for simulations. return inportl(PCI_CONFIGURATION_DATA); }
-
Obige Aussage trifft demnach zu ...
Dann sollte man besser schreiben, daß echte HW Bit 7-2 beachtet und Bit 1-0 ignoriert (beim PCI-Scan).
-
echte HW Bit 7-2 beachtet und Bit 1-0 ignoriert
Ja, eindeutig präziser. Danke!
static uint32_t pci_config_read(uint32_t bus, uint32_t device, uint32_t func, uint32_t reg) { outportl(PCI_CONFIGURATION_ADDRESS, 0x80000000 | (bus << 16) | (device << 11) | (func << 8) | (reg )); // Real hardware ignores bits 0 and 1, and reads only bits 7-2. // Hence, we do not really need "& 0xFC". // This mask should be used for tests with simulation software. return inportl(PCI_CONFIGURATION_DATA); }