I continued where I left off from my previous post with a USB Armory and an FT232RL connected thru UART for communication to host.
Compiling the kernel
Turns out it's just vanilla kernel with custom config. The only vendor specific things beside the kernel config are the kernel device trees and a driver for some security controller specific to i.MX53 SoC.
First, I downloaded the source packages, which the kernel source code from kernel.org as well as the NXP security controller driver.
export LINUX_VER=6.6.24 LOCALVERSION=-0
wget https://www.kernel.org/pub/linux/kernel/v6.x/linux-${LINUX_VER}.tar.xz
wget https://github.com/usbarmory/mxc-scc2/archive/master.zip -O mxc-scc2-master.zip
Then I downloaded the configs and DTSs from the USB armory repo
cat > dts_list.txt << EOF
imx53-usbarmory-host.dts
imx53-usbarmory-gpio.dts
imx53-usbarmory-spi.dts
imx53-usbarmory-i2c.dts
imx53-usbarmory-scc2.dts
EOF
wget -B "https://raw.githubusercontent.com/usbarmory/usbarmory/master/software/kernel_conf/mark-one/" -i dts_list.txt -C dts
wget https://raw.githubusercontent.com/usbarmory/usbarmory/master/software/kernel_conf/usbarmory_linux-6.6.defconfig
Time to start building
tar -xf linux-${LINUX_VER}.tar.xz
cd linux-${LINUX_VER}
make mrproper
cp ../usbarmory_linux-6.6.defconfig .config
LOCALVERSION=${LOCALVERSION} ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- make -j8 olddefconfig zImage modules nxp/imx/imx53-usbarmory.dtb
cp ../dts/* arch/arm/boot/dts/nxp/imx/
LOCALVERSION=${LOCALVERSION} ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- make -j8 nxp/imx/imx53-usbarmory-host.dtb nxp/imx/imx53-usbarmory-gpio.dtb nxp/imx/imx53-usbarmory-spi.dtb nxp/imx/imx53-usbarmory-i2c.dtb nxp/imx/imx53-usbarmory-scc2.dtb
cd ..
unzip -o mxc-scc2-master.zip
cd mxc-scc2-master
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- KERNEL_SRC=../linux-${LINUX_VER} -j8 all
Last but not least, all the final output files are put under a single directory.
mkdir -p kernel-final/{boot,lib/modules}
cd linux-${LINUX_VER}
make INSTALL_MOD_PATH=../kernel-final ARCH=arm modules_install
cp -r arch/arm/boot/zImage kernel-final/boot/zImage-${LINUX_VER}${LOCALVERSION}-usbarmory
cp -r .config kernel-final/boot/config-${LINUX_VER}${LOCALVERSION}-usbarmory
cp -r System.map kernel-final/boot/System.map-${LINUX_VER}${LOCALVERSION}-usbarmory
cp -r arch/arm/boot/dts/nxp/imx/imx53-usbarmory.dtb ../kernel-final/boot/imx53-usbarmory-default-${LINUX_VER}${LOCALVERSION}.dtb
cp -r arch/arm/boot/dts/nxp/imx/imx53-usbarmory-host.dtb ../kernel-final/boot/imx53-usbarmory-host-${LINUX_VER}${LOCALVERSION}.dtb
cp -r arch/arm/boot/dts/nxp/imx/imx53-usbarmory-spi.dtb ../kernel-final/boot/imx53-usbarmory-spi-${LINUX_VER}${LOCALVERSION}.dtb
cp -r arch/arm/boot/dts/nxp/imx/imx53-usbarmory-gpio.dtb ../kernel-final/boot/imx53-usbarmory-gpio-${LINUX_VER}${LOCALVERSION}.dtb
cp -r arch/arm/boot/dts/nxp/imx/imx53-usbarmory-i2c.dtb ../kernel-final/boot/imx53-usbarmory-i2c-${LINUX_VER}${LOCALVERSION}.dtb
cp -r arch/arm/boot/dts/nxp/imx/imx53-usbarmory-scc2.dtb ../kernel-final/boot/imx53-usbarmory-scc2-${LINUX_VER}${LOCALVERSION}.dtb
cd ../mxc-scc2-master
make INSTALL_MOD_PATH=../kernel-final ARCH=arm KERNEL_SRC=../linux-${LINUX_VER} modules_install
rm -f kernel-final/lib/modules/${LINUX_VER}${LOCALVERSION}/{build,source}
Following the convention of Alpine Linux, I moved all the imx53-usbarmory-*.dtb
to a single directory under boot
, which I promptly named dtbs-usbarmory
. I then copied the content of kernel-final/boot
into the boot
directory of micro SD. The original Makefile would have me linking imx53-usbarmory.dtb
to imx53-usbarmory-default-6.624-0.dtb
, but FAT filesystems don't support symlink. So I simply copied it instead.
Modifying the modloop
A modloop is simply a squashfs image.
just modify the modloop to add the kernel modules
unsquashfs modloop-lts
rm squashfs-root/modules/*
cp kernel-final/modules/* squashfs-root/modules/
mksquashfs .modloop squashfs-root/ ~/Project/usbarmory/modloop-usbarmory -b 1048576 -comp xz -Xdict-size 100% -all-root
Turns out xz is not supported in the usbarmory kernel config. So I had to redo it with gzip compression, which is the default.
mksquashfs .modloop squashfs-root/ ~/Project/usbarmory/modloop-usbarmory -b 1048576 -all-root
Modifying the initramfs
Now I need to add the modules to the initramfs as well.
I thought about generating it like a civilized person. Just like any Linux distro you can think of, Alpine has a utility for generating initramfs, this one is called mkinitfs
. I tried it, but it just didn't work out. So I resorted to repackaging an existing one from the tar package.
First, I extracted the initramfs.
mkdir /tmp/initramfs ; cd /tmp/initramfs
gunzip -c '/mnt/mmcblk0p1/boot/initramfs-lts' | cpio -i
Then I removed the modules of the old kernel and placed the new ones I built.
rm -r lib/modules/*
cp -r ~/Project/usbarmory/kernel/kernel-final/lib/modules/6.6.24-0/ lib/modules/
Finally, I repacked it.
find | cpio -o -H newc | gzip > /tmp/initramfs-6.6.24-0-usbarmory
After inspecting the result, I was satisfied, and copied the initramfs to the boot
directory of micro SD.
Alpine Overlay
Usually, setting up Alpine requires a screen and a keyboard. But that's not possible with USB Armory since it has none of those.
While I've been doing just fine with the UART, I'd rather have SSH just like how it was with the stock OS.
Thankfully, somebody created this thing that sets up the network and enables SSH upon boot.
The original Alpine tar package comes with an overlay called alpine.ovlapk.tar.gz
. However, this doesn't seem to play nicely when I try to have the headless.ovlapk.tar.gz
. I suspect the system doesn't seem to like it when I have multiple overlay.
In the end, I got rid of alpine.ovlapk.tar.gz
and just have headless.ovlapk.tar.gz
on the root of my micro SD.
For static IP, I added a file called interfaces
on the root of my micro SD.
auto usb0
allow-hotplug usb0
iface usb0 inet static
netmask 255.255.255.0
address 10.0.100.1
gateway 10.0.100.2
extlinux
Last but not least, I modified extlinux/extlinux.conf
in the micro SD.
Most importantly, I changed KERNEL
and INITRD
parameters to include my new kernel and initramfs. FTDDIR
was also changed accordingly.
On the APPEND
parameter, which is the kernel command line, I ensured to have ledtrig-heartbeat
as well as g_ether
in the modules
option which contains a comma-separated list of modules to load upon boot. I also included the modloop
option to point to the modloop that I made.
As a finishing touch, I changed all the labels from lts
to usbarmory
to better represent the current configuration. I also shortened the TIMEOUT
from 10 to 3 seconds.
My extlinux/extlinux.conf
then became:
TIMEOUT 3
PROMPT 1
DEFAULT usbarmory
LABEL usbarmory
MENU LABEL Linux usbarmory
KERNEL /boot/zImage-6.6.24-0-usbarmory
INITRD /boot/initramfs-6.6.24-0-usbarmory
FDTDIR /boot/dtbs-usbarmory
APPEND modules=loop,squashfs,sd-mod,usb-storage,ledtrig-heartbeat,g_ether quiet modloop=/boot/modloop-usbarmory
Making Connections
When I connected the USB Armory to my PC, it finally appeared as a network device!
The network setting on my PC needs to be set manual, with the IP of 10.0.100.2
and gateway of 10.0.100.1
, which is opposite of what's on the interface
file above.
I was able to then ssh in with ssh root@10.0.100.1
without any issue.
The USB Armory itself is not automatically connected to the internet. For this, I simply put a NAT forwarding on my PC thru iptables.
sudo iptables -t nat -A POSTROUTING -s 10.0.100.1/32 -o wlp3s0 -j MASQUERADE
And voila, I was able to ping the internet this way!
Next up: further customizations thru overlay!
Ref:
- https://github.com/macmpi/alpine-linux-headless-bootstrap
- https://github.com/usbarmory/usbarmory-debian-base_image