Linux utilise segmentation + pagination, ce qui simplifie la notation.
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
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
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.
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
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
L'échange est géré par le service kswapd (fil du noyau).
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 |}
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