« HermèsFaites chauffer les rotatives ! »

Mémoire virtuelle

11.11.10 | par Le Grincheux | Catégories: Mauvaise humeur, Je hais l'informatique, Haines ordinaires

Je vais finir par haïr l'informatique au plus haut point. Depuis quelques jours, j'essaie péniblement de faire fonctionner une mémoire virtuelle sur une architecture x86 en 64 bits. Le but ultime est l'écriture d'un système d'exploitation aussi proche que possible d'OpenVMS sur une architecture plus courante que l'Itanium.

Je vous rassure toute de suite, je n'ai pas écrit cette mémoire virtuelle depuis rien, je me suis honteusement inspiré de ce qui se faisait par ailleurs. Mais je n'ai fait que m'inspirer tant la qualité intrinsèque du code qu'on peut trouver est déplorable.

Mon inspiration vient de la gestion de la mémoire virtuelle d'un système qui s'appelle Iguana et qui sert de base à un certain nombre de systèmes d'exploitation comme Darbat qui est un port du système Darwin sur un micronoyau de type L4. A priori quelque chose de stable. Pourtant après avoir disséqué le fonctionnement de la chose, je n'arrive pas à comprendre comment cette mémoire virtuelle arrive à fonctionner tant il y a d'erreurs de conception. Un simple exemple : pour allouer une plage de mémoire contenant un programme dont les adresses initiale et finale sont connues, le système cherche à allouer la plus grande page comprise dans cette plage, ignorant crânement les octets initiaux et finaux s'ils ne sont pas alignés sur un début ou une fine de page ! Pour contourner toutes ces erreurs, le code est plein de commentaires disant qu'on fait telle ou telle chose, qu'on ne sait pas pourquoi ça fonctionne avec ce hack, mais qu'on est en revanche sûr que si on l'enlève, ça ne fonctionne plus. C'est donc ce qu'il est convenu d'appeler une programmation fiable et robuste.

J'ai donc corrigé un tas de choses. Ne me demandez surtout pas d'envoyer mes patches aux concepteurs d'Iguana, je ne vais pas faire leur boulot à leur place. Ils n'ont qu'à prendre les corrections sur le serveur git de FreeVMS. À leur place, j'aurais même honte de fournir un logiciel d'une telle qualité.

Quoi qu'il en soit, et malgré ces erreurs, je suis arrivé à booter un micronoyau L4/X2 en mode kernel avec un serveur σ0 et une roottask qui est de fait le noyau FreeVMS tournant en mode executive et lançant un processus léger VMS$INIT.SYS se chargeant de lancer les pilotes requis pour accéder au matériel. Il faut bien charger un pilote pour lancer la couche RMS (l'équivalent en mieux du VFS des systèmes Unix), un deuxième pour accéder au disque dur, un autre pour lire la table de partition du disque et un dernier pour accéder au système de fichiers et lire SYS$ROOT:[VMS$COMMON.SYSMGR]VMSKERNEL.CNF;1 permettant de continuer la séquence de démarrage.

La preuve en image :

KickStart 0.12.56
Detected multiboot compliant loader
Limiting physical memory to 128MB
Reserving 8MB for kernel memory
kernel    (0x0011b000-0x0038adc4)   => 0x00b59000
(0x0011c000-0x00374500) -> 0x00800000-0x00a58500
(0x00375000-0x0037ce70) -> 0x00b59000-0x00b60e70
sigma0    (0x0038b000-0x003a4b30)   => 0x00040000
(0x0038b0c0-0x00391080) -> 0x00040000-0x00045fc0
roottask  (0x003a5000-0x003e7cf1)   => 0x01002f5c
(0x003a50b0-0x004199e0) -> 0x010000b0-0x010749e0
Launching kernel ...

>>> FreeVMS 0.4.0 (R)

