{
  lib,
  bc,
  bison,
  fetchurl,
  flex,
  gnutls,
  installShellFiles,
  libuuid,
  ncurses,
  openssl,
  swig,
  which,
  python3,
  perl,
  buildPackages,
  callPackages,
  darwin,
}@pkgs:

let
  defaultVersion = "2025.07";
  defaultSrc = fetchurl {
    url = "https://ftp.denx.de/pub/u-boot/u-boot-${defaultVersion}.tar.bz2";
    hash = "sha256-D5M/bFpCaJW/MG6T5qxTxghw5LVM2lbZUhG+yZ5jvsc=";
  };

  # Dependencies for the tools need to be included as either native or cross,
  # depending on which we're building
  toolsDeps = [
    ncurses # tools/kwboot
    libuuid # tools/mkeficapsule
    gnutls # tools/mkeficapsule
    openssl # tools/mkimage and tools/env/fw_printenv
  ];

  buildUBoot = lib.makeOverridable (
    {
      version ? null,
      src ? null,
      filesToInstall,
      pythonScriptsToInstall ? { },
      installDir ? "$out",
      defconfig,
      extraPatches ? [ ],
      extraMakeFlags ? [ ],
      extraMeta ? { },
      crossTools ? false,
      stdenv ? pkgs.stdenv,
      ...
    }@args:
    stdenv.mkDerivation (
      {
        pname = "uboot-${defconfig}";

        version = if src == null then defaultVersion else version;

        src = if src == null then defaultSrc else src;

        patches = extraPatches;

        postPatch = ''
          ${lib.concatMapStrings (script: ''
            substituteInPlace ${script} \
            --replace "#!/usr/bin/env python3" "#!${pythonScriptsToInstall.${script}}/bin/python3"
          '') (builtins.attrNames pythonScriptsToInstall)}
          patchShebangs tools
          patchShebangs scripts
        '';

        nativeBuildInputs = [
          ncurses # tools/kwboot
          bc
          bison
          flex
          installShellFiles
          (buildPackages.python3.withPackages (p: [
            p.libfdt
            p.setuptools # for pkg_resources
            p.pyelftools
          ]))
          swig
          which # for scripts/dtc-version.sh
          perl # for oid build (secureboot)
        ]
        ++ lib.optionals (!crossTools) toolsDeps
        ++ lib.optionals stdenv.buildPlatform.isDarwin [ darwin.DarwinTools ]; # sw_vers command is needed on darwin
        depsBuildBuild = [ buildPackages.gccStdenv.cc ]; # gccStdenv is needed for Darwin buildPlatform
        buildInputs = lib.optionals crossTools toolsDeps;

        hardeningDisable = [ "all" ];

        enableParallelBuilding = true;

        makeFlags = [
          "DTC=${lib.getExe buildPackages.dtc}"
          "CROSS_COMPILE=${stdenv.cc.targetPrefix}"
          "HOSTCFLAGS=-fcommon"
        ]
        ++ extraMakeFlags;

        passAsFile = [ "extraConfig" ];

        configurePhase = ''
          runHook preConfigure

          make -j$NIX_BUILD_CORES ${defconfig}

          cat $extraConfigPath >> .config

          runHook postConfigure
        '';

        installPhase = ''
          runHook preInstall

          mkdir -p ${installDir}
          cp ${
            lib.concatStringsSep " " (filesToInstall ++ builtins.attrNames pythonScriptsToInstall)
          } ${installDir}

          mkdir -p "$out/nix-support"
          ${lib.concatMapStrings (file: ''
            echo "file binary-dist ${installDir}/${baseNameOf file}" >> "$out/nix-support/hydra-build-products"
          '') (filesToInstall ++ builtins.attrNames pythonScriptsToInstall)}

          runHook postInstall
        '';

        dontStrip = true;

        meta =
          with lib;
          {
            homepage = "https://www.denx.de/wiki/U-Boot/";
            description = "Boot loader for embedded systems";
            license = licenses.gpl2Plus;
            maintainers = with maintainers; [
              dezgeg
              lopsided98
            ];
          }
          // extraMeta;
      }
      // removeAttrs args [
        "extraMeta"
        "pythonScriptsToInstall"
      ]
    )
  );
