Alpine opstartproces op de Raspberry Pi

Vandaag zullen we het opstartproces van Alpine Linux op een Raspberry Pi eens in detail bekijken.

clip_image001

De afbeelding toont de inhoud van een "maagdelijke" SD-kaart met de Alpine image, die nog niet is opgestart.

clip_image003

Deze foto toont de inhoud van de opstartmap.

Eerste opstartfasen op de Raspberry Pi

Raadpleeg deze link voor een uitgebreide handleiding over verschillende opstartmedia:

https://www.raspberrypi.org/documentation/hardware/raspberrypi/bootmodes/bootflow.md

De Raspberry Pi heeft geen klassiek "BIOS" zoals in x86-gebaseerde IBM PC-compatibele computers. De CPU moet worden gezien als een toevoeging aan de VideoCore IV voor opstartdoeleinden, in plaats van andersom.

Dus, in eerste instantie heeft de VideoCore IV, de GPU, de controle. Hij start vanuit zijn eigen ROM (eerste stadium), en controleert de boot bronnen voor een bestand genaamd bootcode.bin. Voor onze doeleinden zullen we aannemen dat dit bestand van de SD-kaart wordt geladen.

bootcode.bin (51 KB) wordt in de lokale 128K L2 cache van de GPU geladen. Het schakelt RAM in en laadt de derde trap: start.elf (2759 KB)

start.elf leest config.txt, en stelt de juiste instellingen in voor de VideoCore IV. config.txt is een parameter bestand voor de Raspberry Pi waar je bijv. de video mode, overscan, audio opties, MPEG codecs, overklok instellingen, etc. kunt instellen. - Het is "zoals" het BIOS instellingen gedeelte van de traditionele computer. start.elf zelf is de firmware voor de GPU, dat zijn eigen besturingssysteem is, genaamd "VideoCore OS".

NB: Er zijn verschillende versies van start.elf, waaronder start_x.elf die cameradrivers bevat, en start_cd.elf - dat is een verkorte versie van start.elf, om te gebruiken wanneer het GPU-geheugen beperkt is tot het maximum: gpu_mem=16. Deze laatste versie kan interessant zijn voor embedded systemen. Raadpleeg deze site voor meer informatie: https://www.raspberrypi.org/documentation/configuration/boot_folder.md

config.txt is optioneel. Als u dezelfde SD-kaart (of image) voor meerdere Pi's gebruikt, kunt u voorwaardelijke filters instellen om op bepaalde scenario's toe te passen; u kunt zelfs een voorwaarde toepassen op basis van de serie van de Raspberry Pi, of op de toestand van een GPIO. Er is ook de mogelijkheid om bijkomende bestanden in de config.txt op te nemen. Alles bij elkaar krijg je een vrij krachtig systeem voor de basisconfiguratie van de Raspberry Pi.

Natuurlijk zijn er ook opstartopties in config.txt, die bepalen hoe het verdere opstarten verloopt.

start.elf laadt dan de kernel (zoals gespecificeerd door config.txt / defaults), en start deze met cmdline.txt als kernel commandoregel .

config.txt opstart opties

kijk eens aan:

https://www.raspberrypi.org/documentation/configuration/config-txt/boot.md

om meer te lezen over de beschikbare opstartopties.

Alpine's standaard config.txt

