2
0

1 Commits

Author SHA1 Message Date
dan e8e0de0284 make tftpboot work on devices with old u-boot
Some devices have a U-boot variant that does not accept a third
parameter on the "bootm" command, meaning we can't override the dtb
in the bootloader so have to smush it back into the kernel image

This is WIP because
- still hardcodes MIPS
- doesn't work in QEMU

Based on
https://gti.telent.net/raboof/liminix/src/branch/tftp-old-uboot

Co-authored-by:  Arnout Engelen <arnout@bzzt.net>
2024-02-15 20:12:03 +00:00
1744 changed files with 4403 additions and 19584 deletions
+3 -92
View File
@@ -34,17 +34,13 @@ Upstream changes that have led to incompatible Liminix changes are:
2024-01-30
New port! Thanks to Arnout Engelen <arnout@bzzt.net>, Liminix
now runs on the TP-Link Archer AX23.
now runs on the TP-Link Archer AX23
2024-02-12
* We now build wifi drivers (mac80211) from the same kernel source as
* we now build wifi drivers (mac80211) from the same kernel source as
the running kernel, instead of using drivers from the linux-backports
project. This may be a regression on some devices that depend on
OpenWrt patches for wireless functionality: if you have a device that
used to work and now doesn't, refer to OpenWrt
package/kernel/mac80211/patches/ to see if there's something in there
that needs to be applied.
project.
* in general, we build kernel modules (e.g. for nftables) at the same
time as the kernel itself instead of expecting to be able to build
@@ -72,88 +68,3 @@ the old location to the new one before rebooting into the new system
The `output`, `mkoutputs` functions defined by ${serviceFns}
have been updated for the new location.
2024-02-16
New (or at least, previously unreported) port! Liminix now runs on the
Turris Omnia and has been serving my family's internet needs for most
of this week. Thanks to NGI0 Entrust and the NLnet Foundation for
sponsoring this development (and funding the hardware)
2024-02-21
New port! Thanks to Raito Bezarius, Liminix now runs on the Zyxel NWA50AX,
an MT7621 (MIPS EL) dual radio WiFi AP.
2024-04-29
The setup for using `levitate` has changed: now it accepts an entire
config fragment, not just a list of services. Hopefully this makes it
a bit more useful :-)
defaultProfile.packages = with pkgs; [
...
(levitate.override {
config = {
services = {
inherit (config.services) dhcpc sshd watchdog;
};
defaultProfile.packages = [ mtdutils ];
users.root.openssh.authorizedKeys.keys = secrets.root.keys;
};
})
];
2024-07-16
* structured parameters are available for the pppoe service
* The "wan" configuration in modules/profiles/gateway.nix has changed:
instead of passing options that are used to create a pppoe interface,
callers should create a (pppoe or other) interface and pass that as
the value of profile.gateway.wan. For the pppoe case this is now only
very slightly more verbose, and it allows using the gateway profile
with other kinds of upstream.
2024-8-16
As part of implementing log shipping, the default directory for system
logs has beenchanged from /run/uncaught-logs to /run/log
2024-10-09
liminix-rebuild is being deprecated. From hereon in, the preferred way
to do an incremental update on an installed device with a writable
filesystem is to build the systemConfiguration output
nix-build -I liminix-config=hosts/myhost.nix --argstr deviceName turris-omnia -A outputs.systemConfiguration
and then run the generated `install.sh` script
result/install.sh root@192.168.8.1
2024-12-16
Config options changed: if you had set config.hardware.dts.includes
(maybe in an out-of-tree device port) to specify the search paths
in which dtc finds include files, you will need to change this to
hardware.dts.includePaths.
The "new" hardware.dts.includes option is now for dtsi files which
should be merged into the device tree.
2024-12-19
Incremental updates changed again (but not massively). From hereon in,
the preferred way to do an incremental update on an installed device
with a writable filesystem is to build the updater output
nix-build -I liminix-config=hosts/myhost.nix --argstr deviceName turris-omnia -A outputs.updater
and then run the generated `update.sh` script. See
https://www.liminix.org/doc/admin.html#updating-an-installed-system
2024-12-22
outputs.zimage is now outputs.kernel.zImage. This is unlikely to
affect many people at all but I mention it anyway.
-3119
View File
File diff suppressed because it is too large Load Diff
-42
View File
@@ -1,42 +0,0 @@
# This is for use with minicom, but needs you to configure it to
# use expect as its "Script program" instead of runscript. Try
# Ctrl+A O -> Filenames and paths -> D
fconfigure stderr -buffering none
fconfigure stdout -buffering none
proc waitprompt { } {
expect {
"BusyBox" { puts stderr "DONE\r"; exit 0 }
"READY" { puts stderr ";;; READY\r"; }
timeout { puts stderr ";;; timed out waiting after $line\r" }
}
}
proc sendline { line } {
send "$line; echo \$ready \r"
sleep 0.1
}
log_user 0
log_file -a -open stderr
set f [open "result/boot.scr"]
send "setenv ready REA\r"
sleep 0.1
send "setenv ready \${ready}DY\r"
sleep 0.1
set timeout 300
expect_before timeout abort
while {[gets $f line] >= 0} {
puts stderr ";;; next line $line\r"
puts stderr ";;; waiting for prompt\r"
puts stderr ";;; sending\r"
sendline $line
waitprompt
}
puts stderr "done\r\n"
close $f
+32 -110
View File
@@ -1,26 +1,9 @@
{
config,
pkgs,
lib,
...
}:
{ config, pkgs, lib, ... }:
let
cfg = config.bordervm;
inherit (lib)
mkOption
mkEnableOption
mdDoc
types
optional
optionals
;
in
{
inherit (lib) mkOption mkEnableOption mdDoc types optional optionals;
in {
options.bordervm = {
keys = mkOption {
type = types.listOf types.str;
default = [ ];
};
l2tp = {
host = mkOption {
description = mdDoc ''
@@ -68,17 +51,18 @@ in
<nixpkgs/nixos/modules/virtualisation/qemu-vm.nix>
];
config = {
boot.kernelParams = [ "loglevel=9" ];
boot.kernelParams = [
"loglevel=9"
];
systemd.services.pppoe =
let
conf = pkgs.writeText "kpppoed.toml" ''
interface_name = "eth1"
services = [ "myservice" ]
lns_ipaddr = "${cfg.l2tp.host}:${builtins.toString cfg.l2tp.port}"
ac_name = "kpppoed-1.0"
'';
in
{
let conf = pkgs.writeText "kpppoed.toml"
''
interface_name = "eth1"
services = [ "myservice" ]
lns_ipaddr = "${cfg.l2tp.host}:${builtins.toString cfg.l2tp.port}"
ac_name = "kpppoed-1.0"
'';
in {
wantedBy = [ "multi-user.target" ];
after = [ "network-online.target" ];
serviceConfig = {
@@ -92,114 +76,52 @@ in
};
};
services.openssh.enable = true;
services.dnsmasq = {
enable = true;
resolveLocalQueries = false;
settings = {
# domain-needed = true;
dhcp-range = [ "10.0.0.10,10.0.0.240" ];
interface = "eth1";
};
};
services.nginx = {
enable = true;
user = "liminix";
virtualHosts.${config.networking.hostName} = {
root = "/home/liminix";
default = true;
};
};
systemd.services.nginx.serviceConfig.ProtectHome = "read-only";
systemd.services.sshd.wantedBy = pkgs.lib.mkForce [ "multi-user.target" ];
virtualisation = {
forwardPorts = [
{
from = "host";
host.port = 7654;
# guest.address = "10.0.2.15";
guest.port = 7654;
}
{
host.port = 2222;
guest.address = "10.0.2.15";
guest.port = 22;
}
];
qemu = {
networkingOptions = [ ];
options =
[ ]
++ optional cfg.ethernet.pci.enable "-device vfio-pci,host=${cfg.ethernet.pci.id}"
++ optionals cfg.ethernet.usb.enable [
networkingOptions = [];
options = [] ++
optional cfg.ethernet.pci.enable
"-device vfio-pci,host=${cfg.ethernet.pci.id}" ++
optionals cfg.ethernet.usb.enable [
"-device usb-ehci,id=ehci"
"-device usb-host,bus=ehci.0,vendorid=${cfg.ethernet.usb.vendor},productid=${cfg.ethernet.usb.product}"
]
++ [
] ++ [
"-nographic"
"-serial mon:stdio"
];
};
sharedDirectories = {
liminix = {
securityModel = "none";
source = builtins.toString ./.;
target = "/home/liminix/liminix";
};
};
};
services.tang = {
enable = true;
ipAddressAllow = [
"10.0.0.0/24"
"0.0.0.0/0"
];
};
environment.systemPackages =
let
wireshark-nogui = pkgs.wireshark.override { withQt = false; };
in
with pkgs;
[
tcpdump
wireshark-nogui
socat
tufted
iptables
usbutils
busybox
clevis
];
let wireshark-nogui = pkgs.wireshark.override { withQt = false ; };
in with pkgs; [
tcpdump
wireshark-nogui
socat
tufted
iptables
usbutils
];
security.sudo.wheelNeedsPassword = false;
networking = {
hostName = "border";
firewall = {
enable = false;
};
firewall = { enable = false; };
interfaces.eth1 = {
useDHCP = false;
ipv4.addresses = [
{
address = "10.0.0.1";
prefixLength = 24;
}
];
};
nat = {
enable = true;
internalInterfaces = [ "eth1" ];
externalInterface = "eth0";
ipv4.addresses = [ { address = "10.0.0.1"; prefixLength = 24;}];
};
};
users.users.liminix = {
isNormalUser = true;
uid = 1000;
extraGroups = [ "wheel" ];
openssh.authorizedKeys.keys = cfg.keys;
extraGroups = [ "wheel"];
};
services.getty.autologinUser = "liminix";
};
+2 -6
View File
@@ -1,12 +1,8 @@
{ ... }:
{...}:
{
bordervm = {
# ethernet.pci = { id = "01:00.0"; enable = true; };
ethernet.usb = {
vendor = "0x0bda";
product = "0x8153";
enable = true;
};
ethernet.usb = { vendor = "0x0bda"; product = "0x8153"; enable = true; };
l2tp = {
host = "l2tp.aa.net.uk";
};
+45 -52
View File
@@ -1,84 +1,77 @@
{
nixpkgs
, unstable
, liminix
, ... }:
let
pkgs = import <nixpkgs> { };
liminix = <liminix>;
borderVmConf = ./bordervm.conf-example.nix;
inherit (builtins) map;
pkgs = (import nixpkgs {});
borderVmConf = ./bordervm.conf-example.nix;
inherit (pkgs.lib.attrsets) genAttrs;
devices = [
"gl-ar750"
"gl-mt300a"
"gl-mt300n-v2"
"qemu"
"qemu-aarch64"
"qemu-armv7l"
"gl-ar750" "gl-mt300n-v2" "gl-mt300a"
"qemu" "qemu-aarch64" "qemu-armv7l"
"tp-archer-ax23"
"openwrt-one"
"zyxel-nwa50ax"
"turris-omnia"
"belkin-rt3200"
];
vanilla = ./vanilla-configuration.nix;
for-device =
name:
for-device = name:
(import liminix {
inherit borderVmConf;
inherit nixpkgs borderVmConf;
device = import (liminix + "/devices/${name}");
liminix-config = vanilla;
}).outputs.default;
tests = import ./tests/ci.nix;
jobs =
(genAttrs devices for-device)
// tests
// {
buildEnv =
(import liminix {
inherit borderVmConf;
device = import (liminix + "/devices/qemu");
liminix-config = vanilla;
}).buildEnv;
(genAttrs devices for-device) //
tests //
{
buildEnv = (import liminix {
inherit nixpkgs borderVmConf;
device = import (liminix + "/devices/qemu");
liminix-config = vanilla;
}).buildEnv;
doc =
let
json =
(import liminix {
inherit borderVmConf;
device = import (liminix + "/devices/qemu");
liminix-config =
{ ... }:
{
let json =
(import liminix {
inherit nixpkgs borderVmConf;
device = import (liminix + "/devices/qemu");
liminix-config = {...} : {
imports = [ ./modules/all-modules.nix ];
};
}).outputs.optionsJson;
in
pkgs.stdenv.mkDerivation {
}).outputs.optionsJson;
installers = map (f: "system.outputs.${f}") [
"vmroot"
"mtdimage"
"ubimage"
];
inherit (pkgs.lib) concatStringsSep;
in pkgs.stdenv.mkDerivation {
name = "liminix-doc";
nativeBuildInputs = with pkgs; [
gnumake
sphinx
fennel
luaPackages.lyaml
gnumake sphinx fennel luaPackages.lyaml
];
src = ./.;
buildPhase = ''
cat ${json} | fennel --correlate doc/parse-options.fnl > doc/modules-generated.inc.rst
cat ${json} | fennel --correlate doc/parse-options-outputs.fnl > doc/outputs-generated.inc.rst
cat ${json} | fennel --correlate doc/parse-options.fnl > doc/modules-generated.rst
cat ${json} | fennel --correlate doc/parse-options-outputs.fnl > doc/outputs-generated.rst
cp ${(import ./doc/hardware.nix)} doc/hardware.rst
make -C doc html
'';
installPhase = ''
mkdir -p $out/nix-support $out/share/doc/
cd doc
cp *-generated.inc.rst hardware.rst $out
cp *-generated.rst $out
ln -s ${json} $out/options.json
cp -a _build/html $out/share/doc/liminix
echo "file source-dist \"$out/share/doc/liminix\"" \
> $out/nix-support/hydra-build-products
'';
};
};
with-unstable = (import liminix {
nixpkgs = unstable;
inherit borderVmConf;
device = import (liminix + "/devices/qemu");
liminix-config = vanilla;
}).outputs.default;
};
in
jobs
// {
all = pkgs.mkShell {
name = "all tests";
contents = pkgs.lib.collect pkgs.lib.isDerivation jobs;
};
}
in jobs
+29 -59
View File
@@ -1,85 +1,56 @@
{
deviceName ? null,
device ? (import ./devices/${deviceName}),
liminix-config ? <liminix-config>,
borderVmConf ? ./bordervm.conf.nix,
imageType ? "primary",
device
, liminix-config ? <liminix-config>
, nixpkgs ? <nixpkgs>
, borderVmConf ? ./bordervm.conf.nix
}:
let
overlay = import ./overlay.nix;
pkgs = import <nixpkgs> (
device.system
// {
overlays = [ overlay ];
config = {
allowUnsupportedSystem = true; # mipsel
permittedInsecurePackages = [
"python-2.7.18.6" # kernel backports needs python <3
"python-2.7.18.7"
];
};
}
);
pkgs = import nixpkgs (device.system // {
overlays = [overlay];
config = {
allowUnsupportedSystem = true; # mipsel
permittedInsecurePackages = [
"python-2.7.18.6" # kernel backports needs python <3
"python-2.7.18.7"
];
};
});
eval = pkgs.lib.evalModules {
specialArgs = {
modulesPath = builtins.toString ./modules;
};
modules = [
{
_module.args = {
inherit pkgs;
inherit (pkgs) lim;
};
}
{ _module.args = { inherit pkgs; inherit (pkgs) lim; }; }
./modules/hardware.nix
./modules/base.nix
./modules/busybox.nix
./modules/hostname.nix
./modules/kernel
./modules/logging.nix
./modules/klogd.nix
device.module
liminix-config
./modules/s6
./modules/users.nix
./modules/outputs.nix
{
boot.imageType = imageType;
}
];
};
config = eval.config;
borderVm =
((import <nixpkgs/nixos/lib/eval-config.nix>) {
system = builtins.currentSystem;
modules = [
{
nixpkgs.overlays = [
(final: prev: {
go-l2tp = final.callPackage ./pkgs/go-l2tp { };
tufted = final.callPackage ./pkgs/tufted { };
})
];
}
(import ./bordervm-configuration.nix)
borderVmConf
];
}).config.system;
in
{
borderVm = ((import <nixpkgs/nixos/lib/eval-config.nix>) {
system = builtins.currentSystem;
modules = [
({ ... } : { nixpkgs.overlays = [ overlay ]; })
(import ./bordervm-configuration.nix)
borderVmConf
];
}).config.system;
in {
outputs = config.system.outputs // {
default = config.system.outputs.${config.hardware.defaultOutput};
optionsJson =
let
o = import ./doc/extract-options.nix {
inherit pkgs eval;
lib = pkgs.lib;
};
in
pkgs.writeText "options.json" (builtins.toJSON o);
let o = import ./doc/extract-options.nix {
inherit pkgs eval;
lib = pkgs.lib;
};
in pkgs.writeText "options.json" (builtins.toJSON o);
};
# this is just here as a convenience, so that we can get a
@@ -97,7 +68,6 @@ in
min-copy-closure
fennelrepl
lzma
lua
];
};
}
+187 -281
View File
@@ -4,8 +4,15 @@
******************************
This device is based on a 64 bit Mediatek MT7622 ARM platform,
and is mostly feature-complete in Liminix but as of Dec 2024
has seen very little actual use.
and is "work in progress" in Liminix.
.. note:: The factory flash image contains ECC errors that make it
incompatible with Liminix: you need to use the `OpenWrt
UBI Installer <https://github.com/dangowrt/owrt-ubi-installer>`_ to
rewrite the partition layout before you can flash
Liminix onto it (or even use it with
:ref:`system-outputs-tftpboot`, if you want the wireless
to work).
Hardware summary
================
@@ -20,94 +27,10 @@
Installation
============
Liminix on this device uses the UBI volume management system to
perform wear leveling on the flash. This is not set up from the
factory, so a one-time step is needed to prepare it before Liminix
can be installed.
Installation is currently a manual process (you need a :ref:`serial <serial>` conection and
TFTP) following the instructions at :ref:`system-outputs-ubimage`
Preparation
-----------
To prepare the device for Liminix you first need to use the
`OpenWrt UBI Installer
<https://github.com/dangowrt/owrt-ubi-installer>`_ image to
rewrite the flash layout. As of Jan 2025 there are two versions
of the installer available: the release version 1.0.2 and the
pre-release 1.1.3 and for Liminix you nee the pre-relese.
The release version of the installer creates UBI volumes
according to an older layout that is not compatible with
the Linux 6.6.67 kernel used in Liminix.
You can run the installer in one of two ways:
either follow the instructions to do it through the vendor web
interface, or you can drop to U-Boot and use TFTP
.. code-block:: console
MT7622> setenv ipaddr 10.0.0.6
MT7622> setenv serverip 10.0.0.1
MT7622> tftpboot 0x42000000 openwrt-mediatek-mt7622-linksys_e8450-ubi-initramfs-recovery-installer.itb
MT7622> bootm 0x42000000
This will write the new flash layout and then boot into a
"recovery" OpenWrt installation.
Building/installing Liminix
----------------
The default target for this device is ``outputs.ubimage`` which
makes a ubifs image suitable for use with :command:`ubiupdatevol`.
To write this to the device we use the OpenWrt recovery system
installed in the previous step. In this configuration the
device assigns itself the IP address 192.168.1.1/24 on its LAN
ports and expects the connected computer to have 192.168.1.254
.. warning:: The `ubi0_7` device in these instructions is correct
as of Dec 2024 (dangowrt/owrt-ubi-installer commit
d79e7928). If you are installing some time later, it
is important to check the output from
:command:`ubinfo -a` and make sure you are updating
the "liminix" volume and not some other one which had
been introduced since I wrote this.
.. code-block:: console
$ nix-build -I liminix-config=./my-configuration.nix --arg device "import ./devices/belkin-rt3200" -A outputs.default
$ cat result/rootfs | ssh root@192.168.1.1 "cat > /tmp/rootfs"
$ ssh root@192.168.1.1
root@OpenWrt:~# ubimkvol /dev/ubi0 --name=liminix --maxavsize
root@OpenWrt:~# ubinfo -a
[...]
Volume ID: 7 (on ubi0)
Type: dynamic
Alignment: 1
Size: 851 LEBs (108056576 bytes, 103.0 MiB)
State: OK
Name: liminix
Character device major/minor: 250:8
root@OpenWrt:~# ubiupdatevol /dev/ubi0_7 /tmp/rootfs
To make the new system bootable we also need to change some U-Boot variables.
``boot_production`` needs to mount the filesystem and boot the FIT image
found there, and :code:`bootcmd` needs to be told _not_ to boot the rescue
image if there are records in pstore, because that interferes with
``config.log.persistent``
.. code-block:: console
root@OpenWrt:~# fw_setenv orig_boot_production $(fw_printenv -n boot_production)
root@OpenWrt:~# fw_setenv orig_bootcmd $(fw_printenv -n bootcmd)
root@OpenWrt:~# fw_setenv boot_production 'led $bootled_pwr on ; ubifsmount ubi0:liminix && ubifsload ''${loadaddr} boot/fit && bootm ''${loadaddr}'
root@OpenWrt:~# fw_setenv bootcmd 'run boot_ubi'
For subsequent Liminix reinstalls, just run the
:command:`ubiupdatevol` command again. You don't need to repeat
the "Preparation" step and in fact should seek to avoid it if
possible, as it will reset the erase counters used for write
levelling. Using UBI-aware tools is therefore preferred over any
kind of "factory" wipe which will reset them.
'';
'';
system = {
crossSystem = {
@@ -115,218 +38,201 @@
};
};
module =
{
pkgs,
config,
lib,
lim,
...
}:
let
inherit (lib) mkIf;
firmware = pkgs.stdenv.mkDerivation {
name = "wlan-firmware";
phases = [ "installPhase" ];
installPhase = ''
mkdir $out
cp ${pkgs.linux-firmware}/lib/firmware/mediatek/{mt7915,mt7615,mt7622}* $out
'';
};
openwrt = pkgs.openwrt_24_10;
in
{
module = {pkgs, config, lib, lim, ... }:
let firmware = pkgs.stdenv.mkDerivation {
name = "wlan-firmware";
phases = ["installPhase"];
installPhase = ''
mkdir $out
cp ${pkgs.linux-firmware}/lib/firmware/mediatek/{mt7915,mt7615,mt7622}* $out
'';
};
in {
imports = [
../../modules/arch/aarch64.nix
../../modules/outputs/tftpboot.nix
../../modules/outputs/ubifs.nix
];
config = {
kernel = {
extraPatchPhase = ''
${openwrt.applyPatches.mediatek}
'';
src = openwrt.kernelSrc;
version = openwrt.kernelVersion;
config = {
PCI = "y";
ARCH_MEDIATEK = "y";
# ARM_MEDIATEK_CPUFREQ = "y";
kernel = {
src = pkgs.pkgsBuildBuild.fetchurl {
name = "linux.tar.gz";
url = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.137.tar.gz";
hash = "sha256-PkdzUKZ0IpBiWe/RS70J76JKnBFzRblWcKlaIFNxnHQ=";
};
extraPatchPhase = ''
${pkgs.openwrt.applyPatches.mediatek}
'';
config = {
PCI = "y";
ARCH_MEDIATEK = "y";
# ARM_MEDIATEK_CPUFREQ = "y";
# needed for "Cannot find regmap for /infracfg@10000000"
MFD_SYSCON = "y";
MTK_INFRACFG = "y";
# needed for "Cannot find regmap for /infracfg@10000000"
MFD_SYSCON = "y";
MTK_INFRACFG = "y";
MTK_PMIC_WRAP = "y";
DMADEVICES = "y";
MTK_HSDMA = "y";
MTK_SCPSYS = "y";
MTK_SCPSYS_PM_DOMAINS = "y";
# MTK_THERMAL="y";
MTK_TIMER = "y";
MTK_PMIC_WRAP = "y";
MTK_EFUSE="y";
# MTK_HSDMA="y";
MTK_SCPSYS="y";
MTK_SCPSYS_PM_DOMAINS="y";
# MTK_THERMAL="y";
MTK_TIMER="y";
COMMON_CLK_MT7622 = "y";
COMMON_CLK_MT7622_ETHSYS = "y";
COMMON_CLK_MT7622_HIFSYS = "y";
COMMON_CLK_MT7622_AUDSYS = "y";
PM_CLK = "y";
COMMON_CLK_MT7622 = "y";
COMMON_CLK_MT7622_ETHSYS = "y";
COMMON_CLK_MT7622_HIFSYS = "y";
COMMON_CLK_MT7622_AUDSYS = "y";
PM_CLK="y";
REGMAP_MMIO = "y";
CLKSRC_MMIO = "y";
REGMAP = "y";
REGMAP_MMIO = "y";
CLKSRC_MMIO = "y";
REGMAP = "y";
MEDIATEK_GE_PHY = "y";
# MEDIATEK_MT6577_AUXADC = "y";
NET_MEDIATEK_SOC = "y";
NET_MEDIATEK_SOC_WED = "y";
NET_MEDIATEK_STAR_EMAC = "y"; # this enables REGMAP_MMIO
NET_VENDOR_MEDIATEK = "y";
PCIE_MEDIATEK = "y";
MEDIATEK_GE_PHY = "y";
# MEDIATEK_MT6577_AUXADC = "y";
# MEDIATEK_WATCHDOG = "y";
NET_MEDIATEK_SOC = "y";
NET_MEDIATEK_SOC_WED = "y";
NET_MEDIATEK_STAR_EMAC = "y"; # this enables REGMAP_MMIO
NET_VENDOR_MEDIATEK = "y";
PCIE_MEDIATEK = "y";
BLOCK = "y"; # move this to base option
BLOCK = "y"; # move this to base option
SPI_MASTER = "y";
SPI = "y";
SPI_MEM = "y";
SPI_MTK_NOR = "y";
SPI_MTK_SNFI = "y";
SPI_MASTER = "y";
SPI = "y";
SPI_MEM="y";
SPI_MTK_NOR="y";
SPI_MTK_SNFI = "y";
MTD = "y";
MTD_BLOCK = "y";
MTD_RAW_NAND = "y";
MTD_NAND_MTK = "y";
MTD_NAND_MTK_BMT = "y"; # Bad-block Management Table
MTD_NAND_ECC_MEDIATEK = "y";
MTD_NAND_ECC_SW_HAMMING = "y";
MTD_SPI_NAND = "y";
MTD_OF_PARTS = "y";
MTD_NAND_CORE = "y";
MTD_SPI_NOR = "y";
MTD_SPLIT_FIRMWARE = "y";
MTD_SPLIT_FIT_FW = "y";
MTD = "y";
MTD_BLOCK = "y";
MTD_RAW_NAND = "y";
MTD_NAND_MTK = "y";
MTD_NAND_MTK_BMT = "y"; # Bad-block Management Table
MTD_NAND_ECC_MEDIATEK= "y";
MTD_NAND_ECC_SW_HAMMING= "y";
MTD_SPI_NAND= "y";
MTD_OF_PARTS = "y";
MTD_NAND_CORE= "y";
MTD_SPI_NOR= "y";
MTD_SPLIT_FIRMWARE= "y";
MTD_SPLIT_FIT_FW= "y";
MTD_UBI_NVMEM = "y";
NVMEM_MTK_EFUSE = "y";
NVMEM_BLOCK = "y";
NVMEM_LAYOUT_ADTRAN = "y";
MMC = "y";
MMC_BLOCK = "y";
MMC_CQHCI = "y";
MMC_MTK = "y";
MMC = "y";
MMC_BLOCK = "y";
MMC_CQHCI = "y";
MMC_MTK = "y";
# Distributed Switch Architecture is needed
# to make the ethernet ports visible
NET_DSA = "y";
NET_DSA_MT7530 = "y";
NET_DSA_TAG_MTK = "y";
NET_DSA_MT7530_MDIO = "y";
# Distributed Switch Architecture is needed
# to make the ethernet ports visible
NET_DSA="y";
NET_DSA_MT7530="y";
NET_DSA_TAG_MTK="y";
SERIAL_8250 = "y";
SERIAL_8250_CONSOLE = "y";
SERIAL_8250_MT6577 = "y";
# SERIAL_8250_NR_UARTS="3";
# SERIAL_8250_RUNTIME_UARTS="3";
SERIAL_OF_PLATFORM = "y";
PSTORE = "y";
PSTORE_RAM = "y";
PSTORE_CONSOLE = "y";
PSTORE_DEFLATE_COMPRESS = "n";
# Must enble hardware watchdog drivers. Else the device reboots after several seconds
WATCHDOG = "y";
MEDIATEK_WATCHDOG = "y";
};
conditionalConfig = {
WLAN = {
MT7615E = "m";
MT7622_WMAC = "y";
MT7915E = "m";
};
};
SERIAL_8250 = "y";
SERIAL_8250_CONSOLE = "y";
SERIAL_8250_MT6577="y";
# SERIAL_8250_NR_UARTS="3";
# SERIAL_8250_RUNTIME_UARTS="3";
SERIAL_OF_PLATFORM="y";
# Must enble hardware watchdog drivers. Else the device reboots after several seconds
WATCHDOG = "y";
MEDIATEK_WATCHDOG = "y";
};
conditionalConfig = {
WLAN= {
MT7615E = "m";
MT7622_WMAC = "y";
MT7915E = "m";
};
boot = {
commandLine = [ "console=ttyS0,115200" ];
tftp.loadAddress = lim.parseInt "0x48000000";
imageFormat = "fit";
loader.fit.enable = lib.mkDefault true; # override this if you are building tftpboot
};
rootfsType = lib.mkDefault "ubifs"; # override this if you are building tftpboot
filesystem =
let
inherit (pkgs.pseudofile) dir symlink;
in
dir {
lib = dir {
firmware = dir {
mediatek = symlink firmware;
};
};
};
hardware =
let
mac80211 = pkgs.kmodloader.override {
targets = [
"mt7615e"
"mt7915e"
];
inherit (config.system.outputs) kernel;
};
in
{
ubi = {
minIOSize = "2048";
logicalEraseBlockSize = "126976";
physicalEraseBlockSize = "131072";
maxLEBcount = "1024"; # guessing
};
defaultOutput = "ubimage";
# the kernel expects this to be on a 2MB boundary. U-Boot
# (I don't know why) has a default of 0x41080000, which isn't.
# We put it at the 32MB mark so that tftpboot can put its rootfs
# image and DTB underneath, but maybe this is a terrible waste of
# RAM unless the kernel is able to reuse it later. Oh well
loadAddress = lim.parseInt "0x42000000";
entryPoint = lim.parseInt "0x42000000";
rootDevice = "ubi0:liminix";
dts = {
src = "${openwrt.src}/target/linux/mediatek/dts/mt7622-linksys-e8450-ubi.dts";
includePaths = [
"${openwrt.src}/target/linux/mediatek/dts"
"${config.system.outputs.kernel.modulesupport}/arch/arm64/boot/dts/mediatek/"
];
includes = mkIf config.logging.persistent.enable [
./pstore-pmsg.dtsi
];
};
# - 0x000000000000-0x000008000000 : "spi-nand0"
# - 0x000000000000-0x000000080000 : "bl2"
# - 0x000000080000-0x0000001c0000 : "fip"
# - 0x0000001c0000-0x0000002c0000 : "factory"
# - 0x0000002c0000-0x000000300000 : "reserved"
# - 0x000000300000-0x000008000000 : "ubi"
networkInterfaces =
let
inherit (config.system.service.network) link;
in
rec {
wan = link.build { ifname = "wan"; };
lan1 = link.build { ifname = "lan1"; };
lan2 = link.build { ifname = "lan2"; };
lan3 = link.build { ifname = "lan3"; };
lan4 = link.build { ifname = "lan4"; };
lan = lan3;
wlan = link.build {
ifname = "wlan0";
dependencies = [ mac80211 ];
};
wlan5 = link.build {
ifname = "wlan1";
dependencies = [ mac80211 ];
};
};
};
};
};
boot = {
commandLine = [ "console=ttyS0,115200" ];
tftp.loadAddress = lim.parseInt "0x4007ff28";
imageFormat = "fit";
};
filesystem =
let inherit (pkgs.pseudofile) dir symlink;
in
dir {
lib = dir {
firmware = dir {
mediatek = symlink firmware;
};
};
};
hardware =
let
openwrt = pkgs.openwrt;
mac80211 = pkgs.kmodloader.override {
targets = ["mt7615e" "mt7915e"];
inherit (config.system.outputs) kernel;
};
in {
ubi = {
minIOSize = "2048";
eraseBlockSize = "126976";
maxLEBcount = "1024"; # guessing
};
defaultOutput = "ubimage";
# the kernel expects this to be on a 2MB boundary. U-Boot
# (I don't know why) has a default of 0x41080000, which isn't.
# We put it at the 32MB mark so that tftpboot can put its rootfs
# image and DTB underneath, but maybe this is a terrible waste of
# RAM unless the kernel is able to reuse it later. Oh well
loadAddress = lim.parseInt "0x42000000";
entryPoint = lim.parseInt "0x42000000";
rootDevice = "ubi0:liminix";
dts = {
src = "${openwrt.src}/target/linux/mediatek/dts/mt7622-linksys-e8450-ubi.dts";
includes = [
"${openwrt.src}/target/linux/mediatek/dts"
"${config.system.outputs.kernel.modulesupport}/arch/arm64/boot/dts/mediatek/"
];
};
# - 0x000000000000-0x000008000000 : "spi-nand0"
# - 0x000000000000-0x000000080000 : "bl2"
# - 0x000000080000-0x0000001c0000 : "fip"
# - 0x0000001c0000-0x0000002c0000 : "factory"
# - 0x0000002c0000-0x000000300000 : "reserved"
# - 0x000000300000-0x000008000000 : "ubi"
networkInterfaces =
let
inherit (config.system.service.network) link;
inherit (config.system.service) bridge;
in rec {
wan = link.build { ifname = "wan"; };
lan1 = link.build { ifname = "lan1"; };
lan2 = link.build { ifname = "lan2"; };
lan3 = link.build { ifname = "lan3"; };
lan4 = link.build { ifname = "lan4"; };
lan = lan3;
wlan = link.build {
ifname = "wlan0";
dependencies = [ mac80211 ];
};
wlan5 = link.build {
ifname = "wlan1";
dependencies = [ mac80211 ];
};
};
};
};
};
}
-8
View File
@@ -1,8 +0,0 @@
/ {
reserved-memory {
/* make sure address matches upstream */
ramoops@42ff0000 {
pmsg-size = <0x10000>;
};
};
};
+11 -14
View File
@@ -5,6 +5,11 @@
];
config = {
kernel = {
src = pkgs.pkgsBuildBuild.fetchurl {
name = "linux.tar.gz";
url = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.137.tar.gz";
hash = "sha256-PkdzUKZ0IpBiWe/RS70J76JKnBFzRblWcKlaIFNxnHQ=";
};
config = {
MTD = "y";
MTD_BLOCK = "y";
@@ -18,29 +23,21 @@
VIRTIO_BLK = "y";
VIRTIO_NET = "y";
};
conditionalConfig = {
WLAN = {
MAC80211_HWSIM = "m";
};
};
};
hardware =
let
mac80211 = pkgs.kmodloader.override {
inherit (config.system.outputs) kernel;
targets = [ "mac80211_hwsim" ];
mac80211 = pkgs.mac80211.override {
drivers = ["mac80211_hwsim"];
klibBuild = config.system.outputs.kernel.modulesupport;
};
in
{
in {
defaultOutput = "vmroot";
rootDevice = "/dev/mtdblock0";
dts.src = pkgs.lib.mkDefault null;
flash.eraseBlockSize = 65536;
networkInterfaces =
let
inherit (config.system.service.network) link;
in
{
let inherit (config.system.service.network) link;
in {
wan = link.build {
devpath = "/devices/pci0000:00/0000:00:13.0/virtio0";
ifname = "wan";
+37 -62
View File
@@ -4,7 +4,7 @@
config = "mips-unknown-linux-musl";
gcc = {
abi = "32";
arch = "24kc"; # maybe mips_24kc-
arch = "24kc"; # maybe mips_24kc-
};
};
};
@@ -41,11 +41,10 @@
:ref:`system-outputs-mtdimage` can be flashed using the
vendor web UI or the U-Boot emergency "unbrick" routine.
Flashing over an existing Liminix system is not possible while
that system is running, otherwise you'll be overwriting flash
partitions while they're in use - and that might not end well.
Configure the system with :ref:`levitate` if you need to
make it upgradable.
For flashing from an existing Liminix system (we believe that) it
is necessary to first boot into a :ref:`system-outputs-kexecboot`
system, otherwise you'll be overwriting flash partitions while
they're in use - and that might not end well.
Vendor web page: https://www.gl-inet.com/products/gl-ar750/
@@ -53,16 +52,8 @@
'';
module =
{
pkgs,
config,
lim,
lib,
...
}:
module = {pkgs, config, lim, ... }:
let
inherit (lib) mkIf;
openwrt = pkgs.openwrt;
firmwareBlobs = pkgs.pkgsBuildBuild.fetchFromGitHub {
owner = "kvalo";
@@ -72,7 +63,7 @@
};
firmware = pkgs.stdenv.mkDerivation {
name = "wlan-firmware";
phases = [ "installPhase" ];
phases = ["installPhase"];
installPhase = ''
mkdir -p $out/ath10k/QCA9887/hw1.0/
blobdir=${firmwareBlobs}/QCA9887/hw1.0
@@ -81,19 +72,14 @@
'';
};
mac80211 = pkgs.kmodloader.override {
targets = [
"ath9k"
"ath10k_pci"
];
targets = ["ath9k" "ath10k_pci"];
inherit (config.system.outputs) kernel;
dependencies = [ ath10k_cal_data ];
};
ath10k_cal_data =
let
offset = lim.parseInt "0x5000";
size = lim.parseInt "0x844";
in
pkgs.liminix.services.oneshot rec {
in pkgs.liminix.services.oneshot rec {
name = "ath10k_cal_data";
up = ''
part=$(basename $(dirname $(grep -l art /sys/class/mtd/*/name)))
@@ -102,11 +88,11 @@
(in_outputs ${name}
dd if=/dev/$part of=data iflag=skip_bytes,fullblock bs=${toString size} skip=${toString offset} count=1
)
'';
};
'';
};
inherit (pkgs.pseudofile) dir symlink;
in
{
inherit (pkgs.liminix.networking) interface;
in {
imports = [
../../modules/network
../../modules/arch/mipseb.nix
@@ -130,37 +116,23 @@
rootDevice = "/dev/mtdblock5";
dts = {
src = "${openwrt.src}/target/linux/ath79/dts/qca9531_glinet_gl-ar750.dts";
includePaths = [
includes = [
"${openwrt.src}/target/linux/ath79/dts"
];
includes = mkIf config.logging.persistent.enable [
./pstore-ramoops.dtsi
];
};
networkInterfaces =
let
inherit (config.system.service.network) link;
in
{
lan = link.build {
ifname = "lan";
devpath = "/devices/platform/ahb/1a000000.eth";
};
wan = link.build {
ifname = "wan";
devpath = "/devices/platform/ahb/19000000.eth";
};
let inherit (config.system.service.network) link;
in {
lan = link.build { ifname = "eth0"; };
wan = link.build { ifname = "eth1"; };
wlan = link.build {
ifname = "wlan0";
dependencies = [ mac80211 ];
};
wlan5 = link.build {
ifname = "wlan1";
dependencies = [
ath10k_cal_data
mac80211
];
dependencies = [ mac80211 ath10k_cal_data ];
};
};
};
@@ -176,16 +148,19 @@
};
boot.tftp = {
loadAddress = lim.parseInt "0x00A00000";
appendDTB = true;
};
kernel = {
src = pkgs.pkgsBuildBuild.fetchurl {
name = "linux.tar.gz";
url = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.137.tar.gz";
hash = "sha256-PkdzUKZ0IpBiWe/RS70J76JKnBFzRblWcKlaIFNxnHQ=";
};
# Mainline linux 5.19 doesn't have device-tree support for
# this device or even for the SoC, so we use the extensive
# OpenWrt kernel patches
extraPatchPhase = ''
${openwrt.applyPatches.ath79}
sed -i.bak -e '\,include <linux/hw_random.h>,a #include <linux/gpio/driver.h>' drivers/net/wireless/ath/ath9k/ath9k.h # context reqd for next patch
patch -p1 < ${openwrt.src}/package/kernel/mac80211/patches/ath9k/552-ath9k-ahb_of.patch
'';
config = {
@@ -210,31 +185,31 @@
NET = "y";
ETHERNET = "y";
NET_VENDOR_ATHEROS = "y";
AG71XX = "y"; # ethernet (qca,qca9530-eth)
MFD_SYSCON = "y"; # ethernet (compatible "syscon")
AR8216_PHY = "y"; # eth1 is behind a switch
AG71XX = "y"; # ethernet (qca,qca9530-eth)
MFD_SYSCON = "y"; # ethernet (compatible "syscon")
AR8216_PHY = "y"; # eth1 is behind a switch
MTD_SPI_NOR = "y";
SPI_ATH79 = "y"; # these are copied from OpenWrt.
SPI_MASTER = "y"; # At least one of them is necessary
SPI_MEM = "y";
SPI_AR934X = "y";
SPI_BITBANG = "y";
SPI_GPIO = "y";
SPI_ATH79 = "y"; # these are copied from OpenWrt.
SPI_MASTER= "y"; # At least one of them is necessary
SPI_MEM= "y";
SPI_AR934X= "y";
SPI_BITBANG= "y";
SPI_GPIO= "y";
GPIO_ATH79 = "y";
GPIOLIB = "y";
EXPERT = "y";
EXPERT="y";
GPIO_SYSFS = "y"; # required by patches-5.15/0004-phy-add-ath79-usb-phys.patch
OF_GPIO = "y";
SYSFS = "y";
SPI = "y";
MTD = "y";
MTD_BLOCK = "y"; # fix undefined ref to register_mtd_blktrans_devs
MTD_BLOCK = "y"; # fix undefined ref to register_mtd_blktrans_devs
WATCHDOG = "y";
ATH79_WDT = "y"; # watchdog timer
ATH79_WDT = "y"; # watchdog timer
EARLY_PRINTK = "y";
-9
View File
@@ -1,9 +0,0 @@
/ {
reserved-memory {
ramoops@03f00000 {
compatible = "ramoops";
reg = <0x03f00000 0x10000>;
pmsg-size = <0x10000>;
};
};
};
+63 -56
View File
@@ -6,7 +6,7 @@
config = "mipsel-unknown-linux-musl";
gcc = {
abi = "32";
arch = "mips32"; # maybe mips_24kc-
arch = "mips32"; # maybe mips_24kc-
};
};
};
@@ -32,11 +32,10 @@
binary created by :ref:`system-outputs-mtdimage` can be flashed
using the vendor web UI or the U-Boot emergency "unbrick" routine.
Flashing over an existing Liminix system is not possible while
that system is running, otherwise you'll be overwriting flash
partitions while they're in use - and that might not end well.
Configure the system with :ref:`levitate` if you need to
make it upgradable.
For flashing from an existing Liminix system (we think) it
is necessary to first boot into a :ref:`system-outputs-kexecboot`
system, otherwise you'll be overwriting flash partitions while
they're in use - and that might not end well.
Vendor web page: https://www.gl-inet.com/products/gl-mt300a/
@@ -44,22 +43,15 @@
'';
module =
{
pkgs,
config,
lib,
lim,
...
}:
module = { pkgs, config, lib, lim, ...}:
let
inherit (pkgs.liminix.networking) interface;
inherit (pkgs) openwrt;
mac80211 = pkgs.kmodloader.override {
targets = [ "rt2800soc" ];
targets = ["rt2800soc"];
inherit (config.system.outputs) kernel;
};
in
{
in {
imports = [
../../modules/arch/mipsel.nix
../../modules/outputs/tftpboot.nix
@@ -90,7 +82,7 @@
dts = {
src = "${openwrt.src}/target/linux/ramips/dts/mt7620a_glinet_gl-mt300a.dts";
includePaths = [
includes = [
"${openwrt.src}/target/linux/ramips/dts"
];
};
@@ -98,19 +90,33 @@
let
inherit (config.system.service.network) link;
inherit (config.system.service) vlan;
in
rec {
inherit (pkgs.liminix.services) oneshot;
swconfig = oneshot {
name = "swconfig";
up = ''
PATH=${pkgs.swconfig}/bin:$PATH
swconfig dev switch0 set reset
swconfig dev switch0 set enable_vlan 1
swconfig dev switch0 vlan 1 set ports '1 2 3 4 6t'
swconfig dev switch0 vlan 2 set ports '0 6t'
swconfig dev switch0 set apply
'';
down = "${pkgs.swconfig}/bin/swconfig dev switch0 set reset";
};
in rec {
eth = link.build { ifname = "eth0"; };
# lan and wan ports are both behind a switch on eth0
lan = vlan.build {
ifname = "eth0.1";
primary = eth;
vid = "1";
dependencies = [swconfig eth];
};
wan = vlan.build {
ifname = "eth0.2";
primary = eth;
vid = "2";
dependencies = [swconfig eth];
};
wlan = link.build {
ifname = "wlan0";
@@ -120,57 +126,58 @@
};
boot.tftp = {
loadAddress = lim.parseInt "0x00A00000";
appendDTB = true;
};
kernel = {
src = pkgs.fetchurl {
name = "linux.tar.gz";
url = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.137.tar.gz";
hash = "sha256-PkdzUKZ0IpBiWe/RS70J76JKnBFzRblWcKlaIFNxnHQ=";
};
extraPatchPhase = ''
${openwrt.applyPatches.ramips}
${openwrt.applyPatches.rt2x00}
'';
config =
{
config = {
RALINK = "y";
PCI = "y";
SOC_MT7620 = "y";
RALINK = "y";
PCI = "y";
SOC_MT7620 = "y";
SERIAL_8250_CONSOLE = "y";
SERIAL_8250 = "y";
SERIAL_CORE_CONSOLE = "y";
SERIAL_OF_PLATFORM = "y";
SERIAL_8250_CONSOLE = "y";
SERIAL_8250 = "y";
SERIAL_CORE_CONSOLE = "y";
SERIAL_OF_PLATFORM = "y";
CONSOLE_LOGLEVEL_DEFAULT = "8";
CONSOLE_LOGLEVEL_QUIET = "4";
CONSOLE_LOGLEVEL_DEFAULT = "8";
CONSOLE_LOGLEVEL_QUIET = "4";
NET = "y";
ETHERNET = "y";
NET_VENDOR_RALINK = "y";
NET_RALINK_MDIO = "y";
NET_RALINK_MDIO_MT7620 = "y";
NET_RALINK_MT7620 = "y";
SWPHY = "y";
NET = "y";
ETHERNET = "y";
NET_VENDOR_RALINK = "y";
NET_RALINK_MDIO = "y";
NET_RALINK_MDIO_MT7620 = "y";
NET_RALINK_MT7620 = "y";
SWPHY = "y";
SPI = "y";
MTD_SPI_NOR = "y";
SPI_MT7621 = "y"; # } probably don't need both of these
SPI_RT2880 = "y"; # }
SPI_MASTER = "y";
SPI_MEM = "y";
SPI = "y";
MTD_SPI_NOR = "y";
SPI_MT7621 = "y"; # } probably don't need both of these
SPI_RT2880 = "y"; # }
SPI_MASTER= "y";
SPI_MEM= "y";
MTD = "y";
MTD_BLOCK = "y"; # fix undefined ref to register_mtd_blktrans_devs
MTD = "y";
MTD_BLOCK = "y"; # fix undefined ref to register_mtd_blktrans_devs
EARLY_PRINTK = "y";
EARLY_PRINTK = "y";
NEW_LEDS = "y";
LEDS_CLASS = "y"; # required by rt2x00lib
NEW_LEDS = "y";
LEDS_CLASS = "y"; # required by rt2x00lib
PRINTK_TIME = "y";
}
// lib.optionalAttrs (config.system.service ? vlan) {
SWCONFIG = "y";
};
PRINTK_TIME = "y";
} // lib.optionalAttrs (config.system.service ? vlan) {
SWCONFIG = "y";
};
conditionalConfig = {
WLAN = {
WLAN_VENDOR_RALINK = "y";
+59 -70
View File
@@ -4,7 +4,7 @@
config = "mipsel-unknown-linux-musl";
gcc = {
abi = "32";
arch = "mips32"; # maybe mips_24kc-
arch = "mips32"; # maybe mips_24kc-
};
};
};
@@ -13,7 +13,7 @@
GL.iNet GL-MT300N-v2
********************
The GL-MT300N-v2 "Mango" is is very similar to the :ref:`gl-mt300a`, but is
The GL-MT300N-v2 "Mango" is is very similar to the :ref:`MT300A <GL.iNet GL-MT300A>, but is
based on the MT7628 chipset instead of MT7620. It's also marginally cheaper
and comes in a yellow case not a blue one. Be sure your device is
v2 not v1, which is a different animal and has only half as much RAM.
@@ -25,11 +25,10 @@
binary created by :ref:`system-outputs-mtdimage` can be flashed
using the vendor web UI or the U-Boot emergency "unbrick" routine.
Flashing over an existing Liminix system is not possible while
that system is running, otherwise you'll be overwriting flash
partitions while they're in use - and that might not end well.
Configure the system with :ref:`levitate` if you need to
make it upgradable.
For flashing from an existing Liminix system (we think) it
is necessary to first boot into a :ref:`system-outputs-kexecboot`
system, otherwise you'll be overwriting flash partitions while
they're in use - and that might not end well.
Vendor web page: https://www.gl-inet.com/products/gl-mt300n-v2/
@@ -37,29 +36,22 @@
'';
module =
{
pkgs,
config,
lib,
lim,
...
}:
module = { pkgs, config, lib, lim, ...}:
let
inherit (pkgs.liminix.networking) interface;
inherit (pkgs.liminix.services) oneshot;
inherit (pkgs.pseudofile) dir symlink;
inherit (pkgs) openwrt;
mac80211 = pkgs.kmodloader.override {
targets = [ "mt7603e" ];
targets = ["mt7603e"];
inherit (config.system.outputs) kernel;
};
wlan_firmware = pkgs.fetchurl {
url = "https://github.com/openwrt/mt76/raw/f24b56f935392ca1d35fae5fd6e56ef9deda4aad/firmware/mt7628_e2.bin";
hash = "sha256:1dkhfznmdz6s50kwc841x3wj0h6zg6icg5g2bim9pvg66as2vmh9";
};
in
{
in {
imports = [
../../modules/arch/mipsel.nix
../../modules/outputs/tftpboot.nix
@@ -87,7 +79,7 @@
dts = {
src = "${openwrt.src}/target/linux/ramips/dts/mt7628an_glinet_gl-mt300n-v2.dts";
includePaths = [
includes = [
"${openwrt.src}/target/linux/ramips/dts"
];
};
@@ -105,14 +97,10 @@
swconfig dev switch0 vlan 2 set ports '0 6t'
swconfig dev switch0 set apply
'';
down = "${pkgs.swconfig}/bin/swconfig dev switch0 set reset";
};
in
rec {
eth = link.build {
ifname = "eth0";
dependencies = [ swconfig ];
down = "swconfig dev switch0 set reset";
};
in rec {
eth = link.build { ifname = "eth0"; dependencies = [swconfig]; };
# lan and wan ports are both behind a switch on eth0
lan = vlan.build {
ifname = "eth0.1";
@@ -134,68 +122,69 @@
# 20MB seems to give enough room to uncompress the kernel
# without anything getting trodden on. 10MB was too small
loadAddress = lim.parseInt "0x1400000";
appendDTB = true;
};
kernel = {
src = pkgs.fetchurl {
name = "linux.tar.gz";
url = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.137.tar.gz";
hash = "sha256-PkdzUKZ0IpBiWe/RS70J76JKnBFzRblWcKlaIFNxnHQ=";
};
extraPatchPhase = ''
${openwrt.applyPatches.ramips}
'';
config =
{
config = {
RALINK = "y";
PCI = "y";
SOC_MT7620 = "y";
RALINK = "y";
PCI = "y";
SOC_MT7620 = "y";
SERIAL_8250_CONSOLE = "y";
SERIAL_8250 = "y";
SERIAL_CORE_CONSOLE = "y";
SERIAL_OF_PLATFORM = "y";
SERIAL_8250_CONSOLE = "y";
SERIAL_8250 = "y";
SERIAL_CORE_CONSOLE = "y";
SERIAL_OF_PLATFORM = "y";
CONSOLE_LOGLEVEL_DEFAULT = "8";
CONSOLE_LOGLEVEL_QUIET = "4";
CONSOLE_LOGLEVEL_DEFAULT = "8";
CONSOLE_LOGLEVEL_QUIET = "4";
MTD = "y";
MTD_BLOCK = "y"; # fix undefined ref to register_mtd_blktrans_dev
MTD = "y";
MTD_BLOCK = "y"; # fix undefined ref to register_mtd_blktrans_dev
SPI = "y";
MTD_SPI_NOR = "y";
SPI_MT7621 = "y";
SPI_MASTER = "y";
SPI_MEM = "y";
SPI = "y";
MTD_SPI_NOR = "y";
SPI_MT7621 = "y";
SPI_MASTER= "y";
SPI_MEM= "y";
REGULATOR = "y";
REGULATOR_FIXED_VOLTAGE = "y";
REGULATOR = "y";
REGULATOR_FIXED_VOLTAGE = "y";
NET = "y";
ETHERNET = "y";
NET = "y";
ETHERNET = "y";
PHYLIB = "y";
AT803X_PHY = "y";
FIXED_PHY = "y";
GENERIC_PHY = "y";
NET_VENDOR_RALINK = "y";
NET_RALINK_RT3050 = "y";
NET_RALINK_SOC = "y";
SWPHY = "y";
PHYLIB = "y";
AT803X_PHY="y";
FIXED_PHY="y";
GENERIC_PHY="y";
NET_VENDOR_RALINK = "y";
NET_RALINK_RT3050 = "y";
NET_RALINK_SOC="y";
SWPHY = "y";
GPIOLIB = "y";
GPIO_MT7621 = "y";
GPIOLIB="y";
GPIO_MT7621 = "y";
PHY_RALINK_USB = "y";
PHY_RALINK_USB = "y";
EARLY_PRINTK = "y";
EARLY_PRINTK = "y";
PRINTK_TIME = "y";
}
// lib.optionalAttrs (config.system.service ? vlan) {
SWCONFIG = "y";
}
// lib.optionalAttrs (config.system.service ? watchdog) {
RALINK_WDT = "y"; # watchdog
MT7621_WDT = "y"; # or it might be this one
};
PRINTK_TIME = "y";
} // lib.optionalAttrs (config.system.service ? vlan) {
SWCONFIG = "y";
} // lib.optionalAttrs (config.system.service ? watchdog) {
RALINK_WDT = "y"; # watchdog
MT7621_WDT = "y"; # or it might be this one
};
conditionalConfig = {
WLAN = {
WLAN_VENDOR_RALINK = "y";
-751
View File
@@ -1,751 +0,0 @@
{
description = ''
OpenWrt One
***********
Hardware summary
================
- MediaTek MT7981B (1300MHz)
- 256MB NAND Flash
- 1024MB RAM
- WLan hardware: Mediatek MT7976C
Status
======
- Only tested over TFTP so far.
- WiFi (2.4G and 5G) works.
- 2.5G ethernet port works.
Limitations
===========
- adding `he_bss_color="128"` causes `Invalid argument` for hostap
- nvme support untested
- I don't think the front LEDs work yet
Installation
============
TODO: add instructions on how to boot directly from TFTP to memory
and how to install from TFTP to flash without going through OpenWrt.
The instructions below assume you can boot and SSH into OpenWrt:
Boot into OpenWrt and create a 'liminix' UBI partition:
root@OpenWrt:~# ubimkvol /dev/ubi0 --name=liminix --maxavsize
Remember the 'Volume ID' that was created for this new partition
Build the UBI image and write it to this new partition:
$ nix-build -I liminix-config=./my-configuration.nix --arg device "import ./devices/openwrt-one" -A outputs.default
$ cat result/rootfs | ssh root@192.168.1.1 "cat > /tmp/rootfs"
$ ssh root@192.168.1.1
root@OpenWrt:~# ubiupdatevol /dev/ubi0_X /tmp/rootfs # replace X with the volume id, if needed check with `ubinfo`
Reboot into the U-Boot prompt and boot with:
OpenWrt One> ubifsmount ubi0:liminix && ubifsload ''${loadaddr} boot/fit && bootm ''${loadaddr}'
If this works, reboot into OpenWrt and configure U-Boot to boot ubifs by default:
root@OpenWrt:~# fw_setenv orig_boot_production $(fw_printenv -n boot_production)
root@OpenWrt:~# fw_setenv boot_production 'led white on ; ubifsmount ubi0:liminix && ubifsload ''${loadaddr} boot/fit && bootm ''${loadaddr}'
Troubleshooting
===============
The instructions above assume you can boot and SSH into the (recovery)
OpenWrt installation. If you have broken your device to the point where that
is no longer possible, you could re-install OpenWrt, but probably you could
also install directly from U-Boot:
https://github.com/u-boot/u-boot/blob/master/doc/README.ubi
'';
system = {
crossSystem = {
config = "aarch64-unknown-linux-musl";
gcc = {
# https://openwrt.org/docs/techref/instructionset/aarch64_cortex-a53
# openwrt ./target/linux/mediatek/filogic/target.mk
# https://gcc.gnu.org/onlinedocs/gcc/AArch64-Options.html
# https://en.wikipedia.org/wiki/Comparison_of_ARM_processors
arch = "armv8-a";
};
};
};
module =
{
pkgs,
config,
lib,
lim,
...
}:
let
openwrt = pkgs.openwrt_24_10;
mediatek-firmware = pkgs.stdenv.mkDerivation {
name = "wlan-firmware";
phases = [ "installPhase" ];
installPhase = ''
mkdir $out
cp ${pkgs.linux-firmware}/lib/firmware/mediatek/{mt7915,mt7615,mt7986_eeprom_mt7976,mt7981}* $out
'';
};
airoha-firmware = pkgs.stdenv.mkDerivation {
name = "airoha-firmware";
phases = [ "installPhase" ];
installPhase = ''
mkdir $out
cp ${pkgs.linux-firmware}/lib/firmware/airoha/* $out
'';
};
in
{
imports = [
../../modules/arch/aarch64.nix
../../modules/outputs/tftpboot.nix
../../modules/outputs/ubifs.nix
];
config = {
kernel = {
src = openwrt.kernelSrc;
version = openwrt.kernelVersion;
extraPatchPhase = ''
${openwrt.applyPatches.mediatek}
'';
config =
{
NET = "y"; # unlock NET_XGRESS
SERIAL_8250 = "y"; # unlock SERIAL_8250_FSL
SERIAL_8250_CONSOLE = "y"; # to get the serial console
WATCHDOG = "y"; # unlock WATCHDOG_CORE
NEW_LEDS = "y"; # unlock LEDS_PWM
LEDS_CLASS = "y"; # unlock LEDS_PWM
LEDS_TRIGGERS = "y"; # unlock LEDS_TRIGGER_PATTERN
DEFERRED_STRUCT_PAGE_INIT = "y"; # trigger PADATA
# Taken from openwrt's ./target/linux/mediatek/filogic/config-6.6
"64BIT" = "y";
AIROHA_EN8801SC_PHY = "y";
ARCH_BINFMT_ELF_EXTRA_PHDRS = "y";
ARCH_CORRECT_STACKTRACE_ON_KRETPROBE = "y";
ARCH_DEFAULT_KEXEC_IMAGE_VERIFY_SIG = "y";
ARCH_DMA_ADDR_T_64BIT = "y";
ARCH_FORCE_MAX_ORDER = "10";
ARCH_KEEP_MEMBLOCK = "y";
ARCH_MEDIATEK = "y";
ARCH_MHP_MEMMAP_ON_MEMORY_ENABLE = "y";
ARCH_MMAP_RND_BITS = "18";
ARCH_MMAP_RND_BITS_MAX = "24";
ARCH_MMAP_RND_BITS_MIN = "18";
ARCH_MMAP_RND_COMPAT_BITS_MIN = "11";
ARCH_PROC_KCORE_TEXT = "y";
ARCH_SPARSEMEM_ENABLE = "y";
ARCH_STACKWALK = "y";
ARCH_SUSPEND_POSSIBLE = "y";
ARCH_WANTS_NO_INSTR = "y";
ARCH_WANTS_THP_SWAP = "y";
ARM64 = "y";
ARM64_4K_PAGES = "y";
ARM64_ERRATUM_843419 = "y";
ARM64_LD_HAS_FIX_ERRATUM_843419 = "y";
ARM64_PAGE_SHIFT = "12";
ARM64_PA_BITS = "48";
ARM64_PA_BITS_48 = "y";
ARM64_TAGGED_ADDR_ABI = "y";
ARM64_VA_BITS = "39";
ARM64_VA_BITS_39 = "y";
ARM_AMBA = "y";
ARM_ARCH_TIMER = "y";
ARM_ARCH_TIMER_EVTSTREAM = "y";
ARM_GIC = "y";
ARM_GIC_V2M = "y";
ARM_GIC_V3 = "y";
ARM_GIC_V3_ITS = "y";
ARM_GIC_V3_ITS_PCI = "y";
ARM_MEDIATEK_CPUFREQ = "y";
ARM_PMU = "y";
ARM_PMUV3 = "y";
ARM_PSCI_FW = "y";
ATA = "y";
AUDIT_ARCH_COMPAT_GENERIC = "y";
BLK_DEV_LOOP = "y";
BLK_DEV_SD = "y";
BLK_MQ_PCI = "y";
BLK_PM = "y";
BLOCK_NOTIFIERS = "y";
BSD_PROCESS_ACCT = "y";
BSD_PROCESS_ACCT_V3 = "y";
BUFFER_HEAD = "y";
BUILTIN_RETURN_ADDRESS_STRIPS_PAC = "y";
CC_HAVE_SHADOW_CALL_STACK = "y";
CC_HAVE_STACKPROTECTOR_SYSREG = "y";
#CC_IMPLICIT_FALLTHROUGH="-Wimplicit-fallthrough=5";
CC_NO_ARRAY_BOUNDS = "y";
CLKSRC_MMIO = "y";
CLONE_BACKWARDS = "y";
CMDLINE_OVERRIDE = "y";
COMMON_CLK = "y";
COMMON_CLK_MEDIATEK = "y";
COMMON_CLK_MT7981 = "y";
COMMON_CLK_MT7981_ETHSYS = "y";
COMMON_CLK_MT7986 = "y";
COMMON_CLK_MT7986_ETHSYS = "y";
COMMON_CLK_MT7988 = "y";
COMPACT_UNEVICTABLE_DEFAULT = "1";
CONFIGFS_FS = "y";
CONSOLE_LOGLEVEL_DEFAULT = "15";
CONTEXT_TRACKING = "y";
CONTEXT_TRACKING_IDLE = "y";
CPU_FREQ = "y";
CPU_FREQ_DEFAULT_GOV_USERSPACE = "y";
CPU_FREQ_GOV_ATTR_SET = "y";
CPU_FREQ_GOV_COMMON = "y";
CPU_FREQ_GOV_CONSERVATIVE = "y";
CPU_FREQ_GOV_ONDEMAND = "y";
CPU_FREQ_GOV_PERFORMANCE = "y";
CPU_FREQ_GOV_POWERSAVE = "y";
CPU_FREQ_GOV_SCHEDUTIL = "y";
CPU_FREQ_GOV_USERSPACE = "y";
CPU_FREQ_STAT = "y";
CPU_LITTLE_ENDIAN = "y";
CPU_RMAP = "y";
CPU_THERMAL = "y";
CRC16 = "y";
CRC_CCITT = "y";
CRYPTO_AES_ARM64 = "y";
CRYPTO_AES_ARM64_CE = "y";
CRYPTO_AES_ARM64_CE_BLK = "y";
CRYPTO_AES_ARM64_CE_CCM = "y";
CRYPTO_CMAC = "y";
CRYPTO_CRC32 = "y";
CRYPTO_CRC32C = "y";
CRYPTO_CRYPTD = "y";
CRYPTO_DEFLATE = "y";
CRYPTO_DRBG = "y";
CRYPTO_DRBG_HMAC = "y";
CRYPTO_DRBG_MENU = "y";
CRYPTO_ECB = "y";
CRYPTO_ECC = "y";
CRYPTO_ECDH = "y";
CRYPTO_GHASH_ARM64_CE = "y";
CRYPTO_HASH_INFO = "y";
CRYPTO_HMAC = "y";
CRYPTO_JITTERENTROPY = "y";
CRYPTO_LIB_BLAKE2S_GENERIC = "y";
CRYPTO_LIB_GF128MUL = "y";
CRYPTO_LIB_SHA1 = "y";
CRYPTO_LIB_SHA256 = "y";
CRYPTO_LIB_UTILS = "y";
CRYPTO_LZO = "y";
CRYPTO_RNG = "y";
CRYPTO_RNG2 = "y";
CRYPTO_RNG_DEFAULT = "y";
CRYPTO_SHA256 = "y";
CRYPTO_SHA256_ARM64 = "y";
CRYPTO_SHA2_ARM64_CE = "y";
CRYPTO_SHA3 = "y";
CRYPTO_SHA512 = "y";
CRYPTO_SM4 = "y";
CRYPTO_SM4_ARM64_CE_BLK = "y";
CRYPTO_SM4_ARM64_CE_CCM = "y";
CRYPTO_SM4_ARM64_CE_GCM = "y";
CRYPTO_ZSTD = "y";
DCACHE_WORD_ACCESS = "y";
#DEBUG_INFO="y";
DEBUG_MISC = "y";
DIMLIB = "y";
DMADEVICES = "y";
DMATEST = "y";
DMA_BOUNCE_UNALIGNED_KMALLOC = "y";
DMA_DIRECT_REMAP = "y";
DMA_ENGINE = "y";
DMA_ENGINE_RAID = "y";
DMA_OF = "y";
DMA_VIRTUAL_CHANNELS = "y";
DTC = "y";
EDAC_SUPPORT = "y";
EINT_MTK = "y";
EXCLUSIVE_SYSTEM_RAM = "y";
EXT4_FS = "y";
F2FS_FS = "y";
FIXED_PHY = "y";
FIX_EARLYCON_MEM = "y";
FRAME_POINTER = "y";
FS_IOMAP = "y";
FS_MBCACHE = "y";
FUNCTION_ALIGNMENT = "4";
FUNCTION_ALIGNMENT_4B = "y";
FWNODE_MDIO = "y";
FW_LOADER_PAGED_BUF = "y";
#FW_LOADER_SYSFS="y";
#GCC11_NO_ARRAY_BOUNDS="y";
#GCC_ASM_GOTO_OUTPUT_WORKAROUND="y";
GCC_SUPPORTS_DYNAMIC_FTRACE_WITH_ARGS = "y";
GENERIC_ALLOCATOR = "y";
GENERIC_ARCH_TOPOLOGY = "y";
GENERIC_BUG = "y";
GENERIC_BUG_RELATIVE_POINTERS = "y";
GENERIC_CLOCKEVENTS = "y";
GENERIC_CLOCKEVENTS_BROADCAST = "y";
GENERIC_CPU_AUTOPROBE = "y";
GENERIC_CPU_VULNERABILITIES = "y";
GENERIC_CSUM = "y";
GENERIC_EARLY_IOREMAP = "y";
GENERIC_GETTIMEOFDAY = "y";
GENERIC_IDLE_POLL_SETUP = "y";
GENERIC_IOREMAP = "y";
GENERIC_IRQ_EFFECTIVE_AFF_MASK = "y";
GENERIC_IRQ_SHOW = "y";
GENERIC_IRQ_SHOW_LEVEL = "y";
GENERIC_LIB_DEVMEM_IS_ALLOWED = "y";
GENERIC_MSI_IRQ = "y";
GENERIC_PCI_IOMAP = "y";
GENERIC_PHY = "y";
GENERIC_PINCONF = "y";
GENERIC_PINCTRL_GROUPS = "y";
GENERIC_PINMUX_FUNCTIONS = "y";
GENERIC_SCHED_CLOCK = "y";
GENERIC_SMP_IDLE_THREAD = "y";
GENERIC_STRNCPY_FROM_USER = "y";
GENERIC_STRNLEN_USER = "y";
GENERIC_TIME_VSYSCALL = "y";
GLOB = "y";
GPIO_CDEV = "y";
GPIO_WATCHDOG = "y";
GPIO_WATCHDOG_ARCH_INITCALL = "y";
GRO_CELLS = "y";
HARDIRQS_SW_RESEND = "y";
HAS_DMA = "y";
HAS_IOMEM = "y";
HAS_IOPORT = "y";
HAS_IOPORT_MAP = "y";
HWMON = "y";
HW_RANDOM = "y";
HW_RANDOM_MTK = "y";
I2C = "y";
I2C_BOARDINFO = "y";
I2C_CHARDEV = "y";
I2C_MT65XX = "y";
ICPLUS_PHY = "y";
ILLEGAL_POINTER_VALUE = "0xdead000000000000";
#INITRAMFS_SOURCE="""";
IRQCHIP = "y";
IRQ_DOMAIN = "y";
IRQ_DOMAIN_HIERARCHY = "y";
IRQ_FORCED_THREADING = "y";
IRQ_TIME_ACCOUNTING = "y";
IRQ_WORK = "y";
JBD2 = "y";
JUMP_LABEL = "y";
LEDS_PWM = "y";
LEDS_SMARTRG_LED = "y";
LIBFDT = "y";
LOCK_DEBUGGING_SUPPORT = "y";
LOCK_SPIN_ON_OWNER = "y";
LZO_COMPRESS = "y";
LZO_DECOMPRESS = "y";
MAGIC_SYSRQ = "y";
MAXLINEAR_GPHY = "y";
MDIO_BUS = "y";
MDIO_DEVICE = "y";
MDIO_DEVRES = "y";
MEDIATEK_2P5GE_PHY = "y";
MEDIATEK_GE_PHY = "y";
MEDIATEK_GE_SOC_PHY = "y";
MEDIATEK_WATCHDOG = "y";
MESSAGE_LOGLEVEL_DEFAULT = "7";
MFD_SYSCON = "y";
MIGRATION = "y";
MMC = "y";
MMC_BLOCK = "y";
MMC_CQHCI = "y";
MMC_MTK = "y";
MMU_LAZY_TLB_REFCOUNT = "y";
MODULES_TREE_LOOKUP = "y";
MODULES_USE_ELF_RELA = "y";
MTD_NAND_CORE = "y";
MTD_NAND_ECC = "y";
MTD_NAND_ECC_MEDIATEK = "y";
MTD_NAND_ECC_SW_HAMMING = "y";
MTD_NAND_MTK = "y";
MTD_NAND_MTK_BMT = "y";
MTD_PARSER_TRX = "y";
MTD_RAW_NAND = "y";
MTD_SPI_NAND = "y";
MTD_SPI_NOR = "y";
MTD_SPLIT_FIRMWARE = "y";
MTD_SPLIT_FIT_FW = "y";
MTD_UBI = "y";
MTD_UBI_BEB_LIMIT = "20";
MTD_UBI_BLOCK = "y";
MTD_UBI_FASTMAP = "y";
MTD_UBI_NVMEM = "y";
MTD_UBI_WL_THRESHOLD = "4096";
MTK_CPUX_TIMER = "y";
MTK_HSDMA = "y";
MTK_INFRACFG = "y";
MTK_LVTS_THERMAL = "y";
MTK_LVTS_THERMAL_DEBUGFS = "y";
MTK_PMIC_WRAP = "y";
MTK_REGULATOR_COUPLER = "y";
MTK_SCPSYS = "y";
MTK_SCPSYS_PM_DOMAINS = "y";
MTK_SOC_THERMAL = "y";
MTK_THERMAL = "y";
MTK_TIMER = "y";
MUTEX_SPIN_ON_OWNER = "y";
NEED_DMA_MAP_STATE = "y";
NEED_SG_DMA_LENGTH = "y";
NET_DEVLINK = "y";
NET_DSA = "y";
NET_DSA_MT7530 = "y";
NET_DSA_MT7530_MDIO = "y";
NET_DSA_MT7530_MMIO = "y";
NET_DSA_TAG_MTK = "y";
#NET_EGRESS="y";
NET_FLOW_LIMIT = "y";
#NET_INGRESS="y";
NET_MEDIATEK_SOC = "y";
NET_MEDIATEK_SOC_WED = "y";
NET_SELFTESTS = "y";
NET_SWITCHDEV = "y";
NET_VENDOR_MEDIATEK = "y";
#NET_XGRESS="y";
NLS = "y";
NO_HZ_COMMON = "y";
NO_HZ_IDLE = "y";
NR_CPUS = "4";
NVMEM = "y";
NVMEM_BLOCK = "y";
NVMEM_LAYOUTS = "y";
NVMEM_LAYOUT_ADTRAN = "y";
NVMEM_MTK_EFUSE = "y";
NVMEM_SYSFS = "y";
OF = "y";
OF_ADDRESS = "y";
OF_DYNAMIC = "y";
OF_EARLY_FLATTREE = "y";
OF_FLATTREE = "y";
OF_GPIO = "y";
OF_IRQ = "y";
OF_KOBJ = "y";
OF_MDIO = "y";
OF_OVERLAY = "y";
OF_RESOLVE = "y";
PADATA = "y";
PAGE_POOL = "y";
PAGE_POOL_STATS = "y";
PAGE_SIZE_LESS_THAN_256KB = "y";
PAGE_SIZE_LESS_THAN_64KB = "y";
#PAHOLE_HAS_LANG_EXCLUDE="y";
PARTITION_PERCPU = "y";
PCI = "y";
PCIEAER = "y";
PCIEASPM = "y";
PCIEASPM_PERFORMANCE = "y";
PCIEPORTBUS = "y";
PCIE_MEDIATEK_GEN3 = "y";
PCIE_PME = "y";
PCI_DEBUG = "y";
PCI_DOMAINS = "y";
PCI_DOMAINS_GENERIC = "y";
PCI_MSI = "y";
PCS_MTK_LYNXI = "y";
PCS_MTK_USXGMII = "y";
PERF_EVENTS = "y";
PER_VMA_LOCK = "y";
PGTABLE_LEVELS = "3";
PHYLIB = "y";
PHYLIB_LEDS = "y";
PHYLINK = "y";
PHYS_ADDR_T_64BIT = "y";
PHY_MTK_TPHY = "y";
PHY_MTK_XFI_TPHY = "y";
PHY_MTK_XSPHY = "y";
PINCTRL = "y";
PINCTRL_MT7981 = "y";
PINCTRL_MT7986 = "y";
PINCTRL_MT7988 = "y";
PINCTRL_MTK_MOORE = "y";
PINCTRL_MTK_V2 = "y";
PM = "y";
PM_CLK = "y";
PM_GENERIC_DOMAINS = "y";
PM_GENERIC_DOMAINS_OF = "y";
PM_OPP = "y";
POLYNOMIAL = "y";
POSIX_CPU_TIMERS_TASK_WORK = "y";
POWER_RESET = "y";
POWER_RESET_SYSCON = "y";
POWER_SUPPLY = "y";
PREEMPT_NONE_BUILD = "y";
PRINTK_TIME = "y";
PSTORE = "y";
PSTORE_COMPRESS = "y";
PSTORE_CONSOLE = "y";
PSTORE_PMSG = "y";
PSTORE_RAM = "y";
PTP_1588_CLOCK_OPTIONAL = "y";
PWM = "y";
PWM_MEDIATEK = "y";
PWM_SYSFS = "y";
QUEUED_RWLOCKS = "y";
QUEUED_SPINLOCKS = "y";
RANDSTRUCT_NONE = "y";
RAS = "y";
RATIONAL = "y";
REALTEK_PHY = "y";
REED_SOLOMON = "y";
REED_SOLOMON_DEC8 = "y";
REED_SOLOMON_ENC8 = "y";
REGMAP = "y";
REGMAP_I2C = "y";
REGMAP_MMIO = "y";
REGULATOR = "y";
REGULATOR_FIXED_VOLTAGE = "y";
REGULATOR_MT6380 = "y";
REGULATOR_RT5190A = "y";
RESET_CONTROLLER = "y";
RESET_TI_SYSCON = "y";
RFS_ACCEL = "y";
RODATA_FULL_DEFAULT_ENABLED = "y";
RPS = "y";
RTC_CLASS = "y";
RTC_DRV_MT7622 = "y";
RTC_I2C_AND_SPI = "y";
RWSEM_SPIN_ON_OWNER = "y";
SCHED_MC = "y";
SCSI = "y";
SCSI_COMMON = "y";
SERIAL_8250_FSL = "y";
SERIAL_8250_MT6577 = "y";
SERIAL_8250_NR_UARTS = "3";
SERIAL_8250_RUNTIME_UARTS = "3";
SERIAL_DEV_BUS = "y";
SERIAL_DEV_CTRL_TTYPORT = "y";
SERIAL_MCTRL_GPIO = "y";
SERIAL_OF_PLATFORM = "y";
SGL_ALLOC = "y";
SG_POOL = "y";
SMP = "y";
SOCK_RX_QUEUE_MAPPING = "y";
SOFTIRQ_ON_OWN_STACK = "y";
SPARSEMEM = "y";
SPARSEMEM_EXTREME = "y";
SPARSEMEM_VMEMMAP = "y";
SPARSEMEM_VMEMMAP_ENABLE = "y";
SPARSE_IRQ = "y";
SPI = "y";
SPI_DYNAMIC = "y";
SPI_MASTER = "y";
SPI_MEM = "y";
SPI_MT65XX = "y";
SPI_MTK_SNFI = "y";
#SQUASHFS_DECOMP_MULTI_PERCPU="y";
SWIOTLB = "y";
SWPHY = "y";
SYSCTL_EXCEPTION_TRACE = "y";
THERMAL = "y";
THERMAL_DEFAULT_GOV_STEP_WISE = "y";
THERMAL_EMERGENCY_POWEROFF_DELAY_MS = "0";
THERMAL_GOV_BANG_BANG = "y";
THERMAL_GOV_FAIR_SHARE = "y";
THERMAL_GOV_STEP_WISE = "y";
THERMAL_GOV_USER_SPACE = "y";
THERMAL_HWMON = "y";
THERMAL_OF = "y";
THERMAL_WRITABLE_TRIPS = "y";
THREAD_INFO_IN_TASK = "y";
TICK_CPU_ACCOUNTING = "y";
TIMER_OF = "y";
TIMER_PROBE = "y";
TRACE_IRQFLAGS_NMI_SUPPORT = "y";
TREE_RCU = "y";
TREE_SRCU = "y";
UBIFS_FS = "y";
UIMAGE_FIT_BLK = "y";
USB_SUPPORT = "y";
VMAP_STACK = "y";
WATCHDOG_CORE = "y";
WATCHDOG_PRETIMEOUT_DEFAULT_GOV_PANIC = "y";
WATCHDOG_PRETIMEOUT_GOV = "y";
WATCHDOG_PRETIMEOUT_GOV_PANIC = "y";
WATCHDOG_PRETIMEOUT_GOV_SEL = "m";
WATCHDOG_SYSFS = "y";
XPS = "y";
XXHASH = "y";
ZLIB_DEFLATE = "y";
ZLIB_INFLATE = "y";
ZONE_DMA32 = "y";
ZSTD_COMMON = "y";
ZSTD_COMPRESS = "y";
ZSTD_DECOMPRESS = "y";
# from DEVICE_PACKAGES in the openwrt_one section of
# openwrt's ./target/linux/mediatek/image/filogic.mk:
# chop off the 'kmod-' prefix and search for 'KernelPackage/...'
# in ./package/kernel/linux/modules/*.mk, and remember to add
# modules to kmodloader targets below
AIR_EN8811H_PHY = "m";
RTC_DRV_PCF8563 = "m";
NVME_CORE = "m";
BLK_DEV_NVME = "m";
NVME_MULTIPATH = "n";
NVME_HWMON = "y";
# ???
AQUANTIA_PHY = "m";
MT798X_WMAC = "y";
}
// lib.optionalAttrs (config.system.service ? watchdog) {
RALINK_WDT = "y"; # watchdog
MT7621_WDT = "y"; # or it might be this one
};
conditionalConfig = {
WLAN = {
MT7915E = "m";
};
};
};
boot = {
commandLine = [ "console=ttyS0,115200" ];
tftp = {
# Should be a segment of free RAM, where the tftp artifact
# can be stored before unpacking it to the 'hardware.loadAddress'
# The 'hardware.loadAddress' is 0x44000000, and the bootlog
# suggests it loads the fit to 0x46000000
loadAddress = lim.parseInt "0x46000000";
};
imageFormat = "fit";
loader.fit.enable = lib.mkDefault true; # override this if you are building tftpboot
};
rootfsType = lib.mkDefault "ubifs"; # override this if you are building tftpboot
filesystem =
let
inherit (pkgs.pseudofile) dir symlink;
in
dir {
lib = dir {
firmware = dir {
mediatek = symlink mediatek-firmware;
airoha = symlink airoha-firmware;
};
};
};
hardware =
let
phy = pkgs.kmodloader.override {
targets = [
"air_en8811h"
];
inherit (config.system.outputs) kernel;
};
mac80211 = pkgs.kmodloader.override {
targets = [
"mt7915e"
"rtc-pcf8563"
"nvme_core"
"nvme"
#"mt7996e"
"aquantia"
];
inherit (config.system.outputs) kernel;
};
in
{
# from OEM bootlog
# Creating 4 MTD partitions on "spi0.0":
# 0x000000000000-0x000000040000 : "bl2-nor"
# 0x000000040000-0x000000100000 : "factory"
# 0x000000100000-0x000000180000 : "fip-nor"
# 0x000000180000-0x000000e00000 : "recovery"
# spi-nand spi1.1: calibration result: 0x3
# spi-nand spi1.1: Winbond SPI NAND was found.
# spi-nand spi1.1: 256 MiB, block size: 128 KiB, page size: 2048, OOB size: 128
# 2 fixed-partitions partitions found on MTD device spi1.1
# Creating 2 MTD partitions on "spi1.1":
# 0x000000000000-0x000000100000 : "bl2"
# 0x000000100000-0x000010000000 : "ubi"
flash = {
# from the OEM bootlog:
# ## Checking Image at 46000000 ...
# FIT image found
# FIT description: ARM64 OpenWrt FIT (Flattened Image Tree)
# Image 0 (kernel-1)
# Description: ARM64 OpenWrt Linux-6.6.57
# Type: Kernel Image
# Compression: gzip compressed
# Data Start: 0x46001000
# Data Size: 5751840 Bytes = 5.5 MiB
# Architecture: AArch64
# OS: Linux
# Load Address: 0x44000000
# Entry Point: 0x44000000
address = lim.parseInt "0x44000000";
size = lim.parseInt "0xf60000";
# /proc/mtd on a running system:
# dev: size erasesize name
# mtd0: 00040000 00010000 "bl2-nor"
# mtd1: 000c0000 00010000 "factory"
# mtd2: 00080000 00010000 "fip-nor"
# mtd3: 00c80000 00010000 "recovery"
# mtd4: 00100000 00020000 "bl2"
# mtd5: 0ff00000 00020000 "ubi"
eraseBlockSize = 65536;
};
ubi = {
# TODO taken from belkin-rt3200, to review
minIOSize = "2048";
logicalEraseBlockSize = "126976";
physicalEraseBlockSize = "131072";
maxLEBcount = "1024"; # guessing
};
defaultOutput = "ubimage";
loadAddress = lim.parseInt "0x44000000";
entryPoint = lim.parseInt "0x44000000";
# TODO AFAICT this should be 2048, but I got 'FIT: image rootfs-1 start not aligned to page boundaries' with that...
#alignment = 2048;
alignment = 4096;
rootDevice = "ubi0:liminix";
dts = {
src = "${openwrt.src}/target/linux/mediatek/dts/mt7981b-openwrt-one.dts";
includePaths = [
"${openwrt.src}/target/linux/mediatek/dts"
"${config.system.outputs.kernel.modulesupport}/arch/arm64/boot/dts/mediatek/"
];
};
networkInterfaces =
let
inherit (config.system.service.network) link;
in
rec {
eth0 = link.build {
ifname = "eth0";
dependencies = [ phy ];
};
eth1 = link.build { ifname = "eth1"; };
wlan0 = link.build {
ifname = "wlan0";
dependencies = [ mac80211 ];
};
wlan1 = link.build {
ifname = "wlan1";
dependencies = [ mac80211 ];
};
};
};
};
};
}
+20 -26
View File
@@ -19,39 +19,33 @@
ARM targets differ from MIPS in that the kernel format expected
by QEMU is an "Image" (raw binary file) rather than an ELF
file, but this is taken care of by :command:`run.sh`. Check the
documentation for the :ref:`qemu` target for more information.
documentation for the :ref:`QEMU` (MIPS) target for more information.
'';
# this device is described by the "qemu" device
installer = "vmroot";
module =
{ config, lim, ... }:
{
imports = [
../../modules/arch/aarch64.nix
../families/qemu.nix
];
kernel = {
config = {
VIRTUALIZATION = "y";
PCI_HOST_GENERIC = "y";
module = {pkgs, config, lim, ... }: {
imports = [
../../modules/arch/aarch64.nix
../families/qemu.nix
];
kernel = {
config = {
VIRTUALIZATION = "y";
PCI_HOST_GENERIC="y";
SERIAL_AMBA_PL011 = "y";
SERIAL_AMBA_PL011_CONSOLE = "y";
};
SERIAL_AMBA_PL011 = "y";
SERIAL_AMBA_PL011_CONSOLE = "y";
};
boot.commandLine = [
"console=ttyAMA0,38400"
];
hardware =
let
addr = lim.parseInt "0x40010000";
in
{
loadAddress = addr;
entryPoint = addr;
};
};
boot.commandLine = [
"console=ttyAMA0,38400"
];
hardware = let addr = lim.parseInt "0x40010000"; in {
loadAddress = addr;
entryPoint = addr;
};
};
}
+23 -29
View File
@@ -5,7 +5,7 @@
{
system = {
crossSystem = {
config = "armv7l-unknown-linux-musleabihf";
config = "armv7l-unknown-linux-musleabihf";
};
};
@@ -24,36 +24,30 @@
'';
installer = "vmroot";
module =
{ config, lim, ... }:
{
imports = [
../../modules/arch/arm.nix
../families/qemu.nix
];
kernel = {
config = {
PCI_HOST_GENERIC = "y";
ARCH_VIRT = "y";
module = {pkgs, config, lim, ... }: {
imports = [
../../modules/arch/arm.nix
../families/qemu.nix
];
kernel = {
config = {
PCI_HOST_GENERIC = "y";
ARCH_VIRT = "y";
VFP = "y";
NEON = "y";
AEABI = "y";
VFP = "y";
NEON = "y";
AEABI = "y";
SERIAL_AMBA_PL011 = "y";
SERIAL_AMBA_PL011_CONSOLE = "y";
};
SERIAL_AMBA_PL011 = "y";
SERIAL_AMBA_PL011_CONSOLE = "y";
};
boot.commandLine = [
"console=ttyAMA0"
];
hardware =
let
addr = lim.parseInt "0x40008000";
in
{
loadAddress = addr;
entryPoint = addr;
};
};
boot.commandLine = [
"console=ttyAMA0"
];
hardware = let addr = lim.parseInt "0x40008000"; in {
loadAddress = addr;
entryPoint = addr;
};
};
}
+34 -43
View File
@@ -7,7 +7,7 @@
config = "mips-unknown-linux-musl";
gcc = {
abi = "32";
arch = "mips32"; # maybe mips_24kc-
arch = "mips32"; # maybe mips_24kc-
};
};
};
@@ -36,50 +36,41 @@
in the Development manual.
'';
module =
{
config,
lib,
lim,
...
}:
{
imports = [
../../modules/arch/mipseb.nix
../families/qemu.nix
];
kernel = {
config = {
MIPS_MALTA = "y";
CPU_MIPS32_R2 = "y";
module = {pkgs, config, lib, lim, ... }: {
imports = [
../../modules/arch/mipseb.nix
../families/qemu.nix
];
kernel = {
config = {
MIPS_MALTA= "y";
CPU_MIPS32_R2= "y";
POWER_RESET = "y";
POWER_RESET_SYSCON = "y";
POWER_RESET = "y";
POWER_RESET_SYSCON = "y";
SERIAL_8250 = "y";
SERIAL_8250_CONSOLE = "y";
};
SERIAL_8250= "y";
SERIAL_8250_CONSOLE= "y";
};
hardware =
# from arch/mips/mti-malta/Platform:load-$(CONFIG_MIPS_MALTA) += 0xffffffff80100000
let
addr = lim.parseInt "0x80100000";
in
{
loadAddress = addr;
entryPoint = addr;
# Unlike the arm qemu targets, we need a static dts when
# running u-boot-using tests, qemu dumpdtb command doesn't
# work for this board. I am not at all sure this dts is
# *correct* but it does at least boot
dts = lib.mkForce {
src = "${config.system.outputs.kernel.modulesupport}/arch/mips/boot/dts/mti/malta.dts";
includePaths = [
"${config.system.outputs.kernel.modulesupport}/arch/mips/boot/dts/"
];
};
};
};
hardware =
# from arch/mips/mti-malta/Platform:load-$(CONFIG_MIPS_MALTA) += 0xffffffff80100000
let addr = lim.parseInt "0x80100000";
in {
loadAddress = addr;
entryPoint = addr;
# Unlike the arm qemu targets, we need a static dts when
# running u-boot-using tests, qemu dumpdtb command doesn't
# work for this board. I am not at all sure this dts is
# *correct* but it does at least boot
dts = lib.mkForce {
src = "${config.system.outputs.kernel.modulesupport}/arch/mips/boot/dts/mti/malta.dts";
includes = [
"${config.system.outputs.kernel.modulesupport}/arch/mips/boot/dts/"
];
};
};
};
}
+372 -380
View File
@@ -33,25 +33,16 @@
};
};
module =
{
pkgs,
config,
lib,
lim,
...
}:
let
firmware = pkgs.stdenv.mkDerivation {
name = "wlan-firmware";
phases = [ "installPhase" ];
installPhase = ''
mkdir $out
cp ${pkgs.linux-firmware}/lib/firmware/mediatek/{mt7915,mt7615,mt7622}* $out
'';
};
in
{
module = {pkgs, config, lib, lim, ... }:
let firmware = pkgs.stdenv.mkDerivation {
name = "wlan-firmware";
phases = ["installPhase"];
installPhase = ''
mkdir $out
cp ${pkgs.linux-firmware}/lib/firmware/mediatek/{mt7915,mt7615,mt7622}* $out
'';
};
in {
imports = [
../../modules/arch/mipsel.nix
../../modules/outputs/tftpboot.nix
@@ -59,278 +50,281 @@
];
config = {
kernel = {
src = pkgs.pkgsBuildBuild.fetchurl {
name = "linux.tar.gz";
url = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.137.tar.gz";
hash = "sha256-PkdzUKZ0IpBiWe/RS70J76JKnBFzRblWcKlaIFNxnHQ=";
};
extraPatchPhase = ''
${pkgs.openwrt.applyPatches.ramips}
'';
config =
{
# Initially taken from openwrt's ./target/linux/ramips/mt7621/config-5.15,
# then tweaked here and there
ARCH_32BIT_OFF_T = "y";
ARCH_HIBERNATION_POSSIBLE = "y";
ARCH_KEEP_MEMBLOCK = "y";
ARCH_MMAP_RND_BITS_MAX = "15";
ARCH_MMAP_RND_COMPAT_BITS_MAX = "15";
ARCH_SUSPEND_POSSIBLE = "y";
AT803X_PHY = "y";
BLK_MQ_PCI = "y";
BOARD_SCACHE = "y";
CEVT_R4K = "y";
CLKSRC_MIPS_GIC = "y";
CLK_MT7621 = "y";
CLOCKSOURCE_WATCHDOG = "y";
CLONE_BACKWARDS = "y";
CMDLINE_BOOL = "y";
COMMON_CLK = "y";
COMPAT_32BIT_TIME = "y";
CPU_GENERIC_DUMP_TLB = "y";
CPU_HAS_DIEI = "y";
CPU_HAS_PREFETCH = "y";
CPU_HAS_RIXI = "y";
CPU_HAS_SYNC = "y";
CPU_LITTLE_ENDIAN = "y";
CPU_MIPS32 = "y";
CPU_MIPS32_R2 = "y";
CPU_MIPSR2 = "y";
CPU_MIPSR2_IRQ_EI = "y";
CPU_MIPSR2_IRQ_VI = "y";
CPU_NEEDS_NO_SMARTMIPS_OR_MICROMIPS = "y";
CPU_R4K_CACHE_TLB = "y";
CPU_RMAP = "y";
CPU_SUPPORTS_32BIT_KERNEL = "y";
CPU_SUPPORTS_HIGHMEM = "y";
CPU_SUPPORTS_MSA = "y";
CRC16 = "y";
CRYPTO_DEFLATE = "y";
CRYPTO_HASH_INFO = "y";
CRYPTO_LIB_BLAKE2S_GENERIC = "y";
CRYPTO_LIB_POLY1305_RSIZE = "2";
CRYPTO_LZO = "y";
CRYPTO_ZSTD = "y";
CSRC_R4K = "y";
DIMLIB = "y";
DMA_NONCOHERENT = "y";
DTB_RT_NONE = "y";
DTC = "y";
EARLY_PRINTK = "y";
FIXED_PHY = "y";
FWNODE_MDIO = "y";
FW_LOADER_PAGED_BUF = "y";
GENERIC_ATOMIC64 = "y";
GENERIC_CLOCKEVENTS = "y";
GENERIC_CMOS_UPDATE = "y";
GENERIC_CPU_AUTOPROBE = "y";
GENERIC_FIND_FIRST_BIT = "y";
GENERIC_GETTIMEOFDAY = "y";
GENERIC_IOMAP = "y";
GENERIC_IRQ_CHIP = "y";
GENERIC_IRQ_EFFECTIVE_AFF_MASK = "y";
GENERIC_IRQ_SHOW = "y";
GENERIC_LIB_ASHLDI3 = "y";
GENERIC_LIB_ASHRDI3 = "y";
GENERIC_LIB_CMPDI2 = "y";
GENERIC_LIB_LSHRDI3 = "y";
GENERIC_LIB_UCMPDI2 = "y";
GENERIC_PCI_IOMAP = "y";
GENERIC_PHY = "y";
GENERIC_PINCONF = "y";
GENERIC_SCHED_CLOCK = "y";
GENERIC_SMP_IDLE_THREAD = "y";
GENERIC_TIME_VSYSCALL = "y";
GLOB = "y";
GPIOLIB_IRQCHIP = "y";
GPIO_CDEV = "y";
GPIO_GENERIC = "y";
GPIO_MT7621 = "y";
GRO_CELLS = "y";
HANDLE_DOMAIN_IRQ = "y";
HARDWARE_WATCHPOINTS = "y";
HAS_DMA = "y";
HAS_IOMEM = "y";
HAS_IOPORT_MAP = "y";
I2C = "y";
I2C_ALGOBIT = "y";
I2C_BOARDINFO = "y";
I2C_CHARDEV = "y";
I2C_GPIO = "y";
I2C_MT7621 = "y";
ICPLUS_PHY = "y";
IRQCHIP = "y";
IRQ_DOMAIN = "y";
IRQ_DOMAIN_HIERARCHY = "y";
IRQ_FORCED_THREADING = "y";
IRQ_MIPS_CPU = "y";
IRQ_WORK = "y";
LIBFDT = "y";
LOCK_DEBUGGING_SUPPORT = "y";
LZO_COMPRESS = "y";
LZO_DECOMPRESS = "y";
MDIO_BUS = "y";
MDIO_DEVICE = "y";
MDIO_DEVRES = "y";
MEDIATEK_GE_PHY = "y";
MEMFD_CREATE = "y";
MFD_SYSCON = "y";
MIGRATION = "y";
MIKROTIK = "y";
MIKROTIK_RB_SYSFS = "y";
MIPS = "y";
MIPS_ASID_BITS = "8";
MIPS_ASID_SHIFT = "0";
MIPS_CLOCK_VSYSCALL = "y";
MIPS_CM = "y";
MIPS_CPC = "y";
MIPS_CPS = "y";
MIPS_CPU_SCACHE = "y";
MIPS_GIC = "y";
MIPS_L1_CACHE_SHIFT = "5";
MIPS_LD_CAN_LINK_VDSO = "y";
MIPS_MT = "y";
MIPS_MT_FPAFF = "y";
MIPS_MT_SMP = "y";
MIPS_NR_CPU_NR_MAP = "4";
MIPS_PERF_SHARED_TC_COUNTERS = "y";
MIPS_SPRAM = "y";
MODULES_USE_ELF_REL = "y";
MTD_CMDLINE_PARTS = "y";
MTD_NAND_CORE = "y";
MTD_NAND_ECC = "y";
MTD_NAND_ECC_SW_HAMMING = "y";
MTD_NAND_MT7621 = "y";
MTD_NAND_MTK_BMT = "y";
MTD_RAW_NAND = "y";
MTD_ROUTERBOOT_PARTS = "y";
MTD_SERCOMM_PARTS = "y";
MTD_SPI_NOR = "y";
MTD_SPLIT_FIT_FW = "y";
MTD_SPLIT_MINOR_FW = "y";
MTD_SPLIT_SEAMA_FW = "y";
MTD_SPLIT_TPLINK_FW = "y";
MTD_SPLIT_TRX_FW = "y";
MTD_SPLIT_UIMAGE_FW = "y";
MTD_UBI = "y";
MTD_UBI_BEB_LIMIT = "20";
MTD_UBI_BLOCK = "y";
MTD_UBI_WL_THRESHOLD = "4096";
MTD_VIRT_CONCAT = "y";
NEED_DMA_MAP_STATE = "y";
NET_DEVLINK = "y";
NET_DSA = "y";
NET_DSA_MT7530 = "y";
NET_DSA_MT7530_MDIO = "y";
NET_DSA_TAG_MTK = "y";
NET_FLOW_LIMIT = "y";
NET_MEDIATEK_SOC = "y";
NET_SELFTESTS = "y";
NET_SWITCHDEV = "y";
NET_VENDOR_MEDIATEK = "y";
NO_HZ_COMMON = "y";
NO_HZ_IDLE = "y";
NR_CPUS = "4";
NVMEM = "y";
OF = "y";
OF_ADDRESS = "y";
OF_EARLY_FLATTREE = "y";
OF_FLATTREE = "y";
OF_GPIO = "y";
OF_IRQ = "y";
OF_KOBJ = "y";
OF_MDIO = "y";
PAGE_POOL = "y";
PAGE_POOL_STATS = "y";
PCI = "y";
PCIE_MT7621 = "y";
PCI_DISABLE_COMMON_QUIRKS = "y";
PCI_DOMAINS = "y";
PCI_DOMAINS_GENERIC = "y";
PCI_DRIVERS_GENERIC = "y";
PCS_MTK_LYNXI = "y";
PERF_USE_VMALLOC = "y";
PGTABLE_LEVELS = "2";
PHYLIB = "y";
PHYLINK = "y";
PHY_MT7621_PCI = "y";
PINCTRL = "y";
PINCTRL_AW9523 = "y";
PINCTRL_MT7621 = "y";
PINCTRL_RALINK = "y";
PINCTRL_SX150X = "y";
POWER_RESET = "y";
POWER_RESET_GPIO = "y";
POWER_SUPPLY = "y";
PTP_1588_CLOCK_OPTIONAL = "y";
QUEUED_RWLOCKS = "y";
QUEUED_SPINLOCKS = "y";
RALINK = "y";
RATIONAL = "y";
REGMAP = "y";
REGMAP_I2C = "y";
REGMAP_MMIO = "y";
REGULATOR = "y";
REGULATOR_FIXED_VOLTAGE = "y";
RESET_CONTROLLER = "y";
RFS_ACCEL = "y";
RPS = "y";
RTC_CLASS = "y";
RTC_DRV_BQ32K = "y";
RTC_DRV_PCF8563 = "y";
RTC_I2C_AND_SPI = "y";
SCHED_SMT = "y";
SERIAL_8250 = "y";
SERIAL_8250_CONSOLE = "y";
SERIAL_8250_NR_UARTS = "3";
SERIAL_8250_RUNTIME_UARTS = "3";
SERIAL_MCTRL_GPIO = "y";
SERIAL_OF_PLATFORM = "y";
SGL_ALLOC = "y";
SMP = "y";
SMP_UP = "y";
SOCK_RX_QUEUE_MAPPING = "y";
SOC_BUS = "y";
SOC_MT7621 = "y";
SPI = "y";
SPI_MASTER = "y";
SPI_MEM = "y";
SPI_MT7621 = "y";
SRCU = "y";
SWPHY = "y";
SYNC_R4K = "y";
SYSCTL_EXCEPTION_TRACE = "y";
SYS_HAS_CPU_MIPS32_R1 = "y";
SYS_HAS_CPU_MIPS32_R2 = "y";
SYS_HAS_EARLY_PRINTK = "y";
SYS_SUPPORTS_32BIT_KERNEL = "y";
SYS_SUPPORTS_ARBIT_HZ = "y";
SYS_SUPPORTS_HIGHMEM = "y";
SYS_SUPPORTS_HOTPLUG_CPU = "y";
SYS_SUPPORTS_LITTLE_ENDIAN = "y";
SYS_SUPPORTS_MIPS16 = "y";
SYS_SUPPORTS_MIPS_CPS = "y";
SYS_SUPPORTS_MULTITHREADING = "y";
SYS_SUPPORTS_SCHED_SMT = "y";
SYS_SUPPORTS_SMP = "y";
SYS_SUPPORTS_ZBOOT = "y";
TARGET_ISA_REV = "2";
TICK_CPU_ACCOUNTING = "y";
TIMER_OF = "y";
TIMER_PROBE = "y";
TREE_RCU = "y";
TREE_SRCU = "y";
UBIFS_FS = "y";
USB_SUPPORT = "y";
USE_OF = "y";
WEAK_ORDERING = "y";
XPS = "y";
XXHASH = "y";
ZLIB_DEFLATE = "y";
ZLIB_INFLATE = "y";
ZSTD_COMPRESS = "y";
ZSTD_DECOMPRESS = "y";
}
// lib.optionalAttrs (config.system.service ? watchdog) {
RALINK_WDT = "y"; # watchdog
MT7621_WDT = "y"; # or it might be this one
};
config = {
# Initially taken from openwrt's ./target/linux/ramips/mt7621/config-5.15,
# then tweaked here and there
ARCH_32BIT_OFF_T="y";
ARCH_HIBERNATION_POSSIBLE="y";
ARCH_KEEP_MEMBLOCK="y";
ARCH_MMAP_RND_BITS_MAX="15";
ARCH_MMAP_RND_COMPAT_BITS_MAX="15";
ARCH_SUSPEND_POSSIBLE="y";
AT803X_PHY="y";
BLK_MQ_PCI="y";
BOARD_SCACHE="y";
CEVT_R4K="y";
CLKSRC_MIPS_GIC="y";
CLK_MT7621="y";
CLOCKSOURCE_WATCHDOG="y";
CLONE_BACKWARDS="y";
CMDLINE_BOOL="y";
COMMON_CLK="y";
COMPAT_32BIT_TIME="y";
CPU_GENERIC_DUMP_TLB="y";
CPU_HAS_DIEI="y";
CPU_HAS_PREFETCH="y";
CPU_HAS_RIXI="y";
CPU_HAS_SYNC="y";
CPU_LITTLE_ENDIAN="y";
CPU_MIPS32="y";
CPU_MIPS32_R2="y";
CPU_MIPSR2="y";
CPU_MIPSR2_IRQ_EI="y";
CPU_MIPSR2_IRQ_VI="y";
CPU_NEEDS_NO_SMARTMIPS_OR_MICROMIPS="y";
CPU_R4K_CACHE_TLB="y";
CPU_RMAP="y";
CPU_SUPPORTS_32BIT_KERNEL="y";
CPU_SUPPORTS_HIGHMEM="y";
CPU_SUPPORTS_MSA="y";
CRC16="y";
CRYPTO_DEFLATE="y";
CRYPTO_HASH_INFO="y";
CRYPTO_LIB_BLAKE2S_GENERIC="y";
CRYPTO_LIB_POLY1305_RSIZE="2";
CRYPTO_LZO="y";
CRYPTO_ZSTD="y";
CSRC_R4K="y";
DIMLIB="y";
DMA_NONCOHERENT="y";
DTB_RT_NONE="y";
DTC="y";
EARLY_PRINTK="y";
FIXED_PHY="y";
FWNODE_MDIO="y";
FW_LOADER_PAGED_BUF="y";
GENERIC_ATOMIC64="y";
GENERIC_CLOCKEVENTS="y";
GENERIC_CMOS_UPDATE="y";
GENERIC_CPU_AUTOPROBE="y";
GENERIC_FIND_FIRST_BIT="y";
GENERIC_GETTIMEOFDAY="y";
GENERIC_IOMAP="y";
GENERIC_IRQ_CHIP="y";
GENERIC_IRQ_EFFECTIVE_AFF_MASK="y";
GENERIC_IRQ_SHOW="y";
GENERIC_LIB_ASHLDI3="y";
GENERIC_LIB_ASHRDI3="y";
GENERIC_LIB_CMPDI2="y";
GENERIC_LIB_LSHRDI3="y";
GENERIC_LIB_UCMPDI2="y";
GENERIC_PCI_IOMAP="y";
GENERIC_PHY="y";
GENERIC_PINCONF="y";
GENERIC_SCHED_CLOCK="y";
GENERIC_SMP_IDLE_THREAD="y";
GENERIC_TIME_VSYSCALL="y";
GLOB="y";
GPIOLIB_IRQCHIP="y";
GPIO_CDEV="y";
GPIO_GENERIC="y";
GPIO_MT7621="y";
GRO_CELLS="y";
HANDLE_DOMAIN_IRQ="y";
HARDWARE_WATCHPOINTS="y";
HAS_DMA="y";
HAS_IOMEM="y";
HAS_IOPORT_MAP="y";
I2C="y";
I2C_ALGOBIT="y";
I2C_BOARDINFO="y";
I2C_CHARDEV="y";
I2C_GPIO="y";
I2C_MT7621="y";
ICPLUS_PHY="y";
IRQCHIP="y";
IRQ_DOMAIN="y";
IRQ_DOMAIN_HIERARCHY="y";
IRQ_FORCED_THREADING="y";
IRQ_MIPS_CPU="y";
IRQ_WORK="y";
LIBFDT="y";
LOCK_DEBUGGING_SUPPORT="y";
LZO_COMPRESS="y";
LZO_DECOMPRESS="y";
MDIO_BUS="y";
MDIO_DEVICE="y";
MDIO_DEVRES="y";
MEDIATEK_GE_PHY="y";
MEMFD_CREATE="y";
MFD_SYSCON="y";
MIGRATION="y";
MIKROTIK="y";
MIKROTIK_RB_SYSFS="y";
MIPS="y";
MIPS_ASID_BITS="8";
MIPS_ASID_SHIFT="0";
MIPS_CLOCK_VSYSCALL="y";
MIPS_CM="y";
MIPS_CPC="y";
MIPS_CPS="y";
MIPS_CPU_SCACHE="y";
MIPS_GIC="y";
MIPS_L1_CACHE_SHIFT="5";
MIPS_LD_CAN_LINK_VDSO="y";
MIPS_MT="y";
MIPS_MT_FPAFF="y";
MIPS_MT_SMP="y";
MIPS_NR_CPU_NR_MAP="4";
MIPS_PERF_SHARED_TC_COUNTERS="y";
MIPS_SPRAM="y";
MODULES_USE_ELF_REL="y";
MTD_CMDLINE_PARTS="y";
MTD_NAND_CORE="y";
MTD_NAND_ECC="y";
MTD_NAND_ECC_SW_HAMMING="y";
MTD_NAND_MT7621="y";
MTD_NAND_MTK_BMT="y";
MTD_RAW_NAND="y";
MTD_ROUTERBOOT_PARTS="y";
MTD_SERCOMM_PARTS="y";
MTD_SPI_NOR="y";
MTD_SPLIT_FIT_FW="y";
MTD_SPLIT_MINOR_FW="y";
MTD_SPLIT_SEAMA_FW="y";
MTD_SPLIT_TPLINK_FW="y";
MTD_SPLIT_TRX_FW="y";
MTD_SPLIT_UIMAGE_FW="y";
MTD_UBI="y";
MTD_UBI_BEB_LIMIT="20";
MTD_UBI_BLOCK="y";
MTD_UBI_WL_THRESHOLD="4096";
MTD_VIRT_CONCAT="y";
NEED_DMA_MAP_STATE="y";
NET_DEVLINK="y";
NET_DSA="y";
NET_DSA_MT7530="y";
NET_DSA_MT7530_MDIO="y";
NET_DSA_TAG_MTK="y";
NET_FLOW_LIMIT="y";
NET_MEDIATEK_SOC="y";
NET_SELFTESTS="y";
NET_SWITCHDEV="y";
NET_VENDOR_MEDIATEK="y";
NO_HZ_COMMON="y";
NO_HZ_IDLE="y";
NR_CPUS="4";
NVMEM="y";
OF="y";
OF_ADDRESS="y";
OF_EARLY_FLATTREE="y";
OF_FLATTREE="y";
OF_GPIO="y";
OF_IRQ="y";
OF_KOBJ="y";
OF_MDIO="y";
PAGE_POOL="y";
PAGE_POOL_STATS="y";
PCI="y";
PCIE_MT7621="y";
PCI_DISABLE_COMMON_QUIRKS="y";
PCI_DOMAINS="y";
PCI_DOMAINS_GENERIC="y";
PCI_DRIVERS_GENERIC="y";
PCS_MTK_LYNXI="y";
PERF_USE_VMALLOC="y";
PGTABLE_LEVELS="2";
PHYLIB="y";
PHYLINK="y";
PHY_MT7621_PCI="y";
PINCTRL="y";
PINCTRL_AW9523="y";
PINCTRL_MT7621="y";
PINCTRL_RALINK="y";
PINCTRL_SX150X="y";
POWER_RESET="y";
POWER_RESET_GPIO="y";
POWER_SUPPLY="y";
PTP_1588_CLOCK_OPTIONAL="y";
QUEUED_RWLOCKS="y";
QUEUED_SPINLOCKS="y";
RALINK="y";
RATIONAL="y";
REGMAP="y";
REGMAP_I2C="y";
REGMAP_MMIO="y";
REGULATOR="y";
REGULATOR_FIXED_VOLTAGE="y";
RESET_CONTROLLER="y";
RFS_ACCEL="y";
RPS="y";
RTC_CLASS="y";
RTC_DRV_BQ32K="y";
RTC_DRV_PCF8563="y";
RTC_I2C_AND_SPI="y";
SCHED_SMT="y";
SERIAL_8250="y";
SERIAL_8250_CONSOLE="y";
SERIAL_8250_NR_UARTS="3";
SERIAL_8250_RUNTIME_UARTS="3";
SERIAL_MCTRL_GPIO="y";
SERIAL_OF_PLATFORM="y";
SGL_ALLOC="y";
SMP="y";
SMP_UP="y";
SOCK_RX_QUEUE_MAPPING="y";
SOC_BUS="y";
SOC_MT7621="y";
SPI="y";
SPI_MASTER="y";
SPI_MEM="y";
SPI_MT7621="y";
SRCU="y";
SWPHY="y";
SYNC_R4K="y";
SYSCTL_EXCEPTION_TRACE="y";
SYS_HAS_CPU_MIPS32_R1="y";
SYS_HAS_CPU_MIPS32_R2="y";
SYS_HAS_EARLY_PRINTK="y";
SYS_SUPPORTS_32BIT_KERNEL="y";
SYS_SUPPORTS_ARBIT_HZ="y";
SYS_SUPPORTS_HIGHMEM="y";
SYS_SUPPORTS_HOTPLUG_CPU="y";
SYS_SUPPORTS_LITTLE_ENDIAN="y";
SYS_SUPPORTS_MIPS16="y";
SYS_SUPPORTS_MIPS_CPS="y";
SYS_SUPPORTS_MULTITHREADING="y";
SYS_SUPPORTS_SCHED_SMT="y";
SYS_SUPPORTS_SMP="y";
SYS_SUPPORTS_ZBOOT="y";
TARGET_ISA_REV="2";
TICK_CPU_ACCOUNTING="y";
TIMER_OF="y";
TIMER_PROBE="y";
TREE_RCU="y";
TREE_SRCU="y";
UBIFS_FS="y";
USB_SUPPORT="y";
USE_OF="y";
WEAK_ORDERING="y";
XPS="y";
XXHASH="y";
ZLIB_DEFLATE="y";
ZLIB_INFLATE="y";
ZSTD_COMPRESS="y";
ZSTD_DECOMPRESS="y";
} // lib.optionalAttrs (config.system.service ? watchdog) {
RALINK_WDT = "y"; # watchdog
MT7621_WDT = "y"; # or it might be this one
};
conditionalConfig = {
WLAN = {
MT7915E = "m";
@@ -351,100 +345,98 @@
};
};
filesystem =
let
inherit (pkgs.pseudofile) dir symlink;
in
dir {
lib = dir {
firmware = dir {
mediatek = symlink firmware;
};
};
let inherit (pkgs.pseudofile) dir symlink;
in
dir {
lib = dir {
firmware = dir {
mediatek = symlink firmware;
};
};
};
hardware =
let
openwrt = pkgs.openwrt;
mac80211 = pkgs.kmodloader.override {
targets = [
"mt7915e"
];
inherit (config.system.outputs) kernel;
};
in {
# from OEM bootlog (openwrt wiki):
# 4 cmdlinepart partitions found on MTD device raspi
# Creating 4 MTD partitions on "raspi":
# 0x000000000000-0x000000040000 : "uboot"
# 0x000000040000-0x000000440000 : "uImage"
# 0x000000440000-0x000000ff0000 : "rootfs"
# 0x000000ff0000-0x000001000000 : "ART"
# from openwrt bootlog (openwrt wiki):
# 5 fixed-partitions partitions found on MTD device spi0.0
# OF: Bad cell count for /palmbus@1e000000/spi@b00/flash@0/partitions
# OF: Bad cell count for /palmbus@1e000000/spi@b00/flash@0/partitions
# OF: Bad cell count for /palmbus@1e000000/spi@b00/flash@0/partitions
# OF: Bad cell count for /palmbus@1e000000/spi@b00/flash@0/partitions
# Creating 5 MTD partitions on "spi0.0":
# 0x000000000000-0x000000040000 : "u-boot"
# 0x000000040000-0x000000fa0000 : "firmware"
# 2 uimage-fw partitions found on MTD device firmware
# Creating 2 MTD partitions on "firmware":
# 0x000000000000-0x0000002c0000 : "kernel"
# 0x0000002c0000-0x000000f60000 : "rootfs"
# mtd: setting mtd3 (rootfs) as root device
# 1 squashfs-split partitions found on MTD device rootfs
# 0x000000640000-0x000000f60000 : "rootfs_data"
# 0x000000fa0000-0x000000fb0000 : "config"
# 0x000000fb0000-0x000000ff0000 : "tplink"
# 0x000000ff0000-0x000001000000 : "radio"
flash = {
# from the OEM bootlog 'Booting image at bc040000'
# (0x40000 from 0xbc000000)
address = lim.parseInt "0xbc040000";
# 0x000000040000-0x000000fa0000
size = lim.parseInt "0xf60000";
# TODO: find in /proc/mtd on a running system
eraseBlockSize = 65536;
};
hardware =
let
openwrt = pkgs.openwrt;
mac80211 = pkgs.kmodloader.override {
targets = [
"mt7915e"
];
inherit (config.system.outputs) kernel;
};
in
{
# from OEM bootlog (openwrt wiki):
# 4 cmdlinepart partitions found on MTD device raspi
# Creating 4 MTD partitions on "raspi":
# 0x000000000000-0x000000040000 : "uboot"
# 0x000000040000-0x000000440000 : "uImage"
# 0x000000440000-0x000000ff0000 : "rootfs"
# 0x000000ff0000-0x000001000000 : "ART"
# from openwrt bootlog (openwrt wiki):
# 5 fixed-partitions partitions found on MTD device spi0.0
# OF: Bad cell count for /palmbus@1e000000/spi@b00/flash@0/partitions
# OF: Bad cell count for /palmbus@1e000000/spi@b00/flash@0/partitions
# OF: Bad cell count for /palmbus@1e000000/spi@b00/flash@0/partitions
# OF: Bad cell count for /palmbus@1e000000/spi@b00/flash@0/partitions
# Creating 5 MTD partitions on "spi0.0":
# 0x000000000000-0x000000040000 : "u-boot"
# 0x000000040000-0x000000fa0000 : "firmware"
# 2 uimage-fw partitions found on MTD device firmware
# Creating 2 MTD partitions on "firmware":
# 0x000000000000-0x0000002c0000 : "kernel"
# 0x0000002c0000-0x000000f60000 : "rootfs"
# mtd: setting mtd3 (rootfs) as root device
# 1 squashfs-split partitions found on MTD device rootfs
# 0x000000640000-0x000000f60000 : "rootfs_data"
# 0x000000fa0000-0x000000fb0000 : "config"
# 0x000000fb0000-0x000000ff0000 : "tplink"
# 0x000000ff0000-0x000001000000 : "radio"
flash = {
# from the OEM bootlog 'Booting image at bc040000'
# (0x40000 from 0xbc000000)
address = lim.parseInt "0xbc040000";
# 0x000000040000-0x000000fa0000
size = lim.parseInt "0xf60000";
# TODO: find in /proc/mtd on a running system
eraseBlockSize = 65536;
};
# since this is mentioned in the partition table as well?
defaultOutput = "tplink-safeloader";
# taken from openwrt sysupgrade image:
# openwrt-23.05.2-ramips-mt7621-tplink_archer-ax23-v1-squashfs-sysupgrade.bin: u-boot legacy uImage, MIPS OpenWrt Linux-5.15.137, Linux/MIPS, OS Kernel Image (lzma), 2797386 bytes, Tue Nov 14 13:38:11 2023, Load Address: 0X80001000, Entry Point: 0X80001000, Header CRC: 0X19F74C5B, Data CRC: 0XF685563C
loadAddress = lim.parseInt "0x80001000";
entryPoint = lim.parseInt "0x80001000";
rootDevice = "/dev/mtdblock3";
dts = {
src = "${openwrt.src}/target/linux/ramips/dts/mt7621_tplink_archer-ax23-v1.dts";
includePaths = [
"${openwrt.src}/target/linux/ramips/dts"
"${config.system.outputs.kernel.modulesupport}/arch/arm64/boot/dts/mediatek/"
];
};
networkInterfaces =
let
inherit (config.system.service.network) link;
in
rec {
lan1 = link.build { ifname = "lan1"; };
lan2 = link.build { ifname = "lan2"; };
lan3 = link.build { ifname = "lan3"; };
lan4 = link.build { ifname = "lan4"; };
wan = link.build { ifname = "wan"; };
wlan = link.build {
ifname = "wlan0";
dependencies = [ mac80211 ];
};
wlan5 = link.build {
ifname = "wlan1";
dependencies = [ mac80211 ];
};
};
# since this is mentioned in the partition table as well?
defaultOutput = "tplink-safeloader";
# taken from openwrt sysupgrade image:
# openwrt-23.05.2-ramips-mt7621-tplink_archer-ax23-v1-squashfs-sysupgrade.bin: u-boot legacy uImage, MIPS OpenWrt Linux-5.15.137, Linux/MIPS, OS Kernel Image (lzma), 2797386 bytes, Tue Nov 14 13:38:11 2023, Load Address: 0X80001000, Entry Point: 0X80001000, Header CRC: 0X19F74C5B, Data CRC: 0XF685563C
loadAddress = lim.parseInt "0x80001000";
entryPoint = lim.parseInt "0x80001000";
rootDevice = "/dev/mtdblock3";
dts = {
src = "${openwrt.src}/target/linux/ramips/dts/mt7621_tplink_archer-ax23-v1.dts";
includes = [
"${openwrt.src}/target/linux/ramips/dts"
"${config.system.outputs.kernel.modulesupport}/arch/arm64/boot/dts/mediatek/"
];
};
};
networkInterfaces =
let
inherit (config.system.service.network) link;
inherit (config.system.service) bridge;
in rec {
lan1 = link.build { ifname = "lan1"; };
lan2 = link.build { ifname = "lan2"; };
lan3 = link.build { ifname = "lan3"; };
lan4 = link.build { ifname = "lan4"; };
wan = link.build { ifname = "wan"; };
wlan = link.build {
ifname = "wlan0";
dependencies = [ mac80211 ];
};
wlan5 = link.build {
ifname = "wlan1";
dependencies = [ mac80211 ];
};
};
};
};
};
}
+109 -120
View File
@@ -153,18 +153,13 @@
};
};
module =
{
pkgs,
config,
lib,
lim,
...
}:
module = {pkgs, config, lib, lim, ... }:
let
openwrt = pkgs.openwrt;
inherit (lib) mkOption types;
inherit (pkgs.liminix.services) oneshot;
inherit (pkgs) liminix;
mtd_by_name_links = pkgs.liminix.services.oneshot rec {
mtd_by_name_links = pkgs.liminix.services.oneshot rec {
name = "mtd_by_name_links";
up = ''
mkdir -p /dev/mtd/by-name
@@ -174,18 +169,15 @@
done
'';
};
in
{
in {
imports = [
../../modules/arch/arm.nix
../../modules/outputs/tftpboot.nix
../../modules/outputs/mbrimage.nix
../../modules/outputs/extlinux.nix
];
config = {
rootfsType = lib.mkDefault "btrfs"; # override this if you are building tftpboot
rootOptions = lib.mkDefault "subvol=@";
services.mtd-name-links = mtd_by_name_links;
kernel = {
src = pkgs.pkgsBuildBuild.fetchurl {
@@ -202,7 +194,7 @@
CPU_V7 = "y";
ARCH_MULTIPLATFORM = "y";
ARCH_MVEBU = "y";
ARCH_MULTI_V7 = "y";
ARCH_MULTI_V7= "y";
PCI_MVEBU = "y";
AHCI_MVEBU = "y";
@@ -212,6 +204,7 @@
EXPERT = "y";
ALLOW_DEV_COREDUMP = "n";
# dts has a compatible for this but dmesg is not
# showing it
EEPROM_AT24 = "y"; # atmel,24c64
@@ -222,44 +215,49 @@
MACH_ARMADA_38X = "y";
SMP = "y";
# this is disabled for the moment because it relies on a
# this is disabled for the moment because it relies on a
# GCC plugin that requires gmp.h to build, and I can't see
# right now how to confgure it to find gmp
STACKPROTECTOR_PER_TASK = "n";
NR_CPUS = "4";
VFP = "y";
NEON = "y";
NEON= "y";
# WARNING: unmet direct dependencies detected for ARCH_WANT_LIBATA_LEDS
ATA = "y";
BLOCK = "y";
MMC = "y";
PWRSEQ_EMMC = "y"; # ???
PWRSEQ_SIMPLE = "y"; # ???
MMC_BLOCK = "y";
PSTORE = "y";
PSTORE_RAM = "y";
PSTORE_CONSOLE = "y";
# PSTORE_DEFLATE_COMPRESS = "n";
MMC_SDHCI = "y";
MMC_SDHCI_PLTFM = "y";
MMC_SDHCI_PXAV3 = "y";
MMC_MVSDIO = "y";
BLOCK = "y";
MMC="y";
PWRSEQ_EMMC="y"; # ???
PWRSEQ_SIMPLE="y"; # ???
MMC_BLOCK="y";
MMC_SDHCI= "y";
MMC_SDHCI_PLTFM= "y";
MMC_SDHCI_PXAV3= "y";
MMC_MVSDIO= "y";
SERIAL_8250 = "y";
SERIAL_8250_CONSOLE = "y";
SERIAL_OF_PLATFORM = "y";
SERIAL_OF_PLATFORM="y";
SERIAL_MVEBU_UART = "y";
SERIAL_MVEBU_CONSOLE = "y";
SERIAL_8250_DMA = "y";
SERIAL_8250_DW = "y";
SERIAL_8250_EXTENDED = "y";
SERIAL_8250_MANY_PORTS = "y";
SERIAL_8250_SHARE_IRQ = "y";
OF_ADDRESS = "y";
OF_MDIO = "y";
SERIAL_8250_DMA= "y";
SERIAL_8250_DW= "y";
SERIAL_8250_EXTENDED= "y";
SERIAL_8250_MANY_PORTS= "y";
SERIAL_8250_SHARE_IRQ= "y";
OF_ADDRESS= "y";
OF_MDIO= "y";
WATCHDOG = "y"; # watchdog is enabled by u-boot
ORION_WATCHDOG = "y"; # so is non-optional to keep feeding
WATCHDOG = "y"; # watchdog is enabled by u-boot
ORION_WATCHDOG = "y"; # so is non-optional to keep feeding
MVEBU_DEVBUS = "y"; # "Device Bus controller ... flash devices such as NOR, NAND, SRAM, and FPGA"
MVMDIO = "y";
@@ -302,7 +300,6 @@
};
};
boot = {
loader.extlinux.enable = lib.mkDefault true; # override this if you are building tftpboot
commandLine = [
"console=ttyS0,115200"
"pcie_aspm=off" # ath9k pci incompatible with PCIe ASPM
@@ -313,14 +310,13 @@
inherit (pkgs.pseudofile) dir symlink;
firmware = pkgs.stdenv.mkDerivation {
name = "wlan-firmware";
phases = [ "installPhase" ];
phases = ["installPhase"];
installPhase = ''
mkdir $out
cp -r ${pkgs.linux-firmware}/lib/firmware/ath10k/QCA988X $out
'';
};
in
dir {
in dir {
lib = dir {
firmware = dir {
ath10k = symlink firmware;
@@ -328,12 +324,10 @@
};
etc = dir {
"fw_env.config" =
let
f = pkgs.writeText "fw_env.config" ''
/dev/mtd/by-name/u-boot-env 0x0 0x10000 0x10000
'';
in
symlink f;
let f = pkgs.writeText "fw_env.config" ''
/dev/mtd/by-name/u-boot-env 0x0 0x10000 0x10000
'';
in symlink f;
};
};
@@ -343,81 +337,76 @@
compressRoot = true;
};
hardware =
let
mac80211 = pkgs.kmodloader.override {
inherit (config.system.outputs) kernel;
targets = [
"ath9k"
"ath10k_pci"
];
};
in
{
defaultOutput = "updater";
loadAddress = lim.parseInt "0x00800000"; # "0x00008000";
entryPoint = lim.parseInt "0x00800000"; # "0x00008000";
rootDevice = "/dev/mmcblk0p1";
dts = {
src = "${config.system.outputs.kernel.modulesupport}/arch/arm/boot/dts/marvell/armada-385-turris-omnia.dts";
includePaths = [
"${config.system.outputs.kernel.modulesupport}/arch/arm/boot/dts/marvell/"
];
};
flash.eraseBlockSize = 65536; # only used for tftpboot
networkInterfaces =
let
inherit (config.system.service.network) link;
in
rec {
en70000 = link.build {
# in armada-38x.dtsi this is eth0.
# It's connected to port 5 of the 88E6176 switch
devpath = "/devices/platform/soc/soc:internal-regs/f1070000.ethernet";
# name is unambiguous but not very semantic
ifname = "en70000";
};
en30000 = link.build {
# in armada-38x.dtsi this is eth1
# It's connected to port 6 of the 88E6176 switch
devpath = "/devices/platform/soc/soc:internal-regs/f1030000.ethernet";
# name is unambiguous but not very semantic
ifname = "en30000";
};
# the default (from the dts? I'm guessing) behavour for
# lan ports on the switch is to attach them to
# en30000. It should be possible to do something better,
# per
# https://www.kernel.org/doc/html/latest/networking/dsa/configuration.html#affinity-of-user-ports-to-cpu-ports
# but apparently OpenWrt doesn't either so maybe it's more
# complicated than it looks.
wan = link.build {
# in armada-38x.dtsi this is eth2. It may be connected to
# an ethernet phy or to the SFP cage, depending on a gpio
devpath = "/devices/platform/soc/soc:internal-regs/f1034000.ethernet";
ifname = "wan";
};
lan0 = link.build { ifname = "lan0"; };
lan1 = link.build { ifname = "lan1"; };
lan2 = link.build { ifname = "lan2"; };
lan3 = link.build { ifname = "lan3"; };
lan4 = link.build { ifname = "lan4"; };
lan5 = link.build { ifname = "lan5"; };
lan = lan0; # maybe we should build a bridge?
wlan = link.build {
ifname = "wlan0";
dependencies = [ mac80211 ];
};
wlan5 = link.build {
ifname = "wlan1";
dependencies = [ mac80211 ];
};
};
hardware = let
mac80211 = pkgs.kmodloader.override {
inherit (config.system.outputs) kernel;
targets = ["ath9k" "ath10k_pci"];
};
in {
defaultOutput = "mtdimage";
loadAddress = lim.parseInt "0x00800000"; # "0x00008000";
entryPoint = lim.parseInt "0x00800000"; # "0x00008000";
rootDevice = "/dev/mmcblk0p1";
dts = {
src = "${config.system.outputs.kernel.modulesupport}/arch/arm/boot/dts/marvell/armada-385-turris-omnia.dts";
includes = [
"${config.system.outputs.kernel.modulesupport}/arch/arm/boot/dts/marvell/"
];
};
flash.eraseBlockSize = 65536; # only used for tftpboot
networkInterfaces =
let
inherit (config.system.service.network) link;
inherit (config.system.service) bridge;
in rec {
en70000 = link.build {
# in armada-38x.dtsi this is eth0.
# It's connected to port 5 of the 88E6176 switch
devpath = "/devices/platform/soc/soc:internal-regs/f1070000.ethernet";
# name is unambiguous but not very semantic
ifname = "en70000";
};
en30000 = link.build {
# in armada-38x.dtsi this is eth1
# It's connected to port 6 of the 88E6176 switch
devpath = "/devices/platform/soc/soc:internal-regs/f1030000.ethernet";
# name is unambiguous but not very semantic
ifname = "en30000";
};
# the default (from the dts? I'm guessing) behavour for
# lan ports on the switch is to attach them to
# en30000. It should be possible to do something better,
# per
# https://www.kernel.org/doc/html/latest/networking/dsa/configuration.html#affinity-of-user-ports-to-cpu-ports
# but apparently OpenWrt doesn't either so maybe it's more
# complicated than it looks.
wan = link.build {
# in armada-38x.dtsi this is eth2. It may be connected to
# an ethernet phy or to the SFP cage, depending on a gpio
devpath = "/devices/platform/soc/soc:internal-regs/f1034000.ethernet";
ifname = "wan";
};
lan0 = link.build { ifname = "lan0"; };
lan1 = link.build { ifname = "lan1"; };
lan2 = link.build { ifname = "lan2"; };
lan3 = link.build { ifname = "lan3"; };
lan4 = link.build { ifname = "lan4"; };
lan5 = link.build { ifname = "lan5"; };
lan = lan0; # maybe we should build a bridge?
wlan = link.build {
ifname = "wlan0";
dependencies = [ mac80211 ];
};
wlan5 = link.build {
ifname = "wlan1";
dependencies = [ mac80211 ];
};
};
};
};
};
}
@@ -1,155 +0,0 @@
#include "mt7621.dtsi"
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/input/input.h>
/ {
aliases {
label-mac-device = &gmac0;
};
};
&nand {
status = "okay";
mediatek,nmbm;
mediatek,bmt-max-ratio = <15>;
mediatek,bmt-max-reserved-blocks = <64>;
mediatek,bmt-remap-range =
<0x0 0x980000>,
<0x2980000 0x7800000>;
partitions {
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
partition@0 {
label = "u-boot";
reg = <0x0 0x80000>;
read-only;
};
partition@80000 {
label = "u-boot-env";
reg = <0x80000 0x80000>;
read-only;
};
factory: partition@100000 {
label = "factory";
reg = <0x100000 0x80000>;
read-only;
};
partition@180000 {
label = "firmware_a";
reg = <0x180000 0x2800000>;
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
partition@0 {
label = "kernel_a";
reg = <0x0 0x800000>;
};
partition@400000 {
label = "ubi";
reg = <0x800000 0x2000000>;
};
};
partition@2980000 {
label = "firmware_b";
reg = <0x2980000 0x2800000>;
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
partition@0 {
label = "kernel_b";
reg = <0x0 0x800000>;
};
partition@400000 {
label = "ubi_b";
reg = <0x800000 0x2000000>;
};
};
partition@5180000 {
label = "rootfs_data";
reg = <0x5180000 0x1400000>;
};
partition@6580000 {
label = "logs";
reg = <0x6580000 0xd00000>;
};
partition@7280000 {
label = "vendor-myzyxel";
reg = <0x7280000 0x480000>;
read-only;
};
partition@7700000 {
label = "bootconfig";
reg = <0x7700000 0x80000>;
};
mrd: partition@7780000 {
label = "mrd";
reg = <0x7780000 0x80000>;
read-only;
nvmem-layout {
compatible = "fixed-layout";
#address-cells = <1>;
#size-cells = <1>;
macaddr_mrd_1fff8: macaddr@1fff8 {
reg = <0x1fff8 0x6>;
};
};
};
};
};
&pcie {
status = "okay";
};
&pcie1 {
wlan_5g: wifi@0,0 {
reg = <0x0 0 0 0 0>;
compatible = "mediatek,mt76";
mediatek,mtd-eeprom = <&factory 0x0>;
/* MAC-Address set in userspace */
};
};
&gmac0 {
nvmem-cells = <&macaddr_mrd_1fff8>;
nvmem-cell-names = "mac-address";
};
&switch0 {
ports {
port@4 {
status = "okay";
label = "lan";
};
};
};
&state_default {
gpio {
groups = "uart3";
function = "gpio";
};
};
@@ -1,155 +0,0 @@
#include "mt7621.dtsi"
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/input/input.h>
/ {
aliases {
label-mac-device = &gmac0;
};
};
&nand {
status = "okay";
mediatek,nmbm;
mediatek,bmt-max-ratio = <15>;
mediatek,bmt-max-reserved-blocks = <64>;
mediatek,bmt-remap-range =
<0x0 0x980000>,
<0x2980000 0x7800000>;
partitions {
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
partition@0 {
label = "u-boot";
reg = <0x0 0x80000>;
read-only;
};
partition@80000 {
label = "u-boot-env";
reg = <0x80000 0x80000>;
read-only;
};
factory: partition@100000 {
label = "factory";
reg = <0x100000 0x80000>;
read-only;
};
partition@2980000 {
label = "firmware_b";
reg = <0x2980000 0x2800000>;
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
partition@0 {
label = "kernel_b";
reg = <0x0 0x800000>;
};
partition@400000 {
label = "ubi";
reg = <0x800000 0x2000000>;
};
};
partition@180000 {
label = "firmware_a";
reg = <0x180000 0x2800000>;
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
partition@0 {
label = "kernel_a";
reg = <0x0 0x800000>;
};
partition@400000 {
label = "ubi_a";
reg = <0x800000 0x2000000>;
};
};
partition@5180000 {
label = "rootfs_data";
reg = <0x5180000 0x1400000>;
};
partition@6580000 {
label = "logs";
reg = <0x6580000 0xd00000>;
};
partition@7280000 {
label = "vendor-myzyxel";
reg = <0x7280000 0x480000>;
read-only;
};
partition@7700000 {
label = "bootconfig";
reg = <0x7700000 0x80000>;
};
mrd: partition@7780000 {
label = "mrd";
reg = <0x7780000 0x80000>;
read-only;
nvmem-layout {
compatible = "fixed-layout";
#address-cells = <1>;
#size-cells = <1>;
macaddr_mrd_1fff8: macaddr@1fff8 {
reg = <0x1fff8 0x6>;
};
};
};
};
};
&pcie {
status = "okay";
};
&pcie1 {
wlan_5g: wifi@0,0 {
reg = <0x0 0 0 0 0>;
compatible = "mediatek,mt76";
mediatek,mtd-eeprom = <&factory 0x0>;
/* MAC-Address set in userspace */
};
};
&gmac0 {
nvmem-cells = <&macaddr_mrd_1fff8>;
nvmem-cell-names = "mac-address";
};
&switch0 {
ports {
port@4 {
status = "okay";
label = "lan";
};
};
};
&state_default {
gpio {
groups = "uart3";
function = "gpio";
};
};
-371
View File
@@ -1,371 +0,0 @@
{
system = {
crossSystem = {
config = "mipsel-unknown-linux-musl";
gcc = {
abi = "32";
arch = "mips32"; # mips32r2?
};
};
};
description = ''
Zyxel NWA50AX
********************
Zyxel NWA50AX is quite close to the GL-MT300N-v2 "Mango" device, but it is based on the MT7621
chipset instead of the MT7628.
Installation
============
This device is pretty, but, due to its A/B capabilities, can be a bit hard
to use completely.
The stock vendor firmware is a downstream fork of U-Boot: <https://github.com/RaitoBezarius/uboot-nwa50ax>
with restricted boot commands. Fortunately, OpenWrt folks figured out trivial command injections,
so you can use most of the OpenWrt commands without trouble by just command injecting
atns, atna or atnf, e.g. atns "; $real_command".
From factory web UI, you can upload the result of the zyxel-nwa-fit output.
From another operating system, you need to `dumpimage -T flat_dt -p 0 $zyxel-nwa-fit -o firmware.bin`,
`flash_erase $(mtd partition of the target partition firmware or zy_firmware) 0 0`, then you complete by
`nandwrite -p $(mtd partition of the target partition firmware or zy_firmware) firmware.bin`.
How to put the firmware.bin on the machine is left to you as an exercise, e.g. SSH, TFTP, whatever.
From serial, you have two choices:
- Flash this system via U-Boot:
same reasoning as from an existing Linux system, two choices:
- ymodem the binary, perform the write manually, you can inspire yourself
from the `script` contained in the vendor firmware, those are just a FIT containing a script.
- prepare a FIT containing a script executing your commands, tftpboot this.
- boot from an existing Liminix system, e.g. TFTPBOOT image.
- boot from an OpenWrt system, i.e. follow OpenWrt steps.
Once you are in a Linux system, understand that this device has A/B boot.
OpenWrt provides you with `zyxel-bootconfig` to set/unset the image status and choice.
The kernel is booted with `bootImage=<number>` which tells you which slot are you on.
You should find yourself with 10ish MTD partitions, the most interesting ones are two:
- firmware: 40MB
- firmware_1: 40MB
In the current setup, they are split further into kernel (8MB) and ubi (32MB).
Once you are done with first installation, note that if you want to use the A/B feature,
you need to write a _secondary_ image on the slot B. There is no proper flashing code
that will set the being-updated slot to `new` and boot on it to verify if it's working.
This is a WIP.
Upgrading your system can be achieved via:
- `liminix-rebuild` for the userspace.
- `flash_erase` + `nandwrite` for the kernelspace to the other slot than the one you are booted on,
note that you can just nandwrite the mtd partition corresponding to the *kernel* and not the whole firmware.
If you soft-bricked your AP, i.e. you cannot boot anything in U-Boot, no worries, just plug the serial console,
prepare a TFTP server (via `tufted` for example), download vendor firmware, set up `atns`, `atnf`, etc. and run `atnz`.
This will reflash everything back to normal via TFTP.
If you hard-bricked your AP, i.e. U-Boot is telling you to transfer a valid bootloader via ymodem, just extract
a U-Boot from the vendor OS, send it via ymodem and use the previous operations to perform a full flash this time
of all partitions.
Note that if you erased your MRD partition, you lost your serial and MAC address. There's no way to recover the original one
except by reading the physical label on your… device!
If you super-hard-bricked your AP, i.e. no output on serial console, congratulations, you reached one of the rare state
of this device. You need an external NAND flasher to repair it and write the first stage from Mediatek to continue the previous
recovery operations.
Development TODO list:
- Better support for upgrade automation w.r.t. to A/B, e.g. automagic scripts.
- Mount the logs partition, mount / as overlayfs of firmware ? rootfs and rootfs_data for extended data.
- Jitter-based entropy injection? Device can be slow to initialize its CRNG and hostapd will reject few clients at the start because of that.
- Defaults for hostapd based on MT7915 capabilities? See the example for one possible list.
- Remove primary/secondary hack and put it in preinit.
- Offer ways to reflash the *bootloader* itself to support direct boot via UBI and kernel upgrades via filesystem rewrite.
Vendor web page: https://www.zyxel.com/fr/fr/products/wireless/ax1800-wifi-6-dual-radio-nebulaflex-access-point-nwa50ax
OpenWrt web page: https://openwrt.org/inbox/toh/zyxel/nwa50ax
OpenWrt tech data: https://openwrt.org/toh/hwdata/zyxel/zyxel_nwa50ax
'';
module =
{
pkgs,
config,
lib,
lim,
...
}:
let
inherit (pkgs.pseudofile) dir symlink;
inherit (pkgs) openwrt;
mac80211 = pkgs.mac80211.override {
drivers = [ "mt7915e" ];
klibBuild = config.system.outputs.kernel.modulesupport;
};
# v204520220929
wlan_firmware = pkgs.fetchurl {
url = "https://github.com/openwrt/mt76/raw/1b88dd07f153b202e57fe29734806744ed006b0e/firmware/mt7915_wa.bin";
hash = "sha256-wooyefzb0i8640+lwq3vNhcBXRFCtGuo+jiL7afZaKA=";
};
wlan_firmware' = pkgs.fetchurl {
url = "https://github.com/openwrt/mt76/raw/1b88dd07f153b202e57fe29734806744ed006b0e/firmware/mt7915_wm.bin";
hash = "sha256-k62nQewRuKjBLd5R3RxU4F74YKnQx5zr6gqMMImqVQw=";
};
wlan_firmware'' = pkgs.fetchurl {
url = "https://github.com/openwrt/mt76/raw/1b88dd07f153b202e57fe29734806744ed006b0e/firmware/mt7915_rom_patch.bin";
hash = "sha256-ifriAjWzFACrxVWCANZpUaEZgB/0pdbhnTVQytx6ddg=";
};
in
{
imports = [
# We include it to ensure the bridge functionality
# is available on the target kernel.
../../modules/bridge
../../modules/arch/mipsel.nix
../../modules/outputs/tftpboot.nix
../../modules/outputs/zyxel-nwa-fit.nix
../../modules/zyxel-dual-image
];
filesystem = dir {
lib = dir {
firmware = dir {
mediatek = dir {
"mt7915_wa.bin" = symlink wlan_firmware;
"mt7915_wm.bin" = symlink wlan_firmware';
"mt7915_rom_patch.bin" = symlink wlan_firmware'';
};
};
};
};
rootfsType = "ubifs";
hardware = {
# Taken from OpenWRT
# root@OpenWrt:/# ubinfo /dev/ubi0
# ubi0
# Volumes count: 2
# Logical eraseblock size: 126976 bytes, 124.0 KiB
# Total amount of logical eraseblocks: 256 (32505856 bytes, 31.0 MiB)
# Amount of available logical eraseblocks: 0 (0 bytes)
# Maximum count of volumes 128
# Count of bad physical eraseblocks: 0
# Count of reserved physical eraseblocks: 19
# Current maximum erase counter value: 2
# Minimum input/output unit size: 2048 bytes
# Character device major/minor: 250:0
# Present volumes: 0, 1
ubi = {
minIOSize = "2048";
logicalEraseBlockSize = "126976";
physicalEraseBlockSize = "128KiB";
maxLEBcount = "256";
};
# This is a FIT containing a kernel padded and
# a UBI volume rootfs.
defaultOutput = "zyxel-nwa-fit";
loadAddress = lim.parseInt "0x80001000";
entryPoint = lim.parseInt "0x80001000";
# Aligned on 2kb.
alignment = 2048;
rootDevice = "ubi:rootfs";
dts = {
# Actually, this is not what we want.
# This DTS is insufficient.
src = ./mt7621_zyxel_nwa50ax.dtsi;
includePaths = [
# Here's one weird trick to make `ubi` detection
# out of the box.
# We will write ubi on /dev/firmware_a:rootfs location
# and same for /dev/firmware_b:rootfs.
# How do we distinguish both?
# We can just use the DTS to point ubi at A or B.
# This, unfortunately, means that we have "two images".
# But they are really just 1 image with 2 different DTS.
# TODO: improve this hack in preinit?
(if config.boot.imageType == "primary" then "${./a_image}" else "${./b_image}")
"${openwrt.src}/target/linux/ramips/dts"
];
};
networkInterfaces =
let
inherit (config.system.service.network) link;
in
{
eth = link.build { ifname = "eth0"; };
lan = link.build { ifname = "lan"; };
wlan0 = link.build {
ifname = "wlan0";
dependencies = [ mac80211 ];
};
wlan1 = link.build {
ifname = "wlan1";
dependencies = [ mac80211 ];
};
};
};
boot = {
# Critical because NWA50AX will extend your cmdline with the image number booted.
# and some bootloader version.
# You don't want to find yourself being overridden.
commandLineDtbNode = "bootargs-override";
imageFormat = "fit";
tftp = {
# 5MB is nice.
freeSpaceBytes = 5 * 1024 * 1024;
loadAddress = lim.parseInt "0x2000000";
};
};
# Dual image management service in userspace.
services.zyxel-dual-image = config.boot.zyxel-dual-image.build {
ensureActiveImage = "primary";
# TODO: use mtd names rather…
# primary and secondary are always /dev/mtd3 by virtue of the
# dtb being not too wrong…
# TODO: remove this hack.
primaryMtdPartition = "/dev/mtd3";
secondaryMtdPartition = "/dev/mtd3";
bootConfigurationMtdPartition = "/dev/mtd12";
};
# DEVICE_VENDOR := ZyXEL
# KERNEL_SIZE := 8192k
# DEVICE_PACKAGES := kmod-mt7915-firmware zyxel-bootconfig
# KERNEL := kernel-bin | lzma | fit lzma $$(KDIR)/image-$$(firstword $$(DEVICE_DTS)).dtb
# IMAGES += factory.bin ramboot-factory.bin
# IMAGE/factory.bin := append-kernel | pad-to $$(KERNEL_SIZE) | append-ubi | zyxel-nwa-fit
# IMAGE/ramboot-factory.bin := append-kernel | pad-to $$(KERNEL_SIZE) | append-ubi
kernel = {
extraPatchPhase = ''
${openwrt.applyPatches.ramips}
'';
config =
{
RALINK = "y";
PCI = "y";
PHY_MT7621_PCI = "y";
PCIE_MT7621 = "y";
SOC_MT7621 = "y";
CLK_MT7621 = "y";
CLOCKSOURCE_WATCHDOG = "y";
SERIAL_8250_CONSOLE = "y";
SERIAL_8250 = "y";
SERIAL_CORE_CONSOLE = "y";
SERIAL_OF_PLATFORM = "y";
SERIAL_8250_NR_UARTS = "3";
SERIAL_8250_RUNTIME_UARTS = "3";
SERIAL_MCTRL_GPIO = "y";
CONSOLE_LOGLEVEL_DEFAULT = "8";
CONSOLE_LOGLEVEL_QUIET = "4";
# MTD_UBI_BEB_LIMIT = "20";
# MTD_UBI_WL_THRESHOLD = "4096";
MTD = "y";
MTD_BLOCK = "y"; # fix undefined ref to register_mtd_blktrans_dev
MTD_RAW_NAND = "y";
MTD_NAND_MT7621 = "y";
MTD_NAND_MTK_BMT = "y"; # Bad-block Management Table
MTD_NAND_ECC_SW_HAMMING = "y";
MTD_SPI_NAND = "y";
MTD_OF_PARTS = "y";
MTD_NAND_CORE = "y";
MTD_SPLIT_FIRMWARE = "y";
MTD_SPLIT_FIT_FW = "y";
PINCTRL = "y";
PINCTRL_MT7621 = "y";
I2C = "y";
I2C_MT7621 = "y";
SPI = "y";
MTD_SPI_NOR = "y";
SPI_MT7621 = "y";
SPI_MASTER = "y";
SPI_MEM = "y";
REGULATOR = "y";
REGULATOR_FIXED_VOLTAGE = "y";
RESET_CONTROLLER = "y";
POWER_RESET = "y";
POWER_RESET_GPIO = "y";
POWER_SUPPLY = "y";
LED_TRIGGER_PHY = "y";
PCI_DISABLE_COMMON_QUIRKS = "y";
PCI_DOMAINS = "y";
PCI_DOMAINS_GENERIC = "y";
PCI_DRIVERS_GENERIC = "y";
PCS_MTK_LYNXI = "y";
SOC_BUS = "y";
NET = "y";
ETHERNET = "y";
WLAN = "y";
PHYLIB = "y";
AT803X_PHY = "y";
FIXED_PHY = "y";
GENERIC_PHY = "y";
NET_DSA = "y";
NET_DSA_MT7530 = "y";
NET_DSA_MT7530_MDIO = "y";
NET_DSA_TAG_MTK = "y";
NET_MEDIATEK_SOC = "y";
NET_SWITCHDEV = "y";
NET_VENDOR_MEDIATEK = "y";
SWPHY = "y";
GPIOLIB = "y";
GPIO_MT7621 = "y";
OF_GPIO = "y";
EARLY_PRINTK = "y";
NEW_LEDS = "y";
LEDS_TRIGGERS = "y";
LEDS_CLASS = "y"; # required by rt2x00lib
LEDS_CLASS_MULTICOLOR = "y";
LEDS_BRIGHTNESS_HW_CHANGED = "y";
PRINTK_TIME = "y";
}
// lib.optionalAttrs (config.system.service ? vlan) {
SWCONFIG = "y";
}
// lib.optionalAttrs (config.system.service ? watchdog) {
RALINK_WDT = "y"; # watchdog
MT7621_WDT = "y"; # or it might be this one
};
};
};
}
@@ -1,56 +0,0 @@
#include "mt7621_zyxel_nwa-ax-for-ab.dtsi"
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/input/input.h>
/ {
compatible = "zyxel,nwa50ax", "mediatek,mt7621-soc";
model = "ZyXEL NWA50AX";
aliases {
led-boot = &led_system_green;
led-failsafe = &led_system_red;
led-running = &led_system_green;
led-upgrade = &led_system_red;
};
leds {
compatible = "gpio-leds";
led_system_red: system_red {
label = "red:system";
gpios = <&gpio 6 GPIO_ACTIVE_HIGH>;
};
led_system_green: system_green {
label = "green:system";
gpios = <&gpio 7 GPIO_ACTIVE_HIGH>;
};
system_blue {
label = "blue:system";
gpios = <&gpio 8 GPIO_ACTIVE_HIGH>;
};
};
keys {
compatible = "gpio-keys";
reset {
label = "reset";
gpios = <&gpio 30 GPIO_ACTIVE_LOW>;
linux,code = <KEY_RESTART>;
};
};
};
&ethernet {
pinctrl-0 = <&mdio_pins>, <&rgmii1_pins>;
};
&state_default {
gpio {
groups = "uart3", "rgmii2";
function = "gpio";
};
};
+139 -312
View File
@@ -4,247 +4,155 @@ System Administration
Services on a running system
****************************
Liminix services are built on s6-rc, which is itself layered on s6.
Services are defined at build time in your configuration (see
:ref:`configuration-services` for information) and can't be added
to/changed at runtime, but to monitor
events or diagnose problems you may need to inspect them on the
running system. Here are some of the most commonly used s6,-rc
commands:
* add an s6-rc cheatsheet here
.. list-table:: Service management quick reference
:widths: 55 45
:header-rows: 1
* - What
- How
* - List all running services
- ``s6-rc -a list``
* - List all services that are **not** running
- ``s6-rc -da list``
* - List services that ``wombat`` depends on
- ``s6-rc-db dependencies wombat``
* - ... transitively
- ``s6-rc-db all-dependencies wombat``
* - List services that depend on service ``wombat``
- ``s6-rc-db -d dependencies wombat``
* - ... transitively
- ``s6-rc-db -d all-dependencies wombat``
* - Stop service ``wombat`` and everything depending on it
- ``s6-rc -d change wombat``
* - Start service ``wombat`` (but not any services depending on it)
- ``s6-rc -u change wombat``
* - Start service ``wombat`` and all* services depending on it
- ``s6-rc-up-tree wombat``
:command:`s6-rc-up-tree` brings up a service and all services that
depend on it, except for any services that depend on a "controlled"
service that is not currently running. Controlled services are not
started at boot time but in response to external events (e.g. plugging
in a particular piece of hardware) so you probably don't want to be
starting them by hand if the conditions aren't there.
Flashing and updating
*********************
A service may be **up** or **down** (there are no intermediate states
like "started" or "stopping" or "dying" or "cogitating"). Some (but
not all) services have "readiness" notifications: the dependents of a
service with a readiness notification won't be started until the
service signals (by writing to a nominated file descriptor) that it's
prepared to start work. Most services defined by Liminix also have a
``timeout-up`` parameter, which means that if a service has readiness
notifications and doesn't become ready in the allotted time (defaults
20 seconds) it will be terminated and its state set to **down**.
If the process providing a service dies, it will be restarted
automatically. Liminix does not automatically set it to **down**.
(If the process providing a service dies without ever notifying
readiness, Liminix will restart it as many times as it has to until the
timeout period elapses, and then stop it and mark it down.)
Flashing from Liminix
=====================
Controlled services
===================
The flash procedure from an existing Liminix-system has two steps.
First we reboot the device (using "kexec") into an "ephemeral"
RAM-based version of the new configuration, then when we're happy it
works we can flash the image - and if it doesn't work we can reboot
the device again and it will boot from the old image.
**Controlled** services are those which are started/stopped on demand
by a **controller** (another service) instead of being started at boot
time. For example:
* ``svc.uevent-rule.build`` creates a controlled service which is
active when a particular hardware device (identified by uevent/sysfs
directory) is present.
Building the RAM-based image
----------------------------
* ``svc.round-robin.build`` creates a service controller that
invokes two or more services in turn, running the next one when the
process providing the previous one exits. We use this for failover
from one network connection to a backup connection, for example.
To create the ephemeral image, build ``outputs.kexecboot`` instead of
``outputs.default``. This generates a directory containing the root
filesystem image and kernel, along with an executable called `kexec`
and a `boot.sh` script that runs it with appropriate arguments.
* ``svc.health-check.build`` creates a service controller that
runs a controlled service and periodically tests whether it is
healthy by running an external health check command or script. If the
check command repeatedly fails, the controlled service is
restarted.
The Configuration section of the manual describes controlled
services in more detail. Some operational considerations
* ``round-robin`` detects a service status by looking at its
:file:`outputs` directory, so it won't work unless the service
creates some outputs. This is considered a bug and will be
fixed in a future release
* ``health-check`` works for longruns but not for oneshots, as it
internally relies on ``s6-svc`` to restart the process
Logs
====
Logs for all services are collated into :file:`/run/log/current`.
The log file is rotated when it reaches a threshold size, into another
file in the same directory whose name contains a TAI64 timestamp.
Each log line is prefixed with a TAI64 timestamp and the name of the
service, if it is a longrun. If it is a oneshot, a timestamp and the
name of some other service. To convert the timestamp into a
human-readable format, use :command:`s6-tai64nlocal`.
For example
.. code-block:: console
# ls -l /run/log/
-rw-r--r-- 1 0 lock
-rw-r--r-- 1 0 state
-rwxr--r-- 1 98059 @4000000000025cb629c311ac.s
-rwxr--r-- 1 98061 @40000000000260f7309c7fb4.s
-rwxr--r-- 1 98041 @40000000000265233a6cc0b6.s
-rwxr--r-- 1 98019 @400000000002695d10c06929.s
-rwxr--r-- 1 98064 @4000000000026d84189559e0.s
-rwxr--r-- 1 98055 @40000000000271ce1e031d91.s
-rwxr--r-- 1 98054 @400000000002760229733626.s
-rwxr--r-- 1 98104 @4000000000027a2e3b6f4e12.s
-rwxr--r-- 1 98023 @4000000000027e6f0ed24a6c.s
-rw-r--r-- 1 42374 current
# tail -2 /run/log/current
@40000000000284f130747343 wan.link.pppoe Connect: ppp0 <--> /dev/pts/0
@40000000000284f230acc669 wan.link.pppoe sent [LCP ConfReq id=0x1 <asyncmap 0x0> <magic 0x667a9594> <pcomp> <accomp>]
# tail -2 /run/log/current | s6-tai64nlocal
1970-01-02 21:51:45.828598156 wan.link.pppoe sent [LCP ConfReq id=0x1 <asyncmap 0x0> <magic 0x667a9594> <pcomp> <accom
p>]
1970-01-02 21:51:48.832588765 wan.link.pppoe sent [LCP ConfReq id=0x1 <asyncmap 0x0> <magic 0x667a9594> <pcomp> <accom
p>]
nix-build -I liminix-config=./examples/arhcive.nix \
--arg device "import ./devices/gl-ar750"
-A outputs.kexecboot && \
(tar chf - result | ssh root@the-device tar -C /run -xvf -)
Log persistence
---------------
Logs written to :file:`/run/log/` will not survive a reboot or crash,
as it is an ephemeral filesystem.
On supported hardware you can enable logging to `pstore
<https://www.kernel.org/doc/Documentation/ABI/testing/pstore>`_ which
means the most recent log messages will be preserved on reboot. Set
the config option ``logging.persistent.enable = true`` to log messages
to :file:`/dev/pmsg0` as well as to the regular log. This is a
circular buffer, so when it fills up newer messages will overwrite the
oldest messages.
Logs found in pstore after a reboot will be moved at startup to
:file:`/run/log/previous-boot`
Updating an installed system
****************************
If your system has a writable root filesystem (JFFS2, btrfs etc -
anything but squashfs), we have mechanisms for in-places updates
analogous to :command:`nixos-rebuild`, but the operation is a bit
different because it expects to run on a build machine and then copy
to the host device using :command:`ssh`.
To use this, build the ``outputs.updater``
target and then run the :command:`update.sh` script it generates.
and then login to the device and run
.. code-block:: console
nix-build -I liminix-config=./my-configuration.nix \
--arg device "import ./devices/mydevice" \
-A outputs.updater
./result/bin/update.sh root@the-device
The update script uses min-copy-closure to copy new or changed
packages to the device, then (perhaps) reboots it. The reboot
behaviour can be affected by flags:
* `--no-reboot` will cause it not to reboot at all, if you would
rather do that yourself. Note that none of the newly-installed or
updated services will be running until you do.
* `--fast` causes it tn not do a full reboot, but instead to restart
only the services that have been changed. This will restart all of
the services that have updated store paths (and anything that
depends on them), but will not affect services that haven't changed.
It doesn't delete old packages automatically: to do that run
:command:`min-collect-garbage`, which will delete any packages not in
the current system closure. Note that Liminix does not have the NixOS
concept of environments or generations, and there is no way back from
this except for building the previous configuration again.
Caveats
-------
* it needs there to be enough free space on the device for all the new
packages in addition to all the packages already on it - which may
be a problem if there is little flash storage or if a lot of things
have changed (e.g. a new version of nixpkgs).
* it may not be able to upgrade the kernel: this is device-dependent.
If your device boots from a kernel image on a raw MTD partition or
or UBI volume, update.sh is unable to alter the kernel partition.
If your device boots from a kernel inside the filesystem (e.g. using
bootloader.extlinux or bootloder.fit) then the kernel will be
upgraded along with the userland
cd /run/result
sh ./boot.sh .
Recovery/downgrades
-------------------
This will load the new kernel and map the root filesystem into a RAM
disk, then start executing the new kernel. *This is effectively a
reboot - be sure to close all open files and finish anything else
you were doing first.*
The :command:`update.sh` script also creates a timestamped symlink on
the device which points to the system configuration it installs. If
you install a configuration that doesn't work, you can revert to any
other installed configuration by
If the new system crashes or is rebooted, then the device will revert
to the old configuration it finds in flash.
1) booting to some kind of rescue or recovery system (which may be
some vendor-provided rescue option, or your own recovery system
perhaps based on :file:`examples/recovery.nix`) and mounting
your Liminix filesystem on /mnt
2) picking another previously-installed configuration that _did_ work,
and switching back to it:
Building the second (permanent) image
-------------------------------------
While running in the kexecboot system, you can build the permanent
image and copy it to the device with :command:`ssh`
.. code-block:: console
# ls -ld /mnt/*configuration
lrwxrwxrwx 1 90 /mnt/20252102T182104.configuration -> nix/store/v1w0h4zw65ah4c2r0k7nyy125qrxhq78-system-configuration-aarch64-unknown-linux-musl
lrwxrwxrwx 1 90 /mnt/20251802T181822.configuration -> nix/store/wqjl9s9xljl2wg8257292zghws9ssidk-system-configuration-aarch64-unknown-linux-musl
# : 20251802T181822 is the working system, so reinstall it
# /mnt/20251802T181822.configuration/bin/install /mnt
# umount /mnt
# reboot
This will install the previous configuration's activation binary into
/bin, and copy its kernel and initramfs into /boot. Note that it
depends on the previous system not having been garbage-collected.
build-machine$ nix-build -I liminix-config=./examples/arhcive.nix \
--arg device "import ./devices/gl-ar750"
-A outputs.default && \
(tar chf - result | ssh root@the-device tar -C /run -xvf -)
build-machine$ tar chf - result/firmware.bin | \
ssh root@the-device tar -C /run -xvf -
Next you need to connect to the device and locate the "firmware"
partition, which you can do with a combination of :command:`dmesg`
output and the contents of :file:`/proc/mtd`
.. code-block:: console
<5>[ 0.469841] Creating 4 MTD partitions on "spi0.0":
<5>[ 0.474837] 0x000000000000-0x000000040000 : "u-boot"
<5>[ 0.480796] 0x000000040000-0x000000050000 : "u-boot-env"
<5>[ 0.487056] 0x000000050000-0x000000060000 : "art"
<5>[ 0.492753] 0x000000060000-0x000001000000 : "firmware"
# cat /proc/mtd
dev: size erasesize name
mtd0: 00040000 00001000 "u-boot"
mtd1: 00010000 00001000 "u-boot-env"
mtd2: 00010000 00001000 "art"
mtd3: 00fa0000 00001000 "firmware"
mtd4: 002a0000 00001000 "kernel"
mtd5: 00d00000 00001000 "rootfs"
Now run (in this example)
.. code-block:: console
flashcp -v firmware.bin /dev/mtd3
"I know my new image is good, can I skip the intermediate step?"
----------------------------------------------------------------
In addition to giving you a chance to see if the new image works, this
two-step process ensures that you're not copying the new image over
the top of the active root filesystem. Sometimes it works, but you
will at least need physical access to the device to power-cycle it
because it will be effectively frozen afterwards.
.. _levitate:
Flashing from the boot monitor
==============================
If you are prepared to open the device and have a TTL serial adaptor
of some kind to connect it to, you can probably use U-Boot and a TFTP
server to download and flash the image. This is quite
hardware-specific, and sometimes involves soldering: please refer
to :ref:`serial`.
Flashing from OpenWrt
=====================
.. CAUTION:: Untested! A previous version of these instructions
(without the -e flag) led to bricking the device
when flashing a jffs2 image. If you are reading
this message, nobody has yet reported on whether the
new instructions are any better.
If your device is running OpenWrt then it probably has the
:command:`mtd` command installed. After transferring the image onto the
device using e.g. :command:`ssh`, you can run it as follows:
.. code-block:: console
mtd -e -r write /tmp/firmware.bin firmware
The options to this command are for "erase before writing" and "reboot
after writing".
For more information, please see the `OpenWrt manual <https://openwrt.org/docs/guide-user/installation/sysupgrade.cli>`_ which may also contain (hardware-dependent) instructions on how to flash an image using the vendor firmware - perhaps even from a web interface.
Updating an installed system (JFFS2)
************************************
Adding packages
===============
If you simply wish to add a package without any change to services,
you can call :command:`min-copy-closure` directly to install
any package in Nixpkgs or in the Liminix overlay
If your device is running a JFFS2 root filesystem, you can build
extra packages for it on your build system and copy them to the
device: any package in Nixpkgs or in the Liminix overlay is available
with the ``pkgs`` prefix:
.. code-block:: console
@@ -253,119 +161,38 @@ any package in Nixpkgs or in the Liminix overlay
nix-shell -p min-copy-closure root@the-device result/
Note that this only copies the package and its dependencies to the
device: it doesn't update any profile to add it to ``$PATH``
Note that this only copies the package to the device: it doesn't update
any profile to add it to ``$PATH``
.. _rebuilding the system:
Rebuilding the system
=====================
Reinstalling on a running system
********************************
Liminix is initially installed from a monolithic
:file:`firmware.bin` - and unless you're running a writable
filesystem, the only way to update it is to build and install a whole
new :file:`firmware.bin`. However, you probably would prefer not to
have to remove it from its installation site, unplug it from the
network and stick serial cables in it all over again.
It is not (generally) safe to install a new firmware onto the flash
partitions that the active system is running on. To address this we
have :command:`levitate`, which a way for a running Liminix system to
"soft restart" into a ramdisk running only a limited set of services,
so that the main partitions can then be safely flashed.
Configuration
=============
Levitate *needs to be configured when you create the initial system*
to specify which services/packages/etc to run in maintenance
mode. Most likely you want to configure a network interface and an ssh
for example so that you can login to reflash it.
.. code-block:: nix
defaultProfile.packages = with pkgs; [
...
(levitate.override {
config = {
services = {
inherit (config.services) dhcpc sshd watchdog;
};
defaultProfile.packages = [ mtdutils ];
users.root = config.users.root;
};
})
];
Use
===
Connect (with ssh, probably) to the running Liminix system that you
wish to upgrade.
:command:`liminix-rebuild` is the Liminix analogue of :command:`nixos-rebuild`, although its operation is a bit different because it expects to run on a build machine and then copy to the host device. Run it with the same ``liminix-config`` and ``device`` parameters as you would run :command:`nix-build`, and it will build any new/changed packages and then copy them to the device using SSH. For example:
.. code-block:: console
bash$ ssh root@the-device
Run :command:`levitate`. This takes a little while (perhaps a few
tens of seconds) to execute, and copies all config required for
maintenance mode to :file:`/run/maintenance`.
.. code-block:: console
# levitate
Reboot into maintenance mode. You will be logged out
.. code-block:: console
liminix-rebuild root@the-device -I liminix-config=./examples/rotuer.nix --arg device "import ./devices/gl-ar750"
# reboot
Connect to the device again - note that the ssh host key will have changed.
.. code-block:: console
This will
# ssh -o UserKnownHostsFile=/dev/null root@the-device
Check we're in maintenance mode
.. code-block:: console
* build anything that needs building
* copy new or changed packages to the device
* reboot the device
# cat /etc/banner
LADIES AND GENTLEMEN WE ARE FLOATING IN SPACE
Most services are disabled. The system is operating
with a ram-based root filesystem, making it safe to
overwrite the flash devices in order to perform
upgrades and maintenance.
Don't forget to reboot when you have finished.
Perform the upgrade, using flashcp. This is an example,
your device will differ
.. code-block:: console
It doesn't delete old packages automatically: to do that run
:command:`min-collect-garbage`, which will delete any packages not in
the current system closure. Note that Liminix does not have the NixOS
concept of environments or generations, and there is no way back from
this except for building the previous configuration again.
# cat /proc/mtd
dev: size erasesize name
mtd0: 00030000 00010000 "u-boot"
mtd1: 00010000 00010000 "u-boot-env"
mtd2: 00010000 00010000 "factory"
mtd3: 00f80000 00010000 "firmware"
mtd4: 00220000 00010000 "kernel"
mtd5: 00d60000 00010000 "rootfs"
mtd6: 00010000 00010000 "art"
# flashcp -v firmware.bin mtd:firmware
All done
.. code-block:: console
Caveats
-------
# reboot
* it needs there to be enough free space on the device for all the new
packages in addition to all the packages already on it - which may be
a problem if a lot of things have changed (e.g. a new version of
nixpkgs).
* it cannot upgrade the kernel, only userland
+3 -3
View File
@@ -7,19 +7,19 @@
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
project = 'Liminix'
copyright = '2023-2024 Daniel Barlow'
copyright = '2023, Daniel Barlow'
author = 'Daniel Barlow'
# -- General configuration ---------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
extensions = [
# 'sphinx.ext.autosectionlabel'
'sphinx.ext.autosectionlabel'
]
autosectionlabel_prefix_document = True
templates_path = ['_templates']
exclude_patterns = ['*.inc.rst', '_build', 'Thumbs.db', '.DS_Store']
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
+30 -253
View File
@@ -1,8 +1,27 @@
.. _configuration:
Configuration
#############
Liminix uses the Nix language to provide congruent configuration
management. This means that to change anything about the way in
which a Liminix system works, you make that change in
your :file:`configuration.nix` (or one of the other files it references),
and rerun :command:`nix-build` or :command:`liminix-rebuild` to action
the change. It is not possible (at least, without shenanigans) to make
changes by logging into the device and running imperative commands
whose effects may later be overridden: :file:`configuration.nix`
always describes the entire system and can be used to recreate that
system at any time. You can usefully keep it under version control.
If you are familiar with NixOS, you will notice some similarities
between NixOS and Liminix configuration, and also some
differences. Sometimes the differences are due to the
resource-constrained devices we deploy onto, sometimes due to
differences in the uses these devices are put to.
Configuration taxonomy
**********************
There are many things you can specify in a configuration, but these
are the ones you most commonly need to change:
@@ -67,166 +86,14 @@ domains, or you want to run two SSH daemons on different ports.
don't use the NixOS modules themselves, because the
underlying system is not similar enough for them to work.
.. _configuration-services:
Services
********
In Liminix a service is any kind of long-running task or process on
the system, that is managed (started, stopped, and monitored) by a
service supervisor. A typical SOHO router might have services to
* answer DHCP and DNS requests from the LAN
* provide a wireless access point
* connect using PPPoE or L2TP to an upstream network
* start/stop the firewall
* enable/disable IP packet forwarding
* mount filesystems
(Some of these might not be considered services using other
definitions of the term: for example, this L2TP process would be a
"client" in the client/server classification; and enabling packet
forwarding doesn't require any long-lived process - just a setting to
be toggled. However, there is value in being able to use the same
abstractions for all the things to manage them and specify their
dependency relationships - so in Liminix "everything is a service")
The service supervision system enables service health monitoring,
restart of unhealthy services, and failover to "backup" services when
a primary service fails or its dependencies are unavailable. The
intention is that you have a framework in which you can specify policy
requirements like "ethernet wan dhcp-client should be restarted if it
crashes, but if it can't start because the hardware link is down, then
4G ppp service should be started instead".
Any attribute in `config.services` will become part of the default set
of services that s6-rc will try to bring up. Services are usually
started at boot time, but **controlled services** are those that are
required only in particular contexts. For example, a service to mount
a USB backup drive should run only when the drive is attached to the
system. Liminix currently implements three kinds of controlled service:
* "uevent-rule" service controllers use sysfs/uevent to identify when
particular hardware devices are present, and start/stop a controlled
service appropriately.
* the "round-robin" service controller is used for service failover:
it allows you to specify a list of services and runs each of them
in turn until it exits, then runs the next.
* the "health-check" service wraps another service, and runs a "health
check" command at regular intervals. When the health check fails,
indicating that the wrapped service is not working, it is terminated
and allowed to restart.
Runtime secrets (external vault)
================================
Secrets (such as wifi passphrases, PPP username/password, SSH keys,
etc) that you provide as literal values in :file:`configuration.nix`
are processed into into config files and scripts at build time, and
eventually end up in various files in the (world-readable)
:file:`/nix/store` before being baked into a flashable image. To
change a secret - whether due to a compromise, or just as part of to a
routine key rotation - you need to rebuild the configuration and
potentially reflash the affected devices.
To avoid this, you may instead use a "secrets service", which is a
mechanism for your device to fetch secrets from a source external to
the Nix store, and create at runtime the configuration files and
scripts that start the services which require them.
Not every possible parameter to every possible service is configurable
using a secrets service. Parameters which can be configured this way
are those with the type ``liminix.lib.types.replacable``. At the time
this document was written, these include:
* ppp (pppoe and l2tp): ``username``, ``password``
* ssh: ``authorizedKeys``
* hostapd: all parameters (most likely to be useful for ``wpa_passphrase``)
To use a runtime secret for any of these parameters:
* create a secrets service to specify the source of truth for secrets
* use the :code:`outputRef` function in the service parameter to specify the secrets service and path
For example, given you had an HTTPS server hosting a JSON file with the structure
.. code-block:: json
"ssh": {
"authorizedKeys": {
"root": [ "ssh-rsa ....", "ssh-rsa ....", ... ]
"guest": [ "ssh-rsa ....", "ssh-rsa ....", ... ]
}
}
you could use a :file:`configuration.nix` fragment something like this
to make those keys visible to ssh:
.. code-block:: nix
services.secrets = svc.secrets.outboard.build {
name = "secret-service";
url = "http://10.0.0.1/secrets.json";
username = "secrets";
password = "liminix";
interval = 30; # minutes
dependencies = [ config.services.lan ];
};
services.sshd = svc.ssh.build {
authorizedKeys = outputRef config.services.secrets "ssh/authorizedKeys";
};
There are presently two implementations of a secrets service:
Outboard secrets (HTTPS)
------------------------
This service expects a URL to a JSON file containing all the secrets.
You may specify a username and password along with the URL, which are
used if the file is password-protected (HTTP Basic
authentication). Note that this is not a protection against a
malicious local user: the username and password are normal build-time
parameters so will be readable in the Nix store. This is a mitigation
against the URL being accidentally discovered due to e.g. a log file
or error message on the server leaking.
Tang secrets (encrypted local file)
-----------------------------------
Aternatively, secrets may be stored locally on the device, in a file
that has been encrypted using `Tang <https://github.com/latchset/tang>`_.
Tang is a server for binding data to network presence.
This sounds fancy, but the concept is simple. You have some data, but you only want it to be available when the system containing the data is on a certain, usually secure, network.
.. code-block:: nix
services.secrets = svc.secrets.tang.build {
name = "secret-service";
path = "/run/mnt/usbstick/secrets.json.jwe";
interval = 30; # minutes
dependencies = [ config.services.mount-usbstick ];
};
The encryption uses the
same scheme/algorithm as `Clevis <https://github.com/latchset/clevis>`_ : you may use the `Clevis instructions <https://github.com/latchset/clevis?tab=readme-ov-file#pin-tang>`_ to
encrypt the file on another host and then copy it to your Liminix
device, or you can use :command:`tangc encrypt` to encrypt directly on
the device. (That latter approach may pose a chicken/egg problem if
the device needs secrets to boot up and run the services you are
relying on in order to login).
Writing services
================
We use the `s6-rc service manager <https://www.skarnet.org/software/s6-rc/overview.html>`_ to start/stop/restart services and handle
service dependencies. Any attribute in `config.services` will become
part of the default set of services that s6-rc will try to bring up on
boot.
For the most part, for common use cases, hopefully the services you
need will be defined by modules and you will only have to pass the
@@ -274,101 +141,11 @@ Services may have dependencies: as you see above in the ``cowsayd``
example, it depends on some service called ``config.services.lan``,
meaning that it won't be started until that other service is up.
Service outputs
===============
Outputs are a mechanism by which a service can provide data which may
be required by other services. For example:
* the DHCP client service can expect to receive nameserver address
information as one of the fields in the response from the DHCP
server: we provide that as an output which a dependent service for a
stub name resolver can use to configure its upstream servers.
* a service that creates a new network interface (e.g. ppp) will
provide the name of the interface (:code:`ppp0`, or :code:`ppp1` or
:code:`ppp7`) as an output so that a dependent service can reference
it to set up a route, or to configure firewall rules.
A service :code:`myservice` should write its outputs as files in
:file:`/run/services/outputs/myservice`: you can look around this
directory on a running Liminix system to see how it's used currently.
Usually we use the :code:`in_outputs` shell function in the
:command:`up` or :command:`run` attributes of the service:
.. code-block:: shell
(in_outputs ${name}
for i in lease mask ip router siaddr dns serverid subnet opt53 interface ; do
(printenv $i || true) > $i
done)
The outputs are just files, so technically you can read them using
anything that can read a file. Liminix has two "preferred"
mechanisms, though:
One-off lookups
---------------
In any context that ends up being evaluated by the shell, use
:code:`output` to print the value of an output
.. code-block:: nix
services.defaultroute4 = svc.network.route.build {
via = "$(output ${services.wan} address)";
target = "default";
dependencies = [ services.wan ];
};
Continuous updates
------------------
The downside of using shell functions in downstream service startup