Differences

This shows you the differences between two versions of the page.

Link to this comparison view

si:laboratoare:06 [2020/11/15 10:59]
dragos_florin.costea
si:laboratoare:06 [2023/11/15 12:03] (current)
florin.stancu fix losetup arg order
Line 1: Line 1:
-====== Laboratorul 06. Yocto ======+====== Laboratorul 06. Root filesystem și servicii de sistem ​======
  
 +===== Root file system =====
  
-[[https://www.yoctoproject.org/|Yocto]] este o colecție de utilitaremetadate ​și șabloane ce permit construirea/compilarea distribuțiilor de Linux pentru platforme embedded. Acest proiect este dezvoltat ​de Linux Foundation ​și condus ​de către Richard Purdie.+Pentru ca sistemul să fie inițializat corect după pornirea kernel-ului,​ este necesar ca toate script-urile și executabilele necesare pentru a porni daemon-ul de inițializare, ​//init//, și restul proceselor ​//​user-space//,​ să existe în anumite locații în sistemul ​de fișiere. Acest sistem minimal ​de fișiere necesar la inițializare poartă numele de **root file system** sau **rootfs**. În cazul sistemelor Unix, //​rootfs//​-ul are ca rădăcină directorul ''/'' ​și înglobează o serie de directoare ce contin restul de fișiere necesare. De obicei, în directorul ''/''​ nu se află niciun fișier, doar subdirectoareAceste subdirectoare sunt organizate în funcție de fișierele pe care le conțin:
  
-Proiectul Yocto se adresează atât utilizatorilor experimentați cât și utilizatorilor noi. Pentru utilizatorii experimentați, Yocto oferă posibilitatea ​de a crea distribuții personalizate pornind ​de la 0 sau de la imagini scheletice. Utilizatorii noi au la dispoziție o serie de exemple ​și un kernel ​ce poate fi folosit ​ca punct de pornire. De asemenea, aceste imagini ​de bază sunt disponibile pentru diferite platforme: ARMPPCMIPSx86 etc.+  * ''/​bin''​ - conține programe ​și comenzi necesare la inițializare ce pot fi folosite apoi de către un utilizator neprivilegiat în timpul unei sesiuni 
 +  * ''/​sbin''​ - conține programe asemănătoare cu cele din /bin ca utilitate, dar care pot fi utilizate în general doar de utilizatorul privilegiat //root// 
 +  * ''/​etc''​ - conține fișierele ​de configurare specifice sistemului 
 +  * ''/​lib''​ - conține bibliotecile folosite ​de programele din //rootfs// (cele din ''/​bin''​ și ''/​sbin''​) 
 +  * ''/​dev''​ - conține referințe ​la toate dispozitivele periferice; aceste referințe sunt în general fișiere speciale 
 +  * ''/​boot''​ - conține fișierele necesare bootării ​și imaginea ​kernel-ului; este posibil ​ca acestea să fie păstrate pe un sistem ​de fișiere separat ​de //​rootfs//​ 
 +  * ''/​tmp''​ - conține fișiere temporare și este de obicei curățat la repornirea sistemului 
 +  * ''/​opt''​ - conține în principal aplicațiile third-party 
 +  * ''/​proc'',​ ''/​usr'',​ ''/​mnt'',​ ''/​var'',​ ''/​home''​ - sunt directoare careîn generalreprezintă puncte în care se pot monta alte sisteme de fișiere pentru a stoca log-uribiblioteci și alte aplicații și programe folosite de către utilizatori.
  
-Pentru a-și ajuta utilizatorii,​ Yocto vine cu o serie de aplicații: un sistem de build numit ''​Bitbake'',​ o interfață grafică numită ''​Hob'',​ un plug-in ​de Eclipse ce permite lucrul într-un IDE și o documentație.+<​note>​ 
 +Organizarea unui rootfs Linux în termeni ​de directoare este bine definită de standardul ierarhiei sistemului de fișiere: [[https://​refspecs.linuxfoundation.org/​fhs.shtml|Filesystem Hierarchy Standard]], ultimul standard FHS 3.0 fiind definit in 2015. 
 +</​note>​
  
-Sursele Yocto pot fi găsite în repository-ul de la adresa **[[http://git.yoctoproject.org/cgit/cgit.cgi/​poky]]**.+Standardul Unix recomandă ca //rootfs//-ul să aibe dimensiuni relativ mici, deoarece orice problemă sau corupere a acestuia poate împiedica inițializarea corectă a sistemuluiDacă, totuși, rootfs-ul devine corupt, există modalități prin care poate fi remediat. O soluție des folosită este de a monta acest sistem de fișiere într-un alt sistem, funcțional,​ pentru a putea fi explorat și verificat.
  
 +În cazul sistemelor embedded, de multe ori spațiul de stocare pe care îl avem la dispoziție este deja limitat: < 32MB. De cele mai multe ori, o bună parte din acest spațiu este ocupat de imaginea kernel-ului. De aceea, în majoritatea cazurilor, //​rootfs//​-ul pentru aceste sisteme este fie compus doar din minimul de programe necesar pentru funcționare,​ fie este stocat pe un server accesibil prin rețea și montat de către kernel la inițializare (e.g., folosind protocolul NFS).
  
-===== Bitbake ​=====+===== Pseudo Filesystems ​=====
  
-[[http://​docs.openembedded.org/​bitbake/​html/​|Bitbake]] este sistemul ​de build folosit de Yocto. Acesta este asemănător sistemului folosit uzual pe distribuțiile Linux, ''​make''​. Ca și ''​make''​''​bitbake'' ​trebuie să determine ce acțiuni trebuie executate și apoi să le lanseze efectiv în execuțieAceste acțiuni se determină în funcție ​de: comenzile date de către utilizatordatele proiectului și starea curentă ​build-ului. Toate operațiile ce trebuie ​executate, dependențele dintre acestea, variabilele și instrucțiunile sunt ținute și citite din fișiere scrise în sintaxa specifică ''​bitbake'':​+Un kernel Linux expune mai multe pseudo-sisteme ​de fișiereprecum ​''​/dev'' ​(unde există noduri pentru toate dispozitivele detectate), ​''​/proc'' ​sau ''​/sys''​. ​Unele aplicații ce gestionează sistemul ​de operare au nevoie ca aceste mountpointuri să existeele fiind folosite pentru ​interfața cu kernelul (mai ales în sisteme incorporate,​unde programele ​trebuie ​să comunice cu hardware-ul).
  
-<code bitbake HelloWorld.bb>​ +==== Sistemul virtual proc ====
-DESCRIPTION ​"Hello world program"​ +
-PR "​r0"​ +
-SRC_URI ​"​file://​myhelloworld.c \ +
-           ​file://​README.txt"​+
  
-TARGET_CC_ARCH += "​${LDFLAGS}"​  +Acest sistem de fișiere există de când există și Linux-ul și permite expunerea de statistici despre procesele rulate în sistem dar și ajustarea la runtime a diverșilor parametrii ce implică managementul proceselor, ale memoriei etc. Este utilizat de majoritatea aplicațiilor standard. Aplicații precum **ps** și **top** nu pot funcționa fără acest filesystem.
-            +
-do_compile() { +
-        ${CC} ${CFLAGS} ${LDFLAGS} ${WORKDIR}/​myhelloworld.c ​-o ${WORKDIR}/​myhelloworld +
-}+
  
-do_install() { +Pentru a monta **proc** se poate folosi comanda: <​code>​ mount -t proc nodev /proc </​code>​
-        install ​-d ${D}${bindir}+
  
-        install -m 0755 -t ${D}${bindir} ${WORKDIR}/myhelloworld +Printre conținutul aflat în **proc** putem găsi: 
-+  * ///​proc/​interrupts,​ /​proc/​iomem,​ /​proc/​cpuinfo//:​ ce conțin informații specifice de device 
-</code>+  ​* ​///​proc/<​pid>, /​proc/​3840/​cmdline//:​ conține detalii despre fișierele deschise de proces, utilizarea memoriei, procesorului etc. 
 +  * ///​proc/​cmdline//:​ conține linia de comandă cu care a fost pornită imaginea kernel-ului 
 +  * ///​proc/​sys//:​ conține ​ fișiere care pot fi scrise pentru a ajusta parametrii ai kernel-ului. Poartă numele de **sysctl**. Mai multe detalii despre asta aici: [[https://​www.kernel.org/​doc/​html/​latest/​admin-guide/​sysctl/​|documentație sysctl]].
  
-Asemănător cu un Makefile, putem folosi variabile de sistem pentru a specifica flag-uri, executabile,​ căi etc. Principala diferență constă în modul de organizare a fișierului. În aceste fișiere de configurare ne este permis să definim task-uri pentru fiecare etapă a procesului de build ce trebuie executată. Astfel, codul este mult mai bine organizat, mai ușor de urmărit și de depanat.+==== Sistemul virtual sys ====
  
-Un alt avantaj al lui ''​bitbake''​ este organizarea sa ierarhică. Atunci când se pornește un build, ''​bitbake'' ​are o viziune de ansamblu ​asupra ​distribuțieiSe vor citi mai întâi toate fișierele de configurare (rețetele) ce au legătură cu acea distribuție ​și abia apoi se va decide care sunt task-urile ce trebuie executate și în ce ordine se vor executa.+Permite reprezentarea în userspace a viziunii pe care o are kernel-ul ​asupra ​magistralelor,​ dispozitivelor și driverelor din sistemEste util pentru diverse aplicații din userspace care trebuie să enumere ​și să interogheze hardware-ul disponibil, de exemplu **udev** sau **mdev**:
  
-===== Fișiere speciale și variabile de sistem =====+<​code>​ls /sys/ 
 +block bus class dev devices firmware fs kernel module power 
 +</​code>​
  
-Observați că fișierul din exemplul de mai sus are extensia ''​.bb''​. Aceasta este o extensie specială specifică unei categorii de fișiere de configurare pentru ''​bitbake''​. Există mai multe categorii de astfel de fișiere, fiecare exprimând un set diferit de metadate (dependențe,​ patch-uri, instrucțiuni) ​pentru ​o anumită componentă. Categoriile importante (în funcție de extensie):+===== Utilitare folosite ​pentru ​crearea / inspecția unui RootFS =====
  
-  * ''​.bb'': ​fișiere concise ce definesc operațiile ce trebuie executate. Poartă numele de **rețete**. O rețetă poate include alte rețete ​și poate moșteni dintr-o altă rețetă +Uneori vom fi în situația în care nu avem acces la un server ​și imaginea de care dispunem pentru sistemul nostru nu este satisfăcătoareÎn aceste condiții va trebui ​să ne creăm propriul //rootfs// pe care să îl scriem în memoria sistemului embedded.
-  * ''​.bbclass'':​ fișiere folosite pentru a preciza metadatele folosite uzual pentru operațiile comune de build sau împachetare. Aceste fișiere sunt de obicei moștenite de tre rețete +
-  * ''​.inc'':​ fișiere ce conțin un anumit set de definiții. Sunt folosite atunci când vrem să particularizăm procesul de build pentru o anumită versiune, arhitectură etc. +
-  * ''​.bbappend'':​ fișiere ce conțin adăugiri sau componente opționale pentru rețete +
-  * ''​.conf'':​ fișierul local de configurare al unui proiect+
  
-Pe lângă aceste fișiere, ​pentru ​a personaliza un proiect/​buildavem la dispoziție și o serie de variabile de sistem:+Imaginea recomandată pentru ​RaspberryPiRaspbian, conține două partiții: o partiție ''​FAT''​ folosită pentru boot și o partiție ''​ext4''​ pentru //rootfs//. Fiecare dintre aceste partiții începe ​de la un anumit offset în cadrul imaginii. Atunci când dorim să creăm o imagine nouă pentru RaspberryPi,​ trebuie să ne asigurăm că respectăm aceste partiții și formatele lor. Pașii pe care trebuie să îi urmăm sunt:
  
-  * ''​BBFILES'':​ variabila ce spune sistemului ''​bitbake''​ care sunt rețetele disponibile +  * Stabilirea dimensiunii imaginii și inițializarea acesteia cu zero-uri 
-  * ''​SRC_URI'':​ identifică fișierele care trebuiesc incluse în directorul de lucru special făcut pentru rețeta respectivă +  * Crearea tabelei de partiții ​și a celor două partiții necesare 
-  * ''​BB_NUMBER_THREADS'':​ denotă numărul de thread-uri de ''​bitbake''​ care să ruleze +  * Formatarea partițiilor cu formatul corespunzător 
-  * ''​PARALLEL_MAKE'':​ modul în care va fi făcută compilarea ​și numărul de thread-uri de compilare care vor porni. Valoarea acestei variabile este aceeași ca în cazul sistemului ''​make'':​ -j <​num_threads>​ +  * Pentru popularea rootfs-ului,​ putem fie să montam partiția ​și să copiem manual directoarele ​și fișierele, fie putem să copiem o partiție întreagă de pe o altă imagine
-  * ''​MACHINE'':​ denumirea sistemului (mașinii) pentru care se realizează compilarea +
-  * ''​BBMASK'':​ lista de pachete ce vor fi ignorate în momentul compilării +
-===== Rețete =====+
  
-Fișierele de configurare prezentate anterior poartă denumirea de rețete ​și au uzual extensia ''​.bb''​. În cadrul unui proiect (o distribuție) acestea definesc operațiile ​ce trebuie executate. În funcție de complexitatea și dimensiunea proiectului,​ acesta va parcurge un anumit număr de etape. Dacă proiectul este mic și presupune, spre exemplu, doar compilarea unor surse, atunci este suficientă o rețetă ce conține un task ''​do_compile''​. Un proiect mai mare va trece însă cel puțin prin etapele de ''​fetch'',​ ''​configure'',​ ''​compile''​ și ''​install''​.+Pentru fiecare dintre acești pași există utilitare ​ce ne ajută să realizăm operațiile necesare.
  
-Pentru un astfel de proiect va exista câte o rețetă ce conține un task de tip ''​do_''​ pentru fiecare operație. Folosind apoi proprietatea rețetelor de a include sau a specifica dependențe față de alte rețete, se creează o ierarhie ce pornește de la o rețetă top level și parcurge și execută în ordine toate operațiile.+==== dd ====
  
-Directivele ce pot fi folosite într-o rețetă pentru a include sau moșteni alte fișiere de configurare sunt: +Pentru copierea, ​și eventual convertirea,​ unui fișier, la nivel de byte, se poate folosit utilitarul //dd//.. Folosind //dd//, putem de asemenea genera ​fișiere de anumite dimensiuni ​și le putem stabili conținutulÎn cazul nostru//dd// este util pentru a inițializa o imagine ​și pentru a copia în acea imagine conținutul care ne interesează. Dintre parametrii lui //dd//cei mai des utilizați sunt:
-  * include <​file_name>:​ include fișierul cu numele <​file_name>​Este folosită variabila ''​BBPATH''​ pentru a căuta ​fișierul +
-  * require [<​path>​]<​file_name>:​ un tip special ​de includere a fișierului <​file_name>​Se va încerca includerea fișierului ca și în cazul lui ''​include''​dar operația va eșua dacă nu există fișierul ​în locația specificată +
-  * inherit <​file_name>:​ include definițiile din fișierul <​file_name>​.bbclassdacă acesta există ​+
  
-===== Layer =====+  * ''​if''​ - fișierul de intrare; dacă nu se specifică acest parametru, se va citi de la //standard input// 
 +  * ''​of''​ - fișierul de ieșire; ca și la ''​if'',​ dacă nu este specificat, se scrie la //standard output// 
 +  * ''​count''​ - numărul de blocuri de input ce vor fi copiate 
 +  * ''​bs''​ - numărul de bytes dintr-un bloc
  
-Un set de rețete și alte fișiere specifice ​''​bitbake'' ​ce au legătura ​cu o anumită funcționalitate sau o anumită componentă pot fi organizate într-un **layer**. Layer-ul este un fișier ​ce conține referința către o configurație și setul de rețete ce trebuiesc executate pentru a obține ​anumită distribuție.+<note tip> 
 +Un exemplu ​de utilizare a lui ''​dd'' ​pentru a inițializa ​cu zerouri ​un fișier de o dimensiune exactă:
  
-<​code ​bash LayerExample+<​code ​shell
-meta-layer:  +$ dd if=/​dev/​zero of=<​file>​ bs=1M count=2048
-  - conf +
-  - recipes-core +
-      - important_recipe +
-          - x.bb +
-  - recipes-category1 +
-      - recipe-1a +
-          - y.bb +
-          - t.bbappend +
-      - recipe-1b +
-          - ... +
-  - recipes-category2 +
-      - recipe-2a +
-          - ...  +
-      - recipe-2b +
-          - ...+
 </​code>​ </​code>​
  
-Structura unui layer este următoarea:​ denumirea layer-ului urmată ​de o serie de categorii de rețeteFiecare categorie conține lista rețetelor componente ​șfișierele de configurare aferente fiecarei dintre acestea.+Observați valorile lui ''​count''​ si ''​bs''​. Se vor copia în total 2048 de blocuri de câte 1MB fiecare, rezultând ​dimensiune ​de 2GBFișierul de intrare ''/​dev/​zero''​ este un fișier special din care se pot citi oricâte caractere ASCII NUL (0x00). 
 +</​note>​
  
-Atunci când parsează un fișier de tip ''​bblayer'',​ ''​bitbake''​ va configura variabila de sistem ''​BBPATH''​ cu locațiile în care se găsesc rețetele necesare. În cadrul acestui proces de construire a variabilei ''​BBPATH'',​ dacă ierarhia conține rețete cu nume duplicat, pot apărea conflincte sau situații neașteptate în timpul compilării,​ deoarece fișierele de configurare pentru o rețetă pot fi incărcate dintr-o locație diferită față de cea dorită.+==== parted ====
  
-Specificarea layer-elor ce se doresc a fi incluse într-un proiect se face prin scrierea unui fișier numit ''​bblayers.conf''​Structura acestuia ​este următoarea:+Pentru manipularea tabelei de partiții (crearea sau ștergerea partițiilor) ​se poate folosi utilitarul //parted//. Acesta recunoaște ​și poate manipula multiple formate de partiții: DOS / SUN / GNU / GPT etcUtilitarul primește ca parametru device-ul a cărui tabelă de partiții dorim să o modificămUn exemplu de apel este:
  
-<​code ​bash+<​code ​shell
-BBLAYERS ?= " \ +$ parted ​/dev/<device>
-<​path_to>​/poky-rasp/meta \ +
-<path_to>/​poky-rasp/​meta-yocto \ +
-<​path_to>/​poky-rasp/​meta-yocto-bsp \ +
-<​path_to>/​poky-rasp/​meta-raspberrypi \ +
-"+
 </​code>​ </​code>​
  
-Acest fișier pune în variabila ​de sistem ​''​BBLAYERS'' ​căile către fiecare locație în care se găsește ​fișierul ''​bblayer'' ​al layer-ului dorit. +Rezultatul acestei comenzi este un prompt nou (similar cu //​fdisk//​) ​în care putem folosi tasta ''​m''​ pentru a afișa un meniu cu opțiunile disponibile. Opțiuni utile pentru crearea și ștergerea ​de partiții sunt: 
-===== Instalare Yocto si configurare pentru RaspberryPi =====+  
 +  * ''​print'' ​(sau simplu, ''​p''​) - afișează tabela curentă
 +  * ''​mklabel <​type>''​ - șterge tot și crează o tabelă nouă de partiții (type poate fi ''​msdos'',​ ''​gpt''​ etc.); 
 +  * ''​mkpart [type] [fstype] <​START>​ <​END>''​ - crează o partiție nouă (type poate fi ''​primary''​ / ''​logical''​ / ''​extended''​);​ singurii parametrii obligatorii sunt cele 2 offseturi;​ 
 +  * ''​set <​partition>​ <​flag>​ <​state>''​ - setează un flag unei partiții;​ 
 +  * ''​rm <​NUMBER>''​ - șterge o partiție;​ 
 +  * ''​quit''​ - iese din program (toate comenzile salvează automat).
  
-Sursele proiectului Yocto pot fi descărcate urmărind instrucțiunile ​de [[https://​www.yoctoproject.org/​downloads|aici]] sau clonate direct din repository-ul mentionat ​la începutul laboratorului.+Trebuie reținut că, în mod normal //parted// operează cu sectoare și nu cu octeți. Așadar, este de preferat să punem unitatea de măsură (K, M, G etc.) ca sufix la orice offset cerut de comenzi (e.g., ''​120MB''​).
  
-Următorul pas este să obținem layer-ele și configurațiile necesare pentru ​compila imaginea corespunzătoare pentru sistemul dorit. În cazul nostru, acest sistem ​este ''​RaspberryPi''​. ​Acest layer poate fi obținut clonând repository-ul de la adresa: [[https://​github.com/​djwillis/​meta-raspberrypi.git]] +<​note>​ 
- +  * Dimensiunea standard ​unui sector de disc este ''​512 bytes''​. ​Aceasta ​poate fi schimbată folosind opțiunea ''​-b''​
-După ce avem sursele Yocto și layer-ul necesar pentru dezvoltarea unei imagini de RaspberryPi,​ trebuie să inițializăm mediul ​de compilare ​și directorul de lucruPentru aceasta, trebuie rulată următoarea comandă în directorul ​ce conține sursele Yocto: +  * Există două tipuri ​de partiții: ''​primary'' ​și ''​extended''​Un device ​ce folosește sistemul de partiții ''​DOS''​ nu poate avea mai mult de 4 partiții primare (la GPT s-au eliminat aceste restricții). 
- +  * Exemplu de creare a celor 2 partiții necesare pentru o imagine bootabilă Raspberry PI:<​code>​ 
-<​code ​bash+(parted) mklabel msdos 
-source oe-init-build-env <​path_to_working_directory>/<​rpi_build_folder>/​+(parted) mkpart primary fat32 1MiB 120MiB 
 +(parted) mkpart primary ext4 120MiB 100% 
 +(parted) print 
 +(parted) quit
 </​code>​ </​code>​
 +  * Observați, în exemplu anterior, la ultima partiție s-a folosit o unitate specială, procentul, ceea ce înseamnă că ultimei partiții i s-a repartizat tot spațiul rămas.
 +</​note>​
  
-Apoi vom adăuga intrări în fișierele de configurare a mediului pentru a ne asigura că parametrii folosiți la compilare sunt corecți și că va fi inclus layer-ul pentru RaspberryPi. În directorul inițializat mai devreme, ''<​path_to_working_directory>/<​rpi_build_folder>/'',​ se găsește directorul ''​conf''​ ce conține fișierul de configurare ''​local.conf''​. Trebuie să ne asigurăm că: +==== losetup ====
-  - ''​BB_NUMBER_THREADS''​ are valoarea egală cu numărul de thread-uri de build ce dorim să fie create. Valoarea inițială este 4 +
-  - ''​PARALLEL_MAKE''​ are valoarea egală cu numărul de procesoare disponibile. +
-<note important>​Valoarea trebuie să aibă forma ''​-j x'',​ unde x este numărul de procesoare disponibile.</​note>​ +
-  - ''​MACHINE''​ are valoarea "​raspberrypi"​ +
-  - ''​BBMASK''​ va exclude pachetele ce nu sunt suportate de core-ul Yocto. Spre exemplu, în unele versiuni mai vechi ale layer-ului de RaspberryPi,​ acestea erau: "​meta-raspberrypi/​recipes-multimedia/​libav|meta-raspberrypi/​recipes-core/​systemd"​+
  
-<note tip> Toate valorile acestor variabile sunt șiruri de caractere! O atribuire precum ​''​MACHINE = my_machine_name'' ​va genera eroare ​la parsare. Atribuirea corectă este ''​MACHINE = "​my_machine_name"​''​</note>+Dacă se lucrează cu imagini din fișiere, este util să le putem //monta// pentru a vedea ce conțin. Însă acest lucru nu se poate realiza pe Linux fără a avea un dispozitiv ​de tip bloc. Din fericire, utilitarul ​''​losetup'' ​ne poate salva în aceste situații, el permițând conectarea unui fișier imagine ​la un dispozitiv bloc virtual de forma ''​/​dev/​loop<​N>​''​, unde //N// este un număr din intervalul //[0-9]//.
  
-Tot în directorul ​''​conf'' ​există și fișierul ''​bblayers.conf''​ ce conține informația legată ​de layer-ele ce vor fi compilateTrebuie să adăugăm la variabila ''​BBLAYERS''​ o cale către layer-ul de RaspberryPiRevedeți secțiunea ​**Layers** și exemplul ​de acolo.+**Atenție**: ​''​losetup'' ​nu poate fi utilizat decât cu privilegii ​de **root** (e.g., folosiți **sudo** la toate comenzile ​de manipulare a dispozitivelor de sistem)!
  
-Tot ce mai rămâne acum de făcut este să ne asigurăm că utilitarele folosite de ''​bitbake''​ sunt instalate în sistem ca să putem compila imagineaÎn cazul în care acestea nu există, se pot instala folosind una din comenzile ​de mai jos, în funcție de versiunea sistemului+Exemplu folosire: <code bash> 
- +# conectăm fișierul la un dispozitiv loop 
-<code bash Fedora> +losetup /​dev/​loop0 ​./​path/​to/​your-image.bin 
-sudo yum groupinstall "​development tools"+# scanăm dispozitivul bloc de partiții
 +partprobe /dev/loop0 
 +ls -l /dev/loop0* 
 +# ^ ar trebui să vedeți cele 2 partiții ale imaginii RPI: loop0p1 și loop0p2
 </​code>​ </​code>​
  
-<code bash Ubuntu>​ +**Important / NU uitați:** la final, trebuie să deconectăm dispozitivul pentru a sincroniza cele scrise înapoi în fișier: ''​losetup ​-d /dev/loop<N>''​!
-sudo apt-get install sed wget cvs subversion git-core coreutils \ +
-unzip texi2html texinfo libsdl1.2-dev docbook-utils gawk \ +
-python-pysqlite2 diffstat help2man make gcc build-essential \ +
-g++ desktop-file-utils chrpath libgl1-mesa-dev libglu1-mesa-dev \ +
-mercurial autoconf automake groff libtool xterm +
-</code>+
  
-Compilarea unei imagini inițiale pentru o arhitectură poate dura de la cateva ore la zeci de ore, în funcție de performanța sistemului pe care se face compilarea. Procesul este unul îndelungat deoarece sistemul de build Yocto își va construi singur toate componentele necesare precum biblioteci, cross-compiler,​ etc. Spre exemplu, observați că nu mai este necesară instalarea unui cross-compiler. Acesta va fi creat la începutul build-ului, în două etape: mai întâi va fi compilată biblioteca ''​glibc''​ pentru platforma aleasă și apoi se va crea cross-compiler-ul propriu-zis.+==== mkfs ====
  
-Avantajul acestui mod de lucru este că efortul necesar ​pentru ​pregătirea ​și inițializarea unui build este mic și nu există dependențe numeroase față de alte biblioteci externe sau alte utilitareDezavantajul major este timpul necesar ​pentru ​o compilare. +Crearea unei partiții nu este suficient ​pentru ​a putea stoca fișiere. Avem nevoie ca partiția să conțină și un sistem ​de fișiereUtilitarul folosit ​pentru ​a crea (formata) sisteme de fișiere Linux este //mkfs//. Parametrii pe care îi primește //mkfs// sunt device-ul ce trebuie formatat și tipul sistemului de fișiere dorit, specificat cu parametrul ''​-t''​.
-===== Exerciții =====+
  
-0. Urmăriți instrucțiunile prezentate în +Spre exemplu, comanda <code shell> 
 +$ mkfs -t ext4 -L MyRootFS /dev/fd0 
 +</​code>​
  
-1. În home-ul utilizatorului student există deja o imagine compilată pentru RaspberryPi. Aceasta se află undeva in directorul ''​/home/student/yocto/build''​. Formatul imaginii este ''​ext3'',​ iar numele acesteia este ''​rpi-hello-image-raspberrypi''​. ​ In directorul ''​/home/student/lab-yocto-utils''​ există și o imagine de [[https://drive.google.com/file/d/0B0lgiPZNMMyvMWEtZS1zME9lQjQ| kernel]]Rulați această configurație în Qemu.+Va crea pe device-ul //fd0// un sistem de fișiere //ext4// cu label-ul (denumire logică) //MyRootFS//. În Linux, utilitarul //mkfs// este împărțit în câte un executabil pentru fiecare tip de sistem de fișiere suportatPentru a le vedea pe cele disponibile,​ deschideți un terminal, scrieți ''​mkfs.''​ (punct la coadă!) și apasați tab.
  
-2. Pentru a adăuga un layer nouvă trebuie un director în root-ul Yocto: ​''​meta-labsi'' ​cu fișierul ''​conf/layer.conf''​ identic cu cel din ''​meta-raspberrypi''​. Iată apoi scheletul unei rețete pentru o aplicație hello world:+<​note>​ 
 +Dacă etichetați sistemele de fișierele puteți accesa ulterior după căi speciale din ''​/​dev/​disk/​by-label/''​!  
 +</note>
  
-<code bash hello.bb>​ +==== mount ====
-DESCRIPTION ​"Hello World"​ +
-LICENSE ​"​MIT"​ +
-LIC_FILES_CHKSUM ​"​file://​${COMMON_LICENSE_DIR}/​MIT;​md5=0835ade698e0bcf8506ecda2f7b4f302"​+
  
-PR = "​r0"​+În sistemele Unix, sistemul de fișiere este unul arborescent unde directoarele pot fi considerate noduri, iar fișierele frunze. Utilitarul //mount// ne permite să atașăm unui arbore existent un alt subarbore (sistem de fișiere). Apelată fără niciun parametru, această comandă va afișa toate device-urile montate, locația în care sunt montate și opțiunile cu care au fost montate.
  
-#TODO: scriețîn SRC_URI calea către ​fișierul dorit. +Formatul general al comenzii este ''​mount -t <​type>​ <​device>​ <mount path>'',​ unde //<​type>//​ este acelașca la //mkfs//. De cele mai multe ori, argumentul ''​-t <​type>''​ poate fi omis, acesta fiind autodetectat de către ​kernel.
-SRC_URI = ""​+
  
-S = "​${WORKDIR}"​+Și, desigur, pentru de-montarea de la final a dispozitivelor,​ putem folosi ''​umount''​ cu argumentul ori dispozitivul sursă, ori mountpointul (oricare ne este mai la îndemână -- va face același lucru).
  
-TARGET_CC_ARCH +"​${LDFLAGS}" ​+===== Exerciții =====
  
-do_compile() {+<​note>​ 
 +**În laborator, vom folosi echipamente Raspberry PI 4!** conectate prin USB Type-C și un adaptor UART la USB pentru vizualizarea consolei dispozitivului ​(din păcate, nu dispunem de suficiente monitoare HDMI în laborator + cabluri adaptoare).
  
-}+Înainte de a începe exercițiile,​ asigurați-vă că aveți cel puțin 10GB de storage disponibili în mașină virtuala de laborator. 
 +</​note>​
  
-do_install() {+**0.** Descărcați [[https://​github.com/​cs-pub-ro/​SI-rpi-debian-scripts/​releases|de aici arhiva rootfs referință pentru laborator ​(v2)]] + imaginea partiției de boot ''​rpi-boot.img''​ (pe care o vom clona mai târziu și îi vom adăuga partiție nouă pentru Linux).
  
-}+  * Pentru cei cu Windows, descărcați și instalați utilitarul [[https://​www.raspberrypi.com/​software/​|Raspberry Pi Imager]], pe care îl vom folosi să scriem imaginea pe dispozitivul fizic.
  
 +1. Dorim să creăm propria imagine pe care, ulterior, s-o urcăm pe Raspberry PI și să bootăm Linux-ul (prin U-Boot și modul ''​ums''​ -- USB Mass Storage Device):
 +
 +  * Imaginea de //​rpi-boot.img//​ a RaspberryPi are dimensiunea de ~150MB. Folosiți ''​dd''​ (citiți și documentația din laborator mai sus) și creați o imagine nouă, plină de zerouri, de 2GB (să zicem, ''​rpi-full.img''​).
 +  * Dorim să copiem de-a întregul prima partiție din imaginea ''​rpi-boot.img''​ în cea de 2GB proaspăt creată. Putem folosi ''​dd''​ pentru asta:<​code>​
 +dd if=rpi-boot.img of=rpi-full.img conv=notrunc
 </​code>​ </​code>​
 +  * Folosind ''​parted'',​ inspectați dacă există partiția de boot în noua imagine (cea //full//). Apoi creați pe cea de-a doua partiție (ce va conține un sistem de tip ext4). Vedeți mai sus în laborator pentru exemple de folosire a utilitarului;​
 +  * Formatați sistemul de fișiere a celei de-a doua partiții în ext4. Pentru aceasta, va trebui, mai întâi, să conectați imaginea într-un dispozitiv de tip bloc prin ''​losetup'',​ apoi ''​mkfs''​ pentru a o formata (urmați documentația din laborator a acestor utilitare); ​
 +  * Montați noua partiție ''​ext4''​ (puteți folosi ''/​mnt''​ ca mountpoint) și copiați conținutul arhivei rootfs descărcate mai sus; folosiți argumentul ''​-C''​ al ''​tar''​ pentru a preciza directorul destinație,​ adică mountpointul partiției). **Atenție**:​ folosiți contul de ''​root'',​ deoarece dorim să dezarhivăm fișierele și să păstrăm permisiunile originale (imaginea este un root filesystem de Linux pre-instalat!):​ <code bash>
 +tar xf <​ARCHIVE_FILE>​ -C <​DEST_MOUNTPOINT>​
 +# inspectați calea dezarhivată:​
 +ls -l <​DEST_MOUNTPOINT>​
 +# ar trebui să vedeți toate directoarele unui rootfs clasic: /bin, /usr, /dev, /opt etc.
 +</​code>​
 +  * Încă nu am terminat. Montați partiția de boot (prim partiție din loop device) într-o cale (puteți crea directorul ''/​mnt/​boot/​rpi''​ și să-l folosiți); apoi copiați fișierele ''/​boot/​vmlinuz-<​versiune>''​ ''/​mnt/​boot/​initrd.img-<​versiune>''​ pe prima partiție (în mountpointul acesteia, ofc); acestea sunt necesare deoarece bootloaderul RPI nu știe să citească partiții ''​ext4''​ (ci doar FAT32).
 +  * Tot pe partiția de boot, creați fișierul ''​cmdline.txt''​ și scrieți argumentele kernelului Linux:<​code>​
 +earlycon=pl011,​mmio32,​0xfe201000 console=tty1 console=serial0,​115200 root=/​dev/​mmcblk0p2 rw rootwait fsck.repair=yes
 +</​code>​
 +  * **Acum (atenție!):​** demontați partițiile (mai întâi pe cea de boot, montată ultima oară, apoi pe cea ext4) și deconectați dispozitivul ''​loop''​!
 +
 +2. Acum că imaginea noastră este gata, vrem să vedem că funcționează. Pentru aceasta, va trebui să pornim u-boot în modul ''​ums''​ (vedeți [[:​si:​laboratoare/​05|laboratorul anterior]]) și folosim un utilitar de Raw Disk Imager (precum cel descărcat mai sus) sau ''​dd''​ (pentru cei cu Linux nativ sau cărora le funcționează USB Device Passthrough în mașina virtuală) pentru a scrie imaginea obținută anterior.
  
-<​note ​tip>  ​Scrieți rețeta în folder-ul corespunzătorpregătiți un fișier hello.c ​(va afișa "Hello World!"​) și scrieți funcțiile ​''​do_compile'' ​și ''​do_install''​ +<​note ​important> 
-Layer-ul nou trebuie adăugat în ''<​yocto_dir>/​build/​conf/​bblayers.conf''​+  * **Atenție**: Va trebuimai întâi, să aduceți imaginea pe Windows ​(folosiți ''​scp'' ​cu ''​username@<​ip_sursa>:/​cale/​catre/​fisier.img'' ​ca prim argument, iar, ca destinație,​ o cale de pe PC-ul fizic, e.g., ''​C:​\Users\..etc''​)! 
 +  * **Notă pentru VirtualBox**:​ va trebui să folosiți argumentul ''​-P 2023''​ și ''​student@localhost:​<cale>''​ ca sursă. 
 +  * **Notă pentru cei cu gazda pe Linux**: dacă utilizați ​''​dd'',​ va trebui să rulați comanda ''​sync''​ și să așteptați să se termine! Asta e important deoarece kernelul modern cache-uiește în memoria RAM și scrierea se termină, aproape instant (însă rămâne să se copieze pe SD în background, această operațiune fiind mult mai lentă).
 </​note>​ </​note>​
  
-3. Pachetul cu aplicația ''​hello''​ nu va fi instalat nicăieri dacă o imagine nu are nevoie de elTrebuie făcută o nouă imagine, pe modelul ​''​../meta-raspberrypi/​recipes-core/​images/​rpi-basic-image.bb''​+3. Reporniți Raspberry PI-ulVom încerca să bootăm kernelul și rootfs-ul din prompt-ul ​''​u-boot''​:
  
-  * Includeti restul de rețete folosite de ''​rpi-basic-image''​ in imaginea voastră. Folosiți directiva ''​require''​. Formatul este''​require ​<cale_reteta_rpi_basic_image>''​+  * Deoarece kernelul este compresat, operațiunea este un pic mai complicată,​ trebuind să-i spunem o zonă de memorie folosibilă pentru extracția imaginii: <code> 
- +# load bootargs from device tree (contains BL2-modified cmdline.txt data) 
-<ifauth @admin> +fdt addr ${fdt_addr} && fdt get value bootargs /chosen bootargs 
-<code bash rpi-hello-image.bb> +# set decompression zone in RAM at 400MB, 64MB in size 
-require recipes-core/​images/​rpi-basic-image.bb+setenv kernel_comp_addr_r 0x19000000 
 +setenv kernel_comp_size 0x04000000 
 +# load kernel from file 
 +fatload mmc 0:1 ${kernel_addr_r} vmlinuz-6.1.61-rpi
 +# boot without initrd, for now 
 +booti ${kernel_addr_r} ​${fdt_addr}
 </​code>​ </​code>​
-</ifauth>+  * Dacă vă printează mesajul cu ''​waiting for device ​/dev/​mmcblk0p2''​ și nu se termină procesul, verificați dacă ați rulat kernel-ul 6.1 (este în comanda de mai sus) și dacă partiția a doua există (''​part list mmc 0''​).
  
-  * Oferiti drepturi de scriere tuturor utilizatorilor pe directorul ''/​var/​tmp/''​. +4Dorim să instalăm pachete în imagine. Deoarece pe Raspberry PI nu avem Internet, vom face asta pe mașina virtuală, lucrând direct cu imaginea ​și utilitarele ​''​systemd-nspawn'' ​(pornește facil un chroot container) și ''​qemu-user-static'' ​(ce ne va permite emularea unei arhitecturi străine direct dintr-un container)!
-  * Această nouă rețetă pentru ​imaginea ''​rpi-hello-image'' ​trebuie pusă în layer-ul nou +
-  * Noua imagine trebuie să adauge pachete noi pentru aplicația ​''​hello''​, adăugând (cu += în variabila IMAGE_INSTALL) +
-  * Apelați bitbake cu noua imagine și verificați în Qemu rezultatul obținut!+
  
-Bonus 4. Pentru ​modifica numele pe care îl publică un RaspberryPi este suficient să modificăm ​''/​etc/hostname''​. Pentru aceasta am putea modifica fișierul din imagine, dar dezavantajul este că ar trebui să facem această modificare la fiecare recompilare. Am prefera să obținem direct o imagine ​cu numele nouiar ca să obținem acest lucru trebuie ​să modificăm rețetele Bitbake care stau la baza pachetelor instalate în imagine.+  * Folosind ''​losetup'',​ ''​partprobe''​ și ''​mount'',​ montați partiția ​doua (e.g., în ''/​mnt''​). 
 +  * Copiați utilitarul ''​qemu-<​arch>​-static''​ pentru arhitectura emulată (AArch64) în rootfs (în ''/​mnt/usr/bin''​): <​code>​ 
 +# vedem unde e executabilul:​ 
 +which qemu-aarch64-static 
 +# /​usr/​bin/​qemu-aarch64-static 
 +cp -f /​usr/​bin/​qemu-aarch64-static /​mnt/​usr/​bin 
 +chmod +x /​mnt/​usr/​bin/​qemu-aarch64-static 
 +</​code>​ 
 +  * Rulăm containerul:​ <​code>​ 
 +systemd-nspawn --as-pid2 --resolv-conf=copy-host -D "/​mnt"​ bash 
 +</​code>​ 
 +  * Ar trebui să fiți în containerul de Debian pe arhitectură străină (AArch64), emulat prin qemu-user-static ​cu ajutorul funcționalității din kernel ''​binfmt_misc''​. Rulați ''​apt update''​ și instalați pachetele ''​wpasupplicant''​ (pentru autentificare prin WiFi) și ce alte utilitare mai doriți. 
 +  * La final**nu uitați** ​să de-montați + deconectați dispozitivele loop utilizare! 
 +  * Bonus: testați noua imagine pe dispozitivul RPI4 (va trebui ​să repetați pașii copiere + burn folosind Disk Imager)!
  
-Ca exemplu, noi vom umbla în rețeta base-files. O descriere și implementarea o puteți găsi în ''/​home/​student/​yocto/​poky/​meta/​recipes-core/​base-files/​base-files_3.0.14.bb''​. Alte layer-e de rețete pot modifica rețeta de mai sus, folosind fișiere ''​.bbappend''​. Spre exemplu, urmăriți fișierul ''/​home/​student/​yocto/​poky/​meta-raspberry/​recipes-core/​base-files/​base-files_3.0.14.bbappend''​.+===== Resurse =====
  
-<note tip> Sursele curente pentru layer-ul meta-rapsberrypi nu mai conțin directorul ''​base-files''​ în recipes. Va fi necesar să îl cream noi. Va trebui sa va creati voi ierarhia de directoare asociata. </note> +  * [[https://​github.com/​cs-pub-ro/SI-rpi-debian-scripts|Cod sursă scripturi compilare bootloader ​kernel ​generare rootfs]]
-<note tip> Daca intalniti o eroare de tipul ''​Temporary repodata directory already exists!'',​ puteti sterge cu incredere directorul ''​.repodata/''​ afisat in mesajul de eroare. </note>+
  
-Pentru a adăuga un fișier ''​hostname''​ în imagine trebuie să:  
-  * aveți un fișier ''​hostname''​ în locația unde sunt toate fișierele de inclus 
-  * modificați fișierul ''​.bbappend''​ (adăugirea la rețetă), adăugând în variabila ''​SRC_URI''​ noul fișier (cu += ) și implementând o funcție cu numele ''​do_install_append()'',​ care se va executa în cadrul rețetei după ''​do_install''​ 
-  * Rulați apoi ''​bitbake rpi-basic-image''​ 
-  * Verificați rezultatul rulând noua imagine cu Qemu! 
- 
-===== Resurse ===== 
  
-  * {{.:​si:​laboratoare:​readme.txt | Setup yocto}} ​ 
-  * {{.:​yocto:​sol:​yocto_sol.zip| Soluție laborator}} (disponibilă începând cu 19.11.2019) 
-  * [[https://​drive.google.com/​file/​d/​0B0lgiPZNMMyvMWEtZS1zME9lQjQ| Imagine kernel]] 
-  * [[http://​www.yoctoproject.org/​docs/​1.8/​ref-manual/​ref-manual.html | Reference Manual Yocto]] 
-  * [[https://​www.yoctoproject.org/​docs/​2.0/​mega-manual/​mega-manual.html| Manual Yocto]] 
-  * [[https://​www.yoctoproject.org/​docs/​1.6/​bitbake-user-manual/​bitbake-user-manual.html| Manual BitBake]] 
si/laboratoare/06.1605430799.txt.gz · Last modified: 2020/11/15 10:59 by dragos_florin.costea
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0