Embedded Linux voor gevorderden
- February 27, 2018
- 0
Grote kans dat je al eens gespeeld hebt met een Raspberry Pi en zo je eerste ervaring hebt opgedaan met embedded Linux. Naast de Raspberry Pi is er echter nog een hele wereld aan apparaten, waarop embedded Linux draait. Dit varieert van entertainmentsystemen in vliegtuigen tot het stoplicht waar je dagelijks voor stil staat. In dit artikel lees je wat er komt kijken om embedded Linux op een device te installeren.
We nemen je mee in de verschillende stappen, die nodig zijn om te werken met embedded Linux. Omdat er enorm veel verschillende (keuze)mogelijkheden zijn, bevat dit artikel geen stap voor stap procedure. Als je na het lezen van dit artikel daadwerkelijk aan de slag wilt met embedded Linux, dan raden we je aan om aanvullende informatie te raadplegen op http://free-electrons.com.
Anders
Ook al heb je de nodige ervaring met Linux, je merkt al bij je eerste aanraking dat embedded Linux nogal anders is. Daarvoor zijn een aantal redenen aan te wijzen. Om te beginnen zijn er grote verschillen in de hardware. Dat is niet alleen op het gebied van de processor, maar ook voor wat betreft andere hardware opties, zoals storage, RAM, netwerk interfaces, USB en veel meer. Een standaard Linux distributie voldoet dus niet en je moet alles zelf aansturen.
Een tweede belangrijk verschil is dat je op een embedded systeem geen monitor en toetsenbord aan kunt sluiten. Je zult er dus op andere wijze voor moeten zorgen dat de benodigde gegevens op het systeem terecht komen. Daarnaast zijn er tal van kleinere verschillen waar we het in de loop van dit artikel over zullen hebben.
Boodschappenlijstje
Om te beginnen met embedded Linux, heb je hardware nodig. De keuze aan apparaten (de boards) is groot en de procedure is anders per board. Dit komt niet alleen omdat er verschillende processors op de boards gebruikt kunnen worden, maar ook omdat de hardware heel precies aangestuurd dient te worden en het dus per configuratie afwijkend is.
Een goede keuze om te beginnen met embedded Linux is de Atmel SAMA5D3 Xplained, die voor minder dan 100 euro te koop is. Op dit board bevinden zich verschillende hardwarecomponenten, waaronder 2 USB-poorten, 2 ethernetpoorten en een SSD-slot. Naast deze hardware behoren er nog een paar componenten in je beginnerskit: een USB seriële kabel en een SD-kaart met een capaciteit van minstens 128 MB. Door deze SD-kaart te gebruiken, kies je zelf waarvan je het board wilt starten: vanaf het ingebouwde NAND-geheugen of vanaf de SD-kaart.
Werken met embedded
Op een embedded systeem sluit je niet eenvoudig een toetsenbord en beeldscherm aan, dus de inrichting van het device gaat via een PC. Op deze PC gebruik je uiteraard een Linux-distributie en daar vandaan schrijf je alle componenten naar het embedded device. Om dat voor elkaar te krijgen, compileer je ook de nodige componenten, voordat je ze wegschrijft naar het embedded device. Dit zijn in elk geval de boot loader, de kernel, de C-library en vervolgens de toepassing met bijbehorende libraries, die je wilt gebruiken.
Cross compiler
Alle compilaties, die je vanaf het development werkstation uitvoert, doe je in de cross compiler toolset. De normale C compiler op je computer produceert namelijk binaries voor het verkeerde platform (namelijk de 32 of 64 bits in je PC en niet de Arm processor op het embedded device). Door in de cross compiler toolchain te werken, zorg je er door middel van variabelen voor dat de juiste bestanden geproduceerd worden, die het ook doen op jouw platform. Wat je hiervoor als ontwikkelstation gebruikt, maakt overigens niet heel veel uit. Elke moderne distributie kan hiervoor gebruikt worden. Wel moet gezegd worden dat heel veel ontwikkelaars hun ontwikkelwerk doen op basis van Ubuntu.
Serieel
Om de configuratie vanaf het werkstation naar het device te pushen, is een seriële verbinding nodig. Deze wordt doorgaans tot stand gebracht door middel van een seriële USB-kabel. Op het ontwikkelstation heb je een specifiek programma nodig om met het device te communiceren. Elk programma dat ontwikkeld is voor communicatie over een seriële verbinding voldoet hiervoor. Als je niet thuis bent in dit soort programma’s, gebruik dan picocom. Als het device op de juiste wijze met de seriële kabel aan de computer verbonden is, moet je deze zien als /dev/ttyUSB0, type dus picocom /dev/ttyUSB0 om ermee te verbinden. Je verlaat overigens de picocom interface weer met de toetscombinatie Ctrl-A, Ctrl-X.
De cross compiler toolchain
Om software voor het device te kunnen compileren, heb je naast reguliere compiler packages, zoals autoconf, automake, patch, cvs, git, python-dev and nog een aantal, ook crosstool-ng nodig (de cross compiler toolchain). Je kunt deze downloaden van GIT met het git commando:
git clone git://crosstool-ng.org/crosstool-ng
Hierna kun je hem configureren en compileren.
Zorg er tevens voor dat binutils, kernel headers, C libraries en de GCC compiler geïnstalleerd zijn om verder te kunnen. Vervolgens selecteer je in de toolchain de juiste configuratie om software te compileren voor jouw specifieke platfom. Dit doe je door vanuit de toolchain directory de opdracht make menuconfig te gebruiken.
Copy
Na de configuratie van de toolchain, begin je de verschillende onderdelen naar het device te kopiëren. Het eerste wat hiervoor nodig is, is een bootloader. De bootloader bestaat uit twee onderdelen: een vast machineonderdeel, dat doorgaans in ROM geïntegreerd is of op een vast adres geplaatst wordt en de oorspronkelijke Linux bootloader. Als je gebruik maakt van het genoemde Atmel Xplained board, zijn er niet minder dan drie onderdelen in de boot loader:
· Een 4KB groot RomBoot programma, dat op zoek gaat naar een bootstrap programma.
· Het bootstrap programma dat vanuit SDRAM geladen wordt en de hardware aanspreekt, die nodig is om verder te starten (zoals DRAM, NAND Flash geheugen en de controller) en vervolgens de stage 2 bootloader laadt.
· U-Boot: de oorspronkelijke stage 2 bootloader, die het kernel image laadt en ervoor zorgt dat een shell en de daadwerkelijke OS-omgeving geladen kunnen worden.
De boot loader bestaat dus uit drie verschillende onderdelen, waarvan U-Boot het generieke deel is en de rest hardware-specifiek is. Als beheerder van het embedded device zorg je er zelf voor de configuratie van U-Boot en dat dit naar het device geschreven wordt. Als dit eenmaal gebeurd is, heb je op het device een omgeving, die te vergelijken is met GRUB. Van hier worden bootloader specifieke commando’s geladen, waaronder het commando boot waarmee je de kernel laadt.
De kernel en de rest van het OS
Als U-Boot geïnstalleerd is, ga je verder met de volgende stap. Er moet immers ook een kernel op het systeem gezet worden. Deze kernel moet in de cross compiler toolchain gecompileerd worden voor het specifieke platform, dat je gebruikt. Uiteraard is dit geen standaard kernel, maar je geeft net als vroeger gebruikelijk was met make menuconfig exact aan wat je in die kernel wilt hebben. Op embedded devices is immers maar beperkte ruimte aanwezig om bestanden op te slaan, dus het is zaak om zo efficiënt mogelijk met die ruimte om te gaan.
Omdat embedded systemen vaak veel specifieke hardware aan boord hebben, is het doorgaans niet voldoende om enkel een kernel te laden. Er is ook een device tree nodig. Deze device tree is een toevoeging op de Linux kernel en bevat alle drivers, die nodig zijn om met de embedded hardware te kunnen werken. Je moet deze dus apart naast de kernel configureren en installeren.
Vanuit de kernel moet dan de rest van het besturingssysteem geladen worden. Dit gebeurt door een root filesystem op afstand te mounten, door bijvoorbeeld gebruik te maken van NFS. Om deze optie te gebruiken, wordt de locatie van het root filesystem als boot argument in U-boot aan de kernel meegegeven. Daarnaast is het mogelijk om het root filesystem te integreren op het embedded device, door deze onder te brengen in een initramfs. Als snelheid een doel is, is deze laatste werkwijze aan te raden. Zeker als het root filesystem in een initramfs verwerkt wordt, is het zaak om goed na te denken over de bestanden die er in nodig zijn. Ook hier geldt dat het belangrijk is om efficiënt te zijn met de beperkt beschikbare ruimte.
Busybox
Een gangbare oplossing om de benodigde OS-omgeving op het embedded device te krijgen, is Busybox. Busybox is een minimaal Linux-systeem, met daarin een init programma, een shell en een aantal basis tools, zoals je gewend bent die op Linux te vinden. Je zult echter begrijpen dat geen van deze commando’s de volledige functionaliteit bevat, die je gewend bent, want ook hier is efficiënte omgang met de beschikbare ruimte belangrijk. Zo vindt je in Busybox bijvoorbeeld geen volledige systemd implementatie, maar een minimaal init programma. Hierbij maak je gewoon nog gebruik van een configuratiebestand /etc/inittab om op te geven wat er tijdens het starten van het device moet gebeuren.
Uiteraard is ook Busybox geen standaard onderdeel, maar iets waarbij je exact zelf op kunt geven wat erin aanwezig moet zijn. Dit betekent dat je Busybox zult compileren en naar het device weg zult schrijven, zodat precies die onderdelen erin voorkomen, die je nodig hebt en daarbuiten niets.
Omgaan met storage
Als je dan een basissysteem op je device hebt gezet, wordt het tijd om na te denken over meer geavanceerde features. Één van de belangrijke onderdelen van een device is de storage. Op de meeste devices zijn twee oplossingen beschikbaar: block storage en flash storage. Block storage devices worden aangestuurd als een reguliere harde schijf en dit kunnen hard disks zijn (vrij ongebruikelijk op embedded devices) of SD-kaarten, die een controller hebben die ervoor zorgt dat ondanks het flash media type de SD-kaart niet aangestuurd hoeft te worden als een flash device.
De andere belangrijke storage-optie is het raw flash device. Elk embedded device beschikt over dit belangrijke embedded opslagtype. Wat de omgang ermee bijzonder maakt, is dat om te schrijven op het device er eerst een erase actie uitgevoerd moet worden om de media te prepareren voor de opslag van data. Twee typen flash zijn gebruikelijk: NOR en NAND flash. De eerste aansturing van deze typen flash vindt plaats vanuit de U-boot boot loader. Vervolgens is er een bestandssysteem nodig, dat om kan gaan met de specifieke eigenschappen van flash media.
UBIFS is een gangbaar bestandssysteem voor de omgang met flash, maar er zijn ook oudere bestandssystemen, die gebruikt kunnen worden, zoals JFFS2 en YAFFS2. In UBIFS gebruik je een embedded volume manager, die te vergelijken is met de LVM volume manager. Door de schrijfacties te verspreiden over meerdere volumes, kunnen schrijfacties geoptimaliseerd worden. Om een UBIFS bestandssysteem in te richten op een wijze, die past bij het device, wordt gebruikgemaakt van het ubi commando. Hierin komen veel opties voor, die ervoor zorgen dat het bestandssysteem optimaal wordt ingericht voor de omgang met het device.
Klaar voor gebruik
Met de configuratie van een flash bestandssysteem, is het embedded device in principe klaar voor gebruik. Nu kan er over gegaan worden tot het uiteindelijke doel van het device: het programma dat erop geïnstalleerd moet worden. Omdat embedded devices doorgaans gebruikt worden op specifieke apparaten, variërend van stoplichten tot magnetrons, is dit vaak een heel specifiek programma. Dit dient tevens op maat gemaakt en gecompileerd te worden, voordat het naar het UBIFS bestandssysteem weggeschreven kan worden. Niets houdt je echter tegen om je embedded device in te zetten als webserver, mediaserver of wat dan ook. Ook daarvoor geldt dan weer dat doorgaans gebruikgemaakt wordt van aangepaste versies van gangbare programma’s. Zo is er bijvoorbeeld een specifieke Busybox webserver, die maar 9K toevoegt aan de embedded omgeving.
Tot slot
Zoals je in dit artikel hebt kunnen lezen, is het inrichten van een embedded device bepaald niet eenvoudig. Het leuke voor de Linux-liefhebber is echter dat het je terugbrengt naar de oorsprong en het je de gelegenheid geeft om te werken met Linux, zoals dat in de beginjaren van het besturingssysteem ook gebruikelijk was. Je maakt het jezelf voor een eerste kennismaking echter ook makkelijker, door gewoon het device aan te sluiten op je computer, een programma te starten voor seriële communicatie en in te loggen op het geminimaliseerde besturingssysteem, dat standaard op vrijwel alle embedded devices geïnstalleerd is. Dan kijk je eerst eens rond, voordat je de duik in het diepe neemt.