Page suivante Page précédente Table des matières

7. Gestion de Mémoire de Linux

7.1 Vue d'ensemble

Linux utilise segmentation + pagination, ce qui simplifie la notation.

Segments

Linux utilise seulement 4 segments:

                               __
   4 Go--->|                |    |
           |     Noyau      |    |  Espace Noyau (Code + Donnée/Pile)
           |                |  __|
   3 Go--->|----------------|  __
           |                |    |
           |                |    |
   2 Go--->|                |    |
           |     Tâche      |    |  Espace Utilisateur (Code + Donnée/Pile)
           |                |    |
   1 Go--->|                |    |
           |                |    |
           |________________|  __| 
 0x00000000
          Adresses Linéaires Noyau/Utilisateur
 

7.2 Implémentation i386 spécifique

A nouveau, Linux implémente la Pagination en utilisant 3 Niveaux de Pagination, mais dans l'architecture i386 seulement 2 d'entre elles sont vraiment utilisées:

 
   ------------------------------------------------------------------
     A   D   R   E   S   S   E       L   I   N   E   A   I   R   E
   ------------------------------------------------------------------
        \___/                 \___/                     \_____/ 
 
     PD offset              PF offset                 Frame offset 
     [10 bits]              [10 bits]                 [12 bits]       
          |                     |                          |
          |                     |     -----------          |        
          |                     |     |  Value  |----------|---------
          |     |         |     |     |---------|   /|\    |        |
          |     |         |     |     |         |    |     |        |
          |     |         |     |     |         |    | Frame offset |
          |     |         |     |     |         |   \|/             |
          |     |         |     |     |---------|<------            |
          |     |         |     |     |         |      |            |
          |     |         |     |     |         |      | x 4096     |
          |     |         |  PF offset|_________|-------            |
          |     |         |       /|\ |         |                   |
      PD offset |_________|-----   |  |         |          _________|
            /|\ |         |    |   |  |         |          | 
             |  |         |    |  \|/ |         |         \|/
 _____       |  |         |    ------>|_________|   PHYSICAL ADDRESS 
|     |     \|/ |         |    x 4096 |         |
| CR3 |-------->|         |           |         |
|_____|         | ....... |           | ....... |
                |         |           |         |    
 
               Dossier Page           Fichier Page

                       Pagination Linux i386
 


7.3 Traçage Mémoire

Linux gère le Contrôle d'Accès seulement avec des paginations, ainsi les différentes Tâches auront les mêmes adresses de segment, mais un CR3 différent (registre utilisé pour stocker l'Adresse de Page du Dossier), pointant vers une Page différente.

En Mode Utilisateur une Tâche ne peut pas dépasser la limite de 3 Go (0 x C0 00 00 00), ainsi seulement les 768 premières entrées de répertoire de page sont significative (768*4mb = 3Go).

Quand une Tâche passe en Mode Noyau (par Appel System ou par IRQ) d'autres entrées de répertoire de 256 pages deviennent importantes, et elles pointent vers les mêmes fichiers de page que toutes autres Tâches (qui sont les même que le noyau).

Notez que l'Espace Linéaire du Noyau (et seulement du noyau) est égal à l'Espace Physique du Noyau, ainsi:

 
            ________________ _____                    
           |Other KernelData|___  |  |                |
           |----------------|   | |__|                |
           |     Kernel     |\  |____|   Real Other   |
  3 GB --->|----------------| \      |   Kernel Data  |
           |                |\ \     |                |
           |              __|_\_\____|__   Real       |
           |      Tasks     |  \ \   |     Tasks      |
           |              __|___\_\__|__   Space      |
           |                |    \ \ |                |
           |                |     \ \|----------------|
           |                |      \ |Real KernelSpace|
           |________________|       \|________________|
      
           Adresses Logiques          Adresses Physiques
 

L'Espace Linéaire du Noyau correspond à l'Espace Physique du Noyau transféré 3 Go plus bas (translated 3GB down) (en fait les tables de page sont quelque chose comme { "00000000", "00000001" }, ainsi elles n'effectuent aucune virtualisation, elles reportent seulement des adresses physiques qu'elles prennent des linéaires).

Notez que vous n'aurez pas un "conflit d'adresses" entre les espaces Noyau et Utilisateur parce que nous pouvons gérer des adresses physiques avec les Tableaux de Page.

7.4 Attribution de mémoire de bas niveau

Initialisation du Démarrage

Nous commençons à partir du kmem_cache_init (lancé par start_kernel [ init/main.c ] au démarrage).

|kmem_cache_init
   |kmem_cache_estimate

kmem_cache_init [mm/slab.c]

kmem_cache_estimate

Maintenant nous continuons avec mem_init (également lancé par start_kernel[init/main.c ])

|mem_init
   |free_all_bootmem
      |free_all_bootmem_core

mem_init [arch/i386/mm/init.c]

free_all_bootmem [mm/bootmem.c]

free_all_bootmem_core

Allocation du temps d'exécution

Sous Linux, quand nous voulons allouer de la mémoire, par exemple pendant le mécanisme "copy_on_write" (voir Chap.10), nous appelons:

|copy_mm 
   |allocate_mm = kmem_cache_alloc
      |__kmem_cache_alloc
         |kmem_cache_alloc_one
            |alloc_new_slab
               |kmem_cache_grow
                  |kmem_getpages
                     |__get_free_pages
                        |alloc_pages
                           |alloc_pages_pgdat
                              |__alloc_pages
                                 |rmqueue   
                                 |reclaim_pages

Les fonctions peuvent être trouvées ci-dessous:

TODO: Comprendre les Zones

7.5 Échange (Swap ou glissement)

Vue d'ensemble

L'échange est géré par le service kswapd (fil du noyau).

kswapd

Comme d'autres fils du noyau, le kswapd a une boucle principale qui attend de se réveiller.

|kswapd
   |// initialization routines
   |for (;;) { // Main loop
      |do_try_to_free_pages
      |recalculate_vm_stats
      |refill_inactive_scan
      |run_task_queue
      |interruptible_sleep_on_timeout // on dort en attendant une nouvelle demande d'échange
   |}

Quand avons-nous besoin d'échanger?

L'échange est nécessaire quand nous devons accéder à une page qui n'est pas en mémoire physique.

Linux utilise le fil du noyau ''kswapd'' pour ce faire. Quand la Tâche reçoit une faute d'exception de page nous faisons ce qui suit:

 
 | Faute d'Execption de Page
 | causée par toutes ces conditions: 
 |   a-) Page Utilisateur
 |   b-) Accès lecture ou écriture
 |   c-) Page non présente
 |
 |
 -----------> |do_page_fault
                 |handle_mm_fault
                    |pte_alloc 
                       |pte_alloc_one
                          |__get_free_page = __get_free_pages
                             |alloc_pages
                                |alloc_pages_pgdat
                                   |__alloc_pages
                                      |wakeup_kswapd // Nous réveillons le fil de noyau kswapd
   
                   Page Fault ICA
 

Page suivante Page précédente Table des matières