La structure de paging est organisé en 4 niveaux, que l'on note PML1 à PML4.
La PML4 (qui est la racine) dispose d'une entré récursive, ce qui permet de créé des nouvelles adresses virtuelle simplement :
Pour un pointeur ptr donné, on peut accéder à toutes les pages d'index qui permet de le rendre valide par des opération sur le pointeur :
~0ull << 12
(~0ull << 21) | ((ptr >> 39) & 0x1FF << 12)
(~0ull << 30) | ((ptr >> 30) & 0x3FFFF << 12)
(~0ull << 39) | ((ptr >> 21) & 0x7FFFFFF << 12)
On peut alors créé des addresse en appliquant la procédure suivante :
for (uint64_t off = 0; off < size; off += 0x1000) { void* vaddr = base_addr + off; set_PML3(vaddr, global, user); set_PML2(vaddr, global, user); set_PML1(vaddr, global, user); set_PML0(vaddr, global, user, writable); }
Avec set_PMLx
qui créé la page d'index si nécessaire, la PML0 étant une manière de désigner la page physique où on map l'addresse virtuel.
Le kernel dispose de trois allocateurs en plus de kmalloc :
phys_alloc
pour allouer de la mémoire physiquefake_alloc
pour de la mémoire physique invalide (pour l'allocation des registre mappé des PCIs)special_alloc
pour des addresses virtuelles, qu'on ne souhaite pas placer dans le kmalloc (par exemple si on veut la mapper a des addresse physique spécifique).frame_alloc
est simplement phys_alloc
avec une multiplication par 0x1000 de la taille (nombre de page -> nombre d'octets) et un alignement par défault de 12 bits.
Les allocateurs ont un fonctionnement similaire à un malloc sans le problème d'avoir les donnés au millieu des donné de l'allocateur : Ils tiennent une liste chaîné de bloque libres et font les opérations nécessaire pour la tenir à jour lors d'une allocation ou d'une libération. Ils supporte l'allocations de bloc avec un alignement (indispensable pour le paging), mais contrairement a malloc, ils ont besoin de la taille du bloc alloué pour le free (ce qui permet de free en plusieurs fois).