PCI-Scan
-
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); }
-
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?
-
... 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.
-
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=21097Da 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.
-
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.
-
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=21100Allerdings 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.
-
| (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_StructureDaher 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.
-
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.