Hypercell ein ] Hypercell aus ] Zeige Navigation ] Verstecke Navigation ]
c++.net  
   

Die mobilen Seiten von c++.net:
https://m.c-plusplus.net

  
C++ Forum :: Projekt: OS-Development  ::  PCI-Scan     Zeige alle Beiträge auf einer Seite Auf Beitrag antworten
Autor Nachricht
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 13866
Beitrag Erhard Henkes Mitglied 23:48:35 20.10.2009   Titel:   PCI-Scan            Zitieren

Zum Auffinden der USB-Geräte und der Bestimmung von Program Interfaces (UHCI, EHCI, OHCI, ...) benötigen wir einen PCI Scan. Ich habe in Version 108 mal eine erste Testversion erstellt, die bereits USB detektiert. Bitte testet das mal bei euch auf PCs aus, falls möglich, ob die USB-Devices richtig erkannt werden (Linux: lspci).
http://www.henkessoft.de/OS_Dev/Downloads/108.zip
http://www.henkessoft.de/OS_Dev/Bilder/PCI-Scan.JPG

PS:
http://www.c-plusplus.de/ ....... opic-var-t-is-252501.html
(Diesen Link kann man auch für anderen Testcode, z.B. zum Einblenden in IRC, verwenden)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
abc.w
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2008
Beiträge: 1366
Beitrag abc.w Mitglied 20:21:53 21.10.2009   Titel:              Zitieren

Hallo,

der PCI Scan scheint bei mir zu funktionieren. Und die Nummern scheinen mir denen von lspci zu stimmen.

Übrigens, lspci unter Linux macht keinen richtigen "Scan", sondern nutzt sysfs. In /sys/devices/pci0000:00 stehen die ganzen Geräte (bei mir). Verdammt sei diese Philosophie, alles ist eine Datei... :D
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 13866
Beitrag Erhard Henkes Mitglied 22:27:54 21.10.2009   Titel:              Zitieren

Zitat:
der PCI Scan scheint bei mir zu funktionieren. Und die Nummern scheinen mir denen von lspci zu stimmen
Was heißt "scheint"? Klappt das mit der korrekten Erkennung von USB + Program Interface?

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 13866
Beitrag Erhard Henkes Mitglied 23:45:47 21.10.2009   Titel:              Zitieren

Nächster Schritt:
http://wiki.osdev.org/PCI#Base_Address_Registers - BAR lesen:
Zitat:
When you want to retrieve the actual base address of a BAR, be sure to mask the lower bits. For Memory Space BARs, you calculate (BAR & 0xFFFFFFF0). For I/O Space BARs, you calculate (BAR & 0xFFFFFFFC).

To determine the amount of address space needed by a PCI device, you must read the BAR. Devices must return 0 for address bits used internally and 1 for bits you can set. For example, if a device utilizes 16MBytes it will have BAR0 filled with 0xFF000000. You can only modify the hexadecimal FF part. This means you can only map memory on 16Mbyte boundaries. The zeroed part is used internally by the device to access memory.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Unregistrierter





Beitrag Unregistrierter 23:46:02 21.10.2009   Titel:              Zitieren

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): :)
Code:
// 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:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
// 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:
Code:
Register Nummer           : 0x00 0x01 0x02 0x03 ...
entspricht
Offset im "Config-Space"  : 0x00 0x04 0x08 0x0C ...
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 13866
Beitrag Erhard Henkes Mitglied 23:59:19 21.10.2009   Titel:              Zitieren

Ja, das stimmt mit Offset = 4 * Register-Nummer, aber siehe hier:

http://wiki.osdev.org/PCI#PCI_Device_Structure
Code:
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.brainswar ....... .php/PCI#Header_Type_0x00
Das gleiche Spiel.

Wahrscheinlich ist es so mit offset als Parameter und offset&0xFC (11111100) am klarsten:
C++:
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;
}

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 13866
Beitrag Erhard Henkes Mitglied 00:10:45 22.10.2009   Titel:              Zitieren

Zitat:
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.

Zitat:
scheint der PCI-Scan zu funktionieren.
schon wieder "scheint". :D

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Unregistrierter





Beitrag Unregistrierter 00:23:56 22.10.2009   Titel:              Zitieren

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. :)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 13866
Beitrag Erhard Henkes Mitglied 00:50:10 22.10.2009   Titel:              Zitieren

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

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 01:14:41 22.10.2009, insgesamt 2-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 13866
Beitrag Erhard Henkes Mitglied 00:59:54 22.10.2009   Titel:              Zitieren

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

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

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 01:12:43 22.10.2009, insgesamt 2-mal bearbeitet
Unregistrierter





Beitrag Unregistrierter 19:51:08 23.10.2009   Titel:              Zitieren

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:
Code:
1
2
3
4
5
6
7
8
9
10
11
  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". :live:

Nochwas zum Erbsenzählen:

Wenn in einer Schleife Bit 7-0 hochgezählt werden (ohne das unschöne (xxx & 0xFC)), dann ergibt das folgendes:
Code:
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.
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 13866
Beitrag Erhard Henkes Mitglied 20:00:19 23.10.2009   Titel:              Zitieren

Zitat:
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! :)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
XanClic
Mitglied

Benutzerprofil
Anmeldungsdatum: 13.10.2009
Beiträge: 98
Beitrag XanClic Mitglied 20:07:53 23.10.2009   Titel:              Zitieren

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

_________________
http://www.lowlevel.eu/


Zuletzt bearbeitet von XanClic am 20:09:52 23.10.2009, insgesamt 1-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 13866
Beitrag Erhard Henkes Mitglied 20:16:03 23.10.2009   Titel:              Zitieren

@+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:
Code:
1
2
3
4
5
6
7
8
9
10
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.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 00:03:25 24.10.2009, insgesamt 1-mal bearbeitet
Unregistrierter





Beitrag Unregistrierter 20:44:10 23.10.2009   Titel:              Zitieren

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.
XanClic
Mitglied

Benutzerprofil
Anmeldungsdatum: 13.10.2009
Beiträge: 98
Beitrag XanClic Mitglied 21:19:35 23.10.2009   Titel:              Zitieren

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

_________________
http://www.lowlevel.eu/
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 13866
Beitrag Erhard Henkes Mitglied 21:53:42 23.10.2009   Titel:              Zitieren

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?

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 21:54:15 23.10.2009, insgesamt 1-mal bearbeitet
XanClic
Mitglied

Benutzerprofil
Anmeldungsdatum: 13.10.2009
Beiträge: 98
Beitrag XanClic Mitglied 11:45:38 24.10.2009   Titel:              Zitieren

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:

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

_________________
http://www.lowlevel.eu/


Zuletzt bearbeitet von XanClic am 11:53:05 24.10.2009, insgesamt 2-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 13866
Beitrag Erhard Henkes Mitglied 13:25:26 24.10.2009   Titel:              Zitieren

Zitat:
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.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Unregistrierter





Beitrag Unregistrierter 14:36:45 24.10.2009   Titel:              Zitieren

@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).
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 13866
Beitrag Erhard Henkes Mitglied 15:01:44 24.10.2009   Titel:              Zitieren

Zitat:
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.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 13866
Beitrag Erhard Henkes Mitglied 15:29:24 24.10.2009   Titel:              Zitieren

Zitat:
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:
C++:
1
2
3
4
5
6
7
8
9
10
11
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);
}

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 15:35:28 24.10.2009, insgesamt 1-mal bearbeitet
Unregistrierter





Beitrag Unregistrierter 15:42:44 24.10.2009   Titel:              Zitieren

Zitat:
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). :)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 13866
Beitrag Erhard Henkes Mitglied 15:58:43 24.10.2009   Titel:              Zitieren

