liminix

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

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 }