Differences

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

Link to this comparison view

si:laboratoare:06 [2022/11/13 23:06]
florin.stancu
si:laboratoare:06 [2024/11/11 12:43] (current)
florin.stancu [Exerciții]
Line 1: Line 1:
-====== Laboratorul 06. Yocto ======+====== Laboratorul 06. The embedded boot process ​======
  
-[[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.+Atunci când un microprocesor primește semnalul de reset (prin alimentare ori transmiterea unor comenzi ​întreruperi interne etc.), acesta începe să ruleze un program inițial numit bootloader. 
 +Sistemele moderne folosesc un proces de boot multi-stagiu,​ însă primul ​este mereu încărcat dintr-un ROM (Read Only Memory) care, de cele mai multe ori, este integrat în același chip.
  
-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: ​ARM, PPC, MIPS, x86 etc.+==== Procesul ​de boot standard ​ARM ====
  
-Pentru a-și ajuta utilizatorii,​ Yocto vine cu o serie de aplicații: un sistem de build numit ''​Bitbake'',​ o interfață grafică numită ''​Hob''​ (we don't do that here :D) cât și alte unelte de dezvoltare, și, cel mai important, [[https://​docs.yoctoproject.org/​ref-manual/​|o documentație stufoasă]].+Arhitectura ARMv8 propune următoarea structură:
  
-Sursele Yocto pot fi găsite atât la adresa oficială **[[http://​git.yoctoproject.org/​cgit/​cgit.cgi/​poky]]**,​ cât și [[https://​github.com/​yoctoproject/​poky|la un mirror pe GitHub]] (pentru cine preferă).+{{:si:laboratoare:​arm_booting_process.png?700}}
  
-Acum noi, la toate laboratoarele ​de Yocto ce urmează (cât și la temă), vom folosi [[https://​github.com/​cs-pub-ro/​SI-Lab-VM/​releases/​tag/​y2022-yocto|mașina virtuală de laborator]] cu toate utilitarele necesare instalate, precum și întreaga distribuție precompilată ​(de aici rezultă și dimensiunea mare, de ''​20GB'',​ a disk-ului virtual).+Se observă numărul mare de pași decât metoda naivă pe care sistemul trebuie să-i realizeze până să pornească kernelul sistemului ​de operare. 
 +Acest lucru se datorează punerii accentului pe securitatea soluțiilor incorporate ​(prin tehnologia ARM TrustZone, ​de care doar vom menționa scurt, pe Raspberry PI nefiind implementată în totalitate)însă necesitatea a 3 stagii diferite este dată de un motiv simplu: memoria disponibilă în diferitele momente ale procesului.
  
-===== Descriere componente ​unelte Yocto =====+Așadar, prima dată se începe prin rularea primului stagiu, ''​BL1'',​ stocat în memoria ROM. Acesta va încărca, de pe o memorie flash externă (de obicei, prin SPI: eMMC sau SD), următoarele stagii. Dintre acestea, ''​BL2''​ este, de obicei, un firmware foarte mic (//​10-100KB//​) ce este încărcat în memoria SRAM a SOC-ului (care, uneori, funcționează și pe post de cache) și care, mai departe, inițializează toate perifericele chip-ului (printre care, foare important este DRAM-ul -- folosit de următoarele stagii cu consum ridicat de RAM!).
  
-Pentru începutvom face o descriere componentelor ​și utilitarelor folosite în cadrul laboratoarelor ​de Yocto Linux+Stagiile ''​BL3x''​ devin opționaletotul depinzând dacă ''​BL2''​ conține funcționalitatea de a porni și Kernel-ul ​de Linux șeste suficient de configurabil pentru a putea acoperi o mare parte a cazurilor de utilizare ale sistemului (ceea ce este adevărat pentru RPI, însă deseori nu pentru celelalte SoC-uri) sau dezvoltatorul software dorește să beneficieze de funcționalități avansate de boot (aici, ''​BL31''​ poate oferi partiționare A/B cu toleranță la defecte, actualizări la distanță etc.) sau încărcarea unui sistem de operare securizat (Trusted OS, la pasul ''​BL32''​).
-Revenițasupra acestora oricând aveți nelămuriri despre sintaxă / variabile pe parcursul exercițiilor.+
  
-==== Bitbake ====+În final, ultimul pas al bootloaderului va fi să citească configurația (de pe o partiție de boot sau dintr-o altă memorie ROM re-programabilă) și componentele de rulare (kernel, initrd, device tree blob -- de cele mai multe ori, toate 3 fiind necesare) ale sistemului de operare, să încarce în RAM și apoi să paseze execuția CPU-ului către kernel.
  
-[[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ție. Aceste acțiuni se determină în funcție de: comenzile date de către utilizator, datele proiectului și starea curentă a 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'':​+==== Procesul ​de boot al Raspberry PI ====
  
-<code make HelloWorld.bb> +Deși procesul de boot diferă între //Raspberry PI// versiuni mai vechi sau egale cu **3** (ce folosește SoC-ul ''​BCM2837''​) și cele **după 4** (cu ''​BCM2711'',​ și, pe viitor, v5), stagiile se încadrează în arhitectura propusă de ARM.
-DESCRIPTION = "Hello World"​ +
-LICENSE = "​CLOSED"​+
  
-PR = "​r0"​ +Toate versiunile procesoarelor Broadcom folosite la RPI încep prin rularea stagiului ''​BL1''​ pe microcontrollerul de gestionare a GPU-ul integrat (da, pe bune!), care, mai departe, inițializează memoria cache, interfața SPI (pentru accesarea memoriei flash din eMMC card SD) și, folosind o bibliotecă incorporată de citire de pe partiții FAT32, scanează după existența firmware-ului pentru următorul stagiu, ''​BL2'',​ pe care îl va încărca în cache-ul L2 al procesorului (DRAM-ul încă nu a fost inițializat).
-SRC_URI = "file://​myhelloworld.c \ +
-           ​file://​README.txt"+
  
-TARGET_CC_ARCH += "​${LDFLAGS}"​  +Ordinea de scanare a perifericelor pentru continuarea procesului de boot (e.g., SD Card eMMC, extenal SPI, USB Mass Storage, LAN boot) diferă în funcție de starea unor GPIO-uri sau a unor regiștri OTP (One Time Programmable).
-            +
-do_compile() { +
-        ${CC} ${CFLAGS} ${LDFLAGS} ${WORKDIR}/​myhelloworld.c -o ${WORKDIR}/myhelloworld +
-}+
  
-do_install() +Așadar, un Raspberry PI are nevoie ca dispozitivul de pe care se efectuează bootarea să conțină o primă partiție FAT32 cu cel puțin firmware-urile de inițializare a platformei ​(''​bootcode.bin'',​ ''​start*.elf'',​ ''​config.txt''​ și altele câteva ce depind de modelul efectiv).
-        install -d ${D}${bindir}+
  
-        install ​-m 0755 -t ${D}${bindir} ${WORKDIR}/​myhelloworld +<note important>​ 
-} +Fiecare microprocesor are propriile convenții de stabilire a adreselor de încărcare a stagiului secundar. 
-</code>+Cei de la Broadcom au ales să folosească partiții FAT32, însă majoritatea producătorilor de SoC-ul incorporate cu ARM (e.g., Allwinner, NXP) preferă să încarce o imagine specială de la un anumit offset al disk-ului (e.g., la adresa ''​32KB''​ de la începutul cardului SD). De aici vine și recomandarea de a crea prima partiție abia începând cu offset-ul de ''​1MB''​. 
 +</note>
  
-Asemănător cu un Makefile, putem folosi variabile de sistem pentru a specifica flag-uriexecutabile,​ 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 organizatmai ușor de urmărit și de depanat.+Pentru [[https://​www.raspberrypi.com/​documentation/​computers/​raspberry-pi.html#​boot-sequence|Raspberry PI 3]]se va încărca fișierul ''​bootcode.bin''​ ca stagiu secundar, care, după inițializarea RAM-ului, va citi și încărca următorul stagiu (care este, de obicei, sistemul de operare propriu-zis,​ însă se poate interpune un alt bootloader -- ''​BL31'',​ e.g., [[https://​www.denx.de/​project/​u-boot/​|U-Boot]]).
  
-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ției. Se 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.+La versiunile de Raspberry PI ''​>=4'',​ ''​BL2'' ​poate fi încărcat doar dintr-un EEPROM prin interfață SPI (și NU de pe SD / eMMC-ul extern -- însă există procedură de recovery în caz că se strică ceva), fapt ce ușurează aplicațiile care făceau network boot. De asemenea, firmware-ul este open-source (ceea ce nu era adevărat până acum).
  
-A se observa că este posibilă definirea de funcții în alte limbaje integrate ​(SHell sau chiar Pythonce se vor executa într-un anumit pas al procesului de build (vedeți [[https://docs.yoctoproject.org/​dev-manual/​common-tasks.html#​overview|diagrama din documentația oficială]] pentru o idee).+Mai departe, //Secondary Program Loader//-ul va încărca firmware-uri adiționale pentru GPU (pentru a putea afișa text prin HDMI), va analiza conținutul fișierului ''​config.txt''​ șva pune în aplicare procedurile configurate (încărcarea în memorie a fișierelor de kernel ​device tree initramfs).
  
-==== Fișiere speciale și variabile de sistem ​====+==== Componentele pentru boot ale Linux ====
  
-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șierefiecare exprimând un set diferit de metadate (dependențe,​ patch-uri, instrucțiuni) pentru o anumită componentă. Categoriile importante (în funcție de extensie):+După cum a fost menționat mai sus, pentru a porni un sistem de operare pe bază de Linux se folosesc, ​de cele mai multe ori3 componente:
  
-  * ''​.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ă +  ​- **Imaginea Kernel-ului*(''​kernel*.img''​), ce conține codul executabil al nucleului Linux; 
-  * ''​.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 către rețete +  - **Device Tree Blob-ul** (''​*.dtb''​):​ conține descrierea și configurația tuturor componentelor specifice platformei hardware (i.e., pentru un anumit model + versiune a unei plăci de bază), însă se pot codifica ​și anumite setări ​și meta-informații pentru software (e.g., kernel command line, partiția rădăcină etc.); 
-  * ''​.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ă versiunearhitectură etc. +  ​**RamDisk inițial** (''​initrd*.img''​)opțional, poate conține o imagine a unui sistem ​de fișiere ​minimalist (max. câțiva zeci de MB) cu module ​și scripturi necesare pentru a monta sistemul ​de fișiere ​rădăcină (e.g.dacă se dorește montarea unui sistem la distanță, trebuie mai întâi să se conecteze la rețea și să primească IP prin DHCP).
-  * ''​.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/​build,​ avem la dispoziție și o serie de variabile de sistem:+Bootloaderul (ori ''​BL2''​-ul integrat, ori ''​BL31''​ -- dacă a fost inclus) va încărca aceste fișiere ​în DRAM-ul sistemului și va completa anumiți regiștri (cu pointerii ​la locația de încărcare a tuturor componentelor necesare) ​și va executa ​instrucțiune ​de //branch// pentru a lansa kernelul în execuție, toate în condordanță cu [[https://​www.kernel.org/​doc/​html//​v5.8/​arm64/​booting.html|protocolul definit de kernel pentru arhitectura dată]].
  
-  * ''​BBFILES'':​ variabila ce spune sistemului ''​bitbake''​ care sunt rețetele disponibile +Obiectivul final al componentelor de boot Linux va fi să caute și să monteze sistemul de fișiere rădăcină (**roofs**-ul) ce conține toată configurația și programele din //user-space//, ​de unde se va lansa procesul ​''​init''​ care va continua prin pornirea serviciilor predefinite (care pot, la rândul lor, să inițializeze dispozitive hardware noi și să ruleze procese ​de automatizare).
-  * ''​SRC_URI'':​ identifică fișierele care trebuiesc incluse în directorul de lucru special făcut pentru rețeta respectivă +
-  ​''​BB_NUMBER_THREADS'':​ denotă numărul de thread-uri de ''​bitbake''​ care să ruleze +
-  * ''​PARALLEL_MAKE'':​ modul în care va fi făcută compilarea ​și numărul de thread-uri de compilare care vor porniValoarea acestei variabile este aceeași ca în cazul sistemului ''​make'':​ -j <​num_threads>​ +
-  * ''​MACHINE'':​ denumirea sistemului (mașinii) pentru care se realizează compilarea +
-  * ''​BBMASK'':​ lista de pachete ce vor fi ignorate în momentul compilării+
  
-==== Rețete ​====+==== U-Boot ​====
  
-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''​.+U-boot ​este probabil cel mai popular bootloader open-source folosit atât în lumea embedded / IoT / industrialcât și în platformele mobile (majoritatea telefoanelor pe Android).
  
-Pentru un astfel de proiect va exista câte o rețetă ce conține un task de tip ''​do_'' ​pentru ​fiecare operațieFolosind apoi proprietatea rețetelor ​de a include sau a specifica dependențe față de alte rețetese creează o ierarhie ce pornește de la o rețetă top level și parcurge ​și execută în ordine toate operațiile.+Acesta este scris în C și folosește KConfig (as expected) pentru personalizarea funcționalităților incluse ​pentru ​a se putea încadra în cerințele restrictive de memorie a anumitor sisteme. 
 +De asemenea, U-Boot are implementată o cantitate vastă ​de drivere necesare pentru ​interfața cu cât mai multe periferice de pe care să se încarce sistemul ​de operare (SPIMMC, USB devices, SATA / M.2 PCI-E, chiar și Rețea, prin PXE + TFTP) și conține chiar și un mini-limbaj de scripting (similar bash, însă compilat ​în binar) ce permite implementarea de proceduri avansate de boot cu redundanță și failover (necesare sistemelor realtime).
  
-Directivele ce pot fi folosite într-o rețetă ​pentru a include sau moșteni alte fișiere ​de configurare sunt: +Noi vom folosi un U-Boot la laboratoare ​pentru a putea scrie SD card-ul direct ​de pe PC, prin conectarea Raspberry PI4-ului direct la PC prin USB OTG (fără a utiliza ​un cititor extern ​de carduri SD!), cât și pentru a avea o vizibilitate mult mai bună a procesului de boot Linux.
-  * ''​include <​file_name>'':​ include fișierul cu numele <​file_name>​. Este folosită variabila ''​BBPATH''​ pentru ​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>​.bbclass, dacă acesta există ​+
  
-==== Layer ====+===== Exerciții =====
  
-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 o anumită distribuție.+<​note>​ 
 +**În laborator, vom folosi echipamente Raspberry PI 4!** conectate prin USB Type-și un adaptor UART la USB pentru ​vizualizarea consolei dispozitivului (din păcate, nu dispunem de suficiente monitoare HDMI în laborator + cabluri adaptoare).
  
-<code yaml LayerExample>​ +Î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
-meta-layer:  +</note>
-  - conf +
-  - recipes-core +
-      - important_recipe +
-          - x.bb +
-  - recipes-category1 +
-      - recipe-1a +
-          - y.bb +
-          - t.bbappend +
-      - recipe-1b +
-          - ... +
-  - recipes-category2 +
-      - recipe-2a +
-          - ...  +
-      - recipe-2b +
-          - ..+
-</code>+
  
-Structura unui layer este următoareadenumirea layer-ului urmată ​de o serie de categorii ​de rețete. Fiecare categorie conține lista rețetelor componente și fișierele de configurare aferente fiecarei dintre acestea.+**0.** Descărcați [[https://​github.com/​cs-pub-ro/​SI-rpi-debian-scripts/​releases|de aici arhivă unui sistem ​de fișiere folosit ca referință laborator]] pentru RPI4 + imaginea partiției ''​rpi-boot.img''​ (utilă în caz că se strică bootloaderul).
  
-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ă.+  * Dezarhivați arhiva într-un subdirector (prin ''​tar'', ​folosiți argumentul ​''​-C'' ​pentru a preciza directorul destinație,​ însă ​va trebui să îl creați înainte). **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!);​ 
 +  * Inspectați căile ​''​/boot'' ​(rețineți / copiați într-un ​fișier text output-ul, e util de comparat mai încolo). 
 +  * Apoi, ne vom pregăti să pornim Raspberry PI 4! 
 +  * Asigurați-vă că firele ce conectează Raspberry PI-ul la adaptorul de serială nu sunt ieșite. Dacă da, [[https://​pinout.xyz/​|conectați-le corespunzător]] (UART RX (alb) / TX (verde) la TX (pin 8)/RX (pin 10) al RPI-ului!) + chemați asistentul să verifice! 
 +  * TLDR: începeți cu negru (GND) la pin 6 (al treilea ​de pe margine), apoi imediat lângă (pe același rând), firele alb + verde (în această ordine); **firul roșu SĂ RĂMÂNĂ NECONECTAT**! ​
  
-<​note ​tip+<​note ​warning
-Pentru ​a automatiza procesul de creare a unui layer se poate folosi comanda: +Pentru ​orice eventualitate**vă rugăm să chemați asistentul înainte de a alimenta dispozitivul la laptop!**
-<code bash> +
-# pentru kasintrați în shell mai întâi: +
-# apoi rulați: +
-bitbake-layers create-layer meta-mylayer +
-</​code>​+
 </​note>​ </​note>​
  
-Specificarea layer-elor ce se doresc ​fi incluse într-un proiect se face prin scrierea unui fișier numit ''​bblayers.conf''​. Structura acestuia este următoarea: +  * În final, înainte de a-l alimenta, conectați-vă adaptorul serial la USB în laptop, ​faceți USB passthrough la mașina virtuală (dacă este cazul) și porniți programul preferat de consolă serială (e.g., ​''​picocom''​),​ folosind baud rate-ul ''​115200'':​ <​code>​ 
- +sudo dmesg | tail -20 && ls -l /dev/ttyUSB* 
-<​code ​bash+picocom ​-b 115200 ​/dev/ttyUSB0 ​ # înlocuiți cu ce dispozitiv aveți
-BBLAYERS ?= " \ +
-<​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. 
  
 <note important>​ <note important>​
-**De ținut cont:** modalitățile de personalizare a parametrilor ​în fișiere precum ''​bblayers.conf'' ​și ''​local.conf''​ diferă atunci când folosim utilitarul **kas**deoarece acestea vor fi generate ​automat!+Din păcate, în laborator avem ca adaptoare Serial to USB niște clone chinezești de Prolific PL2303, pe care driverele oficiale Microsoft [[http://​wp.brodzinski.net/​2014/​10/​01/​fake-pl2303-how-to-install/​|le dezactivează automat ca fiind "​counterfeit"​ (găsițo soluție aici)]]De regulă, în mașina virtuală cu Linux nu ar trebui să conteze, doar că mecanismul driverelor de a dezactiva ​automat ​dispozitivele "​copiate"​ poate interfera cu passthrough-ul USB care se face în mod normal. :(( problema apare frecvent pe VirtualBox (pe VMware nu au fost raportate probleme). ​  
 </​note>​ </​note>​
  
-===== Mediul de lucru =====+**1.** Alimentați RPI-ul și urmăriți mesajele din consolă. Ar trebui să vă intre în U-Boot (preinstalat pe cardurile SD ca ''​BL31''​),​ apoi:
  
-Pentru începutaveți nevoie ​de [[https://github.com/cs-pub-ro/SI-Lab-VM/​releases/​tag/​y2022-yocto|mașina virtuală ​cu Yocto]] descărcată.+  * Dacă apare că rulează un proces de network bootapăsați Ctrl+C ​de foarte multe ori (//yep... scriptul de boot face un for cu vreo 10 iterații//) pentru a-l întrerupe;​ 
 +  * După ce vă apare prompt-ul ''​U-Boot> '',​ rulați comanda ''​mmc list''​. O să vă apară o listă de dispozitive MMC (ar trebui să vedeți cardul SD ca fiind detectat); încercați-le pe fiecare cu ''​mmc dev <​N>''​ și apoi ''​mmc info''​ până găsiți cardul SD; 
 +  * Apoi rulați comanda ''​ums mmc <​N>'',​ unde ''<​N>''​ este numărul perifericului MMC. Acesta va lansa în execuție un program care emulează un Mass Storage Device pe interfața USB Type-C folosită la conectarea la laptop; 
 +  * Inspectați noul dispozitiv montat (nu uitați să faceți pass-through la noul device USB în mașina virtuală, dacă este cazul!). Mai precis, montați prima partiție (posibil să fie și singura) pe mașina voastră virtuală cu Linux, e.g., în /mnt. Ce fișiere există? Comparați cu partiția ''/​boot''​ a rootfs-ului.
  
-Se recomandă să aveți ultima versiune ​de VMWare ​Workstation instalatăpe care o puteți descărca gratis de pe portalul [[https://​vmware.pub.ro/​]] ​(vă autentificați cu contul unic al facultății).+<note important>​ 
 +Comanda ''​ums''​ este blocantă (poate fi întreruptă cu Ctrl+C). 
 +Dacă folosiți un soft de virtualizare (VirtualBox / VMWare)va trebui să faceți passthrough la acest dispozitiv ​(se numește "​Netchip USB Download Gadget"​). Apoi verificați prin ''​lsblk''​ / ''​blkid''​ care este dispozitivul nou apărut în VM.
  
-Recomandat ar fi să faceți uz de funcționalitatea de VM snapshotting pe care o pune VMWare la dispozițieastfel încât să puteți ​pleca de la imaginea de bază (pe care să o țineți nemodificată!) și să aveți mai multe instanțe separate (sub forma unor snapshot-uripe care le puteți comuta manual după caz. De exemplu, doriți să experimentați ceva cu Yocto: faceți un snapshot nou, vă jucați liberi ​în acea instanță apoi, dacă experimentul ​eșuat, puteți reveni mereu la starea anterioară a snapshot-ului (cu fișierele de atunci). +Cât timp rulează, vă puteți ​conecta cu laptopul ​(prin interfața USB Type-Cla cardul SD introdus ​în Raspberry pentru ​a-l inspecta / [re]scrie (cu grijă să nu suprascrieți bootloaderul u-boot).
- +
-Pentru un ghid de folosire a snapshot-urilor în VMWare, vedeți ​[[https://​linuxhint.com/​take-virtual-machines-snapshots-vmware-workstation/​|pagina aceasta]]. **TLDR:** Ctrl+M în VMWare pentru Snapshot Manager ;) +
- +
-<​note>​ +
-Un snapshot ocupă spațiu cât doar pentru modificările aduse la imaginea lui de bază (sau un alt snapshot pe care este bazat). +
-Folosiți ​cu încredere, însă este posibil ca spațiul de modificări făcute la un build să aibe ''​~2 GB''​ (puteți oricând combina snapshoturile reușite pentru a reduce spațiul).+
 </​note>​ </​note>​
  
-<note tip> +**2.** Dorim să compilăm **U-Boot** local (pentru a învăța cum se face șexplora ce funcționalități are) șsă construim imaginea de boot de la zero.
-Proiectul de VM al laboratorului ​**NU** are snapshot inițial făcut (pentru a putea fi compatibil și cu VMWare Player, care nu permite acest lucru), deci ar fi o idee bună să-i facețunul; dacă stricați ceva va trebui să-l re-descărcați :( (sau îl dezarhivațdin nou, dacă țineți .zip-ul original ​la seed :D). +
-</​note>​+
  
-<note tip> +  * Aveți nevoie de toolchain-ul pentru Aarch64 ​să fie în ''​$PATH'' ​(lucru adevărat pe VM-ul de la laborator);​ 
-Yocto beneficiază de viteză cu cât are mai multe resurse hardware disponibile. +  * Urmați pașii: <code
-De aceea, este recomandat să utilizați VM-ul de pe un SSD și -i configurați ~8GB ram și 4 nuclee ​(este important dacă doriți să recompilați kernelul sau alte componente mai mari). +# pe Lab VM 2023 lipsește acest pachet, instalați-l
-</​note>​ +sudo apt install ​libssl-dev 
- +git clone --branch=v2023.07.02 https://​github.com/​u-boot/u-boot.git 
-Mai jos aveți instrucțiunile manuale de instalare dacă nu aveți ​VM-ul sau doriți să vedeți cum se face asta (atențiecompilarea inițială poate dura câteva ore bune!) +cd u-boot 
- +# ne pregatim de compilare:​ 
-<spoiler+export CROSS_COMPILE="​aarch64-linux-gnu-
-Este recomandat să folosiți ​VM-ul pus la dispoziție pentru a nu fi nevoiți să recompilați toată distribuția de la zero. +# initializam configul default pentru RPI4 
-De asemenea, **kas** poate rula majoritatea pașilor de descărcare + compilare automat pentru noi! +make rpi_4_defconfig 
- +make menuconfig 
-Pentru început, trebuie să ne asigurăm că utilitarele folosite de Yocto / ''​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 distribuție: +# aici, căutați și activați următoarele opțiuni (ambele sunt necesare!):​ 
- +# CONFIG_USB_FUNCTION_MASS_STORAGE=y 
-<code bash Ubuntu 22.04> +# CONFIG_CMD_USB_MASS_STORAGE=y 
-sudo apt-get -y install ​gawk wget git sed diffstat unzip texinfo gcc build-essential \ +make -j4
- chrpath socat cpio python3 python3-pip python3-pexpect xz-utils debianutils \ +
- iputils-ping python3-git python3-jinja2 libegl1-mesa libsdl1.2-dev \ +
- python3-pylint-common python3-subunit mesa-common-dev zstd liblz4-tool+
 </​code>​ </​code>​
  
-<code bash Fedora>​ +  * O dată terminată compilareacopiați fișierele ​''​u-boot.bin''​ ș''​arch/​arm/​dts/​bcm2711-rpi-4-b.dtb'' ​din directorul lui U-Boot către un director nou creat (să zicem, ​''​~/rpi-boot-firmware''​)
-sudo yum groupinstall "​development tools"​ +  ​* De asemenea, stagiul secundar (''​BL2''​) al RPI4 are nevoie ​de firmware-ul GPU-ului, ce poate fi descărcat de pe GitHub ​de la adresele:
-</​code>​ +
- +
-Apoi, sursele proiectului Yocto pot fi descărcate urmărind instrucțiunile de [[https://​www.yoctoproject.org/​downloads|aici]] sau clonate direct din repository-urile mentionate la începutul laboratorului. +
- +
-Următorul pas este să obținem layer-ele și configurațiile necesare pentru a compila imaginea corespunzătoare pentru sistemul dorit. În cazul nostruacest sistem este ''​RaspberryPi''​. Acest layer poate fi obținut clonând repository-ul de la adresa: [[https://​github.com/​djwillis/​meta-raspberrypi.git]] +
- +
-După ce avem sursele Yocto șlayer-ul necesar pentru dezvoltarea unei imagini de RaspberryPi,​ trebuie să inițializăm mediul de compilare și directorul de lucru. Pentru aceasta, trebuie rulată următoarea comandă în directorul ce conține sursele Yocto: +
- +
-<code bash> +
-source oe-init-build-env <​path_to_working_directory>/<​rpi_build_folder>/​ +
-</​code>​ +
- +
-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ă: +
-  ​''​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 RaspberryPiacestea 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"''​ (i.e., ghilimelele sunt obligatorii)</​note>​ +
- +
-Tot în directorul ''​conf''​ există și fișierul ''​bblayers.conf'' ​ce conține informația legată de layer-ele ce vor fi compilate. Trebuie să adăugăm la variabila ''​BBLAYERS''​ o cale către layer-ul ​de RaspberryPi. Revedeți secțiunea **Layers** și exemplul de acolo. +
- +
-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. +
- +
-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 utilitare. Dezavantajul major este timpul necesar pentru o compilare. +
-</​spoiler>​ +
-\\ +
- +
-===== Exerciții ===== +
- +
-==== 0. Starea / build-ul inițial, introducere kas ==== +
- +
-Considerăm starea inițială a distribuției descărcată / precompilată în VM cu următoarea structură:+
 <​code>​ <​code>​
-/home/​student/​yocto:​ +cd ~/rpi-boot-firmware
-|-- build  # (generat de Yocto bitbake) +wget "​https:​//github.com/raspberrypi/firmware/raw/master/boot/​start4.elf"​ 
-|   |-- conf # generate automat din kas.yml +wget "​https://​github.com/​raspberrypi/​firmware/raw/​master/​boot/​fixup4.dat" 
-|   ​| ​  |-- bblayers.conf +însă le găsiți și pe sistemul rădăcină referință, la calea /​boot/​firmware
-|   ​| ​  |-- local.conf +
-|   ​| ​  `-- templateconf.cfg +
-|   `-- tmp/ +
-|   ​| ​  |-- deploy # resurse generate +
-|   ​| ​      |-- images # aici se află imaginile generate +
-|   ​| ​      |-- ipk    # aici se află pachetele generate +
-|   |-- cache # nimic important aici ;) +
-|-- layers # (descărcate de `kas`) +
-|   |-- meta-raspberrypi/ ​ # layer-ul de la RPI +
-|   `-- poky # distribuția poky +
-|-- kas.yml     # fișierul de configurare kas +
-|-- Makefile ​   ​un makefile ajutător (poate) +
-|-- runqemu.sh ​ # experiment eșuat, puteți să-l ștergeți :D a fost uitat acolo+
 </​code>​ </​code>​
- +  ​Ultimul ​lucru care lipsește este fișierul ''​config.txt''​. ​Strictul necesar ​este următorul: <​code>​ 
-Per parcursul acestui document, vom considera strict acest director de bază (neavând treabă în alte locuri). +config.txt contents to load U-Boot as BL31: 
- +arm_64bit=1 
-În VM a fost deja invocat utilitarul ''​[[https://​kas.readthedocs.io/​en/​latest/​|kas]]''​ (vedeți și documentația oficială), care a avut următoarele efecte: +kernel=u-boot.bin 
- +enable_uart=1
-  ​a clonat (descărcat) de pe git-ul oficial proiectele [[https://​git.yoctoproject.org/​poky/​tree/​|poky]] (ce conține sursele și scripturile principale ale Yocto) și [[https://​github.com/​agherzan/​meta-raspberrypi/​|meta-raspberrypi]] (Layer oficial pentru dispozitivele RaspberryPi);​ toate acestea pe baza descrierii din secțiunea ''​repos''​ a fișierului ''​kas.yml''​. +
-  * a generat fișierele de configurare ale build-ului Yocto: ''​build/​conf/​{bblayers.conf,​ local.conf, templateconf.cfg}''​. +
-  * a făcut un ''​bitbake build''​ inițial la imaginea de bază a distribuției Poky (''​core-image-base''​), ​lucru ce poate dura chiar și câteva ore (pentru compilarea atât a cross toolchain-ului,​ cât și ale kernelului și ale tuturor pachetelor instalate în distribuția de bază); din fericire, o dată compilate, aceste pachete vor rămâne în cache și vor fi refolosite la toate build-urile ulterioare (decât dacă schimbați versiunea layerelor descărcate sau doriți să upgradați pachetele -- we don't do that here!). +
- +
-Deși acest mic tool ne-a automatizat din munca de setup a unui proiect nou Yocto, acesta vine cu inconvenientul că, dacă dorim să modificăm unul dintre fișierele generate (din ''​build/​conf/''​),​ va trebui s-o facem prin intermediul fișierului de configurare ​''​kas.yml'' ​(more on this later). +
- +
-De menționat ar fi faptul că imaginea de bază conține strict pachetele prevăzute de către fișierele implicite de configurare ale Poky și atât. Nu este nici măcar folosibilă în starea aceasta inițială (neavând parolă la contul de ''​root''​). +
-Pentru a schimba aceste lucruri avem nevoie să ne construim propriul layer, ceea ce vom și face într-un exercițiu viitor. +
- +
-Observați faptul că nu puteți rula ''​bitbake''​ (dă ''​command not found''​). Acesta un executabil care nu se află de obicei în ''​$PATH''​-ul normal al sistemelor Linux, putând fi accesat doar după inițializarea mediului Yocto.  +
-Reamintim că utilitarul ''​kas''​ ne-a descărcat codul sursă al ''​poky''​ în calea ''​layers/​poky/''​. +
- +
-Tot aici găsim și scriptul ''​oe-init-build-env''​ responsabil de inițializarea. +
-Astfel, dacă încărcăm acest script în shell-ul curent: <​code ​bash+
-student@vm:​~/​yocto$ source layers/​poky/​oe-init-build-env +
-##Shell environment set up for builds### +
-You can now run '​bitbake <​target>'​ +
-... +
-# sau, alternativa prin kas: +
-student@vm:​~/​yocto$ kas shell kas.yml +
-# (se pornește un subshell unde puteți da comenzi yocto)+
 </​code>​ </​code>​
-După aceasta, utilitarele Yocto devin accesibile (însă doar în shell-ul actual, dacă utilizați mai multe terminale sau îl re-deschideți pe acesta, va trebui să repetați comanda în fiecare). ​**Atenție!** Comanda ne schimbă ​directorul ​nostru actual în ''​build/''​, dați ''​cd ..''​ pentru a reveni în rădăcina proiectului nostru. +  ​Acum directorul ''​rpi-boot-firmware'' ​ar trebui ​să fie identic ca imaginea referință din laborator! 
- +  ​* ​//NotăPentru a boota Linuxeste necesar ​și ''​cmdline.txt''​ (folosiți-l pe cel din imaginea referință de bootloader);//
-În final, dorim să testăm distribuția precompilată din VM: +
-<​code>​ +
-# atenție: rulați într-un shell inițializat prin Yocto ca mai sus: +
-student@vm:​~/yocto$ runqemu qemuarm slirp nographic +
-</code> +
- +
-Argumentele ce vor fi pasate (ușor modificate) comenzii qemu''​slirp''​ - activează un tunel cu gazda prin care se furnizează acces la Internet, și ''​nographic'' ​- folosește consola doar (nu avem server grafic în VM, mai adăuga câțiva GB în plus + mai multă memorie consumată :D).+
  
 <note important>​ <note important>​
-Pentru a ieșdin qemufolosiți combinația ''​Ctrl+a,​ x''​ (adică ctrl+care va intra într-un mod invizibil de comandă a monitorului qemu, apoi, separat, tasta x)+Dacă dorițsă testați noua imaginear trebui să copiați aceste fișiere pe partiția FAT32 Raspberry PI-ului
-</​note>​ +Însă facețasta doar dacă aveți încredere că nu stricați bootloaderul existent! 
- +Dacă ați pățit totuși asta și doriți să refacețiexistă mai multe tehnici de recuperatcea mai simplă fiind folosirea unui SD card reader extern și scrierea imaginii ''​rpi-boot.img''​ descărcate la ex0. Alternativ, puteți scrie imaginea pe un stick USB și introduce în RPIapoi folosiți comanda ''​ums'' ​pentru a scrie cardul SD introdus în dispozitiv și apoi ''​dd''​ pentru a scrie bootloaderul referință:<​code>​ 
-==== 1. Layere șrețete ==== +sudo dd if=~/Downloads/rpi-boot.img.bin of=/dev/sd<x> bs=4k status=progress && sudo sync
- +
-[[https://​docs.yoctoproject.org/​overview-manual/​yp-intro.html#​the-yocto-project-layer-model|Un layer]] este, practic, o colecție de sine stătătoare de scripturi, metadate ​și alte resurse construcție a unui sistem Linux. +
-O distribuție Yocto estepractic, compusă din unul sau mai multe straturi așezate unul peste altul (iar Pokydesigur, stă la baza acestora) ce aplică operații de build într-o anumită ordine pentru a obține rezultatul dorit. +
- +
-Pentru a crea un layer nouputem folosi comanda ''​bitbake-layers'':​ <​code ​bash+
-# asigurațivă că sunteți într-un shell Yocto, citiți mai sus ^^ ;) +
-student@vm:~/yocto/build$ cd ../  # navigăm în afara directorului build/ +
-student@vm:​~/​yocto$ bitbake-layers create-layer meta-tutorial-si +
-NOTE: Starting bitbake server... +
-Add your new layer with '​bitbake-layers add-layer meta-tutorial-si'​+
 </​code>​ </​code>​
- 
-<note info> 
-Nu recomandăm utilizarea directorului ''​build/''​ pentru a stoca codul layerelor, deoarece va fi ignorat de scriptul care împachetează arhiva cu sursele. La fel și cu directorul ''​layers/''​ (aici sunt stocate layerele third-party ce au fost / vor fi descărcate automat prin //kas//). 
 </​note>​ </​note>​
  
-Această comandă va genera scheletul pentru noul nostru layer într-un director cu numele furnizat ca parametru. +**3.** Ne dorim să instalăm sistemul de fișiere Linux referință pe cardul SD din Raspberry PI (folosind USB Mass Storage-ul prin USB Type-C).
-Structura layer-ului nou creat va fi următoarea:​ <​code>​ +
-meta-tutorial-si/​ +
-|-- conf +
-|   `-- layer.conf ​  # variabile de configurație utilizate de layer +
-|-- COPYING.MIT +
-|-- README +
-`-- recipes-example ​ # ce drăguț, avem și exemplu de o rețetă ;) +
-    `-- example +
-        `-- example_0.1.bb +
-</​code>​+
  
-Un ghid oficial pentru creare layere puteți [[https://​docs.yoctoproject.org/​dev-manual/​common-tasks.html#​understanding-and-creating-layers|găsi aici]] ​(să îl puteți consulta ulterior). +  * Folosiți comanda ''​lsblk''​ pentru a descoperi cum se numesc device-urile (și, desigur, aveți grijă la capacitate: ​să nu ștergeți partiția rădăcină a OS-ului real din VM / fizic)! 
- +  * Primul lucruva trebui să creați o partiție ''​ext4'' ​pe cardul SD, **după cea de boot, FAT32 (NU O ȘTERGEȚI)!**Putem folosi ''​fdisk''​ sau utilitarul ​mai modern, ​''​parted'' ​(tot în linia de comandă :D ): 
- +<​code>​ 
-=== Recipes (rețete=== +lsblk  # NOTAȚI CU ATENȚIE CARE E CARDUL SD DE ~16GB !!!! 
- +# probabil SDB/SDC..., poate să fie sda dacă aveți ssd pe NVME și rulați Linux nativ... 
-Pentru a fi utilun layer conține una sau mai multe rețete. +sudo parted ​/dev/sd<​X>  ​înlocuiți <X>-ul 
-O rețetă este un fișier ​''​.bb'' ​cu sintaxă specială Bitbake ce descriu pașii de urmat de către sistemul de build pentru a genera pachete sau altera configurația unei distribuțiiApoi mai avem fișiere ​''​.bbappend'' ​care ne permit ​să re-configurăm rețetele din alte layere fără a le rescrie. +# în parted, dați comenzile '​print'​ pentru ​vedea partițiile curente, '​help'​ pentru comenzi 
-[[https://​docs.yoctoproject.org/dev-manual/common-tasks.html#writing-a-new-recipe|Ghid oficial aici]]. +# creați o partiție nouă (primaryext2 sunt setări bune) pe restul ​de spațiu liber (puteți scrie ''​100%''​)apoi quit 
- +# apoipentru a încărca tabela nouă de partiții, folosiți comanda
-Rețetele se află, de obiceiîntr-un director cu prefixul **//​recipes-//​** în denumirea lorînsă comportamentul real este definit în fișierul layer.conf:<code make> +sudo partprobe ​/dev/sd<X>
-# We have recipes-* directories,​ add to BBFILES +
-BBFILES += "​${LAYERDIR}/recipes-*/*/*.bb \ +
-            ${LAYERDIR}/​recipes-*/​*/​*.bbappend"​+
 </​code>​ </​code>​
-A se observa regula de globbing: se caută recursiv în orice director ce urmează această convenție, precum și sufixul de versionare ([[https://​docs.yoctoproject.org/​dev-manual/​common-tasks.html#​storing-and-naming-the-recipe|obligatoriu]]). 
-Desigur, nu avem de ce să o schimbăm, așa că trecem mai departe ;) 
  
-Pentru a folosi layer-ul nou creat, este necesar ca acesta să fie introdus în fișierul (global) de configurație al Yocto referitor la acestea''​bblayers.conf''​. Ne reamintim, însă, faptul că tool-ul nostru helper de build va suprascrie orice modificări vom face. +<note warning>​ 
-Defapt, ne generează lista de straturi ​pe baza unui fișier ​de configurație ''​kas.yml'',​ deci vom adăuga layer-ul nostru acolo: <code yaml> +**Mare atenție aici**sunteți ​pe cale de a rula operații cu potențial destructiv!
-# ... +
-repos: +
-  # adăugăm, pur și simplu, o cheie nouă (opțional, putem să modificăm calea către layer) +
-  meta-tutorial-si:​ +
-    path: '​./​meta-tutorial-si'​ +
-    # atenție la identarecontează... yaml s-a inspirat din python :(+
  
-  # ... restul ​de layere au fost descărcate prin URL de git... +Dacă folosiți mașina virtuală, este recomandat să faceți snapshot (riscați să ștergeți partițiile sistemului ​de operare real dacă nu aveți grijă!).
-  meta-raspberrypi:​ +
-    url: git://​git.yoctoproject.org/​meta-raspberrypi +
-  # ... +
-</​code>​+
  
-Rulăm apoi ''​kas build kas.yml''​. Observăm că, în ''​build/conf/bblayers.conf'' ​ne-a apărut layer-ul:<​code ​make+Dacă sunteți pe un Linux în mașină fizică și nu sunteți siguri de ce facețiîntrebați un asistent dacă dați comenzile bune **ÎNAINTE DE A LE DA**! 
-BBLAYERS ?= " \ +</​note>​ 
-    /home/student/yocto/layers/meta-raspberrypi \ +  * Formatați noua partiție (cea de-a doua, e.g. ''/​dev/sdX2''​) folosind utilitarul ''​mkfs.ext4''​. Folosiți și argumentul ​''​-L RPI_ROOTFS''​ pentru ​a-i da un label (nume). 
-    ..+  * Copiați conținutul arhivei ''​rootfs.tar.xz''​ (descărcată de pe GitHub la începutul laboratorului) pe partiția ''​ext4''​ nou-creată: 
-    ​/home/student/​yocto/​meta-tutorial-si" ​ # ​<-- here it is+<​code>​ 
 +# montăm partiția în /​media/​rootfs (pe care trebuie să-l cream) 
 +sudo mkdir /media/rootfs 
 +sudo mount /dev/sdX2 /media/​rootfs 
 +# TODO: mount sdX1 undeva (veți avea nevoie mai jos), creați un dir nou sau folosiți /mnt 
 +sudo tar xf rootfs.tar.xz -C /media/rootfs 
 +sudo sync  # ​sincronizează datele cacheuite în RAM către dispozitivele fizice 
 +# dacă comanda sync durează mult, NU O ÎNTRERUPEȚI!!! citiți notița 
 +# când a terminat, nu dați unmount, mai avem de copiat ceva de pe partiție!!
 </​code>​ </​code>​
  
-Doar că trebuia să ne printeze mesajul acela din rețeta //Example// la build, ceea ce nu se întâmplă... de ce oare? (heheee) +<​note>​ 
-Să facem altfel: <code bash> +Cardurile SD sunt extrem de lente, iar Linux are un obicei prost de a cache-ui fișierele copate în RAM-ul local și a le scrie în background după ce returnează comenzile ​de dezarhivare / copiere! Rulați comanda ''​sudo sync'',​ care este blocantă până toate operațiile de scriere pe disk se vor completa.
-# REMINDER: să aveți oe-init-build-env activat! +
-student@vm:​~/​yocto$ bitbake example ​ # să aveți oe-init-build-env activat! +
-Loading cache: 100% |##########​| Time: 0:00:00 +
-... +
-NOTE: Executing Tasks +
-*********************************************** +
-*                                             * +
-*  Example recipe created by bitbake-layers ​  * +
-*                                             * +
-*********************************************** +
-</​code>​+
  
-Now we're getting somewhere! Mai rămânedeci, să adăugăm această rețetă undeva să fie executată la build-ul imaginii principale (//​reminder://​ denumită **''​core-image-base''​**: +Pentru a monitoriza progresulutilizați one-liner-ul ''​watch grep -e Dirty: -e Writeback: /proc/meminfo''​ (așteptați până Writeback devine aproape ​de zeroiar Dirty sub 1MB).
-<code bash> +
-student@vm:​~/​yocto$ cd meta-tutorial-si/​ +
-student@vm:~/yocto/meta-tutorial-si$ mkdir -p recipes-core/​images/​ +
-student@vm:​~/​yocto/​meta-tutorial-si$ vim recipes-core/​images/​core-image-base.bbappend +
-# iar în fișier vom scrie: (suntem în vim, deci apăsăm un '​i'​ înainte pentru insert mode) +
-IMAGE_INSTALL += " example"​ +
-# <​esc>:​wq ca să nu rămânem blocați :P +
-student@vm:​~/​yocto$ cd ../ +
-student@vm:​~/​yocto$ kas build kas.yml +
-</​code>​ +
- +
-... //et voila!// +
- +
-**Cum funcționează:​** am extins rețeta imaginii de bază printr-un fișier ''​.bbappend''​ (pentru asta au fost concepute). Codul nostru va fi procesat după fișierul ''​.bb''​ original, astfel putând modifica [[https://​docs.yoctoproject.org/​singleindex.html#​term-IMAGE_INSTALL|variabila IMAGE_INSTALL]] pentru a ne fi incluse pachete custom de către task-urile rețetei generatoare de imagine. +
-Also check [[https://​docs.yoctoproject.org/​singleindex.html#​ref-features-image|these goodies]] (chestii gata făcute incluzabile printr-o linie de cod). +
- +
-Ca alternativăputeam construi o nouă imagine (e.g., ''​tutorial-si-image''​care să pornească de la primaDoar că trebuia să build-uim noua noastră imagine (''​bitbake tutorial-si-image''​ în loc de ''​core-image-base''​). +
- +
-<​note>​ +
-Am fi putut să facem același lucru prin modificarea ''​conf/​local.conf''​ și adăugarea unei linii:<​code make> +
-IMAGE_INSTALL_append = " example"​ +
-</​code>​ +
-... dar este, desigur, anti-practică! Vrem să avem toată funcționalitatea încapsulată în layer bine definit, păi ce facem noi aici... :P+
 </​note>​ </​note>​
  
 +  * Așa cum a fost menționat, avem nevoie de câteva fișiere din sistemul rădăcină pentru a boota linux-ul (pe care le găsiți în ''/​media/​rootfs/​boot''​ pe partiția a doua, sau în arhiva rootfs.tar.xz în directorul de boot), anume:
 +    * ''​vmlinuz--*'';​
 +    * ''​initrd.img-*'';​
 +    * //device tree blob-ul ar trebui să fie bun cel de la BL2, încărcat automat și de către u-boot, nu-l preluați pe acesta!//;
  
-==== 2. Configurarea distribuției + pachete adiționale ====+  * NU UITAȚI: după ce procesul de copiere s-a terminat (și ''​sync''​ nu mai blochează!),​ demontați toate device-urile implicate (i.e., cele partiții ale cardului SD). 
 +  * După copiere, puteți vizualiza fișierele de pe partiția FAT32 din U-Boot: ''​fatls mmc 1''​ ;)
  
-Înainte de a continua, ​**să aveți un layer creat** (e.g., ''​meta-tutorial-si'' ​de la pasul anteror saudesigur, puteți ​să folosiți ce altă denumire doriți) pe care îl vom extinde.+**4.** Pornim Raspberry PI-ul, din nou (avem mare grijă la firele ​de la serială, să nu facă contact cu alte părți ale dispozitivului!).
  
-Pentru a avea o distribuție Linux utilizabilă va trebuidesigursă avem creat un utilizator ;) +  * Încercațimai întâifără initramfs, apoi dați și comenzile care îl încarcă și îl dau argument la ''​booti'':​
-Apoi vom demonstra adăugarea de resurse (fișiere) în imaginea de bază.+
  
-=== 2.1. Adăugare utilizator nou === 
- 
-Momentan, imaginea este configurată în modul de debugging prin această linie din ''​local.conf''​-ul generat (vedeți în ''​kas.yml''​):​ 
 <​code>​ <​code>​
-EXTRA_IMAGE_FEATURES ​= "debug-tweaks"+# inițial, fără initramfs:​ 
 +fatload mmc <N>:1 ${kernel_addr_r} vmlinuz-6.1.61-rpi+ 
 +#fatload mmc <N>:1 ${ramdisk_addr_r} initrd.img-6.1.61-rpi+ ​ # e degeaba, momentan :D 
 +# astea sunt setate deja în cmdline.txt,​ apoi sunt încărcate în DTB (FDT) mai departe de către BL2 
 +# putem explora device tree-ul din memorie în felul următor: 
 +fdt addr ${fdt_addr} 
 +fdt print /chosen 
 +# verificați valoarea bootargs să conțină cel puțin: 
 +# bootargs ​= "... earlycon=pl011,​mmio32,​0xfe201000 console=serial0,​115200 root=/​dev/​mmcblk0p2 rw rootwait" 
 +booti ${kernel_addr_r} - ${fdt_addr} 
 +# se va plânge că nu aveți zonă de memorie de decompresie alocată! facem asta: 
 +# set decompression zone in RAM at 400MB, 64MB in size 
 +setenv kernel_comp_addr_r 0x19000000 
 +setenv kernel_comp_size 0x04000000 
 +# try again: 
 +booti ${kernel_addr_r} - ${fdt_addr} 
 +# ramdisk-ul momentan nu merge folosit, dar e opțional la debian
 </​code>​ </​code>​
  
-Aceasta ne setează parola goală la contul root. +<​note>​ 
-Pentru a spori securitatea imaginii implicitese pot crea utilizatori noi / schimba parolele, +Pentru a avea vizibilitate la ce face kernelul când bootează pe serială, [[https://www.raspberrypi.com/documentation/computers/​configuration.html#enabling-early-console-for-linux|am urmat pașii de aici]] să activăm earlycon pe RPI
-[[https://docs.yoctoproject.org/ref-manual/classes.html#extrausers-bbclass|vedeți tutorialul acesta]]. +</​note>​
-Cum se citește:+
  
-//"​uses this class in an image recipe:"//​. Deci ''​vim meta-tutorial-si/​recipes-core/​images/​core-image-base.bbappend'':​ +  * Este posibil ca ''​root=<device>''​ să nu fie bun, încercați să îi dați ''​root=LABEL=RPI_ROOTFS''​ sau prin UUID (depinde cum ați creat partiția și dacă ațdat label la ext4).
-<code make> +
-# vechiul conținut:​ +
-IMAGE_INSTALL += "​example"​ +
-# mai adăugăm: +
-inherit extrausers +
-# pentru a schimba parola la root+
-EXTRA_USERS_PARAMS +"​usermod -P student root;"​ +
-# pentru a adăuga un utilizator nou: +
-EXTRA_USERS_PARAMS +"​useradd -P parolalastudent student;"​ +
-# atenție: trebuie să muncim în plus pentru ​a-da drept de sudo utilizatorului,​ deci recomand root-ul +
-</​code>​+
  
-Apoi construim imaginea din nou: ''​kas build kas.yml''​. +<note
-Și rulăm:<code+Login-ul pentru rootfs este ''​pi''​ (fără parolă)!
-# nu uitați să faceți source la oe-init-build-env dacă nu aveți utiltarele în PATH +
-runqemu qemuarm slirp nographic +
-pentru ​a ieși, trebuie să apăsăm combinația Ctrl+a, apoi separat tasta `x` +
-</​code>​ +
- +
-=== 2.2. Inspectare ​rootfs ​=== +
- +
-Următoarea întrebare care se pune este: cum vedem conținutul unei imagini generate? +
-Din fericire, suntem pe un sistem Linux, așadar putem folosi ​''​mount'' ​pentru a inspecta local partiția ext3/4 generată:<​code bash> +
-student@vm:​~/​yocto$ sudo mount -o loop build/​tmp/​deploy/​images/​qemuarm/​core-image-base-qemuarm.ext4 /mnt +
-student@vm:​~/​yocto$ ls -l /mnt +
-student@vm:​~/​yocto$ cat /etc/passwd | grep student +
-student:​x:​1000:​1000::/​home/​student:/​bin/​sh +
-# cool! +
-# NU UITAȚI: să de-montați partiția la final!!! +
-(altfel s-ar putea să se corupă imaginea de la dublă utilizare) +
-student@vm:​~/​yocto$ sudo umount /mnt +
-</​code>​ +
- +
- +
-=== 2.3. Instalare pachete de bază === +
- +
-Deseori vom dori să instalăm pachete standard în imaginea noastră. +
- +
-Ca un prim pas, trebuie să aflăm denumirile pachetelor disponibile în distribuția standard. +
-Pentru acesta, folosim ''​bitbake show-recipes''​ pentru a vedea lista întreagă de rețete. Mod de folosire:<​code bash> +
-student@vm:​~/​yocto$ bitbake-layers show-recipes | grep -A 1 python3 +
-python3: +
-  meta                 ​3.10.7 +
-# ... și multe alte subpachete ale bibliotecilor populare +
-</​code>​ +
- +
-Problema este că acestea sunt denumiri de rețete, însă o rețetă poate defini mai multe pachete (de obicei, se păstrează o convenție de nume prin prefixare). +
-Din păcate, va trebui să ne uităm pe codul sursă al rețetelor de oricâte ori nu există pachetele cu numele lor. +
-Pentru pachetele standard din Poky (versiunea ''​kirkstone''​),​ [[https://​github.com/​yoctoproject/​poky/​tree/​kirkstone-4.0.1/​meta|puteți explora rețetele aici]] (a se observa categorizarea acestora). +
- +
-Pentru a instala un pachet într-o imagine, trebuie să edităm rețeta imaginii (fișierul ''​.bb''​ dacă este imaginea noastră, altfel prin ''​.bbappend''​ să modificăm imaginea standard, ca mai sus):<​code bash> +
-student@vm:​~/​yocto$ vim meta-tutorial-si/​recipes-core/​images/​core-image-base.bbappend +
-# adăugăm pachetele prin variabila IMAGE_INSTALL:​ +
-IMAGE_INSTALL += "​python3 python3-pip"​ +
-</​code>​ +
- +
-Desigur, putem face același lucru prin folosirea variabilei ''​IMAGE_INSTALL_append''​ a lui ''​local.conf'',​ dar vrem să păstrăm gruparea corectă a funcționalității în layere ;) +
- +
-<note warning>​ +
-Pentru fiecare pachet nou adăugat, bitbake va porni un proces de compilare care s-ar putea să dureze câteva minute (posibil și zeci). +
-Să țineți cont acest timp de așteptare când vă planificați activitatea!+
 </​note>​ </​note>​
- 
-Finally, dorim să testăm noua imagine: <code bash> 
-student@vm:​~/​yocto$ kas build kas.yml 
-# (sudo make coffee ...) 
-NOTE: Tasks Summary: ... all succeeded. ​ # doamne-ajută! 
- 
-student@vm:​~/​yocto$ runqemu qemuarm slirp nographic 
-# ... 
-qemuarm login: root 
-Password: 
-root@qemuarm:​~#​ ip a sh eth0 
-2: eth0: <​BROADCAST,​MULTICAST,​UP,​LOWER_UP>​ mtu 1500 qdisc pfifo_fast qlen 1000 
-    link/ether 52:​54:​00:​12:​34:​02 brd ff:​ff:​ff:​ff:​ff:​ff 
-    inet 192.168.7.2/​24 brd 192.168.7.255 scope global eth0 
-       ​valid_lft forever preferred_lft forever 
-# ... 
-root@qemuarm:​~#​ echo "​nameserver 8.8.8.8"​ > /​etc/​resolv.conf 
-root@qemuarm:​~#​ ping google.com 
-PING 8.8.8.8 (8.8.8.8): 56 data bytes 
-64 bytes from 8.8.8.8: seq=0 ttl=127 time=30.050 ms 
-64 bytes from 8.8.8.8: seq=1 ttl=127 time=20.487 ms 
-root@qemuarm:​~#​ pip3 install youtube-dl 
-root@qemuarm:​~#​ python3 
-Python 3.10.7 (main, Sep  5 2022, 13:12:31) [GCC 11.3.0] on linux 
-Type "​help",​ "​copyright",​ "​credits"​ or "​license"​ for more information. 
->>>​ from youtube_dl import YoutubeDL 
->>>​ ydl = YoutubeDL() 
->>>​ ydl.add_default_info_extractors() 
->>>​ info = ('​https://​www.youtube.com/​watch?​v=ITRBsXrPOn8'​) 
->>>​ info['​title'​] 
-# mulțumiți,​ putem ieși ;) 
-# dacă rămâneți blocați în qemu console, căutați mai sus cum ieșiți :P 
-</​code>​ 
- 
-=== 2.4. Adăugare resurse în imagine === 
- 
-O dată instalate pachetele necesare (e.g., interpretorul python), vom dori să configurăm sau să instalăm scripturi custom-made. 
- 
-Putem face asta prin intermediul rețetelor. Reamintim că acestea execută anumite acțiuni într-o ordine bine definită. 
-Printre primele task-uri efectuate se numără cel de //fetch source files//, ce de multe ori constă în descărcarea codului de pe un server. 
-Într-o rețetă, se face asta prin intermediul variabilei de configurare ''​[[https://​docs.yoctoproject.org/​ref-manual/​variables.html#​term-SRC_URI|SRC_URI]]''​ care ne permite inclusiv prin căi locale. 
- 
-De exemplu, edităm rețeta exemplu (''​meta-tutorial-si/​recipes-example/​example/​example_0.1.bb''​):<​code make> 
-# ... (după descrierea din antet) 
-LICENSE = "​MIT"​ 
- 
-# adăugăm fișiere sursă 
-SRC_URI = "​file://​hello.py \ 
-           ​file://​example.conf"​ 
-# sau pe linii separate: 
-#SRC_URI += "​file://​example.conf"​ 
-# fișierele sursă vor fi copiate / descărcate în ${WORKDIR}! 
- 
-# va trebui să intervenim cu un pas de instalare pentru a le copia în imagine: 
-do_install() { 
-    # atenție: ${D} represintă directorul destinație în procesul de împachetare! 
-    #          orice generați în afara acestuia nu va fi inclus în pachet! 
-    # copiem scriptul în bin: 
-    install -D -m 0755 -t ${D}${bindir} ${WORKDIR}/​hello.py 
-    # copiem conf-ul în /etc: 
-    install -D -m 0644 -t ${D}/etc ${WORKDIR}/​example.conf 
-} 
- 
-python do_display_banner() { 
-# ... restul rămâne 
-</​code>​ 
- 
-Dacă încercați să build-uiți pachetul sau imaginea (''​bitbake example''​),​ veți obține o eroare cum că nu poate găsi fișierele incluse (și vă dă și căile unde le puteți crea). 
-O convenție foarte bună ar fi subdirectorul ''​files'',​ deci: <code bash> 
-student@vm:​~/​yocto$ mkdir -p meta-tutorial-si/​recipes-example/​example/​files/​ 
- 
-student@vm:​~/​yocto$ vim meta-tutorial-si/​recipes-example/​example/​files/​hello.py 
-#​!/​usr/​bin/​python3 
-with open("/​etc/​example.conf",​ "​r"​) as f: 
-  name = f.readline().strip() 
-print("​Hello,​ I am " + name) 
- 
-# <​esc>:​wq pentru a ieși din vim ;) 
- 
-student@vm:​~/​yocto$ echo "​STUDENT"​ > meta-tutorial-si/​recipes-example/​example/​files/​example.conf 
-student@vm:​~/​yocto$ bitbake example 
-</​code>​ 
- 
-Desigur, obținem iar o eroare, plângându-se că fișierele adăugate nu au precizată licența și checksum-urile (pentru securitate sporită). 
-Modificăm iar fișierul ''​example_0.1.bb'':<​code make> 
-LICENSE = "​CLOSED"​ 
-</​code>​ 
- 
-Iar ''​bitbake example'',​ iar o erorare despre [[https://​www.google.com/​search?​q=yocto+rdepends+python3|RDEPENDS la python3]], iar rezolvăm (''​example_0.1.bb''​):<​code make> 
-# Yocto detectează automat (prin shebang-ul pus la script) că avem nevoie de python3 
-RDEPENDS:​${PN} += "​python3-core"​ 
-</​code>​ 
- 
-Generăm imaginea: ''​kas build kas.yml''​ apoi o rulăm (prin ''​runqemu''​). 
- 
-În qemu, rulăm scriptul:<​code bash> 
-root@qemuarm:​~#​ hello.py 
-Hello, I am STUDENT 
-</​code>​ 
- 
-<​hidden>​ 
-==== 3. Bonus / extra tasks ==== 
- 
-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 imagine, dar dezavantajul este că ar trebui să facem această modificare la fiecare recompilare. Am 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. 
-Fisierul ''​hostname''​ ar trebui sa fie plasat aici: ''<​poky_path>/​meta/​recipes-core/​base-files/''​. 
- 
-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 core-image-base''​ 
-  * Verificați rezultatul rulând noua imagine cu Qemu! 
- 
-</​hidden>​ 
  
 ===== Resurse ===== ===== Resurse =====
  
-  * [[https://github.com/cs-pub-ro/SI-Lab-VM/releases/tag/y2022-yocto|Yocto Lab VM y2022]] +  * [[https://www.raspberrypi.com/documentation/computers/​raspberry-pi.html#​boot-sequence|Procesul de boot al Raspberry PI]] 
-  * [[https://docs.yoctoproject.org/ref-manual/|Yocto Reference Manual]] +  * [[https://hechao.li/2021/​12/​20/​Boot-Raspberry-Pi-4-Using-uboot-and-Initramfs/​|Mod utilizare U-Boot pentru Raspberry PI 4]] 
-  * [[https://docs.yoctoproject.org/ref-manual/variables.html|Yocto Variables Reference]]+  * [[https://github-wiki-see.page/m/​lulu98/​projects-with-sel4/wiki/​RPi4-Boot-Files|Explicație proces de boot al RPI 4 și fișierele firmware implicate]] 
 +  * [[https://github.com/cs-pub-ro/SI-rpi-debian-scripts|Cod sursă scripturi compilare bootloader / kernel / generare rootfs]]
  
  
si/laboratoare/06.1668373610.txt.gz · Last modified: 2022/11/13 23:06 by florin.stancu
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