Differences

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

Link to this comparison view

si:laboratoare:07 [2022/12/05 00:15]
jan.vaduva [Exerciții]
si:laboratoare:07 [2024/11/19 19:03] (current)
florin.stancu [Exerciții]
Line 1: Line 1:
-====== Laboratorul 07. Yocto images and SDK ======+====== Laboratorul 07. Root filesystem și servicii de sistem ​======
  
-Asa cum am mentionat si laboratorul trecut Yocto este o colecție de utilitare, metadate și șabloane ce permit construirea/​compilarea distribuțiilor de Linux pentru platforme embedded ce oferă posibilitatea de a crea distribuții personalizate pornind de la 0 sau de la imagini scheletice. In cadrul acestui laborator vom continua si vom adauga context si exemple informatiei dobandite pana acum. Printre conceptele pe care le vom acoperi putem include: notiunea de imagine cum se poate lucra cu ea, care este rolul acestei notiuni si cum putem lucra cu ea si de asemenea vom adauga aici si notiundea de SDK si modul in care putem genera cod sursa pentru o platforma hardware (**MACHINE**,​ asa cum este ea definita in domeniul Yocto Project). ​+===== Root file system =====
  
-===== Imagine =====+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 subdirectoare. Aceste subdirectoare sunt organizate în funcție de fișierele pe care le conțin:
  
-Când am rulat „**bitbake core-image-base**” laboratorul trecut, build engine-ul Bitbake se uită la variabila ​**PROVIDES** a fiecărei rețete ​pentru a afla rețeta pentru o anumită aplicatie tinta. Valoarea implicită a **PROVIDES** este **PN**.+  ​''/​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 general, reprezintă puncte în care se pot monta alte sisteme de fișiere ​pentru a stoca log-uri, biblioteci și alte aplicații și programe folosite de către utilizatori.
  
-  * PN --Numele rețetei +<note
-  * PV --> Versiunea rețetei +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. 
-  * PR --Revizuirea rețetei+</note>
  
-Uneorio țintă poate avea mai mulți furnizori**PREFERRED_PROVIDER** determină cărei rețete ar trebui să i se acorde preferință atunci când mai multe rețete oferă același articol.+Standardul Unix recomandă ca //​rootfs//​-ul să aibe dimensiuni relativ micideoarece orice problemă sau corupere a acestuia ​poate împiedica inițializarea corectă a sistemuluiDacă, totuși, rootfs-ul devine corupt, există modalităț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.
  
-De exemplu. **virtual/​kernel****u-boot** va fi furnizat ​de mai multe rețete +Î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).
-  * PREFERRED_PROVIDER_virtual/​kernel ​= "linux-imx" +
-  * PREFERRED_PROVIDER_u-boot = „uboot-imx”+
  
-<​note>​Acest lucru ar trebui să fie scris în **local.conf** sau **machine.conf**</​note>​+===== Pseudo Filesystems =====
  
-Când sunt disponibile ​mai multe versiuni ale unei rețetevariabila **PREFERRED_VERSION** determină rețetei care trebuie ​să primească preferință. Dacă nu precizăm versiunea, bitbake va prelua cea mai mare versiune din punct de vedere lexico-numericDe exemplu.  +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ă existe, ele fiind folosite pentru a interfața cu kernelul (mai ales în sisteme incorporate,​unde programele trebuie să comunice cu hardware-ul).
-  * PREFERRED_VERSION_linux-imx = "​3.10.17-1.0.0"​ +
-  * PREFERRED_VERSION_u-boot-imx = „2013-04”+
  
-Ceea ce este diferita la o reteta de imagine fata de o reteta pentru un aplicatie este definit in modul in care task-urile sunt definite intern. ​+==== Sistemul virtual proc ====
  
-==== task ====+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.
  
-**Task-ul** este unitatea cea mai mica de execuție pe care build engine-ul Bitbake o poate executa. Task-urile sunt definite intern in fisiere generice numite **clase**. Mai jos puteti gasi o definitie pentru principalele task-uri disponibile:​+Pentru a monta **proc** se poate folosi comanda: <​code>​ mount -t proc nodev /proc </​code>​
  
