This shows you the differences between two versions of the page.
so2:laboratoare:lab11 [2016/05/09 19:42] victor.ciurel fix links |
so2:laboratoare:lab11 [2017/05/07 19:19] (current) octavian.purdila update lxr links to use 4.9 |
||
---|---|---|---|
Line 25: | Line 25: | ||
În kernel-ul Linux există posibilitatea mapării unui spaţiu de adresă kernel într-un spaţiu de adresă utilizator. În acest fel se elimină overhead-ul datorat copierii informaţiei din user-space în kernel-space (şi invers). Acest lucru poate fi realizat prin intermediul unui device driver şi a interfeţei dispozitiv (''/dev'') a acestuia în user-space. | În kernel-ul Linux există posibilitatea mapării unui spaţiu de adresă kernel într-un spaţiu de adresă utilizator. În acest fel se elimină overhead-ul datorat copierii informaţiei din user-space în kernel-space (şi invers). Acest lucru poate fi realizat prin intermediul unui device driver şi a interfeţei dispozitiv (''/dev'') a acestuia în user-space. | ||
- | Această facilitate poate fi folosită prin completarea operaţiei [[http://lxr.free-electrons.com/source/include/linux/fs.h?v=3.13#L1532|mmap]] din structura [[http://lxr.free-electrons.com/source/include/linux/fs.h?v=3.13#L1521|struct file_operations]] asociată dispozitivului şi utilizând apelul ''mmap'' din user-space. | + | Această facilitate poate fi folosită prin completarea operaţiei [[http://elixir.free-electrons.com/linux/v4.9/source/include/linux/fs.h#L1708|mmap]] din structura [[http://elixir.free-electrons.com/linux/v4.9/source/include/linux/fs.h#L1696|struct file_operations]] asociată dispozitivului şi utilizând apelul ''mmap'' din user-space. |
==== Structuri de lucru cu memoria ==== | ==== Structuri de lucru cu memoria ==== | ||
Line 31: | Line 31: | ||
Înainte de a discuta despre mecanismul de memory-mapping peste un dispozitiv, vom prezenta câteva din structurile de bază legate de subsistemul de management al memoriei în kernel-ul Linux. | Înainte de a discuta despre mecanismul de memory-mapping peste un dispozitiv, vom prezenta câteva din structurile de bază legate de subsistemul de management al memoriei în kernel-ul Linux. | ||
- | Cateva din structurile importante sunt: [[http://lxr.free-electrons.com/source/include/linux/mm_types.h?v=3.13#L31|struct page]], [[http://lxr.free-electrons.com/source/include/linux/mm_types.h?v=3.13#L241|struct vm_area_struct]] şi [[http://lxr.free-electrons.com/source/include/linux/mm_types.h?v=3.13#L344|struct mm_struct]]. | + | Cateva din structurile importante sunt: [[http://elixir.free-electrons.com/linux/v4.9/source/include/linux/mm_types.h#L45|struct page]], [[http://elixir.free-electrons.com/linux/v4.9/source/include/linux/mm_types.h#L300|struct vm_area_struct]] şi [[http://elixir.free-electrons.com/linux/v4.9/source/include/linux/mm_types.h#L396|struct mm_struct]]. |
==== Structura ''page'' ==== | ==== Structura ''page'' ==== | ||
- | Structura [[http://lxr.free-electrons.com/source/include/linux/mm_types.h?v=3.13#L31|struct page]] este utilizată pentru a încorpora informaţii despre toate paginile fizice din sistem. Kernel-ul deţine o structură ''struct page'' pentru toate paginile din sistem. | + | Structura [[http://elixir.free-electrons.com/linux/v4.9/source/include/linux/mm_types.h#L45|struct page]] este utilizată pentru a încorpora informaţii despre toate paginile fizice din sistem. Kernel-ul deţine o structură ''struct page'' pentru toate paginile din sistem. |
- | + | ||
- | Printre câmpurile importante ale acestei structuri amintim: | + | |
- | *[[http://lxr.free-electrons.com/source/include/linux/mm_types.h?v=3.13#L117|_count]], contorul de utilizare al paginii; când acesta devine 0 pagina este adăugată la lista de pagini libere; | + | |
- | *[[http://lxr.free-electrons.com/source/include/linux/mm_types.h?v=3.13#L180|virtual]], adresa virtuală în spaţiul kernel asociată acestei pagini fizice; paginile din ''ZONE_DMA'' sau ''ZONE_NORMAL'' sunt tot timpul mapate; paginile din ''ZONE_HIHGMEM'' nu sunt tot timpul mapate; Aceste constante se găsesc în [[http://lxr.free-electrons.com/source/include/linux/mmzone.h?v=3.13#L261|enum zone_type]] | + | |
- | *[[http://lxr.free-electrons.com/source/include/linux/mm_types.h?v=3.13#L46|flags]], un set de flag-uri care descriu atributele paginii. | + | |
Există numeroase funcţii care interacţionează cu această structură: | Există numeroase funcţii care interacţionează cu această structură: | ||
- | *[[http://lxr.free-electrons.com/source/arch/x86/include/asm/page.h?v=3.13#L63|virt_to_page]] întoarce pagina asociată unei adrese virtuale; | + | *[[http://elixir.free-electrons.com/linux/v4.9/source/arch/x86/include/asm/page.h#L68|virt_to_page]] întoarce pagina asociată unei adrese virtuale; |
- | *[[http://lxr.free-electrons.com/source/include/asm-generic/memory_model.h?v=3.13#L73|pfn_to_page]] întoarce pagina asociată pentru un număr de pagină (''page frame number''); | + | *[[http://elixir.free-electrons.com/linux/v4.9/source/include/asm-generic/memory_model.h#L81|pfn_to_page]] întoarce pagina asociată pentru un număr de pagină (''page frame number''); |
- | *[[http://lxr.free-electrons.com/source/mm/highmem.c?v=3.13#L348|page_address]] întoarce adresa virtuală a paginii transmise ca parametru. | + | *[[http://elixir.free-electrons.com/linux/v4.9/source/include/linux/mm.h#L1013|page_address]] întoarce adresa virtuală a paginii transmise ca parametru. |
==== Structura ''vm_area_struct'' ==== | ==== Structura ''vm_area_struct'' ==== | ||
- | Structura [[http://lxr.free-electrons.com/source/include/linux/mm_types.h?v=3.13#L246|struct vm_area_struct]] deţine informaţii despre o zonă de memorie virtuală contiguă. Zonele de memorie ale unui proces pot fi vizualizate inspectând ''procfs'': | + | Structura [[http://elixir.free-electrons.com/linux/v4.9/source/include/linux/mm_types.h#L300|struct vm_area_struct]] deţine informaţii despre o zonă de memorie virtuală contiguă. Zonele de memorie ale unui proces pot fi vizualizate inspectând ''procfs'': |
<code bash> | <code bash> | ||
Line 69: | Line 64: | ||
O structură ''vm_area_struct'' este creată la fiecare apel ''mmap'' din user-space. Un driver care are suport pentru operaţia de ''mmap'' trebuie să completeze şi să iniţializeze structura ''vm_area_struct'' asociată. Cele mai importante câmpuri ale acestei structuri sunt: | O structură ''vm_area_struct'' este creată la fiecare apel ''mmap'' din user-space. Un driver care are suport pentru operaţia de ''mmap'' trebuie să completeze şi să iniţializeze structura ''vm_area_struct'' asociată. Cele mai importante câmpuri ale acestei structuri sunt: | ||
- | *[[http://lxr.free-electrons.com/source/include/linux/mm_types.h?v=3.13#L249|vm_start]], [[http://lxr.free-electrons.com/source/include/linux/mm_types.h?v=3.13#L250|vm_end]], reprezintă începutul, respectiv, sfârşitul zonei de memorie (aceste câmpuri apar şi in ''/proc/*/maps''); | + | *[[http://elixir.free-electrons.com/linux/v4.9/source/include/linux/mm_types.h#L303|vm_start]], [[http://elixir.free-electrons.com/linux/v4.9/source/include/linux/mm_types.h#L304|vm_end]], reprezintă începutul, respectiv, sfârşitul zonei de memorie (aceste câmpuri apar şi in ''/proc/*/maps''); |
- | *[[http://lxr.free-electrons.com/source/include/linux/mm_types.h?v=3.13#L301|vm_file]], pointer-ul la structura de fişier asociată (dacă există); | + | *[[http://elixir.free-electrons.com/linux/v4.9/source/include/linux/mm_types.h#L351|vm_file]], pointer-ul la structura de fişier asociată (dacă există); |
- | *[[http://lxr.free-electrons.com/source/include/linux/mm_types.h?v=3.13#L299|vm_pgoff]], offset-ul zonei în cadrul fişierului; | + | *[[http://elixir.free-electrons.com/linux/v4.9/source/include/linux/mm_types.h#L349|vm_pgoff]], offset-ul zonei în cadrul fişierului; |
- | *[[http://lxr.free-electrons.com/source/include/linux/mm_types.h?v=3.13#L270|vm_flags]], un set de indicatori; | + | *[[http://elixir.free-electrons.com/linux/v4.9/source/include/linux/mm_types.h#L324|vm_flags]], un set de indicatori; |
- | *[[http://lxr.free-electrons.com/source/include/linux/mm_types.h?v=3.13#L296|vm_ops]], un set de funcţii de lucru asupra acestei zone. | + | *[[http://elixir.free-electrons.com/linux/v4.9/source/include/linux/mm_types.h#L346|vm_ops]], un set de funcţii de lucru asupra acestei zone. |
- | *[[http://lxr.free-electrons.com/source/include/linux/mm_types.h?v=3.13#L254|vm_next]], [[http://lxr.free-electrons.com/source/include/linux/mm_types.h?v=3.13#L254|vm_prev]], ''vm_area''-urile aferente unui proces sunt înlănțuite printr-o listă | + | *[[http://elixir.free-electrons.com/linux/v4.9/source/include/linux/mm_types.h#L308|vm_next]], [[http://elixir.free-electrons.com/linux/v4.9/source/include/linux/mm_types.h#L308|vm_prev]], ''vm_area''-urile aferente unui proces sunt înlănțuite printr-o listă |
==== Structura ''mm_struct'' ==== | ==== Structura ''mm_struct'' ==== | ||
- | Structura [[http://lxr.free-electrons.com/source/include/linux/mm_types.h?v=3.13#L344|struct mm_struct]] înglobează toate zonele de memorie asociate unui proces; folosind câmpul ''mm'' al structurii [[http://lxr.free-electrons.com/source/include/linux/sched.h?v=3.13#L1042|task_struct]] se poate obţine structura ''mm_struct'' asociată procesului curent. | + | Structura [[http://elixir.free-electrons.com/linux/v4.9/source/include/linux/mm_types.h#L396|struct mm_struct]] înglobează toate zonele de memorie asociate unui proces; folosind câmpul ''mm'' al structurii [[http://elixir.free-electrons.com/linux/v4.9/source/include/linux/sched.h#L1475|task_struct]] se poate obţine structura ''mm_struct'' asociată procesului curent. |
==== Maparea memoriei ==== | ==== Maparea memoriei ==== | ||
Line 84: | Line 79: | ||
Maparea memoriei (''memory mapping'') este una dintre cele mai interesante caracteristici ale unui sistem Unix. Din punct de vedere al unui driver, facilitatea de ''memory-mapping'' permite accesul direct al memoriei unui dispozitiv din user-space. | Maparea memoriei (''memory mapping'') este una dintre cele mai interesante caracteristici ale unui sistem Unix. Din punct de vedere al unui driver, facilitatea de ''memory-mapping'' permite accesul direct al memoriei unui dispozitiv din user-space. | ||
- | Pentru a asocia unui driver o operaţie ''mmap'', trebuie utilizat câmpul [[http://lxr.free-electrons.com/source/include/linux/fs.h?v=3.13#L1532|mmap]] din structura [[http://lxr.free-electrons.com/source/include/linux/fs.h?v=3.13#L1521|struct file_operations]] asociată dispozitivului. Metoda astfel asociată este utilizată în cazul unui apel ''mmap'' din user-space. | + | Pentru a asocia unui driver o operaţie ''mmap'', trebuie utilizat câmpul [[http://elixir.free-electrons.com/linux/v4.9/source/include/linux/fs.h#L1708|mmap]] din structura [[http://elixir.free-electrons.com/linux/v4.9/source/include/linux/fs.h#L1696|struct file_operations]] asociată dispozitivului. Metoda astfel asociată este utilizată în cazul unui apel ''mmap'' din user-space. |
==== User-space ==== | ==== User-space ==== | ||
Line 107: | Line 102: | ||
===== ''remap_pfn_range'' ===== | ===== ''remap_pfn_range'' ===== | ||
- | Pentru maparea unui spaţiu de memorie fizică în spaţiul virtual utilizator, reprezentat de structura ''struct vm_area_struct'', se folosește apelul [[http://lxr.free-electrons.com/source/mm/memory.c?v=3.13#L2319| remap_pfn_range]]. Acesta va mapa un spaţiu de adresă fizic contiguu în spaţiul virtual reprezentat de ''struct vm_area_struct'': | + | Pentru maparea unui spaţiu de memorie fizică în spaţiul virtual utilizator, reprezentat de structura ''struct vm_area_struct'', se folosește apelul [[http://elixir.free-electrons.com/linux/v4.9/source/include/linux/mm.h#L2193|remap_pfn_range]]. Acesta va mapa un spaţiu de adresă fizic contiguu în spaţiul virtual reprezentat de ''struct vm_area_struct'': |
<code C> | <code C> | ||
int remap_pfn_range(struct vm_area_struct *vma, unsigned long addr, | int remap_pfn_range(struct vm_area_struct *vma, unsigned long addr, | ||
Line 116: | Line 111: | ||
*''vma'', spaţiul de memorie virtuală în cadrul căruia se face maparea; | *''vma'', spaţiul de memorie virtuală în cadrul căruia se face maparea; | ||
*''addr'', spaţiul virtual de adresă de unde se începe remaparea; se vor construi tabele de pagini pentru spaţiul virtual de adresă cuprins intre ''addr'' şi ''addr + size''; | *''addr'', spaţiul virtual de adresă de unde se începe remaparea; se vor construi tabele de pagini pentru spaţiul virtual de adresă cuprins intre ''addr'' şi ''addr + size''; | ||
- | *''pfn'', numărul paginii fizice (''page frame number'') în care se mapează adresa virtuală; de obicei acesta se obţine prin shifting-ul adresei fizice [[http://lxr.free-electrons.com/source/include/asm-generic/page.h?v=3.13#L15| PAGE_SHIFT]] biţi la dreapta | + | *''pfn'', numărul paginii fizice (''page frame number'') în care se mapează adresa virtuală; de obicei acesta se obţine prin shifting-ul adresei fizice [[http://elixir.free-electrons.com/linux/v4.9/source/arch/x86/include/asm/page_types.h#L8|PAGE_SHIFT]] biţi la dreapta |
*''size'', dimensiunea (în octeţi) a spaţiului de memorie care va fi remapat; | *''size'', dimensiunea (în octeţi) a spaţiului de memorie care va fi remapat; | ||
*''prot'', caracteristicile de protecţie pentru noul spaţiu de adresă. | *''prot'', caracteristicile de protecţie pentru noul spaţiu de adresă. | ||
Line 136: | Line 131: | ||
În exemplul de mai sus se realizează o mapare a zonei fizice începând de la numărul de pagină ''phys_pgoff'' în întreg spaţiul virtual de adresă reprezentat de ''vma''. | În exemplul de mai sus se realizează o mapare a zonei fizice începând de la numărul de pagină ''phys_pgoff'' în întreg spaţiul virtual de adresă reprezentat de ''vma''. | ||
- | Două funcţii care sunt utile sunt cele de translatare a unei adrese virtuale din spaţiul kernel în adrese fizice. Acestea sunt [[http://lxr.free-electrons.com/source/arch/x86/include/asm/io.h?v=3.13#L111| virt_to_phys]] pentru adrese alocate folosind ''kmalloc'' şi [[http://lxr.free-electrons.com/source/mm/vmalloc.c?v=3.13#L259| vmalloc_to_pfn]] pentru adrese alocate folosind ''vmalloc''. | + | Două funcţii care sunt utile sunt cele de translatare a unei adrese virtuale din spaţiul kernel în adrese fizice. Acestea sunt [[http://elixir.free-electrons.com/linux/v4.9/source/arch/x86/include/asm/io.h#L118| virt_to_phys]] pentru adrese alocate folosind ''kmalloc'' şi [[http://elixir.free-electrons.com/linux/v4.9/source/include/linux/mm.h#L473|vmalloc_to_pfn]] pentru adrese alocate folosind ''vmalloc''. |
Astfel, numărul de pagină ''phys_pgoff'' din exemplul de mai sus se va obţine în cazul unei adrese ''kmalloc_area'' alocate folosind ''kmalloc'' astfel: | Astfel, numărul de pagină ''phys_pgoff'' din exemplul de mai sus se va obţine în cazul unei adrese ''kmalloc_area'' alocate folosind ''kmalloc'' astfel: | ||
Line 155: | Line 150: | ||
===== ''SetPageReserved''/''ClearPageReserved'' ===== | ===== ''SetPageReserved''/''ClearPageReserved'' ===== | ||
- | Înainte de a fi utilizată, unei pagini îi va trebui activat bitul [[http://lxr.free-electrons.com/source/include/linux/page-flags.h?v=3.13#L85|PG_reserved]]. Acest bit înseamnă că pagina nu poate fi evacuată pe disk (''swap''). Activarea se realizează cu ajutorul macroului [[http://lxr.free-electrons.com/source/include/linux/page-flags.h?v=3.13#L182|SetPageReserved]]. Macrodefiniţia primeşte ca parametru un pointer către structura de pagină, ''struct page'', care se obţine din adresa virtuală din kernel cu ajutorul funcţiei ''virt_to_page'', pentru adrese alocate folosind ''kmalloc'': | + | Înainte de a fi utilizată, unei pagini îi va trebui activat bitul [[http://elixir.free-electrons.com/linux/v4.9/source/include/linux/page-flags.h#L85|PG_reserved]]. Acest bit înseamnă că pagina nu poate fi evacuată pe disk (''swap''). Activarea se realizează cu ajutorul macroului [[http://elixir.free-electrons.com/linux/v4.9/source/include/linux/page-flags.h#L194|SetPageReserved]]. Macrodefiniţia primeşte ca parametru un pointer către structura de pagină, ''struct page'', care se obţine din adresa virtuală din kernel cu ajutorul funcţiei ''virt_to_page'', pentru adrese alocate folosind ''kmalloc'': |
<code C> | <code C> | ||
#define NPAGES 16 | #define NPAGES 16 | ||
Line 166: | Line 161: | ||
} | } | ||
</code> | </code> | ||
- | şi cu ajutorul funcţiei [[http://lxr.free-electrons.com/source/mm/vmalloc.c?v=3.13#L225|vmalloc_to_page]] pentru adrese alocate folosind ''vmalloc'': | + | şi cu ajutorul funcţiei [[http://elixir.free-electrons.com/linux/v4.9/source/mm/vmalloc.c#L235|vmalloc_to_page]] pentru adrese alocate folosind ''vmalloc'': |
<code C> | <code C> | ||
#define NPAGES 16 | #define NPAGES 16 | ||
Line 178: | Line 173: | ||
</code> | </code> | ||
- | Înainte de eliberarea paginii (''kfree''/''vfree''), bitul de pagină rezervată trebuie dezactivat cu ajutorul macroului [[http://lxr.free-electrons.com/source/include/linux/page-flags.h?v=3.13#L185|ClearPageReserved]]. Acesta primeşte ca parametru acelaşi pointer către o structura de pagină care a fost dat la ''SetPageReserved''. | + | Înainte de eliberarea paginii (''kfree''/''vfree''), bitul de pagină rezervată trebuie dezactivat cu ajutorul macroului [[http://lxr.free-electrons.com/source/include/linux/page-flags.h?v=4.9#L185|ClearPageReserved]]. Acesta primeşte ca parametru acelaşi pointer către o structura de pagină care a fost dat la ''SetPageReserved''. |