Debian Trixie telepítés BananaPi R3 Mini routerre

Kicsit több mint egy éve beszereztem egy Bananpi R3 Mini routert, elsősorban tanulási céllal. Akkoriban az látszott, hogy a gyártó BSP-jén kívül vannak alternatív firmware-k, pl. OpenWRT is (mainline, nem eszköz specifikus fork). Sőt, közösségi Debian és Arch is elérhető ami kifejezetten az eszközre lett összerakva, a kernel konfig is tartalmazza az összes modult amit az eszköz igényel. A következő logikus lépés, hogy egy stock, az az módosítatlan debian.org-ról elérhető ARM64 Debiant installáljak az eszközre. Nagyjából fél éve úgy tűnt, ez lehetséges, sajnos belefutottam pár dologba ami miatt ez elég bénán jött össze. Most a frissen megjelent Debian Trixievel próbálkoztam még a megjelenés napján és a helyzet sokkal jobb, a disztró installálható és működik. Lentebb röviden összefoglalom a lépéseket, amikkel OpenWRT-vel dual-bootolható módon telepítettem a rendszert. A végső telepítés úgy fog kinézni, hogy a rootfs és home az egy NVMe-n van, de az eszköz eMMC-ről (u-boot) indul és USB pendriveról tölti be a GRUB-ot..

Az R3 Mini router az R3-hoz képest sokkal kisebb és kevesebb Ethernet és I/O portja van. SD kártyát sem lehet belerakni, úgyhogy kicsit nagyobb körültekintést igényel a flashelés: ha valami félremegy, nagyon könnyen előáll egy soft-brickelt rendszer, amit aztán mtk_uartboot-al memóriába töltött u-boot -> OpenWRT recovery-vel lehet csak helyrekalapálni. Van eMMC és SPI NAND háttértárja, köztük kapcsolóval kiválasztható melyikről bootoljon. Így azért kicsit nehezebb a brickelés, mindig lehet egy backup rendszerünk, amiről a másikat megjavíthatjuk. Én mindkettőre a legújabb elérhető (24.10.2) OpenWRT-t raktam és ezekhez továbbiakban nem is nyúltam, boothoz az eMMC-n lévő u-boot-ot fogom majd használni, ennek a konfigjába írok majd bele pár sort, ami a Debian bootoláshoz kell.

Kell nyilván egy TypeC-TypeC kábel, amivel a routerrel soros kapcsolaton kommunikálunk, és sajnos kell két pendrive is, meg egy USB hub is a telepítéshez. ARM64-es Debian Trixie DVD-t ráraktam az egyik pendrivera.
 

sudo dd if=debian-13.0.0-arm64-DVD-1.iso of=/dev/sda bs=16M status=progress oflag=sync


Ez létrehozott két partíciót a meghajtón, egyik ISO9660 másik sima FAT32, ezen vannak az EFI boothoz szükséges dolgok (az installer GRUB bootloaderje). Erre másoltam fel ideiglenesen a devicetree binárist (DTB), ez elérhető Debian szerverein (DVD-n nem találtam) "mt7986a-bananapi-bpi-r3-mini.dtb". Ha ez megvan, az eszközt bootolva be kell lépni az u-bootba. Gyorsnak kell lenni, nagyjából 5 másodperc alatt bebootolja az OpenWRT-t, ezért a menüben ESC-t kell nyomni mielőtt ezt megtenné. Az u-boot konzolban (MT7986> a prompt) az alábbi parancsokkal indítható el a telepítés a Debianos pendriveról:

usb start
setenv fdt_addr_r 0x40000000
setenv kernel_addr_r 0x40008000
fatload usb 0:2 ${kernel_addr_r} EFI/boot/grubaa64.efi
fatload usb 0:2 ${fdt_addr_r} mt7986a-bananapi-bpi-r3-mini.dtb
bootefi ${kernel_addr_r} ${fdt_addr_r}

