PCI-Scan



  • 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. 🙂


  • Mod

    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).


  • Mod

    http://wiki.osdev.org/PCI#Configuration_Mechanism_.231
    Register Number Bit 7-2

    http://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.


  • Mod

    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).


  • Mod

    @+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.


  • Mod

    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).


  • Mod

    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).


  • Mod

    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.


  • Mod

    sind sie auf echter Hardware ungleich 0, dann werden sie anscheinend einfach auf 0 gesetzt

    Tests auf echter Hardware (PC):

    1. (reg ));
    2. (reg + 1 ));
    3. (reg + 2 ));
    4. (reg + 3 ));

    ---> in allen vier Fällen folgendes Bild:
    http://www.henkessoft.de/OS_Dev/Bilder/PCI-Scan2.JPG

    Obige 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). 🙂


  • Mod

    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);
    }
    

  • Mod

    Wenn ich mir den PCI Scan auf dem Monitor (80*24) anschaue, hätte ich gerne eine kleinere - also besser aufgelöste - Text-Darstellung. Dafür benötigen wir aber VM86, leider.



  • Die Spezifikation nicht gelesen, auf einem einzigen PC getestet, und es dann anders machen als alle anderen?


  • Mod

    ... und es dann anders machen als alle anderen?

    Ja, genau, bis wir wissen, dass unser Vorgehen falsch ist. Erst dann wird ... & 0xFC eingebaut. Schlimmer ist es, einfach diesen Masker einzubauen, obwohl man ihn nicht braucht. Kernfrage ist also, ob man ihn wirklich braucht.

    Daher die konkrete Frage an Dich: Wo steht, dass man notwendigerweise ... & 0xFC verwenden muss, wenn man eine Register-Nummer übergibt, weil man ansonsten falsche Daten zurück erhält? 😉

    Hier wird z.B. Bit 0 der Register-Nummer beschrieben:
    http://tldp.org/LDP/tlk/dd/pci.html (Absatz 6.5.2, PCI-PCI Bridges)

    Unter 6.6.4 findet man "Finding Out How Much PCI I/O and PCI Memory Space a Device Needs" (interessant für den Schritt BARs ermitteln):

    Each PCI device found is queried to find out how much PCI I/O and PCI Memory address space it requires. To do this, each Base Address Register has all 1's written to it and then read. The device will return 0's in the don't-care address bits, effectively specifying the address space required.

    ...

    Figure 6.10: PCI Configuration Header: Base Address Registers

    There are two basic types of Base Address Register, the first indicates within which address space the devices registers must reside; either PCI I/O or PCI Memory space. This is indicated by Bit 0 of the register. Figure 6.10 shows the two forms of the Base Address Register for PCI Memory and for PCI I/O.

    To find out just how much of each address space a given Base Address Register is requesting, you write all 1s into the register and then read it back. The device will specify zeros in the don't care address bits, effectively specifying the address space required. This design implies that all address spaces used are a power of two and are naturally aligned.

    For example when you initialize the DECChip 21142 PCI Fast Ethernet device, it tells you that it needs 0x100 bytes of space of either PCI I/O or PCI Memory. The initialization code allocates it space. The moment that it allocates space, the 21142's control and status registers can be seen at those addresses.

    Bild (Figure 6.10): http://tldp.org/LDP/tlk/dd/pci-bars.gif


Anmelden zum Antworten