Peripheral Component Interconnect — Änderungen 7268 → 7269

Zeile 220: Zeile 220:
 
|}
 
|}
 
Das Bit 0 signalisiert mit seinem Wert 1 das es sich bei dem betreffenden BAR um eine IO-Ressource handelt. Das Bit 1 ist reserviert und muss beim lesen ignoriert und beim schreiben mit 0 gelöscht werden. Die Bits 31-2 geben die Basis-Adressbits 31-2 der IO-Ressource an. Die IO-Ressource muss also mindestens 4 Byte groß sein. Oft sind die Bits 31-16 fest auf 0 geklemmt so das nur 16 Bit-IO-Adressen benutzt werden können, auf der PC-Plattform unterstützen die CPUs auch nur 16 Bit-IO-Adressen so das normalerweise daraus kein Problem entsteht.
 
Das Bit 0 signalisiert mit seinem Wert 1 das es sich bei dem betreffenden BAR um eine IO-Ressource handelt. Das Bit 1 ist reserviert und muss beim lesen ignoriert und beim schreiben mit 0 gelöscht werden. Die Bits 31-2 geben die Basis-Adressbits 31-2 der IO-Ressource an. Die IO-Ressource muss also mindestens 4 Byte groß sein. Oft sind die Bits 31-16 fest auf 0 geklemmt so das nur 16 Bit-IO-Adressen benutzt werden können, auf der PC-Plattform unterstützen die CPUs auch nur 16 Bit-IO-Adressen so das normalerweise daraus kein Problem entsteht.
 +
 +
===== Beispiel-Code zur BAR-Analyse =====
 +
Der folgende C-Code analysiert alle BARs im Konfigurations-Adressraum eines PCI-Gerätes und gibt alle verfügbaren Informationen aus. Dieser Code sollte möglichst nicht auf aktivierte PCI-Geräte angewendet werden, falls doch wäre es geschickt den Vorgang atomar zu gestalten und alle BARs vorher zu sichern und hinter zu restaurieren.
 +
<c>/*** Diesen Code darf jeder zu jedem Zweck kopieren, nutzen und verändern! ***/
 +
 +
 +
/* deklariert einen Typ der Bus, Device und Function enthält um ein bestimmtes PCI-Gerät zu adressieren , ich bin einfach zu faul 3 Einzelwerte durch meinen Quähl-Code zu schicken */
 +
typedef  ....  pci_bdf_t;
 +
 +
/* ließt einen 32Bit-Wert aus dem Config-Space vom PCI-Gerät (addr) an Offset (offset) und gibt ihn zurück */
 +
extern uint32_t pci_config_readd(pci_bdf_t addr,uint offset);
 +
 +
/* schreibt einen 32Bit-Wert (value) in den Config-Space vom PCI-Gerät (addr) an Offset (offset) */
 +
extern void pci_config_writed(pci_bdf_t addr,uint offset,uint32_t value);
 +
 +
 +
/* sucht das unterste gesetzte Bit in einem 32Bit-Wert , value darf nicht 0 sein */
 +
static uint get_number_of_lowest_set_bit(uint32_t value);
 +
static uint get_number_of_lowest_set_bit(uint32_t value)
 +
{
 +
  uint pos = 0;
 +
  uint32_t mask = 0x00000001;
 +
  while( ( value & mask ) != 0 )
 +
  { ++pos; mask=mask<<1; }
 +
  return pos;
 +
}
 +
 +
/* sucht das oberste gesetzte Bit in einem 32Bit-Wert , value darf nicht 0 sein */
 +
static uint get_number_of_highest_set_bit(uint32_t value);
 +
static uint get_number_of_highest_set_bit(uint32_t value)
 +
{
 +
  uint pos = 31;
 +
  uint32_t mask = 0x80000000;
 +
  while( ( value & mask ) != 0 )
 +
  { --pos; mask=mask>>1; }
 +
  return pos;
 +
}
 +
 +
 +
/* analysiert die BARs eines bestimmten PCI-Gerätes, das PCI-Gerät sollte hierfür unbenutzt sein */
 +
