Posted on 8 May 2019 By Noah Hütter
After building the Linux Kernel in a recent post we will run Alpine Linux as a leight weight distribution on the Zynq SoC
Disclaimer: This code is largely copied from https://github.com/pavel-demin/red-pitaya-notes, licensed under MIT license.
This tutorial is built on top of the Linux on Zynq tutorial. It requires the Kernel built in the previous post. So if you want to get it working, start over at Linux on Zynq and come back here after you are done.
Clone my zynq-sandbox
repository from github if you have not done so already.
git clone https://github.com/noah95/zynq-sandbox
Install qemu
the CPU emulator.
sudo apt install qemu-user-static
Change to a suitable build folder.
mkdir -p sw/linux/build/alpine
cd sw/linux/build/alpine
We define the base url to pull the sources
alpine_url=http://dl-cdn.alpinelinux.org/alpine/v3.9
Next, download the sources:
# Alpine u-boot tar
alpine_tar=alpine-uboot-3.9.0-armv7.tar.gz
curl -o $alpine_tar -L $alpine_url/releases/armv7/$alpine_tar
# Tools
tools_tar=apk-tools-static-2.10.3-r1.apk
curl -o $tools_tar -L $alpine_url/main/armv7/$tools_tar
# Firmware
firmware_tar=linux-firmware-other-20190322-r0.apk
curl -o $firmware_tar -L $alpine_url/main/armv7/$firmware_tar
Now we unpack the downloaded sources:
# Alpine uboot
mkdir alpine-uboot
tar -zxf $alpine_tar --directory=alpine-uboot
# Alpine tools
mkdir alpine-tools
tar -zxf $tools_tar --directory=alpine-tools --warning=no-unknown-keyword
Create a directory and change into it
mkdir alpine-initramfs
cd alpine-initramfs
Unzip the alpine initramfs vanilla image.
The gzip
commands decompresses (-d
) and outputs on stdout (-c
).
Gzip won’t decompress if it does not know the file suffix, so the file is
copied to the current directory and then unpacked.
cp ../alpine-uboot/boot/initramfs-vanilla initramfs-vanilla.gz
gzip -dc initramfs-vanilla.gz | cpio -id
rm initramfs-vanilla.gz
Remove kernel module configurations
rm -rf etc/modprobe.d
Remove kernel firmware (binary drivers)
rm -rf lib/firmware
Remove kernel modules
rm -rf lib/modules
Remove cache
rm -rf var
Now that the Alpine initramfs is cleaned up, we repack the initramfs.
find .
lists all files in the current directorysort
sort files alphabeticallycpio
Create new archive in the newc
formatgzip
compress the created archivefind . | sort | cpio --quiet -o -H newc | gzip -9 > ../initrd.gz
cd ..
Now that we have packed the initramfs into a compressed archive, a bootimage is generated of U-Boot.
-A arm
for arm architecture-T ramdisk
image type ramdisk-C gzip
compress image with gzip-d initrd.gz
use image data from initrd.gzmkimage -A arm -T ramdisk -C gzip -d initrd.gz uInitrd
We want to use the modules from the previously built Linux kernel. First we create a target directory to copy these files.
linux_dir=../linux-4.14/
linux_ver=4.14.101-xilinx
modules_dir=alpine-modloop/lib/modules/$linux_ver
mkdir -p $modules_dir/kernel
Now look for all .ko
files in the kernel and copy them to the new location.
This command looks for all .ko
files, sets user and group to 0
and copies them to the target location.
find $linux_dir -name \*.ko -printf '%P\0' | tar --directory=$linux_dir --owner=0 --group=0 --null --files-from=- -zcf - | tar -zxf - --directory=$modules_dir/kernel
Copy the modules order and builtin files to the destination.
cp $linux_dir/modules.order $linux_dir/modules.builtin $modules_dir/
From the copied kernel modules we generate modules.dep and map files.
depmod -a -b alpine-modloop $linux_ver
Now we copy selected firmware binaries from the alpine firmware archive into our alpine-modloop directory.
ar*
filesrt*
filestar -zxf $firmware_tar --directory=alpine-modloop/lib/modules --warning=no-unknown-keyword --strip-components=1 --wildcards lib/firmware/ar* lib/firmware/rt*
Additional firmware download and untar:
add_fw="linux-firmware-ath9k_htc-20190322-r0.apk linux-firmware-brcm-20190322-r0.apk linux-firmware-rtlwifi-20190322-r0.apk"
for tar in $add_fw
do
url=$alpine_url/main/armv7/$tar
curl -L $url -o $tar
tar -zxf $tar --directory=alpine-modloop/lib/modules --warning=no-unknown-keyword --strip-components=1
done
Now we pack the kernel modules and firmware into a squashfs file using xz compression.
mksquashfs alpine-modloop/lib modloop -b 1048576 -comp xz -Xdict-size 100%
Now its time to create the root partition and some empty directories.
Create directory.
root_dir=alpine-root
mkdir -p $root_dir/usr/bin
mkdir -p $root_dir/etc
mkdir -p $root_dir/etc/apk
Create an apk cache where the SD-card will be mounted on the target.
mkdir -p $root_dir/media/mmcblk0p1/cache
ln -s /media/mmcblk0p1/cache $root_dir/etc/apk/cache
Copy contents from apline root dir into alpine-root.
cp -r alpine/root/etc $root_dir/
Copy alpine binary and qemu arm CPU emulator to install alpine. Further, for the chroot environment to find the alpine servers, our hosts resolv config is copied.
cp -r alpine-tools/sbin $root_dir/
cp /usr/bin/qemu-arm-static $root_dir/usr/bin/
cp /etc/resolv.conf $root_dir/etc/
We now install alpine by running apk.static in a chroot.
--repository $alpine_url/main
tells apk which repository to use--update-cache
does what it says it does--allow-untrusted
yap, even unsigned packages--initdb
undocumentedadd alpine-base
tell apk to install the alpine base systemsudo chroot $root_dir /sbin/apk.static \
--repository $alpine_url/main \
--update-cache --allow-untrusted --initdb \
add alpine-base
Create a repositories file for upstream repository path.
echo $alpine_url/main > $root_dir/etc/apk/repositories
echo $alpine_url/community >> $root_dir/etc/apk/repositories
Now we chroot into the alpine-base installation and complete further installations.
sudo chroot $root_dir /bin/sh
apk update
apk add haveged openssh iw iptables curl wget less nano bc dcron
Alpine-linux uses OpenRC for its init system. More infos can be found here. Add services to the boot runlevel. From the alpine documentation:
Generally the only services you should add to the boot runlevel are those which deal with the mounting of filesystems, set the initial state of attached peripherals and logging
ln -s /etc/init.d/bootmisc etc/runlevels/boot/bootmisc
ln -s /etc/init.d/hostname etc/runlevels/boot/hostname
ln -s /etc/init.d/hwdrivers etc/runlevels/boot/hwdrivers
ln -s /etc/init.d/modloop etc/runlevels/boot/modloop
ln -s /etc/init.d/swclock etc/runlevels/boot/swclock
ln -s /etc/init.d/sysctl etc/runlevels/boot/sysctl
ln -s /etc/init.d/syslog etc/runlevels/boot/syslog
ln -s /etc/init.d/urandom etc/runlevels/boot/urandom
For the shutdown runlevel:
Changes to the shutdown runlevel and then halts the host.
ln -s /etc/init.d/killprocs etc/runlevels/shutdown/killprocs
ln -s /etc/init.d/mount-ro etc/runlevels/shutdown/mount-ro
ln -s /etc/init.d/savecache etc/runlevels/shutdown/savecache
For the sysinit runlevel:
Brings up any system specific stuff such as /dev, /proc and optionally /sys for Linux based systems
ln -s /etc/init.d/devfs etc/runlevels/sysinit/devfs
ln -s /etc/init.d/dmesg etc/runlevels/sysinit/dmesg
ln -s /etc/init.d/mdev etc/runlevels/sysinit/mdev
Add some services to the default runlevel.
rc-update add local default
rc-update add dcron default
rc-update add haveged default
rc-update add sshd default
Setup ssh deamon.
# permit root login
sed -i 's/^#PermitRootLogin.*/PermitRootLogin yes/' etc/ssh/sshd_config
Change root password.
passwd=root
echo root:$passwd | chpasswd
Set hostname.
hostname=red-pitaya
setup-hostname $hostname
hostname $hostname
Add some aliases to the root .profile
.
cat <<- EOF_CAT > root/.profile
alias rw='mount -o rw,remount /media/mmcblk0p1'
alias ro='mount -o ro,remount /media/mmcblk0p1'
EOF_CAT
Configure alpine local backup to backup to SD card partition 1.
Also include some directories.
lbu
only includes /etc
per default.
More documentation on lbu here.
sed -i 's/^# LBU_MEDIA=.*/LBU_MEDIA=mmcblk0p1/' etc/lbu/lbu.conf
lbu add root
lbu delete etc/resolv.conf
lbu delete root/.ash_history
Create backup
lbu commit -d
We now exit the chroot and restore our hostname.
exit
sudo hostname -F /etc/hostname
We now created all necessary files folders and filesystems. For convenience we copy all needed ressources in a new folder.
zip_dir=alpine-zip
mkdir -p $zip_dir
cp ../boot.bin $zip_dir/
cp ../uImage $zip_dir/
cp ../devicetree.dtb $zip_dir/
cp ../uEnv.txt $zip_dir/
cp -r $root_dir/media/mmcblk0p1/cache $zip_dir/
cp $root_dir/media/mmcblk0p1/red-pitaya.apkovl.tar.gz $zip_dir/
cp modloop $zip_dir/
cp uInitrd $zip_dir/
Zip all files that need to be copied to the SD-Card.
zip -r red-pitaya-alpine-3.9-armv7-`date +%Y%m%d`.zip $zip_dir/