in
{
  inherit buildUBoot;

  ubootTools = buildUBoot {
    defconfig = "tools-only_defconfig";
    installDir = "$out/bin";
    hardeningDisable = [ ];
    dontStrip = false;
    extraMeta.platforms = lib.platforms.linux;

    crossTools = true;
    extraMakeFlags = [
      "HOST_TOOLS_ALL=y"
      "NO_SDL=1"
      "cross_tools"
      "envtools"
    ];

    outputs = [
      "out"
      "man"
    ];

    postInstall = ''
      installManPage doc/*.1

      # from u-boot's tools/env/README:
      # "You should then create a symlink from fw_setenv to fw_printenv. They
      # use the same program and its function depends on its basename."
      ln -s $out/bin/fw_printenv $out/bin/fw_setenv
    '';

    filesToInstall = [
      "tools/dumpimage"
      "tools/fdt_add_pubkey"
      "tools/fdtgrep"
      "tools/kwboot"
      "tools/mkeficapsule"
      "tools/mkenvimage"
      "tools/mkimage"
      "tools/env/fw_printenv"
      "tools/mkeficapsule"
    ];

    pythonScriptsToInstall = {
      "tools/efivar.py" = (python3.withPackages (ps: [ ps.pyopenssl ]));
    };
  };

  ubootPythonTools = lib.recurseIntoAttrs (callPackages ./python.nix { });

  ubootQemuAarch64 = buildUBoot {
    defconfig = "qemu_arm64_defconfig";
    extraMeta.platforms = [ "aarch64-linux" ];
    filesToInstall = [ "u-boot.bin" ];
  };

  ubootQemuArm = buildUBoot {
    defconfig = "qemu_arm_defconfig";
    extraMeta.platforms = [ "armv7l-linux" ];
    filesToInstall = [ "u-boot.bin" ];
  };

  ubootQemuRiscv64Smode = buildUBoot {
    defconfig = "qemu-riscv64_smode_defconfig";
    extraMeta.platforms = [ "riscv64-linux" ];
    filesToInstall = [ "u-boot.bin" ];
  };

  ubootQemuX86 = buildUBoot {
    defconfig = "qemu-x86_defconfig";
    extraConfig = ''
      CONFIG_USB_UHCI_HCD=y
      CONFIG_USB_EHCI_HCD=y
      CONFIG_USB_EHCI_GENERIC=y
      CONFIG_USB_XHCI_HCD=y
    '';
    extraMeta.platforms = [
      "i686-linux"
      "x86_64-linux"
    ];
    filesToInstall = [ "u-boot.rom" ];
  };

  ubootQemuX86_64 = buildUBoot {
    defconfig = "qemu-x86_64_defconfig";
    extraConfig = ''
      CONFIG_USB_UHCI_HCD=y
      CONFIG_USB_EHCI_HCD=y
      CONFIG_USB_EHCI_GENERIC=y
      CONFIG_USB_XHCI_HCD=y
    '';
    extraMeta.platforms = [ "x86_64-linux" ];
    filesToInstall = [ "u-boot.rom" ];
  };

  ubootRaspberryPi4 = buildUBoot {
    defconfig = "rpi_4_defconfig";
    extraMeta.platforms = [ "aarch64-linux" ];
    filesToInstall = [ "u-boot.bin" ];
  };

  ubootRaspberryPi5 = buildUBoot {
    defconfig = "rpi_arm64_defconfig";
    extraMeta.platforms = [ "aarch64-linux" ];
    filesToInstall = [ "u-boot.bin" ];
  };
}
