Debian Cross-Compilation for Mirabox
- Pre-requisites
- Step 1 - Decide where to deploy everything
- Step 2 - install the required packages
- Step 3 - Clone the Linux-stable git repository
- Step 4 - Checkout the desired stable version
- Step 5 - Build the Linux kernel
- Step 6 - Create the ARM chroot environment
- Step 7 - Trim the size of the chroot environment
- Step 8 - Configure the chroot initramfs
- Step 9 - Deploy the kernel into the chroot environment
- Step 10 - Install some additional packages required for the Mirabox
- Step 11 - Configure the chroot environment for the Mirabox
- Step 12 - Create the SD Card image
- Step 13 - Mount the SD Card image
- Step 14 - Populate the SD Card image
- Step 15 - Copy the SD Card image to a real SD card
- Step 16 - Boot on the Mirabox
- Step 17 - Rough notes for the moment - ignore for now
- Changelog
- Notes
Source : Debian Cross-compile
This work in progress procedure will create an image that can be copied onto an SD card and be used to boot a Mirabox. It aims to use a stock kernel and stock Debian.
Pre-requisites
I am assuming you are running Debian 9 (Stretch) on 32-bit or 64-bit Intel PC or Server. I have tested this procedure on a minimal install on a VM.
You will require root access using sudo.
Step 1 - Decide where to deploy everything
You will need around 4GB of free disk space for the git tree and the chroot environment. For this demonstration I will use the MIRABUILD environment variable as the root of the tree.
MIRABUILD=~/mirabuild
export MIRABUILD
The very first time you start, you'll need to create the build directory:
mkdir $MIRABUILD
Don't forget to re-export the environment variable if you repeat parts of the procedure.
Step 2 - install the required packages
Debian now includes a GCC cross-compiler for ARM as well as a really easy mechanism to create a chroot environment for a foreign architecture using Qemu. We'll use both of those in this procedure.
Use apt-get
to install the required packages.
sudo apt-get install --no-install-recommends gcc-arm-linux-gnueabihf build-essential git ca-certificates bc binfmt-support qemu-user-static debootstrap parted dosfstools rsync
Step 3 - Clone the Linux-stable git repository
We will use the linux-stable git repository and install using the latest stable version at the time of writing.
cd $MIRABUILD
git clone git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git
If you have already cloned the repository and want to bring it up to date with the latest stable version, perform the following:
cd $MIRABUILD/linux-stable
git checkout -- .
git checkout master
git pull
Step 4 - Checkout the desired stable version
We will checkout the latest stable version at the time of writing.
cd $MIRABUILD/linux-stable
git checkout v4.14.16
git checkout -b v4.14.16-mirabox
Step 5 - Build the Linux kernel
I will use my personal Linux kernel configuration. You can use this as a base and amend to your liking. Be careful! This configuration probably will not work with systemd as it does not include several required features (e.g. cgroups). Also, make sure the resultant kernel is less than 2MB in size if you intend to flash it to NAND.
I also have a small patch to disable detection of the Marvell SD8787 Bluetooth AMP device, which doesn't work with the SD8787 firmware I use.
cd $MIRABUILD/linux-stable
wget -O.config https://www.solinno.co.uk/public/mirabox/config-mirabox-4.14.16
wget -O- https://www.solinno.co.uk/public/mirabox/mirabox-sdio.patch | patch -p1
export CROSS_COMPILE=arm-linux-gnueabihf-
make ARCH=arm -j3
Step 6 - Create the ARM chroot environment
We'll use an ARM chroot environment both to help create the kernel image and initial ramdisk, but also to let us create an SD card image. Change the Debian mirror to be one appropriate to your country.
Note that I remove dmsetup
as without this the initial ramdisk becomes too large. If you need dmsetup
then you will need to disable the initramfs hook after it is installed.
cd $MIRABUILD
sudo qemu-debootstrap --arch=armhf --include=sysvinit-core,locales,ntp,vim-tiny,initramfs-tools,u-boot-tools,xz-utils stretch $MIRABUILD/debian_armhf_stretch http://ftp.debian.org/debian/
sudo chroot $MIRABUILD/debian_armhf_stretch apt-get remove -y --purge dmsetup systemd
sudo chroot $MIRABUILD/debian_armhf_stretch apt-get clean
sudo mkdir $MIRABUILD/debian_armhf_stretch/uboot
Step 7 - Trim the size of the chroot environment
To keep the chroot environment as small as possible I install a dpkg.cfg
file that excludes man pages, documentation and non-English locales. You may edit this to your needs, if required.
cd $MIRABUILD/debian_armhf_stretch
wget -O- https://www.solinno.co.uk/public/mirabox/etc_dpkg_dpkg.cfg | sudo tee etc/dpkg/dpkg.cfg >/dev/null
sudo rm -fr $MIRABUILD/debian_armhf_stretch/usr/share/man/*
sudo rm -fr $MIRABUILD/debian_armhf_stretch/usr/share/doc/*
ls -d $MIRABUILD/debian_armhf_stretch/usr/share/locale/*/LC_MESSAGES | sed -e 's/\/LC_MESSAGES$//' -e 's/^/rm -fr /' | grep -v -e 'locale/en' -e '/uk$' | sudo sh
Step 8 - Configure the chroot initramfs
In order to keep the initial ramdisk as small as possible we configure it to use xz compression and just include the modules needed to get the root filesystem mounted. NB: This configuration is suitable for booting from the SD Card using the ext4 filesystem.
cd $MIRABUILD/debian_armhf_stretch
wget -O- https://www.solinno.co.uk/public/mirabox/etc_initramfs-tools_initramfs.conf | sudo tee etc/initramfs-tools/initramfs.conf >/dev/null
wget -O- https://www.solinno.co.uk/public/mirabox/etc_initramfs-tools_modules | sudo tee etc/initramfs-tools/modules >/dev/null
NOTE: The fsck
attempted by the initial ramdisk will fail when the mirabox boots, however this won't prevent booting. You can correct the problem by recreating the initial ramdisk on the mirabox itself (where it will be able to correctly determine the root filesystem).
Step 9 - Deploy the kernel into the chroot environment
This step copies the kernel and modules into the chroot environment and creates the u-boot images that can be loaded by the Mirabox.
Firstly, we will create the kernel image. Because the version of u-boot
shipped with the Mirabox is too old to pass a DTB to the bootloader, we will have to append the DTB to the kernel. We set the option to enable this in the kernel configuration downloaded in step 4.
cd $MIRABUILD/linux-stable
RELEASE=$(make ARCH=arm kernelrelease)
sudo cp arch/arm/boot/zImage $MIRABUILD/debian_armhf_stretch/boot/vmlinuz-$RELEASE
cat arch/arm/boot/dts/armada-370-mirabox.dtb | sudo tee -a $MIRABUILD/debian_armhf_stretch/boot/vmlinuz-$RELEASE >/dev/null
sudo chroot $MIRABUILD/debian_armhf_stretch mkimage -A arm -O linux -C none -a 0x00008000 -e 0x00008000 -n uImage-$RELEASE -d /boot/vmlinuz-$RELEASE /uboot/uImage-$RELEASE
Secondly, we will install the kernel modules.
cd $MIRABUILD/linux-stable
make ARCH=arm modules
sudo make ARCH=arm INSTALL_MOD_PATH=$MIRABUILD/debian_armhf_stretch modules_install
Thirdly, we will create the initial ramdisk.
sudo chroot $MIRABUILD/debian_armhf_stretch update-initramfs -c -k $RELEASE
If you've already created an initial ramdisk and need to update, use this instead:
sudo chroot $MIRABUILD/debian_armhf_stretch update-initramfs -u -k $RELEASE
Now, create the u-boot
initial ramdisk image:
sudo chroot $MIRABUILD/debian_armhf_stretch mkimage -A arm -O linux -T ramdisk -C none -a 0 -e 0 -n uInitrd-$RELEASE -d /boot/initrd.img-$RELEASE /uboot/uInitrd-$RELEASE
Step 10 - Install some additional packages required for the Mirabox
We will now install some additional packages that are appropriate for a Mirabox. These include the utilities for PCI, USB, MTD and Wireless components. Also, I use the busybox-syslogd as it doesn't continually write to the filesystem, thus preserving the life of the NAND flash.
sudo chroot $MIRABUILD/debian_armhf_stretch apt-get install --purge -y bluez crda iw mtd-utils pciutils usbutils wireless-regdb wpasupplicant busybox-syslogd
While we are on, remove a package or two we don't need. If you think you need any of these packages, don't remove them!
sudo chroot $MIRABUILD/debian_armhf_stretch apt-get remove --purge dmidecode tasksel tasksel-data debconf-i18n gnupg gnupg-agent
Finally, we will install the SD8787 firmware so that the onboard wireless works. Note! This is for v1 and v2 of the Mirabox. v3 uses a different wireless chip, and I don't have access to one.
sudo mkdir -p $MIRABUILD/debian_armhf_stretch/lib/firmware
wget -O- 'https://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git/plain/mrvl/sd8787_uapsta.bin' | sudo tee $MIRABUILD/debian_armhf_stretch/lib/firmware/sd8787_uapsta.bin >/dev/null
Step 11 - Configure the chroot environment for the Mirabox
Before we create the SD Card image, we need to set up the chroot environment so that when the Mirabox boots from it, things will work correctly.
Set the hostname of the image.
echo mirabox | sudo tee "$MIRABUILD/debian_armhf_stretch/etc/hostname" >/dev/null
Create a suitable filesystem table (/etc/fstab).
wget -O- https://www.solinno.co.uk/public/mirabox/etc_fstab | sudo tee "$MIRABUILD/debian_armhf_stretch/etc/fstab" >/dev/null
Create a suitable inittab placing a getty on the Mirabox serial port.
wget -O- https://www.solinno.co.uk/public/mirabox/etc_inittab | sudo tee "$MIRABUILD/debian_armhf_stretch/etc/inittab" >/dev/null
Add the configuration file for fw_printenv
and fw_setenv
so the u-boot configuration and be modified from the operating system.
wget -O- https://www.solinno.co.uk/public/mirabox/etc_fw_env.config | sudo tee "$MIRABUILD/debian_armhf_stretch/etc/fw_env.config" >/dev/null
Set the root password so we can login the first time we boot.
echo 'root:mirabox' | sudo chpasswd -c SHA512 -R "$MIRABUILD/debian_armhf_stretch"
Step 12 - Create the SD Card image
We will now create an SD card image with a small MS-DOS partition and filling the rest of the image with an ext4 partition. In the dd command seek=1886 will create a (slightly less than) 2GB image suitable for a typical SD card. You may need to check your SD card to see how many sectors are on it to get this precisely right.
rm -f $MIRABUILD/sdcard.img
dd if=/dev/zero of=$MIRABUILD/sdcard.img bs=1024k count=0 seek=1886
sudo losetup /dev/loop0 $MIRABUILD/sdcard.img
sudo parted -s /dev/loop0 mklabel msdos
sudo parted -s /dev/loop0 unit s mkpart primary fat32 -- 2048 64MB
sudo parted -s /dev/loop0 set 1 boot on
sudo parted -s /dev/loop0 unit s mkpart primary ext4 -- 64MB -1
Now, create the filesystems on the image:
sudo mkfs.vfat -n miraboot /dev/loop0p1
sudo mkfs.ext4 -L miraroot /dev/loop0p2
Don't worry about the warning issued by mkfs.vfat, it won't affect the Mirabox.
Step 13 - Mount the SD Card image
Now we create loop devices for the indivual partitions, and mount them.
sudo fdisk -l /dev/loop0 | awk '/loop0p1/{print "losetup /dev/loop1 '$MIRABUILD'/sdcard.img -o " $3 * 512 " --sizelimit " $4 * 512}' | sudo sh
sudo fdisk -l /dev/loop0 | awk '/loop0p2/{print "losetup /dev/loop2 '$MIRABUILD'/sdcard.img -o " $2 * 512 " --sizelimit " $3 * 512}' | sudo sh
sudo mkdir $MIRABUILD/sysimage
sudo mount -t ext4 /dev/loop2 $MIRABUILD/sysimage
sudo mkdir $MIRABUILD/sysimage/uboot
sudo mount -t vfat /dev/loop1 $MIRABUILD/sysimage/uboot
Step 14 - Populate the SD Card image
In this step, we will copy the files across from the chroot environment to the mounted filesystems on the SD Card image file.
sudo rsync -a $MIRABUILD/debian_armhf_stretch/ $MIRABUILD/sysimage/
We can check to see how full the filesystems are, there should be plenty of space free.
df -h $MIRABUILD/sysimage $MIRABUILD/sysimage/uboot
Once we are happy, unmount the filesystems and remove the loop devices.
sudo umount $MIRABUILD/sysimage/uboot
sudo umount $MIRABUILD/sysimage
sudo losetup -d /dev/loop2
sudo losetup -d /dev/loop1
sudo losetup -d /dev/loop0
Step 15 - Copy the SD Card image to a real SD card
This step is DANGEROUS! Make sure you select the correct device for your SD Card reader. Replace /dev/sdXXXXX with the correct device. Check three times before proceeding.
sudo dd if=$MIRABUILD/sdcard.img of=/dev/sdXXXXX bs=2048
Step 16 - Boot on the Mirabox
Interrupt autoboot then type in the following commands to the Marvell> prompt.
usb start
fatload usb 1 0x6400000 uImage-4.14.16+
fatload usb 1 0x7400000 uInitrd-4.14.16+
setenv bootargs console=ttyS0,115200 root=LABEL=miraroot rootdelay=4
bootm 0x6400000 0x7400000
All being well, you now have an SD card that you can manually boot a recent Debian version with a recent kernel.
When I get time I will add instructions to transfer the SD card image to the onboard flash.
If any part of this procedure does not work, please contact leigh AT solinno DOT co DOT uk for assistance.
Step 17 - Rough notes for the moment - ignore for now
To erase kernel and initial ramdisk area in one go:
nand erase 0x400000 0x400000
To erase kernel and initial ramdisk individually:
nand erase 0x400000 0x200000
nand erase 0x600000 0x200000
To write kernel and initial ramdisk:
nand write 0x6400000 0x400000 0x200000
nand write 0x7400000 0x600000 0x200000
To load kernel and initial ramdisk from nand and boot:
nand read 0x6400000 0x400000 0x400000
bootm 0x6400000 0x6600000
For the following refer to Re: Re-Installing OS on Mirabox. Inspect or change a rootfs UBI Image file
Changelog
- V1.0 2018-02-04 Initial release.
- V1.1 2018-02-05 Add download of SD8787 firmware. Fix patching kernel.
- V1.2 2018-02-06 Add note about initial ramdisk fsck failure.
- V1.3 2018-02-06 Add download of /etc/fw_env.config for fw_printenv.
Notes
setenv bootcmd_nand "nand read 0x6400000 0x400000 0x400000; run bootargs_nand; bootm 0x6400000"
setenv bootargs_nand "setenv bootargs console=ttyS0,115200 $mtdparts ubi.mtd=2 root=ubi0:rootfs rootfstype=ubifs"
setenv bootcmd_mmc "usb start; fatload usb 1 0x6400000 uImage-4.14.16+; fatload usb 1 0x7400000 uInitrd-4.14.16+; run bootargs_mmc; bootm 0x6400000 0x7400000"
setenv bootargs_mmc "setenv bootargs console=ttyS0,115200 root=LABEL=miraroot rootdelay=4"
setenv bootcmd "run bootcmd_mmc"
saveenv