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.
This commit is contained in:
Daniel Barlow 2023-09-20 22:53:59 +01:00
parent 9f87fd8625
commit be22fbbb0a
5 changed files with 131 additions and 12 deletions

View file

@ -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 ];
};
};
};
};
}

View file

@ -49,6 +49,7 @@
}; };
in { in {
defaultOutput = "vmroot"; defaultOutput = "vmroot";
rootDevice = "/dev/mtdblock0";
flash.eraseBlockSize = "65536"; # c.f. pkgs/run-liminix-vm/run-liminix-vm.sh flash.eraseBlockSize = "65536"; # c.f. pkgs/run-liminix-vm/run-liminix-vm.sh
networkInterfaces = networkInterfaces =
let inherit (config.system.service.network) link; let inherit (config.system.service.network) link;

16
modules/arch/aarch64.nix Normal file
View file

@ -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"
];
};
}

View file

@ -7,6 +7,12 @@
let let
inherit (lib) mkOption types concatStringsSep; inherit (lib) mkOption types concatStringsSep;
inherit (pkgs) liminix callPackage writeText; 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 in
{ {
imports = [ imports = [
@ -76,14 +82,27 @@ in
inherit dtb; inherit dtb;
}; };
# could use trivial-builders.linkFarmFromDrvs here? # could use trivial-builders.linkFarmFromDrvs here?
vmroot = pkgs.runCommand "qemu" {} '' vmroot =
mkdir $out let
cd $out cmdline = builtins.toJSON (concatStringsSep " " config.boot.commandLine);
ln -s ${config.system.outputs.rootfs} rootfs makeBootableImage = pkgs.runCommandCC "objcopy" {}
ln -s ${kernel} vmlinux (if pkgs.stdenv.isAarch64
ln -s ${manifest} manifest then "${pkgs.stdenv.cc.targetPrefix}objcopy -O binary -S ${kernel} $out"
ln -s ${kernel.headers} build 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); manifest = writeText "manifest.json" (builtins.toJSON config.filesystem.contents);
}; };

View file

@ -12,6 +12,12 @@ usage(){
exit 1 exit 1
} }
arch="mips"
if test "$1" = "--arch" ; then
arch=$2
shift;shift
fi
if test "$1" = "--background" ; then if test "$1" = "--background" ; then
statedir=$2 statedir=$2
if test -z "$statedir" || ! test -d $statedir ; then if test -z "$statedir" || ! test -d $statedir ; then
@ -39,13 +45,21 @@ if test -n "$3"; then
initramfs="-initrd $3" initramfs="-initrd $3"
fi 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} INIT=${INIT-/bin/init}
echo $QEMU_OPTIONS set -x
qemu-system-mips \ $QEMU \
-M malta -m 256 \ -m 256 \
-echr 16 \ -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 \ -drive file=$rootfs,format=raw,readonly=off,if=virtio,index=0 \
${initramfs} \ ${initramfs} \
-netdev socket,id=access,mcast=230.0.0.1:1234,localaddr=127.0.0.1 \ -netdev socket,id=access,mcast=230.0.0.1:1234,localaddr=127.0.0.1 \