Linux kernel cross compilation

Cross-compiling the Linux kernel has been documented of course, and make.cross exists to help with that. But we wanted to boot the kernel via Qemu later on and that's when things got tricky. On a Fedora x86_64 system:

$ sudo dnf install gcc-sparc64-linux-gnu qemu-system-sparc
$ export CCACHE_DIR=/var/tmp/ccache DIR=/var/tmp/linux_sparc
$ cd /usr/local/src/linux
$ mkdir ${CCACHE_DIR} ${DIR}
$ make     O=${DIR} ARCH=sparc64 CROSS_COMPILE="ccache sparc64-linux-gnu-" defconfig
$ make -j8 O=${DIR} ARCH=sparc64 CROSS_COMPILE="ccache sparc64-linux-gnu-" zImage

Once completed, we should have Sparc64 kernels in ${DIR}/arch/sparc/boot:

$ ls -hgo ${DIR}/arch/sparc/boot/
total 22M
-rwxr-x---. 1  17M Feb 14 18:03 image
-rw-r-----. 1 4.5M Feb 14 18:03 zImage

Booting via qemu makes more sense with a small initrd and we needed a working BusyBox installation as well. But Fedora no longer ships SPARC binaries, and due to missing header files we were unable to cross-compile BusyBox on Fedora. A Debian VM was able to help here:

$ sudo apt-get install gcc-sparc64-linux-gnu libc6-dev-sparc64-cross
$ git clone git://busybox.net/busybox.git
$ cd busybox
$ LDFLAGS="--static" make     O=${DIR} ARCH=sparc64 CROSS_COMPILE="sparc64-linux-gnu-" defconfig
$ LDFLAGS="--static" make -j8 O=${DIR} ARCH=sparc64 CROSS_COMPILE="sparc64-linux-gnu-"
$ file -L ./busybox
./busybox: ELF 64-bit MSB executable, SPARC V9, Sun UltraSPARC1 Extensions Required, relaxed memory ordering [...]

Transfer that busybox binary to the Fedora machine and we can now construct our initrd:

$ cat /var/tmp/m.sh
#!/bin/bash -e

outfile=/var/tmp/initrd.cpio
cd $(mktemp -d)
echo "Preparing initrd in $(pwd)..."

mkdir {bin,dev,mnt,proc,sys}

cat > init << EOF
#!/bin/sh
mount -t devtmpfs none /dev
mount -t proc     none /proc
mount -t sysfs    none /sys
echo
echo Mounting...
mount /dev/sda /mnt -t ext4     # Adjust as needed
exec /bin/sh
EOF
chmod +x init

cp /var/tmp/busybox.sparc64 bin/busybox
$(pwd)/bin/busybox --install bin

find . | cpio -o -H newc > ${outfile}
echo "Written to ${outfile}."

Create a small root disk and the initrd:

$ dd if=/dev/zero of=/var/tmp/ext4.img bs=1M count=512
$ mkfs.ext4 /var/tmp/ext4.img
$ sh /var/tmp/m.sh
Preparing initrd in /run/user/1000/tmp.ZLodtsGu72...
4488 blocks
Written to /var/tmp/initrd.cpio.

Now we are finally read to start the new kernel in qemu:

$ qemu-system-sparc64 -kernel ${DIR}/arch/sparc/boot/image -initrd /var/tmp/initrd.cpio \
    -m 512M -drive file=/var/tmp/ext4.img,format=raw -nographic
OpenBIOS for Sparc64
Configuration device id QEMU version 1 machine id 0
kernel phys 404000 virt 40004000 size 0x12d5870
initrd phys 16d6000 virt 40c00000 size 0x231000
kernel cmdline
CPUs: 1 x SUNW,UltraSPARC-IIi
UUID: 00000000-0000-0000-0000-000000000000
Welcome to OpenBIOS v1.1 built on Jul 22 2022 02:10
  Type 'help' for detailed information
[sparc64] Kernel already loaded

[    0.000878] PROMLIB: Sun IEEE Boot Prom 'OBP 3.10.24 1999/01/01 01:01'
[    0.002626] PROMLIB: Root node compatible: sun4u
[    0.003236] Linux version 6.2.0-rc8 sparc64-linux-gnu-gcc (GCC) 12.2.1 20220819
[    0.009692] printk: bootconsole [earlyprom0] enabled
[    0.018163] ARCH: SUN4U
[...]

~ # uname -a; df -h
Linux (none) 6.2.0-rc8 #1 SMP Tue Feb 14 18:02:02 CET 2023 sparc64 GNU/Linux
Filesystem                Size      Used Available Use% Mounted on
none                    240.1M         0    240.1M   0% /dev
/dev/sda                487.2M     24.0K    451.3M   0% /mnt

And with that, we do have a running Sparc machine.