diff --git a/devices/qemu-aarch64/default.nix b/devices/qemu-aarch64/default.nix new file mode 100644 index 0000000..0e93502 --- /dev/null +++ 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 index 2e1ea6e..e75ed53 100644 --- 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 new file mode 100644 index 0000000..40814cc --- /dev/null +++ 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 index 6e8ec2d..bab2c73 100644 --- 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 index f23671b..7fa6351 100755 --- 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 \