Szemben fél évvel ezelőtti weekly DVD-kkel, vagy pár hetes RC-kkel, itt semmiféle további kernel argumentumok nem szükségesek. Az u-boot betölti EFI payloadként a GRUB-ot, menuentry bűvészkedés nélkül betöltötte a kernelt és a Debian installert. Ez azért lepett meg, mert nagyjából fél éve nyitottam PR-t, hogy a clock driver modulok hiányoznak ehhez a boardhoz és még RC2-nél sem működött. Ja és még valami: az u-boot átpasszolja GRUB-nak a DTB-t ami pedig továbbpasszolja a kernel felé! Fél éve GRUB-ig jutott el, de ott menuentry-ben már meg kellett adni, hogy honnan töltse be és juttassa el a kernelnek. Gondolom ez lenne a lényege az EFI-nek, hogy ezekkel ne kelljen szívni.

Az installer nem sokban különbözik az x86_64 verziótól. Őszintén szólva egyikben sem töltöttem túl sok időt, így nem tudom megmondani mik azok a lépések, amik eltérnek. Továbbra is serialon vagyunk, csak konzolos installer jöhet szóba. Expert installon belül érdemes a "Detect and mount installation media" opcióval kezdeni: ha ez elhasal, onnantól úgysem lehet telepíteni a Debiant. Ha sikeres, akkor valami ilyesmit ír ki: "Autodetection of the installation media was successful. A drive has been found that contains 'Debian GNU/Linux 13.0.0 "Trixie" - Official arm64 DVD Binary-1 with firmware 20250809-11:22'. The installation will now continue". Innentől jöhet a load installer components és társai. Meglepetésemre a Wi-Fi firmware és driver része a DVD-nek, így le tud tölteni friss komponenseket is telepítés közben. Ethernet sajnos elég egzotikus, Airoha EN8811 hálókártya, ennek csak a firmware-je része a telepítőnek, a driver kernel modul nem... Szerencsére később lefordítható egyedül in-tree és be is tölthető, de out-of-tree nem próbáltam, az igazi az lenne ha dkms fordítaná kernel updatekor).

Particionálás sajnos kicsit bonyolultabb, mint egy sima server vagy desktop installnál. Ennek a fő oka, hogy Debian nem látja az eMMC-t így ide nem tud települni, csak NVMe-re. Az OpenWRT u-boot viszont az NVMe-t nem látja... :-) Vagyis a /boot egy olyan helyen kell legyen, amit mindketten látnak: SPI NAND vagy egy másik pendrive. Előbbit kilőttem, egyrészt mert nem értek az ubifs-hez, másrészt mert ha valami félremegy, szét kellene szednem a boardot, hogy átkapcsoljam eMMC bootra és debugoljam mi a gond. Ha USB-n van a /boot, akkor ha gond van, átdugom a gépembe és bele tudok nézni mi ment félre, esetleg meg tudom javítani pl. grub.cfg szerkesztgetéssel. Amit nagyon szerettem volna, ha magára az installert tartalmazó pendrive-ra tudtam volna /boot particiót rakni. Sajnos az installer particionáló toolja a partman megijedt az ISO9660-tól, vagy csak a GPT hiányától (?) így ezen nem lehetett partíciókat szerkeszteni. Így USB HUB-al (mivel csak egy Type-A USB portja van az eszköznek) az installer pendrive mellé egy másikat is csatlakoztattam, rajta lesz a /boot. Kötelező EFI system partíciót is létrehozni, ezt nem lehet testreszabni, de helyesen /boot/efi mounttal hozza létre a telepítő.
A végső particiók így néztek ki:

/dev/nvme0n1 - 512.1 GB Micron_2400_MTFDKBK512QFM
>             1.0 MB        FREE SPACE
>     #1     32.0 GB     f  ext4        root  /
>     #2    476.1 GB     f  ext4        home  /home
>     #3      4.0 GB     f  swap              swap
>           335.4 kB        FREE SPACE
SCSI2 (0,0,0) (sda) - 123.0 GB  USB  SanDisk 3.2Gen1
>             1.0 MB        FREE SPACE              
>     #1      8.6 GB  B  F  ext4        boot  /boot 
>     #2      1.0 GB     f  ESP         efi

Telepítő rákérdez, hogy minden modult szeretnék-e átrakni initramfs-be. Bár túlméretezett 8 gigás /boot partíciót csináltam, szóval akár ez is működe, én azt az opciót választottam, hogy csak a szükségeseket. Ez nem tudom mit jelent, felteszem olyasmi mint a make localmodconfig opció, hogy ami most be van töltve itt a telepítőben, azokat berakja az initramdiskbe is. Bootloadernek a GRUB-ot választottam, installer tud még systemd-bootot is. Debian telepítés után nem indítottam újra egyből, hanem kézzel mountoltam a másik pendrive /boot-ját és odaraktam a DTB-t a gyökerébe. Ez kelleni fog majd az u-bootnak.

