Differences

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

Link to this comparison view

si:laboratoare:09 [2022/12/13 18:36]
florin.stancu [Exerciții]
si:laboratoare:09 [2024/10/27 09:23] (current)
florin.stancu created
Line 1: Line 1:
-====== Laboratorul 09. Kernel ​======+====== Laboratorul 09. RootFS Bootstrapping ​======
  
-Kernel-ul reprezintă o parte a sistemului de operare responsabilă cu accesul la hardware și managementul dispozitivelor dintr-un sistem de calcul (ex: procesoul, 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.+===== Crearea unei distribuții Linux =====
  
-| {{ :​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]}} | +Până acum am folosit Root Filesystem ​de-a gata pre-instalat.
-^ Architectura unui sistem de operare ^+
  
-Pentru a îndeplini toate aceste sarcini, codul kernel-ului rulează într-un mod special de lucru al procesoruluifapt 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).+La acest laboratordorim să învățăm procesul ​de generare a unui sistem de bază și modalitățile de personalizare a acestuiaproces numit **rootfs bootstrapping**.
  
-===== Linux =====+Avem 2 variante: 
 +  * plecarea de la o distribuție existentă și alegerea pachetelor pe care să le includem + configurații specifice;​ 
 +  * compilarea (manuală sau automată) a tuturor componentelor unui astfel de sistem;
  
-Linux este numele unui kernel creat de către Linus Torvaldscare stă la baza tuturor distribuțiilor GNU/Linux. Inițialel 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-calculatoareAceastă versatilitatecât și numărul mare de arhitecturi și de periferice suportate, îl face ideal ca bază pentru ​un sistem embedded.+Prima soluție, ​deși mult mai facilă (atât rapidă, cât și ușor de înțeles)nu ne permite o optimizare ​spațiului utilizat (sisteme bazate pe Debian ocupă de ordinul ''​~1GB''​) și nici fine-tuningul ulterior ​pentru ​îmbunătățirea performanțelor ​în cazul rulării pe anumite ​dispozitive ​(e.g., ARMv8 cu extensii NEON pentru ​SIMD).
  
-<​note>​ +Pe de altă parte, dacă am dori să facem asta de la zero, ar trebui să plecăm de la un toolchain (pe care, de cele mai multe ori, trebuie să-l compilăm tot noi), pe care îl vom folosi să compilăm din cod sursă toate componentele necesare într-un sistem ​Linux: biblioteci standard (LibC), sistem de init (SystemV / SystemD / OpenRC etc.), suita de programe de bază Unix (e.g., ​''​mount''​, ''​cat'',​ ''​ls'',​ ''​cp'',​ ''​sh'',​ ''​awk''​ și multe altele!), device manager (''​udev''​) precum și multe alte servicii (e.g., de networking) și aplicații necesare scopului nostru final (e.g., Python, X11 + QT Toolkit pentru interfețe grafice etc.).
-Arhitecturile suportate ​de kernel-ul Linux se pot afla listând conținutul directorului ​''​arch'' ​din cadrul surselor. +
-</​note>​+
  
