Explication du Code E1000

Un、Initialisation E1000

1.fonction_principale

void fonction_principale() {
  ...
	#ifdef LAB_RESEAU
    initialisation_pci();
    initialisation_socket();
	#endif    
...
}

2.initialisation_pci

void initialisation_pci() {
  // Les registres e1000 sont mappés à cette adresse.
  // vm.c mappe cette plage.
  uint64 registres_e1000 = 0x40000000L;

  // qemu -machine virt place l'espace de configuration PCIe ici.
  // vm.c mappe cette plage.
  uint32  *ecam = (uint32 *) 0x30000000L;
  
  // Examine chaque périphérique PCI possible sur le bus 0.
  for(int periph = 0; periph < 32; periph++){
    int bus = 0;
    int fonction = 0;
    int decalage = 0;
    uint32 off = (bus << 16) | (periph << 11) | (fonction << 8) | (decalage);
    volatile uint32 *base = ecam + off;
    uint32 id = base[0];
    
    // 100e:8086 est un e1000
    if(id == 0x100e8086){
      // Registre de commande et de statut.
      // bit 0 : Activation de l'accès E/S
      // bit 1 : Activation de l'accès mémoire
      // bit 2 : Activation du maître
      base[1] = 7;
      __sync_synchronize();

      for(int i = 0; i < 6; i++){
        uint32 ancien = base[4+i];

        // Écrire tous les 1 dans le BAR provoque son
        // remplacement par sa taille.
        base[4+i] = 0xffffffff;
        __sync_synchronize();

        base[4+i] = ancien;
      }

      // Indique à l'e1000 de révéler ses registres à
      // l'adresse physique 0x40000000.
      base[4+0] = registres_e1000;

      initialisation_e1000((uint32*)registres_e1000);
    }
  }
}

Selon memlayout.h, la disposition mémoire de xv6 est déterminée par hw/riscv/virt.c, en examinant le code pertinent

https://github.com/qemu/qemu/blob/master/hw/riscv/virt.c, on trouve les définitions suivantes

static const MemMapEntry memoire_virtuelle[] = {
...
    [VIRT_PCIE_ECAM] =    { 0x30000000,    0x10000000 },
    [VIRT_PCIE_MMIO] =    { 0x40000000,    0x40000000 },
    [VIRT_DRAM] =         { 0x80000000,           0x0 },
};

Les adresses 0x30000000 et 0x40000000 correspondent respectivement à PCIE_ECAM et PCIE_MMIO

PCIE_ECAM

ECAM (PCI Express Configuration Access Mechanism) est un mécanisme permettant d'accéder à l'espace de configuration PCIe, mappant les registres de configuration des périphériques PCIe en mémoire, permettant au logiciel d'accéder à ces registres comme s'il s'agissait de mémoire ordinaire.

PCIE_MMIO

MMIO (Memory-Mapped I/O), mappant les registres dans l'espace d'adresse E/S des périphériques PCIe en mémoire. L'accès à ces registres de périphérique peut être réalisé en lisant et écrivant des adresses mémoire, permettant le contrôle et l'échange de données avec les périphériques.

Espace de configuration PCIe

https://en.wikipedia.org/wiki/PCI_configuration_space

Il s'agit des registres de contrôle des périphériques, permettant de contrôler les périphériques PCIe en manipulant ces registres.

Chaque registre de contrôle a une taille de 32 bits

Note : Les registres de contrôle mentionnés ici sont ceux du périphérique, pas ceux de la carte mère.

La configuration pertinente de l'E1000 PCIe est décrite dans le chapitre 4 Interface Bus PCI Local

Explication du code

Le pointeur base indique vers les registres de contrôle

  1. base[0] stocke l'ID Fournisseur et l'ID Périphérique, selon le manuel E1000 (page 95), les deux valeurs pour le 82540EM sont respectivement 8086 et 100e

Étiquettes: E1000 PCI PCIe interface réseau initialisation matériel

Publié le 19 juin à 23h49