-{{:si:laboratoare:aosa1.jpg?600|}}+Printre conținutul aflat în **proc** putem găsi: 
 +  * ///​proc/​interrupts,​ /​proc/​iomem,​ /​proc/​cpuinfo//​ce conțin informații specifice de device 
 +  * ///​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]].
  
-  * do_build +==== Sistemul virtual sys ====
-Sarcina implicită pentru toate rețetele. Această sarcină depinde de toate celelalte sarcini normale necesare pentru a construi o rețetă. +
-  * do_configure +
-Configurează sursa activând și dezactivând orice opțiuni de configurare și de timp de construcție pentru software-ul care este construit. Sarcina rulează cu directorul de lucru curent setat la **B**. Comportamentul implicit al acestei sarcini este de a rula oe_runmake clean dacă este găsit un makefile (Makefile, makefile sau GNUmakefile) și **CLEANBROKEN** nu este setat la „1”. Dacă nu este găsit un astfel de fișier sau variabila **CLEANBROKEN** este setată la „1”, sarcina do_configure nu face nimic. +
-  * do_compile +
-Compilează codul sursă. Această sarcină rulează cu directorul de lucru curent setat la **B**. Comportamentul implicit al acestei sarcini este de a rula funcția oe_runmake dacă este găsit un makefile (Makefile, makefile sau GNUmakefile). Dacă nu este găsit un astfel de fișier, sarcina do_compile nu face nimic. +
-  * do_deploy +
-Scrie fișiere de ieșire care urmează să fie implementate în **DEPLOY_DIR_IMAGE**. Sarcina rulează cu directorul de lucru curent setat la **B**. Rețetele care implementează această sarcină ar trebui să moștenească clasa de implementare și ar trebui să scrie rezultatul în **DEPLOYDIR**,​ care nu trebuie confundat cu **DEPLOY_DIR**. Clasa deploy setează do_deploy ca sarcină de stare partajată (sstate) care poate fi accelerată prin utilizarea sstate. Mecanismul sstate are grijă să copieze rezultatul de la **DEPLOYDIR** în **DEPLOY_DIR_IMAGE**. +
-  * do_fetch +
-Preia codul sursă. Această sarcină utilizează variabila **SRC_URI** și prefixul argumentului pentru a determina modulul de preluare corect. +
-  * do_rootfs +
-Creează sistemul de fișiere rădăcină (structură de fișiere și directoare) pentru o imagine. Consultați secțiunea [[https://​docs.yoctoproject.org/​overview-manual/​concepts.html#​image-generation|Generarea imaginilor]] din manualul de prezentare și concepte a proiectului Yocto pentru mai multe informații despre cum este creat sistemul de fișiere rădăcină. +
-  * do_image +
-Începe procesul de generare a imaginii. Sarcina do_image rulează după ce sistemul a rulat sarcina do_rootfs în timpul căreia pachetele sunt identificate pentru instalare în imagine și este creat sistemul de fișiere rădăcină,​ complet cu post-procesare. Sarcina do_image efectuează preprocesarea imaginii prin **IMAGE_PREPROCESS_COMMAND** și generează în mod dinamic sarcini de suport do_image_* după cum este necesar. +
-  * do_install +
-Copiază fișierele care urmează să fie împachetate în zona de stocare **D**. Această sarcină rulează cu directorul de lucru curent setat la **B**, care este directorul de compilare. Sarcina do_install, precum și alte sarcini care depind direct sau indirect de fișierele instalate (de exemplu, do_package, do_package_write_* și do_rootfs), rulează sub [[https://​docs.yoctoproject.org/​overview-manual/​concepts.html#​fakeroot-and-pseudo|fakeroot]]. +
-  * do_package +
-Analizează conținutul zonei de stocare **D** și împarte conținutul în subseturi pe baza pachetelor și fișierelor disponibile. Această sarcină folosește variabilele **PACKAGES** si **FILES**. +
-  * do_patch +
-Localizează fișierele cu extensia *.patch și le aplică codului sursă. După preluarea și despachetarea fișierelor sursă, sistemul de compilare folosește instrucțiunile **SRC_URI** ale rețetei pentru a localiza și aplica fișierele de patch la codul sursă. +
-  * do_populate_sdk +
-Creează structura de fișiere și directoare pentru un SDK instalabil. Consultați secțiunea [[https://​docs.yoctoproject.org/​overview-manual/​concepts.html#​sdk-generation|Generare SDK]] din manualul de prezentare generală și concepte a proiectului Yocto pentru mai multe informații. +
-  * do_populate_sysroot +
-Copilează un subset de fișiere instalate de sarcina do_install în sysroot-ul corespunzător. Pentru informații despre cum să accesați aceste fișiere din alte rețete, consultați variabilele **STAGING_DIR***. Directoarele care de obicei nu ar fi necesare pentru alte rețete în momentul construirii (de exemplu, /etc) nu sunt copiate implicit. Pentru informații despre directoarele copiate implicit, consultați variabilele **SYSROOT_DIRS***. Puteți modifica aceste variabile în interiorul rețetei dvs. dacă trebuie să faceți directoare suplimentare (sau mai puține) disponibile pentru alte rețete în timpul construirii. Sarcina do_populate_sysroot este o sarcină de stare partajată (sstate), ceea ce înseamnă că sarcina poate fi accelerată prin utilizarea stării. Realizați, de asemenea, că, dacă sarcina este re-execută,​ orice ieșire anterioară este eliminată (adică „curățată”). +
-  * do_prepare_recipe_sysroot +
-Instalează fișierele în sysroots-uri individuale specifice rețetei (adică recipe-sysroot și recipe-sysroot-native sub **WORKDIR** pe baza dependențelor specificate de **DEPENDS**). Consultați clasa „în scenă” pentru mai multe informații. +
-  * do_rm_work +
-Elimină fișierele de lucru după ce sistemul de build a terminat cu ele. Puteți afla mai multe uitându-vă la secțiunea „rm_work.bbclass”. +
-  * do_unpack +
-Despachetează codul sursă într-un director de lucru indicat de **WORKDIR**. Variabila **S** joacă rol de sursa pentru fișierele dezambalate. Pentru mai multe informații despre modul în care fișierele sursă sunt despachetate,​ consultați secțiunea [[https://​docs.yoctoproject.org/​overview-manual/​concepts.html#​source-fetching|Preluare surse]] din manualul de prezentare generală și concepte a proiectului Yocto și, de asemenea, consultați descrierile variabilelor **WORKDIR** și **S**.+
  
-<​note>​Pentru mai multe informații despre crearea imaginilorconsultațsecțiunea [[https://​docs.yoctoproject.org/​overview-manual/​concepts.html#​image-generation|Generarea imaginilor]] ​din manualul de prezentare ​și concepte a proiectului Yocto.</​note>​+Permite reprezentarea în userspace a viziunii pe care o are kernel-ul asupra magistralelordispozitivelor șdriverelor din sistem. Este util pentru diverse aplicații din userspace care trebuie să enumere ​și să interogheze hardware-ul disponibil, de exemplu **udev** sau **mdev**:
  
-==== clasa ==== +<​code>​ls ​/sys/ 
-Clasele in Yocto Project (**.bbclass**) reprezinta o definitie generica a task-urilor ce se poate aplica unei retete, notiune ce permite extinderea sau modificarea. Sunt folosite pentru a abstractiza funcționalitatea comună și a le partaja între mai multe fișiere cu rețete (.bb), pentru a gestiona unele probleme generale. De exemplu, gestionarea CMake în rețete se face în //cmake.bbclass/​/, astfel încât atunci când adăugați inherit cmake, rețeta dvs. va gestiona specificul CMake.+block bus class dev devices firmware fs kernel module power 
 +</code>
  
-<​note>​Mai multe notiuni despre fiecare clasa in parte se pot afla accesand link-ul: [[https://​docs.yoctoproject.org/​ref-manual/​classes.html|Clase in Yocto Project]] din manualul de prezentare și concepte a proiectului Yocto.</​note>​+===== Utilitare folosite pentru crearea ​inspecția unui RootFS =====
  
-===== masina ===== +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.
-În general, există trei tipuri de informatii disponibile intr-un layer. Le puteți vedea expuse in imaginea ​alaturara ce descrie fluxul ​de lucru pentru sistemul ​de build numit Bitbake.+
  
-{{:si:​laboratoare:​yocto-environment.png?600|}}+Imaginea recomandată pentru RaspberryPi,​ Raspbian, conține două partițiio 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:
  
-  * **Metadate (.bb + Patch-uri)**:​ Straturi de software care conțin fișiere de rețete furnizate de utilizator, patch-uri și fișiere anexate. Un bun exemplu de layer software ar putea fi **meta-qt5**. Acest layer este pentru versiunea 5.0 a popularului IDE utilizat pentru dezvoltarea ​de aplicații multiplatformă Qt pentru desktop, dispozitive încorporate ​și mobil. +  * Stabilirea dimensiunii imaginii ​și inițializarea acesteia cu zero-uri 
-  * **Configurație BSP mașinii**: Board Support Package (BSP)  care oferă configurații specifice mașinii. Acest tip de informații este specific unei anumite arhitecturi țintă. Un bun exemplu de layer BSP din distribuția de referință (Poky) este layer-ul **meta-yocto-bsp**. +  ​Crearea tabelei ​de partiții și a celor două partiții necesare 
-  * **Configurare politici specifice distributiei**:​ Layere de distribuție care oferă politici de nivel superior sau generale pentru imaginile sau SDK-urile care sunt construite pentru o anumită distribuție. De exempluîn layer-ul de referinta al distributiei Poky numit **meta-poky** se afla serie de variante de astfel de politici specifice. În layeer-ul de distribuție se află un director **conf/​distro** care conține fișiere ​de configurare a distribuției (de exemplu, **poky.conf** care conține multe configurații de politică pentru distribuția Poky.+  * Formatarea partițiilor cu formatul corespunzător 
 +  * Pentru popularea rootfs-ului, putem fie să montam partiția și să copiem manual directoarele și fișierelefie putem să copiem ​partiție întreagă de pe o altă imagine
  
-In general informatia specifica de masina se afla in layer specifice de BSP, acolo pe langa configuratia particulara pentru masina disponibila de obicei in fisierul de configuratie [[https://​git.yoctoproject.org/​poky/​tree/​meta/​conf/​machine/​qemuarm.conf|conf/​machine/​machine.conf]] ​ce descrie in general versiune de kernel si bootloader specifica target-ului ales se mai afla retete cu configuratii particulare pentru a pune in functiune suportul de baza cum ar fi drivere video, grafice, audio etc.+Pentru fiecare dintre acești pași există utilitare ​ce ne ajută să realizăm operațiile necesare.
  
-{{:​si:​laboratoare:​poky-machine.png?​600|}}+==== dd ====
  
-Un exemplu pentru un fisier cu o definitie a masinii este qemuarm.conf ​folosit ​si in cadrul laboratoruluiAici se mai pot observa configuratii pentru preferintele ​de compilator aleseconfigurarea interfetei seriale, inclusiv argumente necesare ​pentru ​pornirea emulatorului de Qemu.+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:
  
-===== distributie ===== +  * ''​if''​ - fișierul de intrare; dacă nu se specifică acest parametru, se va citi de la //standard input// 
-In cazul distributiei ​de referinta definita in [[https://git.yoctoproject.org/poky/tree/meta-poky/conf/distro/poky.conf|poky.conf]] pe care o sa se bazeze majoritatea activitatii noastre se poate observa ca pe langa informatii despre numele si versiunea distributiei sau maintainer-ul acesteia se mai pot identifica o serie de caracteristici,​ **FEATURES** asa cum sunt ele numite.+  * ''​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
  
-{{:si:​laboratoare:​poky-distro.png?​600|}}+<note tip> 
 +Un exemplu de utilizare a lui ''​dd''​ pentru a inițializa cu zerouri un fișier de o dimensiune exactă:
  
-Acest capitol oferă o referință pentru caracteristicile echipamentelor livrate și ale distribuției pe care le puteți include ca parte a imaginii dvs., o referință la caracteristicile imaginii pe care le puteți selecta și o referință la completarea caracteristicilor. +<code shell> 
-Caracteristicile oferă un mecanism pentru a stabili ce pachete ar trebui incluse în imaginile generate. Distribuțiile pot selecta caracteristicile pe care doresc să le suporte prin variabila **DISTRO_FEATURES**,​ care este setată sau atașată în fișierul de configurare al unei distribuții,​ cum ar fi **poky.conf**,​ **poky-tiny.conf**,​ **poky-lsb.conf** și așa mai departe. Caracteristicile mașinii sunt setate în variabila **MACHINE_FEATURES**,​ care este setată în fișierul de configurare a mașinii și specifică caracteristicile hardware pentru o anumită mașină.+$ dd if=/​dev/​zero of=<​file>​ bs=1M count=2048 
 +</​code>​
  
-Aceste două variabile se combină pentru a determina ce module kernel, utilitare șalte pachete trebuie incluseO anumită distribuție poate suporta un subset selectat ​de caracteristiciastfel încât unele caracteristici ale mașinii ar putea să nu fie incluse dacă distribuția în sine nu le acceptă.+Observațvalorile lui ''​count''​ si ''​bs''​Se vor copia în total 2048 de blocuri de câte 1MB fiecarerezultând o dimensiune de 2GB. Fișierul de intrare ''/​dev/​zero''​ este un fișier special din care se pot citi oricâte caractere ASCII NUL (0x00). 
 +</​note>​
  
-Pentru mai multe detalii despre lista de caracteristici suportate in fiecare categorie: **DISTRO_FEATURES**,​ **MACHINE_FEATURES** sau **IMAGE_FEATURES** puteti consulta link-ul [[https://​docs.yoctoproject.org/​ref-manual/​features.html|Caracteristicilor Yocto Project]] atasate.+==== parted ====
  
-===== SDK ===== +Pentru manipularea tabelei ​de partiții ​(crearea sau ștergerea partițiilorse poate folosi utilitarul //parted//Acesta recunoaște și poate manipula multiple formate de partițiiDOS / SUN / GNU / GPT etc. Utilitarul primește ca parametru device-ul a cărui tabelă de partiții dorim să o modificămUn exemplu de apel este:
-De asemenea in imaginea ​de mai sus cu **poky.conf** am putut observa notiuni despre Software Development Kit (SDK), acest SDK similar imaginii este specific arhitecturii harware si include tot suportul necesar dezvoltarii de aplicatii pentru target-ul ales. +
-In general SDK-ul contine următoarele:​ +
-  * **Cross-Development Toolchain**:​ acest lanț de instrumente conține un compilator, un debugger ​și diverse instrumente asociate. +
-  * **Biblioteci,​ anteturi ​și simboluri**bibliotecile,​ anteturile ​și simbolurile sunt specifice imaginii (adică se potrivesc cu imaginea cu care a fost construit SDK-ul). +
-  * **Script de configurare ​mediului**: Acest fișier *.sh, odată preluat, configurează mediul ​de dezvoltare prin definirea variabilelor și pregătirea pentru utilizarea SDK.+
  
-Puteți utiliza un SDK pentru a dezvolta și testa în mod independent codul care este destinat să ruleze pe o mașină țintă. SDK-urile sunt complet autonome. Binarele sunt legate de propria lor copie a librariei standard C (libc), ceea ce duce la nicio dependență de sistemul țintă. Pentru a realiza acest lucru, pointer-ul către loader-ul dinamic este configurat în momentul instalării,​ deoarece acea cale nu poate fi modificată dinamic. Acesta este motivul pentru un wrapper în jurul arhivelor **populate_sdk** și **populate_sdk_ext**.+<code shell> 
 +$ parted /​dev/<​device>​ 
 +</​code>​
  
-O altă caracteristică a SDK-urilor ​este că este produs ​un singur set de binare ​pentru ​toolchain-ul folosit pentru cross-compilare indiferent de arhitectura dată. Această caracteristică profită de faptul că hardware-ul țintă poate fi transmis către gcc ca un set de opțiuni de compilareAceste opțiuni ​sunt setate de scriptul de mediu și sunt conținute în variabile precum **CC** și **LD**. Acest lucru reduce spațiul necesar pentru unelte. Înțelegeți,​ totuși, că fiecare țintă are încă nevoie ​de propriul sistem ​**sysroot**, deoarece acele binare sunt specifice ​țintei.+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 disponibileOpțiuni ​utile pentru crearea ​și ștergerea de partiții sunt: 
 +  
 +  ​''​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).
  
-Mediul de dezvoltare SDK constă din următoarele: +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''​).
-  * SDK-ul autonom, care este un lanț de instrumente încrucișat specific arhitecturii ​și sysroots (țintă șnativ) care se potrivesc, toate construite de engine-ul Bitbake (de exemplu, SDK-ul)Lanțul de instrumente ​și sysroots se bazează pe o configurație ​de metadate și extensii, care vă permit ​să dezvoltați încrucișat pe mașina gazdă pentru hardware-ul țintă. În plus, SDK-ul extensibil conține funcționalitatea **devtool** pentru generare automata ​de retete. +
-  * Quick EMUlator ​(QEMU), care vă permite să simulați hardware-ul țintăQEMU nu face parte literalmente din SDKTrebuie să construiți și să includeți acest emulator separat. Cu toate acesteaQEMU joacă un rol important în procesul de dezvoltare care se învârte în jurul utilizării SDK-ului.+
  
-SDK-ul este instalat pe orice mașină și poate fi folosit pentru ​dezvolta aplicații, imagini chiar si functionalitati ale kernelului ​de Linux sau ale bootloader-uluiUn SDK poate fi folosit chiar și de un inginer QA sau un inginer responsabil cu release-urileConceptul fundamental este că mașina care are instalat SDK-ul nu trebuie să fie asociată cu mașina care are instalat proiectul Yocto. Un dezvoltator poate compila și testa în mod independent un obiect pe mașina sa și apoi, când obiectul este gata pentru integrare într-o imagine, îl poate pune pur șsimplu ​la dispoziția mașinii care are Proiectul Yocto. Odată ce obiectul este disponibilimaginea poate fi reconstruită folosind Proiectul Yocto pentru ​produce imaginea modificată.+<​note>​ 
 +  * Dimensiunea standard ​unui sector ​de disc este ''​512 bytes''​Aceasta ​poate fi schimbată folosind opțiunea ''​-b''​. 
 +  * 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>​ 
 +(parted) mklabel msdos 
 +(parted) mkpart primary fat32 1MiB 120MiB 
 +(parted) mkpart primary ext4 120MiB 100% 
 +(parted) print 
 +(parted) quit 
 +</​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-repartizat tot spațiul rămas. 
 +</​note>​
  
-===== Exerciții ​===== +==== losetup ​====
-  * Adaugati un utilizator nou in sistem. ​+
  
-Pentru a modifica numele pe care îl publică un RaspberryPi este suficient să modificăm ''/​etc/​hostname''​. Pentru aceasta am putea modifica ​fișierul din imaginedar dezavantajul ​este că ar trebui ​să facem această modificare la fiecare recompilareAm prefera să obținem direct o imagine cu numele nou, iar ca să obținem ​acest lucru trebuie să modificăm rețetele Bitbake care stau la baza pachetelor instalate în imagine. +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 blocDin 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]//.
-Fisierul ​''​hostname'' ​ar trebui sa fie plasat aici: ''<​poky_path>/​meta/​recipes-core/​base-files/​''​. Vedeți și [[https://git.yoctoproject.org/poky/tree/meta/recipes-core/base-files|codul sursă al rețetei originale aici]].+
  
-Pentru a adăuga un fișier ''​hostname''​ în imagine trebuie să:  +**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)!
-  ​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''​ +
-  * de asemenea, tot în fișierul ''​.bbappend''​ va trebui să adăugați calea către directorul ​cu fișierul nou:  +
-    ​''​FILESEXTRAPATHS:​prepend := "​${THISDIR}/​${PN}:"''​  +
-  ​Rulați apoi ''​bitbake core-image-base''​ +
-  ​Verificați rezultatul rulând noua imagine cu Qemu!+
  
-<note>Puteti de asemenea consulta exemplele disponibile in layer-ul [[https://git.yoctoproject.org/poky/tree/meta-skeleton/recipes-skeleton|meta-skeleton]] precum reteta **useradd-example.bb**</note>+Exemplu folosire: ​<code bash> 
 +# conectăm fișierul la un dispozitiv loop 
 +losetup ​/dev/loop0 ./path/to/your-image.bin 
 +# 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>
  
-  ​Creati un serviciu [[https://​www.linux.com/​training-tutorials/understanding-and-using-systemd/|SystemD]] care porneste binarulul **myhelloworld** generat cu ajutorul retetei **HelloWorld.bb** din laboratorul trecut. Este recomandat sa actualizati reteta **HelloWorld.bb** deja disponibila. ​+**Important / NU uitați:** la final, trebuie să deconectăm dispozitivul pentru a sincroniza cele scrise înapoi în fișier: ''​losetup ​-/dev/loop<​N>''​!
  
-<​note>​ Nu uitati sa adaugati suportul in imaginea de root filesystem folosita si sa rulați ''​bitbake core-image-base''​. Verificați ca aveti rezultatul dorit rulând noua imagine cu Qemu!</​note>​+==== mkfs ====
  
-  * Dupa ce ati adaugat tot suportul de mai sus, generati ​un SDK pentru ​imaginea buildata anterior si modificati aplicatia **myhelloworld.c** astfel incat sa raporteze informatii despre sistemul ​pe care ruleaza. Apoi buildati noua aplicatie ​cu SDK obtinut anterior si incarcati noul binar sub in alt nume in QemuObservati rezultatul!+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șiere. Utilitarul 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''​.
  
-<hidden+Spre exemplu, comanda ​<code shell
-# cat base-files/base-files_%.bbappend +$ mkfs -t ext4 -L MyRootFS /dev/fd0 
-<​code>​ +</code>
-FILESEXTRAPATHS_prepend := "​${THISDIR}/​${PN}:"​+
  
-SRC_URI += "file://hostname \ +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 suportat. Pentru a le vedea pe cele disponibile,​ deschideți un terminal, scrieți ''​mkfs.''​ (punct la coadă!) și apasați tab.
-            "+
  
-do_install_append () { +<​note>​ 
-    ​install ​-m 0644 ${WORKDIR}/hostname ${D}${sysconfdir} +Dacă etichetați sistemele de fișiere, le puteți accesa ulterior după căi speciale din ''/​dev/​disk/​by-label/''​! ​ 
-} +</note>
-</code>+
  
-# Enable systemd +==== mount ====
-<​code>​ +
-DISTRO_FEATURES_append +" systemd " +
-VIRTUAL-RUNTIME_init_manager ​"​systemd"​ +
-DISTRO_FEATURES_BACKFILL_CONSIDERED +"​sysvinit"​ +
-VIRTUAL-RUNTIME_initscripts ​"​systemd-compat-units"​ +
-</​code>​+
  
-# cat files/hello.service +Î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.
-<​code>​ +
-[Unit] +
-Description=GNU Hello World startup script+
  
-[Service] +Formatul general al comenzii este ''​mount -t <​type>​ <​device>​ <mount path>'',​ unde //<​type>​// este același ca la //mkfs//. De cele mai multe ori, argumentul ''​-t <​type>''​ poate fi omis, acesta fiind autodetectat de către kernel.
-ExecStart=/usr/bin/myhelloworld+
  
-[Install+Ș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). 
-WantedBy=multi-user.target+ 
 +===== Exerciții ===== 
 + 
 +<​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>​ 
 + 
 +**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>​ 
 +  * 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 ''/​mnt/​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>​ </​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''​!
  
-# cat HelloWorld.bb +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/​06|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.
-<​code>​ +
-DESCRIPTION = "Hello World"​ +
-LICENSE = "​CLOSED"​+
  
-// liniile adaugate ​pentru ​activarea serviciului systemd in reteta originala sunt marcate cu bold+<note important>​ 
-**inherit systemd+  * **Atenție**:​ Va trebui, mai î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>​
  
-SYSTEMD_AUTO_ENABLE = "​enable"​ +3Reporniți Raspberry PI-ulVom încerca să bootăm kernelul și rootfs-ul din prompt-ul ''​u-boot''​:
-SYSTEMD_SERVICE_\${PN} = "hello.service"​** +
-  +
-PR = "​r0"​ +
-SRC_URI = "​file://​myhelloworld.c \ +
-           file://​README.txt"​+
  
-**SRC_URI_append = " file://hello.service " +  ​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>​ 
-FILES_\${PN} += "​\${systemd_unitdir}/system/​hello.service"​** +# load bootargs from device tree (contains BL2-modified cmdline.txt data) 
-  +fdt addr ${fdt_addr&& fdt get value bootargs ​/chosen bootargs 
-TARGET_CC_ARCH += "​${LDFLAGS}" ​ +# set decompression zone in RAM at 400MB, 64MB in size 
-  +setenv kernel_comp_addr_r 0x19000000 
-do_compile() { +setenv kernel_comp_size 0x04000000 
-        ${CC${CFLAGS} ${LDFLAGS} ${WORKDIR}/​myhelloworld.-o ${WORKDIR}/​myhelloworld +# load kernel from file 
-} +fatload mmc 0:1 ${kernel_addr_rvmlinuz-6.1.61-rpi+ 
-  +# boot without initrd, for now 
-do_install() { +booti ${kernel_addr_r} - ${fdt_addr}
-        install -d ${D}${bindir}  +
-        **install ​-d \${D}/​\${systemd_unitdir}/​system +
-        install -m 0644 \${WORKDIR}/​hello.service \${D}/​\${systemd_unitdir}/​system** +
-        install -m 0755 -t ${D}${bindir} ${WORKDIR}/​myhelloworld +
-}+
 </​code>​ </​code>​
 +  * 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''​).
  
-Pentru a rebuilda imaginea cu noul user si serviciul ce porneste la initializarea sistemuluiApoi putem genera SDK-ul si trebuie sa il instalam pentru a-l putea folosiNu le-am dat studentilor prea multe informatii tocmai pentru ca ma gandeam ca asta pot sa caute singurei si sa incerce sa descoperedaca nu reusesc puteti sa ii ajutati eventual adaugam informatiile in laborator+4Dorim să instalăm pachete în imagineDeoarece 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)!
  
-<​code>​ +  * Folosind ''​losetup'',​ ''​partprobe''​ și ''​mount'',​ montați partiția a doua (e.g., în ''/​mnt''​). 
-bitbake core-image-base +  * Copiați utilitarul ''​qemu-<​arch>​-static''​ pentru arhitectura emulată (AArch64) în rootfs (în ''/​mnt/​usr/​bin''​): ​<​code>​ 
-runqemu qemuarm slirp nographic +vedem unde e executabilul:​ 
-# bitbake core-image-base -c populate_sdk +which qemu-aarch64-static 
-# mkdir ../sdk-install +/​usr/​bin/​qemu-aarch64-static 
-# ./tmp/deploy/sdk/poky-glibc-x86_64-core-image-base-cortexa15t2hf-neon-qemuarm-toolchain-4.0.5.sh -d ../sdk-install +cp -/usr/bin/qemu-aarch64-static /mnt/usr/bin 
-# source ​/opt/poky/4.0.5/environment-setup-cortexa15t2hf-neon-poky-linux-gnueabi+chmod +x /mnt/usr/bin/qemu-aarch64-static
 </​code>​ </​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)!
 +
 +===== Resurse =====
  
-Apoi se scrie codul care face cat la /etc/issue sau apeleaza uname -a si se buildeaza cu SDK-ul obtinut anterior.+  * [[https://github.com/​cs-pub-ro/​SI-rpi-debian-scripts|Cod sursă scripturi compilare bootloader / kernel / generare rootfs]]
  
-</​hidden>​ 
  
si/laboratoare/07.1670192115.txt.gz · Last modified: 2022/12/05 00:15 by jan.vaduva
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