;; Guix system for the GL.iNet GL-MT6000 (Flint 2): MediaTek MT7986A, 1 GB ;; RAM, 8 GB eMMC, 2.5G WAN + 5 switch ports, MT7976 dual-band WiFi 6. ;; ;; Boot chain: BL2 (eMMC boot0) -> ATF + GL.iNet's stock U-Boot (`fip' ;; partition) -> the FIT image in the `kernel' partition (p6): kernel, DTB ;; carrying the Guix command line in /chosen/bootargs-append, initrd. GL's ;; U-Boot has no menu: deploying writes a new FIT, rolling back rewrites it. ;; Recovery: hold reset at power-on for GL's web failsafe. Root: ext4 ;; labelled "Guix" in the `rootfs' partition (p7). ;; See plans/guix-openwrt-mt6000-plan.md. ;; ;; Network (as OpenWrt's board config): ;; WAN eth1 2.5G port, DHCP (netifd) ;; LAN br-lan lan1-lan5 (MT7531 DSA ports) + WiFi APs, 192.168.1.1/24, ;; dnsmasq DHCPv4/DNS, odhcpd RA/DHCPv6 ;; firewall4, LuCI, the OpenWrt userland as on the Pi (rpi4.scm). ;; ;; Load with GUIX_PACKAGE_PATH pointing at this directory's packages/. ;; Must come first: makes every cross build use a glibc whose system()/popen() ;; run /bin/sh, not the build host's bash (packages/cross-libc-fix.scm). (use-modules (cross-libc-fix)) (use-modules (gnu) (gnu bootloader u-boot) (guix packages) (guix utils) ((guix config) #:select (%guix-version)) (nongnu packages linux) (nonguix licenses) (mt6000-linux) (wireless-regdb-signed) (openwrt) (openwrt-services) (router-base) (tollgate-services)) (use-service-modules avahi networking shepherd ssh sysctl) (use-package-modules admin base bash linux networking) (define %mt6000-linux-firmware ;; linux-firmware subset: the MT7986's WiFi (mt7915e: WM/WA/ROM patch, ;; fallback EEPROMs) and WED offload (WO) firmware. (package (inherit linux-firmware) (name "linux-firmware-mt7986") (arguments (substitute-keyword-arguments (package-arguments linux-firmware) ((#:phases phases #~%standard-phases) #~(modify-phases #$phases (add-after 'unpack 'select-firmware (lambda _ (use-modules (ice-9 regex)) (define (wanted? path) (string-match "^\"?mediatek/mt7986_" path)) (substitute* "WHENCE" (("^(File|RawFile|Link|Symlink): *(.*)" _ type rest) (string-append (if (wanted? rest) type "Skip") ": " rest))))))))) (synopsis "MT7986 WiFi and WED firmware") (description "Subset of the linux-firmware package with the MT7986 firmware: the mt7915e driver's WiFi microcode and WED (Wireless Ethernet Dispatch) offload firmware.") (license (nonfree "https://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git/plain/WHENCE")))) (define gl-u-boot-bootloader ;; Nothing to install: GL's U-Boot stays as it is and boots the FIT that ;; the deploy script writes to the `kernel' partition. (The extlinux.conf ;; Guix generates is unused.) (bootloader (inherit u-boot-bootloader) (name 'gl-u-boot) (package #f) (installer #f) (disk-image-installer #f))) ;; /etc/board-base.json, as OpenWrt's board_detect writes it; wifi-setup adds ;; the radios (wlan) into /tmp/sysinfo/board.json = /etc/board.json. (define %board-base.json (plain-file "board-base.json" "\ { \"model\": { \"id\": \"glinet,gl-mt6000\", \"name\": \"GL.iNet GL-MT6000\" }, \"network\": { \"lan\": { \"ports\": [ \"lan1\", \"lan2\", \"lan3\", \"lan4\", \"lan5\" ], \"protocol\": \"static\" }, \"wan\": { \"device\": \"eth1\", \"protocol\": \"dhcp\" } } } ")) ;; After `wifi config' on first boot: WPA2 APs named guix-router on both ;; radios (radio0 2.4 GHz, radio1 5 GHz), in br-lan, with one random key -- ;; read it with `uci get wireless.default_radio0.key'. mt7915 does ACS, so ;; the channels `wifi config' chose stay. (define %wifi-first-config (plain-file "wifi-first-config" "\ key=$(od -An -tx1 -N12 /dev/urandom | tr -d ' \\n') for r in 0 1; do uci -q batch < /proc/irq/$irq/smp_affinity cpu=$((cpu + 1)) done for d in eth0 eth1; do echo b > /sys/class/net/$d/queues/rx-0/rps_cpus; done")))))))) (define %serial-console "ttyS0") (define %mt6000-os (operating-system (host-name "mt6000") (timezone "Etc/UTC") (locale "en_US.utf8") (bootloader (bootloader-configuration (bootloader gl-u-boot-bootloader) (targets '()))) (kernel linux-mt6000) (firmware (list %mt6000-linux-firmware wireless-regdb-signed)) ;; eMMC, its clocks, the serial console and ramoops (the kernel log ;; across resets, in /sys/fs/pstore) are built into linux-mt6000. (initrd-modules '()) ;; Headless: an initrd error must not wait at a REPL on the serial ;; console. It panics instead, and panic=10 reboots -- into GL U-Boot's ;; TFTP recovery window again. (initrd (lambda (file-systems . rest) (apply base-initrd file-systems #:on-error 'backtrace rest))) (kernel-arguments (list (string-append "console=" %serial-console ",115200") "panic=10" ;; mtk_eth_soc is a module, loaded long after the kernel turns ;; off the clocks nobody has claimed; without this its MDIO bus ;; times out ("mdio: MDIO timeout") and Ethernet never probes. ;; (OpenWrt builds the driver in.) "clk_ignore_unused")) (file-systems (cons* (file-system (mount-point "/") (device (file-system-label "Guix")) (type "ext4")) %base-file-systems)) (swap-devices '()) (users (cons* %router-root-account %base-user-accounts)) (packages (append (list usbutils iw ethtool ucode jsonfilter) %base-packages)) (services (cons* ;; No RTC: start from the last known time, not 1970. First, ;; so its activation runs before the others. (service sysfixtime-service-type) (service agetty-service-type (agetty-configuration (tty %serial-console) (term "vt100") (baud-rate "115200"))) (service avahi-service-type) (service netifd-service-type (netifd-configuration (resolv-conf "/etc/resolv.conf"))) (service openwrt-wireless-service-type (openwrt-wireless-configuration (board-base %board-base.json) (first-config %wifi-first-config))) (service openwrt-dnsmasq-service-type (openwrt-dnsmasq-configuration (dnsmasq dnsmasq/cross-fixed))) (service firewall-service-type) (simple-service 'router-sysctl sysctl-service-type %router-sysctls) (service ubus-service-type) (service procd-compat-service-type (procd-compat-configuration (release `(("distribution" . "Guix System") ("version" . ,%guix-version) ("target" . "mediatek/filogic") ("description" . "Guix System, OpenWrt userland"))))) (service uci-service-type (uci-configuration (seeds `(("system" ,(local-file "files/uci-mt6000/system")) ("network" ,(local-file "files/uci-mt6000/network")) ("dhcp" ,(local-file "files/uci-mt6000/dhcp")) ("firewall" ,(local-file "files/uci-mt6000/firewall")))) (defaults `(("12_network-generate-ula" ,(file-append %openwrt-tree "/package/base-files/files/etc/" "uci-defaults/12_network-generate-ula")))) ;; After TollGate's 99-tollgate-setup (a late default ;; too): wired ports into its private network, no ;; admin services on the open SSID's br-lan. (late-defaults `(("99_zz-wired-private" ,(local-file "files/uci-mt6000/99_zz-wired-private")))))) (service odhcpd-service-type) (service uhttpd-service-type) (service luci-service-type) (service nodogsplash-service-type) ;; TollGate (Cashu/Nostr paid access through nodogsplash). ;; Its first-boot setup (99-tollgate-setup) makes both radios ;; an open TollGate-XXXX AP on br-lan, adds a private WPA2 ;; network (br-private), moves uhttpd to :8080 and opens tcp ;; 2121. Wallet and identity in /etc/tollgate (state, not in ;; the store). (service tollgate-service-type) %resize-root-service %packet-steering-service %chrony-accounts %chrony-service ;; Keys only: the open TollGate SSID shares br-lan with sshd, ;; so anyone nearby can reach it. (LuCI still takes the root ;; password: set a strong one with `passwd' on the router.) (service openssh-service-type (openssh-configuration (permit-root-login 'prohibit-password) (password-authentication? #f) (authorized-keys `(("root" ,(local-file "files/workstation.pub")))))) (modify-services %base-services (delete console-font-service-type) ;; Accept store items signed by the build workstation, for ;; `guix copy' deploys. (guix-service-type config => (guix-configuration (inherit config) (authorized-keys (cons (local-file "files/workstation-guix.pub") %default-authorized-guix-keys))))))))) %mt6000-os