Version de cette réponse avec un beau TOC et plus de contenu .
Je corrigerai toute erreur signalée. Si vous voulez faire des modifications importantes ou ajouter un aspect manquant, faites-les sur vos propres réponses pour obtenir une réputation bien méritée. Les modifications mineures peuvent être fusionnées directement.
Exemple de code
Exemple minimal : https://github.com/cirosantilli/x86-bare-metal-examples/blob/5c672f73884a487414b3e21bd9e579c67cd77621/paging.S
Comme pour tout ce qui concerne la programmation, la seule façon de vraiment comprendre est de jouer avec des exemples minimaux.
Ce qui rend ce sujet "difficile", c'est que l'exemple minimal est vaste car vous devez créer votre propre petit OS.
Manuel Intel
Bien qu'il soit impossible de comprendre sans avoir d'exemples en tête, essayez de vous familiariser avec les manuels dès que possible.
Intel décrit la pagination dans le Manuel Intel Volume 3 Guide de programmation du système - 325384-056US Septembre 2015 Chapitre 4 "Paging".
La Figure 4-4 "Formats des entrées CR3 et Paging-Structure avec pagination 32 bits" est particulièrement intéressante, car elle donne les principales structures de données.
MMU
La pagination est effectuée par le Unité de gestion de la mémoire (MMU) de l'unité centrale. Comme beaucoup d'autres (par ex. co-processeur x87 , APIC ), il s'agissait au début d'une puce séparée, qui a ensuite été intégrée à l'unité centrale. Mais le terme est toujours utilisé.
Faits généraux
Les adresses logiques sont les adresses de mémoire utilisées dans le code "normal" de l'utilisateur (par exemple, le contenu de l'écran de l'ordinateur). rsi
en mov eax, [rsi]
).
La segmentation les traduit d'abord en adresses linéaires, puis la pagination traduit ensuite les adresses linéaires en adresses physiques.
(logical) ------------------> (linear) ------------> (physical)
segmentation paging
La plupart du temps, nous pouvons penser que les adresses physiques indexent les cellules de mémoire matérielle RAM réelles, mais ce n'est pas vrai à 100% à cause de :
La radiomessagerie n'est disponible qu'en mode protégé. L'utilisation de la radiomessagerie en mode protégé est facultative. La pagination est activée si le PG
de la cr0
est activé.
Radiomessagerie et segmentation
L'une des principales différences entre la pagination et la segmentation est la suivante :
- La pagination divise la RAM en morceaux de taille égale appelés pages.
- La segmentation divise la mémoire en morceaux de taille arbitraire.
C'est le principal avantage de la pagination, puisque des morceaux de taille égale rendent les choses plus faciles à gérer.
La pagination a tellement gagné en popularité que la prise en charge de la segmentation a été abandonnée en x86-64 en mode 64 bits, le principal mode de fonctionnement des nouveaux logiciels, où elle n'existe qu'en mode de compatibilité, qui émule IA32.
Application
La pagination est utilisée pour mettre en œuvre les espaces d'adressage virtuels des processus sur les systèmes d'exploitation modernes. Grâce aux adresses virtuelles, le système d'exploitation peut faire tenir deux ou plusieurs processus simultanés sur une seule mémoire vive :
- les deux programmes ne doivent rien savoir de l'autre
- la mémoire des deux programmes peut augmenter et diminuer selon les besoins.
- le passage d'un programme à l'autre est très rapide
- un programme ne peut jamais accéder à la mémoire d'un autre processus
Historiquement, la pagination est venue après la segmentation, et l'a largement remplacée pour la mise en œuvre de la mémoire virtuelle dans les systèmes d'exploitation modernes tels que Linux, car il est plus facile de gérer les morceaux de mémoire de taille fixe que sont les pages que les segments de longueur variable.
Mise en œuvre matérielle
Comme la segmentation en mode protégé (où la modification d'un registre de segment déclenche un chargement depuis le GDT ou le LDT), le matériel de pagination utilise des structures de données en mémoire pour faire son travail (tables de pages, répertoires de pages, etc.).
Le format de ces structures de données est fixe par le matériel mais c'est au système d'exploitation de mettre en place et de gérer correctement ces structures de données dans la mémoire vive, et d'indiquer au matériel où les trouver (par l'intermédiaire de la fonction cr3
).
Certaines autres architectures laissent la pagination presque entièrement entre les mains du logiciel, de sorte qu'un défaut de TLB exécute une fonction fournie par le système d'exploitation pour parcourir les tables de pages et insérer le nouveau mappage dans la TLB. Cela laisse les formats de tables de pages à la discrétion du système d'exploitation, mais rend la fonction de pagination plus efficace. Il est peu probable que le matériel puisse chevaucher les passages de page avec l'exécution hors ordre d'autres instructions, comme le fait le x86. .
Exemple : schéma de pagination simplifié à un seul niveau
Ceci est un exemple de la façon dont la pagination fonctionne sur une simplifié version de l'architecture x86 pour mettre en œuvre un espace mémoire virtuel.
Tableaux de pages
L'OS pourrait leur donner les tableaux de pages suivants :
Table des pages donnée au processus 1 par l'OS :
RAM location physical address present
----------------- ----------------- --------
PT1 + 0 * L 0x00001 1
PT1 + 1 * L 0x00000 1
PT1 + 2 * L 0x00003 1
PT1 + 3 * L 0
... ...
PT1 + 0xFFFFF * L 0x00005 1
Table des pages donnée au processus 2 par l'OS :
RAM location physical address present
----------------- ----------------- --------
PT2 + 0 * L 0x0000A 1
PT2 + 1 * L 0x0000B 1
PT2 + 2 * L 0
PT2 + 3 * L 0x00003 1
... ... ...
PT2 + 0xFFFFF * L 0x00004 1
Où :
-
PT1
y PT2
Position initiale des tables 1 et 2 sur la RAM.
Valeurs de l'échantillon : 0x00000000
, 0x12345678
etc.
C'est le système d'exploitation qui décide de ces valeurs.
-
L
Longueur d'une entrée de la table des pages.
-
present
: indique que la page est présente en mémoire.
Les tables de pages sont situées dans la RAM. Elles peuvent par exemple être situées comme suit :
--------------> 0xFFFFFFFF
--------------> PT1 + 0xFFFFF * L
Page Table 1
--------------> PT1
--------------> PT2 + 0xFFFFF * L
Page Table 2
--------------> PT2
--------------> 0x0
Les emplacements initiaux de la RAM pour les deux tables de pages sont arbitraires et contrôlés par le système d'exploitation. C'est au système d'exploitation de s'assurer qu'elles ne se chevauchent pas !
Chaque processus ne peut pas toucher directement aux tables de pages, bien qu'il puisse faire des demandes au système d'exploitation qui entraînent la modification des tables de pages, par exemple en demandant des segments de pile ou de tas plus grands.
Une page est un morceau de 4KB (12 bits), et comme les adresses ont 32 bits, seuls 20 bits (20 + 12 = 32, donc 5 caractères en notation hexadécimale) sont nécessaires pour identifier chaque page. Cette valeur est fixée par le matériel.
Entrées de la table des pages
Une table de pages est... une table d'entrées de tables de pages !
Le format exact des entrées de la table est fixé par le matériel .
Dans cet exemple simplifié, les entrées de la table des pages ne contiennent que deux champs :
bits function
----- -----------------------------------------
20 physical address of the start of the page
1 present flag
donc dans cet exemple, les concepteurs du matériel auraient pu choisir L = 21
.
La plupart des entrées de la table des pages réelles comportent d'autres champs.
Il ne serait pas pratique d'aligner les choses à 21 bits puisque la mémoire est adressable par octets et non par bits. Par conséquent, même si seulement 21 bits sont nécessaires dans ce cas, les concepteurs de matériel choisiraient probablement L = 32
pour rendre l'accès plus rapide, et réserver les bits restants pour une utilisation ultérieure. La valeur réelle de L
sur x86 est de 32 bits.
Traduction d'adresses dans un schéma à un seul niveau
Une fois que les tables de pages ont été mises en place par le système d'exploitation, la traduction des adresses entre les adresses linéaires et physiques est effectuée. par le matériel .
Lorsque le système d'exploitation veut activer le processus 1, il définit le paramètre cr3
a PT1
le début de la table pour le processus 1.
Si le processus 1 veut accéder à l'adresse linéaire 0x00000001
le paging matériel informatique Le circuit effectue automatiquement les opérations suivantes pour le système d'exploitation :
-
diviser l'adresse linéaire en deux parties :
| page (20 bits) | offset (12 bits) |
Donc, dans ce cas, nous aurions :
- page = 0x00000
- décalage = 0x001
-
regardez le tableau 1 de la page car cr3
l'indique.
-
entrée de look 0x00000
parce que c'est la partie de la page.
Le matériel sait que cette entrée est située à l'adresse RAM PT1 + 0 * L = PT1
.
-
puisqu'il est présent, l'accès est valide
-
par la table des pages, l'emplacement du numéro de page 0x00000
est à 0x00001 * 4K = 0x00001000
.
-
pour trouver l'adresse physique finale, il suffit d'ajouter le décalage :
00001 000
+ 00000 001
-----------
00001 001
parce que 00001
est l'adresse physique de la page recherchée dans la table et 001
est le décalage.
Comme son nom l'indique, le décalage est toujours simplement ajouté à l'adresse physique de la page.
-
le matériel obtient alors la mémoire à cet emplacement physique.
De la même manière, les traductions suivantes se produiraient pour le processus 1 :
linear physical
--------- ---------
00000 002 00001 002
00000 003 00001 003
00000 FFF 00001 FFF
00001 000 00000 000
00001 001 00000 001
00001 FFF 00000 FFF
00002 000 00002 000
FFFFF 000 00005 000
Par exemple, lors de l'accès à l'adresse 00001000
la partie de la page est 00001
le matériel sait que son entrée dans la table des pages est située à l'adresse RAM : PT1 + 1 * L
( 1
à cause de la partie page), et c'est là qu'il va le chercher.
Quand le système d'exploitation veut passer au processus 2, il lui suffit de faire cr3
point à la page 2. C'est aussi simple que cela !
Maintenant, les traductions suivantes se produiraient pour le processus 2 :
linear physical
--------- ---------
00000 002 00001 002
00000 003 00001 003
00000 FFF 00001 FFF
00001 000 00000 000
00001 001 00000 001
00001 FFF 00000 FFF
00003 000 00003 000
FFFFF 000 00004 000
La même adresse linéaire se traduit par des adresses physiques différentes pour des processus différents. qui dépend uniquement de la valeur à l'intérieur de cr3
.
De cette façon, chaque programme peut s'attendre à ce que ses données débutent à 0
et se terminent à FFFFFFFF
sans se soucier des adresses physiques exactes.
Défaut de page
Que se passe-t-il si le processus 1 essaie d'accéder à une adresse dans une page qui n'existe pas ?
Le matériel informe le logiciel par une exception de défaut de page.
C'est alors généralement au système d'exploitation d'enregistrer un gestionnaire d'exception pour décider de ce qu'il faut faire.
Il est possible que l'accès à une page qui ne figure pas dans le tableau soit une erreur de programmation :
int is[1];
is[2] = 1;
mais il peut y avoir des cas dans lesquels il est acceptable, par exemple dans Linux lorsque :
-
le programme veut augmenter sa pile.
Il essaie simplement d'accéder à un certain octet dans une plage possible donnée, et si le système d'exploitation est satisfait, il ajoute cette page à l'espace d'adressage du processus.
-
la page a été transférée sur le disque.
Le système d'exploitation devra effectuer un certain travail derrière les processus pour ramener la page dans la RAM.
Le système d'exploitation peut découvrir que c'est le cas en se basant sur le contenu du reste de l'entrée de la table des pages, puisque si l'indicateur present est clair, les autres entrées de l'entrée de la table des pages sont entièrement laissées à la discrétion du système d'exploitation.
Sous Linux par exemple, lorsque présent = 0 :
-
si tous les champs de l'entrée de la table des pages sont à 0, adresse invalide.
-
Sinon, la page a été transférée sur le disque, et les valeurs réelles de ces champs codent la position de la page sur le disque.
Dans tous les cas, le système d'exploitation doit savoir quelle adresse a généré le défaut de page pour pouvoir traiter le problème. C'est pourquoi les gentils développeurs de IA32 ont fixé la valeur de cr2
à cette adresse chaque fois qu'un défaut de page se produit. Le gestionnaire d'exception peut alors simplement regarder dans cr2
pour obtenir l'adresse.
Simplifications
Simplifications de la réalité qui rendent cet exemple plus facile à comprendre :
-
Tous les circuits de pagination réels utilisent la pagination multi-niveaux pour économiser de l'espace, mais ceci a montré un schéma simple à un seul niveau.
-
Les tableaux de pages ne contenaient que deux champs : une adresse de 20 bits et un drapeau de présence de 1 bit.
Les tableaux de pages réelles contiennent un total de 12 champs, et donc d'autres caractéristiques qui ont été omises.
Exemple : système de pagination à plusieurs niveaux
Le problème avec un système de pagination à un seul niveau est qu'il prendrait trop de RAM : 4G / 4K = 1M d'entrées. par processus. Si chaque entrée a une longueur de 4 octets, cela ferait 4M par processus ce qui est trop, même pour un ordinateur de bureau : ps -A | wc -l
indique que j'exécute 244 processus en ce moment, ce qui représente environ 1 Go de ma RAM !
Pour cette raison, les développeurs de x86 ont décidé d'utiliser un schéma à plusieurs niveaux qui réduit l'utilisation de la RAM.
L'inconvénient de ce système est qu'il a un temps d'accès légèrement plus élevé.
Dans le schéma de pagination simple à 3 niveaux utilisé pour les processeurs 32 bits sans PAE, les 32 bits d'adresse sont répartis comme suit :
| directory (10 bits) | table (10 bits) | offset (12 bits) |
Chaque processus doit avoir un et un seul répertoire de pages associé à lui, il contiendra donc au moins 2^10 = 1K
pages de répertoire, ce qui est bien mieux que le minimum de 1M requis sur un schéma à un seul niveau.
Les tables de pages ne sont allouées que si le système d'exploitation en a besoin. Chaque table de pages a 2^10 = 1K
entrées du répertoire des pages
Les répertoires de pages contiennent... des entrées de répertoire de pages ! Les entrées du répertoire des pages sont identiques aux entrées de la table des pages, à l'exception des éléments suivants ils pointent vers les adresses RAM des tables de pages au lieu des adresses physiques des tables . Comme ces adresses n'ont qu'une largeur de 20 bits, les tables de pages doivent se trouver au début des pages de 4KB.
cr3
pointe maintenant vers l'emplacement en RAM du répertoire de pages du processus actuel au lieu des tables de pages.
Les entrées des tables de pages ne changent pas du tout par rapport à un schéma à un seul niveau.
Les tables de pages changent d'un schéma à un seul niveau parce que :
- chaque processus peut avoir jusqu'à 1K tables de pages, une par entrée de répertoire de pages.
- chaque table de pages contient exactement 1K entrées au lieu de 1M entrées.
La raison de l'utilisation de 10 bits sur les deux premiers niveaux (et non pas, disons, de 10 bits sur les deux premiers niveaux) est la suivante 12 | 8 | 12
) est que chaque entrée de la table des pages a une longueur de 4 octets. Alors les 2^10 entrées des répertoires de pages et des tables de pages s'adapteront parfaitement aux pages de 4Kb. Cela signifie qu'il est plus rapide et plus simple d'allouer et de désallouer des pages dans ce but.
Traduction d'adresses dans un système à plusieurs niveaux
Répertoire de pages donné au processus 1 par le système d'exploitation :
RAM location physical address present
--------------- ----------------- --------
PD1 + 0 * L 0x10000 1
PD1 + 1 * L 0
PD1 + 2 * L 0x80000 1
PD1 + 3 * L 0
... ...
PD1 + 0x3FF * L 0
Tableaux de pages donnés au processus 1 par l'OS à PT1 = 0x10000000
( 0x10000
* 4K) :
RAM location physical address present
--------------- ----------------- --------
PT1 + 0 * L 0x00001 1
PT1 + 1 * L 0
PT1 + 2 * L 0x0000D 1
... ...
PT1 + 0x3FF * L 0x00005 1
Tableaux de pages donnés au processus 1 par l'OS à PT2 = 0x80000000
( 0x80000
* 4K) :
RAM location physical address present
--------------- ----------------- --------
PT2 + 0 * L 0x0000A 1
PT2 + 1 * L 0x0000C 1
PT2 + 2 * L 0
... ...
PT2 + 0x3FF * L 0x00003 1
où :
-
PD1
: position initiale du répertoire de pages du processus 1 en RAM.
-
PT1
y PT2
Position initiale de la table de pages 1 et de la table de pages 2 pour le processus 1 sur la RAM.
Ainsi, dans cet exemple, le répertoire des pages et la table des pages pourraient être stockés dans la RAM de la manière suivante :
----------------> 0xFFFFFFFF
----------------> PT2 + 0x3FF * L
Page Table 1
----------------> PT2
----------------> PD1 + 0x3FF * L
Page Directory 1
----------------> PD1
----------------> PT1 + 0x3FF * L
Page Table 2
----------------> PT1
----------------> 0x0
Traduisons l'adresse linéaire 0x00801004
étape par étape.
Nous supposons que cr3 = PD1
c'est-à-dire qu'il pointe vers le répertoire de pages que nous venons de décrire.
En binaire, l'adresse linéaire est :
0 0 8 0 1 0 0 4
0000 0000 1000 0000 0001 0000 0000 0100
Regroupement en tant que 10 | 10 | 12
donne :
0000000010 0000000001 000000000100
0x2 0x1 0x4
ce qui donne :
- entrée du répertoire des pages = 0x2
- entrée de la table des pages = 0x1
- décalage = 0x4
Le matériel cherche donc l'entrée 2 du répertoire de la page.
La table du répertoire des pages indique que la table des pages se trouve à l'adresse suivante 0x80000 * 4K = 0x80000000
. Il s'agit du premier accès à la RAM du processus.
Puisque l'entrée de la table des pages est 0x1
le matériel regarde l'entrée 1 de la table des pages à 0x80000000
ce qui lui indique que la page physique est située à l'adresse 0x0000C * 4K = 0x0000C000
. Il s'agit du deuxième accès à la RAM du processus.
Enfin, le matériel de pagination ajoute le décalage, et l'adresse finale est 0x0000C004
.
D'autres exemples d'adresses traduites sont :
linear 10 10 12 split physical
-------- --------------- ----------
00000001 000 000 001 00001001
00001001 000 001 001 page fault
003FF001 000 3FF 001 00005001
00400000 001 000 000 page fault
00800001 002 000 001 0000A001
00801008 002 001 008 0000C008
00802008 002 002 008 page fault
00B00001 003 000 000 page fault
Les défauts de page se produisent si une entrée de répertoire de page ou une entrée de table de page n'est pas présente.
Si le système d'exploitation veut exécuter un autre processus simultanément, il doit donner au second processus un répertoire de pages distinct et lier ce répertoire à des tables de pages distinctes.
Architectures 64 bits
64 bits, c'est encore trop d'adresse pour les tailles actuelles de RAM, donc la plupart des architectures utiliseront moins de bits.
x86_64 utilise 48 bits (256 TiB), et le PAE du mode legacy autorise déjà les adresses de 52 bits (4 PiB).
12 de ces 48 bits sont déjà réservés pour l'offset, ce qui laisse 36 bits.
Si l'on adopte une approche à deux niveaux, la meilleure répartition serait de deux niveaux de 18 bits.
Mais cela voudrait dire que le répertoire des pages aurait 2^18 = 256K
entrées, ce qui prendrait trop de RAM : proche d'une pagination à un seul niveau pour les architectures 32 bits !
Par conséquent, les architectures 64 bits créent des niveaux de page supplémentaires, généralement 3 ou 4.
x86_64 utilise 4 niveaux dans un 9 | 9 | 9 | 12
de manière à ce que le niveau supérieur ne prenne que 2^9
les entrées de niveau supérieur.
PAE
Extension de l'adresse physique.
Avec 32 bits, on ne peut adresser que 4 Go de RAM.
Cela commençait à devenir une limitation pour les grands serveurs, c'est pourquoi Intel a introduit le mécanisme PAE dans le Pentium Pro.
Pour remédier à ce problème, Intel a ajouté 4 nouvelles lignes d'adresse, de sorte que 64 Go puissent être adressés.
La structure de la table des pages est également modifiée si le PAE est activé. La manière exacte dont elle est modifiée dépend de l'activation ou de la désactivation de PSE.
Le PAE est activé et désactivé via le bouton PAE
un peu de cr4
.
Même si la mémoire adressable totale est de 64 Go, les processus individuels ne peuvent utiliser que 4 Go au maximum. Le système d'exploitation peut cependant placer différents processus sur différents morceaux de 4 Go.
PSE
Extension de la taille de la page.
Permet aux pages d'avoir une longueur de 4M (ou 2M si PAE est activé) au lieu de 4K.
Le PSE est activé et désactivé par l'intermédiaire du PSE
un peu de cr4
.
Schémas de table de pages PAE et PSE
Si le PAE et le PSE sont actifs, différents schémas de niveaux de paging sont utilisés :
-
pas de PAE et pas de PSE : 10 | 10 | 12
-
pas de PAE et PSE : 10 | 22
.
22 est le décalage dans la page de 4Mb, puisque 22 bits adressent 4Mb.
-
PAE et pas de PSE : 2 | 9 | 9 | 12
La raison pour laquelle le chiffre 9 est utilisé deux fois au lieu de 10 est que les entrées ne peuvent plus tenir sur 32 bits, qui étaient tous remplis par 20 bits d'adresse et 12 bits de drapeau significatifs ou réservés.
La raison en est que 20 bits ne suffisent plus pour représenter l'adresse des tables de pages : 24 bits sont maintenant nécessaires à cause des 4 fils supplémentaires ajoutés au processeur.
Par conséquent, les concepteurs ont décidé d'augmenter la taille des entrées à 64 bits, et pour les faire tenir dans une seule page de table, il est nécessaire de réduire le nombre d'entrées à 2^9 au lieu de 2^10.
Le point de départ 2 est un nouveau niveau de Page appelé Page Directory Pointer Table (PDPT), car il points pour paginer les répertoires et remplir l'adresse linéaire de 32 bits. Les PDPT ont également une largeur de 64 bits.
cr3
pointe maintenant vers les PDPTs qui doivent être sur les quatre premiers 4GB de mémoire et alignés sur des multiples de 32 bits pour l'efficacité de l'adressage. Cela signifie que maintenant cr3
a 27 bits significatifs au lieu de 20 : 2^5 pour les 32 multiples * 2^27 pour compléter les 2^32 du premier 4GB.
-
PAE et PSE : 2 | 9 | 21
Les concepteurs ont décidé de conserver un champ de 9 bits de large pour qu'il tienne sur une seule page.
Il reste donc 23 bits. En laissant 2 pour le PDPT pour garder les choses uniformes avec le cas PAE sans PSE, il reste 21 pour le décalage, ce qui signifie que les pages ont une largeur de 2M au lieu de 4M.
TLB
Le Translation Lookahead Buffer (TLB) est un cache pour les adresses de pagination.
Puisqu'il s'agit d'un cache, il partage de nombreux problèmes de conception du cache du CPU, comme le niveau d'associativité.
Cette section décrit une TLB simplifiée entièrement associative avec 4 entrées à adresse unique. Notez que, comme les autres caches, les TLB réelles ne sont généralement pas totalement associatives.
Fonctionnement de base
Après une traduction entre l'adresse linéaire et l'adresse physique, celle-ci est stockée dans la TLB. Par exemple, une TLB à 4 entrées commence dans l'état suivant :
valid linear physical
------ ------- ---------
> 0 00000 00000
0 00000 00000
0 00000 00000
0 00000 00000
El >
indique l'entrée courante à remplacer.
et après une adresse linéaire de page 00003
est traduit en une adresse physique 00005
le TLB devient :
valid linear physical
------ ------- ---------
1 00003 00005
> 0 00000 00000
0 00000 00000
0 00000 00000
et après une deuxième traduction de 00007
a 00009
il devient :
valid linear physical
------ ------- ---------
1 00003 00005
1 00007 00009
> 0 00000 00000
0 00000 00000
Maintenant si 00003
doit être traduit à nouveau, le matériel consulte d'abord la TLB et trouve son adresse en un seul accès à la RAM. 00003 --> 00005
.
Bien sûr, 00000
n'est pas sur la TLB puisqu'aucune entrée valide ne contient 00000
comme une clé.
Politique de remplacement
Lorsque la TLB est remplie, les anciennes adresses sont écrasées. Comme pour le cache du CPU, la politique de remplacement est une opération potentiellement complexe, mais une heuristique simple et raisonnable consiste à supprimer l'entrée la moins récemment utilisée (LRU).
Avec LRU, en partant de l'état :
valid linear physical
------ ------- ---------
> 1 00003 00005
1 00007 00009
1 00009 00001
1 0000B 00003
en ajoutant 0000D -> 0000A
donnerait :
valid linear physical
------ ------- ---------
1 0000D 0000A
> 1 00007 00009
1 00009 00001
1 0000B 00003
CAM
L'utilisation de la TLB accélère la traduction, car la traduction initiale nécessite un seul accès. par niveau de TLB ce qui signifie 2 sur un simple schéma 32 bits, mais 3 ou 4 sur les architectures 64 bits.
La TLB est généralement implémentée comme un type de RAM coûteux appelé mémoire adressable par le contenu (CAM). La CAM implémente une carte associative sur le matériel, c'est-à-dire une structure qui, à partir d'une clé (adresse linéaire), récupère une valeur.
Les mappings peuvent également être implémentés sur des adresses RAM, mais les mappings CAM peuvent nécessiter beaucoup moins d'entrées qu'un mappage RAM.
Par exemple, une carte dans laquelle :
- les clés et les valeurs ont toutes deux 20 bits (cas d'un système de pagination simple).
- il faut stocker au maximum 4 valeurs à chaque instant
pourrait être stocké dans une TLB avec 4 entrées :
linear physical
------- ---------
00000 00001
00001 00010
00010 00011
FFFFF 00000
Cependant, pour mettre en œuvre ce système avec la RAM, il serait nécessaire d'avoir 2^20 adresses :
linear physical
------- ---------
00000 00001
00001 00010
00010 00011
... (from 00011 to FFFFE)
FFFFF 00000
ce qui serait encore plus coûteux que d'utiliser une TLB.
Invalidation des entrées
Lorsque cr3
toutes les entrées TLB sont invalidées, car une nouvelle table de pages pour un nouveau processus va être utilisée, il est donc peu probable que les anciennes entrées aient une quelconque signification.
Le x86 offre également le invlpg
qui invalide explicitement une seule entrée TLB. D'autres architectures offrent encore plus d'instructions pour invalider les entrées TLB, comme l'invalidation de toutes les entrées sur une plage donnée.
Certains processeurs x86 vont au-delà des exigences de la spécification x86 et fournissent plus de cohérence qu'elle ne le garantit, entre la modification d'une entrée de la table des pages et son utilisation, quand elle n'était pas déjà en cache dans la TLB. . Apparemment, Windows 9x s'appuyait sur ce principe pour être correct, mais les processeurs AMD modernes ne permettent pas d'assurer une marche cohérente des pages. Les CPU Intel le font, même s'ils doivent détecter les erreurs de spéculation pour y parvenir. Tirer profit de cette situation est probablement une mauvaise idée, car il n'y a probablement pas grand-chose à gagner, et un grand risque de causer de subtils problèmes de synchronisation qui seront difficiles à déboguer.
Utilisation du noyau Linux
Le noyau Linux fait un usage intensif des fonctions de pagination de x86 pour permettre des changements de processus rapides avec une faible fragmentation des données.
Sur v4.2
regardez sous arch/x86/
:
include/asm/pgtable*
include/asm/page*
mm/pgtable*
mm/page*
Il ne semble pas y avoir de structures définies pour représenter les pages, seulement des macros : include/asm/page_types.h
est particulièrement intéressante. Extrait :
#define _PAGE_BIT_PRESENT 0 /* is present */
#define _PAGE_BIT_RW 1 /* writeable */
#define _PAGE_BIT_USER 2 /* userspace addressable */
#define _PAGE_BIT_PWT 3 /* page write through */
arch/x86/include/uapi/asm/processor-flags.h
définit CR0
et, en particulier, le PG
position du bit :
#define X86_CR0_PG_BIT 31 /* Paging */
Bibliographie
Gratuit :
Non libre :