%SYSBOOT-I-SYSBOOT, leaving kernel privileges
%SYSBOOT-I-SYSBOOT, launching FreeVMS kernel with executive privileges
%SYSBOOT-I-SYSBOOT, booting main processor
%SYSBOOT-I-SYSBOOT, computing page size: 4096 bytes
%SYSBOOT-I-SYSBOOT, CPU0 EXTFREQ=1000 MHz, INTFREQ=2200 MHz
%SYSBOOT-I-SYSBOOT, parsing command line: /boot/vmskernel.sys root=dqa0.0
%SYSBOOT-I-SYSBOOT, selecting root device: DQA0.0
%SYSBOOT-I-SYSBOOT, initializing virtual memory
%MEM-I-AREA, $0000000000000000 - $000000000003FFFF: physical memory
%MEM-I-AREA, $0000000000046000 - $000000000009F3FF: physical memory
%MEM-I-AREA, $0000000000100000 - $0000000000108FFF: physical memory
%MEM-I-AREA, $000000000010B000 - $00000000003E7FFF: physical memory
%MEM-I-AREA, $0000000000404000 - $00000000007FFFFF: physical memory
%MEM-I-AREA, $0000000000B59000 - $0000000000FFFFFF: physical memory
%MEM-I-AREA, $000000000100C000 - $00000000075FFFFF: physical memory
%MEM-I-AREA, $0000000007E00000 - $0000000007FFCFFF: physical memory
%MEM-I-AREA, $0000000000001000 - $FFFFFEFFFFFFFFFF: virtual memory
%MEM-I-AREA, $000000000009F400 - $00000000000FFFFF: mapped IO
%MEM-I-AREA, $0000000007FFD000 - $FFFFFFFFFFFFFFFF: mapped IO
%MEM-I-AREA, $0000000007600000 - $0000000007DFFFFF: reserved
%MEM-I-AREA, $0000000000800000 - $0000000000A58FFF: reserved
%MEM-I-AREA, $0000000000A59000 - $0000000000B58FFF: reserved
%MEM-I-AREA, $0000000000831000 - $0000000000831FFF: reserved
%MEM-I-AREA, $FFFFFFFFFFC00000 - $FFFFFFFFFFC00FFF: reserved
%MEM-I-AREA, $00000000FEC00000 - $00000000FEC00FFF: reserved
%MEM-I-AREA, $0000000000040000 - $0000000000045FC0: reserved
%MEM-I-AREA, $0000000000040000 - $0000000000044817: modules
%MEM-I-AREA, $0000000000044818 - $0000000000044837: kernel
%MEM-I-AREA, $00000000010000B0 - $000000000100B44F: modules
%MEM-I-AREA, $000000000100B460 - $000000000100BB47: kernel
%MEM-I-AREA, $00000000003E8000 - $00000000003EEC3A: modules
%MEM-I-AREA, $00000000003EF000 - $00000000003F5C3A: modules
%MEM-I-AREA, $00000000003F6000 - $00000000003FCC3A: modules
%MEM-I-AREA, $00000000003FD000 - $0000000000403C3A: modules
%MEM-I-AREA, $000000000010A000 - $000000000010AFFF: boot information
%MEM-I-AREA, $0000000000109000 - $00000000001092CF: boot information
%SYSBOOT-I-SYSBOOT, reserving memory for preloaded objects
%MEM-I-ALLOC, allocating $0000000000040000 - $0000000000044817
%MEM-I-ALLOC, allocating $0000000000044818 - $0000000000044837
%MEM-I-ALLOC, allocating $00000000010000B0 - $000000000100B44F
%MEM-I-ALLOC, allocating $000000000100B460 - $000000000100BB47
%MEM-I-ALLOC, allocating $00000000003E8000 - $00000000003EEC3A
%MEM-I-ALLOC, allocating $00000000003EF000 - $00000000003F5C3A
%MEM-I-ALLOC, allocating $00000000003F6000 - $00000000003FCC3A
%MEM-I-ALLOC, allocating $00000000003FD000 - $0000000000403C3A
%MEM-I-ALLOC, allocating $000000000010A000 - $000000000010AFFF
%MEM-I-ALLOC, allocating $0000000000109000 - $00000000001092CF
%MEM-I-F_ALLOC, bootstrapping Fpage allocator at virtual addresses
%MEM-I-F_ALLOC, $0000000000001000 - $000000000003FFFF
%MEM-I-S_ALLOC, bootstrapping Slab allocator at physical addresses
%MEM-I-S_ALLOC, $0000000000000000 - $000000000003FFFF
%MEM-I-FREE, freeing region $0000000000046000 - $000000000009EFFF
%MEM-I-FREE, freeing region $0000000000100000 - $0000000000108FFF
%MEM-I-FREE, freeing region $000000000010B000 - $00000000003E7FFF
%MEM-I-FREE, freeing region $0000000000404000 - $00000000007FFFFF
%MEM-I-FREE, freeing region $0000000000B59000 - $0000000000FFFFFF
%MEM-I-FREE, freeing region $000000000100C000 - $00000000075FFFFF
%MEM-I-FREE, freeing region $0000000007E00000 - $0000000007FFCFFF
%MEM-I-VM_ALLOC, adding $0000000000045000 - $0000000000108FFF
%MEM-I-VM_ALLOC, adding $000000000010B000 - $00000000003E7FFF
%MEM-I-VM_ALLOC, adding $0000000000404000 - $0000000000FFFFFF
%MEM-I-VM_ALLOC, adding $000000000100C000 - $FFFFFEFFFFFFFFFF
%JOBCTL-I-MAX_PROC_ID, setting maximal process number $3FFC4
%DEV-I-TREE, initializing devices tree
%SYSBOOT-I-SYSBOOT, spawning VMS$INIT.SYS
%SYSBOOT-I-SYSBOOT, creating VMS$INIT.SYS process descriptor
%SYSBOOT-I-SYSBOOT, creating VMS$INIT.SYS UTCB pages
%SYSBOOT-I-SYSBOOT, reserving 262144 bytes for 256 kernel threads
%SYSBOOT-I-SYSBOOT, creating VMS$INIT.SYS stack
%SYSBOOT-I-SYSBOOT, creating VMS$INIT.SYS heap
%SYSBOOT-I-SYSBOOT, creating VMS$INIT.SYS clist
%MEM-F-OUTMEM, out of memory $47002-$47FFF