Zitat:
echte HW Bit 7-2 beachtet und Bit 1-0 ignoriert

Ja, eindeutig präziser. Danke!

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
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);
}

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 13866
Beitrag Erhard Henkes Mitglied 16:03:01 24.10.2009   Titel:              Zitieren

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.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 17:15:57 24.10.2009, insgesamt 1-mal bearbeitet
Schablone
Mitglied

Benutzerprofil
Anmeldungsdatum: 03.05.2009
Beiträge: 25
Beitrag Schablone Mitglied 16:11:20 24.10.2009   Titel:              Zitieren

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

_________________
Für mehr Kühlschränke!
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 13866
Beitrag Erhard Henkes Mitglied 17:18:29 24.10.2009   Titel:              Zitieren

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

Zitat:
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

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 19:41:10 24.10.2009, insgesamt 5-mal bearbeitet
XanClic
Mitglied

Benutzerprofil
Anmeldungsdatum: 13.10.2009
Beiträge: 98
Beitrag XanClic Mitglied 19:09:59 24.10.2009   Titel:              Zitieren

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

_________________
http://www.lowlevel.eu/
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 13866
Beitrag Erhard Henkes Mitglied 19:11:22 24.10.2009   Titel:              Zitieren

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

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
XanClic
Mitglied

Benutzerprofil
Anmeldungsdatum: 13.10.2009
Beiträge: 98
Beitrag XanClic Mitglied 19:13:56 24.10.2009   Titel:              Zitieren

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

_________________
http://www.lowlevel.eu/
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 13866
Beitrag Erhard Henkes Mitglied 19:16:53 24.10.2009   Titel:              Zitieren

Zitat:
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. :D

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 19:18:15 24.10.2009, insgesamt 1-mal bearbeitet
Unregistrierter





Beitrag Unregistrierter 19:38:06 24.10.2009   Titel:              Zitieren

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.
XanClic
Mitglied

Benutzerprofil
Anmeldungsdatum: 13.10.2009
Beiträge: 98
Beitrag XanClic Mitglied 19:45:18 24.10.2009   Titel:              Zitieren

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

_________________
http://www.lowlevel.eu/
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 13866
Beitrag Erhard Henkes Mitglied 19:52:48 24.10.2009   Titel:              Zitieren

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" :)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 19:59:01 24.10.2009, insgesamt 2-mal bearbeitet
Unregistrierter





Beitrag Unregistrierter 19:56:52 24.10.2009   Titel:              Zitieren

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:
C++:
...
| (reg  <<  2  ));
:live: :)

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.
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 13866
Beitrag Erhard Henkes Mitglied 20:01:51 24.10.2009   Titel:              Zitieren

Zitat:
| (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.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 20:06:40 24.10.2009, insgesamt 3-mal bearbeitet
Schablone
Mitglied

Benutzerprofil
Anmeldungsdatum: 03.05.2009
Beiträge: 25
Beitrag Schablone Mitglied 20:05:32 24.10.2009   Titel:              Zitieren

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

_________________
Für mehr Kühlschränke!
XanClic
Mitglied

Benutzerprofil
Anmeldungsdatum: 13.10.2009
Beiträge: 98
Beitrag XanClic Mitglied 20:06:32 24.10.2009   Titel:              Zitieren

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

_________________
http://www.lowlevel.eu/


Zuletzt bearbeitet von XanClic am 20:09:18 24.10.2009, insgesamt 1-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 13866
Beitrag Erhard Henkes Mitglied 20:09:30 24.10.2009   Titel:              Zitieren

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

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

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 20:10:01 24.10.2009, insgesamt 1-mal bearbeitet
XanClic
Mitglied

Benutzerprofil
Anmeldungsdatum: 13.10.2009
Beiträge: 98
Beitrag XanClic Mitglied 20:16:42 24.10.2009   Titel:              Zitieren

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

_________________
http://www.lowlevel.eu/


Zuletzt bearbeitet von XanClic am 20:18:55 24.10.2009, insgesamt 1-mal bearbeitet
Unregistrierter





Beitrag Unregistrierter 20:40:40 24.10.2009   Titel:              Zitieren

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.
taljeth
Mitglied

Benutzerprofil
Anmeldungsdatum: 11.09.2009
Beiträge: 149
Beitrag taljeth Mitglied 20:48:15 24.10.2009   Titel:              Zitieren

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.

_________________
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.
Lowlevel - die deutschsprachige OS-Dev-Community


Zuletzt bearbeitet von taljeth am 20:48:45 24.10.2009, insgesamt 1-mal bearbeitet
Unregistrierter





Beitrag Unregistrierter 20:55:51 24.10.2009   Titel:              Zitieren

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ß. :)
XanClic
Mitglied

Benutzerprofil
Anmeldungsdatum: 13.10.2009
Beiträge: 98
Beitrag XanClic Mitglied 21:00:09 24.10.2009   Titel:              Zitieren

Auf qemu kann ich dir das vermutlich ohne Probleme zeigen. :D
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.

_________________
http://www.lowlevel.eu/
Unregistrierter





Beitrag Unregistrierter 21:10:38 24.10.2009   Titel:              Zitieren

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.
XanClic
Mitglied

Benutzerprofil
Anmeldungsdatum: 13.10.2009
Beiträge: 98
Beitrag XanClic Mitglied 21:17:29 24.10.2009   Titel:              Zitieren

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

_________________
http://www.lowlevel.eu/


Zuletzt bearbeitet von XanClic am 21:24:15 24.10.2009, insgesamt 1-mal bearbeitet
taljeth
Mitglied

Benutzerprofil
Anmeldungsdatum: 11.09.2009
Beiträge: 149
Beitrag taljeth Mitglied 21:19:08 24.10.2009   Titel:              Zitieren

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

_________________
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.
Lowlevel - die deutschsprachige OS-Dev-Community
XanClic
Mitglied

Benutzerprofil
Anmeldungsdatum: 13.10.2009
Beiträge: 98
Beitrag XanClic Mitglied 21:41:42 24.10.2009   Titel:              Zitieren

Um zum ursprünglichen Thema von wegen "& 0xFC" zurückzukommen... Linux tut es. Hierzu der Code zum Lesen eines Registers:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#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.

_________________
http://www.lowlevel.eu/


Zuletzt bearbeitet von XanClic am 21:41:55 24.10.2009, insgesamt 1-mal bearbeitet
Unregistrierter





Beitrag Unregistrierter 21:45:49 24.10.2009   Titel:              Zitieren

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. :)
Code:
                     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)?
taljeth
Mitglied

Benutzerprofil
Anmeldungsdatum: 11.09.2009
Beiträge: 149
Beitrag taljeth Mitglied 21:56:24 24.10.2009   Titel:              Zitieren

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:
Code:
                     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.

_________________
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.
Lowlevel - die deutschsprachige OS-Dev-Community
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 13866
Beitrag Erhard Henkes Mitglied 22:00:13 24.10.2009   Titel:              Zitieren

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

Wo finde ich das mit dem Register 0x03? Das habe ich bisher so nicht gesehen, nur immer register number == offset. Vermutlich liegt darin ein Teil der Missverständnisse bezüglich Offset & 0xFC und Register << 2 begraben.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 22:01:23 24.10.2009, insgesamt 2-mal bearbeitet
taljeth
Mitglied

Benutzerprofil
Anmeldungsdatum: 11.09.2009
Beiträge: 149
Beitrag taljeth Mitglied 22:03:32 24.10.2009   Titel:              Zitieren

Soweit ich das verstanden habe, ist das mit dieser Registernummer einfach nur eine Erfindung von +gjm+. Er versteht darunter Offset >> 2 und hält es offenbar aus irgendeinem Grund für sinnvoll, damit zu arbeiten, auch wenn keiner auf Anhieb versteht, was er meint.