Laten we eens kijken naar de config.txt die geleverd wordt met Alpine's 3.8.1 ARMHF release:

  • disable_splash=1
    • dit zal het regenboogscherm bij het opstarten uitschakelen (puur cosmetisch)
  • boot_delay=0
    • wacht niet in start.elf alvorens de kernel te laden. (een opstartvertraging kan nodig zijn voor sommige SD-kaarten om "klaar te komen")
  • gpu_mem=256
    • bepaalt de verdeling van het geheugen tussen GPU en CPU. Het geheugen van de Pi wordt gedeeld. Hier stellen we 256 MB in voor de GPU, u zou dit kunnen verminderen op embedded systemen die geen displays aansturen.
  • gpu_mem_256=64
    • stelt de verdeling van het geheugen in voor Pi's met slechts 256 MB totaal geheugen (alleen sommige oude generatie Pi 1B's)
  • [pi0]
    • voorwaardelijke verklaring voor Pi Zero; deze omvat Pi Zero en Pi Zero W
    • alle statemens tot de volgende voorwaardelijke worden alleen toegepast als we draaien op een Pi Zero / Zero W
    • de Pi Zero / Zero W gebruiken nog steeds een oudere ARMv6 ISA CPU (ARM11 @ 1 GHz)
    • we zullen een kernel gebruiken die gecompileerd is voor ARMv6
  • kernel=boot/vmlinuz-rpi
    • dit specificeert de kernel om te laden
    • dit moet een ongecomprimeerd kernel image bestand zijn
    • 32 bit kernels worden standaard geladen op adres 0x8000
  • initramfs boot/initramfs-rpi
    • "het initramfs commando specificeert zowel de ramfs bestandsnaam als het geheugenadres waar het geladen moet worden"
    • initramfs = initieel RAM-bestandssysteem
    • dit bestand kan worden uitgepakt met 7Zip, bijvoorbeeld (twee keer uitpakken)
    • OPMERKING: deze configuratieparameter wordt gespecificeerd zonder de "="
  • [pi1]
    • dit zal de volgende configuratie regels toepassen op alle Raspberry Pi 1 - zal niet overeenkomen op Pi 2, enz.
  • kernel=boot/vmlinuz-rpi
  • initramfs boot/initramfs-rpi
  •  [pi2]
  • kernel=boot/vmlinuz-rpi2
    • Merk op hoe we een andere kernel gebruiken, aangezien we hier een CPU hebben die ARMv7 code kan draaien
  • initramfs boot/initramfs-rpi2
    • en een andere initramfs ...
  • [pi3]
    • kernel=boot/vmlinuz-rpi2
    • initramfs boot/initramfs-rpi2
  • [pi3+]
    • kernel=boot/vmlinuz-rpi2
    • initramfs boot/initramfs-rpi2
  • [alle]
    • de volgende regel(s) zal weer van toepassing zijn op alle Pi's
  • usercfg.txt opnemen
    • zal een bestand usercfg.txt opnemen in de configuratie, dat nog niet bestaat in het standaard Alpine image.
    • Hier kunt u extra instellingen opgeven die u wilt, bijv. HDMI-resolutie, enz.
    • Als alternatief zou je het hieronder in config.txt kunnen plakken

Opmerking: de configuratie die in Alpine gebruikt wordt, specificeert geen tweede parameter voor de initramfs (adres waarop de initramfs gemount moet worden); het is dus niet aan te raden om dit 1:1 te kopiëren. Dit gezegd zijnde, lijkt het te werken, waarschijnlijk met een veilige standaardinstelling!

Lees meer over config.txt:

De Kernel en de Initramfs

De kernel

Afhankelijk van de config.txt instellingen, wordt de juiste kernel geselecteerd en in RAM geladen. Zodra deze geladen is, wordt/worden de ARM processorkern(en) vrijgegeven van reset zodat deze de kernel kan booten.

De inhoud van cmdline.txt wordt doorgegeven als kernel commandoregel. start.elf geeft ook zelf aanvullende parameters door, bijvoorbeeld voor het instellen van DMA kanalen, het MAC adres van de SMSC LAN chip, etc.

Krijg de cmdline.txt:

cat /proc/cmdline

dmesg | grep "Command line"

cmdline.txt

laten we eens kijken naar Alpine's standaard cmdline.txt:

modules=loop,squashfs,sd-mod,usb-storage quiet dwc_otg.lpm_enable=0 console=tty1

Dit laadt de modules

  • lus
    • het loop device wordt gebruikt om een bestand als een bestandssysteem te mounten
  • squashfs
  • sd-mod
    • SCSI-schijfstuurprogramma / blokstuurprogramma
    • blijkbaar gekopieerd van Alpine standaard configuratie, b.v. hier: https://wiki.alpinelinux.org/wiki/Create_a_Bootable_Compact_Flash
  • usb-opslag
    • Linux USB-stuurprogramma voor massaopslag

NB: modulenamen kunnen zowel - als _ bevatten, deze symbolen kunnen blijkbaar worden verwisseld.

rustig

  • stelt het standaard kernel-logniveau in op KERN_WARNING, wat alle behalve zeer ernstige logberichten onderdrukt tijdens het opstarten (bron: Raspberry Pi-documentatie)

dwc_otg.lpm_enable=0

console=tty1

  • definieert de seriële console

Verder lezen:

initramfs

" Het initramfs commando specificeert zowel de ramfs bestandsnaam als het geheugenadres waarnaar het geladen moet worden. Het voert de acties uit van zowel ramfsfile als ramfsaddr in één parameter. Het adres kan ook followkernel (of 0) zijn om het in het geheugen te plaatsen na de kernel image. Voorbeeldwaarden zijn: initramfs initramf.gz 0x00800000 of initramfs init.gz followkernel. OPMERKING: Deze optie gebruikt een andere syntaxis dan alle andere opties, en u moet hier geen = teken gebruiken." - Raspberry Pi Documentatie

