commit f9626d00f457db6bff1db33606a97bd08e04f2f0
parent a1a1abb8c744966731553c7d2078def3b2e26902
Author: Daniel Barlow <dan@telent.net>
Date: Mon, 3 Oct 2022 22:28:15 +0100
generate probably-non-functional firmware image for gl-ar750
Diffstat:
6 files changed, 141 insertions(+), 10 deletions(-)
diff --git a/default.nix b/default.nix
@@ -16,19 +16,33 @@ let
kernel = callPackage ./kernel {
inherit (config.kernel) config checkedConfig;
};
-in {
- outputs = {
+ outputs = rec {
inherit squashfs kernel;
- default = nixpkgs.pkgs.runCommand "both-kinds" {} ''
- mkdir $out
- cd $out
- ln -s ${squashfs} squashfs
- ln -s ${kernel.vmlinux} vmlinux
- '';
+ uimage = kernel.uimage {
+ inherit (device.boot) loadAddress entryPoint;
+ inherit (kernel) vmlinux;
+ };
+
+ combined-image = nixpkgs.pkgs.runCommand "firmware.bin" {
+ nativeBuildInputs = [ nixpkgs.buildPackages.ubootTools ];
+ } ''
+ dd if=${uimage} of=$out bs=128k conv=sync
+ dd if=${squashfs} of=$out bs=128k conv=sync,nocreat,notrunc oflag=append
+ '';
+
+ directory = nixpkgs.pkgs.runCommand "both-kinds" {} ''
+ mkdir $out
+ cd $out
+ ln -s ${squashfs} squashfs
+ ln -s ${kernel.vmlinux} vmlinux
+ '';
# this exists so that you can run "nix-store -q --tree" on it and find
# out what's in the image, which is nice if it's unexpectedly huge
manifest = writeText "manifest.json" (builtins.toJSON config.filesystem.contents);
};
+in {
+ outputs = outputs // { default = outputs.${device.outputs.default}; };
+
# this is just here as a convenience, so that we can get a
# cross-compiling nix-shell for any package we're customizing
inherit (nixpkgs) pkgs;
diff --git a/devices/gl-ar750.nix b/devices/gl-ar750.nix
@@ -1,3 +1,21 @@
+# GL.INet GL-AR750 "Creta" travel router
+# - QCA9531 @650Mhz SoC
+# - dual band wireless: IEEE 802.11a/b/g/n/ac
+# - two 10/100Mbps LAN ports and one WAN
+# - 128MB DDR2 RAM / 16MB NOR Flash
+# - "ath79" soc family
+# https://www.gl-inet.com/products/gl-ar750/
+
+# I like GL.iNet devices because they're relatively accessible to
+# DIY users: the serial port connections have headers preinstalled
+# and don't need soldering
+
+# The default output is a combined image containing a kernel
+# packaged as a "uimage" and initrd filesystem. This can be
+# downloaded to the device using TFTP and then written into
+# flash, or if PHRAM suport is enabled (handy for development)
+# unpacked and run directly into RAM
+
{
system = {
crossSystem = {
@@ -8,4 +26,55 @@
};
};
};
+ kernel = {
+ checkedConfig = {
+ "MIPS_RAW_APPENDED_DTB" = "y";
+ };
+ config = {
+ # this is all copied from nixwrt ath79 config. Clearly not all
+ # of it is device config, some of it is wifi config or
+ # installation method config or ...
+ "BLK_DEV_INITRD" = "n";
+ "CMDLINE_PARTITION" = "y";
+ "DEBUG_INFO" = "y";
+ "DEVTMPFS" = "y";
+ "EARLY_PRINTK" = "y";
+ "FW_LOADER" = "y";
+ # we don't have a user helper, so we get multiple 60s pauses
+ # at boot time unless we disable trying to call it
+ "FW_LOADER_USER_HELPER" = "n";
+ "IMAGE_CMDLINE_HACK" = "n";
+ "IP_PNP" = "y";
+ "JFFS2_FS" = "n";
+ "MIPS_RAW_APPENDED_DTB" = "y";
+ "MODULE_SIG" = "y";
+ "MTD_CMDLINE_PARTS" = "y";
+ "MTD_SPLIT_FIRMWARE" = "y";
+ "PARTITION_ADVANCED" = "y";
+ "PRINTK_TIME" = "y";
+ "SQUASHFS" = "y";
+ "SQUASHFS_XZ" = "y";
+ "ASN1" = "y";
+ "ASYMMETRIC_KEY_TYPE" = "y";
+ "ASYMMETRIC_PUBLIC_KEY_SUBTYPE" = "y";
+ "CRC_CCITT" = "y";
+ "CRYPTO" = "y";
+ "CRYPTO_ARC4" = "y";
+ "CRYPTO_CBC" = "y";
+ "CRYPTO_CCM" = "y";
+ "CRYPTO_CMAC" = "y";
+ "CRYPTO_GCM" = "y";
+ "CRYPTO_HASH_INFO" = "y";
+ "CRYPTO_LIB_ARC4" = "y";
+ "CRYPTO_RSA" = "y";
+ "CRYPTO_SHA1" = "y";
+ "ENCRYPTED_KEYS" = "y";
+ "KEYS" = "y";
+ };
+ };
+ outputs.default = "combined-image";
+ boot = {
+ loadAddress = "0x80060000";
+ entryPoint = "0x80060000";
+ };
}
diff --git a/devices/qemu.nix b/devices/qemu.nix
@@ -1,3 +1,7 @@
+# This "device" generates images that can be used with the QEMU
+# emulator. The default output is a directory containing separate
+# kernel (uncompressed vmlinux) and initrd (squashfs) images
+
{
system = {
crossSystem = {
@@ -446,4 +450,5 @@
VIRTIO_NET = "y";
};
};
+ outputs.default = "directory";
}
diff --git a/kernel/default.nix b/kernel/default.nix
@@ -34,9 +34,9 @@ let
cp -a . $out
'';
};
-in
-{
+in rec {
vmlinux = callPackage ./vmlinux.nix {
inherit tree config checkedConfig;
};
+ uimage = callPackage ./uimage.nix { };
}
diff --git a/kernel/uimage.nix b/kernel/uimage.nix
@@ -0,0 +1,42 @@
+{
+ lzma
+, stdenv
+, ubootTools
+} :
+let
+ objcopy = "${stdenv.cc.bintools.targetPrefix}objcopy";
+in {
+ vmlinux
+# , commandLine
+# , fdt ? null
+, entryPoint
+# , extraName ? "" # e.g. socFamily
+, loadAddress
+} :
+ # patchDtbCommand = if (fdt != null) then ''
+ # ( cat vmlinux.stripped ${fdt} > vmlinux.tmp ) && mv vmlinux.tmp vmlinux.stripped
+ # '' else ''
+ # echo patch-cmdline vmlinux.stripped '${commandLine}'
+ # patch-cmdline vmlinux.stripped '${commandLine}'
+ # echo
+ # '';
+stdenv.mkDerivation {
+ name = "kernel.image";
+ phases = [ "buildPhase" "installPhase" ];
+ nativeBuildInputs = [
+ # patchImage
+ lzma
+ stdenv.cc
+ ubootTools
+ ];
+ buildPhase = ''
+ ${objcopy} -O binary -R .reginfo -R .notes -R .note -R .comment -R .mdebug -R .note.gnu.build-id -S ${vmlinux} vmlinux.stripped
+ # {patchDtbCommand}
+ rm -f vmlinux.stripped.lzma
+ lzma -k -z vmlinux.stripped
+ mkimage -A mips -O linux -T kernel -C lzma -a ${loadAddress} -e ${entryPoint} -n 'MIPS Liminix Linux ' -d vmlinux.stripped.lzma kernel.image
+ '';
+ installPhase = ''
+ cp kernel.image $out
+ '';
+}
diff --git a/modules/base.nix b/modules/base.nix
@@ -31,6 +31,7 @@ in {
};
checkedConfig = mkOption {
type = types.attrsOf types.nonEmptyStr;
+ default = {};
};
};
groups = mkOption {