La dernière ligne pose problème d'autant que le noyau essaie de mapper une plage mémoire sur une autre alors qu'il n'a pas encore de dérouleur de pages. S'ensuit un défaut de page particulièrement problématique, je ne sais pas si vous voyez bien ce que je veux dire. Et si je rajoute qu'au moment où ce message d'erreur est capturé il reste peu ou prou 120 Mo de mémoire disponible, vous comprendrez toute la portée de cette erreur.

Ce qui est surprenant, c'est qu'au moment où surgit cette erreur, la plage est question est parfaitement disponible, ce qui est confirmé par le message sibyllin suivant :

%MEM-I-FREE, freeing region $0000000000046000 - $000000000009EFFF

Il doit donc rester une aberration quelque part dans ces fonctions de gestion de la mémoire virtuelle. La question est maintenant de trouver cette erreur en évitant autant que possible de maudire les concepteurs d'Iguana qui, à leur décharge, n'ont fait qu'utiliser une bibliothèque au doux nom de l4e sans se préoccuper de ses erreurs internes ni de ses dysfonctionnements.

Il me semblait pourtant avoir déjà signalé qu'un programmeur ne devrait avoir le droit d'utiliser une bibliothèque qu'à partir du moment où il est capable de l'écrire, jamais comme une boîte noire.

 

1 commentaire

Commentaire de: Le Grincheux

Trouvé… Ces psychopathes considèrent que lorsqu’il est impossible d’allouer une page virtuelle dans une zone de la mémoire physique, on atteint une condition de dépassement de mémoire, ce qui est a priori normal.

Là où ça se corse légèrement, c’est que la routine de libération d’une région de la mémoire utilise cette fonction d’allocation pour calculer le nombre de pages à libérer. Dans le cas où la zone est inférieure à une page, il est impossible d’allouer une seule page dans la zone et la condition de dépassement mémoire est atteinte.

Encore du code fiable !

12.11.10 @ 11:53


Formulaire en cours de chargement...