_________________
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.
Lowlevel - die deutschsprachige OS-Dev-Community
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 13866
Beitrag Erhard Henkes Mitglied 22:32:38 24.10.2009   Titel:              Zitieren

Zitat:
Erfindung von +gjm+
@+gjm+: Ist das wirklich so, oder gibt es das auch von offizieller Seite? :D

Die Wissenschaft neigt auch mehr zum Offset:
http://techwww.in.tu-clau ....... der/pci_config_header.gif

Hier ist auch eine interessante Darstellung der letzten zwei Bits als "Type":
http://www.martin-schreib ....... eme/pci/configaddress.gif
Zitat:
00b = Konfigurationszyklus
01b = Einheit ist hinter dieser Bridge. Diese kopiert den Inhalt von CONFIG_ADDRESS unverändert auf den Adress-/Datenbus
10b = ?
11b = ?

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 13866
Beitrag Erhard Henkes Mitglied 22:35:32 24.10.2009   Titel:              Zitieren

Einschub nur zum Festhalten in diesem Thread bezüglich BARs und IRQ:
https://ezs.kr.hsnr.de/lectures/treiber/html/x2161.html

Base Address

Zitat:
Bis zu 6 unterschiedliche Speicher- oder IO-Bereiche kann ein Gerät besitzen. Die Adressen dieser Bereiche werden in den Zellen Base Address 0 bis Base Address 5 abgelegt. In so einer Speicherzelle ist die Adresslage, die Art und auch die Größe des Speicherbereiches kodiert.

Ein Speicherbereich hat eine Mindestgröße von 16 Byte und ist immer ein Vielfaches von 2. Dadurch stehen die 4 unteren Bits für zusätzliche Codierungen zur Verfügung. Bit 0 gibt Auskunft darüber, ob es sich um eine IO Adresse (der Zugriff muß über Port-Befehle erfolgen) oder eine Memory Adresse handelt. Handelt es sich um eine Memory Adresse, geben Bit 1 und 2 den Adresstyp an. 00 signalisiert, dass es sich um eine gewöhnliche 32 bit Adresse handelt. Die Kombination 01 bedeutet, dass die Adresse unterhalb der aus alten Zeiten bekannten 1 Megabyte Grenze liegt und die Kombination 10 wird für eine 64 bit Adresse verwednet. Bei einer 64 bit Adresse werden zwei „Base Address“ Einträge zur Adressbestimmung gebraucht.

Bit 3 schließlich gibt Auskunft darüber, ob auf diesen Adressbereich im Prefetch-Mode zugegriffen werden darf oder nicht. Ein gesetztes Bit bedeutet dabei, dass nicht im Prefetch-Mode zugegriffen werden darf. Im Prefetch-Mode speichert die PCI-Bridge (d.h. der Baustein, der den PCI-Bus an den Processorbus ankoppelt) Daten zwischen, bevor die eigentliche Übertragung zur CPU (lesen oder schreiben) gestartet wird.

Laut Spezifikation sind nur die Bereiche der Base Address auch schreibbar, die die Adresslage festlegen. Die übrigen Bits bleiben 0. Dieser Umstand wird genutzt, um die Größe eines Adressbereiches zu bestimmen. Dazu beschreibt man das Adressregister mit lauter Einsen und liest das Register wieder aus. Die Bits, die jetzt mit 0 belegt sind, identifizieren die Adressbereichgröße.

Das folgende Codefragment zeigt, wie die Größe des Speicherbereiches bestimmt werden kann:


C++:
        pci_read_config_dword( PciDev, PCI_BASE_ADDRESS_0, &OrginalValue );
        cli();
        pci_write_config_dword( PciDev, PCI_BASE_ADDRESS_0, 0xffffffff );
        pci_read_config_dword( PciDev, PCI_BASE_ADDRESS_0, &Base );
        pci_write_config_dword( PciDev, PCI_BASE_ADDRESS_0, OrginalValue );
        sti();
        printk("size of base address 0: %i\n", ~Base+1 );

IRQ-Line

Zitat:
In dieser Speicherzelle findet sich der Interrupt, der dem Board vom PCI-Bios zugeteilt wurde.


Hauptseite, die mir bezüglich Treiber wirklich interessant erscheint:
https://ezs.kr.hsnr.de/lectures/treiber/html/book1.html

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 22:42:58 24.10.2009, insgesamt 2-mal bearbeitet
Unregistrierter





Beitrag Unregistrierter 22:49:13 24.10.2009   Titel:              Zitieren

Na gut. Letzter Versuch. Mit dem von XanClic geposteten Code kann man gezielt ein Byte aus dem "Config-Space" auslesen:
C++:
 case 1:
 *value = inb(0xCFC + (reg & 3));
  break;
Aber dazu muß u.U. die Portadresse geändert werden. Das ist nur typisch für den Zugriff auf (Hardware) Register. :)

P.S.: Im Internet werden Falschmeldungen zu Tatsachen einzig und alleine durch Verbreitung.
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 13866
Beitrag Erhard Henkes Mitglied 23:15:42 24.10.2009   Titel:              Zitieren

Bei mir sieht das nun praktisch wie folgt aus:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include "pci.h"
 
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 & 0xFC  )); // Real hardware ignores bits 0 and 1, and reads only bits 7-2.
                           // The bit mask FCh = 11111100b ensures register numbers aligned with 4.
 
    return inportl(PCI_CONFIGURATION_DATA);
}
 
uint32_t pci_config_read_32 (uint32_t bus, uint32_t device, uint32_t func, uint32_t reg)
{
    return pci_config_read(bus, device, func, reg);
}
 
uint16_t pci_config_read_16 (uint32_t bus, uint32_t device, uint32_t func, uint32_t reg)
{
    return pci_config_read(bus, device, func, reg) & 0xFFFF;
}
 
uint8_t pci_config_read_8 (uint32_t bus, uint32_t device, uint32_t func, uint32_t reg)
{
    return pci_config_read(bus, device, func, reg) & 0xFF;
}
 
void pci_config_write(uint32_t bus, uint32_t device, uint32_t func, uint32_t reg, uint32_t val)
{
    outportl(PCI_CONFIGURATION_ADDRESS,
        0x80000000
        | (bus     << 16)
        | (device  << 11)
        | (func    <<  8)
        | (reg & 0xFC   ));
 
    outportl(PCI_CONFIGURATION_DATA, val);
}


Die write-Funktion benötigen für die BARs (siehe oben).

Bei tyndur ist der Schutz übrigens mit ... &=~11b und ... &11111100b m.E. übertrieben:
C++:
static dword pci_config_read(..., dword reg)
{
    ...
    reg &= ~0x3;
    outl(... | ((reg & 0xFC)));
    ...
}

Ich würde vorschlagen, eine von beiden Schutzmasken zu entfernen. Dann läuft der PCI Scan deutlich schneller. ;)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 23:43:55 24.10.2009, insgesamt 4-mal bearbeitet
Schablone
Mitglied

Benutzerprofil
Anmeldungsdatum: 03.05.2009
Beiträge: 25
Beitrag Schablone Mitglied 23:49:26 24.10.2009   Titel:              Zitieren

Deine pci_config_read_16 und pci_config_read_8 können übrigens keine Werte, die nicht 4 Byte aligned sind, lesen. Nicht dass du dich z.B. irgendwann wunderst, dass du damit nicht die Device ID nicht auslesen kannst.

_________________
Für mehr Kühlschränke!
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 13866
Beitrag Erhard Henkes Mitglied 00:27:01 25.10.2009   Titel:              Zitieren

Ja, das ist richtig und mir zum Glück auch klar. Das ist noch nicht optimal. Die DeviceID habe ich mir z.B. so berechnen müssen: (pciDevVend&0xFFFF0000)>>16 :)