Er zal een kernelboodschap verschijnen zoals deze "[ 0.143709] Trying to unpack rootfs image as initramfs..." in dmesg, die aantoont dat de image uitgepakt wordt.

De initramfs stelt de Linux kernel in staat om modules toe te voegen, en andere taken uit te voeren ter voorbereiding van het mounten van het eigenlijke bestandssysteem. Het zorgt dus voor een zeer veelzijdig boot-systeem, zonder de kernel opnieuw te hoeven compileren of overhead aan de kernel toe te voegen. Bijvoorbeeld voor gebruikers met een versleuteld bestandssysteem, zal initramfs om de passphrase vragen voordat het het bestandssysteem kan ontsleutelen en mounten.

Afhankelijk van de CPU in uw Raspberry Pi, zullen verschillende initramfs-bestanden worden gebruikt, zoals ingesteld in config.txt:

  • boot/initramfs-rpi voor Pi 1 / 1B+ en Pi Zero / Zero W, en Compute Module 1
  • boot/initramfs-rpi2 voor alle andere Pi's (2, 3B, 3B+, ...)

Het initramfs bestand kan worden uitgepakt met, bijvoorbeeld, Windows 7Zip. (Je moet het twee keer uitpakken: het eerste bestand bevat een gzipped tweede bestand)

initramfs images kunnen verschillende formaten hebben, afhankelijk van welke algoritmen statisch in de kernel werden gecompileerd (b.v. gzip / bzip2 / LZMA / XZ / LZO / LZ4).

clip_image005

Dit tweede bestand bevat een map- en bestandsstructuur, die u zult herkennen als u Linux eerder hebt gebruikt. Het is in een speciaal formaat, "cpio", wat lijkt op teer.

clip_image007

Als u nieuwsgierig bent, kunt u hier meer lezen over cpio:

https://en.wikipedia.org/wiki/Cpio

Dit is wat er in het bestand staat:

clip_image008

in bin, het bevat:

  • busybox
    • compact uitvoerbaar bestand met verschillende UNIX-hulpprogramma's in één toepassing
    • vooral voor ingebedde systemen
    • https://busybox.net/about.html
  • sh

in sbin, het bevat

de init bestand wordt door de Linux-kernel gestart als eerste procesen zet Alpine op.

Hier is het gereedschap dat gebruikt wordt om de initramfs voor Alpine te genereren:

https://github.com/alpinelinux/mkinitfs

init

