This shows you the differences between two versions of the page.
si:laboratoare:08 [2022/12/05 01:21] jan.vaduva [Exercitii] |
si:laboratoare:08 [2024/11/24 22:15] (current) andreea.miu [Text & exercitii] |
||
---|---|---|---|
Line 1: | Line 1: | ||
- | ====== Laboratorul 08. Yocto extended content ====== | + | ====== Laboratorul 08. Kernel Build System ====== |
- | Asa cum am mentionat si laboratoarelor trecute si vom reitera si cu aceasta ocazie 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 ultim laborator vom continua si vom adauga context si exemple informatiei dobandite pana acum. Printre conceptele pe care le vom acoperi putem include: notiunea de pachet (package) si grup de pachete (packagegroups), care desi diferite au un scop diferit, sunt extrem de importante ca si concepte, vom detalia despre cum se poate lucra cu ele, care este rolul fiecareia dintre notiuni si cum putem lucra cu ele si de asemenea vom adauga aici si notiundea de module de kernel si modul in care putem integra aceasta notiune intr-o infrastructura precum Yocto Project. | + | Kernel-ul reprezintă o parte a sistemului de operare responsabilă cu accesul la hardware și managementul dispozitivelor dintr-un sistem de calcul (ex: procesorul, memoria, dispozitivele de I/O). De asemenea, el are rolul de a simplifica accesul la diferitele dispozitive hardware, oferind o interfață generică pentru aplicații prin intermediul system-call-urilor. În spatele interfeței generice se află porțiuni din kernel, numite drivere, care implementeză comunicația cu dispozitivele hardware. Un alt rol al kernel-ului este de a izola aplicațiile între ele, atât pentru stabilitatea sistemului, cât și din considerente de securitate. |
- | Pana acum am introdus conceptele esentiale de task, reteta (//.bb//), imagine. Am explicat care este rolul build engine-ului Bitbake si a diferitelor fisiere de configuratie specifice: fie ca discutam de clase (//.bbclass//), fisierul //layer.conf// responsabil cu descrierea structurii layer-ului nostru, //local.conf// unde regasim configuratia specifica build-ului, //bblayers.conf// ce descrie layerele folosite pentru procesul de build, configuratia specifica masinii selectate, in cazul nostru //qemuarm.conf// sau cea a politicilor de distributie folosite cunoscuta ca si //poky.conf//. | + | | {{ :si:lab:2015:kernel:architecture.png?300 |Architectura unui sistem de operare [By Bobbo (Own work) [CC-BY-SA-3.0 (http://creativecommons.org/licenses/by-sa/3.0) or GFDL (http://www.gnu.org/copyleft/fdl.html)], via Wikimedia Commons]}} | |
+ | ^ Architectura unui sistem de operare ^ | ||
- | In cele ce urmeaza vom extinde suportul cunostiintelor dobandite cu notiuni despre pachete, grupuri de pachete, notiunea de server web si cum se poate adauga suportul pentru un asfel de utilitar iar nu in ultimul rand vom discuta despre cum putem adauga suport pentru module de kernel. | + | Pentru a îndeplini toate aceste sarcini, codul kernel-ului rulează într-un mod special de lucru al procesorului, fapt care îi permite să execute o serie de instrucțiuni privilegiate. Acest mod privilegiat de lucru nu este accesibil aplicațiilor obișnuite. Spunem că aplicațiile rulează în //user-space// (modul neprivilegiat), iar kernel-ul rulează în //kernel-space// (modul privilegiat). |
- | Acestea pot fi buildate impreuna cu restul retetelor iar pentru procesul de dezvoltare se poate folosi SDK-ul pus la dispozitie de catre Yocto. Asa cum am mentionat deja 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 a mediului**: Acest fișier *.sh, odată preluat, configurează mediul de dezvoltare prin definirea variabilelor și pregătirea pentru utilizarea SDK. | + | |
- | Notiunea de **meta-toolchain** este un subset al SDK-ului si include **Cross-Development Toolchain** respectiv **Scriptul de configurare a mediului** si este o varianta light-weight pentru compilarea modulelor de kernel deoarece acestea nu depind de utilizare bibliotecilor asociate aplicatiilor disponibile in imaginea sistemului de operare buildat cu Bitbake. | + | ===== Linux ===== |
- | ===== Sursele codului ===== | + | Linux este numele unui kernel creat de către Linus Torvalds, care stă la baza tuturor distribuțiilor GNU/Linux. Inițial, el a fost scris pentru procesorul Intel 80386 însă, datorită licenței permisibile, a cunoscut o dezvoltare extraordinară, în ziua de astăzi el rulând pe o gamă largă de dispozitive, de la ceasuri de mână până la super-calculatoare. Această versatilitate, cât și numărul mare de arhitecturi și de periferice suportate, îl face ideal ca bază pentru un sistem embedded. |
- | Pentru ca sistemul de compilare Bitbake să creeze o imagine sau orice pachet, trebuie să poată accesa fișierele sursă. Asa cum a fost descris in fluxul de lucru fișierele sursă sunt fie descarcate dintr-un „Upstream Project Releases”, „Local Projects” și/sau „SCMs (opțional)”. | + | <note> |
+ | Arhitecturile suportate de kernel-ul Linux se pot afla listând conținutul directorului ''arch'' din cadrul surselor. | ||
+ | </note> | ||
- | Metoda prin care fișierele sursă sunt organizate în cele din urmă este o funcție a proiectului. De exemplu, pentru release-uri, proiectele tind să utilizeze tarball-uri sau alte fișiere arhivate care pot surprinde starea unei ediții, garantând că aceasta este reprezentată static. Pe de altă parte, pentru un proiect care este mai dinamic sau experimental în natură, un proiect poate păstra fișierele sursă într-o locatie controlata de un manager de control sursă (**SCM**), cum ar fi **Git**. Extragerea sursei dintr-o astfel de locatie vă permite să controlați revizia din care doriți să construiți software. O combinație a celor două este, de asemenea, posibilă. | + | Linux este un kernel cu o arhitectură monolitică, acest lucru însemnând că toate serviciile oferite de kernel rulează în același spațiu de adresă și cu aceleași privilegii. Linux permite însă și încărcarea dinamică de cod (în timpul execuției) în kernel prin intermediul modulelor. Astfel, putem avea disponibile o mulțime de drivere, însă cele care nu sunt folosite des nu vor fi încărcate și nu vor rula. Spre deosebire de aplicații însă, care rulează în modul neprivilegiat (//user-space//) și nu pot afecta funcționarea kernel-ului, un modul are acces la toată memoria kernel-ului și se execută în //kernel-space// (poate executa orice instrucțiune privilegiată). Un bug într-un modul sau un modul malițios poate compromite întregul sistem. |
- | BitBake folosește variabila **SRC_URI** pentru a indica fișierele sursă, indiferent de locația acestora. Fiecare rețetă trebuie să aibă o variabilă **SRC_URI** care să indice sursa. | + | Dezvoltarea kernel-ului Linux se face în mod distribuit, folosind sistemul de versionare Git. Versiunea oficială a kernel-ului, denumită //mainline// sau //vanilla// este disponibilă în repository-ul lui Linus Torvalds, la adresa [[https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git]]. |
- | O altă zonă care joacă un rol semnificativ în ceea ce privește provenienta fișierele sursă este indicată de variabila **DL_DIR**. Această zonă este un cache care poate stoca sursa descărcată anterior. De asemenea, puteți instrui sistemul de compilare Bitbake să creeze tarball-uri din depozitele Git, care nu este comportamentul implicit, și să le stocați în **DL_DIR** utilizând variabila **BB_GENERATE_MIRROR_TARBALLS**. | + | Versiunea oficială este însă rar folosită într-un sistem embedded nemodificată. Este foarte comun ca fiecare sistem să folosească o versiune proprie a kernelului (numită un //tree//) bazată mai mult sau mai puțin pe versiunea oficială. Datorită licenței GPLv2 a kernelului, însă, orice producător care folosește o versiune modificată a kernelului este obligat să pună la dispoziție modificările aduse. |
- | Utilizarea judicioasă a unui director **DL_DIR** poate salva sistemul de compilare o călătorie pe Internet atunci când caută fișiere. O metodă bună de utilizare a unui director de descărcare este ca **DL_DIR** să indice o zonă din afara directorului dvs. de compilare. Acest lucru vă permite să ștergeți în siguranță directorul de compilare, dacă este necesar, fără teama de a elimina orice fișier sursă descărcat. | + | Aceste modificări sunt puse la dispoziție sub formă de //patch//-uri care trebuie aplicate unei anumite versiuni de kernel. O altă modalitate, care este folosită și de către fundația RaspberryPi, este de a publica un repository de Git cu versiunea modificată (un //tree// alternativ). Datorită modelului distribuit de dezvoltare suportat de Git, această a doua metodă are avantajul că permite dezvoltarea ușoară în paralel a celor două versiuni. Modificările făcute într-una pot fi portate și în cealaltă, iar Git va ține minte ce diferențe există în fiecare versiune. Cele două versiuni sunt de fapt două //branch//-uri de dezvoltare, care se întâmplă să fie găzduite pe servere diferite. |
- | Proiectele locale sunt fragmente personalizate de software pe care utilizatorul le oferă. Acestea se află undeva la nivel local unui proiect - poate un director în interiorul layer-ului personal. | + | <note> |
+ | Kernel-ul folosit pe RaspberryPi, care include suportul pentru SoC-ul Broadcom BCM2835 folosit de acesta, se găsește la adresa [[https://github.com/raspberrypi/linux.git]]. | ||
+ | </note> | ||
- | Metoda standard prin care să includeți un proiect local este să utilizați clasa **externalsrc** pentru a include acel proiect local. Folosiți fie **local.conf**, fie fișierul //.bbappend// al unei rețete pentru a suprascrie sau pentru a reconfigura rețeta să indice directorul local de pe disc pentru a extrage codul sursă. | + | ===== Linux kernel build system ===== |
- | Un alt loc din care sistemul de compilare poate obține fișiere sursă este **Fetchers** care utilizează diverși Manageri de Control cod Sursă (**SCM**), cum ar fi Git sau Subversion. În astfel de cazuri, un repository este clonat sau verificat. Sarcina //do_fetch// din BitBake utilizează variabila **SRC_URI** și prefixul argumentului pentru a determina modulul de preluare corect. Când preia un repository, BitBake folosește variabila **SRCREV** pentru a determina revizia specifică din care să construiască. | + | Pentru compilare și generarea tuturor componentelor kernel-ului (ex: imaginea principală - //vmlinux//, module, firmware) Linux folosește un sistem de build dezvoltat o dată cu kernel-ul, bazat pe utilitarul //make//. Acest sistem de build însă nu seamănă cu clasicul //config/make/make install//, deși ambele sunt bazate pe utilitarul //make//. |
- | Există două tipuri de oglinzi: pre-oglinzi și oglinzi obișnuite. Variabilele **PREMIRRORS** și, respectiv, **MIRRORS** indică locatiile acestea. BitBake verifică pre-oglinzile înainte de a căuta în amonte orice fișier sursă. Pre-oglinzile sunt adecvate atunci când aveți un director partajat care nu este un director definit de variabila **DL_DIR**. O oglindă prealabilă indică de obicei un director partajat care este local pentru organizația dvs. | + | Toți pașii de compilare sunt implementați ca target-uri pentru //make//. De exemplu, pentru configurare se poate folosi target-ul ''config''. Acestă metodă de configurare însă nu este recomandată deoarece oferă o interfață foarte greoaie de configurare a kernel-ului. |
- | Oglinzile obișnuite pot fi orice site de pe Internet care este folosit ca locație alternativă pentru codul sursă în cazul în care site-ul principal nu funcționează dintr-un motiv sau altul. | + | <note tip> |
+ | Target-ul ''help'' oferă informații despre aproape toate operațiile suportate de către sistemul de build. | ||
- | ===== Fluxul de pachete ===== | + | <code shell> |
+ | $ make help | ||
+ | </code> | ||
+ | </note> | ||
- | Când sistemul de compilare Bitbake generează o imagine sau un SDK, primește pachetele dintr-o zonă de alimentare a pachetelor situată în directorul de build, in general intitulat **build**. Această secțiune explica puțin mai îndeaproape fluxul de pachete utilizat de sistemul de build. Iată o privire mai detaliată asupra zonei: | + | Operațiile oferite sunt grupate în diferite categorii: |
+ | * //cleaning// - conține target-uri pentru ștergerea fișierelor generate la compilare | ||
+ | * spre deosebire de ''clean'', ''mrproper'' șterge în plus toate fișierele generate, plus configurarea și diferite fișiere de backup | ||
+ | * //configuration// - conține diferite target-uri pentru generarea unei configurări a kernelului; există target-uri care permit: | ||
+ | * generarea unui fișier de configurare nou; ex: ''defconfig'', ''allmodconfig'', ... | ||
+ | * actualizarea unui fișier de configurare existent; ex: ''olddefconfig'', ''localyesconfig'', ... | ||
+ | * editarea unui fișier de configurare existent; ex: ''menuconfig'', ''nconfig'', ... | ||
+ | * //generic// - conține target-uri generice; există target-uri pentru: | ||
+ | * compilare; ex: ''all'' - target-ul implicit care este executat la o invocare simplă a lui ''make'', iar ''vmlinux'' și ''modules'' compilează imaginea kernel-ului și, respectiv, modulele selectate | ||
+ | * instalare; ex: ''headers_install'', ''module_install'', ... | ||
+ | * informații; ex: ''kernelrelease'', ''image_name'', ... | ||
+ | * //architecture dependent// - conține target-uri dependente de architectură, care diferă în funcție de arhitectura selectată; există target-uri pentru; | ||
+ | * generarea de imagini în diferite formate: compresate (''zImage'' și ''bzImage''), pentru U-Boot (''uImage''), ... | ||
+ | * generarea de configurări implicite pentru sisteme bazate pe arhitectura selectată; ex: ''*_defconfig'' | ||
- | {{:si:laboratoare:package-feeds.png?600|}} | + | <note> |
+ | Arhitectura care va fi compilată este selectată de variabila de mediu ''ARCH''. | ||
- | Fluxurile de pachete sunt un pas intermediar în procesul de construire a unei imagini. Sistemul de compilare Bitbake oferă clase pentru a genera diferite tipuri de pachete și astfel puteti specifica ce clase să activați prin intermediul variabilei **PACKAGE_CLASSES**. Înainte de a plasa pachetele în fluxuri de pachete, procesul de compilare le validează cu verificări generate de asigurarea calității rezultatelor prin clasa **insane.bbclass**. | + | <code shell> |
+ | $ ARCH=x86 make [<targets>] | ||
+ | sau | ||
+ | $ make ARCH=x86 [<targets>] | ||
+ | </code> | ||
+ | </note> | ||
- | Zona de alimentare a pachetelor se află în directorul de build, locul folosit pentru a stoca temporar pachetele este determinat de o combinație de variabile și de managerul de pachete specific utilizat. Consultați imaginea de mai sus și observati informațiile din dreapta imaginii. În special, următoarele definitii sunt relevante pentru păstrarea fișierele pachetului: | + | <note important> |
+ | Dacă arhitectura nu este setată explicit, se folosește implicit arhitectura sistemului pe care se face compilarea. | ||
+ | </note> | ||
- | * **DEPLOY_DIR**: Definit ca **tmp/deploy** în directorul de build. | + | În cele mai multe situații se dorește compilarea unui kernel pentru un sistem deja existent, fie pentru a adăuga sau elimina funcționalități sau pentru a actualiza versiunea de kernel folosită. În aceste cazuri folosirea target-urilor de generare a unei configurații noi, chiar și a celor care generează o configurație implicită pentru arhitectura noastră nu sunt neapărat utile. Este posibil ca kernel-ul existent să aibă deja o configurație personalizată care se dorește doar a fi actualizată/modificată folosind target-urile de editare. |
- | * **DEPLOY_DIR_***: În funcție de managerul de pachete utilizat, subdosarul tip pachet. Având în vedere ambalarea **RPM**, **IPK** sau **DEB** și crearea tarballului, sunt utilizate variabilele **DEPLOY_DIR_RPM**, **DEPLOY_DIR_IPK**, **DEPLOY_DIR_DEB** respectiv, **DEPLOY_DIR_TAR**. | + | Un kernel care rulează poate conține fișierul de configurare (de obicei în format comprimat //gzip//) din care a fost compilat, dacă această funcționalitate a fost selectată la build. Acest fișier se regăsește în ''/proc/config.gz''. Tot ce rămâne este să extragem acest fișier și să-l modificăm conform dorințelor. |
- | * **PACKAGE_ARCH**: Definește subfolderele specifice arhitecturii. De exemplu, pachetele ar putea fi disponibile pentru arhitecturile i586 sau qemux86. | + | ===== Device Tree Structure ===== |
- | BitBake folosește sarcinile //do_package_write_*// pentru a genera pachete și a le plasa în zona de depozitare a pachetelor (de exemplu, **do_package_write_ipk** pentru pachetele **IPK**). De exemplu, luați în considerare un scenariu în care este utilizat un manager de ambalare **IPK** și există suport pentru arhitectura de pachete atât pentru //i586//, cât și pentru //qemux86//. Pachetele pentru arhitectura //i586// sunt plasate în //build/tmp/deploy/ipk/i586//, în timp ce pachetele pentru arhitectura //qemux86// sunt plasate în //build/tmp/deploy/ipk/qemux86//. | + | Device Tree-ul este o structură de date, la nivelul kernel-ului, care descrie componentele hardware prezente pe sistem, care nu pot fi descoperite automat de kernel. El este prezent pe sistemele cu arhitecturi ARM, dar și pe alte sisteme (nu pe cele care se bazează pe arhitectura x86). Fiecare intrare a device tree-ului descrie o componentă individuală. |
- | <note>Consultați secțiunile [[https://docs.yoctoproject.org/ref-manual/tasks.html#ref-tasks-package-write-deb|„do_package_write_*”]] asociata din manualul de referință al proiectului Yocto pentru informații suplimentare.</note> | + | Device Tree-ul este stocat în 2 fișiere: ''.dtb'' (device tree blob), în format binar, și ''.dts'' (device tree source), în format text. Ambele tipuri de fișiere se găsesc în ''arch/<arhitectură>/boot/dts'', fiind generate de target-ul ''dtbs'' al comenzii ''make''. |
- | ===== Grup de pachete ===== | + | ===== Testare ===== |
- | Pentru imagini personalizate complexe, cea mai bună abordare pentru personalizarea unei imagini este crearea unei rețete de grup de pachete personalizate care este utilizată pentru a construi imaginea sau imaginile. Un bun exemplu de rețetă de grup de pachete este //meta/recipes-core/packagegroups/packagegroup-base.bb//. | + | Pentru a testa un nou kernel acesta trebuie instalat pe //target//. Această procedură diferă de la sistem la sistem, iar pe RaspberryPi constă în copierea acestuia pe card-ul SD în partiția de //boot// sub numele de ''kernel8.img''. În momentul dezvoltării și testării unui nou kernel, instalarea fiecărei versiuni a acestuia pe //target// reprezintă un bottleneck major. |
- | Dacă examinați acea rețetă, vedeți că variabila **PACKAGES** listează pachetele de grup de pachete de produs. Declarația **inherit packagegroup** setează valori implicite adecvate și adaugă automat pachetele complementare //-dev//, //-dbg// și //-ptest// pentru fiecare pachet specificat în instrucțiunea **PACKAGES**. | + | O alternativă la instalarea kernel-ului pe //target// o reprezintă încărcarea acestuia prin rețea direct pe de //host//-ul folosit la dezvoltare, dacă există suport din partea bootloader-ului. Din păcate, bootloader-ul implicit de pe RaspberryPi nu are suport pentru a încărca o imagine de kernel de pe rețea. Un bootloader care oferă însă acestă facilitate este //U-Boot// [[#referinte| [2]]], el folosind protocolul TFTP pentru a boota o imagine de kernel prin rețea. |
- | <note>Instructiunea **inherit packages** ar trebui să fie situate în partea de sus a rețetei, cu siguranță înainte de instrucțiunea **PACKAGES**.</note> | + | ===== Instalare pachete/programe din surse ===== |
- | Pentru fiecare pachet pe care îl specificați în **PACKAGES**, puteți utiliza intrările **RDEPENDS** și **RRECOMMENDS** pentru a furniza o listă de pachete pe care ar trebui să le conțină pachetul de sarcini părinte. Puteți vedea exemple ale acestora mai jos în rețeta //packagegroup-base.bb//. | + | De multe ori ne lovim de problema instalării unui pachet sau a unui program pe care îl găsim doar pe un repository public, de cele mai multe ori bazat pe Git. Astfel, pentru a ne putea folosi de acel pachet/program, trebuie să cunoaștem următoarele utilitare: |
- | Iată un exemplu scurt, care arată configuratia de bază pentru acest grup de pachete: | + | ==== Git ==== |
- | <code> | + | Opțiuni și comenzi git: |
- | DESCRIPTION = „Grupul meu personalizat de pachete” | + | |
- | inherit packagegroup | + | - ''git clone //<repo>//'' - va aduce toate fișierele conținute de repository-ul //repo// pe mașina locală. |
+ | - ''git pull'' - actualizează un repository deja clonat local la ultima versiune remote. | ||
+ | - ''git checkout //<branch>//'' sau ''git checkout //<tag>//'' - actualizează fișierele locale la versiunea indicată de //branch// sau de //tag//. Un repository poate avea mai multe branch-uri, care pot fi văzute ca niște versiuni diferite ale repository-ului. Un exemplu uzual de folosire a branch-urilor este pentru organizarea diferitelor versiuni ale aceluiași program. | ||
+ | - ''git apply //<patch file>//'' - aplică pe fișierele locale modificările conținute de fișierul //patch//. | ||
- | PACKAGES = "\ | ||
- | ${PN}-apps \ | ||
- | ${PN}-tools \ | ||
- | " | ||
- | RDEPENDS:${PN}-apps = "\ | ||
- | dropbear \ | ||
- | portmap \ | ||
- | psplash" | ||
- | RDEPENDS:${PN}-tools = "\ | + | ====== Exerciții ====== |
- | oprofile \ | + | |
- | oprofileui-server \ | + | |
- | lttng-tools" | + | |
- | RRECOMMENDS:${PN}-tools = "\ | + | **0.** Pregăriri |
- | kernel-module-oprofile" | + | |
- | </code> | + | |
- | + | ||
- | În exemplul anterior, două pachete de grup de pachete sunt create cu dependențele lor și dependențele recomandate de pachete dupa cum urmeaza: **packagegroup-custom-apps** și **packagegroup-custom-tools**. Pentru a construi o imagine folosind aceste pachete de grup de pachete, trebuie să adăugați **packagegroup-custom-apps** și/sau **packagegroup-custom-tools** la **IMAGE_INSTALL**. | + | |
- | ===== Module de kernel ===== | + | <hidden> |
+ | * **Pentru asistenți:** descărcați [[https://github.com/cs-pub-ro/SI-rpi-debian-scripts/releases|de aici imaginea 'rpi-full.img' pentru Raspberry PI (v2)]] și scrieți-o pe Raspberry PI folosind un disk imager (ori cu un card reader, ori bootați un U-Boot, schimbați cardul SD, ''mmc rescan'', apoi ''ums mmc 0'' (găsiți disk-ul accesibil de pe calculatorul la care e conectat prin USB Type-C). | ||
+ | </hidden> | ||
- | Deși este întotdeauna de preferat să lucrați cu surse integrate în sursele kernel-ului Linux, dacă aveți nevoie de un modul kernel extern, rețeta //hello-mod.bb// este disponibilă ca șablon din care vă puteți crea propriul modul de kernel Linux disponibil separat de reteta de kernel deja existenta in layer-ul de BSP mostenit. | + | * Descarcati ultima varianta de kernel Linux pentru Raspberry Pi, de [[https://github.com/raspberrypi/linux.git|aici]]. <code> |
+ | git clone https://github.com/raspberrypi/linux.git --depth=1</code> | ||
- | <note>Această rețetă șablon se află în repo-ul git al lui Poky din proiectului Yocto: [[https://git.yoctoproject.org/poky/tree/meta-skeleton/recipes-kernel/hello-mod/hello-mod_0.1.bb|meta-skeleton/recipes-kernel/hello-mod/hello-mod_0.1.bb]]</note> | + | * Instalati pachetele necesare: <code> |
+ | apt-get install -y bc bison flex libssl-dev libc6-dev libncurses5-dev crossbuild-essential-arm64 </code> | ||
- | Pentru a începe, copiați această rețetă în layer-ul dvs. și dați-i un nume semnificativ (de exemplu, //mymodule_1.0.bb//). În același director, creați un director nou numit //files// în care puteți stoca orice fișiere sursă, patch-uri sau alte fișiere necesare pentru construirea modulului care nu vin cu sursele. În cele din urmă, actualizați rețeta după cum este necesar pentru modul. De obicei, va trebui să setați următoarele variabile: **DESCRIPTION**, **LICENSE***, **SRC_URI**, **PV** etc. | + | * Generati configurarea implicita a kernel-ului (tip: defconfig). <code> |
- | + | cd linux/ | |
- | În funcție de sistemul de build utilizat de sursele modulelor, este posibil să fie nevoie să faceți unele ajustări. De exemplu, un modul tipic //Makefile// seamănă mult cu cel furnizat cu șablonul //hello-mod//: | + | export KERNEL=kernel8 |
- | + | make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- bcm2711_defconfig | |
- | <code> | + | </code> |
- | obj-m := hello.o | + | |
- | + | ||
- | SRC := $(shell pwd) | + | |
- | all: | + | * Modificati din ''menuconfig'' numele imaginii de kernel. |
- | $(MAKE) -C $(KERNEL_SRC) M=$(SRC) | + | |
- | modules_install: | + | <note tip>Lansati meniul pentru arhitectura selectata anterior:<code> |
- | $(MAKE) -C $(KERNEL_SRC) M=$(SRC) modules_install | + | make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- menuconfig |
- | ... | + | |
</code> | </code> | ||
+ | Optiunea se afla in General Setup -> Local Version</note> | ||
- | Punctul important de remarcat aici este variabila **KERNEL_SRC**. Clasa **module** setează această variabilă și variabila **KERNEL_PATH** la **${STAGING_KERNEL_DIR}** cu informațiile necesare de construire a kernel-ului Linux pentru a construi module. Dacă modulul //Makefile// folosește o variabilă diferită, poate doriți să înlocuiți pasul //do_compile// sau să creați un patch pentru //Makefile// pentru a lucra cu variabilele **KERNEL_SRC** sau **KERNEL_PATH** mai tipice. | + | * Verificati daca driver-ul de mmc este activat (nu ca modul). |
- | După ce ați pregătit rețeta, probabil că veți dori să includeți modulul în imagini. Pentru a face acest lucru, consultați documentația pentru următoarele variabile din manualul de referință al proiectului Yocto și setați una dintre ele în mod corespunzător pentru fișierul de configurare a mașinii dvs.: | + | <note tip>Trebuie sa vedeti ''MMC [=y]'' </note> |
- | * MACHINE_ESSENTIAL_EXTRA_RDEPENDS | + | * Compilati nucleul, device tree blob-urile si modulele de nucleu. <code> |
- | * MACHINE_ESSENTIAL_EXTRA_RRECOMMENDS | + | make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- Image Image.gz modules dtbs -j$(nproc)</code> |
- | * MACHINE_EXTRA_RDEPENDS | + | |
- | * MACHINE_EXTRA_RRECOMMENDS | + | |
- | Modulele nu sunt adesea necesare pentru pornire și pot fi excluse din anumite configurații de build. Următoarea optiune oferă cea mai mare flexibilitate: | + | <note important>Procesul de compilare va dura destul de mult. Daca folositi o masina virtuala, dati-i cat mai multe nuclee, pentru a reduce timpul</note> |
- | <code> | + | |
- | MACHINE_EXTRA_RRECOMMENDS += „kernel-module-mymodule” | + | |
- | </code> | + | |
- | Valoarea este derivată prin adăugarea numelui de fișier al modulului fără extensia **.ko** la șirul **„kernel-module-“**. | + | |
- | Deoarece variabila este **RRECOMMENDS** și nu o variabilă **RDEPENDS**, compilarea nu va eșua dacă acest modul nu este disponibil pentru a fi inclus în imagine. | + | * Cat se compileaza nucleul, inspectati fisierul ''.dts'' corespunzator placii RaspberryPI 4B. <code> |
+ | arch/arm64/boot/dts/broadcom/bcm2711-rpi-4-b.dts</code> | ||
+ | * Kernelul nostru experimental se instalează folosind următorii pași: <code> | ||
+ | # se presupune că aveți deja montate imaginea / cardul SD al RPi-ului (citiți mai jos!) | ||
+ | sudo env PATH=$PATH make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- INSTALL_PATH=<path_catre_partitia_de_boot> install | ||
+ | sudo env PATH=$PATH make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- INSTALL_MOD_PATH=<path_catre_partitia_de_rootfs> modules_install | ||
- | ===== Exercitii ===== | + | # Notă: nu suprascrieți device tree-ul deoarece o versiune greșită ar strica u-boot-ul :D |
- | * Adaugati suport pentru serverul web python-flask | + | # Dar așa s-ar copia: |
- | * Folosind examplul de mai sus si referinta [[https://github.com/davidscholberg/merandom|merandom]] creati o reteta cu un modul kernel care scrie un caracter random in ///dev/merandom// | + | #sudo cp arch/arm64/boot/dts/broadcom/bcm2711-rpi-4-b.dtb <path_catre_partitia_de_boot>/ |
- | * Creati o aplicatie Python care preia datele de pe device si le expune pe un server web local | + | #sudo cp arch/arm64/boot/dts/overlays/bcm2711-rpi-4-b.dtb* <path_catre_partitia_de_boot>/overlays/ |
- | * (Bonus) Creati un packagegroup pentru aceste pachete create. | + | |
- | <hidden> | + | # Redenumim imaginea de kernel (e deja cea compresata) |
- | <code> | + | sudo mv <path_catre_partitia_de_boot>/vmlinuz-<versiunea-noua> <path_catre_partitia_de_boot>/vmlinuz-student |
- | git clone https://github.com/openembedded/meta-openembedded.git | + | |
- | git checkout kirkstone | + | |
- | bitbake-layers create-layer meta-lab8-si | + | # Demontam partitiile |
- | bitbake-layers add-layer meta-lab8-si | + | sudo umount <path_catre_partitia_de_boot> |
- | bitbake-layers add-layer ../layers/meta-openembedded/meta-oe/ | + | sudo umount <path_catre_partitia_de_rootfs> |
- | bitbake-layers add-layer ../layers/meta-openembedded/meta-python/ | + | |
- | mkdir -p recipes-core/images | + | # Oprim ums |
- | touch recipes-core/images/core-image-base.bbappend | + | </code> |
- | require recipes-core/images/core-image-base.bb | + | |
- | IMAGE_INSTALL += " python3-flask" | + | |
- | IMAGE_INSTALL += " openssh" | + | |
- | IMAGE_INSTALL += " avahi-daemon | + | |
- | bitbake core-image-base | + | |
- | mkdir recipes-kernel/ | + | * **Notă**: dacă aveți probleme cu USB device passthrough-ul pe Raspberry PI, este suficient să copiem DOAR fișierul vmlinuz pe partiția de boot, cea FAT32. Pentru aceasta, bootați-l în modul ''ums'' din U-Boot, conectat la USB Type-C) și copiați DOAR fișierul ''arch/arm64/boot/Image.gz'' sub numele de ''vmlinuz-student''. |
- | cp layers/poky/meta-skeleton/recipes-kernel/hello-mod/ recipes-kernel/ | + | |
- | mv recipes-kernel/hello-mod/ recipes-kernel/merandom-mod/ | + | |
- | mv recipes-kernel/merandom-mod/metarandom-mod_0.1.bb recipes-kernel/merandom-mod/merandom-mod_0.1.bb | + | |
- | LICENSE = "GPL-3.0" | + | |
- | LIC_FILES_CHKSUM = "file://LICENSE;md5=d32239bcb673463ab874e80d47fae504" | + | |
- | SRC_URI = "git://github.com/davidscholberg/merandom \ | + | <note tip>Pentru a porni ums, urmati urmatorii pasi: |
- | file://0001-Update-support-to-match-Yocto-environment.patch | + | * conectati adaptorul de seriala la laptop |
- | " | + | * ''picocom /dev/ttyUSB0 -b 115200'' |
- | SRCREV = "9faf489cc3d38bff1aec4f0516ab795c624073e1" | + | * conectati cablu de alimentare |
- | S = "${WORKDIR}/git" | + | * la un moment dat va aparea **Hit any key to stop autoboot:**; apasati orice tasta |
- | cat files/0001-Update-support-to-match-Yocto-environment.patch | + | * daca nu ati intrat in meniul de U-Boot, apasati Ctrl-C |
- | From 77dc528f4206ddc3e650bcb9578f1e8fbd60d2b0 Mon Sep 17 00:00:00 2001 | + | * din meniul de U-Boot, dati comanda ''ums mmc 0'' |
- | From: Alex Vaduva <jan.vaduva@upb.ro> | + | * partitiile ar trebui sa fie vizibile: **/dev/sda1**(root) si **/dev/sda2**(rootfs) |
- | Date: Mon, 5 Dec 2022 01:20:03 +0200 | + | * daca nu vi le monteaza sistemul de operare automat, montati-le |
- | Subject: [PATCH] Update support to match Yocto environment | + | </note> |
- | Signed-off-by: Alex Vaduva <jan.vaduva@upb.ro> | + | <note important> |
- | --- | + | U-boot din imaginea nouă este configurat să booteze automat ''vmlinuz-student'', dacă există! |
- | Makefile | 11 +++++++++-- | + | |
- | merandom.c | 15 +++------------ | + | |
- | merandom.mod | 2 ++ | + | |
- | 3 files changed, 14 insertions(+), 14 deletions(-) | + | |
- | create mode 100644 merandom.mod | + | |
- | diff --git a/Makefile b/Makefile | + | Acesta va aștepta 10 secunde, permițând să întrerupeți procesul pentru a putea re-accesa modul ''ums'' pentru a rescrie imaginea pe viitor. |
- | index 88ff7bb..c607a29 100644 | + | |
- | --- a/Makefile | + | |
- | +++ b/Makefile | + | |
- | @@ -1,7 +1,14 @@ | + | |
- | obj-m += merandom.o | + | |
- | +SRC := $(shell pwd) | + | Puteți vedea [[https://github.com/cs-pub-ro/SI-rpi-debian-scripts/blob/labsi/configs/labsi-rpi4/files/uboot-script.txt|codul sursă al scriptului de u-boot aici]]. |
- | + | + | </note> |
- | all: | + | |
- | - make -C $(KDIR) M=$(PWD) modules | + | |
- | + $(MAKE) -C $(KERNEL_SRC) M=$(SRC) | + | |
- | + | + | |
- | +modules_install: | + | |
- | + $(MAKE) -C $(KERNEL_SRC) M=$(SRC) modules_install | + | |
- | clean: | + | * Porniti RaspberryPI-ul cu noua versiune, ca in [[https://ocw.cs.pub.ro/courses/si/laboratoare/06#exercitii|laboratorul 6]]. |
- | - make -C $(KDIR) M=$(PWD) clean | + | |
- | + rm -f *.o *~ core .depend .*.cmd *.ko *.mod.c | + | |
- | + rm -f Module.markers Module.symvers modules.order | + | |
- | + rm -rf .tmp_versions Modules.symvers | + | |
- | diff --git a/merandom.c b/merandom.c | + | |
- | index 02129fd..ff6d674 100644 | + | |
- | --- a/merandom.c | + | |
- | +++ b/merandom.c | + | |
- | @@ -199,18 +199,9 @@ static int __init merandom_init(void) | + | |
- | static void __exit merandom_exit(void) | + | <note warning> |
- | { | + | Dacă nu ați copiat modulele externe pe rootfs-ul de pe Raspberry PI al noului kernel, Linux se va plânge când bootează că lipsesc o parte din modulele necesare de anumite dispozitive hardware / software non-esențiale (//ahem: multe sunt, defapt, necesare pentru a avea suport pentru rețelistică în Linux//), însă procesul de boot ar trebui să se finalizeze. |
- | - int ret; | + | </note> |
- | - | + | |
- | - ret = misc_deregister(&merandom_miscdev); | + | |
- | - if (ret) { | + | |
- | - pr_err("%s: misc_deregister failed: %d\n", MERANDOM_DEV_NAME, | + | |
- | - ret); | + | |
- | - } else { | + | |
- | - pr_info("%s: unregistered\n", MERANDOM_DEV_NAME); | + | |
- | - pr_info("%s: deleted /dev/%s\n", | + | |
- | - MERANDOM_DEV_NAME, | + | |
- | - MERANDOM_DEV_NAME); | + | |
- | - } | + | |
- | + misc_deregister(&merandom_miscdev); | + | |
- | + pr_info("%s: unregistered\n", MERANDOM_DEV_NAME); | + | |
- | + pr_info("%s: deleted /dev/%s\n", MERANDOM_DEV_NAME, MERANDOM_DEV_NAME); | + | |
- | } | + | |
- | module_init(merandom_init); | + | ====== Referințe ====== |
- | diff --git a/merandom.mod b/merandom.mod | + | |
- | new file mode 100644 | + | |
- | index 0000000..89116e5 | + | |
- | --- /dev/null | + | |
- | +++ b/merandom.mod | + | |
- | @@ -0,0 +1,2 @@ | + | |
- | +/home/student/yocto/build/tmp/work/qemuarm-poky-linux-gnueabi/merandom-mod/0.1-r0/git/merandom.o | + | |
- | + | + | |
- | -- | + | |
- | 2.34.1 | + | |
- | bitbake merandom-mod | + | - [[https://www.raspberrypi.com/documentation/computers/linux_kernel.html| Ghid compilare kernel RaspberryPi]] |
+ | - [[https://www.thegoodpenguin.co.uk/blog/build-boot-linux-on-raspberry-pi-3-model-b/| Ghid compilare U-Boot pentru RaspberryPi]] | ||
- | </code> | ||
- | |||
- | |||
- | </hidden> |