Comment fonctionne x86 paging?

cette question est destinée à combler le vide d'une bonne information gratuite sur le sujet.

je crois qu'une bonne réponse s'insérera dans une grande réponse ou au moins dans quelques réponses.

le but principal est de donner aux débutants complets juste assez d'informations pour qu'ils puissent prendre le manuel par eux-mêmes, et être en mesure de comprendre les concepts de base de L'OS liés à la pagination.

lignes directrices suggérées:

  • les réponses doivent être conviviales pour les débutants:
    • le béton, mais les exemples éventuellement simplifiés sont très importants
    • les applications des concepts présentés sont les bienvenues
  • citer des ressources utiles est bon
  • petites digressions dans la façon dont les fonctionnalités de paging OSs utilisation sont les bienvenus
  • PAE et PSE explications sont les bienvenues
  • petites digressions dans x86_64 sont les bienvenus

questions connexes et pourquoi je pense qu'ils ne sont pas dupés:

64
demandé sur Community 2013-08-25 20:42:02

2 réponses

Version de cette réponse avec un TOC agréable et plus de contenu .

je corrigerai toute erreur signalée. Si vous voulez faire de grandes modifications ou ajouter un aspect manquant, faites-les sur vos propres réponses pour obtenir bien mérité rep. Les modifications mineures peuvent être fusionnées directement.

code échantillon

exemple Minimal: https://github.com/cirosantilli/x86-bare-metal-examples/blob/5c672f73884a487414b3e21bd9e579c67cd77621/paging.S

comme tout le reste dans la programmation, la seule façon de vraiment comprendre cela est de jouer avec des exemples minimaux.

ce qui rend ce sujet" difficile " est que l'exemple minimal est grand parce que vous avez besoin de faire votre propre petit OS.

manuel Intel

bien qu'il est impossible à comprendre sans exemples à l'esprit, essayer de se familiariser avec les manuels dès que possible.

Intel décrit la pagination dans le manuel Intel Volume 3 Guide de programmation de système-325384-056US septembre 2015 Chapitre 4 "pagination".

est particulièrement intéressante la Figure 4-4 "Formats des entrées CR3 et des structures de pagination avec pagination 32 bits", qui donne les structures de données clés.

MMU

la Pagination est faite par Unité de Gestion Mémoire (MMU) la partie de la CPU. Comme beaucoup d'autres (par exemple x87 co-processeur , APIC ), ce qui était par le passé par puce séparée sur les premiers jours, qui a été plus tard intégré dans le CPU. Mais le terme est encore utilisé.

faits Généraux

les adresses logiques sont les adresses mémoire utilisées dans code d'Utilisateur" régulier "(par exemple le contenu de rsi dans 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 aux adresses physiques comme l'indexation de la mémoire vive réelle, mais ce n'est pas 100% vrai en raison de:

d'échange est uniquement disponible en mode protégé. L'utilisation de la pagination en mode protégé est facultative. La pagination est sur iff le bit PG du registre cr0 est défini.

Échange vs segmentation

une différence majeure entre la pagination et la segmentation est que:

  • échange divise la mémoire vive en morceaux égaux de taille appelés pages
  • segmentation divise la mémoire en morceaux de dimensions arbitraires

C'est le principal avantage de la pagination, car des morceaux de taille égale rendent les choses plus faciles à gérer.

Paging est devenu tellement plus populaire que le support pour la segmentation a été abandonné dans x86-64 en mode 64 bits, le principal mode de fonctionnement pour les nouveaux logiciel, où il n'existe qu'en mode compatibilité, qui émule IA32.

Application

Paging est utilisé pour mettre en œuvre des processus espaces d'adresse virtuelle sur les systèmes D'exploitation modernes. Avec les adresses virtuelles, L'OS peut s'adapter à deux processus concurrents ou plus sur une seule RAM d'une manière telle que:

  • les deux programmes ne doivent rien savoir de l'autre
  • la mémoire des deux programmes peut croître et rétrécir au besoin
  • le changement entre les programmes est très rapide
  • un programme ne peut jamais accéder à la mémoire d'un autre processus

