I think the best way to get the Espressobin board running is installing Armbian. The good folks (or... the one person running the show?) build a decently working U-Boot and kernel and there is an SD card image that you can just dd onto a SD card. You don't even have to expand the partition to cover the whole SD card after copying the image -- after boot it expands it automatically.
This is all cool and dandy... But if you want to build your own U-Boot or kernel, Armbian does not make it easy. There is official documentation on how to build Armbian. This makes sense when you want to build the whole system but not so much if you just want to build the U-Boot and the kernel. Yet the fact that Armbian uses reasonably recent U-Boot and kernel, together with a bunch of patches, is interesting and I wanted to get to the U-Boot and kernel sources w/o having to run the whole Armbian build machinery. So I took a dive into the Armbian build scripts.
The build scripts including Armbian patches live in a github repo. Depending on when you read this, Armbian might have moved on. This dive is based on commit 5659f7fffa which is current master at the time of writing this.
If you followed the official build instructions, you would run compile.sh. This eventually sources lib/main.sh. Following the breadcrumbs:
- prepare_host is called which, among other things downloads all toolchains used by Armbian (for all possible targets)
- if not yet selected via config, it asks for the user to select a board
- the available board configurations are stored in config/boards; the Espressobin config lives in espressobin.conf
- the board config file is sourced
- LINUXFAMILY is set to BOARDFAMILY, which is "mvebu64" for the Espressobin
- kernel "branch" is selected using a bit of funky string matching; for the Espressobin, the board config currently specifies the branches default and next; the result is stored in the variable BRANCH
- the actual meaning of default and next is defined in config/sources/mvebu64.conf -- see further down, but the summary is: default is Marvell's 4.14.22 kernel, next is mainline linux-4.19.y
- lib/configuration.sh is sourced
- config/sources/$LINUXFAMILY.conf is sourced -- this pulls in config/sources/mvebu64.conf for the Espressobin
- this defines sources to use for building the kernel, U-Boot, ATF
- this also defines what branches/tags to check out
- LINUXCONFIG is set to "linux-${LINUXFAMILY}-${BRANCH}" -- so for Espressobin and branch next, it's set to "linux-mvebu64-next"
- KERNELPATCHDIR is set to "$LINUXFAMILY-$BRANCH" which expands to "mvebu64-next" for Espressobin next
- sources are fetched, assuming the Espressobin with kernel branch "next" and using config at the time of writing this, the following ATF, U-Boot and kernel are fetched:
- ATF: https://github.com/MarvellEmbeddedProcessors/atf-marvell, branch atf-v1.5-armada-18.12
- U-Boot: https://github.com/MarvellEmbeddedProcessors/u-boot-marvell.git, branch u-boot-2018.03-armada-18.12
- kernel: mainline (git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git), branch linux-4.19.y
- ATF and U-Boot are built
- kernel is build
- attempts to apply patches via advanced_patch from multiple directories:
- patch/kernel/mvebu64-next/target_next
- patch/kernel/mvebu64-next/board_espressobin
- patch/kernel/mvebu64-next/branch_mvebu64-next
- patch/kernel/mvebu64-next
- for the Espressobin, currently only patch/kernel/mvebu64-next is relevant
- the patches are applied in alphabetic order across all the searched directories
- each patch is applied via process_patch_file
- when a patch creates a file, original file is deleted
- patch is applied via patch --batch --silent -p1 -N $patch
- some extra patches are applied, like some shady Realtek drivers
- config/kernel/$LINUXCONFIG.config (config/kernel/linux-mvebu64-next.config) is used as the kernel config
- the kernel is built via:
- make ARCH=$ARCHITECTURE CROSS_COMPILE="$CCACHE $KERNEL_COMPILER" olddefconfig
- make $CTHREADS ARCH=$ARCHITECTURE CROSS_COMPILE="$CCACHE $KERNEL_COMPILER" LOCALVERSION="-$LINUXFAMILY" $KERNEL_IMAGE_TYPE modules dtbs
- for Espressobin next the variables expand to:
- ARCHITECTURE=arm64 (see lib/configuration.sh)
- KERNEL_COMPILER=aarch64-linux-gnu- (see lib/configuration.sh, download_toolchain and find_toolchain)
- LOCALVERSION="-mvebu64"
- KERNEL_IMAGE_TYPE=Image
- the PATH is adjusted so that the compiler from the toolchain is found first (for the Espressobin the toolchain used is gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu.tar.xz)
- clone mainline kernel git repo e.g. from git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git
- check out branch linux-4.19.y
- clone Armbian build repo from https://github.com/armbian/build.git to get hold of kernel patches
- apply patches from Armbian build repo, from patch/kernel/mvebu64-next
- this seems like the tricky part: the patches are a varied bunch, a simple git am would not work as some patches are indeed just plain patches
- I created a helper script that tries to apply the patches, making a commit for each: apply-armbian-patches.sh
- use config from config/kernel/linux-mvebu64-next.config
- make the targets Image, modules and dtb
- copy the right results
- To get the modules copied into a directory, you can run make INSTALL_MOD_PATH=some-dir modules_install. These need to be copied into /lib/modules on the Espressobin.
- You need the actual kernel image which lives in arch/arm64/boot/Image. This needs to be copied into /boot. Armbian names these vmlinuz-$VERSION$LOCALVERSION, e.g. vmlinuz-4.19.13-mvebu64
- You need device tree binary files that live in arch/arm64/boot/dts/marvel/*.dtb. These should be copied to /boot/dtb-$VERSION$LOCALVERSION/marvell, e.g. /boot/dtb-4.19.13-mvebu64/marvell.
- You could also use a script that does the build + copying: espressobin-kernel-install.sh
- Create initramfs for the new kernel. On the Espressobin, run as root: update-initramfs -c -k $VERSION$LOCALVERSION (e.g. update-initramfs -c -k 4.19.14-ebin-mine)
- as a sometimes-unwanted bonus, this seems to also update the uInitrd symlink (see below)
- There are symlinks in /boot that point to the current version of kernel, initramfs and dtb, so update these:
- dtb → dtb-$VERSION$LOCALVERSION
- Image → vmlinuz-$VERSION$LOCALVERSION
- uInitrd → uInitrd-$VERSION$LOCALVERSION
- Reboot and hope for the best. :-)
Hi that's a fantastic breakdown of the workflow inside the armbian build framework. Do you mind if I reuse this and add it to the documentation?
ReplyDeleteFYI you're also welcome to contribute to the docs :) https://github.com/armbian/documentation
Feel free to use whatever you find useful here.
DeleteThis was written mostly as a note to myself, for when I need it next time. With my one interaction with Armbian forums, and after reading the docs, I did not think this kind of info would be welcome.