mtdimage.nix (3984B)
1 { 2 config, 3 pkgs, 4 lib, 5 ... 6 }: 7 let 8 inherit (lib) mkOption types concatStringsSep; 9 inherit (config.boot) tftp; 10 in 11 { 12 options.system.outputs = { 13 firmware = mkOption { 14 type = types.package; 15 internal = true; # component of mtdimage 16 description = '' 17 Binary image (combining kernel, FDT, rootfs, initramfs 18 if needed, etc) for the target device. 19 ''; 20 }; 21 flash-scr = mkOption { 22 type = types.package; 23 internal = true; # component of mtdimage 24 description = '' 25 Copy-pastable U-Boot commands to TFTP download the 26 image and write it to flash 27 ''; 28 }; 29 mtdimage = mkOption { 30 type = types.package; 31 description = '' 32 mtdimage 33 ********** 34 35 This creates an image called :file:`firmware.bin` suitable for 36 squashfs or jffs2 systems. It can be flashed from U-Boot (if 37 you have a serial console connection), or on some devices from 38 the vendor firmware, or from Liminix when using 39 :ref:`levitate` 40 41 If you are flashing from U-Boot, the file 42 :file:`flash.scr` is a sequence of commands 43 which you can paste at the U-Boot prompt to 44 to transfer the firmware file from a TFTP server and 45 write it to flash. **Please read the script before 46 running it: flash operations carry the potential to 47 brick your device** 48 49 .. NOTE:: 50 51 TTL serial connections typically have no form of flow 52 control and so don't always like having massive chunks of 53 text pasted into them - and U-Boot may drop characters 54 while it's busy. So don't necessarily expect to copy-paste 55 the whole of :file:`flash.scr` into a terminal emulator and 56 have it work just like that. You may need to paste each 57 line one at a time, or even retype it. 58 ''; 59 }; 60 }; 61 62 config = { 63 kernel = { 64 config = 65 { 66 # this needs to be conditional on "not qemu" 67 MTD_SPLIT_UIMAGE_FW = "y"; 68 } 69 // lib.optionalAttrs (pkgs.stdenv.isMips) { 70 # https://stackoverflow.com/questions/26466470/can-the-logical-erase-block-size-of-an-mtd-device-be-increased 71 MTD_SPI_NOR_USE_4K_SECTORS = "n"; 72 }; 73 }; 74 75 programs.busybox.applets = [ 76 "flashcp" 77 ]; 78 79 system.outputs = { 80 firmware = 81 let 82 o = config.system.outputs; 83 bs = toString config.hardware.flash.eraseBlockSize; 84 in 85 pkgs.runCommand "firmware" { } '' 86 dd if=${o.uimage} of=$out bs=${bs} conv=sync 87 dd if=${o.rootfs} of=$out bs=${bs} conv=sync,nocreat,notrunc oflag=append 88 ''; 89 mtdimage = 90 let 91 o = config.system.outputs; 92 in 93 # could use trivial-builders.linkFarmFromDrvs here? 94 pkgs.runCommand "mtdimage" { } '' 95 mkdir $out 96 cd $out 97 ln -s ${o.firmware} firmware.bin 98 ln -s ${o.rootfs} rootfs 99 ln -s ${o.kernel} vmlinux 100 ln -s ${o.manifest} manifest 101 ln -s ${o.kernel.headers} build 102 ln -s ${o.uimage} uimage 103 ln -s ${o.dtb} dtb 104 ln -s ${o.flash-scr} flash.scr 105 ''; 106 107 flash-scr = 108 let 109 inherit (pkgs.lib.trivial) toHexString; 110 inherit (config.hardware) flash; 111 in 112 pkgs.buildPackages.runCommand "" { } '' 113 imageSize=$(stat -L -c %s ${config.system.outputs.firmware}) 114 cat > $out << EOF 115 setenv serverip ${tftp.serverip} 116 setenv ipaddr ${tftp.ipaddr} 117 tftp 0x${toHexString tftp.loadAddress} result/firmware.bin 118 erase 0x${toHexString flash.address} +0x${toHexString flash.size} 119 cp.b 0x${toHexString tftp.loadAddress} 0x${toHexString flash.address} \''${filesize} 120 echo command line was ${builtins.toJSON (concatStringsSep " " config.boot.commandLine)} 121 EOF 122 ''; 123 }; 124 }; 125 }