Paging historiquement venu après la segmentation, et largement remplacé pour la mise en œuvre de la mémoire virtuelle dans les os modernes tels que Linux car il est plus facile de gérer les morceaux de taille fixe de la mémoire des pages au lieu de segments de longueur variable.

Matériel de mise en œuvre

comme la segmentation en mode protégé (où la modification d'un registre de segments déclenche une charge à partir du GDT ou LDT), le matériel de pagination utilise des structures de données en mémoire pour faire son travail (tableaux de page, répertoires de page, etc.).

le format de ces structures de données est fixé par le matériel , mais c'est à L'OS de configurer et de gérer ces structures de données sur la RAM correctement, et de dire le matériel où les trouver (via cr3 ).

D'autres architectures laissent la pagination presque entièrement entre les mains du logiciel, de sorte qu'une fonction TLB fonctionne avec une fonction fournie par OS pour parcourir les tables de page et insérer la nouvelle mapping dans le TLB. Cela laisse les formats de table de page à choisir par le système D'exploitation, mais rend peu probable que le matériel puisse chevaucher les marches de page avec l'exécution hors-ordre d'autres instructions, de la même manière que x86 peut .

Exemple: unique simplifié au niveau de la pagination régime

ceci est un exemple de la façon dont la paging fonctionne sur une version simplifiée de l'architecture x86 mettre en place un espace mémoire virtuel.

tables de Page

L'OS pourrait leur donner la page suivante tables:

de la Page table donnée à 1 par le système d'exploitation:

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

de la Page table de traiter 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 et PT2 : position initiale des tableaux 1 et 2 sur la mémoire vive.

    valeurs échantillons: 0x00000000 , 0x12345678 , etc.

    c'est L'OS qui décide de ces valeurs.

  • L : longueur d'un tableau de page entrée.

  • present : indique que la page est présente dans la mémoire.

les tables de Page se trouvent sur RAM. Ils pourraient par exemple être localisés comme:

--------------> 0xFFFFFFFF


--------------> PT1 + 0xFFFFF * L
Page Table 1
--------------> PT1


--------------> PT2 + 0xFFFFF * L
Page Table 2
--------------> PT2

--------------> 0x0

les emplacements initiaux sur la RAM pour les deux tables de page sont arbitraires et contrôlés par L'OS. C'est à l'OS de s'assurer qu'ils ne se chevauchent pas!

chaque procédé ne peut pas toucher directement les tables de page, bien qu'il puisse faire des requêtes à L'OS qui provoquent la modification des tables de page, par exemple en demandant une plus grande pile ou des segments tas.

une page est un morceau de 4KB (12 bits), et puisque les adresses ont 32 bits, seulement 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 tableau de Page

un tableau de page est... une table d'entrées de tableau de pages!

le format exact des entrées de tableau est fixé par le matériel .

dans cet exemple simplifié, les entrées du tableau de page ne contiennent que deux champs:

bits   function
-----  -----------------------------------------
20     physical address of the start of the page
1      present flag

ainsi, dans cet exemple, les concepteurs de matériel auraient pu choisir L = 21 .

la plupart des entrées de table de page réelles ont d'autres champs.

il ne serait pas pratique d'aligner les choses à 21 octets puisque la mémoire est adressable par octets et non par bits. Par conséquent, même en 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 il suffit de réserver les bits restants bits pour une utilisation ultérieure. La valeur réelle pour L sur x86 est de 32 bits.

traduction d'Adresse dans à un seul niveau régime

une fois le les tables de page ont été établies par L'OS, la traduction d'adresse entre les adresses linéaires et physiques est faite par le matériel .

quand L'OS veut activer le processus 1 , Il fixe le cr3 à PT1 , le début de la table pour le processus 1.

si Process 1 veut accéder à l'adresse linéaire 0x00000001 , la pagination matériel circuit fait automatiquement le suivant pour L'OS:

  • la scission de l'adresse linéaire en deux parties:

    | page (20 bits) | offset (12 bits) |
    

    donc dans ce cas nous aurions:

    • page = 0x00000
    • offset = 0x001
  • examinez le tableau de la Page 1 parce que cr3 y renvoie.

  • regardez entrée 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

  • dans le tableau, le numéro de page 0x00000 se trouve à 0x00001 * 4K = 0x00001000 .

  • pour trouver le physique final adresse il suffit d'ajouter l'offset:

      00001 000
    + 00000 001
      -----------
      00001 001
    

    parce que 00001 est l'adresse physique de la page cherchée sur la table et 001 est l'offset.

    Comme son nom l'indique, le décalage est toujours simplement ajouté l'adresse physique de la page.

  • le matériel reçoit alors la mémoire à cet endroit 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 de table de page est située à L'adresse RAM: PT1 + 1 * L ( 1 en raison de la partie de la page), et c'est là qu'il le cherchera.

quand L'OS veut passer au processus 2, Tout ce qu'il a à faire est de faire cr3 point 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 , en fonction uniquement de la valeur à l'intérieur de cr3 .

de cette façon , chaque programme peut s'attendre à ce que ses données commencent à 0 et se terminent à FFFFFFFF , sans s'inquiéter des adresses physiques exactes.

Page fault

Que si le Processus 1 tente d'accéder à une adresse à l'intérieur d'une page qui n'est pas présente?

le matériel avertit le logiciel via une exception D'erreur de Page.

il appartient alors habituellement à L'OS d'enregistrer un gestionnaire d'exception pour décider de ce qui doit être fait.

il est possible que l'accès à une page qui n'est pas la table est une erreur de programmation:

int is[1];
is[2] = 1;

mais il peut y avoir des cas dans lesquels il est acceptable, par exemple sous Linux quand:

  • le programme veut augmenter sa pile.

    il essaie simplement d'accéder à un octet donné dans une plage donnée, et si L'OS est content il ajoute cette page à l'espace d'adresse du processus.

  • la page a été échangé sur le disque.

    L'OS aura besoin de faire un peu de travail derrière les processus de retour pour obtenir la page de nouveau dans la RAM.

    L'OS peut découvrir que c'est le cas basé sur le contenu du reste de l'entrée de table de page, puisque si le drapeau actuel est clair, les autres entrées de l'entrée de table de page sont complètement laissés pour L'OS à ce qu'il veut.

    sur Linux par exemple, quand présent = 0:

    • si tous les champs de l'entrée de table de page sont 0, adresse invalide.

    • autrement, la page a été changée en disque, et les valeurs réelles de ces champs encodent 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é la Page Fault pour être en mesure de traiter le problème. C'est pourquoi les développeurs de nice IA32 ont défini la valeur de cr2 à cette adresse chaque fois qu'une Page est défectueuse. Le gestionnaire d'exception peut alors simplement regarder dans cr2 pour obtenir l'adresse.

Simplifications

Simplifications à la réalité qui rendent cet exemple plus facile à comprendre:

  • " tous les circuits de téléappel réels utilisent la téléappel à plusieurs niveaux pour économiser de l'espace, mais cela a montré une niveau régime.

  • les tables de page ne contenaient que deux champs: une adresse de 20 bits et un drapeau de present DE 1 bit.

    les tables des pages réelles contiennent un total de 12 champs, et donc d'autres caractéristiques qui ont été omises.

Exemple: multi-niveau de la pagination régime

Le problème avec un seul niveau de pagination régime, c'est qu'il prendrait trop beaucoup de RAM: 4G / 4K = 1m entrées par processus. Si chaque entrée est de 4 bytes de long, cela ferait 4M par processus , ce qui est trop même pour un ordinateur de bureau: ps -A | wc -l dit que je suis en train d'exécuter 244 processus en ce moment, donc cela prendrait 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.

le système is 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 divisés comme suit:

| directory (10 bits) | table (10 bits) | offset (12 bits) |

chaque processus doit avoir un et un seul répertoire de page associé à lui, de sorte qu'il contiendra au moins 2^10 = 1K les entrées de répertoire de page, beaucoup mieux que le minimum de 1M requis sur un schéma de niveau unique.

Page les tableaux ne sont attribués qu'en fonction des besoins de L'EO. Chaque table de page a 2^10 = 1K les entrées de répertoire de page

les répertoires de pages contiennent... entrées du répertoire de page! Les entrées de répertoire de Page sont les mêmes que les entrées de table de page sauf que ils pointent vers les adresses RAM des tables de page au lieu des adresses physiques des tables . Puisque ces adresses sont seulement 20 bits de large, les tableaux de page doivent être au début de 4KB pages.

cr3 indique maintenant L'emplacement sur la RAM du répertoire de page du processus courant au lieu des tables de page.

les entrées de tableaux de Page ne changent pas du tout d'un schéma à un niveau.

les tableaux de Page changent d'un schéma à un niveau parce que:

  • chaque processus peut comporter jusqu'à 1K tableaux de page, un par entrée de répertoire de page.
  • chaque tableau de page contient exactement 1K entrées au lieu d'entrées de 1M.

la raison de l'utilisation de 10 bits sur les deux premiers niveaux (et pas, disons, 12 | 8 | 12 ) est que chaque entrée de Table de Page est de 4 octets de long. Ensuite, les 2^10 entrées des répertoires de Page et des Tables de Page s'adapteront bien dans des pages de 4KB. Cela signifie qu'il est plus rapide et plus simple d'allouer et de désallouer des pages à cette fin.

traduction d'Adresse en multi-niveau de régime

répertoire de Page donnée au procédé 1 par L'OS:

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

tables de Page données 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

tables de Page données 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 page du processus 1 sur RAM.
  • PT1 et PT2 : la position initiale de la table de page 1 et la page du tableau 2 pour 1 sur la RAM.

ainsi dans cet exemple le répertoire de page et la table de page pourraient être stockés en RAM quelque chose comme:

----------------> 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 pas à pas.

nous supposons que cr3 = PD1 , c'est-à-dire qu'il pointe vers le répertoire de page 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

Groupement 10 | 10 | 12 donne:

0000000010 0000000001 000000000100
0x2        0x1        0x4

qui donne:

  • répertoire de la page d'entrée = 0 x 2
  • entrée de table de page = 0x1
  • offset = 0 x 4

ainsi le matériel cherche l'entrée 2 du répertoire de page.

la table de répertoire de page indique que la table de page est située à 0x80000 * 4K = 0x80000000 . C'est le premier accès RAM du processus.

puisque l'entrée de tableau de page est 0x1 , le matériel regarde l'entrée 1 du tableau de page à 0x80000000 , qui lui dit que la page physique est située à l'adresse 0x0000C * 4K = 0x0000C000 . C'est le deuxième accès RAM du processus.

enfin, le matériel de pagination ajoute l'offset, et le final l'adresse est 0x0000C004 .

autres exemples d'adresses traduites:

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

défauts de Page se produire si une page d'entrée de répertoire ou d'une entrée de table de page n'est pas présente.

si le système d'exploitation veut exécuter un autre processus en même temps, il donnerait au deuxième processus un répertoire de page séparé, et lierait ce répertoire à des tables de page séparées.

architectures 64 bits

64 bits est encore trop d'adresse pour les tailles de RAM actuelles, 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 52 bits (4 PiB).

12 de ces 48 bits sont déjà réservés pour l'offset, qui laisse 36 bits.

si une approche à deux niveaux est adoptée, la meilleure répartition serait deux niveaux à 18 bits.

mais que cela signifierait que le répertoire de page aurait des entrées 2^18 = 256K , ce qui prendrait trop de RAM: proche d'une pagination à un seul niveau pour des architectures 32 bits!

par conséquent, les architectures 64 bits créent encore plus de niveaux de page, Généralement 3 ou 4.

x86_64 utilise 4 niveaux dans un schéma 9 | 9 | 9 | 12 , de sorte que le niveau supérieur ne prend que les entrées de niveau supérieur 2^9 .

PAE

Extension de l'adresse physique.

avec 32 bits, seule la RAM de 4 Go peut être adressée.

cela a commencé à devenir une limitation pour les gros serveurs, donc Intel a introduit le mécanisme PAE à Pentium Pro.

pour résoudre le problème, Intel a ajouté 4 nouvelles lignes d'adresse, de sorte que 64 Go puisse être adressée.

La structure du tableau de Page

est également modifiée si le PAE est activé. La manière exacte dont il est modifié dépend météo PSE est on ou off.

Le

PAE est allumé et éteint via le PAE bit de cr4 .

même si la mémoire adressable totale est de 64 Go, les processus individuels ne peuvent toujours utiliser que jusqu'à 4 Go. L'OS peut cependant mettre différents processus sur différents morceaux de 4 Go.

PSE

taille de la Page de l'extension.

permet aux pages d'être 4M ( ou 2M si PAE est sur ) en longueur au lieu de 4K.

PSE est activé et désactivé via le PAE bit de cr4 .

PAE et PSE page de la table des systèmes de 15191230920"

si L'un ou l'autre PAE et PSE sont actifs, différents systèmes de niveaux de pagination sont utilisés:

  • pas de PAE et pas de PSE: 10 | 10 | 12

  • pas de PAE et PSE: 10 | 22 .

    22 est l'offset dans la page de 4Mb, puisque l'adresse de 22 bits 4MB.

  • PAE et pas de PSE: 2 | 9 | 9 | 12

    la raison de conception pour laquelle 9 est utilisé deux fois au lieu de 10 est que maintenant les entrées ne peuvent plus s'insérer dans 32 bits, qui ont tous été remplis par 20 bits d'adresse et 12 bits de drapeau significatifs ou réservés.

    la raison est que 20 bits ne sont plus assez pour représenter l'adresse des tables de pages: 24 bits sont maintenant nécessaires en raison des 4 fils supplémentaires ajoutés au processeur.

    par conséquent, les concepteurs ont décidé d'augmenter la taille d'entrée à 64 bits, et pour les faire entrer dans un tableau d'une seule page, il est nécessaire de réduire le nombre d'entrées à 2^9 au lieu de 2^10.

    le niveau de départ 2 est un nouveau niveau de Page appelé page Directory Pointer Table (PDPT), depuis qu'il points aux annuaires de page et remplir le Adresse linéaire 32 bits. Les TDP ont aussi une largeur de 64 bits.

    cr3 indique maintenant PDPTs qui doit être sur le poing quatre 4 Go de mémoire et aligné sur 32 bits multiples pour l'efficacité d'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 des premiers 4 Go.

  • PAE and PSE: 2 | 9 | 21

    les Créateurs décidé de garder un champ 9 bits large pour le faire rentrer dans une seule page.

    il reste 23 bits. Laisser 2 pour le PDPT pour garder les choses uniformes avec le cas PAE sans PSE laisse 21 pour offset, ce qui signifie que les pages sont 2m de large au lieu de 4M.

TLB

le tampon Lookahead de traduction (TLB) est un cache pour les adresses de pagination.

Puisqu'il s'agit d'un cache, il partage bon nombre des problèmes de conception du cache CPU, tels que le niveau d'associativité.

cette section doit décrire un TLB entièrement associatif simplifié comportant 4 entrées à une seule adresse. Notez que comme les autres caches, les TLB réels ne sont généralement pas entièrement associatifs.

opération de base

après une traduction entre adresse linéaire et adresse physique se produit, il est stocké sur le TLB. Par exemple, un TLB à 4 entrées commence dans l'état suivant::

  valid   linear   physical
  ------  -------  ---------
> 0       00000    00000
  0       00000    00000
  0       00000    00000
  0       00000    00000

le > indique la rubrique actuelle à remplacer.

et après qu'une adresse linéaire de page 00003 est traduite 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 en 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 d'abord regarde le TLB et découvre son adresse avec un seul accès RAM 00003 --> 00005 .

bien sûr, 00000 ne figure pas sur le TLB car aucune entrée valide ne contient 00000 comme clé.

Politique de remplacement

quand TLB est rempli, les adresses plus anciennes sont écrasées. Tout comme pour le cache CPU, la Politique de remplacement est une opération potentiellement complexe, mais un heuristique simple et raisonnable est d'enlever le moins entrée récemment utilisée (LRU).

avec LRU, à partir de l'état:

  valid   linear   physical
  ------  -------  ---------
> 1       00003    00005
  1       00007    00009
  1       00009    00001
  1       0000B    00003

ajouter 0000D -> 0000A donnerait:

  valid   linear   physical
  ------  -------  ---------
  1       0000D    0000A
> 1       00007    00009
  1       00009    00001
  1       0000B    00003

CAM

en utilisant le TLB rend la traduction plus rapide, parce que la traduction initiale prend un accès par niveau TLB , ce qui signifie 2 sur un schéma 32 bits simple, mais 3 ou 4 sur des architectures 64 bits.

le TLB est généralement mis en œuvre comme un type coûteux de RAM appelé content-addressable memory (CAM). CAM implémente une carte associative sur le matériel, c'est-à-dire une structure qui donne une clé (adresse linéaire), récupère une valeur.

Les mappages

peuvent aussi être implémentés sur les adresses RAM, mais les mappages CAM peuvent nécessiter beaucoup moins d'entrées qu'un mappage RAM.

par exemple, une carte dans laquelle:

  • clés et valeurs avoir 20 bits (le cas d'une pagination simple régimes)
  • au maximum 4 valeurs doivent être stockées à chaque fois

peut être stocké dans un BLT avec 4 entrées:

linear   physical
-------  ---------
00000    00001
00001    00010
00010    00011
FFFFF    00000

Cependant, pour implémenter cela avec RAM, il faudrait avoir 2^20 adresses :

linear   physical
-------  ---------
00000    00001
00001    00010
00010    00011
... (from 00011 to FFFFE)
FFFFF    00000

qui serait encore plus coûteux que l'utilisation d'un TLB.

Invaliding entries

lorsque cr3 change, toutes les entrées TLB sont invalidées, parce qu'une nouvelle table de page pour un nouveau processus va être utilisé, il est donc peu probable que l'une des anciennes entrées ont un sens.

le x86 offre également l'instruction invlpg qui invalide explicitement une seule entrée TLB. D'autres architectures offrent encore plus d'instructions pour invalider les entrées TLB, comme invalider toutes les entrées sur une plage donnée.

certains CPU x86 vont au-delà des exigences de la spécification x86 et offrent plus de cohérence qu'elle ne garantit, entre la modification d'une entrée de table de page et son utilisation, lorsqu'elle n'était pas déjà mise en cache dans le TLB . Apparemment, Windows 9x s'est fié à cela pour être correct, mais les processeurs AMD modernes ne fournissent pas de chemins de page cohérents. Les processeurs Intel le font, même s'ils doivent détecter les fausses spéculations pour le faire. Prendre avantage de cela est probablement une mauvaise idée, puisqu'il n'y a probablement pas grand chose à gagner, et un grand risque de causer des problèmes subtils sensibles au timing qui seront difficiles à débugger.

Utilisation du noyau Linux

le noyau Linux utilise largement les fonctionnalités de paging de x86 pour permettre des commutateurs de processus rapides avec une faible fragmentation des données.

Dans v4.2 , regardez sous arch/x86/ :

  • include/asm/pgtable*
  • include/asm/page*
  • mm/pgtable*
  • mm/page*
  • include/asm/page_types.h

    il ne semble pas y avoir de structure définie pour représenter les pages, seulement des macros: include/asm/page_types.h est particulièrement intéressant. 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 la PG bit position:

    #define X86_CR0_PG_BIT      31 /* Paging */
    

    Bibliographie

    gratuit: 15191190920"

    • rutgers-pxk-416 au chapitre "gestion de la Mémoire: notes de cours"

      Bonne revue d'histoire de l'organisation de la mémoire les techniques utilisées par les anciens OS.

    Non-free:

    • bovet05 chapitre "Adressage de mémoire"

      introduction raisonnable à l'adressage mémoire x86. Manque de bons exemples simples.

104

Voici une réponse de haut niveau très courte:

un processeur x86 opère dans l'un des modes possibles (en gros: real, protected, 64-bit). Chaque mode peut utiliser l'un des différents modèles d'adressage mémoire possibles (mais tous les modes ne peuvent pas utiliser tous les modèles), à savoir: l'adressage en mode réel, l'adressage segmenté et l'adressage linéaire plat.

dans le monde moderne, seule l'adressage plat-linéaire en mode protégé ou 64 bits sont pertinents, et les deux les modes sont essentiellement les mêmes, la principale différence étant la taille du mot machine et donc la quantité adressable de mémoire.

maintenant , le mode d'adressage mémoire donne sens aux opérandes mémoire des instructions machine (telles que mov DWORD PTR [eax], 25 , qui stocke un entier 32 bits (alias dword ) de valeur 25 dans la mémoire dont l'adresse est stockée dans le registre eax 32 bits). En adressage plat-linéaire, ce nombre dans eax est autorisé à exécuter sur une seule plage contigüe, de zéro jusqu'à la valeur maximale (dans notre cas, c'est 2 32 - 1).

