tftpboot.nix (6650B)
1 { 2 config, 3 pkgs, 4 lib, 5 ... 6 }: 7 let 8 inherit (lib) mkOption types concatStringsSep; 9 cfg = config.boot.tftp; 10 hw = config.hardware; 11 arch = pkgs.stdenv.hostPlatform.linuxArch; 12 in 13 { 14 imports = [ ../ramdisk.nix ]; 15 options.boot.tftp = { 16 freeSpaceBytes = mkOption { 17 type = types.int; 18 default = 0; 19 }; 20 kernelFormat = mkOption { 21 type = types.enum [ 22 "zimage" 23 "uimage" 24 ]; 25 default = "uimage"; 26 }; 27 compressRoot = mkOption { 28 type = types.bool; 29 default = false; 30 }; 31 appendDTB = mkOption { 32 type = types.bool; 33 default = false; 34 }; 35 }; 36 options.system.outputs = { 37 tftpboot = mkOption { 38 type = types.package; 39 description = '' 40 tftpboot 41 ******** 42 43 This output is intended for developing on a new device. 44 It assumes you have a serial connection and a 45 network connection to the device and that your 46 build machine is running a TFTP server. 47 48 The output is a directory containing kernel and 49 root filesystem image, and a script :file:`boot.scr` of U-Boot 50 commands that will load the images into memory and 51 run them directly, 52 instead of first writing them to flash. This saves 53 time and erase cycles. 54 55 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. 56 ''; 57 }; 58 }; 59 config = { 60 boot.ramdisk.enable = true; 61 62 system.outputs = rec { 63 tftpboot = 64 # no ubifs on an mtd directly, it needs ubi volumes 65 assert config.rootfsType != "ubifs"; 66 let 67 o = config.system.outputs; 68 image = 69 let 70 choices = { 71 uimage = o.uimage; 72 zimage = o.kernel.zImage; 73 }; 74 in 75 choices.${cfg.kernelFormat}; 76 bootCommand = 77 let 78 choices = { 79 uimage = "bootm"; 80 zimage = "bootz"; 81 }; 82 in 83 choices.${cfg.kernelFormat}; 84 85 cmdline = concatStringsSep " " config.boot.commandLine; 86 objcopy = "${pkgs.stdenv.cc.bintools.targetPrefix}objcopy"; 87 stripAndZip = '' 88 ${objcopy} -O binary -S vmlinux.elf vmlinux.bin 89 rm -f vmlinux.bin.lzma ; lzma -k -z vmlinux.bin 90 ''; 91 in 92 pkgs.runCommand "tftpboot" 93 { 94 nativeBuildInputs = with pkgs.pkgsBuildBuild; [ 95 lzma 96 dtc 97 pkgs.stdenv.cc 98 ubootTools 99 ]; 100 } 101 '' 102 mkdir $out 103 cd $out 104 binsize() { local s=$(stat -L -c %s $1); echo $(($s + 0x1000 &(~0xfff))); } 105 binsize64k() { local s=$(stat -L -c %s $1); echo $(($s + 0x10000 &(~0xffff))); } 106 hex() { printf "0x%x" $1; } 107 108 rootfsStart=${toString cfg.loadAddress} 109 rootfsSize=$(binsize64k ${o.rootfs} ) 110 rootfsSize=$(($rootfsSize + ${toString cfg.freeSpaceBytes} )) 111 112 ln -s ${o.manifest} manifest 113 ln -s ${o.kernel} vmlinux # handy for gdb 114 115 # if we are transferring kernel and dtb separately, the 116 # dtb has to precede the kernel in ram, because zimage 117 # decompression code will assume that any memory after the 118 # end of the kernel is free 119 120 dtbStart=$(($rootfsStart + $rootfsSize)) 121 ${ 122 if cfg.compressRoot then 123 '' 124 lzma -z9cv ${o.rootfs} > rootfs.lz 125 rootfsLzStart=$dtbStart 126 rootfsLzSize=$(binsize rootfs.lz) 127 dtbStart=$(($dtbStart + $rootfsLzSize)) 128 '' 129 else 130 '' 131 ln -s ${o.rootfs} rootfs 132 '' 133 } 134 135 cat ${o.dtb} > dtb 136 address_cells=$(fdtget dtb / '#address-cells') 137 size_cells=$(fdtget dtb / '#size-cells') 138 if [ $address_cells -gt 1 ]; then ac_prefix=0; fi 139 if [ $size_cells -gt 1 ]; then sz_prefix=0; fi 140 141 fdtput -p dtb /reserved-memory '#address-cells' $address_cells 142 fdtput -p dtb /reserved-memory '#size-cells' $size_cells 143 fdtput -p dtb /reserved-memory ranges 144 node=$(printf "phram-rootfs@%x" $rootfsStart) 145 fdtput -p -t s dtb /reserved-memory/$node compatible phram 146 fdtput -p -t lx dtb /reserved-memory/$node reg $ac_prefix $(hex $rootfsStart) $sz_prefix $(hex $rootfsSize) 147 fdtput -p dtb /reserved-memory/$node no-map 148 149 cmd="liminix ${cmdline} mtdparts=phram0:''${rootfsSize}(rootfs) phram.phram=phram0,''${rootfsStart},''${rootfsSize},${toString config.hardware.flash.eraseBlockSize} root=/dev/mtdblock0"; 150 fdtput -t s dtb /chosen ${config.boot.commandLineDtbNode} "$cmd" 151 152 dtbSize=$(binsize ./dtb ) 153 154 ${ 155 if cfg.appendDTB then 156 '' 157 imageStart=$dtbStart 158 # re-package image with updated dtb 159 cat ${o.kernel} > vmlinux.elf 160 ${objcopy} --update-section .appended_dtb=dtb vmlinux.elf 161 ${stripAndZip} 162 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 163 # dtc -I dtb -O dts -o /dev/stdout dtb | grep -A10 chosen ; exit 1 164 tftpcmd="tftpboot $(hex $imageStart) result/image " 165 bootcmd="bootm $(hex $imageStart)" 166 '' 167 else 168 '' 169 imageStart=$(($dtbStart + $dtbSize)) 170 tftpcmd="tftpboot $(hex $imageStart) result/image; tftpboot $(hex $dtbStart) result/dtb " 171 ln -s ${image} image 172 bootcmd="${bootCommand} $(hex $imageStart) - $(hex $dtbStart)" 173 '' 174 } 175 176 cat > boot.scr << EOF 177 setenv serverip ${cfg.serverip} 178 setenv ipaddr ${cfg.ipaddr} 179 ${ 180 if cfg.compressRoot then 181 "tftpboot $(hex $rootfsLzStart) result/rootfs.lz" 182 else 183 "tftpboot $(hex $rootfsStart) result/rootfs" 184 }; $tftpcmd 185 ${if cfg.compressRoot then "lzmadec $(hex $rootfsLzStart) $(hex $rootfsStart); " else ""} $bootcmd 186 EOF 187 ''; 188 189 }; 190 }; 191 }