In superficie, questa sembra essere una domanda stupida. Po 'di pazienza per favore .. :-) Am strutturare questo qs in 2 parti:In che modo gli indirizzi virtuali del kernel vengono convertiti nella RAM fisica?
Parte 1: Capisco pienamente che la piattaforma di RAM è mappato nel segmento kernel; specialmente sui sistemi a 64 bit funzionerà bene. Quindi ogni indirizzo virtuale del kernel è in effetti solo un offset dalla memoria fisica (DRAM).
Inoltre, è la mia comprensione che, come Linux è un moderno sistema operativo di memoria virtuale, (più o meno) tutti indirizzi vengono trattati come gli indirizzi virtuali e devono "andare" via hardware - il TLB/MMU - in fase di esecuzione e quindi ottenere tradotto dal TLB/MMU tramite tabelle di paging del kernel. Di nuovo, facile da capire per i processi in modalità utente.
TUTTAVIA, che dire degli indirizzi virtuali del kernel? Per efficienza, non sarebbe più semplice mapparli direttamente (e una mappatura dell'identità è effettivamente impostata da PAGE_OFFSET in poi). Tuttavia, in fase di runtime, l'indirizzo virtuale del kernel deve passare tramite TLB/MMU e ottenere tradotto a destra ??? È questo il vero caso? O è la traduzione addr virtuale del kernel solo un calcolo di offset ?? (Ma come può essere, dato che lo deve passare a tramite hardware TLB/MMU?). Come semplice esempio, consideriamo:
char *kptr = kmalloc(1024, GFP_KERNEL);
Ora kptr è un indirizzo virtuale del kernel. Capisco che virt_to_phys() possa eseguire il calcolo dell'offset e restituire l'indirizzo fisico DRAM. Ma, , ecco la domanda reale: non può essere fatto in questo modo tramite software - che sarebbe pateticamente lento! Quindi, tornando al mio punto precedente: avrebbe dovuto essere tradotto via hardware (TLB/MMU). È questo il caso ??
Parte 2: Va bene, lascia per dire questo è il caso, e lo facciamo utilizzare paging nel kernel per fare questo, dobbiamo di impostazione naturalmente tavoli kernel paging; Capisco che sia rootato su swapper_pg_dir.
(Comprendo anche che vmalloc() a differenza di kmalloc() è un caso speciale: è una regione virtuale pura che viene supportata dai frame fisici solo in caso di errore di pagina).
Se (nella parte 1) concludiamo che la traduzione dell'indirizzo virtuale del kernel viene eseguita tramite le tabelle di paging del kernel, allora come esattamente la tabella di paging del kernel (swapper_pg_dir) viene "collegata" o "mappata" a un processo in modalità utente ?? Questo dovrebbe accadere nel codice di commutazione di contesto? Come? Dove?
Es. Su un x86_64, 2 processi A e B sono vivi, 1 cpu. A è in esecuzione, quindi è l'addr più alto canonico 0xFFFF8000 00000000 through 0xFFFFFFFF FFFFFFFF
"map" per il segmento del kernel, ed è l'indice di basso canonico addr 0x0 through 0x00007FFF FFFFFFFF
mappa al suo spazio utente privato.
Ora, se impostiamo il contesto A-> B, l'area inferiore di canonica di B è univoca. Ma deve "mappare" allo stesso kernel, ovviamente! Come avviene esattamente? Come fare "auto" riferimento alla tabella di paging del kernel quando in modalità kernel? O è una dichiarazione sbagliata?
Grazie per la vostra pazienza, apprezzerebbero davvero una risposta ben ponderata!
Grazie Liran. Per spazio logico di indirizzo presumo tu intenda la regione DRAM con mappatura diretta. Quindi, in effetti, stai dicendo che per la regione logica, il kernel "aggiusta" il phy addr tramite la gestione degli errori di pagina e fa _non_ cercare la tabella di paging del kernel (il che implica che non dobbiamo cambiare il valore del registro CR3/TTBRn)? E solo per gli errori vmalloc vengono effettivamente utilizzate le tabelle di paging del kernel? – kaiwan
La mia comprensione è che abbiamo solo (pagina) errori nello spazio del kernel per le correzioni vmalloc ed eccezione (come copy_to | from_user). Qualsiasi altro errore in modalità kernel è un bug e si verifica un errore Oops .. – kaiwan
Sì. Esattamente, è così che funziona nella maggior parte delle architetture. (Linux supporta 21 hardware arch e il suo specifico arco quindi forse in uno è fatto in modo diverso) –