void pci_config_bar_analyze(const pci_bdf_t addr)
 +
{
 +
  const uint32_t headerType = ( pci_config_readd(addr,0x00C) >> 16 ) & 0x7F; // Header-Type auslesen um zu ermitteln wie viele BARs vorhanden sind.
 +
  if (headerType >= 0x02) // es werden nur Type 0x00 (normale Devices) und 0x01 (PCI-to-PCI-Bridges) unterstützt
 +
  { printf("FEHLER : nicht unterstützter Header-Type gefunden!\n"); return; }
 +
 +
  const uint max_bars = 6 - (headerType * 4); // 6 BARs für Type 0x00 und 2 BARs für Type 0x01
 +
 +
  for (uint bar = 0 ; bar < max_bars ; ++bar)
 +
  {
 +
    const uint barOffset = 0x010+(bar*4);
 +
    if ( (pci_config_readd(addr,barOffset) & 0x1) == 0 )
 +
      { // Speicher-Ressource :
 +
        static const char ptext_pref[] = "prefetchable"; //Text für prefetchable
 +
        static const char ptext_nopr[] = "non-prefetchable"; //Text für non-prefetchable
 +
        const char* const ptext = (((pci_config_readd(addr,barOffset) >> 3) & 0x1) == 1) ? &ptext_pref[0] : &ptext_nopr[0];
 +
 +
        switch(((pci_config_readd(addr,barOffset) >> 1) & 0x3)) // check Memory-BAR-Type
 +
        {
 +
          case 0x0: // 32Bit Memory-BAR :
 +
            {
 +
            pci_config_writed(addr,barOffset,0xFFFFFFF0); // mit lauter 1en überschreiben
 +
            const uint32_t barValue = pci_config_readd(addr,barOffset) & 0xFFFFFFF0; //und wieder zurücklesen
 +
            if (barValue == 0) // es muss mindestens ein Adressbit 1 (also beschreibbar) sein
 +
              {
 +
                if (ptext != &ptext_nopr[0]) // unbenutzte BARs müssen komplett 0 sein
 +
                { printf("FEHLER : 32Bit-Memory-BAR %u enthält keine beschreibbaren Adressbits!\n",bar); return; }
 +
 +
                // BAR-Infos ausgeben :
 +
                printf("BAR %u ist unbenutzt.\n",bar);
 +
              }
 +
            else
 +
              {
 +
                const uint lowestBit = get_number_of_lowest_set_bit(barValue);
 +
                if ( (get_number_of_highest_set_bit(barValue) != 31) || (lowestBit > 31) || (lowestBit < 4) ) //es muss eine gültige 32Bit-Adresse sein
 +
                { printf("FEHLER : 32Bit-Memory-BAR %u enthält ungültige beschreibbare Adressbits!\n",bar); return; }
 +
 +
                // BAR-Infos ausgeben :
 +
                printf("BAR %u enhält eine %s 32Bit-Memory-Ressource mit einer Größe von 2^%u Bytes.\n",bar,ptext,lowestBit);
 +
              }
 +
            }
 +
            break;
 +
 +
          case 0x1: // 20Bit Memory-BAR :
 +
            {
 +
            pci_config_writed(addr,barOffset,0xFFFFFFF0); // mit lauter 1en überschreiben
 +
            const uint32_t barValue = pci_config_readd(addr,barOffset) & 0xFFFFFFF0; //und wieder zurücklesen
 +
            if (barValue == 0) // es muss mindestens ein Adressbit 1 (also beschreibbar) sein
 +
              { printf("FEHLER : 20Bit-Memory-BAR %u enthält keine beschreibbaren Adressbits!\n",bar); return; }
 +
 +
            const uint lowestBit = get_number_of_lowest_set_bit(barValue);
 +
            if ( (get_number_of_highest_set_bit(barValue) != 19) || (lowestBit > 19) || (lowestBit < 4) ) //es muss eine gültige 20Bit-Adresse sein
 +
              { printf("FEHLER : 20Bit-Memory-BAR %u enthält ungültige beschreibbare Adressbits!\n",bar); return; }
 +
 +
            // BAR-Infos ausgeben :
 +
            printf("BAR %u enhält eine %s 20Bit-Memory-Ressource mit einer Größe von 2^%u Bytes.\n",bar,ptext,lowestBit);
 +
            }
 +
            break;
 +
 +
          case 0x2: // 64Bit Memory-BAR :
 +
            {
 +
            if (bar >= (max_bars-1)) // prüfen ob ein 64Bit-BAR an der aktuellen Position überhaupt möglich ist
 +
              { printf("FEHLER : 64Bit-Memory-BAR %u darf nicht an letzter Position beginnen!\n",bar); return; }
 +
            if (ptext != &ptext_pref[0]) // non-prefetchable 64-BARs können nicht hinter Bridges benutzt werden (? aber in der Spec sind sie nicht verboten ?)
 +
              { printf("FEHLER : 64Bit-Memory-BAR %u enthält eine non-prefetchable Memory-Ressource!\n",bar); return; }
 +
 +
            pci_config_writed(addr,barOffset,0xFFFFFFF0); // mit lauter 1en überschreiben
 +
            pci_config_writed(addr,barOffset+4,0xFFFFFFFF); // mit lauter 1en überschreiben
 +
            const uint32_t barLowValue  = pci_config_readd(addr,barOffset) & 0xFFFFFFF0; //und wieder zurücklesen
 +
            const uint32_t barHighValue = pci_config_readd(addr+4,barOffset); //und wieder zurücklesen
 +
 +
            uint lowestBit = 0;
 +
            if (barLowValue != 0)
 +
              { // kleiner als 4 GByte
 +
                lowestBit = get_number_of_lowest_set_bit(barLowValue);
 +
                if ( (barHighValue != 0xFFFFFFFF) || (get_number_of_highest_set_bit(barLowValue) != 31) || (lowestBit > 31) || (lowestBit < 4) ) //es muss eine gültige kleine 64Bit-Adresse sein
 +
                { printf("FEHLER : 64Bit-Memory-BAR %u enthält ungültige beschreibbare Adressbits im unteren Adressteil!\n",bar); return; }
 +
              }
 +
            else
 +
              { // größer/gleich als 4 GByte
 +
                lowestBit = get_number_of_lowest_set_bit(barHighValue) + 32;
 +
                if ( (get_number_of_highest_set_bit(barHighValue) != 31) || (lowestBit > 63) || (lowestBit < 32) ) //es muss eine gültige große 64Bit-Adresse sein
 +
                { printf("FEHLER : 64Bit-Memory-BAR %u enthält ungültige beschreibbare Adressbits im oberen Adressteil!\n",bar); return; }
 +
              }
 +
 +
            // BAR-Infos ausgeben :
 +
            printf("BAR %u enhält eine %s 64Bit-Memory-Ressource mit einer Größe von 2^%u Bytes.\nBAR %u ist nicht nutzbar da er die oberen 32 Bits des vorrangegangenen 64Bit-BARs enthält\n",bar,ptext,lowestBit,bar+1);
 +
 +
            ++bar; //den folgenden BAR für die analyse überspringen
 +
            }
 +
            break;
 +
 +
          default: // ungültiger Memory-BAR :
 +
            printf("FEHLER : Memory-BAR %u is invalid!\n",bar); return;
 +
        }
 +
      }
 +
    else
 +
      { // IO-Ressource :
 +
        pci_config_writed(addr,barOffset,0xFFFFFFFC); // mit lauter 1en überschreiben
 +
        const uint32_t barValue = pci_config_readd(addr,barOffset) & 0xFFFFFFFC; //und wieder zurücklesen
 +
        if (barValue == 0) // es muss mindestens ein Adressbit 1 (also beschreibbar) sein
 +
        { printf("FEHLER : IO-BAR %u enthält keine beschreibbaren Adressbits!\n",bar); return; }
 +
 +
        const uint lowestBit  = get_number_of_lowest_set_bit(barValue);
 +
        const uint highestBit = get_number_of_highest_set_bit(barValue);
 +
        if ( ( (highestBit != 31) && (highestBit != 15) ) || (highestBit < lowestBit) || (lowestBit < 2) ) //es muss entwerder eine gültige 32Bit-Adresse oder eine gültige 16Bit-Adresse sein
 +
        { printf("FEHLER : IO-BAR %u enthält ungültige beschreibbare Adressbits!\n",bar); return; }
 +
 +
        // BAR-Infos ausgeben :
 +
        printf("BAR %u enhält eine %uBit-IO-Ressource mit einer Größe von 2^%u Bytes.\n",bar,highestBit+1,lowestBit);
 +
      }
 +
  }
 +
}</c>
  
 
=== Zugriff auf den Konfigurations-Adressraum ===
 
=== Zugriff auf den Konfigurations-Adressraum ===