Contexte et problème observé

Le développeur du système d’exploitation floss a implémenté un spin‑lock en assembleur AArch64. Le code utilise ldaxr pour la lecture exclusive et stxr pour l’écriture exclusive. Sur les plateformes QEMU virt et Raspberry Pi 4, le verrou fonctionne sans incident. En revanche, sur un Raspberry Pi 5 réel, le processeur déclenche une exception de type Data Abort (EC = 37, valeur hexadécimale 0x25) avec le syndrome 0x96000410 au moment de l’exécution de l’instruction ldaxr w0, [x1] située à l’adresse 0x84474.

Le remplacement de ldaxr/stxr par un simple ldar suivi de str élimine l’erreur, ce qui indique que le problème provient du mécanisme d’accès exclusif.

Fonctionnement du spin‑lock en assembleur

Le verrou repose sur un mot de 32 bits (w registers) où 0 signifie « déverrouillé » et 1 signifie « verrouillé ». Le code source est :

void SpinLock::lock() {
    uint32_t lock_read, store_result;
    asm volatile (
        "1:\n"
        "    ldaxr %w0, [%2]\n"
        "    cbnz %w0, 1b\n"
        "    mov %w0, #1\n"
        "    stxr %w1, %w0, [%2]\n"
        "    cbnz %w1, 1b\n"
        : "=&r" (lock_read), "=&r" (store_result)
        : "r" (&_lock)
        : "memory");
}

void SpinLock::unlock() {
    asm volatile ("stlr wzr, [%0]" :: "r" (&_lock) : "memory");
}

L’instruction ldaxr possède la sémantique d’acquisition (acquire), garantissant que les lectures suivantes ne sont pas réordonnées avant le chargement. L’instruction stlr possède la sémantique de libération (release), assurant le contraire pour les écritures précédentes.

Analyse des attributs de mémoire et des moniteurs exclusifs

Arm définit un ensemble d’attributs de mémoire pour lesquels les instructions exclusives sont garanties atomiques. La documentation indique que les mémoires Normal doivent être :

  • Inner Shareable, Inner Write‑Back, Outer Write‑Back avec indices d’allocation en lecture et écriture, non transitoires ;
  • Outer Shareable, Inner Write‑Back, Outer Write‑Back avec les mêmes indices d’allocation, non transitoires.

Si la page contenant le verrou ne possède pas ces attributs, le processeur peut désactiver les moniteurs exclusifs, ce qui conduit à un Data Abort lorsqu’une instruction ldaxr tente d’accéder à une zone non cacheable ou mal configurée. Sur le Raspberry Pi 5, la table de pages utilisée par floss configure la région du verrou en Device ou en mémoire non cacheable, ce qui n’est pas couvert par les exigences ci‑dessus. QEMU, en revanche, ne reproduit pas cette contrainte et accepte les accès exclusifs même avec des attributs inadéquats, d’où la différence de comportement.

Le passage à ldar/str fonctionne parce que ces instructions ne dépendent pas des moniteurs exclusifs et ne déclenchent donc pas d’erreur de cacheabilité.

Implications et solutions pratiques

Pour garantir le bon fonctionnement du spin‑lock sur du matériel réel, il faut :

  • Mapper la page contenant le verrou avec les attributs Inner Shareable et Write‑Back requis ;
  • Vérifier que le bit Cacheable du registre de contrôle de la MMU est activé pour la région concernée ;
  • Utiliser les fonctions de configuration de la MMU du noyau afin d’appliquer les attributs MAIR_EL1 appropriés.

Une fois ces réglages appliqués, les moniteurs exclusifs sont activés, ldaxr s’exécute sans abort et le spin‑lock conserve son atomicité sur le Raspberry Pi 5.