Die Funktionen sind wirklich noch nicht bahnbrechend. Da könnte man z.B. noch einen Start-Parameter pos (von Byte 0 aus gerechnet) einführen mit 0,1,2,3. Würde das Sinn machen? Vielleicht sogar nur eine Funktion mit pci_config_read_value(bus,dev,func,reg,width,pos) und uint32_t als return type.


IRQ (Version 110 in Arbeit) klappt auch sehr gut (Vergleich PCI Scan mit BIOS-PCI-Auflistung per Foto), lediglich das IDE-Interface mit IRQ 14/15 wurde vom PrettyOS PCI Scan mit IRQ 0 angezeigt. Die beiden USB-Devices haben beide IRQ 9, so dass man das IRQ sharing hiermit erkennen kann.

Nun kommt das Thema BARs.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 01:26:10 25.10.2009, insgesamt 3-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 13866
Beitrag Erhard Henkes Mitglied 01:49:38 25.10.2009   Titel:              Zitieren

Zum Thema maskieren mit 0xFC eine Antwort bei osdev.org:
http://forum.osdev.org/viewtopic.php?f=1&t=21098
Zitat:
The rule is, you can only read doublewords from configuration space. If you don't I have enough pieces of real hardware that make your code fail.
It is your choice whether you need the 0xfc or not.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
taljeth
Mitglied

Benutzerprofil
Anmeldungsdatum: 11.09.2009
Beiträge: 149
Beitrag taljeth Mitglied 11:02:23 25.10.2009   Titel:              Zitieren

Erhard Henkes schrieb:
Hier ist auch eine interessante Darstellung der letzten zwei Bits als "Type":
http://www.martin-schreib ....... eme/pci/configaddress.gif
Zitat:
00b = Konfigurationszyklus
01b = Einheit ist hinter dieser Bridge. Diese kopiert den Inhalt von CONFIG_ADDRESS unverändert auf den Adress-/Datenbus
10b = ?
11b = ?

Da ist was durcheinandergeworfen worden. Das Bild zeigt, was auf dem Bus übertragen wird, nicht das CONFIG_ADDRESS-Register.

Und zum 0xfc, lies dir einfach mal selbst Abschnitt 3.2.2.3.2. in der Spezifikation durch. Auf CONFIG_ADDRESS darfst du nur dwords schreiben und Bits 0 und 1 sind read-only und auf 0 hartverdrahtet. Ich würde es trotzdem drinlassen, weil auch Hardware buggy sein kann. Um genau zu sein, liest meine Funktion ja sogar immer von der abgerundeten Adresse und schiebt das Ergebnis hinterher so zurecht, dass ich genau das Register bekomme, das ich angefordert habe.

_________________
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.
Lowlevel - die deutschsprachige OS-Dev-Community
XanClic
Mitglied

Benutzerprofil
Anmeldungsdatum: 13.10.2009
Beiträge: 98
Beitrag XanClic Mitglied 13:41:53 25.10.2009   Titel:              Zitieren

+gjm+ schrieb:
Aber dazu muß u.U. die Portadresse geändert werden. Das ist nur typisch für den Zugriff auf (Hardware) Register. :)

Der I/O-Port hat doch nix mit dem Konfigurationsadressraum zu tun. Ich schreibe die Adresse im Konfigurationsraum nach 0xCF8. Dann steht ab 0xCFC automatisch der Wert des adressierten DWords. Das heißt nicht, dass diese DWord in 0xCFC steht und ich an 0xCFD was völlig anderes auslese. In 0xCFC steht das niederwertigste Byte dieses DWords. In 0xCFD das zweite, in 0xCFE das dritte und in 0xCFF das höchstwertige Byte (Little Endian). Wenn ich also ein Word ab 0x02 auslesen möchte, fordert diese Linuxfunktion das DWord ab 0x00 an, ab 0xCFC steht dann dessen Wert. Die Linuxfunktion liest dann also ein Word ab 0xCFE ein, das heißt, das niederwertige Byte aus 0xCFE und das höherwertige Byte aus 0xCFF (geschieht automatisch mit inw).
Ich hoffe, ich habe deinen Einwand verstanden und hoffe auch, dass ich verständlich antworten konnte. ;)

_________________
http://www.lowlevel.eu/
Unregistrierter





Beitrag Unregistrierter 14:44:42 25.10.2009   Titel:              Zitieren

Sehr gut beschrieben. :live:
XanClic schrieb:
Ich schreibe die Adresse im Konfigurationsraum nach 0xCF8.
Dann steht ab 0xCFC automatisch der Wert des adressierten DWords.
Für die Bildung der "Adresse" stehen aber nur Bit 7-2 zur Verfügung. (Bit 1-0 sind reserviert). Somit geht der Bereich von "Adresse" nur von 0x00-0x3F. Die Darstellung des "Config-Space" mit einem "Offset" links oder rechts der Tabelle ist deshalb falsch. Hoffentlich war das verständlich. Didaktisch begabt bin ich leider nicht. Aber ich arbeite daran. :)
taljeth
Mitglied

Benutzerprofil
Anmeldungsdatum: 11.09.2009
Beiträge: 149
Beitrag taljeth Mitglied 15:00:59 25.10.2009   Titel:              Zitieren

Die offizielle Spezifikation als falsch zu bezeichnen ist zumindest mutig. ;)

_________________
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.
Lowlevel - die deutschsprachige OS-Dev-Community
XanClic
Mitglied

Benutzerprofil
Anmeldungsdatum: 13.10.2009
Beiträge: 98
Beitrag XanClic Mitglied 15:11:22 25.10.2009   Titel:              Zitieren

+gjm+ schrieb:
Für die Bildung der "Adresse" stehen aber nur Bit 7-2 zur Verfügung. (Bit 1-0 sind reserviert).

Es gibt jede Menge Beispiele, in denen man z. B. in ein 32-Bit-Feld eine Adresse eintragen muss, wo aber die unteren 4 Bits oder so reserviert sind (siehe z. B. die OHCI-Spezifikation, Abschnitt 4.2.1 "Endpoint Descriptor Formats" und dort das Feld "TD Queue Tail Pointer", hier sind die unteren Bits nicht reserviert, sondern stehen für den Programmierer frei zur Verfügung). Im erwähnten Beispiel ist in den Bits 4 bis 31 eine Adresse einzutragen. Man trägt dort aber nicht die Bits 0 bis 27 der Adresse ein, sondern die Bits 4 bis 31. Dass die unteren 4 Bits von der Hardware ignoriert werden, heißt hier nur, dass die Adresse an 16 Bytes ausgerichtet sein muss.
Und genau so wird es bei PCI auch sein, dass die unteren 2 Bites ignoriert werden, heißt nur, dass die Adresse an 4 Bytes ausgerichtet sein muss.

_________________
http://www.lowlevel.eu/
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 13866
Beitrag Erhard Henkes Mitglied 15:23:27 25.10.2009   Titel:              Zitieren

Ich denke, inzwischen ist zumindest die Sachlage jedem klar. Daher gehe ich darauf nicht mehr ein. Der Grund, warum man in der Tat reg & 0xFC bzw. alternativ reg & ~0x03 verwenden sollte, ist hauptsächlich die mögliche Inkompatibilität mit ausgefallener Hardware bzw. mit Simulationsprogrammen wie qemu.

Nun bleibt die Frage, wie man zu der gewünschten Information gelangt. Hierbei muss noch folgendes passieren:

a) Der Offset zu Bit 0 muss angegeben werden. Hier gibt es zwei Varianten:
a1) Man akzeptiert "falsche" Register-Nummern und erhält den Offset durch reg % 4 (Methode bei tyndur)
a2) Man rundet "falsche" Register-Nummern ab und ignoriert den "Rest". Der Offset muss dann als separater Parameter (z.B. pos: 0,1,2,3) übergeben werden (diese Vorgehensweise gefällt mir didaktisch besser)

b) Die Breite (byte, word, dword) muss angegeben werden (tyndur erledigt dies durch drei verschiedene Funktionen)

Ich neige inzwischen zur Kombination von a2) und b) im Rahmen einer einzigen Funktion mit den Parametern bus, dev, func, reg, pos, width, d.h. in der inneren lesenden Funktion nur "saubere" Register zulassen (z.B. bei Abweichung eine Warnung ausgeben, damit Bugs auffallen) und nur in der umhüllenden Funktion schieben und schneiden.

Das ist sicher Geschmacksache, ob man die tyndur-Variante (innere Funktion: "non-aligned" lesen und schieben; drei äußere Funktionen zum Schneiden) verwendet oder den von mir vorgeschlagenen weg einschlägt.

Man könnte alle drei Aufgaben (lesen, schieben, schneiden) sogar in einer einzigen Funktion verdichten. Das würde allerdings für Außenstehende nicht leicht verständlich.

Die tyndur-Methode (a1) hat allerdings einen praktischen Vorteil: Man kann das nicht direkt lesbare Register als Konstante durchreichen (tyndur - pcihw.h):
Code:
1
2
3
4
5
6
7
8
9
10
11
#define PCI_VENDOR_ID   0x00
#define PCI_DEVICE_ID   0x02
#define PCI_COMMAND     0x04
#define PCI_STATUS      0x06
#define PCI_REVISION    0x08
#define PCI_CLASS       0x0B
#define PCI_SUBCLASS    0x0A
#define PCI_INTERFACE   0x09
#define PCI_HEADERTYPE  0x0E
#define PCI_BAR0        0x10
#define PCI_INTERRUPT   0x3C


Register und Offset sind darin bereits enthalten. Es fehlt aber noch die Breite!
Ideal wäre eine Funktion read(bus,dev,func,PCI_BLABLA), die alles erledigt.
Dazu benötigt man aber noch die Breite, vielleicht:
Code:
#define PCI_VENDOR_ID   0x0002
#define PCI_DEVICE_ID   0x0202
...
#define PCI_INTERRUPT   0x3C01
...
also Register/Offset vorne und Breite (length) in Bytes hinten. Dann könnte man mit read(bus,dev,func,PCI_BLABLA) alles in einem Schritt erledigen (auch ideal für eine Schleife, um eine Struktur zu füllen). Wäre das elegant oder eher schrecklich?

Bin etwas hin und her gerissen zwischen Didaktik (mehrere klare Schritte, dafür kompliziert) und einer optimalen praktischen Lösung (nur eine Funktion für alles, Konstante bringt alle Infos mit!).

Also was ist der schönste Weg? :confused:

EDIT: Im IRC hat mich XanClic bestätigt den Weg mit nur einer Funktion und Konstanten, die alles mitbringen, zu gehen. :)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 18:14:15 25.10.2009, insgesamt 9-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 13866
Beitrag Erhard Henkes Mitglied 22:00:24 25.10.2009   Titel:              Zitieren

Das ist jetzt dabei heraus gekommen und funktioniert bisher gut. Ist das Innenleben der Funktion pci_config_read(...) ausreichend verständlich?

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#ifndef PCI_H
#define PCI_H

#include "os.h"


#define PCI_CONFIGURATION_ADDRESS 0xCF8   // Address I/O Port

#define PCI_CONFIGURATION_DATA    0xCFC   // Data    I/O Port
 
// upper byte: length in bytes
// lower byte: register number plus offset

#define PCI_VENDOR_ID   0x0200 // length: 0x02 reg: 0x00 offset: 0x00

#define PCI_DEVICE_ID   0x0202 // length: 0x02 reg: 0x00 offset: 0x02
#define PCI_COMMAND     0x0204
#define PCI_STATUS      0x0206
#define PCI_REVISION    0x0108
#define PCI_CLASS       0x010B
#define PCI_SUBCLASS    0x010A
#define PCI_INTERFACE   0x0109
#define PCI_HEADERTYPE  0x010E
#define PCI_BAR0        0x0410
#define PCI_BAR1        0x0414
#define PCI_BAR2        0x0418
#define PCI_BAR3        0x041C
#define PCI_BAR4        0x0420
#define PCI_BAR5        0x0424
#define PCI_IRQLINE     0x013C
 
uint32_t pci_config_read( uint8_t bus, uint8_t device, uint8_t func, uint16_t content );
void pci_config_write_dword( uint8_t bus, uint8_t device, uint8_t func, uint8_t reg, uint32_t val );

#endif

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include "pci.h"
 
uint32_t pci_config_read( uint8_t bus, uint8_t device, uint8_t func, uint16_t content )
{
    // example: PCI_VENDOR_ID 0x0200 ==> length: 0x02 reg: 0x00 offset: 0x00
    uint8_t length  = content >> 8;
    uint8_t reg_off = content & 0x00FF;
    uint8_t reg     = reg_off & 0xFC;     // bit mask: 11111100b
    uint8_t offset  = reg_off % 0x04;     // remainder of modulo operation provides offset
 
    outportl(PCI_CONFIGURATION_ADDRESS,
        0x80000000
        | (bus    << 16)
        | (device << 11)
        | (func   <<  8)
        | (reg         ));
 
    // use offset to find searched content
    uint32_t readVal = inportl(PCI_CONFIGURATION_DATA) >> (8 * offset);
 
    switch(length)
    {
        case 1:
            readVal &= 0x000000FF;
        break;
        case 2:
            readVal &= 0x0000FFFF;
        break;
        case 4:
            readVal &= 0xFFFFFFFF;
        break;
    }
    return readVal;
}
 
void pci_config_write_dword( uint8_t bus, uint8_t device, uint8_t func, uint8_t reg, uint32_t val )
{
    outportl(PCI_CONFIGURATION_ADDRESS,
        0x80000000
        | (bus     << 16)
        | (device  << 11)
        | (func    <<  8)
        | (reg & 0xFC   ));
 
    outportl(PCI_CONFIGURATION_DATA, val);
}


Code in main(): siehe unten

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 02:42:45 26.10.2009, insgesamt 3-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 13866
Beitrag Erhard Henkes Mitglied 22:19:34 25.10.2009   Titel:              Zitieren

fricky sprach im IRC das Thema PCI-Aktivierung an:
Zitat:
A PCI device ignores all IO and memory access from the PCI bus until it has been activated, steht z.b. dort: http://ecos.sourceware.or ....... ref/ecos-pci-library.html


weiterhin:
Zitat:
<fricky> erhard: zum testen: scanne den PCI-bus nach einem EHCI controller
<*ehenkes> muss erstmal einer da sein
<*ehenkes> if( pciProgrInterface==0x20 ) { printformat("EHCI"); }
<fricky> an offset 2 der memory-mapped i/o-register befindet sich das register HCIVERSION
<*ehenkes> du bekommst von dem: bus:device.function usw.
<fricky> wenn du dort einen 16-bit lesezugriff machst, sollte der wert 0x100 zu lesen sein

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 22:38:32 25.10.2009, insgesamt 1-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 13866
Beitrag Erhard Henkes Mitglied 02:36:21 26.10.2009   Titel:              Zitieren

Ich habe nun auch die Bestimmung der BARs / Memory Size versuchsweise implementiert.

C++:
    /// TEST PCI-SCAN BEGIN
    /// Erweiterte Version siehe unten ...
    /// TEST PCI-SCAN END


