Next Previous Contents

7. Gestione della Memoria su Linux

7.1 Introduzione

Linux usa la segmentazione paginata che semplifica molto la notazione.

Segmenti

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
 

7.2 Implementazione 386+

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+
 


7.3 Mappatura Memory

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.

7.4 Allocazione della memoria a basso livello

Inizializzazione di Avvio

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

Allocazione Run-time

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

7.5 Swapping

Introduzione

Lo Swapping viene gestito dal demone ''kswapd'' (Kernel Thread).

kswapd

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
   |}

Quando abbiamo bisogno dello swapping?

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
 


Next Previous Contents