PCI-Scan



  • 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



  • +gjm+ schrieb:

    Bit 1 und Bit 0 sind reserviert

    Wenn in Intelmanuals oder so "reserviert" steht, dann heißt das nicht "auf irgendwas setzen". Das heißt immer - wenn nicht ausdrücklich anders gesagt - "dieses Bit ist auf 0 zu setzen". Denn reserviert heißt zumindest in diesem Fall: "In der Zukunft könnten wir das für was anderes brauchen, und damit dein Programm dann noch funktioniert, musst du das auf 0 setzen."
    Natürlich mag das bei PCI anders sein, dass das auf echter Hardware automatisch auf 0 gesetzt wird. Aber reserviert heißt meiner Meinung nach keinesfalls undefiniert.


  • Mod

    XanClic hat mich davon unterrichtet, dass qemu auch Zwischenwerte von 0x0, 0x4, 0x8, 0xC ... für die Ausgabe von Daten zulässt. Während also echte Hardware dies auf die nächst-tiefere Register-Nummer "abrundet", liefert qemu falsche Werte zurück. Ein Test eines "korrekten" OS ergäbe dann falsche Werte auf qemu.

    Es kann im Umkehrschluss aber auch sein, dass mit qemu etwas funktioniert, was dann auf echter HW versagt.

    Folgerung: Daher sollte man - wie alle anderen auch - reg & 0xFC verwenden, damit auf echter HW und auf qemu das Verhalten gleich ist.

    Es geht also eher um den Ausgleich dieses "bugs" (man könnte es auch "feature" nennen) von qemu.

    Ich schlage vor, wir warten noch die Antworten und Ideen hier ab:
    http://forum.osdev.org/viewtopic.php?f=1&t=21098
    http://forum.osdev.org/viewtopic.php?f=1&t=21097

    Da qemu z.B. die Standardsimulation für tyndur ist, während ich bisher Bochs bevorzugt habe, spricht einiges dafür, diese Kröte "reg & 0xFC" einfach zu schlucken mit dem Hinweis im Kommentar auf die Kompatibilität mit qemu. 😉



  • Erhard Henkes schrieb:

    Ein Test eines "korrekten" OS ergäbe dann falsche Werte auf qemu.

    Nein, denn ein "korrektes" OS greift nicht auf Adressen im Konfigurationsadressraum zu, die nicht an vier ausgerichtet sind. 😉


  • Mod

    Nein, denn ein "korrektes" OS greift nicht auf Adressen im Konfigurationsadressraum zu, die nicht an vier ausgerichtet sind.

    Macht PrettyOS ja auch nicht, aber mit dem Masker 0xFC wird es das überhaupt nicht mehr können. Das ist der Punkt dafür. Es geht hier um doppelte Absicherung. 😃



  • XanClic schrieb:

    Wenn in Intelmanuals oder so "reserviert" steht, dann heißt das nicht "auf irgendwas setzen". Das heißt immer - wenn nicht ausdrücklich anders gesagt "dieses Bit ist auf 0 zu setzen".

    Quelle? Eine würde schon reichen. 🙂 Grade das würde ja bedeuten, daß bestehender Code umgeschrieben werden muß, falls ein reserviertes Bit plötzlich eine dokumentierte Bedeutung kriegt. Reservierte Bits dürfen weder gelöscht noch gesetzt werden. Das muß im Code entsprechend berücksichtigt werden.



  • +gjm+ schrieb:

    Grade das würde ja bedeuten, daß bestehender Code umgeschrieben werden muß, falls ein reserviertes Bit plötzlich eine dokumentierte Bedeutung kriegt.

    Nein. Deshalb setzt man es auf 0. Die "Leute bei Intel" wissen dann, dass bisheriger Code das auf 0 setzt. Um eine neue Funktion zu nutzen, muss man das Bit dann setzen.
    Beispiel ist die GDT. Früher (zu 16-Bit-Protected-Mode-Zeiten) war das Bit für 32-Bit-Segmente reserviert, also auf 0 zu setzen. Heute ist es so, dass wenn man es setzt, das Segment ein 32-Bit-Segment ist. Das heißt, dass Code für den 16-Bit-Protected-Mode das Bit auf 0 setzt (es ist für ihn ja reserviert) und somit so läuft wie immer.


  • Mod

    Was +gjm+ schreibt, klingt für mich ebenso überzeugend wie das von XanClic. Es ist letztendlich Definitionssache. Aber mit reg & 0xFC setze ich die beiden Bits eindeutig auf 0, zumindest in der Theorie. Ich denke, dass reservierte Bits von der HW selbst geschützt, also ignoriert, werden müssen, bis man sie zur Verwendung frei gibt.

    Noch konkret zum PCI Scan: habt ihr einen Link, dass Bit0 und Bit1 des PCI Address-I/O-Port "reserviert" sind? Hätte +gjm+ Recht, so dürfte man das mit dem knallharten auf Null setzen der Bits so nicht machen, zumindest theoretisch. Auch die Version ohne & 0xFC wäre falsch. man müsste eine ergänzende Bit-Verknüpfung (Bit 7-2 vom einen und Bit 1-0 vom anderen) zweier Bytes ausführen.

    Interessante Diskussion. 😉
    Lassen wir die englische OSDEV-Welt doch erhellend teilhaben: http://forum.osdev.org/viewtopic.php?f=1&t=21100

    Allerdings ist der Fall auf praktischem Niveau gelöst: "reg & 0xFC" 🙂



  • Erhard Henkes schrieb:

    Macht PrettyOS ja auch nicht, aber mit dem Masker 0xFC wird es das überhaupt nicht mehr können. Das ist der Punkt dafür. Es geht hier um doppelte Absicherung.

    Es geht da eher um die Frage, ob sich der "Config-Space" entweder über eine Registernummer ansprechen läßt oder eben über einen Offset.

    Meine "Ansicht" ist ja bekannt:

    ...
    | (reg  <<  2  ));
    

    👍 🙂

    XanClic schrieb:

    Beispiel ist die GDT. Früher (zu 16-Bit-Protected-Mode-Zeiten) war das Bit für 32-Bit-Segmente reserviert, also auf 0 zu setzen.

    Allerdings hat ein 16-bit-Prozessor dieses Bit ignoriert.


  • Mod

    | (reg << 2 ));

    wäre aber etwas Neues und damit verwirrend, weil es "reg" in dieser lückenlosen Abzählform in keiner Übersicht gibt, soweit ich das bisher gesehen habe.

    http://lowlevel.brainsware.org/wiki/index.php/PCI
    http://wiki.osdev.org/PCI#PCI_Device_Structure

    Daher können wir dies m.E. so nicht machen. Die "reg & 0xFC" - Methode ist so schlimm ja auch wieder nicht. Das qemu-Argument reicht beispielsweise aus, es so zu machen. Dann ist reg identisch mit den Auflistungen bezüglich register number bei Low Level und osdev.org.



  • +gjm+ schrieb:

    XanClic schrieb:

    Beispiel ist die GDT. Früher (zu 16-Bit-Protected-Mode-Zeiten) war das Bit für 32-Bit-Segmente reserviert, also auf 0 zu setzen.

    Allerdings hat ein 16-bit-Prozessor dieses Bit ignoriert.

    Exakt! Damit hat man erreicht, dass Programme, die für den 286er geschrieben wurden, auf neueren Prozessoren weiterhin funktionieren.


Anmelden zum Antworten