-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 modulelorAstfel, putem avea disponibile o multime de drivere, însă cele care nu sunt folosite des nu vor fi încarcate și nu vor rulaSpre 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.+Din fericireexistă suite software ​([[https://​www.yoctoproject.org/|Yocto Linux]][[https://buildroot.org/|Buildroot]]care pot automatiza repetabil acest proces. Însă ​un dezavantaj tot rămâne: timpul de compilare este de ordinul orelor, iar spațiul pe disk necesar între ''​20GB ​-- 50GB''​.
  
-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]]. 
  
-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.+===== Exerciții =====
  
-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.+Pentru acest laborator, vom încerca ambele abordări!
  
-<​note>​ +==== 1. Crearea de distribuții bazate ​pe Debian (debootstrap) ====
-Kernel-ul folosit ​pe RaspberryPi,​ care include suportul pentru SoC-ul Broadcom BCM2385 folosit de acesta, se găsește la adresa [[https://​github.com/​raspberrypi/​linux.git]]. +
-</​note>​+
  
-===== Linux kernel build system =====+Pentru a genera distribuții personalizate bazate pe Debian (și derivate, e.g., Ubuntu), se poate folosi utilitarul ''​debootstrap''​.
  
-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-ulbazat 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//.+Acesta descarcă automat din repository-uri pachetele ''​.dpkg''​pe care le instalează într-un prefix (director) precizat de utilizatore.g.: 
 +<code shell> 
 +# Sfat: încă nu rulați (veți aștepta mult și vă va da o eroare la final). Vedeți mai jos cauza + soluția! 
 +$ sudo debootstrap --verbose --arch="​arm64"​ --include="​netbase,​vim,​bash,​curl"​ \ 
 +        --variant=minbase "​bookworm"​ "/root/mydebian/" "http://ftp.de.debian.org/debian"​ 
 +</code>
  
-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.+Puteți alege [[https://www.debian.org/​mirror/​list|alt mirror din lista oficială de aici]] (**recomandat!**). Alegeți la întâmplare o țară din Europa (să nu fiți toți pe același server că s-ar putea să facă throttling!).
  
 <note tip> <note tip>
-Target-ul ''​help''​ oferă informații despre aproape ​toate operațiile ​suportate ​de către sistemul ​de build+Aproape ​toate distribuțiile de Linux au câte un utilitar (de multe ori, chiar package managerul distribuției) care permite bootstrappingul RootFS-urilor din pachete (tot așa sunt generate și imaginile ISO live!)
- +Spre exemplu, Arch Linux are ''​pacstrap'',​ Alpine Linux are ''​apk.static''​ and so on...
-<code shell> +
-$ make help +
-</​code>​+
 </​note>​ </​note>​
  
-Operațiile oferite sunt grupate ​în diferite categorii+De menționat ar fi că instalarea unui pachet are loc în 2 etape
-  * //​cleaning//​ - conține target-uri pentru ștergerea ​fișierelor ​generate la compilare +  * decompresia arhivei (extragerea ​fișierelor ​din pachet ​în directorul rădăcină destinație)
-    * spre deosebire de ''​clean'',​ ''​mrproper''​ șterge ​în plus toate fișierele generate, plus configurarea și diferite fișiere de backup +  * rularea unor scripturi post-install pentru crearea configurațiilor implicite / upgrade fișiere / integrarea cu alte aplicații / instalarea serviciilor etc.;
-  * //​configuration//​ - conține diferite target-uri pentru generarea unei configurări a kernelului; există target-uri care permit: +
-    * generarea unui fișier de configurare nouex: ''​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''​+
  
-<​note>​ +Acest aspect devine important când încercăm să generăm un rootfs pentru o arhitectură străină celei gazdă (cross-bootstrapping)! 
-Arhitectura care va fi compilată este selectată de variabila ​de mediu ''​ARCH''​.+Pentru a realiza acest lucru, ​va trebui să distingem cele două etape: decompresia va putea avea loc direct pe host (avem utilitarele necesare instalate cu scriptul ​de bootstrapping),​ pe când etapa de execuție a programelor va trebui să fie virtualizată cumva (chroot + ''​qemu-user-static'' ​FTW).
  
 +Astfel, pentru a realiza ''​debootstrap''​ de pe o arhitectură Intel/AMD ''​x86_64''​ pentru o țintă AArch64 (ARM 64-bit):
 <code shell> <code shell>
-ARCH=x86 make [<​targets>​] +# a fost adăugat flag-ul `--foreign` în plus la comanda de debootstrap normală: 
-sau +sudo debootstrap --foreign --verbose --arch="​arm64"​ ... /​root/​mydebian ... # restul de argumente normale 
-make ARCH=x86 [<​targets>​]+# apoi copiem emulatorul în noua rădăcină (va fi rulat de binfmt_misc ca în Lab 04) 
 +sudo cp -af "​$(which qemu-aarch64-static)"​ /​root/​mydebian/​usr/​bin/​ 
 +# Acum va trebui să rulăm stagiul 2 al debootstrap,​ însă într-un container / chroot! 
 +# Folosim systemd-nspawn pentru a rula binarul de second-stage instalat pe rootfs de la primul: 
 +$ sudo systemd-nspawn --as-pid2 --resolv-conf=copy-host -D /​root/​mydebian \ 
 +    /​debootstrap/​debootstrap --second-stage --verbose
 </​code>​ </​code>​
-</​note>​ 
  
-<​note ​important> +<​note>​Este posibil ca descărcarea să dureze cevaîn funcție de viteza de conectare la Internet + mirror-ul ales.</​note>​
-Dacă arhitectura nu este setată explicitse folosește implicit arhitectura sistemului pe care se face compilarea. +
-</​note>​+
  
-Î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ățsau pentru a actualiza versiunea de kernel folosită. În aceste cazuri folosirea target-urilor de generare ​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+Tehnica cu systemd-nspawn + qemu-user-static (și binfmt_misc) este utilă ​pentru a intra într-un chroot pe rootfs-ul nostru pentru ​a-l personaliza (putem ​chiar și instala programe noi sau configura ​servicii etc.). Însă va trebui configurat programul de gestionat de pachetele, ''​apt'':​ de adăugat mirror-uri la repo-urile de bază (și cele extinse, de preferat) în ''​/etc/​apt/​sources.list'' ​-- [[https://​wiki.debian.org/​SourcesList#​Example_sources.list|găsiți exemplu aici]].
  
-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ționalitatea 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 -l modificăm conform dorințelor.+**Atenție:** momentan, rootfs-ul NU ARE parolă la contul ''​root'' ​(și nu are nici un alt cont) și nu vă veți putea autentifica din niciun ​//tty//
 +Se recomandă accesarea unui chroot (rulaț''/​usr/bin/bash'' ​ca ultim argument al lui ''​systemd-nspawn''​) ​și setarea uneia prin ''​passwd'':​ 
 +<code shell> 
 +host$ sudo systemd-nspawn --as-pid2 --resolv-conf=copy-host -D /​root/​mydebian bash 
 +root@debian$ passwd root 
 +root@debian$ apt update && apt install -y wget curl # nu le vom folosi, dar exemplu :P 
 +</​code>​
  
-===== Device Tree Structure =====+O dată generat rootfs-ul, acesta trebuie copiat (atenție să nu se piardă permisiunile și atributele unor fișiere speciale -- mai ales symlink-urile) pe o partiție și bootat! Se recomandă arhivarea acestuia folosind utilitarul ''​tar''​ (acesta salvând automat metadatele necesare în arhivă):<​code shell> 
 +$ tar czf mydebian.tar.gz -C /​root/​mydebian . 
 +</​code>​
  
-Device Tree-ul este o structura 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 si pe alte sisteme (nu pe cele care se bazeaza pe arhitectura x86). Fiecare intrare a device tree-ului descrie o componenta individuala.+În final, dorim să vedem cât ocupă rootfs-ul nostru: 
 +<code shell> 
 +$ du -hs /​root/​mydebian 
 +</​code>​
  
-Un exemplu de intrare, prezenta in Device Tree-ul specific placii VersatilePB,​ este urmatorul:+<note tip> 
 +Vom trece să instalăm + rulăm sistemul pe un Raspberry PI 4 fizic imediat ce pornim compilarea unui sistem Buildroot ;) 
 +</​note>​
  
- uart@9000 { +==== 2. Compilarea programelor de bază (buildroot) ====
- compatible ​"​arm,​pl011",​ "​arm,​primecell";​ +
- reg <0x9000 0x1000>;​ +
- interrupt-parent ​<&​sic>;​ +
- interrupts ​<​6>;​ +
- clocks ​<&​xtal24mhz>,​ <&​pclk>;​ +
- clock-names ​"​uartclk",​ "​apb_pclk";​ +
- };+
  
-Intrarea este specifica ​unui modul de UART, care se afla la adresa 0x9000. Aceasta indica adresa registrelor,​ numarul ​de intreruperi disponibile,​ ceasurile existente si componenta hardware care gestioneaza intreruperile.+Mai departe, descriem procesul de utilizare al unui utilitar destul ​de popular (cel mai important fiind ușurința ​de învățare față de Yocto Linux).
  
-Device Tree-ul este stocat in 2 fisiere: ''​.dtb''​ (device tree blob), in format binar, si ''​.dts''​ (device tree source), in format text. Ambele tipuri de fisiere se gasesc in ''​arch/​<arhitectura>/​boot/​dts''​fiind generate ​de target-ul ​''​dtbs''​ al comenzii ''​make''​.+<note warning> 
 +Din păcatevom avea nevoie ​de aproximativ ​''​~20-30GB'' ​de spațiu disponibil (în mașina virtuală).
  
-===== Testare =====+Cel mai simplu este să creați un Virtual HDD nou de ''​30GB''​ (**nu îi pre-alocați** spațiul, deoarece nu va ajunge să ocupe atât azi -- poate la temă :P ) și atașați-l proiectului VirtualBox / VMWare ca dispozitiv de stocare suplimentar (din setări / storage, add [hard] disk pe ambele hipervizoare). 
 +Apoi va trebui formatat + montat din VM: ''​mkdir /media/big && mkfs.ext4 /​dev/​sd<​X>​ && mount /​dev/​sd<​X>​ /​media/​big''​. 
 +O idee bună ar mai fă să creați director de lucru pentru ''​student'':​ ''​mkdir /​media/​big/​work && chown student:​student /​media/​big/​work -R''​.
  
-Pentru a testa un nou kernel acesta trebuie instalat pe //target//. Această procedură diferă de la sistem la sistemiar pe RaspberryPi constă în copierea acestuia pe card-ul SD în partiția de //boot// sub numele de ''​kernel.img''​. În momentul dezvoltării ștestării unui nou kernel, instalarea fiecărei versiuni a acestuia pe //target// reprezintă un bottleneck major.+De asemenea, tot acum ar fi momentul să alocați memorie RAM mai multă (3-6GBdacă avețde unde) aproape câte nuclee aveți procesorului virtualizat (să se paralelizeze procesul). 
 +Și să conectațlaptop-ul la 230V ;) 
 +</note>
  
-O alternativă la instalarea kernel-ului pe //​target// ​reprezintă încărcarea acestuia prin rețea direct pe de //host//-ul folosit la dezvoltare, dacă există suport din partea bootloader-uluiDin 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.+Spre deosebire de ''​debootstrap'',​ care avea nevoie de drepturi de ''​root'',​ aceste utilitare folosesc principiul de ''​fake root''​ (metadatele sistemului de fișiere sunt virtualizate într-o bază de date externă kernelului),​ fiind utilizabile (uneori obligatoriu) și de către conturi non-superuserAproape toți pașii va trebui să-i urmați autentificați ca ''​student''​!
  
-===== Instalare pachete/programe din surse =====+Primul pas, ar fi, desigur descărcarea lui ''​buildroot''​. Alegeți o versiune de la [[https://​buildroot.org/​downloads/​]] și descărcați-o + dezarhivați-o (sub contul student și pe HDD-ul mare!)<​code shell> 
 +$ wget https://​buildroot.org/​downloads/​buildroot-2023.08.tar.xz 
 +$ tar xf ... 
 +$ cd buildroot-* 
 +</​code>​
  
-De multe ori ne lovim de problema instalării unui pachet sau a unui program pe care îl găsim doar pe un repository publicde cele mai multe ori bazat pe GitAstfel, pentru a ne putea folosi de acel pachet/​program,​ trebuie să cunoaștem următoarele ​utilitare:+Utilitarul Buildroot folosește mecanismul Kconfig (la fel ca U-Boot și kernel-ul Linux)deci: ''​make menuconfig''​. 
 +Navigați prin meniuri ​și schimbați ​următoarele ​opțiuni:
  
-==== Git ====+  * ''​Target Options'' ​=> ''​Target Architecture'' ​=> ''​AArch64 (little endian)'';​ 
 +  * ''​Target Options'' ​=> ''​Target Architecture Variant'' ​=> ''​cortex-A53''​ (pentru compatibilitate sporită cu mai multe modele Raspberry PI + Qemu); 
 +  * ''​Target Options'' ​=> ''​Floating point strategy'' ​=> ''​VFPv4''​ (la fel, compatibilitate sporită);​ 
 +  * ''​Toolchain'' ​=> ''​Enable compatibility shims ...'';​ 
 +  * ''​System Configuration'' ​=> ''​Root password''​ => ''​student''​ -- pentru a ne putea autentifica în shell! 
 +  * ''​Filesystem images''​ => ''​Compression method''​ => ''​gzip''​ -- opțional, imaginea ocupă extrem de puțin oricum.
  
-Opțiuni școmenzi git: +Apoi rulați ''​make''​! Procesul poate dura între 10 minute ​și 1h, în funcție de numărul de nuclee, frecvența lor (ce poate fi scăzută dacă suntețpe baterieși memoria RAM disponibilă.
- +
-   ​- ​''​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//​. +
- +
- +
- +
-====== Exerciții ====== +
- +
-  * Descarcati ultima varianta de kernel Linux pentru Raspberry Pi, de [[https://​github.com/​raspberrypi/​linux.git|aici]]. +
-  * Verificati ce tip de procesor este pe Raspberry PI. ''​armv7''​ este pe 32 de biti, ''​armv8''​ este pe 64 de biti. +
-  * Instalati pachetele ''​bc'',​ ''​bison'',​ ''​flex'',​ ''​libssl-dev'',​ ''​libc6-dev'',​ ''​libncurses5-dev'',​ ''​crossbuild-essential-armhf''​ sau ''​crossbuild-essential-arm64'',​ in functie de tipul procesorului. +
-  * Generati configurarea implicita a kernel-ului pentru arhitectura procesorului de pe RPI (tip: defconfig)+
-  * Eliminat suportul pentru ''​virtio drivers''​ si adaugati suport pentru driver-ul PL061, ca modul de nucleu (tip: menuconfig, tasta / pentru cautarea unei optiuni) +
-  * Compilati nucleul, device tree blob-urile si modulele de nucleu (tip: (z)Image, modules, dtbs). +
-  * Verificati ca noul nucleu este bun, folosind QEMU (tip: revedeti laboratorul 3) +
-  * Adaugati noul nucleu pe Raspberry PI si faceti configurarile necesare pentru a fi folosit dupa restart.+
  
 <note tip> <note tip>
-  * puteti urmari ghidul oficial al celor de la Raspberry PI: [[https://www.raspberrypi.com/documentation/​computers/​linux_kernel.html]] +Distribuția ​de bază Buildroot include doar utilitarele ce vin cu [[https://busybox.net/|busybox]]. 
-  * la compilare dati cat mai multe nuclee de procesor make-uluipentru a reduce timpul de compilarecu optiunea ''​-j''​. +Avețiînsăo mulțime de pachete ​de aplicații ​pe care le puteți bifa la secțiunea ​''​Target packages''​!
-  * nu stergeti vechiul nucleu ​de pe Raspberry PI; adaugati noul nucleu cu alt nume, si modificati kernel-ul folosit in fisierul ​''​/​boot/​config.txt''​ +
-  * imaginea de nucleu compilata este in ''​arch/​arm/​boot''​ +
-  * device tree blob-urile sunt in ''​arch/​arm/​boot/​dts''​ +
-</​note>​+
  
-<note tip> +Însă acest lucru va duce la o mărire drastică ​timpului ​de compilare + consum ​de spațiu pe disk (în funcție de ce câte pachete + câte dependințe au)!
-Pentru ​reduce timpul ​de download, puteti descarca doar o anumita versiune ​de kernel<​code bash> +
-mkdir linux +
-cd linux +
-git init +
-git remote add origin <adresa repo> +
-git fetch --depth 1 origin <​versiune>​  +
-# eg: git fetch --depth 1 origin rpi-5.15.y +
-git checkout rpi-5.15.y +
-</code> +
- +
-Pentru a putea vedea alta versiune, trebuie facut fetch pentru ea, in mod similar+
 </​note>​ </​note>​
  
-<note important>​ +**Nu așteptați! lăsați-l să ruleze și treceți la task-ul următor ;)**
-Nu utiati ​sa folositi variabliele ARCH si CROSS_COMPILE cand rulati ''​make''​ +
-</​note>​+
  
-<​ifauth>​ +La final, să inspectați sistemul de fișiere rezultat, îl găsiți la calea ''<​buildroot-dir>/​output/​images/''​. Cât ocupă?
-<​hidden>​ +
-3. Compilați și rulați pe Qemu o versiune a kernel-ului, urmărind instrucțiunile de mai jos:+
  
-<​note>​ +==== 3. Instalarea rootfs-ului în imaginea RPI 4 ====
-Pentru simplificarea execițiului vom folosi versiunea ​3.12 a kernelului. Spre deosebire de ultimele versiuni, aceasta oferă o configurație minimală pentru platforma RaspberryPi,​ ceea ce duce la un timp de compilare rezonabil pe PC-urile disponibile ​în laborator. În plus, față de ultimele versiuni, compilarea acestei configurații implicite se face fără erori. +
-</​note>​+
  
-  ​Schimbați repository-ul pe //branch-ul// ''​rpi-3.12.y''​ pentru a obține sursele versiunii 3.12 a kernel-ului pentru RaspberryPi. +**0.** Descărcați [[https://github.com/​cs-pub-ro/SI-rpi-debian-scripts/releases|de aici imaginea rpi-full.img.tar.xz]].
-    * Efectuați un //clean// pentru a curăța fișierele binare rămase ​de la compilarea unei alte versiuni. +
-  * Generați fișierul configurării implicite //quick// pentru RaspberryPi. +
-  * Compilaţi kernel-ul. +
-  * Vom ignora instalarea modulelor pentru moment. +
-  * Afișați versiunea kernel-ului care rulează.+
  
-<note tip> +**1.** Trebuie ​să montăm imaginea șsă copiem noul RootFs pe cea de a doua partiție (pe care o vom formata):
-  ​Nu uitați ​să curățațfișierele binare generate ​de compilarea unei alte versiuni ​kernel-ului. +
-  * Compilarea durează aproximativ 8min. +
-</​note>​+
  
-4Modificați configurația anterioară astfel încât să integreze toate driverele folosite ​de kernel-ul original direct în imagineCompilați și rulați noua configurație, afișând totodată versiunea kernel-ului.+  * Dezarhivați fișierul imaginii ''​rpi-full.img'';​ ar trebui să obțineți imaginea de ''​2GB'';​ 
 +  * Verificați că există ambele partiții: ''​parted rpi-full.img print'';​ 
 +  * Conectați imaginea la un dispozitiv ​de tip bloc folosind ''​losetup /dev/loop0 rpi-full.img''​ și ''​partprobe /​dev/​loop0''​ (verificați cu ''​losetup -L''​ ce aveți conectat dacă întâmpinați probleme);​ 
 +  * Formatați sistemul de fișiere a celei de-a doua partiții în ext4: ''​mkfs.ext4 -L RPI_ROOTFS /​dev/​loop0p2''​ (confirmați!); 
 +  * Montați noua partiție goală ''​ext4''​ (puteți folosi ''/​mnt''​ ca mountpoint) ​și copiați conținutul arhivei rootfs generate anterior (ori cea de Debian, ori cea obținută prin Buildroot): <code shell> 
 +tar xf <​ARCHIVE_FILE> ​-C <​DEST_MOUNTPOINT>​ 
 +# inspectați calea dezarhivată:​ 
 +ls -l <​DEST_MOUNTPOINT>​ 
 +</​code>​ 
 +  * Demontați partiția ext4 și deconectați dispozitivul ''​loop''​ folosite!
  
-<​note>​ +**2.** Porniți Raspberry PI-ul în u-bootapoi intrați ​în modul ''​ums mmc X''​ (vedeți [[:​si:​laboratoare/​05|laboratorul 5]]); folosiți ori ''​dd'',​ ori un utilitar de Raw Disk Imager pentru Windows (recomandat:​ Raspberry PI Imagerca la laboratoarele anterioare pentru a scrie noua imagine pe RPI.
-Driverele integrare ​în imagine vor fi încărcate o dată cu imaginea kernel-uluide fiecare dată, încă de la bootare. Astfel nu se va pierde timp cu încărcarea dinamică a acestora ​în timpul rulării. Pentru o configurație hardware stabilă șo aplicație fixată (precum ​un sistem embeddedacest lucru poate constitui un avantaj. +
-</​note>​+
  
-  ​Preluați lista de module folosite de kernel-ul original folosind comanda ''​lsmod''​ pe //target// în timp ce acest kernel rulează. Copiați lista de module într-un fișier ​pe //host//. +<note important>​ 
-  * Folosiți target-ul de make ''​localyesconfig''​, împreună ​cu variabila de mediu ''​LSMOD'' ​setată la calea către fișierul care conține lista de modulepentru a transforma configurația curentă într-configurație care integrează driverele necesare. +  ​**Atenție**: Va trebui, mai întâi, să aduceți imaginea ​pe Windows (folosiți ''​scp''​ cu ''​username@<​ip_sursa>:/​cale/​catre/​fisier.img'' ​ca prim argument, iar, ca destinație, o cale de pe PC-ul fizic, e.g.''​C:​\Users\..etc''​)! 
-  * Editați manual configurația modificată anterior pentru a repara eventualele warning-uri apăruteRecomandăm rularea target-ului de make ''​menuconfig'' ​pentru efectuarea de modificări manuale. +  **Notă pentru VirtualBox**:​ va trebui să folosiți argumentul ''​-P 2023'' ​și ''​student@localhost:<​cale>​'' ​ca sursă
-    Căutați locația configurărilor care cauzează warning-uri și activați-le. +  * **Notă pentru cei cu gazda pe Linux**: dacă utilizați ​''​dd''​, va trebui să rulați comanda ​''​sync'' ​și să așteptați să se termine! Asta e important deoarece kernelul modern cache-uiește ​în memoria RAM șscrierea se termină, aproape instant (însă rămâne să se copieze pe SD în backgroundaceastă operațiune fiind mult mai lentă).
-    * Verificați eliminarea warning-urilor prin rerularea target-ului de make ''​localyesconfig''​. +
- +
-<note tip> +
-  *  +
-  ​''​menuconfig''​ suportă tasta ''​/'' ​pentru căutare. +
-  * Folosiți tasta ''​y/Y'' ​pentru ​selecta integrarea unei opțiuni în kernel. +
-  * Începețcăutarea cu configurările pentru modulele //​snd_soc_core//​//​snd_seq_device//​ și //​leds_gpio//​. +
-  * Activați suportul pentru //I2C// și //SPI// din meniul //Device Drivers//​. +
-  * Puteți particulariza versiunea afișată a kernel-ului din meniul ''​General setup -> Local version''​.+
 </​note>​ </​note>​
  
-BonusComparați configurația kernel-ului original cu fișierul de configurare creat de voi la exercițiul 5Ce diferență observați la opțiunile selectate de voi la pasul anterior?+3Reporniți Raspberry PI-ulLăsați-l să booteze normal, ar trebui să pornească kernel-ul implicit cu rootfs-ul vostru!
  
-<note tip> +  ​Inspectați-l! Cât ocupă pe disk (''​df''​)? 
-  ​Revedeți [[#​linux_kernel_build_system| finalul]] secțiunii despre sistemul de build. +  * Dacă vă printează mesajul cu ''​waiting for device ​/dev/mmcblk0p2''​ și nu se termină procesul, verificați dacă partiția doua există din u-boot (''​part list mmc 0''​).
-  * Dezarhivați configurația originală cu ''​gunzip //<​fisier>//​''​. +
-  * Folosiți ​''​kdiff3 //<​path1>//​ //<​path2>​//'' ​pentru a compara două fișiere sau două directoare. +
-</​note>​ +
-Bonus. **(bragging rights)** Compilați și rulați ultima versiune ​kernel-ului disponibil pe Raspbian Wheezy.+
  
-<​note>​ +==== 4[BONUS] Rulați imaginea voastră în QEmu (system====
-Configurațiile pentru RaspberryPi existente în //​branch//​-ul ''​rpi-3.18.y''​ sunt voluminoase,​ ceea ce duce la un timp de compilare foarte mare pe PC-urile din laborator. Din acest motiv vom transplanta configurația //​bcmrpi_quick//​ de pe un alt branch. Ultimul //commit// care conțiune acea configurație a fost găsit folosind ''​git bisect''​ între un branch ​(''​rpi-3.17.y''​care conține configurația și branch-ul nostru. Pentru mai multe informații despre utilizarea //git bisect// studiați această [[https://​www.kernel.org/​pub/​software/​scm/​git/​docs/​git-bisect-lk2009.html| pagină]]. +
-</​note>​+
  
-  * Folosiți ''​git cherry-pick eff92148ee1b5a1ff07e5817179fefb4a0562b17''​ pentru a transplanta commit-ul ''​eff92148ee1b5a1ff07e5817179fefb4a0562b17''​ care este cel care conține configurația dorită. +Observăcă procesul de testare ​unei imagini embedded consumă ceva timp (mai ales la scrierea pe cardul SD)
-  * Generați configurarea. +Dorim să optimizăm!
-    * Actualizați fișierul de configurație conform versiunii 3.18 folosind target-ul de make ''​silentoldconfig''​. Opțiunile noi adăugate în kernel de la commit-ul ''​eff92148''​ încoace vor trebui configurate manual. Folosiți valoarea ''​0''​ pentru opțiunea ''​PHYS_OFFSET''​. +
-  * Compilați noul kernel. Vom ignora din nou instalarea modulelor. +
-    * Apariția unor erori de simboluri negăsite (//​unresolved symbol//) cu o configurație transplantată astfel nu este un lucru neobișnuit. +
-    * Notați funcția sau variabila care nu poate fi găsită. +
-    * Căutați această funcție/​variabilă în surse folosind ''​grep -nHR //<​string>//''​ și notați fișierul în care apare. +
-    * Porniți configurarea manuală și utați printre opțiunile oferite pe cea/cele care conțin bucăți din calea fișierului notat anterior. Activați-le cu tasta ''​y/​Y''​. +
-    * Reporniți compilarea. Fișierele deja compilate vor fi refolosite pe cât posibil de //make//, astfel încât ​procesul de compilare se reia în mare parte de unde rămas+
-    * Dacă mai apar erori de compilare reluați procesul (nu ar trebui ​să mai apară). +
-  * Porniți RaspberyPi-ul folosind noul kernel și afișati versiunea kernelul folosit. +
-</​hidden>​  +
-</​ifauth>​+
  
 +Rulați imaginea obținută anterior (va trebui să exrageți kernel-ul din imagine!) prin ''​qemu-system-aarch64''​.
 +Re-vedeți instrucțiunile din [[:​si:​laboratoare/​04|laboratorul 4]].
  
-<​hidden>​ +===== Resurse ​=====
-  * {{:​si:​laboratoare:​lab8_2022.txt| Soluție laborator}} +
-</​hidden>​ +
-====== Referințe ======+
  
-  ​[[https://www.raspberrypi.com/documentation/computers/​linux_kernel.htmlGhid compilare kernel ​RaspberryPi]] +  ​[[https://github.com/cs-pub-ro/SI-rpi-debian-scripts|Cod sursă scripturi ​compilare ​bootloader / kernel ​/ generare rootfs]] 
-  ​[[https://www.thegoodpenguin.co.uk/blog/build-boot-linux-on-raspberry-pi-3-model-b/| Ghid compilare U-Boot pentru RaspberryPi]]+  ​[[https://buildroot.org/downloads/manual/manual.html#​_getting_started|Buildroot Manual ​Getting started]]
  
  
si/laboratoare/09.1670949361.txt.gz · Last modified: 2022/12/13 18:36 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