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
1772 changed files with 5541 additions and 21577 deletions
+57
View File
@@ -0,0 +1,57 @@
# Liminix community spaces Code of Conduct
As of Feb 2023, "RESPONSE TEAM" and "LEADERSHIP TEAM" in the text that follows
both refer to me, Daniel Barlow, as there are not yet any other project members.
Liminix is dedicated to providing a harassment-free experience for everyone. We do not tolerate harassment of participants in any form.
This code of conduct applies to all Liminix spaces, including the IRC channel, mailing lists, and Github forums, both online and off. Anyone who violates this code of conduct may be sanctioned or expelled from these spaces at the discretion of the RESPONSE TEAM.
Some Liminix spaces may have additional rules in place, which will be made clearly available to participants. Participants are responsible for knowing and abiding by these rules.
Harassment includes:
*Offensive comments related to gender, gender identity and expression, sexual orientation, disability, mental illness, neuro(a)typicality, physical appearance, body size, age, race, or religion.
*Unwelcome comments regarding a persons lifestyle choices and practices, including those related to food, health, parenting, drugs, and employment.
*Deliberate misgendering or use of dead or rejected names.
*Gratuitous or off-topic sexual images or behaviour in spaces where theyre not appropriate.
*Physical contact and simulated physical contact (eg, textual descriptions like “*hug*” or “*backrub*”) without consent or after a request to stop.
*Threats of violence.
*Incitement of violence towards any individual, including encouraging a person to commit suicide or to engage in self-harm.
*Deliberate intimidation.
*Stalking or following.
*Harassing photography or recording, including logging online activity for harassment purposes.
*Sustained disruption of discussion.
*Unwelcome sexual attention.
*Pattern of inappropriate social contact, such as requesting/assuming inappropriate levels of intimacy with others
*Continued one-on-one communication after requests to cease.
*Deliberate “outing” of any aspect of a persons identity without their consent except as necessary to protect vulnerable people from intentional abuse.
*Publication of non-harassing private communication.
Liminix prioritizes marginalized peoples safety over privileged peoples comfort. RESPONSE TEAM reserves the right not to act on complaints regarding:
*Reverse -isms, including reverse racism, reverse sexism, and cisphobia
*Reasonable communication of boundaries, such as “leave me alone,” “go away,” or “Im not discussing this with you.”
*Communicating in a tone you dont find congenial
*Criticizing racist, sexist, cissexist, or otherwise oppressive behavior or assumptions
## Reporting
If you are being harassed by a member of Liminix, notice that someone else is being harassed, or have any other concerns, please contact the RESPONSE TEAM at [email address or other contact point]. If the person who is harassing you is on the team, they will recuse themselves from handling your incident. We will respond as promptly as we can.
This code of conduct applies to Liminix spaces, but if you are being harassed by a member of Liminix outside our spaces, we still want to know about it. We will take all good-faith reports of harassment by Liminix members, especially LEADERSHIP TEAM, seriously. This includes harassment outside our spaces and harassment that took place at any point in time. The abuse team reserves the right to exclude people from Liminix based on their past behavior, including behavior outside Liminix spaces and behavior towards people who are not in Liminix.
In order to protect volunteers from abuse and burnout, we reserve the right to reject any report we believe to have been made in bad faith. Reports intended to silence legitimate criticism may be deleted without response.
We will respect confidentiality requests for the purpose of protecting victims of abuse. At our discretion, we may publicly name a person about whom weve received harassment complaints, or privately warn third parties about them, if we believe that doing so will increase the safety of Liminix members or the general public. We will not name harassment victims without their affirmative consent.
### Consequences
Participants asked to stop any harassing behavior are expected to comply immediately.
If a participant engages in harassing behavior, RESPONSE TEAM may take any action they deem appropriate, up to and including expulsion from all Liminix spaces and identification of the participant as a harasser to other Liminix members or the general public.
## License and attribution
The policy is based on the Geek Feminism
[Community anti-harassment/Policy](https://geekfeminism.fandom.com/wiki/Community_anti-harassment/Policy)
and is the work of Annalee Flower Horne with assistance from Valerie
Aurora, Alex Skud Bayley, Tim Chevalier, and Mary Gardiner.
+3 -104
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,100 +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.
2024-03-11
The fennel function (svc.open ...) now expects to be given the store
directory of a service derivation, not a direct path to the .outputs
directory. Thus
(svc.open "/nix/store/eeeeeeeeeeeeee-hellod")
not
(svc.open "/nix/store/eeeeeeeeeeeeee-hellod/.outputs")
This simplifies most extant uses of it
-3560
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";
};
+64 -34
View File
@@ -1,47 +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;
doc = pkgs.callPackage ./doc.nix { inherit liminix borderVmConf; } ;
(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 nixpkgs borderVmConf;
device = import (liminix + "/devices/qemu");
liminix-config = {...} : {
imports = [ ./modules/all-modules.nix ];
};
}).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
];
src = ./.;
buildPhase = ''
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.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>;
};
};
};
+13 -16
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,35 +23,27 @@
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:12.0/virtio0";
devpath = "/devices/pci0000:00/0000:00:13.0/virtio0";
ifname = "wan";
};
lan = link.build {
devpath = "/devices/pci0000:00/0000:00:13.0/virtio1";
devpath = "/devices/pci0000:00/0000:00:14.0/virtio1";
ifname = "lan";
};
+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";
};
};
-55
View File
@@ -1,55 +0,0 @@
{ stdenv,
lib,
liminix,
gnumake,
fennel,
pandoc,
luaPackages,
asciidoctor,
borderVmConf
}:
let
json =
(import liminix {
inherit borderVmConf;
device = import (liminix + "/devices/qemu");
liminix-config =
{ ... }:
{
imports = [ ./modules/all-modules.nix ];
};
}).outputs.optionsJson;
in
stdenv.mkDerivation {
name = "liminix-doc";
nativeBuildInputs = [
gnumake
fennel
pandoc
asciidoctor
luaPackages.lyaml
];
src = lib.sources.sourceFilesBySuffices
(lib.cleanSource ./. ) [
".adoc"
".nix" ".rst" "Makefile" ".svg"
".fnl" ".py" ".css" ".html"
".md" ".html.in"
];
buildPhase = ''
cat ${json} | fennel --correlate doc/parse-options.fnl > doc/module-options-generated.inc.rst
cat ${json} | fennel --correlate doc/parse-options-outputs.fnl > doc/outputs-generated.inc.rst
cp ${(import ./doc/hardware.nix)} doc/hardware.rst
make -C doc html
'';
installPhase = ''
mkdir -p $out/nix-support
cd doc
make install prefix=$out
ln -s ${json} $out/options.json
echo "file source-dist \"$out/share/doc/liminix\"" \
> $out/nix-support/hydra-build-products
'';
}
+20 -19
View File
@@ -1,23 +1,24 @@
DOCS=\
admin \
configuration \
development \
index \
installation \
intro \
hardware \
module-options-generated.inc \
outputs-generated.inc \
tutorial
# Minimal makefile for Sphinx documentation
#
%.adoc: %.rst
pandoc -f rst -t asciidoc $< | sed -E -e 's/^(=*) /=\1 /g' > $@
# You can set these variables from the command line, and also
# from the environment for the first two.
SPHINXOPTS ?=
SPHINXBUILD ?= sphinx-build
SOURCEDIR = .
BUILDDIR = _build
hardware.adoc: hardware.nix
# Put it first so that "make" without argument is like "make help".
help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
html: Makefile $(patsubst %,%.adoc,$(DOCS))
asciidoctor -D _build -d book index.adoc
hardware.rst: hardware.nix
@rm -f hardware.rst || true
@cp $$(nix-build hardware.nix) hardware.rst
install:
mkdir -p $(prefix)/share/doc/liminix
cp -a _build/* $(prefix)/share/doc/liminix
.PHONY: help Makefile
# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
html: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
-352
View File
@@ -1,352 +0,0 @@
== 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
<<_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:
.Service management quick reference
[width="100%",cols="55%,45%",options="header",]
|===
|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+`
|===
`+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.
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.)
==== Controlled services
*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.
* `+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.
* `+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 `+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 `+/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 `+s6-tai64nlocal+`.
[source,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>]
----
===== Log persistence
Logs written to `+/run/log/+` will not survive a reboot or crash, as it
is an ephemeral filesystem.
On supported hardware you can enable logging to
https://www.kernel.org/doc/Documentation/ABI/testing/pstore[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 `+/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
`+/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 `+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 `+ssh+`.
To use this, build the `+outputs.updater+` target and then run the
`+update.sh+` script it generates.
[source,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:
* [.title-ref]#--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.
* [.title-ref]#--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
`+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
==== Recovery/downgrades
The `+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
[arabic]
. 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 `+examples/recovery.nix+`) and mounting your Liminix filesystem on
/mnt
. picking another previously-installed configuration that _link:[did]
work, and switching back to it:
[source,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.
==== Adding packages
If you simply wish to add a package without any change to services, you
can call `+min-copy-closure+` directly to install any package in Nixpkgs
or in the Liminix overlay
[source,console]
----
nix-build -I liminix-config=./my-configuration.nix \
--arg device "import ./devices/mydevice" -A pkgs.tcpdump
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+`
[reftext="Levitate"]
[[levitate]]
=== Levitate: Reinstalling on a running system
Liminix is initially installed from a monolithic `+firmware.bin+` - and
unless you're running a writable filesystem, the only way to update it
is to build and install a whole new `+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
`+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.
[source,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.
[source,console]
----
bash$ ssh root@the-device
----
Run `+levitate+`. This takes a little while (perhaps a few tens of
seconds) to execute, and copies all config required for maintenance mode
to `+/run/maintenance+`.
[source,console]
----
# levitate
----
Reboot into maintenance mode. You will be logged out
[source,console]
----
# reboot
----
Connect to the device again - note that the ssh host key will have
changed.
[source,console]
----
# ssh -o UserKnownHostsFile=/dev/null root@the-device
----
Check we're in maintenance mode
[source,console]
----
# 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
[source,console]
----
# 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
[source,console]
----
# reboot
----
+198
View File
@@ -0,0 +1,198 @@
System Administration
#####################
Services on a running system
****************************
* add an s6-rc cheatsheet here
Flashing and updating
*********************
Flashing from Liminix
=====================
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.
Building the RAM-based image
----------------------------
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.
For example
.. code-block:: console
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 -)
and then login to the device and run
.. code-block:: console
cd /run/result
sh ./boot.sh .
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.*
If the new system crashes or is rebooted, then the device will revert
to the old configuration it finds in flash.
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
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.
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 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
nix-build -I liminix-config=./my-configuration.nix \
--arg device "import ./devices/mydevice" -A pkgs.tcpdump
nix-shell -p min-copy-closure root@the-device result/
Note that this only copies the package to the device: it doesn't update
any profile to add it to ``$PATH``
Rebuilding the system
=====================
: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
liminix-rebuild root@the-device -I liminix-config=./examples/rotuer.nix --arg device "import ./devices/gl-ar750"
This will
* build anything that needs building
* copy new or changed packages to the device
* reboot the device
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 a lot of things have changed (e.g. a new version of
nixpkgs).
* it cannot upgrade the kernel, only userland
-106
View File
@@ -1,106 +0,0 @@
= Code of Conduct
NOTE: As of Feb 2023, "`RESPONSE TEAM`" and "`LEADERSHIP TEAM`" in the text
that follows both refer to me, Daniel Barlow, as the project leader.
Liminix is dedicated to providing a harassment-free experience for
everyone. We do not tolerate harassment of participants in any form.
This code of conduct applies to all Liminix spaces, including the IRC
channel, mailing lists, and other forums, both online and off. Anyone
who violates this code of conduct may be sanctioned or expelled from
these spaces at the discretion of the RESPONSE TEAM.
Some Liminix spaces may have additional rules in place, which will be
made clearly available to participants. Participants are responsible for
knowing and abiding by these rules.
Harassment includes:
* Offensive comments related to gender, gender identity and expression,
sexual orientation, disability, mental illness, neuro(a)typicality,
physical appearance, body size, age, race, or religion.
* Unwelcome comments regarding a persons lifestyle choices and
practices, including those related to food, health, parenting, drugs,
and employment.
* Deliberate misgendering or use of '`dead`' or rejected names.
* Gratuitous or off-topic sexual images or behaviour in spaces where
theyre not appropriate.
* Physical contact and simulated physical contact (eg, textual
descriptions like "`__hug__`" or "`__backrub__`") without consent or
after a request to stop.
* Threats of violence.
* Incitement of violence towards any individual, including encouraging a
person to commit suicide or to engage in self-harm.
* Deliberate intimidation.
* Stalking or following.
* Harassing photography or recording, including logging online activity
for harassment purposes.
* Sustained disruption of discussion.
* Unwelcome sexual attention.
* Pattern of inappropriate social contact, such as requesting/assuming
inappropriate levels of intimacy with others
* Continued one-on-one communication after requests to cease.
* Deliberate "`outing`" of any aspect of a persons identity without
their consent except as necessary to protect vulnerable people from
intentional abuse.
* Publication of non-harassing private communication.
Liminix prioritizes marginalized peoples safety over privileged
peoples comfort. RESPONSE TEAM reserves the right not to act on
complaints regarding:
* '`Reverse`' -isms, including '`reverse racism,`' '`reverse sexism,`'
and '`cisphobia`'
* Reasonable communication of boundaries, such as "`leave me alone,`"
"`go away,`" or "`Im not discussing this with you.`"
* Communicating in a '`tone`' you dont find congenial
* Criticizing racist, sexist, cissexist, or otherwise oppressive
behavior or assumptions
== Reporting
If you are being harassed by a member of Liminix, notice that someone
else is being harassed, or have any other concerns, please contact the
RESPONSE TEAM at [email address or other contact point]. If the person
who is harassing you is on the team, they will recuse themselves from
handling your incident. We will respond as promptly as we can.
This code of conduct applies to Liminix spaces, but if you are being
harassed by a member of Liminix outside our spaces, we still want to
know about it. We will take all good-faith reports of harassment by
Liminix members, especially LEADERSHIP TEAM, seriously. This includes
harassment outside our spaces and harassment that took place at any
point in time. The abuse team reserves the right to exclude people from
Liminix based on their past behavior, including behavior outside Liminix
spaces and behavior towards people who are not in Liminix.
In order to protect volunteers from abuse and burnout, we reserve the
right to reject any report we believe to have been made in bad faith.
Reports intended to silence legitimate criticism may be deleted without
response.
We will respect confidentiality requests for the purpose of protecting
victims of abuse. At our discretion, we may publicly name a person about
whom weve received harassment complaints, or privately warn third
parties about them, if we believe that doing so will increase the safety
of Liminix members or the general public. We will not name harassment
victims without their affirmative consent.
== Consequences
Participants asked to stop any harassing behavior are expected to comply
immediately.
If a participant engages in harassing behavior, RESPONSE TEAM may take
any action they deem appropriate, up to and including expulsion from all
Liminix spaces and identification of the participant as a harasser to
other Liminix members or the general public.
== License and attribution
The policy is based on the Geek Feminism
https://geekfeminism.fandom.com/wiki/Community_anti-harassment/Policy[Community
anti-harassment/Policy] and is the work of Annalee Flower Horne with
assistance from Valerie Aurora, Alex Skud Bayley, Tim Chevalier, and
Mary Gardiner.
+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']
-223
View File
@@ -1,223 +0,0 @@
== Configuration
There are many things you can specify in a configuration, but most
commonly you need to change:
* which services (processes) to run
* what packages to install
* permitted users and groups
* Linux kernel configuration options
* Busybox applets
* filesystem layout
=== Modules
*Modules* are a means of abstraction which allow "bundling" of
configuration options related to a common purpose or theme. For example,
the `+dnsmasq+` module defines a template for a dnsmasq service, ensures
that the dnsmasq package is installed, and provides a dnsmasq user and
group for the service to run as. The `+ppp+` module defines a service
template and also enables various PPP-related kernel configuration.
Not all modules are included in the configuration by default, because
that would mean that the kernel (and the Busybox binary providing common
CLI tools) was compiled with many unnecessary bells and whistles and
therefore be bigger than needed. (This is not purely an academic concern
if your device has little flash storage). Therefore, specifying a
service is usually a two-step process. For example, to add an NTP
service you first add `+modules/ntp+` to your `+imports+` list, then you
create a service by calling `+config.system.service.ntp.build { .... }+`
with the appropriate service-dependent configuration parameters.
[source,nix]
----
let svc = config.system.service;
in {
# ...
imports = [
./modules/ntp
# ....
];
config.services.ntp = svc.ntp.build {
pools = { "pool.ntp.org" = ["iburst"]; };
makestep = { threshold = 1.0; limit = 3; };
};
----
Merely including the module won't define the service on its own: it only
creates the template in `+config.system.service.foo+` and you have to
create an actual service using the template. This is an intentional
choice to allow the creation of multiple differently-configured services
based on the same template - perhaps e.g. when you have multiple
networks (VPNs etc) in different trust domains, or you want to run two
SSH daemons on different ports. (For the background to this, please
refer to the `+architecture decision record <adr/module-system>+`)
[TIP]
====
Liminix modules should be quite familiar (but also different) if you
already know how to use NixOS modules. We use the NixOS module
infrastructure code, meaning that you should recognise the syntax, the
type system, the rules for combining configuration values from different
sources. We 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 [.title-ref]#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 `+configuration.nix+` are
processed into into config files and scripts at build time, and
eventually end up in various files in the (world-readable)
`+/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+`)