liminix

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

tftpboot.nix (6170B)


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