This shows you the differences between two versions of the page.
| so2:laboratoare:lab11:exercitii [2016/05/08 18:58] sorin.baltateanu [Laborator 11: Exerciții] | so2:laboratoare:lab11:exercitii [2019/05/08 09:53] (current) constantin.ghioc [2. [3p] Mapare de memorie virtual contiguă în user space] | ||
|---|---|---|---|
| Line 1: | Line 1: | ||
| ====== Laborator 11: Exerciții ====== | ====== Laborator 11: Exerciții ====== | ||
| - | Pentru desfășurarea laboratorului pornim de la [[http://elf.cs.pub.ro/so2/res/laboratoare/lab11-tasks.zip|arhiva de sarcini a laboratorului]]. Descărcăm și decomprimăm arhiva în directorul ''so2/'' din directorul home al utilizatorului ''student'' de pe sistemul de bază (stația ''mjolnir''):<code bash> | + | |
| - | student@mjolnir:~$ cd so2/ | + | ===== Pregătirea laboratorului ===== | 
| - | student@mjolnir:~/so2$ wget http://elf.cs.pub.ro/so2/res/laboratoare/lab11-tasks.zip | + | |
| - | student@mjolnir:~/so2$ unzip lab11-tasks.zip | + | Pentru rezolvarea laboratorului, vom lucra în același director din care pornim mașina virtuală (''~/so2/linux/tools/labs''). | 
| - | student@mjolnir:~/so2$ tree lab11-tasks | + | |
| + | Pașii de rezolvare sunt următorii: | ||
| + | * pregătirea scheletului de laborator | ||
| + | * compilarea modulelor de Kernel | ||
| + | * copierea modulelor pe mașina virtuală | ||
| + | * pornirea mașinii virtuale și testarea modulelor | ||
| + | |||
| + | ==== Pregătirea scheletului de laborator ==== | ||
| + | |||
| + | Pentru rezolvarea laboratorului trebuie sa activam suportul de netfilter din kernel. In meniul deschis cu ''make menuconfig'' | ||
| + | activati optiunea ''Networking support/Networking options/Network packet filtering framework (Netfilter)''. | ||
| + | |||
| + | Scheletul de laborator este generat din sursele din directorul ''tools/labs/templates''. Putem genera scheletele pentru toate laboratoarele folosind următoarea comanda: | ||
| + | |||
| + | <code bash> | ||
| + | tools/labs $ make skels | ||
| </code> | </code> | ||
| - | În cadrul directorului ''lab11-tasks/'' se găsesc resursele necesare pentru dezvoltarea exercițiilor de mai jos: fișiere schelet de cod sursă, fișiere Makefile și Kbuild, scripturi și programe de test. | ||
| - | Vom dezvolta exercițiile pe sistemul de bază (stația ''mjolnir'') și apoi le vom testa pe [[:so2:resurse:masini-virtuale|mașina virtuală QEMU]]. După editarea și compilarea unui modul de kernel îl vom copia în directorul dedicat pentru mașina virtuală QEMU folosind o comandă de forma<code bash> | + | Pentru a genera scheletul pentru un singur laborator, vom folosi variabila de mediu ''LABS'': | 
| - | student@mjolnir:~/so2$ cp /path/to/module.ko ~/so2/qemu-vm/fsimg/root/modules/ | + | |
| - | </code> unde ''/path/to/module.ko'' este calea către fișierul obiect aferent modulului de kernel. Apoi vom porni, din directorul ''~/so2/qemu-vm/'' mașina virtuală QEMU folosind comanda<code bash> | + | <code bash> | 
| - | student@mjolnir:~/so2/qemu-vm$ make | + | tools/labs $ make clean | 
| + | tools/labs $ LABS=<lab name> make skels | ||
| </code> | </code> | ||
| - | După pornirea mașinii virtuale QEMU vom putea folosi comenzi în fereastra QEMU pentru a încărca și descărca modulul de kernel:<code> | + | <note important> | 
| - | # insmod modules/module-name.ko | + | Numele laboratorului curent este ''memory_mapping''. | 
| - | # rmmod module/module-name | + | </note> | 
| - | </code> unde ''module-name'' este numele modulului de kernel. | + | |
| + | Similar, putem genera și scheletul pentru un singur exercițiu, atribuind valoarea ''<lab_name>/<task_name>'' variabilei ''LABS''. | ||
| <note> | <note> | ||
| - | Pentru dezvoltarea laboratorului, este recomandat să folosim trei terminale sau, mai bine, trei tab-uri de terminal. Pentru a deschide un nou tab de terminal folosim combinația de taste ''Ctrl+Alt+t''. Cele trei tab-uri de terminal îndeplinesc următoarele roluri: | + | Scheletul este generat în directorul ''tools/labs/skels''. | 
| - | - În primul tab de terminal dezvoltăm modulul de kernel: editare, compilare, copiere în directorul dedicat pentru mașina virtaulă QEMU. Lucrăm în directorul aferent rezultat în urma decomprimării arhivei de sarcini a laboratorului. | + | </note> | 
| - | - În al doilea tab de terminal pornim mașina virtuală QEMU și apoi testăm modulul de kernel: încărcare/descărcare modul, rulare teste. Lucrăm în directorul aferent mașinii virtuale: ''~/so2/qemu-vm/''. | + | |
| - | - În al treilea tab de terminal pornim un server UDP care să primească [[:so2:laboratoare:lab02#netconsole|mesajele de netconsole]]. Nu contează în ce director ne aflăm. Folosim comanda<code bash> | + | ==== Compilarea modulelor ==== | 
| - | student@mjolnir:~$ netcat -lup 6666 | + | |
| + | Comanda ''make build'' compilează toate modulele din directorul ''skels''. | ||
| + | |||
| + | <code bash> | ||
| + | student@eg106:~/so2/linux/tools/labs$ make build | ||
| + | echo "# autogenerated, do not edit " > skels/Kbuild | ||
| + | echo "ccflags-y += -Wno-unused-function -Wno-unused-label -Wno-unused-variable " >> skels/Kbuild | ||
| + | for i in ./memory_mapping/vmmap ./memory_mapping/kmmap; do echo "obj-m += $i/" >> skels/Kbuild; done | ||
| + | ... | ||
| </code> | </code> | ||
| + | |||
| + | ==== Copierea modulelor pe mașina virtuală ==== | ||
| + | |||
| + | Putem copia modulele generate pe mașina virtuală folosind target-ul ''copy'' al comenzii make, atunci când mașina virtuală este oprită. | ||
| + | |||
| + | <code bash> | ||
| + | student@eg106:~/so2/linux/tools/labs$ make copy | ||
| + | student@eg106:~/so2/linux/tools/labs$ make boot | ||
| + | </code> | ||
| + | |||
| + | Alternativ, putem copia fișierele prin ''scp'', pentru e evita repornirea mașinii virtuale. Pentru detalii despre folosirea interacțiunea prin rețea cu mașina virtuală citiți [[https://ocw.cs.pub.ro/courses/so2/resurse/masini-virtuale#interactiunea_cu_masina_virtuala|Interacțiunea cu mașina virtuală]]. | ||
| + | |||
| + | ==== Testarea modulelor ==== | ||
| + | |||
| + | Modulele generate sunt copiate pe mașina virtuală în directorul ''/home/root/skels/<lab_name>''. | ||
| + | |||
| + | <code bash> | ||
| + | root@qemux86:~/skels/memory_mapping# ls | ||
| + | kmmap test vmmap | ||
| + | root@qemux86:~/skels/memory_mapping# ls vmmap/ | ||
| + | vmmap.ko | ||
| + | </code> | ||
| + | |||
| + | După pornirea mașinii virtuale QEMU vom putea folosi comenzi în fereastra QEMU (sau în ''minicom'') pentru a încărca și descărca modulul de kernel:<code> | ||
| + | root@qemux86:~# insmod skels/<lab_name>/<task_name>/<module_name>.ko | ||
| + | root@qemux86:~# rmmod skels/<lab_name>/<task_name>/<module_name>.ko | ||
| + | </code> | ||
| + | |||
| + | <note> | ||
| + | Pentru dezvoltarea laboratorului, este recomandat să folosim trei terminale sau, mai bine, trei tab-uri de terminal. Pentru a deschide un nou tab de terminal folosim combinația de taste ''Ctrl+Shift+t''. Cele trei tab-uri de terminal îndeplinesc următoarele roluri: | ||
| + | - În primul tab de terminal dezvoltăm modulul de kernel: editare, compilare, copiere în directorul dedicat pentru mașina virtuală QEMU. Lucrăm în directorul aferent rezultat în urma decomprimării arhivei de sarcini a laboratorului. | ||
| + | - În al doilea tab de terminal pornim mașina virtuală QEMU și apoi testăm modulul de kernel: încărcare/descărcare modul, rulare teste. Lucrăm în directorul aferent mașinii virtuale: ''~/so2/linux/tools/labs''. | ||
| + | - În al treilea tab de terminal accesăm directorul ''~/so2/linux/'' cu sursele nucleului unde putem folosi [[:so2:laboratoare:lab01#cscope|Vim și cscope]] pentru parcurgerea codului sursă.<code> | ||
| + | student@eg106-pc:~$ netcat -lup 6666 | ||
| + | </code> | ||
| + | |||
| </note> | </note> | ||
| - | - (**3 puncte**) Mapare de memorie fizic contiguă în user space | + | ===== Exerciții ===== | 
| - | * Utilizați scheletul de modul de kernel din directorul ''lin/kmmap/'' pentru a crea o mapare a memoriei driver-ului în user-space. | + | |
| + | <note important> | ||
| + | Înainte de începerea rezolvării laboratorului, rulați comanda ''%%git pull --rebase%%'' in directorul ''~/so2/linux'', pentru a obține ultima versiune a scheletului de laborator. | ||
| + | </note> | ||
| + | |||
| + | ==== 1. [3p] Mapare de memorie fizic contiguă în user space ==== | ||
| + | * Utilizați scheletul de modul de kernel din directorul ''kmmap/'' pentru a crea o mapare a memoriei driver-ului în user-space. | ||
| * Memoria driver-ului este alocată folosind ''kmalloc''. | * Memoria driver-ului este alocată folosind ''kmalloc''. | ||
| * Completați zonele marcate cu ''TODO 1''. | * Completați zonele marcate cu ''TODO 1''. | ||
| * Parcurgeți secțiunea [[:so2:laboratoare:lab11#Kernel-space|Maparea memoriei. Kernel-space]]. | * Parcurgeți secțiunea [[:so2:laboratoare:lab11#Kernel-space|Maparea memoriei. Kernel-space]]. | ||
| - | * Alocați, în funcția de inițializare a modulului, o zonă de memorie de ''NPAGES+1'' pagini folosind ''kmalloc''. | + | * Alocați, în funcția de inițializare a modulului, o zonă de memorie de ''NPAGES+2'' pagini folosind ''kmalloc''. | 
| - | * O pagină în kernel are dimensiunea [[http://lxr.linux.no/linux+*/arch/x86/include/asm/page_types.h#L8|PAGE_SIZE]]. | + | * O pagină în kernel are dimensiunea [[http://elixir.free-electrons.com/linux/v4.9/source/arch/x86/include/asm/page_types.h#L9|PAGE_SIZE]]. | 
| * Zona alocată din spațiul kernel este indicată de ''kmalloc_area''. | * Zona alocată din spațiul kernel este indicată de ''kmalloc_area''. | ||
| - | * Dimensiunea ''NPAGES+1'' este necesară pentru aliniere. | + | * Dimensiunea ''NPAGES+2'' este necesară pentru aliniere. | 
| * Adresa  ''kmalloc_ptr'' (variabilă globală) obținută în urma apelului ''kmalloc'' trebuie aliniată la adresa unei pagini. | * Adresa  ''kmalloc_ptr'' (variabilă globală) obținută în urma apelului ''kmalloc'' trebuie aliniată la adresa unei pagini. | ||
| * Pentru aceasta, va trebui să alocați o pagină în plus față de numărul de pagini necesare și să folosiți formula:<code> | * Pentru aceasta, va trebui să alocați o pagină în plus față de numărul de pagini necesare și să folosiți formula:<code> | ||
| Line 43: | Line 109: | ||
| </code> | </code> | ||
| * Activați/dezactivați bitul ''PG_reserved'' al fiecărei pagini cu ajutorul funcțiilor ''SetPageReserved'' (în funcția de inițializare a modulului), respectiv ''ClearPageReserved'' (în funcția de ieșire a modulului). | * Activați/dezactivați bitul ''PG_reserved'' al fiecărei pagini cu ajutorul funcțiilor ''SetPageReserved'' (în funcția de inițializare a modulului), respectiv ''ClearPageReserved'' (în funcția de ieșire a modulului). | ||
| - | * Folosiți [[http://lxr.free-electrons.com/source/tools/virtio/linux/virtio.h?v=3.7#L32|virt_to_page]] pentru a traduce paginile virtuale în pagini fizice folosite de funcțiile ''SetPageReserved'' și ''ClearPageReserved''. | + | * Folosiți [[http://elixir.free-electrons.com/linux/v4.9/source/arch/x86/include/asm/page.h#L68|virt_to_page]] pentru a traduce paginile virtuale în pagini fizice folosite de funcțiile ''SetPageReserved'' și ''ClearPageReserved''. | 
| * Pentru verificare (folosind testul indicat mai jos) completați primii 4 octeți din fiecare pagină alocată cu valorile, respectiv, ''0xaa'',''0xbb'',''0xcc'',''0xdd''. | * Pentru verificare (folosind testul indicat mai jos) completați primii 4 octeți din fiecare pagină alocată cu valorile, respectiv, ''0xaa'',''0xbb'',''0xcc'',''0xdd''. | ||
| * Implementați funcția ''mmap'' pentru driver. | * Implementați funcția ''mmap'' pentru driver. | ||
| - | * Pentru mapare folosiți funcția [[http://lxr.free-electrons.com/source/mm/memory.c?v=3.7#L2282|remap_pfn_range]]. | + | * Pentru mapare folosiți funcția [[http://elixir.free-electrons.com/linux/v4.9/source/mm/memory.c#L1760|remap_pfn_range]]. | 
| - | * Al treilea argument primit de [[http://lxr.free-electrons.com/source/mm/memory.c?v=3.7#L2282|remap_pfn_range]] este un număr de pagină fizică (''pfn'' -- //page frame number//). | + | * Al treilea argument primit de [[http://elixir.free-electrons.com/linux/v4.9/source/mm/memory.c#L1760|remap_pfn_range]] este un număr de pagină fizică (''pfn'' -- //page frame number//). | 
| - | * Pentru conversia din adresă kernel virtuală (adică ''kmalloc_area'') în adresă fizică utilizați [[http://lxr.free-electrons.com/source/arch/x86/include/asm/io.h?v=3.7#L98|virt_to_phys]]. | + | * Pentru conversia din adresă kernel virtuală (adică ''kmalloc_area'') în adresă fizică utilizați [[http://elixir.free-electrons.com/linux/v4.9/source/arch/x86/include/asm/io.h#L118|virt_to_phys]]. | 
| - | * Shiftați rezultatul cu ''PAGE_SHIFT'' biți pentru a obține ''pfn''. | + | * Shiftați rezultatul cu [[http://elixir.free-electrons.com/linux/v4.9/source/arch/x86/include/asm/page_types.h#L8|PAGE_SHIFT]] biți pentru a obține ''pfn''. | 
| * Încărcați modulul în kernel. | * Încărcați modulul în kernel. | ||
| - | * Pentru testare utilizați testul din directorul ''lin/test''. | + | * Pentru testare utilizați testul din directorul ''test/''. | 
| - | * Compilați testul folosind comanda ''make''. | + | |
| * Rulați testul folosind comanda ''./mmap-test''. | * Rulați testul folosind comanda ''./mmap-test''. | ||
| * Dacă totul merge bine testul va afișa mesaje ''matched''. | * Dacă totul merge bine testul va afișa mesaje ''matched''. | ||
| * Descărcați modulul din kernel. | * Descărcați modulul din kernel. | ||
| - | - (**3 puncte**) Mapare de memorie virtual contiguă în user space | + | |
| - | * Utilizați scheletul de modul de kernel din directorul ''lin/vmmap/'' pentru a crea o mapare a memoriei driver-ului în user-space. | + | ==== 2. [3p] Mapare de memorie fizic discontiguă în user space ==== | 
| + | * Utilizați scheletul de modul de kernel din directorul ''vmmap/'' pentru a crea o mapare a memoriei driver-ului în user-space. | ||
| * Memoria driver-ului este alocată folosind ''vmalloc''. | * Memoria driver-ului este alocată folosind ''vmalloc''. | ||
| - | * Completați zonele marcate cu ''TODO 2''. | + | * Completați zonele marcate cu ''TODO 1''. | 
| * Parcurgeți secțiunea [[:so2:laboratoare:lab11#Kernel-space|Maparea memoriei. Kernel-space]] din laborator. | * Parcurgeți secțiunea [[:so2:laboratoare:lab11#Kernel-space|Maparea memoriei. Kernel-space]] din laborator. | ||
| * Alocați  o zonă de memorie de ''NPAGES'' pagini în funcția de inițializare a modulului folosind ''vmalloc''. | * Alocați  o zonă de memorie de ''NPAGES'' pagini în funcția de inițializare a modulului folosind ''vmalloc''. | ||
| Line 65: | Line 131: | ||
| * Alocarea cu ''vmalloc'' întoarce adrese aliniate la dimensiunea paginii; nu este nevoie de operații suplimentare. | * Alocarea cu ''vmalloc'' întoarce adrese aliniate la dimensiunea paginii; nu este nevoie de operații suplimentare. | ||
| * Activați/dezactivați bitul ''PG_reserved'' al fiecărei pagini cu ajutorul funcțiilor ''SetPageReserved'' (în funcția de inițializare a modulului), respectiv ''ClearPageReserved'' (în funcția de ieșire a modulului); | * Activați/dezactivați bitul ''PG_reserved'' al fiecărei pagini cu ajutorul funcțiilor ''SetPageReserved'' (în funcția de inițializare a modulului), respectiv ''ClearPageReserved'' (în funcția de ieșire a modulului); | ||
| - | * Folosiți [[http://lxr.free-electrons.com/source/mm/vmalloc.c?v=3.7#L202|vmalloc_to_page]] pentru a traduce paginile virtuale în pagini fizice folosite de funcțiile ''SetPageReserved'' și ''ClearPageReserved''. | + | * Folosiți [[http://elixir.free-electrons.com/linux/v4.9/source/mm/vmalloc.c#L235|vmalloc_to_page]] pentru a traduce paginile virtuale în pagini fizice folosite de funcțiile ''SetPageReserved'' și ''ClearPageReserved''. | 
| * Pentru verificare folosind testul, completați primii 4 octeți din fiecare pagină alocată cu următoarele valori: ''0xaa'',''0xbb'',''0xcc'',''0xdd''. | * Pentru verificare folosind testul, completați primii 4 octeți din fiecare pagină alocată cu următoarele valori: ''0xaa'',''0xbb'',''0xcc'',''0xdd''. | ||
| * Implementați funcția ''mmap'' pentru driver. | * Implementați funcția ''mmap'' pentru driver. | ||
| - | * Pentru conversia din adresă kernel virtuală în adresă fizică utilizați [[http://lxr.free-electrons.com/source/mm/vmalloc.c?v=3.7#L236|vmalloc_to_pfn]]. | + | * Pentru conversia din adresă kernel virtuală în adresă fizică utilizați [[http://elixir.free-electrons.com/linux/v4.9/source/mm/vmalloc.c#L269|vmalloc_to_pfn]]. | 
| - | * [[http://lxr.free-electrons.com/source/mm/vmalloc.c?v=3.7#L236|vmalloc_to_pfn]] întoarce un index de pagină (//page frame number//), astfel că **nu** este nevoie de shift la dreapta. | + | * [[http://elixir.free-electrons.com/linux/v4.9/source/mm/vmalloc.c#L269|vmalloc_to_pfn]] întoarce un index de pagină (//page frame number//), astfel că **nu** este nevoie de shift la dreapta. | 
| * Paginile alocate cu ''vmalloc'' nu sunt fizic contigue. | * Paginile alocate cu ''vmalloc'' nu sunt fizic contigue. | ||
| - | * Apelați [[http://lxr.free-electrons.com/source/mm/memory.c?v=3.7#L2282|remap_pfn_range]] pentru **fiecare** pagină virtuală. | + | * Apelați [[http://elixir.free-electrons.com/linux/v4.9/source/mm/memory.c#L1760|remap_pfn_range]] pentru **fiecare** pagină virtuală. | 
| * Adică veți avea nevoie de un ciclu for și veți incrementa adresa virtuală kernel (''vmalloc_area'') cu câte o pagină și veți obține pentru fiecare adresă virtuală astfel obținută ''pfn''-ul.  | * Adică veți avea nevoie de un ciclu for și veți incrementa adresa virtuală kernel (''vmalloc_area'') cu câte o pagină și veți obține pentru fiecare adresă virtuală astfel obținută ''pfn''-ul.  | ||
| * Folosiți ''vmalloc_area_ptr'' pentru parcurgerea spațiului virtual din kernel space. | * Folosiți ''vmalloc_area_ptr'' pentru parcurgerea spațiului virtual din kernel space. | ||
| * Nu modificați variabila globală ''vmalloc_area''. | * Nu modificați variabila globală ''vmalloc_area''. | ||
| - | * Argumentul pentru [[http://lxr.free-electrons.com/source/mm/vmalloc.c?v=3.7#L236|vmalloc_to_pfn]] este o adresă virtuală din kernel space. | + | * Argumentul pentru [[http://elixir.free-electrons.com/linux/v4.9/source/mm/vmalloc.c#L269|vmalloc_to_pfn]] este o adresă virtuală din kernel space. | 
| - | * Al doilea argument pentru [[http://lxr.free-electrons.com/source/mm/memory.c?v=3.7#L2282|remap_pfn_range]] este o adresă virtuală din cadrul unui VMA. | + | * Al doilea argument pentru [[http://elixir.free-electrons.com/linux/v4.9/source/mm/memory.c#L1760|remap_pfn_range]] este o adresă virtuală din cadrul unui VMA. | 
| - | * Al treilea argument pentru [[http://lxr.free-electrons.com/source/mm/memory.c?v=3.7#L2282|remap_pfn_range]] este pfn-ul paginii virtuale din kernel-space care se dorește remapată. | + | * Al treilea argument pentru [[http://elixir.free-electrons.com/linux/v4.9/source/mm/memory.c#L1760|remap_pfn_range]] este pfn-ul paginii virtuale din kernel-space care se dorește remapată. | 
| * Încărcați modulul în kernel. | * Încărcați modulul în kernel. | ||
| - | * Pentru testare utilizați testul din directorul ''lin/test''. | + | * Pentru testare utilizați testul din directorul ''test/''. | 
| - | * Compilați testul folosind comanda ''make''. | + | |
| * Rulați testul folosind comanda ''./mmap-test''. | * Rulați testul folosind comanda ''./mmap-test''. | ||
| * Dacă totul merge bine testul va afișa mesaje ''matched''. | * Dacă totul merge bine testul va afișa mesaje ''matched''. | ||
| * Descărcați modulul din kernel. | * Descărcați modulul din kernel. | ||
| - | - (**2 puncte**) Operații de read/write în memoria mapată | + | |
| + | |||
| + | ==== 3. [2p] Operații de read/write în memoria mapată ==== | ||
| * Modificați **unul dintre** modulele anterioare astfel încât să permiteți operații read/write pe dispozitiv. | * Modificați **unul dintre** modulele anterioare astfel încât să permiteți operații read/write pe dispozitiv. | ||
| * E vorba de un exercițiu didactic ca să vedem că același spațiu poate fi folosit și cu apel-ul ''mmap'' și cu apeluri de tipul ''read'' și ''write''. | * E vorba de un exercițiu didactic ca să vedem că același spațiu poate fi folosit și cu apel-ul ''mmap'' și cu apeluri de tipul ''read'' și ''write''. | ||
| * Operațiile de citire și scriere vor acționa chiar asupra zonei de memorie alocate. | * Operațiile de citire și scriere vor acționa chiar asupra zonei de memorie alocate. | ||
| - | * Completați zonele marcate cu ''TODO 3''. | + | * Completați zonele marcate cu ''TODO 2''. | 
| * Revedeți [[so2:laboratoare:lab04 | Laboratorul 4]] | * Revedeți [[so2:laboratoare:lab04 | Laboratorul 4]] | ||
| * **Ignorați** parametrul ''offset'' trimis operației de read/write. | * **Ignorați** parametrul ''offset'' trimis operației de read/write. | ||
| - | * Pentru testare utilizați testul din directorul ''lin/test''. | + | * Pentru testare utilizați testul din directorul ''test/''. | 
| - | * Definiți macroul ''TASK_3'' în ''mmap_test.c'' | + | * Rulați testul folosind comanda ''./mmap-test 3''. | 
| - | - (**3 puncte**) Afișare memorie mapată în ''procfs'' | + | |
| + | |||
| + | ==== 4. [3p] Afișare memorie mapată în ''procfs'' ==== | ||
| * Folosind **unul dintre** modulele anterioare, creați un fișier ''procfs'' în care să afișați totalul memoriei mapate de procesul apelant. | * Folosind **unul dintre** modulele anterioare, creați un fișier ''procfs'' în care să afișați totalul memoriei mapate de procesul apelant. | ||
| - | * Completați zonele marcate cu ''TODO 4''. | + | * Completați zonele marcate cu ''TODO 3''. | 
| - | * Creați o intrare nouă în ''procfs'' (''PROC_ENTRY_NAME'', definit în ''mmap-test.h'') care va afișa totalul memoriei mapate de procesul care a apelat read-ul pe acel fișier. Folosiți apelul [[http://lxr.free-electrons.com/source/include/linux/proc_fs.h?v=3.13#L30|proc_create]]. | + | * Creați o intrare nouă în ''procfs'' (''PROC_ENTRY_NAME'', definit în ''mmap-test.h'') care va afișa totalul memoriei mapate de procesul care a apelat read-ul pe acel fișier. Folosiți apelul [[http://elixir.free-electrons.com/linux/v4.9/source/include/linux/proc_fs.h#L30|proc_create]]. | 
| * Pentru parametrul ''mode'' folosiți ''0'', iar pentru parametrul ''parent'' folosiți ''NULL''. | * Pentru parametrul ''mode'' folosiți ''0'', iar pentru parametrul ''parent'' folosiți ''NULL''. | ||
| * Operațiile sunt descrise în structura ''my_proc_file_ops''. | * Operațiile sunt descrise în structura ''my_proc_file_ops''. | ||
| - | * În funcția de ieșire a modulului ștergeți intrarea ''PROC_ENTRY_NAME'' folosind [[http://lxr.free-electrons.com/source/fs/proc/generic.c?v=3.13#L484|remove_proc_entry]]. | + | * În funcția de ieșire a modulului ștergeți intrarea ''PROC_ENTRY_NAME'' folosind [[http://elixir.free-electrons.com/linux/v4.9/source/fs/proc/generic.c#L548|remove_proc_entry]]. | 
| - | * O utilizare (complexă) și descriere a interfeței [[http://lxr.free-electrons.com/source/include/linux/seq_file.h?v=3.7#L18|seq_file]] se găsește aici [[http://tldp.org/LDP/lkmpg/2.6/html/x861.html | acest exemplu]]. | + | * O utilizare (complexă) și descriere a interfeței [[http://elixir.free-electrons.com/linux/v4.9/source/include/linux/seq_file.h#L15|seq_file]] se găsește aici [[http://tldp.org/LDP/lkmpg/2.6/html/x861.html | acest exemplu]]. | 
| - | * Pentru acest exercițiu este suficientă doar o simplă utilizare a interfeței, descrisă [[http://lwn.net/Articles/22355/ | aici]]. Căutați **extra-simple**. Atenție, funcția create_proc_entry nu mai este disponibilă în versiunea 3.13 a kernelului. Va trebui să folosiţi funcţia [[http://lxr.free-electrons.com/source/include/linux/proc_fs.h?v=3.13#L30|proc_create]], care primeşte ca parametru suplimentar un pointer către operaţiile de tip fişier ce vor fi folosite pentru intrarea procfs. | + | * Pentru acest exercițiu este suficientă doar o simplă utilizare a interfeței, descrisă [[http://lwn.net/Articles/22355/ | aici]]. Căutați **extra-simple**.  | 
| * În funcția de afișare ''my_seq_show'' va trebui să: | * În funcția de afișare ''my_seq_show'' va trebui să: | ||
| - | * Obțineți structura [[http://lxr.free-electrons.com/source/include/linux/mm_types.h?v=3.7#L311|mm_struct]] a procesului curent folosind funcția [[http://lxr.linux.no/#linux+v3.9.2/kernel/fork.c#L661|get_task_mm]]. | + | * Obțineți structura [[http://elixir.free-electrons.com/linux/v4.9/source/include/linux/mm_types.h#L396|mm_struct]] a procesului curent folosind funcția [[http://elixir.free-electrons.com/linux/v4.9/source/include/linux/sched.h#L2912|get_task_mm]]. | 
| * Procesul curent este indicat de variabila ''current'' de tip ''struct task_struct *''. | * Procesul curent este indicat de variabila ''current'' de tip ''struct task_struct *''. | ||
| - | * Iterați prin toată lista de structuri [[http://lxr.free-electrons.com/source/include/linux/mm_types.h?v=3.7#L220|vm_area_struct]] asociată procesului. | + | * Iterați prin toată lista de structuri [[http://elixir.free-electrons.com/linux/v4.9/source/include/linux/mm_types.h#L300|vm_area_struct]] asociată procesului. | 
| * Folosiți variabila ''vma_iterator''. | * Folosiți variabila ''vma_iterator''. | ||
| * Porniți de la ''%%mm->mmap%%''. | * Porniți de la ''%%mm->mmap%%''. | ||
| - | * Folosiți câmpul ''vm_next'' al [[http://lxr.free-electrons.com/source/include/linux/mm_types.h?v=3.7#L220|structurii vm_area_struct]] pentru a parcurge lista de zone de memorie (vma-uri -- //virtual memory areas//). | + | * Folosiți câmpul ''vm_next'' al [[http://elixir.free-electrons.com/linux/v4.9/source/include/linux/mm_types.h#L300|vm_area_struct]] pentru a parcurge lista de zone de memorie (vma-uri -- //virtual memory areas//). | 
| * Opriți-vă când ajungeți la ''NULL''. | * Opriți-vă când ajungeți la ''NULL''. | ||
| * Vă bazați pe ''vm_start'' și ''vm_end'' pentru fiecare structură pentru a deduce dimensiunea totală. | * Vă bazați pe ''vm_start'' și ''vm_end'' pentru fiecare structură pentru a deduce dimensiunea totală. | ||
| * Afișați, folosind ''%%printk("%lx %lx\n, ... )%%'', ''vm_start'' și ''vm_end'' pentru fiecare structură ''vm_area_struct''. | * Afișați, folosind ''%%printk("%lx %lx\n, ... )%%'', ''vm_start'' și ''vm_end'' pentru fiecare structură ''vm_area_struct''. | ||
| - | * Pentru a "elibera" structura [[http://lxr.free-electrons.com/source/include/linux/mm_types.h?v=3.7#L311|mm_struct]], decrementați reference counter-ul structurii folosind [[http://lxr.linux.no/#linux+v3.9.2/kernel/fork.c#L606|mmput]]. | + | * Pentru a "elibera" structura [[http://elixir.free-electrons.com/linux/v4.9/source/include/linux/mm_types.h#L396|mm_struct]], decrementați reference counter-ul structurii folosind [[http://elixir.free-electrons.com/linux/v4.9/source/kernel/fork.c#L877|mmput]]. | 
| - | * Folosiți [[http://lxr.linux.no/#linux+v2.6.38/include/linux/seq_file.h#L86|seq_printf]] pentru a scrie în fișier. | + | * Folosiți [[http://elixir.free-electrons.com/linux/v4.9/source/fs/seq_file.c#L413|seq_printf]] pentru a scrie în fișier. | 
| * Afișați **doar** domensiunea totală, fără alt mesaj/șir de caractere. **Nu** afișați nici măcar newline (''\n''). | * Afișați **doar** domensiunea totală, fără alt mesaj/șir de caractere. **Nu** afișați nici măcar newline (''\n''). | ||
| - | * În funcția ''my_seq_open'' înregistrați funcția de afișare (''my_seq_show'') folosind apelul [[http://lxr.free-electrons.com/source/fs/seq_file.c?v=3.7#L581|single_open]]. | + | * În funcția ''my_seq_open'' înregistrați funcția de afișare (''my_seq_show'') folosind apelul [[http://elixir.free-electrons.com/linux/v4.9/source/fs/seq_file.c#L566|single_open]]. | 
| * Ca al treilea argument pentru ''single_open'' puteți folosi ''NULL''. | * Ca al treilea argument pentru ''single_open'' puteți folosi ''NULL''. | ||
| - | * Pentru testare utilizați testul din directorul ''lin/test''. | + | * Pentru testare utilizați testul din directorul ''test/''. | 
| - | * Definiți ''TASK_4'' în ''mmap_test.c''. | + | * Rulați testul folosind comanda ''./mmap-test 4''. | 
| - | * Rulați testul. | + | |
| * Testul așteaptă un timp (are o instrucțiune ''sleep'' internă). | * Testul așteaptă un timp (are o instrucțiune ''sleep'' internă). | ||
| * Cât timp testul așteaptă, folosiți în altă consolă comanda ''pmap'' pentru a vedea mapările testului și a le compara cu cele obținute. | * Cât timp testul așteaptă, folosiți în altă consolă comanda ''pmap'' pentru a vedea mapările testului și a le compara cu cele obținute. | ||
| * Puteți folosi comanda în forma<code> | * Puteți folosi comanda în forma<code> | ||
| - | pmap $(pidof mmap-test) | + | cat /proc/$(pidof mmap-test)/maps | 
| </code> | </code> | ||
| - | * Pentru a accesa altă consolă în mașina virtuală folosiți combinația de taste ''Alt+F2''. | + | <note> | 
| + | * Pentru a accesa altă consolă porniți mașina virtuală în mod grafic și folosiți combinația de taste ''Alt+F2''. | ||
| * Pentru a reveni înapoi în prima consolă folosiți combinația de taste ''Alt+F1''. | * Pentru a reveni înapoi în prima consolă folosiți combinația de taste ''Alt+F1''. | ||
| + | </note> | ||
| ==== Soluții ==== | ==== Soluții ==== | ||
| * [[http://elf.cs.pub.ro/so2/res/laboratoare/lab11-sol.zip | Soluții exerciții laborator 11]] | * [[http://elf.cs.pub.ro/so2/res/laboratoare/lab11-sol.zip | Soluții exerciții laborator 11]] | ||
| ===== Resurse utile ===== | ===== Resurse utile ===== | ||