commit be22fbbb0a10ca5d561aaecd516127b4d1c3bc84
parent 9f87fd86258a0757de246d16091fd9fe310e5ca6
Author: Daniel Barlow <dan@telent.net>
Date: Wed, 20 Sep 2023 22:53:59 +0100
bootable aarch64 liminux with qemu
I may have broken the run-liminix-vm command a bit for MIPS due to
necessary changes in how we pass the command line. If CI isn't green
for this commit and youre trying the worked examples, I suggest
reverting to the commit before this one.
Diffstat:
5 files changed, 131 insertions(+), 12 deletions(-)
diff --git a/devices/qemu-aarch64/default.nix b/devices/qemu-aarch64/default.nix
@@ -0,0 +1,69 @@
+# This "device" generates images that can be used with the QEMU
+# emulator. The default output is a directory containing separate
+# kernel ("Image" format) and root filesystem (squashfs or jffs2)
+# images
+{
+ system = {
+ crossSystem = {
+ config = "aarch64-unknown-linux-musl";
+ };
+ };
+
+ module = {pkgs, config, ... }: {
+ imports = [ ../../modules/arch/aarch64.nix ];
+ kernel = {
+ src = pkgs.pkgsBuildBuild.fetchurl {
+ name = "linux.tar.gz";
+ url = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.71.tar.gz";
+ hash = "sha256-yhO2cXIeIgUxkSZf/4aAsF11uxyh+UUZu6D1h92vCD8=";
+ };
+ config = {
+ VIRTUALIZATION = "y";
+ PCI_HOST_GENERIC="y";
+
+ MTD = "y";
+ MTD_BLOCK2MTD = "y";
+ MTD_BLKDEVS = "y";
+ MTD_BLOCK = "y";
+
+ VIRTIO_MENU = "y";
+ PCI = "y";
+ VIRTIO_PCI = "y";
+ BLOCK = "y";
+ VIRTIO_BLK = "y";
+ NETDEVICES = "y";
+ VIRTIO_NET = "y";
+
+ SERIAL_EARLYCON_ARM_SEMIHOST = "y"; # earlycon=smh
+ SERIAL_AMBA_PL011 = "y";
+ SERIAL_AMBA_PL011_CONSOLE = "y";
+ };
+ };
+ hardware =
+ let
+ mac80211 = pkgs.mac80211.override {
+ drivers = ["mac80211_hwsim"];
+ klibBuild = config.system.outputs.kernel.modulesupport;
+ };
+ in {
+ defaultOutput = "vmroot";
+ loadAddress = "0x0";
+ entryPoint = "0x0";
+ rootDevice = "/dev/mtdblock0";
+
+ flash.eraseBlockSize = "65536"; # c.f. pkgs/mips-vm/mips-vm.sh
+ networkInterfaces =
+ let inherit (config.system.service.network) link;
+ in {
+ wan = link.build { ifname = "eth0"; };
+ lan = link.build { ifname = "eth1"; };
+
+ wlan_24 = link.build {
+ ifname = "wlan0";
+ dependencies = [ mac80211 ];
+ };
+ };
+ };
+
+ };
+}
diff --git a/devices/qemu/default.nix b/devices/qemu/default.nix
@@ -49,6 +49,7 @@
};
in {
defaultOutput = "vmroot";
+ rootDevice = "/dev/mtdblock0";
flash.eraseBlockSize = "65536"; # c.f. pkgs/run-liminix-vm/run-liminix-vm.sh
networkInterfaces =
let inherit (config.system.service.network) link;
diff --git a/modules/arch/aarch64.nix b/modules/arch/aarch64.nix
@@ -0,0 +1,16 @@
+{ lib, pkgs, config, ...}:
+{
+ config = {
+ kernel.config = {
+ CPU_LITTLE_ENDIAN= "y";
+ CPU_BIG_ENDIAN= "n";
+ # CMDLINE_FROM_BOOTLOADER availability is conditional
+ # on CMDLINE being set to something non-empty
+ CMDLINE="\"console=ttyAMA0\"";
+ CMDLINE_FROM_BOOTLOADER = "y";
+ };
+ boot.commandLine = [
+ "console=ttyAMA0,38400"
+ ];
+ };
+}
diff --git a/modules/outputs.nix b/modules/outputs.nix
@@ -7,6 +7,12 @@
let
inherit (lib) mkOption types concatStringsSep;
inherit (pkgs) liminix callPackage writeText;
+ arch = let s = pkgs.stdenv; in
+ if s.isAarch64
+ then "aarch64"
+ else if s.isMips
+ then "mips"
+ else throw "can't determine arch";
in
{
imports = [
@@ -76,14 +82,27 @@ in
inherit dtb;
};
# could use trivial-builders.linkFarmFromDrvs here?
- vmroot = pkgs.runCommand "qemu" {} ''
- mkdir $out
- cd $out
- ln -s ${config.system.outputs.rootfs} rootfs
- ln -s ${kernel} vmlinux
- ln -s ${manifest} manifest
- ln -s ${kernel.headers} build
- '';
+ vmroot =
+ let
+ cmdline = builtins.toJSON (concatStringsSep " " config.boot.commandLine);
+ makeBootableImage = pkgs.runCommandCC "objcopy" {}
+ (if pkgs.stdenv.isAarch64
+ then "${pkgs.stdenv.cc.targetPrefix}objcopy -O binary -S ${kernel} $out"
+ else "cp ${kernel} $out");
+ in pkgs.runCommandCC "vmroot" {} ''
+ mkdir $out
+ cd $out
+ ln -s ${config.system.outputs.rootfs} rootfs
+ ln -s ${kernel} vmlinux
+ ln -s ${manifest} manifest
+ ln -s ${kernel.headers} build
+ echo ${cmdline} > commandline
+ cat > run.sh << EOF
+ #!${pkgs.runtimeShell}
+ CMDLINE=${cmdline} run-liminix-vm --arch ${arch} ${makeBootableImage} ${config.system.outputs.rootfs}
+ EOF
+ chmod +x run.sh
+ '';
manifest = writeText "manifest.json" (builtins.toJSON config.filesystem.contents);
};
diff --git a/pkgs/run-liminix-vm/run-liminix-vm.sh b/pkgs/run-liminix-vm/run-liminix-vm.sh
@@ -12,6 +12,12 @@ usage(){
exit 1
}
+arch="mips"
+if test "$1" = "--arch" ; then
+ arch=$2
+ shift;shift
+fi
+
if test "$1" = "--background" ; then
statedir=$2
if test -z "$statedir" || ! test -d $statedir ; then
@@ -39,13 +45,21 @@ if test -n "$3"; then
initramfs="-initrd $3"
fi
+case "$arch" in
+ mips)
+ QEMU="qemu-system-mips -M malta"
+ ;;
+ aarch64)
+ QEMU="qemu-system-aarch64 -M virt -semihosting -cpu cortex-a72"
+ ;;
+esac
INIT=${INIT-/bin/init}
-echo $QEMU_OPTIONS
-qemu-system-mips \
- -M malta -m 256 \
+set -x
+$QEMU \
+ -m 256 \
-echr 16 \
- -append "liminix default console=ttyS0,38400n8 panic=10 oops=panic init=$INIT loglevel=8 root=/dev/mtdblock0 block2mtd.block2mtd=/dev/vda,65536" \
+ -append "$CMDLINE liminix root=/dev/mtdblock0 block2mtd.block2mtd=/dev/vda,65536" \
-drive file=$rootfs,format=raw,readonly=off,if=virtio,index=0 \
${initramfs} \
-netdev socket,id=access,mcast=230.0.0.1:1234,localaddr=127.0.0.1 \