Typisches Ergebnis bezüglich USB-Devices:
Code:
0:3.0  IRQ  5  USB OHCI  BAR0: CFFFD000h size: 4096
0:3.1  IRQ 11  USB OHCI  BAR0: CFFFE000h size: 4096
0:3.2  IRQ  5  USB EHCI  BAR0: CFFFF000h size: 4096


Sieht als Einstieg nicht schlecht aus. Klappt aber nur, weil die letzten Bits 00b sind. Die letzten 4 Bits müssen daher noch gesondert ausgewertet werden: (siehe Beitrag weiter oben)
Zitat:
Ein Speicherbereich hat eine Mindestgröße von 16 Byte und ist immer ein Vielfaches von 2. Dadurch stehen die 4 unteren Bits für zusätzliche Codierungen zur Verfügung. Bit 0 gibt Auskunft darüber, ob es sich um eine IO Adresse (der Zugriff muß über Port-Befehle erfolgen) oder eine Memory Adresse handelt. Handelt es sich um eine Memory Adresse, geben Bit 1 und 2 den Adresstyp an. 00 signalisiert, dass es sich um eine gewöhnliche 32 bit Adresse handelt. Die Kombination 01 bedeutet, dass die Adresse unterhalb der aus alten Zeiten bekannten 1 Megabyte Grenze liegt und die Kombination 10 wird für eine 64 bit Adresse verwednet. Bei einer 64 bit Adresse werden zwei „Base Address“ Einträge zur Adressbestimmung gebraucht. Bit 3 schließlich gibt Auskunft darüber, ob auf diesen Adressbereich im Prefetch-Mode zugegriffen werden darf oder nicht. Ein gesetztes Bit bedeutet dabei, dass nicht im Prefetch-Mode zugegriffen werden darf. Im Prefetch-Mode speichert die PCI-Bridge (d.h. der Baustein, der den PCI-Bus an den Processorbus ankoppelt) Daten zwischen, bevor die eigentliche Übertragung zur CPU (lesen oder schreiben) gestartet wird.


Sobald das stabil steht, schiebe ich es als Test-Version 110 hoch.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 11:01:34 26.10.2009, insgesamt 6-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 13866
Beitrag Erhard Henkes Mitglied 10:11:19 26.10.2009   Titel:              Zitieren

In einem Fall ergab die Auswertung eines PCI-Gerätes den IRQ 255. Macht das Sinn? Wohl nicht.
bus:dev.func: 1:0.1 device: 4170h vendor: 1002h IRQ: 255

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 13866
Beitrag Erhard Henkes Mitglied 11:00:17 26.10.2009   Titel:              Zitieren

C++:
1
2
3
4
5
6
7
8
//...
struct pciBasicAddressRegister
{
    uint32_t baseAddress;
    size_t   memorySize;
    uint8_t  memoryType;
};
//...

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
    /// TEST PCI-SCAN BEGIN
    uint16_t pciDevice          = 0; // device
    uint16_t pciVendor          = 0; // vendor
    uint8_t  pciClass           = 0; // device class
    uint8_t  pciSubclass        = 0; // device subclass
    uint8_t  pciProgrInterface  = 0; // program interface
    uint8_t  pciIRQLine         = 0; // IRQ line (interrupt line)
    uint8_t  bus                = 0; // max. 256
    uint8_t  device             = 0; // max.  32
    uint8_t  func               = 0; // max.   8
 
    struct pciBasicAddressRegister pciBAR[6]; // base address, size, type of BAR0 - BAR5
    uint32_t pciBar             = 0;
 
    for(bus=0;bus<8;++bus)
    {
        for(device=0;device<32;++device)
        {
            for(func=0;func<8;++func)
            {
                pciVendor                 = pci_config_read( bus, device, func, PCI_VENDOR_ID );
                pciDevice                 = pci_config_read( bus, device, func, PCI_DEVICE_ID );
                pciClass                  = pci_config_read( bus, device, func, PCI_CLASS     );
                pciSubclass               = pci_config_read( bus, device, func, PCI_SUBCLASS  );
                pciProgrInterface         = pci_config_read( bus, device, func, PCI_INTERFACE );
                pciIRQLine                = pci_config_read( bus, device, func, PCI_IRQLINE   );
                pciBAR[0].baseAddress     = pci_config_read( bus, device, func, PCI_BAR0      );
                pciBAR[1].baseAddress     = pci_config_read( bus, device, func, PCI_BAR1      );
                pciBAR[2].baseAddress     = pci_config_read( bus, device, func, PCI_BAR2      );
                pciBAR[3].baseAddress     = pci_config_read( bus, device, func, PCI_BAR3      );
                pciBAR[4].baseAddress     = pci_config_read( bus, device, func, PCI_BAR4      );
                pciBAR[5].baseAddress     = pci_config_read( bus, device, func, PCI_BAR5      );
 
                if( pciVendor != 0xFFFF )
                {
                    if(pciIRQLine!=255)
                    {
                        printformat("%d:%d.%d\t dev:%x vend:%x IRQ:%d ",
                                     bus, device, func, pciDevice, pciVendor, pciIRQLine);
                    }
                    else // "255 is defined as meaning "unknown" or "no connection" to the interrupt controller"
                    {
                        printformat("%d:%d.%d\t dev:%x vend:%x IRQ:-- ",
                                     bus, device, func, pciDevice, pciVendor);
 
                    }
 
                    if( (pciClass==0x0C) && (pciSubclass==0x03) ) // USB
                    {
                        printformat(" USB ");
                        if( pciProgrInterface==0x00 ) { printformat("UHCI ");   }
                        if( pciProgrInterface==0x10 ) { printformat("OHCI ");   }
                        if( pciProgrInterface==0x20 ) { printformat("EHCI ");   }
                        if( pciProgrInterface==0x80 ) { printformat("no HCI "); }
                        if( pciProgrInterface==0xFE ) { printformat("any ");    }
 
                        for(i=0;i<6;++i) // check USB BARs
                        {
                            pciBAR[i].memoryType = pciBAR[i].baseAddress & 0x01;
 
                            if(pciBAR[i].baseAddress)
                            {
                                if(pciBAR[i].memoryType == 0)
                                {
                                    printformat("%d:%X MEM ", i, pciBAR[i].baseAddress & 0xFFFFFFF0 );
                                }
                                if(pciBAR[i].memoryType == 1)
                                {
                                    printformat("%d:%X I/O ", i, pciBAR[i].baseAddress & 0xFFFFFFFC );
                                }
 
                                /// TEST Memory Size Begin
                                cli();
                                pci_config_write_dword  ( bus, device, func, PCI_BAR0 + 4*i, 0xFFFFFFFF );
                                pciBar = pci_config_read( bus, device, func, PCI_BAR0 + 4*i             );
                                pci_config_write_dword  ( bus, device, func, PCI_BAR0 + 4*i, pciBAR[i].baseAddress  );
                                sti();
                                pciBAR[i].memorySize = (~pciBar | 0x0F) + 1;
                                printformat("sz:%d ", pciBAR[i].memorySize );
                                /// TEST Memory Size End
                            }
                        }
                    }
                    printformat("\n");
                }
 
                // Bit 7 in header type (Bit 23-16) --> multifunctional
                if( !(pci_config_read(bus, device, 0, PCI_HEADERTYPE) & 0x80) )
                {
                    break; // --> not multifunctional
                }
            }
        }
    }
    printformat("\n");
    /// TEST PCI-SCAN END


Damit man mehr ausdrucken kann in einer Monitorzeile habe ich in printformat(...) %X auf acht Zeichen und %x auf vier Zeichen Hexadezimal-Ausgabe gesetzt. %x macht z.B. Sinn bei VendorID und DeviceID.

