PCI-Scan


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



  • +gjm+ schrieb:

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

    Sehr schlechtes Argument. Dann hätte man das Bit ja auch für etwas anderes nutzen können und eben bei 32-Bit-Prozessoren sagen müssen: "Tja, 16-Bit-PM funktioniert hier nicht mehr, Leute."
    Wenn man so denkt, kann man sich den ganzen Schmus mit A20-Gate und Real Mode sparen.

    +gjm+ schrieb:

    Meine "Ansicht" ist ja bekannt:

    Das sind aber keine Register. Das ist ein Adressraum, wie der I/O-Adressraum und der Speicheradressraum einer ist. Für dich, also für den Programmierer, sind das nur Bytes und keine Register.
    Siehe auch MMIO: Der Speicher besteht aus Bytes. Und alle Memory-Mapped-Register sind auch erstmal Bytes. Dass es Register sind, spielt beim Ansprechen keine Rolle.
    Die Frage ist auch, was du als Register bezeichnest. Sehen wir uns das "Register" 3 an (Offset 0x0C). Da sind vier Einzelbytes, die meiner Meinung nach nichts miteinander zu tun haben. Das wären also für mich vier Register.
    Wenn die Registernummer dem Offset mal 4 entspricht, dann müsste jedes dieser vier Register jeweils 32 Bits lang sein. Ich revidiere meine Meinung, wenn du mir glaubhaft vermitteln kannst, dass das ein Register und nicht vier sind. 😉


  • Mod

    Ist der Begriff "Register" bezüglich Bedeutung und Größe überhaupt sauber definiert? 😕

    Bezüglich der Größe in Bytes oder Bits ist da doch alles möglich?
    http://www.henkessoft.de/OS_Dev/Bilder/Register386.png



  • Erhard Henkes schrieb:

    Bezüglich der Größe in Bytes oder Bits ist da doch alles möglich?

    Klar, ich meinte nicht, dass jedes Register 32 Bits lang sein muss. Aber wenn man sagt, man übergibt eine Registernummer und liest ein DWord, dann muss jedes Register 32 Bits lang sein.
    Und ich meine nur, dass für mich ein Register zumindest eine logische Einheit sein muss. Klar ist ein Register wie das CR0-Register bei x86-Prozessoren eine Art Flickenteppich, aber an sich sind es alles wieder Bits, die den Prozessorzustand kontrollieren. Am Offset 0x0C im Konfigurationsadressraum hingegen habe ich ein Byte, mit dem ich einen Selbsttest durchführen kann, ein Byte, dass den Aufbau des Adressraums angibt, eines, das mir etwas über das Gerät sagt (Cache Line Size) und ein Byte, dessen Bedeutung ich nicht kenne. 😃 Und diese Bytes haben für mich keine gemeinsame Bedeutung (natürlich sind es im ganz Groben Bytes, die die Eigenschaften des Geräts anzeigen und seinen Zustand ändern können, aber das sind alle Register im Konfigurationsadressraum).



  • Erhard Henkes schrieb:

    Ist der Begriff "Register" bezüglich Bedeutung und Größe überhaupt sauber definiert?

    Der Begriff "Register" bezieht sich auf "alles", was in einer Hardwarekomponente u.a. als Speicher benutzt werden kann. Beispielsweise sind die "Register" im CMOS 8-bit breit.



  • Man braucht sich da gar nicht groß streiten, was denn nun ein Register ist, denn die PCI-Spezifikation benutzt dieses Wort selbst. Und die Register im Sinn der Spezifikation sind bei weitem nicht alle 32 Bit breit - die BARs sind es zum Beispiel, Vendor- und Device-ID sind 16 Bit und mit dem Class Code haben wir sogar ein lustiges 24-Bit-Register.



  • XanClic schrieb:

    Ich revidiere meine Meinung, wenn du mir glaubhaft vermitteln kannst, dass das ein Register und nicht vier sind. 😉

    Ich revidiere meine Meinung, wenn du mir zeigst, wie man bei einem PCI-Gerät die VendorID auslesen kann, ohne daß man mit einem "auf 4 ausgerichteten Offset" herumgurken muß. 🙂



  • Auf qemu kann ich dir das vermutlich ohne Probleme zeigen. 😃
    Aber wie taljeth sagt, sind die Register nicht alle 32 Bit breit. Er nennt zum Beispiel Vendor- und Device-ID, die jeweils ein 16-Bit-Register sind. Nach deiner Zählweise sind aber beide Register Nummer 0, also ein 32-Bit-Register.



  • Und man erhält die Vendor- und die DeviceID immer nur zusammen. Niemals getrennt. Darum kommt das mit einem Offset auch nicht hin. Im (32 bit breitem) Register Nr. 0 hat der Hardwarehersteller eben zwei Informationen abgelegt, die sich nur zusammen auslesen lassen.



  • Wie gesagt.

    XanClic schrieb:

    Ich revidiere meine Meinung, wenn du mir glaubhaft vermitteln kannst, dass das [DWord an Offset 0x0C] ein Register und nicht vier sind.

    😉

    EDIT: Ich möchte nachtragen, dass ich jetzt besser verstehe, was du meinst, auch wenn ich noch nicht genau der gleichen Meinung bin. 🙂



  • Du solltest Begriffe lieber so benutzen, wie sie definiert sind und wie sie der Rest der Welt benutzt, nicht so wie du es für logischer hältst.

    Du kannst CONFIG_ADDRESS nur auf einen 32-Bit-alignten Wert setzen, richtig. Du kannst die Register aber einzeln auslesen, indem du ein 16-Bit- oder 8-Bit-in auf CONFIG_DATA machst. Nur beim Class Code funktioniert das wieder nicht so gut, weil es kein 24-Bit-in gibt...



  • Um zum ursprünglichen Thema von wegen "& 0xFC" zurückzukommen... Linux tut es. Hierzu der Code zum Lesen eines Registers:

    #define PCI_CONF1_ADDRESS(bus, devfn, reg) \
            (0x80000000 | ((reg & 0xF00) << 16) | (bus << 16) \
            | (devfn << 8) | (reg & 0xFC))
    
    static int pci_conf1_read(unsigned int seg, unsigned int bus,
                              unsigned int devfn, int reg, int len, u32 *value)
    {
            unsigned long flags;
    
            if ((bus > 255) || (devfn > 255) || (reg > 4095)) {
                    *value = -1;
                    return -EINVAL;
            }
    
            spin_lock_irqsave(&pci_config_lock, flags);
    
            outl(PCI_CONF1_ADDRESS(bus, devfn, reg), 0xCF8);
    
            switch (len) {
            case 1:
                    *value = inb(0xCFC + (reg & 3));
                    break;
            case 2:
                    *value = inw(0xCFC + (reg & 2));
                    break;
            case 4:
                    *value = inl(0xCFC);
                    break;
            }
    
            spin_unlock_irqrestore(&pci_config_lock, flags);
    
            return 0;
    }
    

    Mit diesem Code kann man, wie schon von taljeth angesprochen, auch 16- und 8-Bit-Register auslesen.



  • taljeth schrieb:

    Du solltest Begriffe lieber so benutzen, wie sie definiert sind und wie sie der Rest der Welt benutzt, nicht so wie du es für logischer hältst.

    Daran arbeite ich ja. 🙂

    Bits Nr.
    | Register | Offset | 31-24 |    23-16    |    15-8       |      7-0        |
    |   0x03   |  0x0C  | BIST  | Header Type | Latency Timer | Cache Line Size |
    

    CONFIG_ADDRESS ist auf Register 0x03 und/oder Offset 0x0C gesetzt. Was liefert nun ein 8-bit-IN (immer und ewig)?



  • XanClic schrieb:

    Um zum ursprünglichen Thema von wegen "& 0xFC" zurückzukommen... Linux tut es.

    tyndur tut es auch und Erhard hat doch sogar explizit gefragt, wie die Funktion funkioniert.

    +gjm+ schrieb:

    Bits Nr.
    | Register | Offset | 31-24 |    23-16    |    15-8       |      7-0        |
    |   0x03   |  0x0C  | BIST  | Header Type | Latency Timer | Cache Line Size |
    

    CONFIG_ADDRESS ist auf Register 0x03 und/oder Offset 0x0C gesetzt. Was liefert nun ein 8-bit-IN (immer und ewig)?

    Du verwirrst mich schon wieder mit deinen Begriffen. CONFIG_ADDRESS hat nur einen Wert, ich hoffe mal, dass 0x0c das ist, was du meinst. Ein Byte-read von CONFIG_DATA würde dann den Wert von Cache Line Size lesen. Eins von CONFIG_DATA + 2 würde den Subclass Code lesen.


Anmelden zum Antworten