dit is een opeenvolgende uittreksel van wat het init-script, gestart vanuit de initramfs, doet:

  • maakt recursief de mappen /usr/bin, /usr/sbin, /proc, /sys, /dev, /sysroot , /media/cdrom, /media/usb, /tmp, /run aan
    • sommige van deze directories lijken al aanwezig te zijn in de initramfs
  • installeert busybox (zet symlinks op naar busybox' embedded commands)
  • stelt PATH in op /usr/bin:/bin:/usr/sbin:/sbin
  • creëert /dev/null met mknod
  • mounten proc naar /proc
    • proc is een pseudo-bestandssysteem met procesinformatie
    • u kunt informatie over de kernel verkrijgen door te lezen en bepaalde dingen te configureren door naar sommige bestanden in deze directory te schrijven
    • de genummerde ingangen zijn mappen met informatie over het proces met dit specifieke proces-id
    • https://www.tldp.org/LDP/Linux-Filesystem-Hierarchy/html/proc.html
  • ... en sysfs naar /sys
  • de via cmdline.txt doorgegeven opties parseert, worden de volgende herkend:
    • alpine_dev autodetect autoraid grafiek cryptroot cryptdm cryptheader cryptoffset
    • cryptdiscards cryptkey debug_init dma init_args keep_apk_new modules ovl_dev
    • pkgs quiet root_size root usbdelay ip alpine_repo apkovl alpine_start splash
    • blacklist overlaytmpfs rootfstype rootflags nbd resume s390x_net dasd ssh_key

Tip: probeer "rustig" in cmdline.txt naar "noquiet"om een meer verbose boot te krijgen, en veel berichten van init te zien

  • mounten devtmpfs naar /dev
  • laadt drivers om modloop later te kunnen mounten
  • indien de parameter nbd aanwezig en geconfigureerd is (netwerk block device), probeert dan een ip adres op te halen, en het netwerk block device te configureren met nbd-client
  • als de wortelparameter is ingesteld
    • if [ -n "$KOPT_root" ]; then
    • n evalueert als de lengte van "$KOPT_root" niet nul is
    • dan wordt nlplug-findfs uitgevoerd
    • overlaytmpfs wordt optioneel behandeld
    • de huidige mount punten worden gemigreerd naar /sysroot
    • switch_root wordt uitgevoerd en de controle wordt doorgegeven aan /sbin/init
    • (dit is een startpunt om Alpine Linux te installeren in een normale modus, niet in alleen-lezen modus)

anders:

  • nlplug-findfs wordt uitgevoerd om het opstartmedium te vinden,
  • als de parameter apkovl is ingesteld,
    • en het is leeg - en /tmp/apkovls bestaat (dat wil zeggen, bestanden werden gevonden door nlplug-findfs) - de ovl is ingesteld uit de eerste regel van /tmp/apkovls
    • en het begint met http:// / https:// / ftp:// - een netwerkverbinding wordt geprobeerd om de apkovl te trekken
    • anders wordt de ovl ingesteld op de string in de apkovl optie
  • als de apkovl bestaat,
    • en is een .gz bestand, de apkovl is uitgepakt tar -C "$dest" -zxvf "$ovl" > $ovlfiles en /tmp/ovlfiles is gevuld met de uitvoer van tar
  • er is code voor een splash screen, fbsplash is een van de functies die is opgenomen in busybox - het toont fbsplash*.ppm bestanden
  • if [ -z "$ALPINE_REPO" ] -> betekent, als de string $ALPINE_REPO leeg is
    • onder sommige omstandigheden worden standaard bootservices toegevoegd, voor de runlevels sysinit, boot, shutdown en default (b.v. de service firstboot)
  • apk repositories zijn toegevoegd en uitgebreid
    • het pakket alpine-base hangt af van alpine-baselayout, alpine-conf en enkele andere pakketten
      • het bevat ook het bestand /etc/os-release -> dat de naam, versie, en mooie naam van Alpine Linu weergeeft
    • alpine-baselayout is de basismap lay-out
    • alpine-conf bevat, onder andere, het lbu script en setup scripts
    • busybox bevat de busybox binary
    • busybox-initscripts bevat enkele initscripts
  • tenslotte, wordt de root directory omgeschakeld, en /sbin/init wordt gestart
    • dit zal OpenRC starten en de runlevels uitvoeren
    • /sbin/init is een symlink naar /bin/busybox

Let op: De apkovl wordt gemount vóór modloop en vóór de installatie van de pakketten. Hierdoor kan de apkovl onder andere configureren welke pakketten geïnstalleerd gaan worden.

OpenRC Runlevels

sysinit -> boot -> default -> shutdown

https://hoverbear.org/2014/09/29/init-runlevels-and-targets/

Runlevel sysinit:

clip_image010

modloop zal gestart worden na dev-mount, en voor checkfs, fsck, hwdriver, modules, hwclock, dev, sysfs

hwdrivers zal gestart worden na modloop. hwdrivers zal de drivers laden met modprobe.

Runlevel opstarten:

clip_image012

Runlevel standaard:

clip_image014

Modloop

Er is ook het modloop-bestand (modloop-rpi of modloop-rpi2).

hoe het gemonteerd is

Het juiste bestand voor uw systeem wordt bepaald in het script /etc/init.d/modloop in de functie find_modloop()

Het resultaat van uname -r wordt gecontroleerd met de directory modules/ - de subdirectory met de juiste naam moet er in staan.

Bijvoorbeeld: 4.14.69-0-rpi2

Op deze manier worden de juiste modules voor uw kernel gebruikt (uname -r drukt de kernel release af).

modloop is aangekoppeld in de directory /.modloop

clip_image015

Symlinks worden gemaakt van /lib/firmware naar /lib/modules/firmwareen /lib/modules is gesymlinked naar /.modloop/modules

Hint: Als je de Raspberry Pi 3B+ WiFi firmware wilt patchen, moet je het in modloop.

Modloop's inhoud

Om de inhoud van modloop te verkennen, kun je gebruik maken van (getest op een mint systeem):

apt-get install squashfs-tools

unsquashfs modloop-rpi2

Het bevat firmware en drivers.

clip_image016

clip_image017

Referenties:

verder lezen: