Linux usa la segmentazione paginata che semplifica molto la notazione.
Vengono utilizzati soltanto 4 segmenti:
__ 4 GB--->| | | | Kernel | | Kernel Mode (Codice + Dati/Stack) | | __| 3 GB--->|----------------| __ | | | | | | 2 GB--->| | | | Tasks | | User Mode (Codice + Dati/Stack) | | | 1 GB--->| | | | | | |________________| __| 0x00000000 Indirizzi Lineari Kernel/User
Linux implementa la Paginazione usando 3 Levelli di Pagine, ma su architettura 386+ solo 2 sono effettivamente utilizzati:
----------------------------------------------------------------- I N D I R I Z Z I L I N E A R I ----------------------------------------------------------------- \___/ \___/ \_____/ PD offset PF offset Frame offset [10 bits] [10 bits] [12 bits] | | | | | ----------- | | | | Valore |----------|--------- | | | | |---------| /|\ | | | | | | | | | | | | | | | | | | Frame offset | | | | | | | \|/ | | | | | |---------|<------ | | | | | | | | | | | | | | | | x 4096 | | | | PF offset|_________|------- | | | | /|\ | | | PD offset |_________|----- | | | _________| /|\ | | | | | | | | | | | \|/ | | \|/ _____ | | | ------>|_________| INDIRIZZO FISICO | | \|/ | | x 4096 | | | CR3 |-------->| | | | |_____| | ....... | | ....... | | | | | Page Directory Page File Paginazione su 386+
Linux gestisce il Controllo di Accesso soltanto sulla Paginazione, quindi Tasks differenti possono condividere lo stesso indirizzo di Segmento ma, avendo differenti valori nel registro CR3 (usato per puntare alla Page Directory), puntano effettivamente a differenti Pagine.
In User mode un Task non puo' superare il limite di 3 GB (0 x C0 00 00 00), quindi soltanto le prime 768 page directories hanno senso (768*4MB = 3GB, perche' ogni page directory e' grande 4MB).
Quando un Task entra in Kernel Mode (tramite System call o IRQ) le altre 256 pages directories sono effettivamente utilizzate e sono in comune rispetto a tutti gli altri Tasks (quindi sempre le stesse aree di memoria).
Si noti che lo Spazio Lineare del Kernel (e soltanto del Kernel) e' uguale allo Spazio Fisico, cosicche':
________________ _____ |Altri Dati Kernel|___ | | | |-----------------| | |__| | | Kernel |\ |____| Spazio Reale | 3 GB --->|-----------------| \ | Altri Dati Kernel | | |\ \ | | | ___|_\_\____|__ Spazio | | Tasks | \ \ | Reale | | ___|___\_\__|__ Tasks | | | \ \ | | | | \ \|-------------------| | | \ |Spazio Reale Kernel| |_________________| \|___________________| Indirizzi Logici Indirizzi Fisici
Lo Spazio Lineare del Kernel corrisponde allo Spazio Fisico traslato di 3 GB in basso (infatti le page tables sono del tipo { "00000000", "00000001" }, di modo che possano lavorare senza virtualizzazione, riportando semplicemente il valore lineare su quello fisico).
Si noti come non esista neanche conflitto tra gli indirizzi fisici Kernel e quelli User perche' il Kernel ha un'allocazione di tipo statica (quindi conosciamo subito dove piazzare i dati): per quanto riguarda i moduli o i dati aggiuntivi, basta scegliere i valori in modo tale che non vadano in conflitto con le Page Tables gia' presenti dello User Mode.
Si parte dalla funzione ''kmem_cache_init'' (lanciata da start_kernel [init/main.c] all'avvio):
|kmem_cache_init |kmem_cache_estimate
Continuiamo con ''mem_init'' (anch'essa lanciata da start_kernel[init/main.c])
|mem_init |free_all_bootmem |free_all_bootmem_core
Su Linux, quando vogliamo allocate memoria, ad esempio durante la "copy_on_write" (si veda il Cap.10), chiamiamo:
|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
DAFARE: Capire le Zone
Lo Swapping viene gestito dal demone ''kswapd'' (Kernel Thread).
Come tutti i Kernel Threads, ''kswapd'' ha un ciclo principale in attesa di essere svegliato.
|kswapd |// routines di inizializzazione |for (;;) { // Ciclo principale |do_try_to_free_pages |recalculate_vm_stats |refill_inactive_scan |run_task_queue |interruptible_sleep_on_timeout // In attesa di essere svegliati |}
Lo Swapping e' necessario quando dobbiamo accedere ad una pagina che non e' presente in memoria fisica: il tutto viene scatenato da un'eccezione (generata dall'accesso non autorizzato):
| Page Fault Exception | cause by all these conditions: | a-) User page | b-) Read or write access | c-) Page not present | | -----------> |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 // Svegliamo kswapd Page Fault ICA