Bei USB gegeb ich nun aus:
USB UHCI 4:0000D400h I/O sz: 32
USB UHCI 4:0000D000h I/O sz: 32

von rechts nach links: Subclass Program-Interface BAR-Nr. Memory-Address
Memory-Type(MEM oder I/O) Memory-Size

Hier zwei konkrete Beispiele:
http://www.henkessoft.de/OS_Dev/Bilder/USB_UHCI_IO_32.JPG (UHCI IO 32 Byte)
http://www.henkessoft.de/ ....... SB_OHCI_EHCI_MEM_4096.JPG (OHCI u. EHCI MEM 4096 Byte)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 12:03:29 26.10.2009, insgesamt 2-mal bearbeitet
Unregistrierter





Beitrag Unregistrierter 13:22:31 26.10.2009   Titel:              Zitieren

Erhard Henkes schrieb:
In einem Fall ergab die Auswertung eines PCI-Gerätes den IRQ 255. Macht das Sinn?
Das würde "Sinn" machen bei PCI-Geräten, die keinen Interrupt brauchen (i.e. 0xFF -> nicht vorhanden, nicht gebraucht). Hast du mal auf dem Testrechner im BIOS alle Optionen de/aktiviert, die in etwa heißen "plug and play os" oder "pci-autoconfig" o.ä? Mein BIOS kennt solche Optionen nicht, da der Rechner nicht dafür ausgelegt ist, nach dem Kauf noch großartig aufgerüstet zu werden. Aber der PCI-Scan sollte dann völlig neue Ergebnisse bringen.
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 13866
Beitrag Erhard Henkes Mitglied 13:38:46 26.10.2009   Titel:              Zitieren

Ja, 255 bedeutet nicht da, hab ich im Code ergänzt, mache da jetzt "IRQ:--" :)
Genaue Daten sind: 1:0.1 dev:4170h vend:1002h IRQ:255 (jetzt: IRQ:--)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Unregistrierter





Beitrag Unregistrierter 14:01:20 26.10.2009   Titel:              Zitieren

Meine teuer bezahlten "RAM-Controller" und "PCI-PCI-Bridges" haben/nutzen auch keinen Interrupt. Hast du den PCI-Scan mal mit geänderten BIOS-Einstellungen gemacht? Das Ergebnis interessiert mich. :)

Hier noch ein Bit Twiddle Hack:
C++:
1
2
3
4
5
6
7
8
9
uint32_t pci_config_read( uint8_t bus, uint8_t device, uint8_t func, uint16_t content )
{
(...)
 uint8_t reg     = reg_off & 0xFC;     // bit mask: 11111100b
// uint8_t offset  = reg_off % 0x04;     // remainder of modulo operation provides offset
 uint8_t offset  = reg_off & 0x03;     // x & 0x03 == x % 0x04
                                       // aber das wird der Kompiler eh so machen :)
(...)
}
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 13866
Beitrag Erhard Henkes Mitglied 14:40:48 26.10.2009   Titel:              Zitieren

Bit Twiddle Hack
Danke! Interessanter Link. ;)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 14:42:21 26.10.2009, insgesamt 1-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 13866
Beitrag Erhard Henkes Mitglied 18:01:45 26.10.2009   Titel:              Zitieren

Das mit dem Auslesen der Register beginnend ab dem genutzten BAR, nachfolgend nur am Beipsiel USB EHCI, wie von fricky gewünscht, klappt nun ebenso:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
   /// TEST PCI-SCAN BEGIN
    settextcolor(15,0);
    uint16_t pciDevice          = 0; // device
    uint16_t pciVendor          = 0; // vendor
    uint8_t  pciClass           = 0; // device class
    uint8_t  pciSubclass        = 0; // device subclass
    uint8_t  pciProgrInterface  = 0; // program interface
    uint8_t  pciIRQLine         = 0; // IRQ line (interrupt line)
    uint8_t  bus                = 0; // max. 256
    uint8_t  device             = 0; // max.  32
    uint8_t  func               = 0; // max.   8
 
    struct pciBasicAddressRegister pciBAR[6]; // base address, size, type of BAR0 - BAR5
    uint32_t pciBar             = 0;
    uint32_t EHCI_data          = 0;
 
    for(bus=0;bus<8;++bus)
    {
        for(device=0;device<32;++device)
        {
            for(func=0;func<8;++func)
            {
                pciVendor                 = pci_config_read( bus, device, func, PCI_VENDOR_ID );
                pciDevice                 = pci_config_read( bus, device, func, PCI_DEVICE_ID );
                pciClass                  = pci_config_read( bus, device, func, PCI_CLASS     );
                pciSubclass               = pci_config_read( bus, device, func, PCI_SUBCLASS  );
                pciProgrInterface         = pci_config_read( bus, device, func, PCI_INTERFACE );
                pciIRQLine                = pci_config_read( bus, device, func, PCI_IRQLINE   );
                pciBAR[0].baseAddress     = pci_config_read( bus, device, func, PCI_BAR0      );
                pciBAR[1].baseAddress     = pci_config_read( bus, device, func, PCI_BAR1      );
                pciBAR[2].baseAddress     = pci_config_read( bus, device, func, PCI_BAR2      );
                pciBAR[3].baseAddress     = pci_config_read( bus, device, func, PCI_BAR3      );
                pciBAR[4].baseAddress     = pci_config_read( bus, device, func, PCI_BAR4      );
                pciBAR[5].baseAddress     = pci_config_read( bus, device, func, PCI_BAR5      );
 
                if( pciVendor != 0xFFFF )
                {
                    if(pciIRQLine!=255)
                    {
                        printformat("%d:%d.%d\t dev:%x vend:%x IRQ:%d ",
                                     bus, device, func, pciDevice, pciVendor, pciIRQLine);
                    }
                    else // "255 is defined as meaning "unknown" or "no connection" to the interrupt controller"
                    {
                        printformat("%d:%d.%d\t dev:%x vend:%x IRQ:-- ",
                                     bus, device, func, pciDevice, pciVendor);
 
                    }
 
                    if( (pciClass==0x0C) && (pciSubclass==0x03) ) // USB
                    {
                        printformat(" USB ");
                        if( pciProgrInterface==0x00 ) { printformat("UHCI ");   }
                        if( pciProgrInterface==0x10 ) { printformat("OHCI ");   }
                        if( pciProgrInterface==0x20 ) { printformat("EHCI ");   }
                        if( pciProgrInterface==0x80 ) { printformat("no HCI "); }
                        if( pciProgrInterface==0xFE ) { printformat("any ");    }
 
                        for(i=0;i<6;++i) // check USB BARs
                        {
                            pciBAR[i].memoryType = pciBAR[i].baseAddress & 0x01;
 
                            if(pciBAR[i].baseAddress)
                            {
                                if(pciBAR[i].memoryType == 0)
                                {
                                    printformat("%d:%X MEM ", i, pciBAR[i].baseAddress & 0xFFFFFFF0 );
                                }
                                if(pciBAR[i].memoryType == 1)
                                {
                                    printformat("%d:%X I/O ", i, pciBAR[i].baseAddress & 0xFFFFFFFC );
                                }
 
                                /// TEST Memory Size Begin
                                cli();
                                pci_config_write_dword  ( bus, device, func, PCI_BAR0 + 4*i, 0xFFFFFFFF );
                                pciBar = pci_config_read( bus, device, func, PCI_BAR0 + 4*i             );
                                pci_config_write_dword  ( bus, device, func, PCI_BAR0 + 4*i, pciBAR[i].baseAddress  );
                                sti();
                                pciBAR[i].memorySize = (~pciBar | 0x0F) + 1;
                                printformat("sz:%d ", pciBAR[i].memorySize );
 
                                    /// TEST EHCI Data Begin
                                    if( (pciProgrInterface==0x20) && pciBAR[i].baseAddress )
                                    {
                                        for(j=0;j<24;++j)
                                        {
                                             EHCI_data = *((volatile uint8_t*)( (pciBAR[i].baseAddress & 0xFFFFFFF0) + j ));
                                             if(!j)
                                             {
                                                 printformat("\n");
                                             }
                                             else
                                             {
                                                 printformat("\t");
                                             }
                                             printformat("BAR%d+%d: %x ",i, j, EHCI_data);
                                        }
                                    }
                                    /// TEST EHCI Data Begin
 
                                /// TEST Memory Size End
                            }
                        }
                    }
                    printformat("\n");
                }
 
                // Bit 7 in header type (Bit 23-16) --> multifunctional
                if( !(pci_config_read(bus, device, 0, PCI_HEADERTYPE) & 0x80) )
                {
                    break; // --> not multifunctional
                }
            }
        }
    }
    printformat("\n");
    /// TEST PCI-SCAN END


