Gestion de la mémoire

Fonctions - gestion de la mémoire physique

  • Allocation de pages contigües ou discontigües
  • Libération des pages mémoire

Fonctions - gestion de la mémoire logique

  • Allocation de tables
  • Ajout / suppression d'entrées dans les tables
  • Allocation de pages logiques contigües (allocation des pages physiques correspondantes lors de l'accès ou pas suivant les cas)
  • Gestion du TLB
  • Modification de la zone d'adressage courante

Gestion de la mémoire au démarrage

Aucun gestionnaire de mémoire ne sera disponible avant l'initialisation de la mémoire. C'est pourquoi cette tâche doit être effectuée le plus rapidement possible. Par conséquent, pour les zones de mémoire nécessaire avant l'initialisation de la mémoire devront être allouées de manière statique. De plus, pour éviter le gâchis de place mémoire, le prefixe "__initdata" sera placée dans la ligne d'initialisation du buffer : cet espace sera alors libéré à la fin de l'initialisation d'APOS.

Collecteur de fragments de mémoire

APOS possède deux gestionnaires de mémoire complètement indépendants : les gestionnaires de mémoire SLAB et kmalloc. Seul le second nous intéresse dans cette partie.

Dès qu'un fragment de mémoire ne pouvant former une page complète est trouvée, il est donné à kmalloc. Celui-ci enregistre tous ces petits morceaux de mémoire par une liste chaînée double.

Lorsque nous avons besoin de mémoire de manière très occasionnelle, kmalloc doit être utilisé.

Si kmalloc n'a pas assez de mémoire disponible pour satisfaire la demande, il sera possible à kmalloc d'allouer des pages logiques. En revanche, kmalloc ne gardera aucune page complète mais les rendra de suite disponible.

Gestion de la mémoire physique

Chaque bloc de mémoire est associé à ce que l'on appelle un nœud (node en anglais). Chaque nœud possède deux zones au maximum : ZONE_DMA et ZONE_NORMAL. Ces zones regroupent des pages mémoire de taille fixée par la taille mémoire gérée par le MMU matériel (par exemple 4Ko pour les 80x86).

La zone DMA s'étend de 0 à 1Mo.

les pages libres sont d'abord recherchées dans la zone NORMAL. Des pages mémoires ne doivent être puisées dans la zone DMA QUE si c'est pour une utilisation avec le matériel. Aussi, on essaiera d'allouer les pages les plus basses, de manière regroupée avec un système de priorité : plus l'adresse est grande, plus la priorité baisse.

Un espace suffisant, juste après le code du noyau sera alloué pour y stoquer toutes les informations nécessaire au fonctionnement du gestionnaire de mémoire. Cette zone s'appelle la carte mémoire. Cette zone contient chaque structure de chaque page mémoire ainsi que la structure pour le nœud et les zones courantes.

La structure d'une zone contient une carte de bits représentant la présence ou l'absence d'une page mémoire (1 = page présente ; 0 = un trou / page inutilisable). C'est aussi dans cette structure de zone qu'il y aura un spin_lock pour modifier les pages. De plus, des compteurs de pages libres / totales s'y trouveront.

Dans la structure d'une page, on y trouve essentiellement un compteur de références (nr_refs). S'il est à 0, c'est que la page est libre et donc allouable. De plus, une série de drapeaux pour renseigner sur le type de page, leur état...

Il est important de noter que les opérations d'allocation / de recherche doivent être extrêment rapides car elles seront appelées bien trop souvent.

Applications : accès aux buffers utilisateurs

Il est important de noter que APOS doît pouvoir permettre aux programmes d'allouer les 4Go et non pas 3Go comme c'est le cas si le noyau est accessible dans chaque contexte de page sur 1Go. Pour ce faire, lorsqu'une fonction a besoin d'accéder à un bloc de mémoire dans le contexte d'un processus particulier, une fonction nécessitant les paramètres : base, taille, processus devra être utilisée. Elle permettra de "mapper" la zone utilisateur dans l'espace du noyau sachant qu'elle renverra en retour l'adresse d'où des données seront accessible. De ce fait, si la machine est monté en cluster par un réseau, cette fonction se chargera de récupérer les données !

De cette manière, chaque programme ne devra contenir qu'un minimum de code qui correspond aux interruptions matérielles et logiciels dont l'appel système se chargera d'installer le contexte du noyau !

Si le noyau possède son propre contexte, alors, il aura 4Go de disponible pour "mapper" convenablement la mémoire à utiliser et chaque programmes pourra posséder environ 4Go de mémoire. Cependant, si le noyau est contenu dans chaque processus à raison de 1Go, l'espace possédé par le noyau sera moins important mais la fonction pour mapper les zones mémoires ne nécessitera pas d'être grande vu que la majorité des buffers où l'on aura besoin d'accéder seront dans le contexte du processus et renverra simplement la même adresse de base ! Dans tous les cas, quelque soit le choix lors de la compilation, chaque pilote et fonction ne verront pas la différence et donc ce principe sera complètement transparent.