diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..80d26af --- /dev/null +++ b/Dockerfile @@ -0,0 +1,22 @@ +FROM nixos/nix:latest + +# Enable flakes +RUN mkdir -p /etc/nix && \ + echo 'experimental-features = nix-command flakes' >> /etc/nix/nix.conf + +# Create user properly +# RUN useradd -m -u 1000 -s /bin/bash kylepzak + +# Set working directory +WORKDIR /config + +# Copy flake for build step (will be mounted at runtime) +COPY . . + +# Build home-manager configuration +RUN nix run github:nix-community/home-manager/master -- build --flake .#"root@docker" +RUN nix-env -e man-db-2.13.0 +RUN nix run github:nix-community/home-manager/master -- switch --flake .#"root@docker" + +# Set the default command +CMD ["/bin/bash"] diff --git a/build-ubootimg.sh b/build-ubootimg.sh new file mode 100755 index 0000000..c1a2aea --- /dev/null +++ b/build-ubootimg.sh @@ -0,0 +1,28 @@ +# Define output file name +UBOOT_ROCKCHIP_BIN="u-boot-rockchip.bin" + +# Define the offset for u-boot.itb within u-boot-rockchip.bin in bytes +OFFSET_UBOOT_ITB_BYTES=8355840 # This is (16384 - 64) sectors * 512 bytes/sector + +echo "IDBLOADER_PATH: $IDBLOADER_PATH" +echo "UBOOT_ITB_PATH: $UBOOT_ITB_PATH" +echo "Target combined file: $UBOOT_ROCKCHIP_BIN" +echo "Offset for u-boot.itb: $OFFSET_UBOOT_ITB_BYTES bytes" + +# Copy idbloader.img to be the start of u-boot-rockchip.bin +cp "$IDBLOADER_PATH" "$UBOOT_ROCKCHIP_BIN" + +# Pad the u-boot-rockchip.bin file with zeros up to the point where u-boot.itb should start +# This ensures idbloader.img is not overwritten if it's smaller than the offset, +# and the file is extended to the correct size before writing u-boot.itb. +# Using truncate is efficient for creating sparse space if the filesystem supports it, +# or filling with nulls. +truncate -s $OFFSET_UBOOT_ITB_BYTES "$UBOOT_ROCKCHIP_BIN" + +# Now, write u-boot.itb at the specified offset +# 'conv=notrunc' ensures that dd does not truncate the output file. +# 'bs=1' ensures byte-level precision for seek. +dd if="$UBOOT_ITB_PATH" of="$UBOOT_ROCKCHIP_BIN" bs=1 seek=$OFFSET_UBOOT_ITB_BYTES conv=notrunc + +echo "Created $UBOOT_ROCKCHIP_BIN successfully." +ls -lh "$UBOOT_ROCKCHIP_BIN" diff --git a/flake.lock b/flake.lock index c4964d3..a81a1e2 100644 --- a/flake.lock +++ b/flake.lock @@ -561,7 +561,7 @@ }, "flake-utils-plus_5": { "inputs": { - "flake-utils": "flake-utils_6" + "flake-utils": "flake-utils_7" }, "locked": { "lastModified": 1715533576, @@ -580,7 +580,7 @@ }, "flake-utils-plus_6": { "inputs": { - "flake-utils": "flake-utils_7" + "flake-utils": "flake-utils_8" }, "locked": { "lastModified": 1715533576, @@ -667,6 +667,24 @@ "inputs": { "systems": "systems_6" }, + "locked": { + "lastModified": 1701680307, + "narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "4022d587cbbfd70fe950c1e2083a02621806a725", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "flake-utils_7": { + "inputs": { + "systems": "systems_7" + }, "locked": { "lastModified": 1694529238, "narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=", @@ -681,9 +699,9 @@ "type": "github" } }, - "flake-utils_7": { + "flake-utils_8": { "inputs": { - "systems": "systems_7" + "systems": "systems_8" }, "locked": { "lastModified": 1694529238, @@ -699,6 +717,28 @@ "type": "github" } }, + "gitignore": { + "inputs": { + "nixpkgs": [ + "nixos-rk3588", + "pre-commit-hooks", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1660459072, + "narHash": "sha256-8DFJjXG8zqoONA1vXtgeKXy68KdJL5UaXR8NtVMUbx8=", + "owner": "hercules-ci", + "repo": "gitignore.nix", + "rev": "a20de23b925fd8264fd7fad6454652e142fd7f73", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "gitignore.nix", + "type": "github" + } + }, "gpg-base-conf": { "flake": false, "locked": { @@ -836,6 +876,21 @@ "type": "github" } }, + "nixlib_2": { + "locked": { + "lastModified": 1709426687, + "narHash": "sha256-jLBZmwXf0WYHzLkmEMq33bqhX55YtT5edvluFr0RcSA=", + "owner": "nix-community", + "repo": "nixpkgs.lib", + "rev": "7873d84a89ae6e4841528ff7f5697ddcb5bdfe6c", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nixpkgs.lib", + "type": "github" + } + }, "nixos-generators": { "inputs": { "nixlib": "nixlib", @@ -857,6 +912,28 @@ "type": "github" } }, + "nixos-generators_2": { + "inputs": { + "nixlib": "nixlib_2", + "nixpkgs": [ + "nixos-rk3588", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1709557527, + "narHash": "sha256-PV8oYqhTHX6FGZMQ1m5dhRuS914AhofPwgnAMhUZtwE=", + "owner": "nix-community", + "repo": "nixos-generators", + "rev": "d048d6fc4bada612ff08d4b9d5edc48d45389431", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nixos-generators", + "type": "github" + } + }, "nixos-hardware": { "locked": { "lastModified": 1751432711, @@ -872,6 +949,29 @@ "type": "github" } }, + "nixos-rk3588": { + "inputs": { + "flake-utils": "flake-utils_6", + "nixos-generators": "nixos-generators_2", + "nixpkgs": [ + "nixpkgs" + ], + "pre-commit-hooks": "pre-commit-hooks" + }, + "locked": { + "lastModified": 1750844687, + "narHash": "sha256-q4G5xwW3dNwZkM4LIWL4EZ7P/zEvTVMydFypHvzkXKM=", + "owner": "gnull", + "repo": "nixos-rk3588", + "rev": "89d6aad2341c6e2a12059b0c7406e1729513cfda", + "type": "github" + }, + "original": { + "owner": "gnull", + "repo": "nixos-rk3588", + "type": "github" + } + }, "nixpkgs": { "locked": { "lastModified": 1751211869, @@ -888,6 +988,22 @@ "type": "github" } }, + "nixpkgs-master": { + "locked": { + "lastModified": 1752162398, + "narHash": "sha256-j35/DdtmMteHXcsHOo3vDaI0S8bpACSf2r56wyLlVB0=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "097cb94900cf029f003b9c816a0495209a13fe82", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "master", + "repo": "nixpkgs", + "type": "github" + } + }, "nixpkgs_2": { "locked": { "lastModified": 1744868846, @@ -920,6 +1036,39 @@ "type": "github" } }, + "pre-commit-hooks": { + "inputs": { + "flake-compat": [ + "nixos-rk3588" + ], + "flake-utils": [ + "nixos-rk3588", + "flake-utils" + ], + "gitignore": "gitignore", + "nixpkgs": [ + "nixos-rk3588", + "nixpkgs" + ], + "nixpkgs-stable": [ + "nixos-rk3588", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1702456155, + "narHash": "sha256-I2XhXGAecdGlqi6hPWYT83AQtMgL+aa3ulA85RAEgOk=", + "owner": "cachix", + "repo": "pre-commit-hooks.nix", + "rev": "007a45d064c1c32d04e1b8a0de5ef00984c419bc", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "pre-commit-hooks.nix", + "type": "github" + } + }, "rockpi-quad": { "inputs": { "nixos-hardware": [ @@ -963,7 +1112,9 @@ "nix-ld": "nix-ld", "nixos-generators": "nixos-generators", "nixos-hardware": "nixos-hardware", + "nixos-rk3588": "nixos-rk3588", "nixpkgs": "nixpkgs", + "nixpkgs-master": "nixpkgs-master", "rockpi-quad": "rockpi-quad", "snowfall-lib": "snowfall-lib_5", "sops-nix": "sops-nix", @@ -1252,6 +1403,21 @@ "type": "github" } }, + "systems_8": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, "thaw": { "inputs": { "nixpkgs": "nixpkgs_3", diff --git a/flake.nix b/flake.nix index 510dc63..a8a6118 100644 --- a/flake.nix +++ b/flake.nix @@ -4,6 +4,7 @@ inputs = { # NixPkgs nixpkgs.url = "github:nixos/nixpkgs/nixos-25.05"; + nixpkgs-master.url = "github:nixos/nixpkgs/master"; # NixPkgs Unstable unstable.url = "github:nixos/nixpkgs/nixos-unstable"; @@ -134,6 +135,16 @@ inputs.nixos-hardware.follows = "nixos-hardware"; }; + nixos-rk3588 = { + url = "github:gnull/nixos-rk3588"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + + # uboot-flake = { + # url = "path:/home/kylepzak/development/build-software/custom-nix/uboot-radxa-build"; + # inputs.nixpkgs.follows = "nixpkgs-master"; + # }; + }; outputs = @@ -280,6 +291,9 @@ stormjib = { system = "aarch64-linux"; }; + lightship-aus = { + system = "aarch64-linux"; + }; }; modules = let diff --git a/homes/x86_64-linux/root@docker/default.nix b/homes/x86_64-linux/root@docker/default.nix new file mode 100644 index 0000000..3f48b25 --- /dev/null +++ b/homes/x86_64-linux/root@docker/default.nix @@ -0,0 +1,21 @@ +{ lib, ... }: +{ + + projectinitiative = { + home = { + enable = true; + stateVersion = "24.11"; + home = lib.mkForce "/root"; + }; + + suites = { + terminal-env.enable = true; + }; + + cli-apps = { + zsh.enable = true; + nix.enable = true; + home-manager.enable = true; + }; + }; +} diff --git a/modules/home/browsers/chrome/default.nix b/modules/home/browsers/chrome/default.nix index 598d4d6..2f4d33a 100644 --- a/modules/home/browsers/chrome/default.nix +++ b/modules/home/browsers/chrome/default.nix @@ -11,7 +11,7 @@ with lib; with lib.${namespace}; let cfg = config.${namespace}.browsers.chrome; - isGraphical = osConfig.${namespace}.isGraphical; + isGraphical = lib.attrByPath [ namespace "isGraphical" ] false osConfig; in { options.${namespace}.browsers.chrome = with types; { diff --git a/modules/home/browsers/chromium/default.nix b/modules/home/browsers/chromium/default.nix index f51cea8..f693551 100644 --- a/modules/home/browsers/chromium/default.nix +++ b/modules/home/browsers/chromium/default.nix @@ -11,7 +11,7 @@ with lib; with lib.${namespace}; let cfg = config.${namespace}.browsers.chromium; - isGraphical = osConfig.${namespace}.isGraphical; + isGraphical = lib.attrByPath [ namespace "isGraphical" ] false osConfig; in { options.${namespace}.browsers.chromium = with types; { diff --git a/modules/home/browsers/firefox/default.nix b/modules/home/browsers/firefox/default.nix index e3720bd..acfb74b 100644 --- a/modules/home/browsers/firefox/default.nix +++ b/modules/home/browsers/firefox/default.nix @@ -11,7 +11,7 @@ with lib; with lib.${namespace}; let cfg = config.${namespace}.browsers.firefox; - isGraphical = osConfig.${namespace}.isGraphical; + isGraphical = lib.attrByPath [ namespace "isGraphical" ] false osConfig; in { options.${namespace}.browsers.firefox = with types; { diff --git a/modules/home/browsers/ladybird/default.nix b/modules/home/browsers/ladybird/default.nix index 35f3d45..11dd7cf 100644 --- a/modules/home/browsers/ladybird/default.nix +++ b/modules/home/browsers/ladybird/default.nix @@ -11,7 +11,7 @@ with lib; with lib.${namespace}; let cfg = config.${namespace}.browsers.ladybird; - isGraphical = osConfig.${namespace}.isGraphical; + isGraphical = lib.attrByPath [ namespace "isGraphical" ] false osConfig; in { options.${namespace}.browsers.ladybird = with types; { diff --git a/modules/home/browsers/librewolf/default.nix b/modules/home/browsers/librewolf/default.nix index 7ebc56f..f57f245 100644 --- a/modules/home/browsers/librewolf/default.nix +++ b/modules/home/browsers/librewolf/default.nix @@ -11,7 +11,7 @@ with lib; with lib.${namespace}; let cfg = config.${namespace}.browsers.librewolf; - isGraphical = osConfig.${namespace}.isGraphical; + isGraphical = lib.attrByPath [ namespace "isGraphical" ] false osConfig; in { options.${namespace}.browsers.librewolf = with types; { diff --git a/modules/home/browsers/tor/default.nix b/modules/home/browsers/tor/default.nix index e0ccef4..e539471 100644 --- a/modules/home/browsers/tor/default.nix +++ b/modules/home/browsers/tor/default.nix @@ -11,7 +11,7 @@ with lib; with lib.${namespace}; let cfg = config.${namespace}.browsers.tor; - isGraphical = osConfig.${namespace}.isGraphical; + isGraphical = lib.attrByPath [ namespace "isGraphical" ] false osConfig; in { options.${namespace}.browsers.tor = with types; { diff --git a/modules/home/suites/backup/default.nix b/modules/home/suites/backup/default.nix index 47c6179..f11c486 100644 --- a/modules/home/suites/backup/default.nix +++ b/modules/home/suites/backup/default.nix @@ -11,7 +11,7 @@ with lib; with lib.${namespace}; let cfg = config.${namespace}.suites.backup; - isGraphical = osConfig.${namespace}.isGraphical; + isGraphical = lib.attrByPath [ namespace "isGraphical" ] false osConfig; in { options.${namespace}.suites.backup = with types; { diff --git a/modules/home/suites/digital-creation/default.nix b/modules/home/suites/digital-creation/default.nix index 3fd2020..e7b9bdb 100644 --- a/modules/home/suites/digital-creation/default.nix +++ b/modules/home/suites/digital-creation/default.nix @@ -11,7 +11,7 @@ with lib; with lib.${namespace}; let cfg = config.${namespace}.suites.digital-creation; - isGraphical = osConfig.${namespace}.isGraphical; + isGraphical = lib.attrByPath [ namespace "isGraphical" ] false osConfig; in { options.${namespace}.suites.digital-creation = with types; { diff --git a/modules/home/suites/messengers/default.nix b/modules/home/suites/messengers/default.nix index a607d8c..984d590 100644 --- a/modules/home/suites/messengers/default.nix +++ b/modules/home/suites/messengers/default.nix @@ -11,7 +11,7 @@ with lib; with lib.${namespace}; let cfg = config.${namespace}.suites.messengers; - isGraphical = osConfig.${namespace}.isGraphical; + isGraphical = lib.attrByPath [ namespace "isGraphical" ] false osConfig; in { options.${namespace}.suites.messengers = with types; { diff --git a/modules/nixos/hosts/masthead/default.nix b/modules/nixos/hosts/masthead/default.nix index 5e91d4e..979270c 100644 --- a/modules/nixos/hosts/masthead/default.nix +++ b/modules/nixos/hosts/masthead/default.nix @@ -17,222 +17,106 @@ in enable = mkBoolOpt false "Whether or not to enable the masthead router base config."; }; - # config = mkIf cfg.enable { - - # projectinitiative.hosts.base-router = { - # enable = true; - - # # Interface names - # wanInterface = "wan0"; - # lanInterface = "lan0"; - - # # Management VLAN configuration - # managementVlan = { - # id = 1; # Untagged VLAN - # network = "172.16.1.0/24"; - # primaryIp = "172.16.1.2"; # Primary router's IP - # backupIp = "172.16.1.3"; # Backup router's IP - # virtualIp = "172.16.1.1"; # Virtual IP for management - # }; - - # # VRRP base configuration - # vrrp = { - # enable = true; - # routerId = 10; - # authPass = "your_vrrp_password_here"; # Use sops-nix in production - - # # These will be overridden by host-specific configurations - # # priority = set in host config - # # peerAddress = set in host config - # }; - - # # DNS configuration - # dnsServers = [ - # "1.1.1.1" - # "9.9.9.9" - # ]; - - # # DHCP configuration - # # For home network using existing DHCP server: - # dhcpMode = "external"; - # externalDhcpServer = "192.168.1.1"; # Your home router's IP - # --- Router Configuration (using base-router module) --- - # ${namespace}.router = { - # enable = true; - # routerRole = routerRole; # Pass role defined above - - # # --- Interfaces --- - # wanInterface = "eth0"; # Adjust to your hardware - # lanInterface = "eth1"; # Adjust to your hardware - - # # --- Management Network --- - # managementVlan = { - # id = 10; # Tagged management VLAN - # network = "172.16.10.0/24"; - # primaryIp = "172.16.10.2"; - # backupIp = "172.16.10.3"; - # virtualIp = "172.16.10.1"; - # # enableDhcp = false; # Default is false - # }; - - # # --- User VLANs --- - # vlans = [ - # { - # id = 20; - # name = "users"; - # network = "192.168.20.0/24"; - # primaryIp = "192.168.20.2"; - # backupIp = "192.168.20.3"; - # virtualIp = "192.168.20.1"; - # enableDhcp = true; - # dhcpRangeStart = "192.168.20.100"; - # dhcpRangeEnd = "192.168.20.200"; - # } - # { - # id = 30; - # name = "iot"; - # network = "192.168.30.0/24"; - # primaryIp = "192.168.30.2"; - # backupIp = "192.168.30.3"; - # virtualIp = "192.168.30.1"; - # enableDhcp = true; - # dhcpRangeStart = "192.168.30.50"; - # dhcpRangeEnd = "192.168.30.150"; - # isolated = true; # Isolate this VLAN - # } - # ]; - - # # --- WAN IP --- - # externalStaticIp = { - # address = "YOUR_STATIC_IP"; - # prefixLength = 24; # Your prefix length - # gateway = "YOUR_GATEWAY_IP"; - # }; - # # Or set externalStaticIp = null; to use DHCP on WAN - - # # --- DNS --- - # dnsServers = [ "9.9.9.9" "1.1.1.1" ]; # Override defaults if needed - # dnsCacheSize = 2000; # Customize DNS cache - - # # --- DHCP --- - # keaDhcp4.enable = true; - # keaDhcp4.failover = mkIf config.${namespace}.hosts.base-router.vrrp.enable { # Enable failover only if VRRP is enabled - # # Parameters are mostly defaults, adjust if needed - # mclt = 1800; # Example override - # }; - - # # For self-hosted DHCP, change to: - # # dhcpMode = "internal"; - - # # VLAN definitions shared between all routers - # vlans = [ - # # IoT VLAN - # { - # id = 21; - # name = "iot"; - # network = "192.168.21.0/24"; - # virtualIp = "192.168.21.1"; # VRRP address for clients - # primaryIp = "192.168.21.2"; # Primary router's IP - # backupIp = "192.168.21.3"; # Backup router's IP - # enableDhcp = true; - # dhcpRangeStart = "192.168.21.100"; - # dhcpRangeEnd = "192.168.21.250"; - # isolated = true; # Isolate IoT devices from other networks - # } - - # # Guest VLAN - # { - # id = 22; - # name = "guest"; - # network = "192.168.22.0/24"; - # virtualIp = "192.168.22.1"; - # primaryIp = "192.168.22.2"; - # backupIp = "192.168.22.3"; - # enableDhcp = true; - # dhcpRangeStart = "192.168.22.100"; - # dhcpRangeEnd = "192.168.22.250"; - # isolated = true; # Isolate guest network - # } - - # # Home network VLAN - # { - # id = 10; - # name = "home"; - # network = "192.168.10.0/24"; - # virtualIp = "192.168.10.1"; - # primaryIp = "192.168.10.2"; - # backupIp = "192.168.10.3"; - # enableDhcp = true; - # dhcpRangeStart = "192.168.10.100"; - # dhcpRangeEnd = "192.168.10.250"; - # isolated = false; # Allow communication with other non-isolated VLANs - # } - - # # Media VLAN - # { - # id = 30; - # name = "media"; - # network = "192.168.30.0/24"; - # virtualIp = "192.168.30.1"; - # primaryIp = "192.168.30.2"; - # backupIp = "192.168.30.3"; - # enableDhcp = true; - # dhcpRangeStart = "192.168.30.100"; - # dhcpRangeEnd = "192.168.30.250"; - # isolated = false; - # } - # ]; - - # # Port forwarding rules (example) - # portForwarding = [ - # { - # sourcePort = 80; - # destination = "192.168.10.50"; - # destinationPort = 80; - # protocol = "tcp"; - # } - # { - # sourcePort = 443; - # destination = "192.168.10.50"; - # destinationPort = 443; - # protocol = "tcp"; - # } - # ]; - # }; - - # }; - # # --- VRRP / Keepalived --- - # vrrp.enable = true; # Enable HA - # vrrp.virtualRouterIdBase = 50; # Customize base VRID - # vrrp.priority = if routerRole == "primary" then 150 else 100; # Explicit priorities - # # vrrp.authPass = "supersecret"; # Use authPassFile instead - # vrrp.authPassFile = config.sops.secrets."keepalived_vrrp_password".path; - # vrrp.keaFailoverPort = 647; # Ensure this matches Kea config if using failover - - # # --- Firewall --- - # allowPingFromWan = false; - # portForwarding = [ - # { sourcePort = 80; destination = "192.168.20.10"; protocol = "tcp"; description = "Web Server"; } - # { sourcePort = 443; destination = "192.168.20.10"; protocol = "tcp"; } - # { sourcePort = 1194; destination = "192.168.20.11"; destinationPort = 1194; protocol = "udp"; description = "OpenVPN"; } - # ]; - - # # --- Kernel --- - # extraKernelModules = [ "wireguard" ]; # Example - # extraSysctlSettings = { - # "net.core.somaxconn" = 1024; # Example custom sysctl - # }; - - # }; - - # # --- SOPS Configuration (Example) --- - # sops.secrets."keepalived_vrrp_password" = { - # # mode = "0400"; # keepalived runs as root, default mode is fine - # # owner = config.users.users.keepalived.name; # Not needed if root reads it - # }; - # # sops.secrets."root_password" = {}; - - # # Disable NetworkManager as interfaces are manually configured by the router modules - # networking.networkmanager.enable = false; - # }; + config = mkIf cfg.enable { + + # # --- Router Configuration (using base-router module) --- + # ${namespace}.router = { + # enable = true; + # routerRole = routerRole; # Pass role defined above + + # # --- Interfaces --- + # wanInterface = "eth0"; # Adjust to your hardware + # lanInterface = "eth1"; # Adjust to your hardware + + # # --- Management Network --- + # managementVlan = { + # id = 10; # Tagged management VLAN + # network = "172.16.10.0/24"; + # primaryIp = "172.16.10.2"; + # backupIp = "172.16.10.3"; + # virtualIp = "172.16.10.1"; + # # enableDhcp = false; # Default is false + # }; + + # # --- User VLANs --- + # vlans = [ + # { + # id = 20; + # name = "users"; + # network = "192.168.20.0/24"; + # primaryIp = "192.168.20.2"; + # backupIp = "192.168.20.3"; + # virtualIp = "192.168.20.1"; + # enableDhcp = true; + # dhcpRangeStart = "192.168.20.100"; + # dhcpRangeEnd = "192.168.20.200"; + # } + # { + # id = 30; + # name = "iot"; + # network = "192.168.30.0/24"; + # primaryIp = "192.168.30.2"; + # backupIp = "192.168.30.3"; + # virtualIp = "192.168.30.1"; + # enableDhcp = true; + # dhcpRangeStart = "192.168.30.50"; + # dhcpRangeEnd = "192.168.30.150"; + # isolated = true; # Isolate this VLAN + # } + # ]; + + # # --- WAN IP --- + # externalStaticIp = { + # address = "YOUR_STATIC_IP"; + # prefixLength = 24; # Your prefix length + # gateway = "YOUR_GATEWAY_IP"; + # }; + # # Or set externalStaticIp = null; to use DHCP on WAN + + # # --- DNS --- + # dnsServers = [ "9.9.9.9" "1.1.1.1" ]; # Override defaults if needed + # dnsCacheSize = 2000; # Customize DNS cache + + # # --- DHCP --- + # keaDhcp4.enable = true; + # keaDhcp4.failover = mkIf config.${namespace}.hosts.base-router.vrrp.enable { # Enable failover only if VRRP is enabled + # # Parameters are mostly defaults, adjust if needed + # mclt = 1800; # Example override + # }; + + # # --- VRRP / Keepalived --- + # vrrp.enable = true; # Enable HA + # vrrp.virtualRouterIdBase = 50; # Customize base VRID + # vrrp.priority = if routerRole == "primary" then 150 else 100; # Explicit priorities + # # vrrp.authPass = "supersecret"; # Use authPassFile instead + # vrrp.authPassFile = config.sops.secrets."keepalived_vrrp_password".path; + # vrrp.keaFailoverPort = 647; # Ensure this matches Kea config if using failover + # # ======= + + # # --- Firewall --- + # allowPingFromWan = false; + # portForwarding = [ + # { sourcePort = 80; destination = "192.168.20.10"; protocol = "tcp"; description = "Web Server"; } + # { sourcePort = 443; destination = "192.168.20.10"; protocol = "tcp"; } + # { sourcePort = 1194; destination = "192.168.20.11"; destinationPort = 1194; protocol = "udp"; description = "OpenVPN"; } + # ]; + + # # --- Kernel --- + # extraKernelModules = [ "wireguard" ]; # Example + # extraSysctlSettings = { + # "net.core.somaxconn" = 1024; # Example custom sysctl + # }; + + # }; + + # # --- SOPS Configuration (Example) --- + # sops.secrets."keepalived_vrrp_password" = { + # # mode = "0400"; # keepalived runs as root, default mode is fine + # # owner = config.users.users.keepalived.name; # Not needed if root reads it + # }; + # # sops.secrets."root_password" = {}; + + # # Disable NetworkManager as interfaces are manually configured by the router modules + # networking.networkmanager.enable = false; + }; } diff --git a/modules/nixos/system/rockchip-kernel/default.nix b/modules/nixos/system/rockchip-kernel/default.nix new file mode 100644 index 0000000..cd61ee1 --- /dev/null +++ b/modules/nixos/system/rockchip-kernel/default.nix @@ -0,0 +1,248 @@ +# /etc/nixos/modules/custom-patched-kernel.nix +{ + config, + lib, + pkgs, + namespace, # This should be the namespace you use for your custom options + ... +}: + +with lib; + +let + # Configuration for this custom kernel module + cfg = config.${namespace}.system.patched-kernel; + + # Fetch the kernel source based on configuration + kernelSrc = pkgs.fetchFromGitHub { + owner = cfg.kernelOwner; + repo = cfg.kernelRepo; + rev = cfg.kernelRev; + hash = cfg.kernelSourceHash; + }; + + # Derivation to extract version information from the kernel's Makefile + versionInfo = + pkgs.runCommand "custom-kernel-version-info" + { + nativeBuildInputs = [ + pkgs.coreutils + pkgs.gnugrep + pkgs.gnused + ]; + src = kernelSrc; # Use the fetched kernel source + } + '' + cd $src + + # Extract version components from the Makefile + VER=$(grep -E '^VERSION\s*=' Makefile | sed 's/.*= *//') + PL=$(grep -E '^PATCHLEVEL\s*=' Makefile | sed 's/.*= *//') + SL=$(grep -E '^SUBLEVEL\s*=' Makefile | sed 's/.*= *//') + EXTRA=$(grep -E '^EXTRAVERSION\s*=' Makefile | sed 's/.*= *//') # e.g., -rc4, -custom1 + + # Construct the full kernel version string (e.g., 6.14.0-rc6-custom) + kernelVersion="$VER.$PL.$SL$EXTRA" + + # Construct the module directory version string + # For most kernels, this is identical to kernelVersion. + # Some kernels might have a slightly different scheme, but this is a common default. + kernelModDirVersion="$VER.$PL.$SL$EXTRA" + + # Output the versions to files + mkdir -p $out + echo -n "$kernelVersion" > $out/version + echo -n "$kernelModDirVersion" > $out/modDirVersion + + # Basic validation + if [ -z "$VER" ] || [ -z "$PL" ] || [ -z "$SL" ]; then + echo "Error: Failed to parse base version components (VERSION, PATCHLEVEL, SUBLEVEL) from Makefile." >&2 + exit 1 + fi + if [ -z "$kernelVersion" ]; then + echo "Error: Failed to construct kernelVersion string." >&2 + exit 1 + fi + if [ -z "$kernelModDirVersion" ]; then + echo "Error: Failed to construct kernelModDirVersion string." >&2 + exit 1 + fi + ''; + + # Define the custom/patched kernel package + linux_patched = + { buildLinux, fetchpatch, ... }@args: # Added fetchpatch for patch handling + buildLinux ( + args + // { + # Use the dynamically determined versions + version = builtins.readFile (versionInfo + "/version"); + modDirVersion = builtins.readFile (versionInfo + "/modDirVersion"); + + src = kernelSrc; # Use the fetched kernel source + + # Apply any additional patches specified in the configuration + # Patches are applied in the order they are listed. + patches = cfg.extraPatches; + + # Standard kernel hardening options (optional, adjust as needed) + hardeningEnable = [ "fortify" ]; # Example, can be customized or removed + + # Kernel configuration + # This section needs to be tailored for your Rockchip board (e.g., Radxa E52C) + # and the base configuration of the kernel source you are using (e.g., Collabora's). + # Start by ensuring essential Rockchip drivers and features are enabled. + structuredExtraConfig = + with lib.kernel; + { + # --- Essential ARM64 and Rockchip Options (Examples - VERIFY AND CUSTOMIZE) --- + ARCH_ROCKCHIP = yes; + ROCKCHIP_PM_DOMAINS = yes; # Rockchip Power Management Domains + + # Interrupt Controller (GIC - Generic Interrupt Controller) + IRQ_GIC_V3 = yes; + IRQ_GIC_V3_ITS = yes; # ITS (Interrupt Translation Service) for GICv3 + + # Console Support (ensure your serial console works) + SERIAL_8250 = yes; + SERIAL_8250_CONSOLE = yes; + SERIAL_8250_ROCKCHIP = yes; # If a specific Rockchip 8250 driver is used/needed + + # Storage (MMC/SD/eMMC - Essential for booting) + MMC = yes; + # Choose the correct Rockchip MMC/SDHCI driver for your SoC (RK3582/RK3588) + # Common ones include: + MMC_ROCKCHIP = yes; # General Rockchip MMC driver + DW_MMC = yes; # DesignWare MMC interface + DW_MMC_ROCKCHIP = yes; # Rockchip specific DesignWare MMC + + # Pin Control and Clocking (Crucial for board bring-up) + PINCTRL = yes; + PINCTRL_ROCKCHIP = yes; # Or a more specific one for RK358x series + COMMON_CLK = yes; + COMMON_CLK_ROCKCHIP = yes; # Or a more specific one for RK358x series + + # Reset Controller + RESET_CONTROLLER = yes; + RESET_ROCKCHIP = yes; + + # Device Tree Support + OF_EARLY_FLATTREE = yes; # For early device tree parsing + + # --- End Essential Rockchip Options --- + + # Add any configurations required by your specific patches or kernel source + # For example, if a patch enables a new driver: + # MY_NEW_ROCKCHIP_DRIVER = module; # or yes + + } + // ( # Conditionally add debug options + if cfg.debug then + { + DEBUG_KERNEL = yes; + DEBUG_INFO = yes; + # Add other relevant debug Kconfig options if needed + # For GIC issues, you might look for GIC_DEBUG or IRQ_DEBUG options + # DEBUG_IRQCHIP = yes; # Example, check Kconfig for actual name + } + else + { } + ); + + # If the kernel source you are using (e.g., Collabora's) provides a + # specific defconfig for your board (e.g., rockchip_linux_defconfig, rk3588_defconfig), + # you might consider using it as a base. However, `buildLinux` in Nixpkgs + # typically starts from a generic config and applies `structuredExtraConfig`. + # To use a defconfig directly, you'd modify how `buildLinux` is called or + # ensure your `structuredExtraConfig` is comprehensive enough. + } + ); + + # Build the kernel package itself + customKernel = pkgs.callPackage linux_patched { + # You can pass additional arguments to linux_patched here if needed, + # for example, if you need to override stdenv or other build inputs. + }; + + # Create the corresponding linuxPackages set (headers, tools, etc.) + linuxPackages_custom_patched = pkgs.linuxPackagesFor customKernel; + +in +{ + # Define the NixOS options for this module + options.${namespace}.system.patched-kernel = { + enable = mkEnableOption "a custom patched kernel"; + + kernelOwner = mkOption { + type = types.str; + default = "torvalds"; # Example: "collabora", "rockchip-linux" + description = "The GitHub owner (user or organization) of the kernel repository."; + }; + + kernelRepo = mkOption { + type = types.str; + default = "linux"; # Example: "linux", "kernel-rockchip" + description = "The name of the kernel repository on GitHub."; + }; + + kernelRev = mkOption { + type = types.str; + default = "master"; # Or a specific tag like "v6.14.0", or a commit SHA + description = "Git branch, tag, or commit hash of the kernel repository to use."; + }; + + kernelSourceHash = mkOption { + type = types.str; + # IMPORTANT: You MUST replace this with the actual prefetch hash. + # Use lib.fakeSha256 or a placeholder like below initially. + # nix-build will fail and tell you the correct hash. + default = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="; # REPLACE THIS + description = "SHA256 hash of the fetched kernel source code (replace after first failed build)."; + example = "sha256-abcdefghijklmnopqrstuvwxyz0123456789ABCDEFG="; + }; + + extraPatches = mkOption { + type = types.listOf types.path; # A patch can be a local file path or a derivation (e.g., from fetchpatch) + default = []; + description = '' + A list of additional patches to apply to the kernel source. + Patches are applied in the order they are listed. + ''; + example = literalExpression '' + [ + (pkgs.fetchpatch { + name = "0001-rockchip-gic-fix.patch"; + url = "https://example.com/path/to/your/rockchip-gic-fix.patch"; + hash = "sha256-patchhashhere"; + # Apply arguments if the patch needs it, e.g., stripLen = 1; + }) + ./my-local-board-quirk.patch # Assuming this patch is next to your configuration.nix + ] + ''; + }; + + debug = mkOption { + type = types.bool; + default = false; # Set to true to enable kernel debug options + description = "Enable kernel debug features (DEBUG_KERNEL, DEBUG_INFO, etc.)."; + }; + }; + + # Apply the configuration if this module is enabled + config = mkIf cfg.enable { + # Set the system to use the custom patched kernel and its packages + boot.kernelPackages = mkForce linuxPackages_custom_patched; + + # If you were using bcachefs and no longer need it with this kernel, + # you might want to remove it from supportedFilesystems and systemPackages. + # boot.supportedFilesystems = lib.mkIf (builtins.elem "bcachefs" config.boot.supportedFilesystems) + # (lib.filter (fs: fs != "bcachefs") config.boot.supportedFilesystems) + # else config.boot.supportedFilesystems; # Or just let it be if not harmful + + # environment.systemPackages = lib.mkIf (builtins.any (p: p.pname == "bcachefs-tools") config.environment.systemPackages) + # (lib.filter (p: p.pname != "bcachefs-tools") config.environment.systemPackages) + # else config.environment.systemPackages; + # Consider if perf tools from the custom kernel are needed: + # environment.systemPackages = with pkgs; [ linuxPackages_custom_patched.perf ]; + }; +} diff --git a/overlays/uboot-build/default.nix b/overlays/uboot-build/default.nix new file mode 100644 index 0000000..fa179f3 --- /dev/null +++ b/overlays/uboot-build/default.nix @@ -0,0 +1,43 @@ +{ channels, inputs, ... }: + +final: prev: { + # Just use the version from the channels.nixpkgs that you've provided + # We are defining a NEW package from scratch using the 'buildUBoot' + # factory function, which is the proper way to do this. + uboot-rk3582-generic = channels.nixpkgs-master.buildUBoot { + pname = "uboot-rk3582-generic"; + # Use the version from the default U-Boot in nixpkgs, and add a suffix. + version = "${prev.ubootOrangePi5.version}-rk3582-patched"; + + # --- Critical Build Configuration --- + # We use the generic RK3588 defconfig, which your patch modifies. + defconfig = "generic-rk3588_defconfig"; + + # Add our patches. + extraPatches = [ + ./patches/0001-rockchip-Add-initial-RK3582-support.patch + ./patches/0002-rockchip-rk3588-generic-Enable-support-for-RK3582.patch + ]; + + # --- Dependencies for RK3588/RK3582 Architecture --- + # These are the same dependencies the other RK3588 boards need. + BL31 = "${prev.armTrustedFirmwareRK3588}/bl31.elf"; + ROCKCHIP_TPL = prev.rkbin.TPL_RK3588; + + # --- Output Files --- + # Tell the build what files to copy to the output directory. + filesToInstall = [ + "u-boot.itb" + "idbloader.img" + "u-boot-rockchip.bin" + # "u-boot-rockchip-spi.bin" + ]; + + # --- Metadata --- + extraMeta = { + description = "Patched U-Boot for generic RK3582/RK3588 boards"; + platforms = [ "aarch64-linux" ]; + }; + }; +} + diff --git a/overlays/uboot-build/patches/0001-rockchip-Add-initial-RK3582-support.patch b/overlays/uboot-build/patches/0001-rockchip-Add-initial-RK3582-support.patch new file mode 100644 index 0000000..f297133 --- /dev/null +++ b/overlays/uboot-build/patches/0001-rockchip-Add-initial-RK3582-support.patch @@ -0,0 +1,150 @@ +diff --git a/arch/arm/mach-rockchip/rk3588/rk3588.c b/arch/arm/mach-rockchip/rk3588/rk3588.c +index c1dce3ee3703..06e6318312b2 100644 +--- a/arch/arm/mach-rockchip/rk3588/rk3588.c ++++ b/arch/arm/mach-rockchip/rk3588/rk3588.c +@@ -7,6 +7,7 @@ + #define LOG_CATEGORY LOGC_ARCH + + #include ++#include + #include + #include + #include +@@ -185,6 +186,12 @@ int arch_cpu_init(void) + + #define RK3588_OTP_CPU_CODE_OFFSET 0x02 + #define RK3588_OTP_SPECIFICATION_OFFSET 0x06 ++#define RK3588_OTP_IP_STATE_OFFSET 0x1d ++ ++#define BAD_CPU_CLUSTER0 GENMASK(3, 0) ++#define BAD_CPU_CLUSTER1 GENMASK(5, 4) ++#define BAD_CPU_CLUSTER2 GENMASK(7, 6) ++#define BAD_GPU GENMASK(4, 1) + + int checkboard(void) + { +@@ -230,3 +237,124 @@ int checkboard(void) + + return 0; + } ++ ++#ifdef CONFIG_OF_SYSTEM_SETUP ++static int fdt_path_del_node(void *fdt, const char *path) ++{ ++ int nodeoffset; ++ ++ nodeoffset = fdt_path_offset(fdt, path); ++ if (nodeoffset < 0) ++ return nodeoffset; ++ ++ return fdt_del_node(fdt, nodeoffset); ++} ++ ++static int fdt_path_set_name(void *fdt, const char *path, const char *name) ++{ ++ int nodeoffset; ++ ++ nodeoffset = fdt_path_offset(fdt, path); ++ if (nodeoffset < 0) ++ return nodeoffset; ++ ++ return fdt_set_name(fdt, nodeoffset, name); ++} ++ ++int ft_system_setup(void *blob, struct bd_info *bd) ++{ ++ static const char * const cpu_node_names[] = { ++ "cpu@0", "cpu@100", "cpu@200", "cpu@300", ++ "cpu@400", "cpu@500", "cpu@600", "cpu@700", ++ }; ++ u8 cpu_code[2], ip_state[3]; ++ int parent, node, i, ret; ++ struct udevice *dev; ++ ++ if (!IS_ENABLED(CONFIG_ROCKCHIP_OTP) || !CONFIG_IS_ENABLED(MISC)) ++ return -ENOSYS; ++ ++ ret = uclass_get_device_by_driver(UCLASS_MISC, ++ DM_DRIVER_GET(rockchip_otp), &dev); ++ if (ret) { ++ log_debug("Could not find otp device, ret=%d\n", ret); ++ return ret; ++ } ++ ++ /* cpu-code: SoC model, e.g. 0x35 0x82 or 0x35 0x88 */ ++ ret = misc_read(dev, RK3588_OTP_CPU_CODE_OFFSET, cpu_code, 2); ++ if (ret < 0) { ++ log_debug("Could not read cpu-code, ret=%d\n", ret); ++ return ret; ++ } ++ ++ log_debug("cpu-code: %02x %02x\n", cpu_code[0], cpu_code[1]); ++ ++ /* skip on rk3588 */ ++ if (cpu_code[0] == 0x35 && cpu_code[1] == 0x88) ++ return 0; ++ ++ ret = misc_read(dev, RK3588_OTP_IP_STATE_OFFSET, &ip_state, 3); ++ if (ret < 0) { ++ log_debug("Could not read ip-state, ret=%d\n", ret); ++ return ret; ++ } ++ ++ log_debug("ip-state: %02x %02x %02x\n", ++ ip_state[0], ip_state[1], ip_state[2]); ++ ++ if (cpu_code[0] == 0x35 && cpu_code[1] == 0x82) { ++ /* policy: always disable gpu */ ++ ip_state[1] |= BAD_GPU; ++ ++ /* policy: always disable one big core cluster */ ++ if (!(ip_state[0] & (BAD_CPU_CLUSTER1 | BAD_CPU_CLUSTER2))) ++ ip_state[0] |= BAD_CPU_CLUSTER2; ++ } ++ ++ if (ip_state[0] & BAD_CPU_CLUSTER1) { ++ /* fail entire cluster when one or more core is bad */ ++ ip_state[0] |= BAD_CPU_CLUSTER1; ++ fdt_path_del_node(blob, "/cpus/cpu-map/cluster1"); ++ } ++ ++ if (ip_state[0] & BAD_CPU_CLUSTER2) { ++ /* fail entire cluster when one or more core is bad */ ++ ip_state[0] |= BAD_CPU_CLUSTER2; ++ fdt_path_del_node(blob, "/cpus/cpu-map/cluster2"); ++ } else if (ip_state[0] & BAD_CPU_CLUSTER1) { ++ /* cluster nodes must be named in a continuous series */ ++ fdt_path_set_name(blob, "/cpus/cpu-map/cluster2", "cluster1"); ++ } ++ ++ /* gpu: ip_state[1]: bit1~4 */ ++ if (ip_state[1] & BAD_GPU) { ++ log_debug("fail gpu\n"); ++ fdt_status_fail_by_pathf(blob, "/gpu@fb000000"); ++ } ++ ++ parent = fdt_path_offset(blob, "/cpus"); ++ if (parent < 0) { ++ log_debug("Could not find /cpus, parent=%d\n", parent); ++ return 0; ++ } ++ ++ /* cpu: ip_state[0]: bit0~7 */ ++ for (i = 0; i < 8; i++) { ++ /* fail any bad cpu core */ ++ if (!(ip_state[0] & BIT(i))) ++ continue; ++ ++ node = fdt_subnode_offset(blob, parent, cpu_node_names[i]); ++ if (node >= 0) { ++ log_debug("fail cpu %s\n", cpu_node_names[i]); ++ fdt_status_fail(blob, node); ++ } else { ++ log_debug("Could not find %s, node=%d\n", ++ cpu_node_names[i], node); ++ } ++ } ++ ++ return 0; ++} ++#endif diff --git a/overlays/uboot-build/patches/0002-rockchip-rk3588-generic-Enable-support-for-RK3582.patch b/overlays/uboot-build/patches/0002-rockchip-rk3588-generic-Enable-support-for-RK3582.patch new file mode 100644 index 0000000..86dda65 --- /dev/null +++ b/overlays/uboot-build/patches/0002-rockchip-rk3588-generic-Enable-support-for-RK3582.patch @@ -0,0 +1,12 @@ +diff --git a/configs/generic-rk3588_defconfig b/configs/generic-rk3588_defconfig +index 51e31dce3a96..903653911f71 100644 +--- a/configs/generic-rk3588_defconfig ++++ b/configs/generic-rk3588_defconfig +@@ -16,6 +16,7 @@ CONFIG_SPL_FIT_SIGNATURE=y + CONFIG_SPL_LOAD_FIT=y + # CONFIG_BOOTMETH_VBE is not set + CONFIG_LEGACY_IMAGE_FORMAT=y ++CONFIG_OF_SYSTEM_SETUP=y + CONFIG_DEFAULT_FDT_FILE="rockchip/rk3588-generic.dtb" + # CONFIG_DISPLAY_CPUINFO is not set + CONFIG_SPL_MAX_SIZE=0x40000 diff --git a/systems/aarch64-linux/lightship-aus/default.nix b/systems/aarch64-linux/lightship-aus/default.nix index 38e7797..cc2ba0f 100644 --- a/systems/aarch64-linux/lightship-aus/default.nix +++ b/systems/aarch64-linux/lightship-aus/default.nix @@ -1,5 +1,5 @@ # /etc/nixos/hosts/lighthouse-east.nix -{ config, pkgs, namespace, modulesPath, ... }: +{ config, pkgs, inputs, namespace, modulesPath, ... }: let # Use /dev/sda as the root disk for Hetzner cloud instances @@ -7,9 +7,13 @@ let in { imports = [ - (modulesPath + "/profiles/qemu-guest.nix") + inputs.nixos-rk3588.nixosModules.default ]; + bootType = "u-boot"; # or "uefi" + compilationType = "cross"; # "local-native", "remote-native", or "cross" + boards.rock5a.enable = true; + # Enable and configure the common hetzner module for this host ${namespace}.hosts.lighthouse = { @@ -19,61 +23,61 @@ in }; # Disko configuration for a single disk with LVM - disko.devices = { - disk.rootSystemDisk = { - type = "disk"; - device = rootDiskDevicePath; - content = { - type = "gpt"; - partitions = { - boot = { - size = "1M"; - type = "EF02"; # BIOS boot partition - }; - # EFI System Partition (ESP) for booting - ESP = { - name = "ESP"; - type = "EF00"; - size = "512M"; - content = { - type = "filesystem"; - format = "vfat"; - mountpoint = "/boot"; - }; - }; - # Partition for LVM Physical Volume - lvm_pv_root = { - name = "lvm_pv"; - size = "100%"; - content = { - type = "lvm_pv"; - vg = "vgSystem"; - }; - }; - }; - }; - }; - lvm_vg.vgSystem = { - type = "lvm_vg"; - lvs = { - lvRoot = { - name = "root"; - size = "100%FREE"; - content = { - type = "filesystem"; - format = "ext4"; - mountpoint = "/"; - }; - }; - }; - }; - }; + # disko.devices = { + # disk.rootSystemDisk = { + # type = "disk"; + # device = rootDiskDevicePath; + # content = { + # type = "gpt"; + # partitions = { + # boot = { + # size = "1M"; + # type = "EF02"; # BIOS boot partition + # }; + # # EFI System Partition (ESP) for booting + # ESP = { + # name = "ESP"; + # type = "EF00"; + # size = "512M"; + # content = { + # type = "filesystem"; + # format = "vfat"; + # mountpoint = "/boot"; + # }; + # }; + # # Partition for LVM Physical Volume + # lvm_pv_root = { + # name = "lvm_pv"; + # size = "100%"; + # content = { + # type = "lvm_pv"; + # vg = "vgSystem"; + # }; + # }; + # }; + # }; + # }; + # lvm_vg.vgSystem = { + # type = "lvm_vg"; + # lvs = { + # lvRoot = { + # name = "root"; + # size = "100%FREE"; + # content = { + # type = "filesystem"; + # format = "ext4"; + # mountpoint = "/"; + # }; + # }; + # }; + # }; + # }; - # GRUB Bootloader Configuration for EFI system - boot.loader.grub = { - enable = true; - efiSupport = true; - device = "nodev"; # Required for disko - }; - boot.loader.efi.canTouchEfiVariables = false; + # # GRUB Bootloader Configuration for EFI system + # boot.loader.grub = { + # enable = true; + # efiSupport = true; + # device = "nodev"; # Required for disko + # }; + # boot.loader.efi.canTouchEfiVariables = false; } diff --git a/systems/aarch64-linux/stormjib-rockchip/README.md b/systems/aarch64-linux/stormjib-rockchip/README.md new file mode 100644 index 0000000..22cc8f3 --- /dev/null +++ b/systems/aarch64-linux/stormjib-rockchip/README.md @@ -0,0 +1,101 @@ + +# NixOS Build for Rockchip RK3588/RK3582 + +## Project Overview + +This project is a Nix-based build system for creating custom NixOS images for Rockchip RK3588/RK3582-based single-board computers (SBCs), specifically targeting a device that appears to be the Radxa E52C. It automates the process of building U-Boot, the Linux kernel, a root filesystem, and assembling them into a bootable disk image. + +## File Structure + +* `default.nix`: The main NixOS configuration for the target device. It imports other modules, sets kernel parameters, and defines the overall system configuration. +* `rockchip-sd-image.nix`: This is the core module for building the Rockchip-specific bootable image. It orchestrates the U-Boot build, kernel selection, and image assembly. +* `uboot-build.nix`: This file defines the Nix derivations for building the U-Boot bootloader. It fetches the U-Boot source code, applies necessary patches, and builds the `idbloader.img` and `u-boot.itb` files. +* `assemble-monolithic-image.nix`: This script takes the U-Boot binaries, the boot partition, and the rootfs partition and assembles them into a single, monolithic disk image that can be flashed to an eMMC or SD card. +* `make-ext4.nix` & `make-fat-fs.nix`: These are helper scripts for creating the ext4 root filesystem and the FAT32 boot partition, respectively. +* `sd-image.nix`: A more generic SD card image builder, which seems to be less used in this specific configuration in favor of the `rockchip-sd-image.nix` module. +* `file-options.nix`: Defines Nix options for image configuration. +* `uboot-disable-hdmi0-phy-ref.patch`: A patch file to modify the U-Boot device tree, likely to disable an HDMI port that is not used or causes issues on the target hardware. +* `kernel/`: This directory contains pre-built kernel components (`kernel.img`, `rockchip.dtb`, `boot.scr`). These might be used for testing or as a fallback if the kernel build process is not yet fully integrated into the Nix build. + +## How to Build + +To build the NixOS image, you will use the `nix build` command. The specific command you provided is correct: + +```bash +nix build .#nixosConfigurations.stormjib-rockchip.config.system.build.image +``` + +This command tells Nix to build the `image` attribute of the `stormjib-rockchip` NixOS configuration defined in your flake. The result of the build will be a symlink named `result` in your current directory, which points to the built disk image in the Nix store. + +## How to Test and Install + +After a successful build, the `result` symlink will point to the disk image. You can then flash this image to an SD card or eMMC. + +### 1. Flashing the Image + +You can use the `dd` command to write the image to your storage device. First, identify the device name of your SD card (e.g., `/dev/sdX`). + +**BE EXTREMELY CAREFUL** with this step, as writing to the wrong device can result in data loss. + +```bash +sudo dd if=./result of=/dev/sdX bs=4M status=progress conv=fsync +``` + +Replace `/dev/sdX` with the correct device name for your SD card. + +### 2. Flashing to eMMC with `rkdeveloptool` + +For writing the image directly to the onboard eMMC storage, you'll need to use `rkdeveloptool`. This process involves putting the board into a special programming mode and then using the tool to flash the binaries. + +**1. Enter Maskrom or Loader Mode** + +You must first put your device into a mode where it can accept commands from `rkdeveloptool`. This is typically done by holding a specific button on the board while powering it on, or by shorting specific test points. Please refer to your board's documentation for instructions on how to enter "Maskrom mode" or "Loader mode". + +Once in this mode, the device will be detectable by `rkdeveloptool`. You can verify this by running: +```bash +sudo rkdeveloptool ld +``` + +**2. Download the SPL Loader** + +Next, you need to download a special loader binary to the device's RAM. This loader prepares the eMMC for flashing. You will need the appropriate loader file for your RK3588/RK3582 device (e.g., `rk3588_spl_loader_v1.15.113.bin`). + +```bash +sudo rkdeveloptool db /path/to/your/rk3588_spl_loader.bin +``` +*Replace `/path/to/your/rk3588_spl_loader.bin` with the actual path to your loader file.* + +**3. Write the Image to eMMC** + +After the loader is running, you can write the desired image to the eMMC. The build process generates several images inside the `result/` directory. + +* **To flash the complete NixOS system:** Use the full monolithic image. The `result` symlink points to this file. + ```bash + sudo rkdeveloptool wl 0 ./result + ``` + +* **To flash only the U-Boot bootloader:** If you only want to update U-Boot without touching the rest of the OS, you can flash the `uboot-only.img`. + ```bash + sudo rkdeveloptool wl 0 ./result/uboot-only.img + ``` + +The `wl 0` command tells the tool to start writing the image at block address `0` of the eMMC. After the write operation is complete, you can reboot the device. + +### 3. Debugging with Minicom + +To debug the boot process, you can use a serial console. The `minicom` command you provided is the correct way to connect to the serial console of the E52C board. + +```bash +sudo minicom -w -t xterm -l -R UTF-8 -D /dev/ttyUSB0 -b 1500000 +``` + +This command will open a serial console session with the following settings: + +* `-w`: No line wrap +* `-t xterm`: Xterm terminal type +* `-l`: No log file +* `-R UTF-8`: UTF-8 character encoding +* `-D /dev/ttyUSB0`: Serial device +* `-b 1500000`: Baud rate of 1,500,000 + +This will allow you to see the U-Boot and kernel boot messages and interact with the serial console. diff --git a/systems/aarch64-linux/stormjib-rockchip/assemble-monolithic-image.nix b/systems/aarch64-linux/stormjib-rockchip/assemble-monolithic-image.nix new file mode 100644 index 0000000..ff04283 --- /dev/null +++ b/systems/aarch64-linux/stormjib-rockchip/assemble-monolithic-image.nix @@ -0,0 +1,303 @@ +# assemble-monolithic-image.nix +{ pkgs, lib, + ubootIdbloaderFile, + ubootItbFile, + nixosBootImageFile, + nixosRootfsImageFile, + buildFullImage ? true, + buildUbootImage ? false, + buildOsImage ? false +}: + +let + idbloaderOffsetBytes = 64 * 512; # 32 KiB -> Sector 64 + itbOffsetBytes = 16384 * 512; # 8 MiB -> Sector 16384 + + alignmentUnitBytes = 1 * 1024 * 1024; # 1MiB + bytesToSectors = bytes: bytes / 512; + alignUp = (val: unit: ((val + unit - 1) / unit) * unit); + + # --- Full Monolithic Image (eMMC Style) --- + # ### MODIFIED: Start boot partition at 16MiB to align with Radxa's parameter_gpt.txt + fullImgBootPartitionStartMinBytes = 16 * 1024 * 1024; # Start boot partition at 16MiB + fullImgBootPartitionStartBytes = alignUp fullImgBootPartitionStartMinBytes alignmentUnitBytes; + fullImgBootPartitionStartSectors = bytesToSectors fullImgBootPartitionStartBytes; + + # --- OS Only Image (SD Card Style) --- + osImgBootPartitionStartBytes = alignUp (1 * 1024 * 1024) alignmentUnitBytes; # Start at 1 MiB + osImgBootPartitionStartSectors = bytesToSectors osImgBootPartitionStartBytes; + + linuxFsTypeGuid = "0FC63DAF-8483-4772-8E79-3D69D8477DE4"; + efiSysTypeGuid = "C12A7328-F81F-11D2-BA4B-00A0C93EC93B"; + +in pkgs.stdenv.mkDerivation { + name = "nixos-e52c-disk-images"; + + srcs = [ + ubootIdbloaderFile + ubootItbFile + nixosBootImageFile + nixosRootfsImageFile + ]; + + nativeBuildInputs = [ + pkgs.coreutils + pkgs.util-linux + pkgs.parted + ]; + + env = { + IDBLOADER_FILE_PATH_ENV = ubootIdbloaderFile; + ITB_FILE_PATH_ENV = ubootItbFile; + BOOT_IMAGE_FILE_PATH_ENV = nixosBootImageFile; + ROOTFS_IMAGE_FILE_PATH_ENV = nixosRootfsImageFile; + + IDBLOADER_OFFSET_SECTORS_ENV = builtins.toString (bytesToSectors idbloaderOffsetBytes); + ITB_OFFSET_SECTORS_ENV = builtins.toString (bytesToSectors itbOffsetBytes); + + FULL_IMG_BOOT_PART_START_SECTORS_ENV = builtins.toString fullImgBootPartitionStartSectors; + OS_IMG_BOOT_PART_START_SECTORS_ENV = builtins.toString osImgBootPartitionStartSectors; + + ALIGNMENT_BYTES_ENV = builtins.toString alignmentUnitBytes; + LINUX_FS_GUID_ENV = linuxFsTypeGuid; + EFI_SYS_GUID_ENV = efiSysTypeGuid; + + BUILD_FULL_IMAGE_ENV = if buildFullImage then "true" else "false"; + BUILD_UBOOT_IMAGE_ENV = if buildUbootImage then "true" else "false"; + BUILD_OS_IMAGE_ENV = if buildOsImage then "true" else "false"; + }; + + outputs = [ "out" ]; + phases = [ "buildPhase" "installPhase" ]; + + buildPhase = '' + set -xe + + local idbloader_file="$IDBLOADER_FILE_PATH_ENV" + local itb_file="$ITB_FILE_PATH_ENV" + local boot_img_file="$BOOT_IMAGE_FILE_PATH_ENV" + local rootfs_img_file="$ROOTFS_IMAGE_FILE_PATH_ENV" + + local idbloader_offset_sectors="$IDBLOADER_OFFSET_SECTORS_ENV" + local itb_offset_sectors="$ITB_OFFSET_SECTORS_ENV" + local full_img_boot_part_start_sectors="$FULL_IMG_BOOT_PART_START_SECTORS_ENV" + local os_img_boot_part_start_sectors="$OS_IMG_BOOT_PART_START_SECTORS_ENV" + local alignment_unit_bytes="$ALIGNMENT_BYTES_ENV" + local linux_fs_guid="$LINUX_FS_GUID_ENV" + local efi_sys_guid="$EFI_SYS_GUID_ENV" + local build_full_img="$BUILD_FULL_IMAGE_ENV" + local build_uboot_img="$BUILD_UBOOT_IMAGE_ENV" + local build_os_img="$BUILD_OS_IMAGE_ENV" + + local idbloader_size_bytes=0 + [[ -f "$idbloader_file" ]] && idbloader_size_bytes=$(${pkgs.coreutils}/bin/stat -c %s "$idbloader_file" | ${pkgs.coreutils}/bin/tr -d '[:space:]') + local itb_size_bytes=0 + [[ -f "$itb_file" ]] && itb_size_bytes=$(${pkgs.coreutils}/bin/stat -c %s "$itb_file" | ${pkgs.coreutils}/bin/tr -d '[:space:]') + local boot_img_size_bytes=0 + [[ -f "$boot_img_file" ]] && boot_img_size_bytes=$(${pkgs.coreutils}/bin/stat -c %s "$boot_img_file" | ${pkgs.coreutils}/bin/tr -d '[:space:]') + local rootfs_img_size_bytes=0 + [[ -f "$rootfs_img_file" ]] && rootfs_img_size_bytes=$(${pkgs.coreutils}/bin/stat -c %s "$rootfs_img_file" | ${pkgs.coreutils}/bin/tr -d '[:space:]') + + local boot_img_min_sectors=0 + [[ -n "$boot_img_size_bytes" && "$boot_img_size_bytes" -gt 0 ]] && boot_img_min_sectors=$(( ($boot_img_size_bytes + 511) / 512 )) # Ensure sectors cover full size + local rootfs_img_min_sectors=0 + [[ -n "$rootfs_img_size_bytes" && "$rootfs_img_size_bytes" -gt 0 ]] && rootfs_img_min_sectors=$(( ($rootfs_img_size_bytes + 511) / 512 )) # Ensure sectors cover full size + + echo "--- Input Files ---" + echo "IDBloader: $idbloader_file (Size: $idbloader_size_bytes bytes)" + echo "U-Boot ITB: $itb_file (Size: $itb_size_bytes bytes)" + echo "Boot Image: $boot_img_file (Size: $boot_img_size_bytes bytes, Min Sectors: $boot_img_min_sectors)" + echo "RootFS Image: $rootfs_img_file (Size: $rootfs_img_size_bytes bytes, Min Sectors: $rootfs_img_min_sectors)" + + if [[ "$build_uboot_img" == "true" || "$build_full_img" == "true" ]]; then + if (( idbloader_size_bytes <= 0 )); then echo "Error: IDBloader file size is zero or invalid ($idbloader_size_bytes)."; exit 1; fi + if (( itb_size_bytes <= 0 )); then echo "Error: U-Boot ITB file size is zero or invalid ($itb_size_bytes)."; exit 1; fi + fi + if [[ "$build_os_img" == "true" || "$build_full_img" == "true" ]]; then + if (( boot_img_min_sectors <= 0 )); then + echo "Error: Boot image minimum sectors evaluated as zero or less ('$boot_img_min_sectors'). Size was $boot_img_size_bytes bytes. Check path: $boot_img_file" + exit 1 + fi + if (( rootfs_img_min_sectors <= 0 )); then + echo "Error: RootFS image minimum sectors evaluated as zero or less ('$rootfs_img_min_sectors'). Size was $rootfs_img_size_bytes bytes. Check path: $rootfs_img_file" + exit 1 + fi + fi + + # --- Build U-Boot Only Image --- + if [[ "$build_uboot_img" == "true" ]]; then + echo "" + echo "--- Assembling U-Boot Only Image: uboot-only.img ---" + local uboot_img_name="uboot-only.img" + # ### MODIFIED: Ensure image is large enough for ITB at its offset + ITB size + local uboot_img_min_end_bytes=$(($itb_offset_sectors * 512 + $itb_size_bytes)) + local uboot_img_total_size_bytes=$(( (($uboot_img_min_end_bytes + $alignment_unit_bytes - 1) / $alignment_unit_bytes ) * $alignment_unit_bytes )) + # Ensure minimum 16MB for uboot only image if it's smaller, to be safe with some tools/expectations + if (( uboot_img_total_size_bytes < 16 * 1024 * 1024 )); then uboot_img_total_size_bytes=$((16 * 1024 * 1024)); fi + + echo "U-Boot image min end: $uboot_img_min_end_bytes, Aligned total size: $uboot_img_total_size_bytes bytes" + echo "[INFO] 1. Creating empty sparse image file: $uboot_img_name" + "${pkgs.coreutils}/bin/truncate" -s "$uboot_img_total_size_bytes" "$uboot_img_name" + echo "[INFO] 2. Writing idbloader.img to sector $idbloader_offset_sectors..." + "${pkgs.coreutils}/bin/dd" if="$idbloader_file" of="$uboot_img_name" seek="$idbloader_offset_sectors" conv=notrunc,fsync bs=512 status=progress + echo "[INFO] 3. Writing u-boot.itb to sector $itb_offset_sectors..." + "${pkgs.coreutils}/bin/dd" if="$itb_file" of="$uboot_img_name" seek="$itb_offset_sectors" conv=notrunc,fsync bs=512 status=progress + echo "--- U-Boot Only image created: $uboot_img_name ---" + fi + + # --- Build OS Only Image --- + if [[ "$build_os_img" == "true" ]]; then + echo "" + echo "--- Assembling OS Only Image (SD Card): os-only.img ---" + local os_img_name="os-only.img" + local os_img_boot_uuid=$(${pkgs.util-linux}/bin/uuidgen) + local os_img_root_uuid=$(${pkgs.util-linux}/bin/uuidgen) + + local os_img_rootfs_part_start_sectors=$(($os_img_boot_part_start_sectors + $boot_img_min_sectors)) + local os_img_min_end_bytes=$(($os_img_rootfs_part_start_sectors * 512 + $rootfs_img_size_bytes)) + # ### MODIFIED: Add some padding to the OS image size (e.g., 100MB) to avoid issues with exact fits + local os_img_total_size_bytes=$(( (($os_img_min_end_bytes + 100 * 1024 * 1024 + $alignment_unit_bytes - 1) / $alignment_unit_bytes ) * $alignment_unit_bytes )) + local os_img_total_sectors=$(($os_img_total_size_bytes / 512)) + + echo "OS Image Layout:" + echo " Boot Partition Start: Sector $os_img_boot_part_start_sectors (Size: $boot_img_min_sectors sectors)" + echo " RootFS Partition Start: Sector $os_img_rootfs_part_start_sectors (Size: $rootfs_img_min_sectors sectors)" + echo " OS Image Total Size: $os_img_total_size_bytes bytes ($os_img_total_sectors sectors)" + + + echo "[INFO] 1. Creating empty sparse image file: $os_img_name" + "${pkgs.coreutils}/bin/truncate" -s "$os_img_total_size_bytes" "$os_img_name" + + echo "[INFO] 2. Creating GPT partition table on $os_img_name..." + local os_img_rootfs_part_end_sector=$(($os_img_rootfs_part_start_sectors + $rootfs_img_min_sectors - 1)) + if (( os_img_rootfs_part_end_sector >= os_img_total_sectors )); then + echo "Error: OS image: Calculated rootfs partition end ($os_img_rootfs_part_end_sector) exceeds or equals total sectors ($os_img_total_sectors)." + exit 1 + fi + + "${pkgs.util-linux}/bin/sfdisk" "$os_img_name" << EOF +label: gpt +unit: sectors +first-lba: 34 + +name="NIXOS_BOOT", start=$os_img_boot_part_start_sectors, size=$boot_img_min_sectors, type="$efi_sys_guid", uuid="$os_img_boot_uuid" +name="NIXOS_ROOT", start=$os_img_rootfs_part_start_sectors, size=$rootfs_img_min_sectors, type="$linux_fs_guid", uuid="$os_img_root_uuid" +EOF + + echo "[INFO] OS image partition table created. Verifying..." + "${pkgs.util-linux}/bin/sfdisk" --verify --no-tell-kernel "$os_img_name" || echo "[WARNING] sfdisk verification (OS image) reported issues." + "${pkgs.util-linux}/bin/sfdisk" -l "$os_img_name" + "${pkgs.parted}/bin/parted" -s "$os_img_name" print + + echo "[INFO] 3. Writing NixOS boot image to partition 1 (sector $os_img_boot_part_start_sectors)..." + "${pkgs.coreutils}/bin/dd" if="$boot_img_file" of="$os_img_name" seek="$os_img_boot_part_start_sectors" conv=notrunc,fsync bs=512 status=progress + + echo "[INFO] 4. Writing NixOS rootfs image to partition 2 (sector $os_img_rootfs_part_start_sectors)..." + "${pkgs.coreutils}/bin/dd" if="$rootfs_img_file" of="$os_img_name" seek="$os_img_rootfs_part_start_sectors" conv=notrunc,fsync bs=512 status=progress + + echo "--- OS Only image created: $os_img_name ---" + fi + + if [[ "$build_full_img" == "true" ]]; then + echo "" + echo "--- Assembling Full Monolithic Image: nixos-e52c-full.img ---" + local full_img_name="nixos-e52c-full.img" + local full_img_boot_uuid=$(${pkgs.util-linux}/bin/uuidgen) + local full_img_root_uuid=$(${pkgs.util-linux}/bin/uuidgen) + + local full_img_rootfs_part_start_sectors=$(($full_img_boot_part_start_sectors + $boot_img_min_sectors)) + local full_img_min_end_bytes=$(($full_img_rootfs_part_start_sectors * 512 + $rootfs_img_size_bytes)) + # ### MODIFIED: Add some padding to the full image size (e.g., 100MB) + local full_img_total_size_bytes=$(( (($full_img_min_end_bytes + 100 * 1024 * 1024 + $alignment_unit_bytes - 1) / $alignment_unit_bytes ) * $alignment_unit_bytes )) + local full_img_total_sectors=$(($full_img_total_size_bytes / 512)) + + echo "Full Image Layout:" + echo " IDBLoader Offset: Sector $idbloader_offset_sectors" + echo " U-Boot ITB Offset: Sector $itb_offset_sectors" + echo " Boot Partition Start: Sector $full_img_boot_part_start_sectors (Size: $boot_img_min_sectors sectors)" + echo " RootFS Partition Start: Sector $full_img_rootfs_part_start_sectors (Size: $rootfs_img_min_sectors sectors)" + echo " Full Image Total Size: $full_img_total_size_bytes bytes ($full_img_total_sectors sectors)" + + + echo "[INFO] 1. Creating empty sparse image file: $full_img_name" + "${pkgs.coreutils}/bin/truncate" -s "$full_img_total_size_bytes" "$full_img_name" + + echo "[INFO] 2. Writing idbloader.img..." + "${pkgs.coreutils}/bin/dd" if="$idbloader_file" of="$full_img_name" seek="$idbloader_offset_sectors" conv=notrunc,fsync bs=512 status=progress + echo "[INFO] 3. Writing u-boot.itb..." + "${pkgs.coreutils}/bin/dd" if="$itb_file" of="$full_img_name" seek="$itb_offset_sectors" conv=notrunc,fsync bs=512 status=progress + + echo "[INFO] 4. Creating GPT partition table on $full_img_name..." + local full_img_rootfs_part_end_sector=$(($full_img_rootfs_part_start_sectors + $rootfs_img_min_sectors - 1)) + if (( full_img_rootfs_part_end_sector >= full_img_total_sectors )); then + echo "Error: Full image: Calculated rootfs partition end ($full_img_rootfs_part_end_sector) exceeds or equals total sectors ($full_img_total_sectors)." + exit 1 + fi + + "${pkgs.util-linux}/bin/sfdisk" "$full_img_name" << EOF +label: gpt +unit: sectors +first-lba: 34 + +name="NIXOS_BOOT", start=$full_img_boot_part_start_sectors, size=$boot_img_min_sectors, type="$efi_sys_guid", uuid="$full_img_boot_uuid" +name="NIXOS_ROOT", start=$full_img_rootfs_part_start_sectors, size=$rootfs_img_min_sectors, type="$linux_fs_guid", uuid="$full_img_root_uuid" +EOF + + echo "[INFO] Full image partition table created. Verifying..." + "${pkgs.util-linux}/bin/sfdisk" --verify --no-tell-kernel "$full_img_name" || echo "[WARNING] sfdisk verification (Full image) reported issues." + "${pkgs.util-linux}/bin/sfdisk" -l "$full_img_name" + "${pkgs.parted}/bin/parted" -s "$full_img_name" print + + echo "[INFO] 5. Writing NixOS boot image..." + "${pkgs.coreutils}/bin/dd" if="$boot_img_file" of="$full_img_name" seek="$full_img_boot_part_start_sectors" conv=notrunc,fsync bs=512 status=progress + echo "[INFO] 6. Writing NixOS rootfs image..." + "${pkgs.coreutils}/bin/dd" if="$rootfs_img_file" of="$full_img_name" seek="$full_img_rootfs_part_start_sectors" conv=notrunc,fsync bs=512 status=progress + + echo "--- Full monolithic image created: $full_img_name ---" + fi + + if [[ "$build_full_img" == "false" && "$build_uboot_img" == "false" && "$build_os_img" == "false" ]]; then + echo "[WARNING] No image types selected for building. Nothing to do in buildPhase." + fi + echo "--- Build phase completed ---" + ''; + + installPhase = '' + mkdir -p $out + local any_image_built=false + if [[ "$BUILD_UBOOT_IMAGE_ENV" == "true" ]] && [[ -f uboot-only.img ]]; then + echo "Installing uboot-only.img..." + mv uboot-only.img $out/uboot-only.img + any_image_built=true + fi + if [[ "$BUILD_OS_IMAGE_ENV" == "true" ]] && [[ -f os-only.img ]]; then + echo "Installing os-only.img..." + mv os-only.img $out/os-only.img + any_image_built=true + fi + if [[ "$BUILD_FULL_IMAGE_ENV" == "true" ]] && [[ -f nixos-e52c-full.img ]]; then + echo "Installing nixos-e52c-full.img..." + mv nixos-e52c-full.img $out/nixos-e52c-full.img # This will be the primary output for flakes + any_image_built=true + fi + + if [[ "$any_image_built" == "false" ]]; then + echo "[INFO] No images were built or found to install." + touch $out/.no_images_built_placeholder # Create a placeholder if no images built + else + # ### ADDED: Ensure there's at least one primary output file if any image was built + # If building full image, that's the primary. Otherwise, pick one. + if [[ "$BUILD_FULL_IMAGE_ENV" == "true" ]] && [[ -f $out/nixos-e52c-full.img ]]; then + echo "Default output will be nixos-e52c-full.img" + elif [[ "$BUILD_OS_IMAGE_ENV" == "true" ]] && [[ -f $out/os-only.img ]]; then + ln -s $out/os-only.img $out/default.img + elif [[ "$BUILD_UBOOT_IMAGE_ENV" == "true" ]] && [[ -f $out/uboot-only.img ]]; then + ln -s $out/uboot-only.img $out/default.img + fi + fi + echo "--- Installation phase completed ---" + ''; + + dontStrip = true; + dontFixup = true; +} diff --git a/systems/aarch64-linux/stormjib-rockchip/boot.cmd b/systems/aarch64-linux/stormjib-rockchip/boot.cmd new file mode 100644 index 0000000..f12161f --- /dev/null +++ b/systems/aarch64-linux/stormjib-rockchip/boot.cmd @@ -0,0 +1,17 @@ + +# boot.cmd + +# Set the device and partition to boot from +setenv devtype mmc +setenv devnum 0 +setenv partition 1 + +# Load the extlinux.conf file +if load ${devtype} ${devnum}:${partition} ${loadaddr} /extlinux/extlinux.conf; then + # Source the extlinux.conf file to get the boot entries + env import -t ${loadaddr} ${filesize} + # Run the default boot entry + run bootcmd +else + echo "Could not load extlinux.conf" +fi diff --git a/systems/aarch64-linux/stormjib-rockchip/default.nix b/systems/aarch64-linux/stormjib-rockchip/default.nix new file mode 100644 index 0000000..d115c58 --- /dev/null +++ b/systems/aarch64-linux/stormjib-rockchip/default.nix @@ -0,0 +1,145 @@ +# default.nix +{ + config, + inputs, + pkgs, + lib, + modulesPath, + ... +}: +let + hostSSHFile = pkgs.writeText "ssh_host_ed25519_key" config.sensitiveNotSecret.stormjib_private_ssh_key; + hostSSHPubFile = pkgs.writeText "ssh_host_ed25519_key.pub" config.sensitiveNotSecret.stormjib_public_ssh_key; + + # ### ADDED: Example of how to specify a custom TPL file if you generated one + # ### Option 1: You generated it outside Nix and have a path + # myCustomTpl = /path/to/my/generated_ddr.bin; + # ### Option 2: You have a ddrbin_param.txt and want Nix to try generating it (EXPERIMENTAL) + # myDdrParamFile = ./my_e52c_ddrbin_param.txt; # You need to create this file! + +in +{ + imports = with inputs.nixos-hardware.nixosModules; [ + (modulesPath + "/installer/scan/not-detected.nix") + # ### MODIFIED: Pass custom TPL options to rockchip-sd-image.nix + (import ./rockchip-sd-image.nix { + inherit config + lib + pkgs + modulesPath + inputs; + # customTplFileForUboot = myCustomTpl; # Uncomment if using Option 1 + # ddrParamFileForUboot = myDdrParamFile; # Uncomment if using Option 2 + # If both are null, uboot-build.nix will use its default generic TPL. + }) + ]; + + # home-manager.users.kylepzak.home.stateVersion = "25.05"; + + boot = { + supportedFilesystems.zfs = lib.mkForce false; + loader = { + grub.enable = false; + systemd-boot.enable = false; + generic-extlinux-compatible.enable = true; + }; + kernelParams = [ + "nomodeset" # Often needed for initial boot on SBCs if display drivers are tricky + "keep_bootcon" + ]; + # kernelPackages = pkgs.linuxPackages_latest; # This is now handled in rockchip-sd-image.nix + }; + + environment.etc = { + "ssh/ssh_host_ed25519_key" = { + source = hostSSHFile; + mode = "0600"; + user = "root"; + group = "root"; + }; + "ssh/ssh_host_ed25519_key.pub" = { + source = hostSSHPubFile; + mode = "0644"; + user = "root"; + group = "root"; + }; + }; + + projectinitiative = { + hosts.masthead.stormjib.enable = false; # Assuming this is your project-specific module + networking = { + tailscale = { + enable = false; + ephemeral = false; + extraArgs = [ + "--accept-dns=false" + ]; + }; + }; + system = { + console-info.ip-display.enable = false; + }; + }; + + services.openssh.enable = true; + console.enable = true; # For serial console access in NixOS + environment.systemPackages = with pkgs; [ + # Add any essential tools you want in the final image + vim + htop + # rkdeveloptool # If you want this on the device itself + ]; + + # Networking: Your systemd-networkd setup looks reasonable. + # Ensure the MAC addresses 0a:80:4e:8f:aa:37 and 0e:80:4e:8f:aa:37 are correct for your E52C's interfaces. + # networking = { + # networkmanager.enable = false; + # useDHCP = false; + # interfaces = { }; + # useNetworkd = true; + # }; + # systemd.network = { + # enable = true; + # # wait-online.enable = false; # Might be useful during debugging if network is slow to come up + + # links = { + # "10-lan" = { + # matchConfig.MACAddress = "16:ba:ba:b6:27:7a"; + # linkConfig.Name = "lan0"; + # }; + # "11-wan" = { + # matchConfig.MACAddress = "16:ba:ba:b6:27:7b"; + # linkConfig.Name = "wan0"; + # }; + # }; + # networks = { + # "12-lan" = { + # matchConfig.Name = "lan0"; + # networkConfig = { + # DHCP = "yes"; # or static IP configuration + # IPv6AcceptRA = false; # Explicitly false if you don't want RA + # }; + # }; + # "13-wan" = { + # matchConfig.Name = "wan0"; + # networkConfig = { + # DHCP = "yes"; # or static IP configuration + # IPv6AcceptRA = false; # Explicitly false if you don't want RA + # }; + # }; + # }; + # }; + + # Keep tmpfs and journald settings for SD card longevity + # fileSystems."/tmp" = { + # device = "tmpfs"; + # fsType = "tmpfs"; + # options = [ "nosuid" "nodev" "relatime" "size=256M" ]; + # }; + # services.journald.extraConfig = '' + # Storage=volatile + # RuntimeMaxUse=64M + # SystemMaxUse=64M + # ''; + +} diff --git a/systems/aarch64-linux/stormjib-rockchip/file-options.nix b/systems/aarch64-linux/stormjib-rockchip/file-options.nix new file mode 100644 index 0000000..dff30e7 --- /dev/null +++ b/systems/aarch64-linux/stormjib-rockchip/file-options.nix @@ -0,0 +1,48 @@ +{ + lib, + config, + pkgs, + ... +}: +{ + options.image = { + baseName = lib.mkOption { + type = lib.types.str; + default = "nixos-image-${config.system.nixos.label}-${pkgs.stdenv.hostPlatform.system}"; + description = '' + Basename of the image filename without any extension (e.g. `image_1`). + ''; + }; + + extension = lib.mkOption { + type = lib.types.str; + description = '' + Extension of the image filename (e.g. `raw`). + ''; + }; + + # FIXME: this should be marked readOnly, when there are no + # mkRenamedOptionModuleWith calls with `image.fileName` as + # as a target left anymore (i.e. 24.11). We can't do it + # before, as some source options where writable before. + # Those should use image.baseName and image.extension instead. + fileName = lib.mkOption { + type = lib.types.str; + default = "${config.image.baseName}.${config.image.extension}"; + description = '' + Filename of the image including all extensions (e.g `image_1.raw` or + `image_1.raw.zst`). + ''; + }; + + filePath = lib.mkOption { + type = lib.types.str; + default = config.image.fileName; + description = '' + Path of the image, relative to `$out` in `system.build.image`. + While it defaults to `config.image.fileName`, it can be different for builders where + the image is in sub directory, such as `iso`, `sd-card` or `kexec` images. + ''; + }; + }; +} diff --git a/systems/aarch64-linux/stormjib-rockchip/make-ext4.nix b/systems/aarch64-linux/stormjib-rockchip/make-ext4.nix new file mode 100644 index 0000000..3b8b2a5 --- /dev/null +++ b/systems/aarch64-linux/stormjib-rockchip/make-ext4.nix @@ -0,0 +1,149 @@ +# Builds an ext4 image containing a populated /nix/store with the closure +# of store paths passed in the storePaths parameter, in addition to the +# contents of a directory that can be populated with commands. The +# generated image is sized to only fit its contents, with the expectation +# that a script resizes the filesystem at boot time. +# --- MODIFIED VERSION: Includes file truncation after resize --- +{ + pkgs, + lib, + # List of derivations to be included + storePaths, + # Whether or not to compress the resulting image with zstd + compressImage ? false, + zstd, + # Shell commands to populate the ./files directory. + # All files in that directory are copied to the root of the FS. + populateImageCommands ? "", + volumeLabel, + uuid ? "44444444-4444-4444-8888-888888888888", + e2fsprogs, + libfaketime, + perl, + fakeroot, +}: + +let + sdClosureInfo = pkgs.buildPackages.closureInfo { rootPaths = storePaths; }; +in +pkgs.stdenv.mkDerivation { + name = "ext4-fs.img${lib.optionalString compressImage ".zst"}"; + + nativeBuildInputs = [ + e2fsprogs.bin + libfaketime + perl + fakeroot + ] ++ lib.optional compressImage zstd; + + buildCommand = '' + set -e # Exit immediately if a command exits with a non-zero status. + echo "--- Starting make-ext4-fs buildCommand ---" + + img_file_name="ext4-rootfs.img" # Define a consistent internal name + ${if compressImage then "img=$img_file_name" else "img=$out"} + + # Need to handle the case where img IS $out if not compressing + if [ "$img" != "$out" ]; then + touch $img # Ensure temp file exists if compressing + else + # If not compressing, $img points directly to $out, ensure it exists + # $out is a directory, so we create the final file path inside it + img="$out/''${img_file_name}" + mkdir -p $out + touch $img + fi + + ( + mkdir -p ./files + ${populateImageCommands} + ) + + echo "Preparing store paths for image..." + + # Create nix/store before copying path + mkdir -p ./rootImage/nix/store + + xargs -I % cp -a --reflink=auto % -t ./rootImage/nix/store/ < ${sdClosureInfo}/store-paths + ( + GLOBIGNORE=".:.." + shopt -u dotglob + + for f in ./files/*; do + cp -a --reflink=auto -t ./rootImage/ "$f" + done + ) + + # Also include a manifest of the closures in a format suitable for nix-store --load-db + cp ${sdClosureInfo}/registration ./rootImage/nix-path-registration + + # --- Size calculation, mkfs, resize2fs --- + numInodes=$(find ./rootImage | wc -l) + numDataBlocks=$(du -s -c -B 4096 --apparent-size ./rootImage | tail -1 | awk '{ print int($1 * 1.20) }') + bytes=$((2 * 4096 * $numInodes + 4096 * $numDataBlocks)) + echo "Initial calculated size estimate: $bytes bytes (numInodes=$numInodes, numDataBlocks=$numDataBlocks)" + mebibyte=$(( 1024 * 1024 )) + if (( bytes % mebibyte )); then bytes=$(( ( bytes / mebibyte + 1) * mebibyte )); fi + echo "Rounding up initial size to $bytes bytes" + truncate -s $bytes $img # Initial truncate based on estimation + faketime -f "1970-01-01 00:00:01" fakeroot mkfs.ext4 -m 0 -L ${volumeLabel} -U ${uuid} -d ./rootImage $img + export EXT2FS_NO_MTAB_OK=yes + fsck.ext4 -n -f $img || { echo "--- Fsck failed after mkfs ---"; exit 1; } + echo "Shrinking filesystem to minimum size..." + resize2fs -M $img + echo "--- Filesystem info after resize2fs -M ---" + dumpe2fs -h $img || echo "ERROR: dumpe2fs after resize2fs -M failed" + echo "-------------------------------------------" + echo "Calculating target size with 16MiB buffer..." + dumpe2fs_output=$(dumpe2fs -h $img) || { echo "ERROR: dumpe2fs command for target_blocks failed"; exit 1; } + target_blocks=$(echo "$dumpe2fs_output" | awk -F: '/Block count/{count=$2} /Block size/{size=$2} END{ if (size > 0) { print int((count*size+16*1024*1024)/size + 0.999999) } else { exit 1 } }') + if [ -z "$target_blocks" ]; then echo "ERROR: Failed to parse target_blocks"; echo "$dumpe2fs_output"; exit 1; fi + echo "Resizing filesystem to $target_blocks blocks..." + resize2fs $img $target_blocks + # --- End Size calculation --- + + + # --- Truncate file and VERIFY --- + echo "Truncating image file to match resized filesystem..." + dumpe2fs_output_after_resize=$(dumpe2fs -h $img) || { echo "ERROR: dumpe2fs command failed after resize"; exit 1; } + blockSize=$(echo "$dumpe2fs_output_after_resize" | awk -F: '/Block size/ { print $2 }' | tr -d ' ') + if [ -z "$blockSize" ] || [ "$blockSize" -le 0 ]; then echo "ERROR: Failed to determine valid blockSize"; echo "$dumpe2fs_output_after_resize"; exit 1; fi + finalSizeBytes=$((''${target_blocks} * ''${blockSize})) + if [ -z "$finalSizeBytes" ] || [ "$finalSizeBytes" -le 0 ]; then echo "ERROR: Calculation of finalSizeBytes failed ($target_blocks * $blockSize)"; exit 1; fi + + echo "Final calculated filesystem size is ''${finalSizeBytes} bytes (''${target_blocks} blocks of size ''${blockSize} bytes)." + echo "Executing: truncate -s ''${finalSizeBytes} ''${img}" + truncate -s ''${finalSizeBytes} ''${img} + echo "Truncate command finished." + + echo "--- Verifying size of resulting file ($img) post-truncate ---" + ls -lh ''${img} || echo "ls failed" + stat ''${img} || echo "stat failed" + echo "--- End verification ---" + # --- End Truncate file --- + + # --- Final Checks and Compression --- + echo "Performing final fsck check..." + fsck.ext4 -n -f $img || { echo "--- Fsck failed after final truncation ---"; exit 1; } + + if [ ''${builtins.toString compressImage} ]; then + echo "Compressing image ''${img} to $out" + zstd -T$NIX_BUILD_CORES -v --no-progress ''${img} -o $out + echo "--- Verifying size of final compressed file ($out) ---" + ls -lh $out || echo "ls failed" + elif [ "$img" != "$out/''${img_file_name}" ]; then + # If not compressing, and $img was temporary, move it to $out + # This case shouldn't happen with the logic at the top now, but as a safeguard + echo "Moving temporary image ''${img} to final destination $out/''${img_file_name}" + # Ensure $out exists (it should, based on top logic) + mkdir -p $out + mv ''${img} $out/''${img_file_name} + echo "--- Verifying size of final uncompressed file ($out/''${img_file_name}) ---" + ls -lh $out/''${img_file_name} || echo "ls failed" + else + echo "--- Final uncompressed file is $img ---" + # Already verified size after truncate + fi + echo "--- Finishing make-ext4-fs buildCommand ---" + ''; +} diff --git a/systems/aarch64-linux/stormjib-rockchip/make-fat-fs.nix b/systems/aarch64-linux/stormjib-rockchip/make-fat-fs.nix new file mode 100644 index 0000000..610181e --- /dev/null +++ b/systems/aarch64-linux/stormjib-rockchip/make-fat-fs.nix @@ -0,0 +1,230 @@ +# make-fat-fs.nix +# Builds a VFAT (FAT32) image containing specified Nix store paths +# and populated files. The image is created with a fixed size. +{ + pkgs, + lib, + # List of derivations to be included (their closures) + storePaths, + # Size of the VFAT image (e.g., "256M", "1G"). Required. + size, + # Volume label for the VFAT filesystem (max 11 characters). + volumeLabel ? "VFAT_BOOT", + # Volume ID (32-bit hex number). Auto-generated if null. + volumeID ? null, # Example: "aabbccdd" + # Whether or not to compress the resulting image with zstd + compressImage ? false, + # Shell commands to populate the ./files directory. + # All files in that directory are copied to the root of the VFAT FS. + populateImageCommands ? "", + # Dependencies (explicitly passed for clarity, could also use pkgs directly) + dosfstools ? pkgs.dosfstools, + mtools ? pkgs.mtools, + coreutils ? pkgs.coreutils, # For du, truncate, basename, etc. + findutils ? pkgs.findutils, # For find + gnused ? pkgs.gnused, # For sed + gawk ? pkgs.gawk, # For awk + libfaketime ? pkgs.libfaketime, + zstd ? pkgs.zstd, +}: + +let + sdClosureInfo = pkgs.buildPackages.closureInfo { rootPaths = storePaths; }; + + # Parse size string (e.g., "256M", "1G") into bytes. Basic implementation. + # More robust parsing could be added if needed. + sizeInBytes = builtins.readFile (pkgs.runCommand "size-in-bytes" { SIZE_STR=size; } '' + SIZE_STR="$SIZE_STR" + SIZE_VAL=$(echo "$SIZE_STR" | sed 's/[KMGTP]$//i') + UNIT=$(echo "$SIZE_STR" | sed 's/^[0-9]*//i' | tr '[:lower:]' '[:upper:]') + FACTOR=1 + case "$UNIT" in + K) FACTOR=1024 ;; + M) FACTOR=$((1024*1024)) ;; + G) FACTOR=$((1024*1024*1024)) ;; + T) FACTOR=$((1024*1024*1024*1024)) ;; + P) FACTOR=$((1024*1024*1024*1024*1024)) ;; + "") FACTOR=1 ;; # Assume bytes if no unit + *) echo "Error: Unknown size unit '$UNIT' in '$SIZE_STR'" >&2; exit 1 ;; + esac + # Use awk for potentially large number arithmetic + echo "$SIZE_VAL $FACTOR" | ${gawk}/bin/awk '{printf "%.0f", $1 * $2}' > $out + ''); + + +in +pkgs.stdenv.mkDerivation { + name = "vfat-${volumeLabel}.img"; + + nativeBuildInputs = [ + dosfstools + mtools + coreutils + findutils + gnused + gawk + libfaketime + ] ++ lib.optional compressImage zstd; + + # Pass derived values via environment vars + IMG_SIZE_BYTES = sizeInBytes; + VOLUME_LABEL = volumeLabel; + VOLUME_ID = volumeID; # Can be empty string if null + + # Note: We don't need fakeroot as VFAT doesn't store POSIX permissions. + + buildCommand = '' + set -e + echo "--- Starting make-fat-fs buildCommand ---" + + # Internal filename consistency, used only for temporary compressed path + local img_file_name="fat32-fs.img" + local img_path # Path to the image file being worked on + + if ${if compressImage then "true" else "false"}; then + # Compressed case: $out is the final compressed file path + img_path="./''${img_file_name}" # Temporary working file + # Ensure temporary file exists + touch "$img_path" + echo "Working on temporary image: $img_path, will compress to final output path: $out" + else + # --- CHANGE: Non-compressed case: $out IS the final image file path --- + img_path="$out" # $out is the target file path + # Ensure the directory containing $out exists + # Nix usually handles creating the $out directory itself if needed, + # but touching the file requires the dir. + mkdir -p "$(dirname "$out")" + # Ensure the target file exists for truncate/mkfs.vfat + touch "$img_path" + echo "Working directly on final image file path: $img_path" + fi + + local target_size_bytes="$IMG_SIZE_BYTES" + local vol_label="$VOLUME_LABEL" + local vol_id="$VOLUME_ID" + + if [ -z "$target_size_bytes" ] || [ "$target_size_bytes" -le 0 ]; then + echo "Error: Calculated image size ($target_size_bytes bytes) is invalid." + exit 1 + fi + + echo "Target image size: $target_size_bytes bytes" + echo "Volume Label: $vol_label" + echo "Volume ID: ''${vol_id:-}" # Show if empty + + # 1. Create the empty image file of the target size + echo "Creating empty image file: $img_path" + truncate -s "$target_size_bytes" "$img_path" + + # 2. Format the image file as FAT32 + echo "Formatting image as FAT32..." + local mkfs_opts="-F 32 -I" # Force FAT32, allow format on non-block-device + if [ -n "$vol_label" ]; then + mkfs_opts="$mkfs_opts -n $vol_label" + fi + if [ -n "$vol_id" ]; then + mkfs_opts="$mkfs_opts -i $vol_id" + fi + # Use faketime for deterministic filesystem creation time/volume ID generation + faketime -f "1970-01-01 00:00:01" mkfs.vfat $mkfs_opts "$img_path" + + # 3. Prepare the source directory structure (`./rootImage`) + echo "Preparing source files..." + mkdir -p ./rootImage + + # Run user-provided commands to populate ./files + ( + mkdir -p ./files + ${populateImageCommands} + ) + + # Copy Nix store paths (dereference symlinks as FAT doesn't support them) + # Check if there are any store paths to copy + if [ -s "${sdClosureInfo}/store-paths" ]; then + echo "Copying Nix store paths (dereferencing links)..." + # Create nix/store structure if needed (usually not for boot partitions) + # mkdir -p ./rootImage/nix/store # Uncomment if needed + # Copy paths listed in closureInfo to the root of './rootImage' + xargs -I % cp -aL --reflink=auto % -t ./rootImage/ < ${sdClosureInfo}/store-paths + else + echo "No Nix store paths specified to copy." + fi + + + # Copy files populated by populateImageCommands + # Need to handle potential name collisions carefully if store paths are also copied to root + echo "Copying files from ./files directory..." + ( + # Set options for reliable copying, including hidden files + shopt -s dotglob nullglob + local file_count=$(find ./files -mindepth 1 -print -quit | wc -l) + if [ "$file_count" -gt 0 ]; then + cp -arT --reflink=auto ./files/ ./rootImage/ + else + echo "No files found in ./files to copy." + fi + shopt -u dotglob nullglob + ) + + + # 4. Copy files from `./rootImage` into the VFAT image using mtools + echo "Populating VFAT image using mtools..." + # Ensure mtools uses deterministic timestamps + export MTOOLS_SKIP_CHECK=1 # Avoid "device partition exceeds disk size" heuristic checks + export MTOOLSRC=/dev/null # Avoid reading user config + + # Create directories first, sorted for determinism + # Need to cd into rootImage to get relative paths for mtools + ( + cd ./rootImage + # Find directories (excluding the root '.') and sort them + find . -mindepth 1 -type d -printf '%P\n' | sort | while IFS= read -r dir; do + echo "Creating directory in VFAT: ::/$dir" + # Use faketime around each mtools command + faketime -f "1970-01-01 00:00:01" mmd -i "$img_path" "::/$dir" + done + + # Copy files next, sorted for determinism + find . -type f -printf '%P\n' | sort | while IFS= read -r file; do + echo "Copying file to VFAT: ::/$file" + # Use faketime around each mtools command + # -p: Attempt to preserve modification time (within VFAT limits) + # -m: Attempt to preserve mode (limited effect on VFAT) + faketime -f "1970-01-01 00:00:01" mcopy -p -m -i "$img_path" "$file" "::/$file" + done + ) + + + # 5. Verify the filesystem + echo "Verifying VFAT filesystem..." + # Use -v for verbose, -n for non-interactive check + fsck.vfat -v -n "$img_path" || { echo "--- fsck.vfat check failed! ---"; exit 1; } + + # 6. Final Steps (Compression or Moving) + echo "--- Verifying size of resulting image file ($img_path) ---" + ls -lh "$img_path" || echo "ls failed" + stat "$img_path" || echo "stat failed" + echo "--- End verification ---" + + if ${if compressImage then "true" else "false"}; then + echo "Compressing temporary image $img_path to final output path $out ..." + zstd -T$NIX_BUILD_CORES -v --no-progress "$img_path" -o "$out" + echo "--- Verifying size of final compressed file ($out) ---" + ls -lh "$out" || echo "ls failed on compressed $out" + rm "$img_path" # Clean up temporary uncompressed file + else + # --- CHANGE: No move needed, $img_path is already $out --- + echo "--- Final uncompressed image is $img_path (which is the final output path $out) ---" + # Optional verification if needed + if [ -f "$out" ]; then + echo "Final file exists: $out" + ls -lh "$out" || echo "ls failed on final $out" + else + echo "Error: Final output file $out not found!" + exit 1 + fi + fi + + echo "--- Finishing make-fat-fs buildCommand ---" + ''; +} diff --git a/systems/aarch64-linux/stormjib-rockchip/manual-boot-commands.txt b/systems/aarch64-linux/stormjib-rockchip/manual-boot-commands.txt new file mode 100644 index 0000000..50df6e9 --- /dev/null +++ b/systems/aarch64-linux/stormjib-rockchip/manual-boot-commands.txt @@ -0,0 +1,16 @@ +reset +env default -f -a +setenv bootargs "console=ttyS2,115200n8 root=/dev/disk/by-label/NIXOS_SD rootwait" +fatload mmc 1:1 0x07000000 /nixos/6bsnly49mhx656bwpm1sajvk6rvpa5wj-initrd-linux-6.15.4-initrd +setenv initrd_size ${filesize} +fatload mmc 1:1 0x02000000 /nixos/iaziacmiwcyvzfqxwnvdylqyw05c00wy-linux-6.15.4-Image +fatload mmc 1:1 0x01000000 /nixos/iaziacmiwcyvzfqxwnvdylqyw05c00wy-linux-6.15.4-dtbs/rockchip/rk3582-radxa-e52c.dtb +printenv bootargs +booti 0x02000000 0x07000000:${initrd_size} 0x01000000 ${bootargs} + + + + +setenv devnum 1 +setenv devtype mmc +sysboot ${devtype} ${devnum}:1 any ${loadaddr} /extlinux/extlinux.conf diff --git a/systems/aarch64-linux/stormjib-rockchip/rockchip-sd-image.nix b/systems/aarch64-linux/stormjib-rockchip/rockchip-sd-image.nix new file mode 100644 index 0000000..edf8631 --- /dev/null +++ b/systems/aarch64-linux/stormjib-rockchip/rockchip-sd-image.nix @@ -0,0 +1,198 @@ +# rockchip-sd-image.nix +{ + config, + lib, + pkgs, + modulesPath, + # ### ADDED: Optional path to a custom TPL file you generate for U-Boot + # ### If you generate one, pass its path here from default.nix + # customTplFileForUboot ? null, + # # ### ADDED: Optional path to your ddrbin_param.txt for U-Boot TPL generation + # ddrParamFileForUboot ? null, + inputs, + ... +}: + +with lib; + +let + # ### MODIFIED: Pass customTplFile and ddrParamFile to uboot-build + # ubootBuilds = import ./uboot-build.nix { + # inherit pkgs; + # customTplFile = customTplFileForUboot; + # ddrParamFile = ddrParamFileForUboot; + # }; + + # ubootIdbloaderFile = "${ubootBuilds.uboot-rk3588}/bin/idbloader.img"; + # ubootItbFile = "${ubootBuilds.uboot-rk3588}/bin/u-boot.itb"; + ubootIdbloaderFile = "${pkgs.uboot-rk3582-generic}/idbloader.img"; + ubootItbFile = "${pkgs.uboot-rk3582-generic}/u-boot.itb"; + + # ### MODIFIED: Consider using a more specific kernel or Radxa's kernel + # ### For now, let's stick to pkgs.linuxPackages_latest for simplicity + # ### but this is a common area for board-specific changes. + customKernel = pkgs.linuxPackages_latest; # Was pkgs.linuxPackages_6_14 + # ### MODIFIED: Make sure this DTB name is correct for your board AND the kernel version. + dtbName = "rk3582-radxa-e52c.dtb"; # Example, verify this exists for your kernel + # dtbName = "rk3588s-evb1-v10.dtb"; # Example, verify this exists for your kernel + dtbPath = "rockchip/${dtbName}"; + + bootVolumeLabel = "NIXOS_BOOT"; + rootVolumeLabel = "NIXOS_ROOT"; + + emptyBootDir = pkgs.runCommand "empty-boot-dir" {} '' + mkdir -p $out/boot + ''; + +in +{ + imports = [ + (modulesPath + "/profiles/base.nix") + ]; + + config = { + boot.loader.generic-extlinux-compatible.enable = true; + boot.loader.grub.enable = false; + + boot.kernelPackages = customKernel; + hardware.deviceTree = { + enable = true; + name = dtbPath; + }; + boot.kernelParams = [ + # "console=tty1" + # "console=ttys2,115200n8" # primary debug console for rk358x u-boot & kernel + "earlycon=uart8250,mmio32,0xfeb50000" # Matches ttyS2 on rk358x + # "console=ttyFIQ0,115200n8" # Often for SPL/TPL, can be noisy or conflict if ttyS2 is main + "rootwait" + "root=/dev/disk/by-label/${rootVolumeLabel}" + "rw" + "ignore_loglevel" + # "debug" # Keep for debugging + # "earlyprintk" # Keep for debugging + ]; + + fileSystems."/" = { + device = "/dev/disk/by-label/${rootVolumeLabel}"; + fsType = "ext4"; + }; + fileSystems."/boot" = { + device = "/dev/disk/by-label/${bootVolumeLabel}"; + fsType = "vfat"; + }; + + boot.initrd.availableKernelModules = [ + "usbhid" "usb_storage" "sd_mod" "mmc_block" "dw_mmc_rockchip" "ext4" "vfat" "nls_cp437" "nls_iso8859-1" + # ### ADDED: Common for USB networking if you use it via UMS/RNDIS from U-Boot later + "usbnet" "cdc_ether" "rndis_host" + # ### ADDED: NVMe if your E52C has an M.2 slot and you plan to boot from NVMe eventually + # "nvme" "nvme_core" "xhci_pci" # xhci_pci might be needed if NVMe is via PCIe + ]; + + system.build.nixosBootPartitionImage = pkgs.callPackage ./make-fat-fs.nix { + storePaths = []; + populateImageCommands = '' + echo "[INFO] Populating /boot VFAT image..." + mkdir -p ./files + ${config.boot.loader.generic-extlinux-compatible.populateCmd} -c ${config.system.build.toplevel} -d ./files + echo "[INFO] /boot VFAT image populated." + ''; + volumeLabel = bootVolumeLabel; + size = "256M"; + compressImage = false; + }; + + system.build.nixosRootfsPartitionImage = pkgs.callPackage "${pkgs.path}/nixos/lib/make-ext4-fs.nix" { + storePaths = config.system.build.toplevel; + volumeLabel = rootVolumeLabel; + compressImage = false; + }; + + system.build.finalDiskImages = pkgs.callPackage ./assemble-monolithic-image.nix { + inherit ubootIdbloaderFile ubootItbFile; + nixosBootImageFile = config.system.build.nixosBootPartitionImage; + nixosRootfsImageFile = config.system.build.nixosRootfsPartitionImage; + buildFullImage = true; + buildUbootImage = true; + buildOsImage = true; + }; + + system.build.image = config.system.build.finalDiskImages; + + boot.postBootCommands = lib.mkBefore '' + # On the first boot, do some maintenance tasks. + # This script runs in a minimal environment, so we provide full paths to all commands. + if [ -f /nix-path-registration ]; then + # Set bash options for safety: exit on error, exit on unset variable, pipefail. + set -euo pipefail + # Enable command echoing for debugging. + set -x + + # --- Define full paths to all our tools upfront for clarity --- + local FINDMNT="${pkgs.util-linux}/bin/findmnt" + local LSBLK="${pkgs.util-linux}/bin/lsblk" + local ECHO="${pkgs.coreutils}/bin/echo" + local SED="${pkgs.gnused}/bin/sed" + local SFDISK="${pkgs.util-linux}/bin/sfdisk" + local GROWPART="${pkgs.cloud-utils}/bin/growpart" + local PARTPROBE="${pkgs.parted}/bin/partprobe" + local RESIZE2FS="${pkgs.e2fsprogs}/bin/resize2fs" + local SLEEP="${pkgs.coreutils}/bin/sleep" + local RM="${pkgs.coreutils}/bin/rm" + local SYNC="${pkgs.coreutils}/bin/sync" + local NIX_STORE="${config.nix.package.out}/bin/nix-store" + local NIX_ENV="${config.nix.package.out}/bin/nix-env" + + + # --- Script Logic --- + local rootPartDev=$($FINDMNT -n -o SOURCE /) + local bootDevice=$($LSBLK -npo PKNAME "$rootPartDev") + # Extract partition number robustly. + local partNum=$($ECHO "$rootPartDev" | $SED -E 's|^.*[^0-9]([0-9]+)$|\1|') + + $ECHO "Root partition device: ''${rootPartDev}, Boot device: ''${bootDevice}, Root Partition number: ''${partNum}" + + # Attempt to resize the root partition. + $ECHO "Attempting resize with growpart..." + # Note: The 'command -v' check is tricky in this environment. We'll just try growpart directly. + # If cloud-utils is in systemPackages (which it is), growpart should be in the PATH set up for this script. + # But for max safety, we call it by its full path. + if $GROWPART "''${bootDevice}" "''${partNum}"; then + $ECHO "growpart succeeded." + else + $ECHO "[WARNING] growpart failed, attempting sfdisk as fallback..." + $ECHO ",+," | $SFDISK -N"''${partNum}" --no-reread "''${bootDevice}" + fi + + $ECHO "Running partprobe on ''${bootDevice}..." + $PARTPROBE "''${bootDevice}" || $ECHO "[WARNING] partprobe on ''${bootDevice} encountered an issue." + $SLEEP 3 # Give kernel time to recognize changes. + + $ECHO "Resizing filesystem on ''${rootPartDev}..." + $RESIZE2FS "''${rootPartDev}" + + $ECHO "Registering Nix paths..." + $NIX_STORE --load-db < /nix-path-registration + + $ECHO "Setting up system profile..." + $NIX_ENV -p /nix/var/nix/profiles/system --set /run/current-system + + $ECHO "Cleaning up first-boot flag..." + $RM -f /nix-path-registration + $SYNC + + $ECHO "First boot setup complete." + set +x + fi + ''; + + hardware.firmware = with pkgs; [ firmwareLinuxNonfree ]; + environment.systemPackages = with pkgs; [ coreutils util-linux iproute2 parted cloud-utils e2fsprogs emptyBootDir ]; + services.openssh = { + enable = true; + settings.PermitRootLogin = "yes"; + }; + nix.settings.experimental-features = [ "nix-command" "flakes" ]; + system.stateVersion = "24.11"; # Or your current version + }; +} diff --git a/systems/aarch64-linux/stormjib-rockchip/sd-image.nix b/systems/aarch64-linux/stormjib-rockchip/sd-image.nix new file mode 100644 index 0000000..6132753 --- /dev/null +++ b/systems/aarch64-linux/stormjib-rockchip/sd-image.nix @@ -0,0 +1,343 @@ +# This module creates a bootable SD card image containing the given NixOS +# configuration. The generated image is MBR partitioned, with a FAT +# /boot/firmware partition, and ext4 root partition. The generated image +# is sized to fit its contents, and a boot script automatically resizes +# the root partition to fit the device on the first boot. +# +# The firmware partition is built with expectation to hold the Raspberry +# Pi firmware and bootloader, and be removed and replaced with a firmware +# build for the target SoC for other board families. +# +# The derivation for the SD image will be placed in +# config.system.build.sdImage + +{ + config, + lib, + pkgs, + modulesPath, + ... +}: + +with lib; + +let + rootfsImage = pkgs.callPackage ./make-ext4.nix ( + { + inherit (config.sdImage) storePaths; + compressImage = config.sdImage.compressImage; + populateImageCommands = config.sdImage.populateRootCommands; + volumeLabel = "NIXOS_SD"; + } + // optionalAttrs (config.sdImage.rootPartitionUUID != null) { + uuid = config.sdImage.rootPartitionUUID; + } + ); +in +{ + imports = [ + (mkRemovedOptionModule [ "sdImage" "bootPartitionID" ] + "The FAT partition for SD image now only holds the Raspberry Pi firmware files. Use firmwarePartitionID to configure that partition's ID." + ) + (mkRemovedOptionModule [ "sdImage" "bootSize" ] + "The boot files for SD image have been moved to the main ext4 partition. The FAT partition now only holds the Raspberry Pi firmware files. Changing its size may not be required." + ) + (lib.mkRenamedOptionModuleWith { + sinceRelease = 2505; + from = [ + "sdImage" + "imageBaseName" + ]; + to = [ + "image" + "baseName" + ]; + }) + (lib.mkRenamedOptionModuleWith { + sinceRelease = 2505; + from = [ + "sdImage" + "imageName" + ]; + to = [ + "image" + "fileName" + ]; + }) + (modulesPath + "/profiles/all-hardware.nix") + ./file-options.nix + ]; + + options.sdImage = { + storePaths = mkOption { + type = with types; listOf package; + example = literalExpression "[ pkgs.stdenv ]"; + description = '' + Derivations to be included in the Nix store in the generated SD image. + ''; + }; + + firmwarePartitionOffset = mkOption { + type = types.int; + default = 8; + description = '' + Gap in front of the /boot/firmware partition, in mebibytes (1024×1024 + bytes). + Can be increased to make more space for boards requiring to dd u-boot + SPL before actual partitions. + + Unless you are building your own images pre-configured with an + installed U-Boot, you can instead opt to delete the existing `FIRMWARE` + partition, which is used **only** for the Raspberry Pi family of + hardware. + ''; + }; + + firmwarePartitionID = mkOption { + type = types.str; + default = "0x2178694e"; + description = '' + Volume ID for the /boot/firmware partition on the SD card. This value + must be a 32-bit hexadecimal number. + ''; + }; + + firmwarePartitionName = mkOption { + type = types.str; + default = "FIRMWARE"; + description = '' + Name of the filesystem which holds the boot firmware. + ''; + }; + + rootPartitionUUID = mkOption { + type = types.nullOr types.str; + default = null; + example = "14e19a7b-0ae0-484d-9d54-43bd6fdc20c7"; + description = '' + UUID for the filesystem on the main NixOS partition on the SD card. + ''; + }; + + firmwareSize = mkOption { + type = types.int; + # As of 2019-08-18 the Raspberry pi firmware + u-boot takes ~18MiB + default = 30; + description = '' + Size of the /boot/firmware partition, in megabytes. + ''; + }; + + populateFirmwareCommands = mkOption { + example = literalExpression "'' cp \${pkgs.myBootLoader}/u-boot.bin firmware/ ''"; + description = '' + Shell commands to populate the ./firmware directory. + All files in that directory are copied to the + /boot/firmware partition on the SD image. + ''; + }; + + populateRootCommands = mkOption { + example = literalExpression "''\${config.boot.loader.generic-extlinux-compatible.populateCmd} -c \${config.system.build.toplevel} -d ./files/boot''"; + description = '' + Shell commands to populate the ./files directory. + All files in that directory are copied to the + root (/) partition on the SD image. Use this to + populate the ./files/boot (/boot) directory. + ''; + }; + + postBuildCommands = mkOption { + example = literalExpression "'' dd if=\${pkgs.myBootLoader}/SPL of=$img bs=1024 seek=1 conv=notrunc ''"; + default = ""; + description = '' + Shell commands to run after the image is built. + Can be used for boards requiring to dd u-boot SPL before actual partitions. + ''; + }; + + compressImage = mkOption { + type = types.bool; + default = true; + description = '' + Whether the SD image should be compressed using + {command}`zstd`. + ''; + }; + + expandOnBoot = mkOption { + type = types.bool; + default = true; + description = '' + Whether to configure the sd image to expand it's partition on boot. + ''; + }; + + nixPathRegistrationFile = mkOption { + type = types.str; + default = "/nix-path-registration"; + description = '' + Location of the file containing the input for nix-store --load-db once the machine has booted. + If overriding fileSystems."/" then you should to set this to the root mount + /nix-path-registration + ''; + }; + }; + + config = { + # hardware.enableAllHardware = true; + + fileSystems = { + "/boot/firmware" = { + device = "/dev/disk/by-label/${config.sdImage.firmwarePartitionName}"; + fsType = "vfat"; + # Alternatively, this could be removed from the configuration. + # The filesystem is not needed at runtime, it could be treated + # as an opaque blob instead of a discrete FAT32 filesystem. + options = [ + "nofail" + "noauto" + ]; + }; + "/" = { + device = "/dev/disk/by-label/NIXOS_SD"; + fsType = "ext4"; + }; + }; + + sdImage.storePaths = [ config.system.build.toplevel ]; + + image.extension = if config.sdImage.compressImage then "img.zst" else "img"; + image.filePath = "sd-card/${config.image.fileName}"; + system.nixos.tags = [ "sd-card" ]; + system.build.image = config.system.build.sdImage; + system.build.sdImage = pkgs.callPackage ( + { + stdenv, + dosfstools, + e2fsprogs, + mtools, + libfaketime, + util-linux, + zstd, + }: + stdenv.mkDerivation { + name = config.image.fileName; + + nativeBuildInputs = [ + dosfstools + e2fsprogs + libfaketime + mtools + util-linux + ] ++ lib.optional config.sdImage.compressImage zstd; + + inherit (config.sdImage) compressImage; + + buildCommand = '' + mkdir -p $out/nix-support $out/sd-image + export img=$out/sd-image/${config.image.baseName}.img + + echo "${pkgs.stdenv.buildPlatform.system}" > $out/nix-support/system + if test -n "$compressImage"; then + echo "file sd-image $img.zst" >> $out/nix-support/hydra-build-products + else + echo "file sd-image $img" >> $out/nix-support/hydra-build-products + fi + + root_fs=${rootfsImage} + + # Gap in front of the first partition, in MiB + gap=${toString config.sdImage.firmwarePartitionOffset} + + # Create the image file sized to fit /boot/firmware and /, plus slack for the gap. + rootSizeBlocks=$(du -B 512 --apparent-size $root_fs | awk '{ print $1 }') + firmwareSizeBlocks=$((${toString config.sdImage.firmwareSize} * 1024 * 1024 / 512)) + imageSize=$((rootSizeBlocks * 512 + firmwareSizeBlocks * 512 + gap * 1024 * 1024)) + truncate -s $imageSize $img + + # type=b is 'W95 FAT32', type=83 is 'Linux'. + # The "bootable" partition is where u-boot will look file for the bootloader + # information (dtbs, extlinux.conf file). + sfdisk --no-reread --no-tell-kernel $img <' + cp -r . $out + ''; + }; + + rkbin = pkgs.fetchgit { + url = "https://gitlab.collabora.com/hardware-enablement/rockchip-3588/rkbin.git"; + rev = "7c35e21a8529b3758d1f051d1a5dc62aae934b2b"; + sha256 = "03z9j7w6iaxxba0svgmdlkbk1k29swnfrc89ph5g40bmwvxqw698"; + }; + + ddrbin_tool_derivation = if ddrParamFile != null then pkgs.runCommand "custom-rk3588-tpl" { + nativeBuildInputs = [ pkgs.python3 ]; + inherit rkbin ddrParamFile; + } '' + mkdir -p $out/bin + echo "Running ddrbin_tool.py..." + echo "Using rkbin from: ${rkbin}" + echo "Using ddr_param.txt from: ${ddrParamFile}" + + cp ${ddrParamFile} ./ddrbin_param.txt + + echo "Attempting to run: python3 ${rkbin}/tools/ddrbin_tool.py rk3588 ./ddrbin_param.txt $out/bin/generated_ddr.bin" + python3 ${rkbin}/tools/ddrbin_tool.py rk3588 ./ddrbin_param.txt $out/bin/generated_ddr.bin + + if [ ! -f $out/bin/generated_ddr.bin ]; then + echo "ERROR: Custom TPL generation failed. generated_ddr.bin not found." + echo "Please check ddrbin_tool.py usage and adjust the script." + exit 1 + fi + echo "Custom TPL generated successfully: $out/bin/generated_ddr.bin" + '' else null; + + effectiveTplFile = + if customTplFile != null then customTplFile + else if ddrbin_tool_derivation != null then "${ddrbin_tool_derivation}/bin/generated_ddr.bin" + else "${rkbin}/bin/rk35/rk3588_ddr_lp4_2112MHz_lp5_2400MHz_v1.18.bin"; + + trusted-firmware-a = stdenv.mkDerivation rec { + pname = "trusted-firmware-a-rk3588"; + version = "main"; + src = pkgs.fetchgit { + url = "https://gitlab.collabora.com/hardware-enablement/rockchip-3588/trusted-firmware-a.git"; + rev = "ed0a82a67572db4ad2e0d8fa6651944d501e941f"; + sha256 = "1pg65zjg0rcc81bzl9mn50jsjr0pm4wib8mvncis49ca5ik39jh5"; + }; + nativeBuildInputs = [ pkgs.buildPackages.gcc pkgs.buildPackages.gnumake pkgs.buildPackages.python3 ]; + buildInputs = [ pkgs.gcc ]; + PLAT = "rk3588"; + buildPhase = '' + runHook preBuild + make PLAT=${PLAT} CC="gcc" AS="gcc -c" bl31 -j$(nproc) + runHook postBuild + ''; + installPhase = '' + runHook preInstall + mkdir -p $out/bin + cp build/${PLAT}/release/bl31/bl31.elf $out/bin/ + runHook postInstall + ''; + hardeningDisable = [ "all" ]; dontStrip = true; + meta = with pkgs.lib; { + description = "Trusted Firmware-A (BL31) for Rockchip RK3588"; + homepage = "https://www.trustedfirmware.org/"; + license = licenses.bsd3; + }; + }; + + uboot-rk3588 = stdenv.mkDerivation rec { + pname = "u-boot-rk3588"; + version = "custom-${builtins.substring 0 7 ubootGitRev}"; + + src = pkgs.fetchgit { + url = ubootGitUrl; + rev = ubootGitRev; + sha256 = ubootGitSha256; + }; + + nativeBuildInputs = [ + pkgs.buildPackages.gcc + pkgs.buildPackages.gnumake + pkgs.buildPackages.bison + pkgs.buildPackages.flex + pkgs.buildPackages.python3 + pkgs.python3Packages.setuptools + pkgs.python3Packages.pyelftools + pkgs.buildPackages.swig + pkgs.buildPackages.openssl + pkgs.gnutls + pkgs.ubootTools + pkgs.buildPackages.xxd + ]; + buildInputs = [ pkgs.gcc ]; + + ROCKCHIP_TPL = effectiveTplFile; + BL31 = "${trusted-firmware-a}/bin/bl31.elf"; + ARCH = "arm"; + + # ### FIXED: Define the new custom defconfig name ### + UBOOT_DEFCONFIG = ubootDefconfigName; + + postPatch = '' + patchShebangs . + + echo "--- Patching U-Boot with Radxa E52C device tree ---" + + local dts_files=( + "rk3582-radxa-e52c.dts" + "rk3588-base-pinctrl.dtsi" + "rk3588-extra-pinctrl.dtsi" + "rk3588.dtsi" + ) + + # FIXED: Copy files to the non-standard path this U-Boot fork expects. + local dts_dest_dir="dts/upstream/src/arm64/rockchip" + mkdir -p ''${dts_dest_dir} + + for f in "''${dts_files[@]}"; do + echo "Copying ''${f} to ''${dts_dest_dir}/''${f}" + cp -v "${kernel_src_unpacked}/arch/arm64/boot/dts/rockchip/''${f}" "''${dts_dest_dir}/''${f}" + done + + echo "--- Creating custom defconfig for Radxa E52C ---" + cp configs/evb-rk3588_defconfig configs/${UBOOT_DEFCONFIG} + + # Now modify the default device tree in our new defconfig. + # IMPORTANT: The path in CONFIG_DEFAULT_DEVICE_TREE must match the location where 'make' looks for the file. + sed -i 's|CONFIG_DEFAULT_DEVICE_TREE=.*|CONFIG_DEFAULT_DEVICE_TREE="rockchip/rk3582-radxa-e52c"|' \ + configs/${UBOOT_DEFCONFIG} + + echo "Custom defconfig created at configs/${UBOOT_DEFCONFIG}" + ''; + + configurePhase = '' + runHook preConfigure + # This now uses our newly created radxa_e52c_defconfig + make ARCH=${ARCH} CROSS_COMPILE="${stdenv.cc.targetPrefix}" ${UBOOT_DEFCONFIG} + if [ ! -f .config ]; then + echo "Error: .config was NOT created by 'make ${UBOOT_DEFCONFIG}'." + exit 1 + fi + echo ".config file found. Proceeding with modifications." + + set_kconfig() { + local key="$1" + local value="$2" + sed -i -e "/^''${key}=.*/d" -e "/^# ''${key} is not set/d" -e "/^#''${key}=.*/d" .config + echo "''${key}=''${value}" >> .config + } + enable_kconfig() { + set_kconfig "$1" "y" + } + + # --- Step 1: Create the default environment text file --- + cat > uboot-environment.txt <<'EOF' +bootdelay=2 +boot_targets=mmc1 mmc0 +bootcmd=run distro_bootcmd +fdt_addr_r=0x0a000000 +kernel_addr_r=0x0a200000 +ramdisk_addr_r=0x14000000 +pxefile_addr_r=0x0d000000 +scriptaddr=0x0d100000 +boot_extlinux=sysboot ''${devtype} ''${devnum}:''${dev_part} any ''${scriptaddr} ''${prefix}extlinux/extlinux.conf +scan_dev_for_boot=echo Scanning ''${devtype} ''${devnum}:''${dev_part}...; for prefix in / /boot/; do if test -e ''${devtype} ''${devnum}:''${dev_part} ''${prefix}extlinux/extlinux.conf; then echo Found ''${prefix}extlinux/extlinux.conf; run boot_extlinux; echo SCRIPT FAILED: continuing...; fi; done +scan_dev_for_boot_part=part list ''${devtype} ''${devnum} -bootable devplist; for dev_part in ''${devplist}; do if test ''${dev_part} = 1; then setenv dev_part 1; if sysboot ''${devtype} ''${devnum}:''${dev_part} any ''${scriptaddr} /boot/extlinux/extlinux.conf; then echo SCRIPT EXECUTED; fi; fi; done; setenv dev_part 1; run scan_dev_for_boot +mmc_boot=if mmc dev ''${devnum}; then setenv devtype mmc; run scan_dev_for_boot_part; fi +bootcmd_mmc0=setenv devnum 0; run mmc_boot +bootcmd_mmc1=setenv devnum 1; run mmc_boot +distro_bootcmd=for target in ''${boot_targets}; do run bootcmd_''${target}; done +EOF + + # --- Step 2: Set ALL remaining Kconfig options --- + echo "Configuring U-Boot to use the default environment file..." + enable_kconfig "CONFIG_USE_DEFAULT_ENV_FILE" + set_kconfig "CONFIG_DEFAULT_ENV_FILE" "\"uboot-environment.txt\"" + + # Since we created a custom defconfig, CONFIG_DEFAULT_DEVICE_TREE is already correct. + # We just need to align the OF_LIST and SPL_OF_LIST for binman and SPL. + set_kconfig "CONFIG_OF_LIST" "\"rockchip/rk3582-radxa-e52c\"" + set_kconfig "CONFIG_SPL_OF_LIST" "\"rockchip/rk3582-radxa-e52c\"" + + # Now we enable all the same features you had before. + # This ensures we don't lose any functionality. + enable_kconfig "CONFIG_DISTRO_DEFAULTS" + set_kconfig "CONFIG_BOOT_TARGET_DEVICES" "\"mmc1 mmc0\"" + enable_kconfig "CONFIG_CMD_FAT" + enable_kconfig "CONFIG_CMD_EXT4" + enable_kconfig "CONFIG_CMD_FS_GENERIC" + enable_kconfig "CONFIG_CMD_PART" + enable_kconfig "CONFIG_CMD_GPT" + enable_kconfig "CONFIG_CMD_EXTLINUX" + enable_kconfig "CONFIG_CMD_USB_MASS_STORAGE" + enable_kconfig "CONFIG_USB_GADGET" + enable_kconfig "CONFIG_BLK" + enable_kconfig "CONFIG_USB_DWC3" + enable_kconfig "CONFIG_USB_DWC3_GADGET" + enable_kconfig "CONFIG_USB_GADGET_DOWNLOAD" + enable_kconfig "CONFIG_USB_FUNCTION_MASS_STORAGE" + enable_kconfig "CONFIG_CMD_UMS" + enable_kconfig "CONFIG_MMC" + enable_kconfig "CONFIG_DM_MMC" + enable_kconfig "CONFIG_MMC_DW" + enable_kconfig "CONFIG_MMC_DW_ROCKCHIP" + enable_kconfig "CONFIG_CMD_MMC" + enable_kconfig "CONFIG_MMC_WRITE" + enable_kconfig "CONFIG_DOS_PARTITION" + enable_kconfig "CONFIG_FS_FAT" + enable_kconfig "CONFIG_MMC_HS200_SUPPORT" + enable_kconfig "CONFIG_SPL_LIBDISK_SUPPORT" + enable_kconfig "CONFIG_SPL_MMC_WRITE" + enable_kconfig "CONFIG_MMC_SDHCI" + enable_kconfig "CONFIG_MMC_SDHCI_SDMA" + enable_kconfig "CONFIG_MMC_SDHCI_ROCKCHIP" + set_kconfig "CONFIG_FASTBOOT_BUF_ADDR" "0x0a000000" + enable_kconfig "CONFIG_HUSH_PARSER" + enable_kconfig "CONFIG_CMD_MBR" + enable_kconfig "CONFIG_OF_LIBFDT_OVERLAY" + enable_kconfig "CONFIG_FS_EXT4" + enable_kconfig "CONFIG_AUTO_COMPLETE" + enable_kconfig "CONFIG_CMD_BOOTD" + enable_kconfig "CONFIG_CMD_EDITENV" + enable_kconfig "CONFIG_CMD_SCRIPT" + enable_kconfig "CONFIG_CMD_SETEXPR" + enable_kconfig "CONFIG_CMD_MEMTEST" + enable_kconfig "CONFIG_CMD_ECHO" + enable_kconfig "CONFIG_CMD_SOURCE" + enable_kconfig "CONFIG_CMD_NET" + enable_kconfig "CONFIG_CMD_PING" + enable_kconfig "CONFIG_CMD_DHCP" + + # --- Finalize the configuration --- + echo "Updating U-Boot configuration with all modifications (olddefconfig)..." + make ARCH=${ARCH} CROSS_COMPILE="${stdenv.cc.targetPrefix}" olddefconfig + + echo "Verifying final key settings in .config:" + grep -E \ + "^CONFIG_DEFAULT_DEVICE_TREE=\"rockchip/rk3582-radxa-e52c\"" \ + .config || echo "Warning: Custom DTB not set as expected." + runHook postConfigure + ''; + + # The postConfigure and preBuild phases are no longer needed + # for the old EVB-specific workarounds. + postConfigure = '' + echo "--- Final .config content (after olddefconfig) ---" + cat .config + echo "--- End of .config content ---" + ''; + + preBuild = '' + echo "Skipping preBuild patch for EVB." + ''; + + # buildPhase and installPhase are standard and remain unchanged. + buildPhase = '' + runHook preBuild + echo "Building U-Boot with ROCKCHIP_TPL=${ROCKCHIP_TPL} BL31=${BL31}" + make ARCH=${ARCH} CROSS_COMPILE="${stdenv.cc.targetPrefix}" -j$(nproc) + runHook postBuild + ''; + + installPhase = '' + runHook preInstall + mkdir -p $out/bin + cp idbloader.img $out/bin/ + cp u-boot.itb $out/bin/ + echo "Copied idbloader.img and u-boot.itb to $out/bin/" + runHook postInstall + ''; + + hardeningDisable = [ "all" ]; + dontStrip = true; + meta = with pkgs.lib; { + description = "U-Boot bootloader for Rockchip RK3588/RK3582 (Radxa E52C)"; + homepage = "https://www.denx.de/wiki/U-Boot"; + license = licenses.gpl2Plus; + }; + }; + +in +{ + inherit rkbin trusted-firmware-a uboot-rk3588 ddrbin_tool_derivation; + effectiveTplFile = effectiveTplFile; +} diff --git a/systems/aarch64-linux/stormjib-rockchip/uboot-disable-hdmi0-phy-ref.patch b/systems/aarch64-linux/stormjib-rockchip/uboot-disable-hdmi0-phy-ref.patch new file mode 100644 index 0000000..8f9b92b --- /dev/null +++ b/systems/aarch64-linux/stormjib-rockchip/uboot-disable-hdmi0-phy-ref.patch @@ -0,0 +1,12 @@ +--- a/dts/upstream/src/arm64/rockchip/rk3588-evb1-v10.dts ++++ b/dts/upstream/src/arm64/rockchip/rk3588-evb1-v10.dts +@@ -328,10 +328,6 @@ + }; + }; + +-&hdptxphy_hdmi0 { +- status = "okay"; +-}; +- + &i2c2 { + status = "okay"; diff --git a/systems/aarch64-linux/stormjib/default.nix b/systems/aarch64-linux/stormjib/default.nix index 947efdd..02e23f0 100644 --- a/systems/aarch64-linux/stormjib/default.nix +++ b/systems/aarch64-linux/stormjib/default.nix @@ -47,7 +47,7 @@ in }; projectinitiative = { - hosts.masthead.stormjib.enable = true; + hosts.masthead.stormjib.enable = false; networking = { tailscale = { enable = true; @@ -58,7 +58,7 @@ in }; }; system = { - console-info.ip-display.enable = true; + console-info.ip-display.enable = false; }; }; diff --git a/systems/x86_64-docker/devcontainer/default.nix b/systems/x86_64-docker/devcontainer/default.nix new file mode 100644 index 0000000..c0c5627 --- /dev/null +++ b/systems/x86_64-docker/devcontainer/default.nix @@ -0,0 +1,98 @@ +{ + lib, + pkgs, + inputs, + namespace, + system, + config, + options, + ... +}: +with lib; +with lib.${namespace}; +{ + imports = [ + # Include the docker hardware configuration + ./hardware-configuration.nix + ]; + + # Docker-specific settings + virtualisation.docker = { + enable = true; + autoPrune.enable = true; + }; + + # Nix garbage collection settings (similar to your ThinkPad) + nix = { + gc = { + automatic = true; + dates = "weekly"; + persistent = true; + options = "--delete-older-than 30d"; + }; + settings = { + auto-optimise-store = true; + }; + extraOptions = '' + min-free = ${toString (100 * 1024 * 1024)} + max-free = ${toString (512 * 1024 * 1024)} + ''; + }; + + home-manager.backupFileExtension = "backup"; + + # Adapting your projectinitiative settings for Docker + projectinitiative = { + # encrypted.nix-signing = enabled; + + # Only include headless services, removing GUI components + services = { + # Removed power-profile-manager as it's not needed in Docker + }; + + suites = { + development = enabled; + }; + + # Network configuration adapted for container + networking = { + tailscale = { + enable = false; + ephemeral = true; + extraArgs = [ "--accept-routes" ]; + }; + }; + }; + + # Enable basic networking + networking.networkmanager.enable = true; + + # Container-specific packages + environment.systemPackages = with pkgs; [ + # Development tools + ]; + + # Enable minimal services needed for development container + services = { + openssh = { + enable = true; + permitRootLogin = "no"; + passwordAuthentication = false; + }; + + # No need for printing, sound, display services in container + }; + + # Container users + users.users.developer = { + isNormalUser = true; + extraGroups = [ + "wheel" + "docker" + "networkmanager" + ]; + }; + + # Keep the stateVersion the same as your ThinkPad for compatibility + system.stateVersion = "24.05"; +} diff --git a/systems/x86_64-docker/devcontainer/hardware-configuration.nix b/systems/x86_64-docker/devcontainer/hardware-configuration.nix new file mode 100644 index 0000000..f6902d3 --- /dev/null +++ b/systems/x86_64-docker/devcontainer/hardware-configuration.nix @@ -0,0 +1,69 @@ +# Hardware configuration for Docker container +{ + config, + lib, + pkgs, + modulesPath, + ... +}: + +{ + imports = [ + (modulesPath + "/profiles/minimal.nix") + (modulesPath + "/profiles/docker.nix") + ]; + + # Container doesn't need most hardware-specific settings + boot = { + # Container doesn't need initrd and most boot settings + isContainer = true; + + # Keep emulation support for cross-compilation like in your ThinkPad + binfmt = { + emulatedSystems = [ + "aarch64-linux" + "armv7l-linux" + "armv6l-linux" + ]; + }; + }; + + # Simplified file systems for container + # fileSystems = { + # "/" = { + # device = "none"; + # fsType = "tmpfs"; + # options = [ "size=2G" "mode=755" ]; + # }; + + # # Mount points for persistent storage + # "/data" = { + # device = "data"; + # fsType = "none"; + # options = [ "bind" ]; + # }; + + # "/home" = { + # device = "home"; + # fsType = "none"; + # options = [ "bind" ]; + # }; + # }; + + # Container doesn't need swap + swapDevices = [ ]; + + # Network configuration simplified for container + networking = { + useDHCP = lib.mkDefault false; + # Use container networking + useHostResolvConf = true; + # Container hostname + hostName = "devcontainer"; + }; + + # Container doesn't need microcode updates + hardware = { + enableRedistributableFirmware = false; + }; +}