Zwei Beispiele:
http://www.henkessoft.de/ ....... PCI_USB_EHCI_Scan_001.JPG
http://www.henkessoft.de/ ....... PCI_USB_EHCI_Scan_002.JPG

Die Bedeutung der 24 Bytes nach der verwendeten BAR findet man in der EHCI-Spezifikation:
Zitat:
CAPLENGTH - Capability Registers Length
Address: Base+ (00h)
Default Value Implementation Dependent
Attribute: RO
Size: 8 bits
This register is used as an offset to add to register base to find the beginning of the Operational Register Space.

HCIVERSION - Host Controller Interface Version Number
Address: Base+ (02h)
Default Value: 0100h
Attribute RO
Size: 16 bits
This is a two-byte register containing a BCD encoding of the EHCI revision number supported by this host controller. The most significant byte of this register represents a major revision and the least significant byte is the minor revision.

HCSPARAMS - Structural Parameters
Address: Base+ (04h)
Default Value Implementation Dependent
Attribute RO
Size: 32 bits
This is a set of fields that are structural parameters: Number of downstream ports, etc.

HCCPARAMS - Capability Parameters
Address: Base+ (08h)
Default Value Implementation Dependent
Attribute RO
Size: 32 bits
Multiple Mode control (time-base bit functionality), addressing capability

HCSP-PORTROUTE - Companion Port Route Description
Address: Base+ (0Ch)
Default Value Implementation Dependent
Attribute RO
Size: 60 bits
This optional field is valid only if Port Routing Rules field in the HCSPARAMS register is set to a one.


Hier die Zusammenfassung:
These registers specify the limits, restrictions and capabilities of the host controller implementation.
Table 2-5. Enhanced Host Controller Capability Registers
Code:
Offset Size Mnemonic    Power Well   Register Name
00h     1   CAPLENGTH      Core      Capability Register Length
01h     1   Reserved       Core      N/A
02h     2   HCIVERSION     Core      Interface Version Number
04h     4   HCSPARAMS      Core      Structural Parameters
08h     4   HCCPARAMS      Core      Capability Parameters
0Ch     8   HCSP-PORTROUTE Core      Companion Port Route Description


Quelle: "Enhanced Host Controller Interface Specification for Universal Serial Bus", Date: March 12, 2002, Revision: 1.0, Intel Corporation

Es gibt inzwischen auch ein Addendum für Revision 1.1
Dort ist der Standardwert für HCIVERSION z.B. 0x110 (Base+2, 16 bits), auch bei HCCPARAMS (Base+8, 32 bits) wurden viele Details geändert.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 19:34:23 26.10.2009, insgesamt 3-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 13866
Beitrag Erhard Henkes Mitglied 12:26:59 01.11.2009   Titel:              Zitieren

Die erhöhte Auflösung der Textausgabe auf 80 Spalten * 50 Zeilen ist hier bei modernen Rechnern recht hilfreich, hier ein ca. 5 Jahre alter, ziemlich gut ausgebauter Rechner:
http://www.henkessoft.de/OS_Dev/Bilder/PCI-Scan3.PNG

Man sieht allerdings, dass die Bestimmung der Speichergröße bei UHCI leider noch eine Macke hat (negative Werte). Die Byte des Enhanced Host Controller Capability Registers müssen auch noch entsprechend zusammengefasst und dargestellt werden. HCIVERSION ist hier auf jeden Fall auch 0x0100. :)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 12:32:58 01.11.2009, insgesamt 2-mal bearbeitet
Unregistrierter





Beitrag Unregistrierter 20:43:15 01.11.2009   Titel:              Zitieren

Erhard Henkes schrieb:
Man sieht allerdings, dass die Bestimmung der Speichergröße bei UHCI leider noch eine Macke hat (negative Werte).
Laut Datenblatt (Kapitel 11, Seite 469 :( ) für "dev:27C8h vend:8086h" sind Offset 10h-1Fh des "Config Space" in etwa "reserviert". D.h. daß man dort eine Speichergröße nicht auslesen kann.
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 13866
Beitrag Erhard Henkes Mitglied 17:26:09 09.11.2009   Titel:              Zitieren

Die PCI-Daten wurden nun noch in eine PCI-Device-Struct eingelesen, damit diese dauerhaft zur Verfügung stehen (Rev. 14 SVN):
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
typedef
struct pciBasicAddressRegister
{
    uint32_t baseAddress;
    size_t   memorySize;
    uint8_t  memoryType;
}pciBar_t;
 
typedef
struct pciDev
{
   uint8_t   number;
   uint8_t   bus;
   uint8_t   device;
   uint8_t   func;
   uint16_t  vendorID;
   uint16_t  deviceID;
   uint8_t   classID;
   uint8_t   subclassID;
   uint8_t   interfaceID;
   uint8_t   revID;
   uint8_t   irq;
   pciBar_t  bar[6];
}pciDev_t;


Ich habe die gültigen PCI Devices auch durchlaufend nummeriert, damit diese mit einer Größe identifizierbar sind.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 17:29:26 09.11.2009, insgesamt 1-mal bearbeitet
C++ Forum :: Projekt: OS-Development  ::  PCI-Scan   Auf Beitrag antworten

Zeige alle Beiträge auf einer Seite




Nächstes Thema anzeigen
Vorheriges Thema anzeigen
Sie können Beiträge in dieses Forum schreiben.
Sie können auf Beiträge in diesem Forum antworten.
Sie können Ihre Beiträge in diesem Forum nicht bearbeiten.
Sie können Ihre Beiträge in diesem Forum nicht löschen.
Sie können an Umfragen in diesem Forum nicht mitmachen.

Powered by phpBB © 2001, 2002 phpBB Group :: FI Theme

c++.net ist Teilnehmer des Partnerprogramms von Amazon Europe S.à.r.l. und Partner des Werbeprogramms, das zur Bereitstellung eines Mediums für Websites konzipiert wurde, mittels dessen durch die Platzierung von Werbeanzeigen und Links zu amazon.de Werbekostenerstattung verdient werden kann.

Die Vervielfältigung der auf den Seiten www.c-plusplus.de, www.c-plusplus.info und www.c-plusplus.net enthaltenen Informationen ohne eine schriftliche Genehmigung des Seitenbetreibers ist untersagt (vgl. §4 Urheberrechtsgesetz). Die Nutzung und Änderung der vorgestellten Strukturen und Verfahren in privaten und kommerziellen Softwareanwendungen ist ausdrücklich erlaubt, soweit keine Rechte Dritter verletzt werden. Der Seitenbetreiber übernimmt keine Gewähr für die Funktion einzelner Beiträge oder Programmfragmente, insbesondere übernimmt er keine Haftung für eventuelle aus dem Gebrauch entstehenden Folgeschäden.