Sono interessato alla differenza tra Highmem e Lowmem:
- Perché esiste una tale differenziazione?
- Cosa otteniamo facendo così?
- Quali funzionalità hanno ciascuna?
Sono interessato alla differenza tra Highmem e Lowmem:
Risposte:
Su un'architettura a 32 bit, l'intervallo di indirizzi per indirizzare la RAM è:
0x00000000 - 0xffffffff
o 4'294'967'295
(4 GB).
Il kernel di Linux lo divide in 3/1 (potrebbe anche essere 2/2 o 1/3 1 ) rispettivamente nello spazio utente (memoria alta) e nello spazio kernel (memoria bassa).
L'intervallo di spazio utente:
0x00000000 - 0xbfffffff
Ogni processo utente appena generato ottiene un indirizzo (intervallo) all'interno di quest'area. I processi utente non sono generalmente attendibili e pertanto è vietato accedere allo spazio del kernel. Inoltre, sono considerati non urgenti, come regola generale, il kernel cerca di rinviare l'allocazione della memoria a tali processi.
La gamma di spazio del kernel:
0xc0000000 - 0xffffffff
I processi di un kernel ottengono qui il suo indirizzo (intervallo). Il kernel può accedere direttamente a questi 1 GB di indirizzi (beh, non tutti i 1 GB, ci sono 128 MB riservati per l'accesso ad alta memoria).
I processi generati nello spazio del kernel sono attendibili, urgenti e considerati privi di errori, la richiesta di memoria viene elaborata istantaneamente.
Ogni processo del kernel può anche accedere all'intervallo di spazio dell'utente se lo desidera. E per raggiungere questo obiettivo, il kernel mappa un indirizzo dallo spazio utente (la memoria alta) al suo spazio kernel (la memoria bassa), i 128 MB sopra menzionati sono particolarmente riservati per questo.
1 Se la divisione è 3/1, 2/2 o 1/3 è controllata CONFIG_VMSPLIT_...
dall'opzione; probabilmente puoi controllare sotto /boot/config*
per vedere quale opzione è stata selezionata per il tuo kernel.
Il primo riferimento a cui rivolgersi è Linux Device Driver (disponibile sia online che in forma di libro), in particolare il capitolo 15 che contiene una sezione sull'argomento.
In un mondo ideale, ogni componente del sistema sarebbe in grado di mappare tutta la memoria a cui deve accedere. E questo è il caso dei processi su Linux e della maggior parte dei sistemi operativi: un processo a 32 bit può accedere solo a poco meno di 2 ^ 32 byte di memoria virtuale (in effetti circa 3 GB su una tipica architettura Linux a 32 bit). Diventa difficile per il kernel, che deve essere in grado di mappare l'intera memoria del processo di cui è in esecuzione la chiamata di sistema, oltre all'intera memoria fisica, oltre a qualsiasi altro dispositivo hardware mappato in memoria.
Pertanto, quando un kernel a 32 bit deve mappare più di 4 GB di memoria, deve essere compilato con un supporto di memoria elevato. La memoria alta è la memoria che non è mappata in modo permanente nello spazio degli indirizzi del kernel. (La memoria insufficiente è l'opposto: è sempre mappata, quindi puoi accedervi nel kernel semplicemente dereferenziando un puntatore.)
Quando si accede a memoria elevata dal codice del kernel, è necessario chiamare kmap
prima per ottenere un puntatore da una struttura di dati di pagina ( struct page
). La chiamata kmap
funziona se la pagina è in memoria alta o bassa. C'è anche quello kmap_atomic
che ha aggiunto vincoli ma è più efficiente su macchine multiprocessore perché utilizza un blocco a grana più fine. Il puntatore ottenuto attraverso kmap
è una risorsa: utilizza lo spazio degli indirizzi. Una volta che hai finito, devi chiamare kunmap
(o kunmap_atomic
) per liberare quella risorsa; quindi il puntatore non è più valido e non è possibile accedere ai contenuti della pagina finché non si chiama di kmap
nuovo.
Questo è rilevante per il kernel Linux; Non sono sicuro di come gestisca questo kernel Unix.
L'High Memory è il segmento di memoria che i programmi di spazio utente possono affrontare. Non può toccare memoria insufficiente.
La memoria insufficiente è il segmento di memoria che il kernel Linux può indirizzare direttamente. Se il kernel deve accedere alla memoria elevata, deve prima mapparlo nel proprio spazio di indirizzi.
Recentemente è stata introdotta una patch che ti consente di controllare dove si trova il segmento. Il compromesso è che puoi portare la memoria indirizzabile lontano dallo spazio utente in modo che il kernel possa avere più memoria che non deve mappare prima dell'uso.
Risorse addizionali:
HIGHMEM è una gamma di spazio di memoria del kernel, ma NON è la memoria a cui si accede ma è un luogo in cui si inserisce ciò a cui si desidera accedere.
Una tipica mappa di memoria virtuale Linux a 32 bit è simile a:
0x00000000-0xbfffffff: processo utente (3 GB)
0xc0000000-0xffffffff: spazio del kernel (1 GB)
(Qui vengono ignorati il vettore specifico della CPU e qualsiasi altra cosa).
Linux divide lo spazio del kernel da 1 GB in 2 pezzi, LOWMEM e HIGHMEM. La divisione varia da installazione a installazione.
Se un'installazione sceglie, diciamo, 512 MB-512 MB per mem LOW e HIGH, il LOWMEM da 512 MB (0xc0000000-0xdfffffff) viene mappato staticamente all'avvio del kernel; di solito vengono utilizzati i primi così tanti byte della memoria fisica in modo che gli indirizzi virtuali e fisici in questo intervallo abbiano un offset costante, diciamo, 0xc0000000.
D'altro canto, quest'ultimo 512 MB (HIGHMEM) non ha una mappatura statica (anche se è possibile lasciare pagine mappate in modo semi-permanente lì, ma è necessario farlo esplicitamente nel codice del driver). Invece, le pagine vengono temporaneamente mappate e non mappate qui in modo che gli indirizzi virtuali e fisici in questo intervallo non abbiano una mappatura coerente. Gli usi tipici di HIGHMEM includono buffer di dati a tempo singolo.
Molte persone hanno detto che la memoria insufficiente è per il sistema operativo. Questo di solito è vero ma non deve essere. Alta memoria e poca memoria sono solo due parti dello spazio di memoria, ma nel sistema Linux la memoria bassa è solo per il kernel e la memoria alta per i processi utente.
Secondo il "Libro dei dinosauri (concetti del sistema operativo)", possiamo posizionare il sistema operativo in memoria insufficiente o memoria elevata. Il principale fattore che influenza questa decisione è la posizione del vettore di interrupt. Poiché il vettore di interruzione è spesso in memoria insufficiente, i programmatori di solito mettono anche il sistema operativo in memoria insufficiente.