tftpboot.nix (4633B)
1 { 2 config 3 , pkgs 4 , lib 5 , ... 6 }: 7 let 8 inherit (lib) mkOption types concatStringsSep; 9 cfg = config.boot.tftp; 10 in { 11 imports = [ ../ramdisk.nix ]; 12 options.boot.tftp = { 13 freeSpaceBytes = mkOption { 14 type = types.int; 15 default = 0; 16 }; 17 kernelFormat = mkOption { 18 type = types.enum [ "zimage" "uimage" ]; 19 default = "uimage"; 20 }; 21 compressRoot = mkOption { 22 type = types.bool; 23 default = false; 24 }; 25 }; 26 options.system.outputs = { 27 tftpboot = mkOption { 28 type = types.package; 29 description = '' 30 tftpboot 31 ******** 32 33 This output is intended for developing on a new device. 34 It assumes you have a serial connection and a 35 network connection to the device and that your 36 build machine is running a TFTP server. 37 38 The output is a directory containing kernel and 39 root filesystem image, and a script :file:`boot.scr` of U-Boot 40 commands that will load the images into memory and 41 run them directly, 42 instead of first writing them to flash. This saves 43 time and erase cycles. 44 45 It uses the Linux `phram <https://github.com/torvalds/linux/blob/master/drivers/mtd/devices/phram.c>`_ driver to emulate a flash device using a segment of physical RAM. 46 ''; 47 }; 48 }; 49 config = { 50 boot.ramdisk.enable = true; 51 52 system.outputs = rec { 53 tftpboot = 54 let 55 inherit (pkgs.lib.trivial) toHexString; 56 o = config.system.outputs; 57 image = let choices = { 58 uimage = o.uimage; 59 zimage = o.zimage; 60 }; in choices.${cfg.kernelFormat}; 61 bootCommand = let choices = { 62 uimage = "bootm"; 63 zimage = "bootz"; 64 }; in choices.${cfg.kernelFormat}; 65 cmdline = concatStringsSep " " config.boot.commandLine; 66 in 67 pkgs.runCommand "tftpboot" { nativeBuildInputs = with pkgs.pkgsBuildBuild; [ lzma dtc ]; } '' 68 mkdir $out 69 cd $out 70 binsize() { local s=$(stat -L -c %s $1); echo $(($s + 0x1000 &(~0xfff))); } 71 binsize64k() { local s=$(stat -L -c %s $1); echo $(($s + 0x10000 &(~0xffff))); } 72 hex() { printf "0x%x" $1; } 73 rootfsStart=${toString cfg.loadAddress} 74 rootfsSize=$(binsize64k ${o.rootfs} ) 75 dtbStart=$(($rootfsStart + $rootfsSize)) 76 dtbSize=$(binsize ${o.dtb} ) 77 imageStart=$(($dtbStart + $dtbSize)) 78 imageSize=$(binsize ${image}) 79 80 ln -s ${o.manifest} manifest 81 ln -s ${image} image 82 ln -s ${o.kernel} vmlinux # handy for gdb 83 84 ${if cfg.compressRoot 85 then '' 86 lzma -z9cv ${o.rootfs} > rootfs.lz 87 rootfsLzStart=$(($imageStart + $imageSize)) 88 rootfsLzSize=$(binsize rootfs.lz) 89 '' 90 else "ln -s ${o.rootfs} rootfs" 91 } 92 cat ${o.dtb} > dtb 93 address_cells=$(fdtget dtb / '#address-cells') 94 size_cells=$(fdtget dtb / '#size-cells') 95 if [ $address_cells -gt 1 ]; then ac_prefix=0; fi 96 if [ $size_cells -gt 1 ]; then sz_prefix=0; fi 97 98 fdtput -p dtb /reserved-memory '#address-cells' $address_cells 99 fdtput -p dtb /reserved-memory '#size-cells' $size_cells 100 fdtput -p dtb /reserved-memory ranges 101 node=$(printf "phram-rootfs@%x" $rootfsStart) 102 fdtput -p -t s dtb /reserved-memory/$node compatible phram 103 fdtput -p -t lx dtb /reserved-memory/$node reg $ac_prefix $(hex $rootfsStart) $sz_prefix $(hex $rootfsSize) 104 105 cmd="liminix ${cmdline} mtdparts=phram0:''${rootfsSize}(rootfs) phram.phram=phram0,''${rootfsStart},''${rootfsSize},${toString config.hardware.flash.eraseBlockSize} root=/dev/mtdblock0"; 106 fdtput -t s dtb /chosen bootargs "$cmd" 107 108 # dtc -I dtb -O dts -o /dev/stdout dtb | grep -A10 chosen ; exit 1 109 110 cat > boot.scr << EOF 111 setenv serverip ${cfg.serverip} 112 setenv ipaddr ${cfg.ipaddr} 113 tftpboot $(hex $imageStart) result/image ; ${ 114 if cfg.compressRoot 115 then "tftpboot $(hex $rootfsLzStart) result/rootfs.lz" 116 else "tftpboot $(hex $rootfsStart) result/rootfs" 117 }; tftpboot $(hex $dtbStart) result/dtb 118 ${if cfg.compressRoot 119 then "lzmadec $(hex $rootfsLzStart) $(hex $rootfsStart); " 120 else "" 121 } ${bootCommand} $(hex $imageStart) - $(hex $dtbStart) 122 EOF 123 ''; 124 125 }; 126 }; 127 }