USB-hubot kihúztam a routerből, a boot partíciós pendriveot átdugtam a gépembe, szerencsére ott voltak rajta a partíciót, azokon meg a kernel (vmlinuz) meg initramfs, ESP partíción meg a GRUB és csatolt részei. Visszadugtam a pendriveot a routerbe és bekapcsoltam. Ahogy az installernél, úgy most is ESC-t nyomtam, hogy ne töltse be az OpenWRT-t, hanem hozza be az u-boot konzolt. Ebben megnéztem hogy néz ki az environment ("env print" parancs). Aztán ezt kicsit módosítottam, hogy default a Debiant bootolja (pontosabban a GRUB-ot a boot pendrive-ról, ami majd aztán a Debiant). Esetemben ez így nézett ki:

env set bootmenu_11 'Boot Debian.=run boot_debian ; run bootmenu_confirm_return'
env set bootmenu_default '11'
env set bootmenu_delay '5'
env set boot_debian 'led $bootled_pwr on; usb reset; setenv fdt_addr_r 0x40000000; setenv kernel_addr_r 0x40008000; ext4load usb 0:1 ${fdt_addr_r} mt7986a-bananapi-bpi-r3-mini.dtb; fatload usb 0:2 ${kernel_addr_r} EFI/boot/grubaa64.efi; bootefi ${kernel_addr_r} ${fdt_addr_r}; led $bootled_pwr off; run boot_debian'
env save

A boot_debian az érdekes, ez automatizálja a GRUB betöltését. Ami feltűnhet, hogy a parancs a boot_debian futtatásával végződik, lényegében egy bootloop. Ez azért van, mert sajnos a pendrive kontrollere néha túl lassú, és nem jelenik meg az u-bootban. Általában két-három reset után megjavul, szóval nem "usb start"-al kezdem a parancsot, hanem "usb reset"-el, aminek egy bootloopban van értelme, mert leállítja és újraindítja az USB-k scannelését. Az env save után egy reset és szépen betölt a Debian alapértelmezetten. Ha mégis kellene az OpenWRT, akkor menüből ki lehet választani (nyilván ez csak soros konzolon, vagy ha u-boot konzolhoz hozzáférünk valami remote módon). Elsőre elrontottam az env-et, de az "eraseenv" meg reset parancsok megoldották, ez egyébként a "Factory reset" opció az u-boot bootmenüben.

Hozzászólások

Köszönöm a részletes leírást! Élvezetes volt olvasni. Még sok ilyen szakmai tartalamat kívánok a hupra!

“The basic tool for the manipulation of reality is the manipulation of words. If you can control the meaning of words, you can control the people who must use them.”

― Philip K. Dick

Örülök ez jól esett! Nagyon régóta szerettem volna ezt a posztot megírni és "lezárni" a kísérletezést és használni a routert. Amit itt nem részletezek, az a szívás része. Ez nem a router hibája, nekem kellett sokat tanulnom. Csak ízelítőnek leírok párat.

* Elkövettem azt a hibát, hogy valami telefon mellé adott Type-C kábellel próbáltam eleinte a routert. Egy Type-C port van, ezen kapja a tápot és itt van a CH340 UART modem is. Random fagyások voltak 3-5 perc után "megmagyarázhatatlan" okból. Persze a magyarázat egyszerű volt, a kábel volt silány, beszereztem egy kicsit minőségibb kábelt (AlzaPower, 0.5M 100W) és így simán meg lehet táplálni PC-ről.

* Ha már soros konzol, eleinte szívtam azzal, hogy "lekésem" a bootmenüt, mert bekapcsolásig nincs /dev/ttyUSB0 eszköz. Picocom/minicom-ot mindig rögtön az után kellett indítanom, hogy csatlakoztattam a routert ez elég idegesítő volt. A megoldás csak annyi, hogy egy tio nevű toolra váltottam, talán itt hup-on futottam bele. Ez figyeli a fájlrendszert és egyből csatlakozik az eszközre, amint az feltűnik.

