This is an old revision of the document!
Până acum am folosit Root Filesystem de-a gata pre-instalat.
La acest laborator, dorim să învățăm procesul de generare a unui sistem de bază și modalitățile de personalizare a acestuia, proces numit rootfs bootstrapping.
Avem 2 variante:
Prima soluție, deși mult mai facilă (atât rapidă, cât și ușor de înțeles), nu ne permite o optimizare a 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).
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.).
Din fericire, există suite software (Yocto Linux, 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
.
Pentru acest laborator, vom încerca ambele abordări!
Pentru a genera distribuții personalizate bazate pe Debian (și derivate, e.g., Ubuntu), se poate folosi utilitarul debootstrap
.
Acesta descarcă automat din repository-uri pachetele .dpkg
, pe care le instalează într-un prefix (director) precizat de utilizator, e.g.:
$ sudo debootstrap --arch="arm64" --include="vim bash curl" \ --variant=minbase "bookworm" "/root/mydebian/" "http://ftp.de.debian.org/debian"
pacstrap
, Alpine Linux are apk.static
and so on…
De menționat ar fi că instalarea unui pachet are loc în 2 etape:
Acest aspect devine important când încercăm să generăm un rootfs pentru o arhitectură străină celei gazdă (cross-bootstrapping)!
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), vom avea de realizat următoarele:
$ sudo debootstrap --foreign --arch="arm64" ... /root/mydebian ... # restul de argumente normale # 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
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 gestionarul de pachete, apt
: de adăugat mirror-uri la repo-urile de bază în /etc/apt/sources.list
– găsiți exemplu aici.
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ți /usr/bin/bash
ca ultim argument al lui systemd-nspawn
) și setarea uneia prin passwd
.
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ă):
$ tar czf mydebian.tar.gz -C /root/mydebian
În final, dorim să vedem cât ocupă rootfs-ul nostru:
$ du -hs /root/mydebian
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).
~20-30GB
de spațiu disponibil (în mașina virtuală).
Cel mai simplu este să creați un Virtual HDD nou de 35GB
și atașați-l proiectului VirtualBox / VMWare ca dispozitiv de stocare suplimentar (din setări, add 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
.
TODO
0. Descărcați de aici imaginea rpi-empty.img.tar.xz.
1. Trebuie să montăm imaginea și să copiem noul RootFs pe cea de a doua partiție (este creată deja!):
rpi-empty
; ar trebui să obțineți o imagine de 2GB
;parted rpi-empty.img print
;losetup /dev/loop0 rpi-empty.img
(verificați cu losetup -L
ce aveți conectat dacă întâmpinați probleme);mkfs.ext4 -L RPI_ROOTFS /dev/loop0p2
; 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): tar xf <ARCHIVE_FILE> -C <DEST_MOUNTPOINT> # inspectați calea dezarhivată: ls -l <DEST_MOUNTPOINT>
loop
folosite!
2. Porniți Raspberry PI-ul în u-boot, apoi intrați în modul ums mmc X
(vedeți laboratorul 5); folosiți ori dd
, ori un utilitar de Raw Disk Imager pentru Windows (recomandat: Raspberry PI Imager) ca la laboratoarele anterioare pentru a scrie noua imagine pe RPI.
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
)!-P 2023
și student@localhost:<cale>
ca sursă.dd
, va trebui să rulați comanda sync
și să așteptați să se termine! Asta e important deoarece kernelul modern cache-uiește în memoria RAM și scrierea se termină, aproape instant (însă rămâne să se copieze pe SD în background, această operațiune fiind mult mai lentă).
3. Reporniți Raspberry PI-ul. Lăsați-l să booteze normal, ar trebui să pornească kernel-ul implicit cu rootfs-ul vostru!
df
)?waiting for device /dev/mmcblk0p2
și nu se termină procesul, verificați dacă partiția a doua există din u-boot (part list mmc 0
).Observăm că procesul de testare a unei imagini embedded consumă ceva timp (mai ales la scrierea pe cardul SD). Dorim să optimizăm!
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 laboratorul 4.