Cependant, plate-adressage linéaire peut être soit paginé ou non paginée . Sans pagination, l'adresse se réfère directement à la mémoire physique. avec paging, l'Unité de gestion de la mémoire du processeur (ou MMU) alimente de manière transparente l'adresse désirée (maintenant appelé a adresse virtuelle ) dans un mécanisme de recherche, le soi-disant tables de page , et obtient une nouvelle valeur, qui est interprété comme une adresse physique. L'opération originale fonctionne maintenant sur cette nouvelle adresse traduite dans la mémoire physique, même si l'utilisateur ne voit que l'adresse virtuelle.

le principal avantage de la pagination est que les tables de page sont gérées par le système d'exploitation. Ainsi le système d'exploitation peut modifier et remplacer la page tables arbitrairement, comme quand "commutation des tâches". Il peut garder toute une collection de tables de page, une pour chaque "processus", et chaque fois qu'il décide qu'un processus particulier va fonctionner sur un CPU donné, il charge les tables de page du processus dans le MMU de ce CPU (chaque CPU a son propre ensemble de tables de page). Le résultat est que chaque processus voit son propre virtuel espace d'adresse qui ressemble à la même indépendamment de quelles pages physiques étaient libres lorsque L'OS a dû allouer de mémoire pour elle. Il ne connaît jamais la mémoire d'aucun autre processus, puisqu'il ne peut accéder directement à la mémoire physique.

les tableaux de Page sont des structures arborescentes imbriquées stockées en mémoire normale, écrites par L'OS mais lues directement par le matériel, de sorte que le format est fixe. Ils sont "chargés" dans le MMU en mettant un registre de contrôle CPU spécial pour pointer vers la table de niveau supérieur. Le CPU utilise un cache appelé TLB pour se souvenir des recherches, donc des accès répétés aux mêmes quelques pages sont beaucoup plus rapides que les accès dispersés, pour des raisons TLB-miss ainsi que les raisons habituelles de cache de données. Il est courant de voir le terme "entrée TLB" utilisé pour renvoyer aux entrées de table de page même si elles ne sont pas mises en cache dans le TLB.

et dans le cas où vous vous inquiétez qu'un processus pourrait juste désactiver paging ou essayer de modifier les tables de page: ceci n'est pas autorisé, car x86 implémente niveaux de privilège (appelé "anneaux"), et le code utilisateur exécute à un niveau de privilège c'est trop bas pour lui permettre de modifier les tables de page du CPU.

15
répondu Kerrek SB 2016-04-05 13:21:13