* Egy idő után elvesztettem a konzol kimenetet. Ez viszonylag egyszerű volt, u-bootban meg kellett adni kernel argumentumként a serial tty nevét és memóriacímét. Ezt később el lehetett hagyni, mert u-boot EFI boottal ezt jól passzolta tovább GRUB-nak ami pedig a kernelnek.

* Eleinte próbáltam megkerülni a GRUB-ot: úgy betölteni az installert, hogy DTB+kernel+initramfs. Sajnos ezzel az a gond, hogy az u-boot által megkövetelt initramfs formáum eltér attól amit a GRUB próbál betölteni. Úgy sikerült, sikerült csak, hogy memóriába betöltöttem az initramfs-t, de u-boot booti parancsának nem adtam meg csak kernel argumentumként (initrd=${ramdsk_addr_r}). Ezzel sem jutottam sokra, az initig nem jutott el a dolog... Nem tudta kitömöríteni a tömörített initramfs-t sajnos ezzel nem tudtam mit kezdeni, GRUB-al viszont ment.

* Az a "pazar" ötletem támadt, hogy u-boot egyből NVMe-ről töltse be a kernelt. Erre jó pár hétvégém ráment, tök feleslegesen. Nem volt zsákutca, sikerült összehozni de akkora efforttal, amennyit nem ért ahhoz képest, hogy egy filléres pendrive-ra rakom a /boot partíciót. Ugyanis sem OpenWRT, sem mainline u-boot nem tud PCIe-t R3 minin. Levlistán bár ott egy éve az RFC patch, nem került be azóta sem. Fejlesztő (Frank Wunderlich) githubján ott a fork, CI buildeli is, de az meg EFI bootot meg EXT4 fájlrendszert nem tud... :-) Forkoltam tehát a forkot, buildconfigban engedélyeztem az EFI bootot, de hogy az OpenWRT u-bootot ne piszkáljam, azt csináltam, hogy chainloadoltam azzal a forkolt, PCIe supportos u-bootot, ami meg betöltötte a GRUB-ot NVMe-ről ami a kernelt. Sok hűhó semmiért, ráadásul ez elég gáz is, hogy a stock OpenWRT u-boo mellé még kell egy másik is...

* Amiről végül PR-t is nyitottam Debian kernelhez, az a clock driverek hiánya. A clock driver modulok az initramdisk-en voltak, amit képtelen volt kicsomagolni, mert bizonyos clock driverek hányoztak... :-) Fordítottam egy saját kernelt, azonos konfiggal mint az installer, azt leszámítva hogy az összes MT7986 clock drivert builtinre állítottam (=y). Így betöltött, de nem akartam eltérni a stock-tól. Ami működött végül, az az volt, hogy megnéztem Mediatek alapú Chromebookoknál mit csinál az Ubuntu installere. Feltűnt, hogy a GRUB-ban bizonys notebookokra külön menuentry van, ebből lestem ki a clk_ignore_unused kernel argumentumot. Ezt beírva a telepítő GRUB menuentry-jébe eljutott az init-be, ahonnan már be tudta tölteni a clock drivereket. Sejtelmem sincs, mi és hogyan javította meg ezt Trixie-re, RC1-ben még ez az argumentum kellett. Buildconfigban nem találom nyomát =y-nak, továbbra is modulként fordul minden. Szerintem berakták az installer initramdiskjébe ezeket a modulokat is, a telepítés utáni /etc/initramfs-tools/initramfs.conf-t nem csekkoltam.

Igen. Érződött így is a leíráson, hogy sok óra munka és tanulás van mögötte. A fiatal önmagamat látom, aki beleássa magát órákon át olvas, próbálkozik és örül a sikernek. Ma már inkább a kész megoldásokat választom, ami egysuerűen csak megy. De azt a sok tapasztalatot és tudást senki nem veheti el tőled, amit egy ilyen projekttel megszereztél. Ez nagyon becsületes.

Amin még gondolkodtam, hogy azért jó lenne pl egy github repóba feptölteni ezeket a módosított initram fileokat, isokat, leírásokat, fordított kernelt, stb feltölteni. Lehet sok száz embernek lenne hasznos.

“The basic tool for the manipulation of reality is the manipulation of words. If you can control the meaning of words, you can control the people who must use them.”

― Philip K. Dick