diff --git a/modules/outputs/tftpboot.nix b/modules/outputs/tftpboot.nix index 00674f23..a947bc00 100644 --- a/modules/outputs/tftpboot.nix +++ b/modules/outputs/tftpboot.nix @@ -7,6 +7,8 @@ let inherit (lib) mkOption types concatStringsSep; cfg = config.boot.tftp; + hw = config.hardware; + arch = pkgs.stdenv.hostPlatform.linuxArch; in { imports = [ ../ramdisk.nix ]; options.boot.tftp = { @@ -22,6 +24,10 @@ in { type = types.bool; default = false; }; + appendDTB = mkOption { + type = types.bool; + default = false; + }; }; options.system.outputs = { tftpboot = mkOption { @@ -62,24 +68,46 @@ in { uimage = "bootm"; zimage = "bootz"; }; in choices.${cfg.kernelFormat}; + cmdline = concatStringsSep " " config.boot.commandLine; + objcopy = "${pkgs.stdenv.cc.bintools.targetPrefix}objcopy"; + stripAndZip = '' + ${objcopy} -O binary -R .reginfo -R .notes -R .note -R .comment -R .mdebug -R .note.gnu.build-id -S vmlinux.elf vmlinux.bin + rm -f vmlinux.bin.lzma ; lzma -k -z vmlinux.bin + ''; in - pkgs.runCommand "tftpboot" { nativeBuildInputs = with pkgs.pkgsBuildBuild; [ lzma dtc ]; } '' + pkgs.runCommand "tftpboot" { nativeBuildInputs = with pkgs.pkgsBuildBuild; [ lzma dtc pkgs.stdenv.cc ubootTools ]; } '' mkdir $out cd $out binsize() { local s=$(stat -L -c %s $1); echo $(($s + 0x1000 &(~0xfff))); } binsize64k() { local s=$(stat -L -c %s $1); echo $(($s + 0x10000 &(~0xffff))); } hex() { printf "0x%x" $1; } + rootfsStart=${toString cfg.loadAddress} rootfsSize=$(binsize64k ${o.rootfs} ) rootfsSize=$(($rootfsSize + ${toString cfg.freeSpaceBytes} )) - dtbStart=$(($rootfsStart + $rootfsSize)) - imageSize=$(binsize ${image}) ln -s ${o.manifest} manifest - ln -s ${image} image ln -s ${o.kernel} vmlinux # handy for gdb + # if we are transferring kernel and dtb separately, the + # dtb has to precede the kernel in ram, because zimage + # decompression code will assume that any memory after the + # end of the kernel is free + + dtbStart=$(($rootfsStart + $rootfsSize)) + ${if cfg.compressRoot + then '' + lzma -z9cv ${o.rootfs} > rootfs.lz + rootfsLzStart=$dtbStart + rootfsLzSize=$(binsize rootfs.lz) + dtbStart=$(($dtbStart + $rootfsLzSize)) + '' + else '' + ln -s ${o.rootfs} rootfs + '' + } + cat ${o.dtb} > dtb address_cells=$(fdtget dtb / '#address-cells') size_cells=$(fdtget dtb / '#size-cells') @@ -93,34 +121,40 @@ in { fdtput -p -t s dtb /reserved-memory/$node compatible phram fdtput -p -t lx dtb /reserved-memory/$node reg $ac_prefix $(hex $rootfsStart) $sz_prefix $(hex $rootfsSize) - dtbSize=$(binsize ./dtb ) - imageStart=$(($dtbStart + $dtbSize)) - ${if cfg.compressRoot - then '' - lzma -z9cv ${o.rootfs} > rootfs.lz - rootfsLzStart=$(($imageStart + $imageSize)) - rootfsLzSize=$(binsize rootfs.lz) - '' - else "ln -s ${o.rootfs} rootfs" - } - cmd="liminix ${cmdline} mtdparts=phram0:''${rootfsSize}(rootfs) phram.phram=phram0,''${rootfsStart},''${rootfsSize},${toString config.hardware.flash.eraseBlockSize} root=/dev/mtdblock0"; fdtput -t s dtb /chosen bootargs "$cmd" - # dtc -I dtb -O dts -o /dev/stdout dtb | grep -A10 chosen ; exit 1 + dtbSize=$(binsize ./dtb ) + + ${if cfg.appendDTB then '' + imageStart=$dtbStart + # re-package image with updated dtb + cat ${o.kernel} > vmlinux.elf + ${objcopy} --update-section .appended_dtb=dtb vmlinux.elf + ${stripAndZip} + mkimage -A ${arch} -O linux -T kernel -C lzma -a $(hex ${toString hw.loadAddress}) -e $(hex ${toString hw.entryPoint}) -n '${lib.toUpper arch} Liminix Linux tftpboot' -d vmlinux.bin.lzma image + # dtc -I dtb -O dts -o /dev/stdout dtb | grep -A10 chosen ; exit 1 + tftpcmd="tftpboot $(hex $imageStart) result/image " + bootcmd="bootm $(hex $imageStart)" + '' else '' + imageStart=$(($dtbStart + $dtbSize)) + tftpcmd="tftpboot $(hex $imageStart) result/image; tftpboot $(hex $dtbStart) result/dtb " + ln -s ${image} image + bootcmd="${bootCommand} $(hex $imageStart) - $(hex $dtbStart)" + ''} cat > boot.scr << EOF setenv serverip ${cfg.serverip} setenv ipaddr ${cfg.ipaddr} - tftpboot $(hex $imageStart) result/image ; ${ + ${ if cfg.compressRoot then "tftpboot $(hex $rootfsLzStart) result/rootfs.lz" else "tftpboot $(hex $rootfsStart) result/rootfs" - }; tftpboot $(hex $dtbStart) result/dtb + }; $tftpcmd ${if cfg.compressRoot then "lzmadec $(hex $rootfsLzStart) $(hex $rootfsStart); " else "" - } ${bootCommand} $(hex $imageStart) - $(hex $dtbStart) + } $bootcmd EOF ''; diff --git a/tests/tftpboot/test.nix b/tests/tftpboot/test.nix index 941d15ba..b7a3e870 100644 --- a/tests/tftpboot/test.nix +++ b/tests/tftpboot/test.nix @@ -12,7 +12,7 @@ let derivation = (import liminix { img = derivation.outputs.tftpboot; uboot = derivation.outputs.u-boot; pkgsBuild = derivation.pkgs.pkgsBuildBuild; -in pkgsBuild.runCommand "check" { +in pkgsBuild.runCommand "check-${deviceName}" { nativeBuildInputs = with pkgsBuild; [ expect socat @@ -44,4 +44,11 @@ in { mipsLz = check "qemu" { boot.tftp.compressRoot = true; }; + # this works on real hardware but I haven't figured out how + # to make it work on qemu: it says + # "OF: fdt: No chosen node found, continuing without" + + # mipsOldUboot = check "qemu" { + # boot.tftp.appendDTB = true; + # }; }