forked from dan/liminix
Compare commits
303 Commits
hark-how-a
...
main
Author | SHA1 | Date | |
---|---|---|---|
9d6e50cbbc | |||
94dbc56595 | |||
2cd7f932eb | |||
3ca0d87c27 | |||
8f30db58ae | |||
f9ab0590a6 | |||
84fa8d65f4 | |||
9b0149ecb7 | |||
|
baf3cf7413 | ||
|
c5145b5fc9 | ||
|
628f4dfdbe | ||
|
da59e2a349 | ||
|
c0a9571a13 | ||
|
d6ffdd7be6 | ||
|
985f982435 | ||
|
a893c0dc4c | ||
|
3ec29dc1b9 | ||
|
0e81953b67 | ||
|
3c70a0d037 | ||
|
422f3edab1 | ||
|
c14b2f6356 | ||
|
cdafff2095 | ||
|
13f1bb9f52 | ||
|
019fef6929 | ||
|
63007859c2 | ||
|
e9ab8d7183 | ||
|
3dc58de0eb | ||
|
dde8386f75 | ||
|
c59364d623 | ||
|
b76c5b4abe | ||
|
0a8343be66 | ||
|
d14ee41325 | ||
|
8f814658fe | ||
60508f4d4e | |||
ca64e9035e | |||
4bcc3d5b28 | |||
28fe37d555 | |||
175db9f604 | |||
b5722a0153 | |||
c373152673 | |||
7e7171556f | |||
6920ee765d | |||
71a1ef286e | |||
ffe0e9d26b | |||
2b22c7aa91 | |||
3c950704e1 | |||
8578a554c7 | |||
3851698d35 | |||
f69ebbb6f5 | |||
16e4b05653 | |||
8ac848b1e6 | |||
b7efbd3e21 | |||
a654577ac2 | |||
c50423f689 | |||
65479e206b | |||
79926c6fe7 | |||
ae4856ea7c | |||
b9c0d93670 | |||
11287a8436 | |||
57aece0709 | |||
c1d285a220 | |||
dce983ec79 | |||
812f497660 | |||
1206d02200 | |||
7c196bf9b4 | |||
86d19c54b3 | |||
aca3e11631 | |||
273c66b2d3 | |||
87f6a31a06 | |||
a9ea01428e | |||
92b0bec038 | |||
82537bbe68 | |||
efb29c5901 | |||
29e61be26c | |||
6f1f9d6f20 | |||
34291292c0 | |||
c9e4c1b0da | |||
|
63e3f2aa58 | ||
|
61494fdc0c | ||
891d6e5f20 | |||
c4041b00f6 | |||
f875622100 | |||
49ec4a2961 | |||
c8154a2db9 | |||
02cf2c6b80 | |||
b0709a6443 | |||
86f5c9b568 | |||
ef707de8b1 | |||
89c88dd472 | |||
c1ad139310 | |||
f682b26c29 | |||
84ce618213 | |||
9e199c6957 | |||
c8e3d84bf4 | |||
dd8ec18881 | |||
1730cf07b1 | |||
de51bfe13d | |||
b09723345c | |||
1781d4b6e4 | |||
c219350d7c | |||
6f83282ff5 | |||
|
04895f9cf6 | ||
5f2d1660bd | |||
|
7642e23c0a | ||
83ee488e4c | |||
f19a937eda | |||
f0490f37d5 | |||
c1101d3af5 | |||
9a3d7a387e | |||
228c0a1668 | |||
63f034e362 | |||
6971d03520 | |||
7bc9cb6c55 | |||
a251ceeb99 | |||
38a7f0b03b | |||
c0c4752350 | |||
3c941b4ce2 | |||
243295aab8 | |||
45e8db09e1 | |||
2a93f24a58 | |||
64898eada8 | |||
|
d5026c2074 | ||
136c5e6f32 | |||
fa9a2c6413 | |||
049cdbb610 | |||
5ee4adff10 | |||
9632a64b47 | |||
fc5def2e15 | |||
9369fdf314 | |||
d2e29543e2 | |||
dad7c2c875 | |||
3459c04f64 | |||
ff991508ae | |||
e4ed9dbec9 | |||
9e0ef68c1f | |||
870e4d86cc | |||
d6f96c0448 | |||
e7747832ad | |||
921b4f24af | |||
e505e37d9a | |||
2152a3f207 | |||
ec1ff283da | |||
0bf98c5243 | |||
dc42969ef6 | |||
1a041392aa | |||
6469408d5f | |||
f020d5b25d | |||
e5cbc2b86b | |||
29f35cb902 | |||
dbf1ecdcb7 | |||
aecc44aaa0 | |||
1042be912c | |||
c931d84828 | |||
64a3f50248 | |||
c5e9fcecc7 | |||
f25c41b4d2 | |||
bfa68d9c55 | |||
ff0ef825a6 | |||
44a0cf364b | |||
c7b2733bea | |||
dfbc72dd51 | |||
9f851b229c | |||
fe2d41a2b1 | |||
9b92bf8447 | |||
5f9ffa804f | |||
231c2cef03 | |||
dbb82339bd | |||
4a606a4b19 | |||
9c894bdabf | |||
a962f18369 | |||
9a29a042e8 | |||
46926a94db | |||
ab0631c555 | |||
32c13c46bb | |||
e5db2691e5 | |||
9ca9723c9d | |||
d1e2d525a4 | |||
f4f4387861 | |||
55fa9992d4 | |||
95d9e014fb | |||
80528376a2 | |||
d707345891 | |||
133b64613d | |||
c6c41e331e | |||
b878d6481a | |||
601bb289ee | |||
876bd7d8ce | |||
39c338d710 | |||
6c8b2bbb83 | |||
4ddce6e926 | |||
5eeb277564 | |||
c81e7c4d35 | |||
53fed8839a | |||
ebaa7b2bcb | |||
15d570f749 | |||
|
aff312bbbe | ||
bb8e974c2b | |||
317457f582 | |||
07e66c462b | |||
4229b42d82 | |||
03b17fa3ed | |||
a8891461aa | |||
5adfb0230f | |||
b519bd15df | |||
f2daa0b669 | |||
3f74fad966 | |||
ed925588f7 | |||
f08c10c8ba | |||
d25a804f13 | |||
0242cec977 | |||
5a2963543e | |||
|
644f42c35e | ||
98d3336926 | |||
cb6ebbdc60 | |||
bb335050fd | |||
395f624338 | |||
e518ab667b | |||
382128b6cf | |||
c803772074 | |||
32c24f3809 | |||
cc73a98419 | |||
e2ea145ce5 | |||
b036a161f5 | |||
31a2969972 | |||
76a370cc92 | |||
bf9f264f0c | |||
e35b61b68c | |||
a8f98ccfe7 | |||
27ce61ae4e | |||
3f0f621809 | |||
b0ae314df4 | |||
d789a23113 | |||
5ba14fd915 | |||
3df34428d6 | |||
62c788eb86 | |||
bab6d346a8 | |||
a202ae476a | |||
7c9297f91d | |||
a0bd250963 | |||
c8b2d58dd3 | |||
e5223f093f | |||
c563a6451f | |||
f45326b9d3 | |||
f9f4d97bb8 | |||
abfb35a231 | |||
315907de98 | |||
185117843b | |||
0131686661 | |||
3da692f7ef | |||
f61e737b54 | |||
262efaabe6 | |||
7cfb92e3ce | |||
22882dabee | |||
5e046490de | |||
a9760d239c | |||
5729cfb4a7 | |||
7d5c7b9b44 | |||
23b3a2baef | |||
4cb4f904f8 | |||
a9d847e2c0 | |||
6bbff2f5b3 | |||
5c1f5fabe2 | |||
6489a39424 | |||
c94d12934f | |||
c40eef25d6 | |||
46991e2761 | |||
a135cb1217 | |||
863045b86b | |||
629624bb25 | |||
92b9bf959e | |||
c5c5f1687a | |||
80793aa694 | |||
824536f9b3 | |||
e6cb5e319b | |||
c3ccee6506 | |||
6db982f25f | |||
86a5224f3c | |||
155a29d9b3 | |||
e6ef4f78bb | |||
d2f517a4e9 | |||
0f38ee0e9c | |||
61dc5beca8 | |||
f3225c2bd5 | |||
8798ee9830 | |||
629914f65e | |||
0693cf23d8 | |||
c341eb46b6 | |||
1a369ff3bf | |||
364c5faf9e | |||
80a09a9a9b | |||
3518e2ecca | |||
fc2eb6ee4d | |||
bd20f3e419 | |||
f62ad0e1d7 | |||
ed792e0dc0 | |||
d025c33d30 | |||
a755c9c3c5 | |||
fdf74fa06b | |||
b8dea2ed34 | |||
c18f07f02f | |||
1c4412a1f4 | |||
dbc16edf96 | |||
528d619d76 |
1
.gitignore
vendored
1
.gitignore
vendored
@ -6,3 +6,4 @@ result-*
|
|||||||
_build
|
_build
|
||||||
*-secrets.nix
|
*-secrets.nix
|
||||||
examples/static-leases.nix
|
examples/static-leases.nix
|
||||||
|
/doc/hardware.rst
|
||||||
|
86
NEWS
Normal file
86
NEWS
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
A brief guide to backward-incompatible changes
|
||||||
|
that are likely to break configurations or workflows
|
||||||
|
|
||||||
|
2023-07-13
|
||||||
|
|
||||||
|
* a significant re-arrangement of modules and services, which will
|
||||||
|
probably break any configuration written before this time. For a
|
||||||
|
detailed explanation, see
|
||||||
|
https://www.liminix.org/doc/configuration.html#modules
|
||||||
|
|
||||||
|
2023-12-10
|
||||||
|
|
||||||
|
* configurations (usually) need no longer import modules from
|
||||||
|
modules/outputs because devices are expected to do this instead. This
|
||||||
|
change is because the outputs that make sense in any given context are
|
||||||
|
usually a property of the device being installed onto.
|
||||||
|
|
||||||
|
2023-12-11
|
||||||
|
|
||||||
|
* rename outputs.flashimage to outputs.mtdimage (and also diskimage to
|
||||||
|
mbrimage). This change is made in the expectation that "fooimage" is
|
||||||
|
the name of an outputs that gloms together other filesystem-like
|
||||||
|
outputs with some kind of partition table - so we might in future have
|
||||||
|
gptimage or lvmimage or ubimage.
|
||||||
|
|
||||||
|
2024-01-03
|
||||||
|
|
||||||
|
Liminix is now targeted to Nixpkgs 23.11 (not 23.05 as previously).
|
||||||
|
Upstream changes that have led to incompatible Liminix changes are:
|
||||||
|
|
||||||
|
* newer U-Boot version
|
||||||
|
* util-linux can now be built (previously depended on systemd)
|
||||||
|
|
||||||
|
2024-01-30
|
||||||
|
|
||||||
|
New port! Thanks to Arnout Engelen <arnout@bzzt.net>, Liminix
|
||||||
|
now runs on the TP-Link Archer AX23.
|
||||||
|
|
||||||
|
2024-02-12
|
||||||
|
|
||||||
|
* 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.
|
||||||
|
|
||||||
|
* 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
|
||||||
|
them afterwards as though they were "out of tree". Refer to commit
|
||||||
|
b9c0d93670275e69df24902b05bf4aa4f0fcbe96 for a fuller explanation
|
||||||
|
of how this simplifies things.
|
||||||
|
|
||||||
|
2024-02-13
|
||||||
|
|
||||||
|
So that we can be more consistent about services that would like their
|
||||||
|
state to be preserved across boots (assuming a writable filesystem)
|
||||||
|
these changes have been made
|
||||||
|
|
||||||
|
* /run/service-state has been moved to /run/services/outputs
|
||||||
|
to better reflect what it's used for
|
||||||
|
* /run/services/state is either a symlink to /persist/services/state
|
||||||
|
(if there's a writeable fs on /persist) or a directory (if there
|
||||||
|
isn't)
|
||||||
|
|
||||||
|
The change will lose your ssh host key(s) unless you copy them from
|
||||||
|
the old location to the new one before rebooting into the new system
|
||||||
|
|
||||||
|
mkdir -m 02751 -p /run/services/state/dropbear
|
||||||
|
cp /persist/secrets/dropbear/* /run/services/state/dropbear
|
||||||
|
|
||||||
|
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.
|
22
README.md
22
README.md
@ -18,22 +18,14 @@ outside word goes across it.
|
|||||||
|
|
||||||
Liminix is pre-1.0. We are still finding new and better ways to do things,
|
Liminix is pre-1.0. We are still finding new and better ways to do things,
|
||||||
and there is no attempt to maintain backward compatibility with the old
|
and there is no attempt to maintain backward compatibility with the old
|
||||||
ways. This will change when it settles down.
|
ways.
|
||||||
|
|
||||||
_In general:_ development mostly happens on the `main` branch, which is
|
The [NEWS](NEWS) file (available wherever you found this README) is
|
||||||
therefore not guaranteed to build or to work on every commit. For the
|
a high-level overview of breaking changes.
|
||||||
latest functioning version, see [the CI system](https://build.liminix.org/jobset/liminix/build) and pick a revision with all jobs green.
|
|
||||||
|
|
||||||
_In particular:_ as of July 2023, a significant re-arrangement of
|
Development mostly happens on the `main` branch, which is therefore
|
||||||
modules and services is ongoing:
|
not guaranteed to build or to work on every commit. For the latest
|
||||||
|
functioning version, see [the CI system](https://build.liminix.org/jobset/liminix/build) and pick a revision with all jobs green.
|
||||||
* if you are using out-of-tree configurations created before commit
|
|
||||||
2e50368, especially if they reference things under pkgs.liminix,
|
|
||||||
they will need updating. Look at changes to examples/rotuer.nix
|
|
||||||
for guidance
|
|
||||||
|
|
||||||
* the same is intermittently true for examples/{extensino,arhcive}.nix
|
|
||||||
where I've updated rotuer and not updated them to match.
|
|
||||||
|
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
@ -41,7 +33,7 @@ modules and services is ongoing:
|
|||||||
Documentation is in the [doc](doc/) directory. You can build it
|
Documentation is in the [doc](doc/) directory. You can build it
|
||||||
by running
|
by running
|
||||||
|
|
||||||
nix-shell -p sphinx --run "make -C doc html"
|
nix-shell -p sphinx --run "make -C doc hardware.rst html"
|
||||||
|
|
||||||
Rendered documentation corresponding to the latest commit on `main`
|
Rendered documentation corresponding to the latest commit on `main`
|
||||||
is published to [https://www.liminix.org/doc/](https://www.liminix.org/doc/)
|
is published to [https://www.liminix.org/doc/](https://www.liminix.org/doc/)
|
||||||
|
1701
THOUGHTS.txt
1701
THOUGHTS.txt
File diff suppressed because it is too large
Load Diff
@ -99,14 +99,16 @@ in {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
environment.systemPackages = with pkgs; [
|
environment.systemPackages =
|
||||||
tcpdump
|
let wireshark-nogui = pkgs.wireshark.override { withQt = false ; };
|
||||||
wireshark
|
in with pkgs; [
|
||||||
socat
|
tcpdump
|
||||||
tufted
|
wireshark-nogui
|
||||||
iptables
|
socat
|
||||||
usbutils
|
tufted
|
||||||
];
|
iptables
|
||||||
|
usbutils
|
||||||
|
];
|
||||||
security.sudo.wheelNeedsPassword = false;
|
security.sudo.wheelNeedsPassword = false;
|
||||||
networking = {
|
networking = {
|
||||||
hostName = "border";
|
hostName = "border";
|
||||||
|
79
ci.nix
79
ci.nix
@ -8,48 +8,69 @@ let
|
|||||||
pkgs = (import nixpkgs {});
|
pkgs = (import nixpkgs {});
|
||||||
borderVmConf = ./bordervm.conf-example.nix;
|
borderVmConf = ./bordervm.conf-example.nix;
|
||||||
inherit (pkgs.lib.attrsets) genAttrs;
|
inherit (pkgs.lib.attrsets) genAttrs;
|
||||||
devices = {
|
devices = [
|
||||||
virt = [ "qemu" "qemu-aarch64" ];
|
"gl-ar750"
|
||||||
hw = [ "gl-ar750" "gl-mt300n-v2" "gl-mt300a" ];
|
"gl-mt300a"
|
||||||
};
|
"gl-mt300n-v2"
|
||||||
|
"qemu"
|
||||||
|
"qemu-aarch64"
|
||||||
|
"qemu-armv7l"
|
||||||
|
"tp-archer-ax23"
|
||||||
|
"zyxel-nwa50ax"
|
||||||
|
];
|
||||||
vanilla = ./vanilla-configuration.nix;
|
vanilla = ./vanilla-configuration.nix;
|
||||||
for-device = cfg: name:
|
for-device = name:
|
||||||
(import liminix {
|
(import liminix {
|
||||||
inherit nixpkgs borderVmConf;
|
inherit nixpkgs borderVmConf;
|
||||||
device = import (liminix + "/devices/${name}");
|
device = import (liminix + "/devices/${name}");
|
||||||
liminix-config = cfg;
|
liminix-config = vanilla;
|
||||||
}).outputs.default;
|
}).outputs.default;
|
||||||
tests = import ./tests/ci.nix;
|
tests = import ./tests/ci.nix;
|
||||||
jobs =
|
jobs =
|
||||||
(genAttrs devices.hw (name: for-device ./vanilla-configuration-hw.nix name)) //
|
(genAttrs devices for-device) //
|
||||||
(genAttrs devices.virt (name: for-device vanilla name)) //
|
|
||||||
tests //
|
tests //
|
||||||
{
|
{
|
||||||
buildEnv = (import liminix {
|
buildEnv = (import liminix {
|
||||||
inherit nixpkgs borderVmConf;
|
inherit nixpkgs borderVmConf;
|
||||||
device = import (liminix + "/devices/qemu");
|
device = import (liminix + "/devices/qemu");
|
||||||
liminix-config = vanilla;
|
liminix-config = vanilla;
|
||||||
}).buildEnv;
|
}).buildEnv;
|
||||||
doc = pkgs.stdenv.mkDerivation {
|
doc =
|
||||||
name = "liminix-doc";
|
let json =
|
||||||
nativeBuildInputs = with pkgs; [
|
(import liminix {
|
||||||
gnumake sphinx
|
inherit nixpkgs borderVmConf;
|
||||||
fennel luaPackages.lyaml
|
device = import (liminix + "/devices/qemu");
|
||||||
];
|
liminix-config = {...} : {
|
||||||
src = ./doc;
|
imports = [ ./modules/all-modules.nix ];
|
||||||
buildPhase = ''
|
};
|
||||||
cat ${(import ./doc/extract-options.nix).doc} > options.json
|
}).outputs.optionsJson;
|
||||||
cat options.json | fennel --correlate parse-options.fnl > modules-generated.rst
|
installers = map (f: "system.outputs.${f}") [
|
||||||
cp ${(import ./doc/hardware.nix)} hardware.rst
|
"vmroot"
|
||||||
make html
|
"mtdimage"
|
||||||
'';
|
"ubimage"
|
||||||
installPhase = ''
|
];
|
||||||
mkdir -p $out/nix-support $out/share/doc/
|
inherit (pkgs.lib) concatStringsSep;
|
||||||
cp modules.rst options.json $out
|
in pkgs.stdenv.mkDerivation {
|
||||||
cp -a _build/html $out/share/doc/liminix
|
name = "liminix-doc";
|
||||||
echo "file source-dist \"$out/share/doc/liminix\"" \
|
nativeBuildInputs = with pkgs; [
|
||||||
> $out/nix-support/hydra-build-products
|
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 {
|
with-unstable = (import liminix {
|
||||||
nixpkgs = unstable;
|
nixpkgs = unstable;
|
||||||
|
19
default.nix
19
default.nix
@ -3,6 +3,7 @@
|
|||||||
, liminix-config ? <liminix-config>
|
, liminix-config ? <liminix-config>
|
||||||
, nixpkgs ? <nixpkgs>
|
, nixpkgs ? <nixpkgs>
|
||||||
, borderVmConf ? ./bordervm.conf.nix
|
, borderVmConf ? ./bordervm.conf.nix
|
||||||
|
, imageType ? "primary"
|
||||||
}:
|
}:
|
||||||
|
|
||||||
let
|
let
|
||||||
@ -13,13 +14,14 @@ let
|
|||||||
allowUnsupportedSystem = true; # mipsel
|
allowUnsupportedSystem = true; # mipsel
|
||||||
permittedInsecurePackages = [
|
permittedInsecurePackages = [
|
||||||
"python-2.7.18.6" # kernel backports needs python <3
|
"python-2.7.18.6" # kernel backports needs python <3
|
||||||
|
"python-2.7.18.7"
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
config = (pkgs.lib.evalModules {
|
eval = pkgs.lib.evalModules {
|
||||||
modules = [
|
modules = [
|
||||||
{ _module.args = { inherit pkgs; lib = pkgs.lib; }; }
|
{ _module.args = { inherit pkgs; inherit (pkgs) lim; }; }
|
||||||
./modules/hardware.nix
|
./modules/hardware.nix
|
||||||
./modules/base.nix
|
./modules/base.nix
|
||||||
./modules/busybox.nix
|
./modules/busybox.nix
|
||||||
@ -29,8 +31,12 @@ let
|
|||||||
./modules/s6
|
./modules/s6
|
||||||
./modules/users.nix
|
./modules/users.nix
|
||||||
./modules/outputs.nix
|
./modules/outputs.nix
|
||||||
|
{
|
||||||
|
boot.imageType = imageType;
|
||||||
|
}
|
||||||
];
|
];
|
||||||
}).config;
|
};
|
||||||
|
config = eval.config;
|
||||||
|
|
||||||
borderVm = ((import <nixpkgs/nixos/lib/eval-config.nix>) {
|
borderVm = ((import <nixpkgs/nixos/lib/eval-config.nix>) {
|
||||||
system = builtins.currentSystem;
|
system = builtins.currentSystem;
|
||||||
@ -43,6 +49,12 @@ let
|
|||||||
in {
|
in {
|
||||||
outputs = config.system.outputs // {
|
outputs = config.system.outputs // {
|
||||||
default = config.system.outputs.${config.hardware.defaultOutput};
|
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);
|
||||||
};
|
};
|
||||||
|
|
||||||
# this is just here as a convenience, so that we can get a
|
# this is just here as a convenience, so that we can get a
|
||||||
@ -59,6 +71,7 @@ in {
|
|||||||
go-l2tp
|
go-l2tp
|
||||||
min-copy-closure
|
min-copy-closure
|
||||||
fennelrepl
|
fennelrepl
|
||||||
|
lzma
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
238
devices/belkin-rt3200/default.nix
Normal file
238
devices/belkin-rt3200/default.nix
Normal file
@ -0,0 +1,238 @@
|
|||||||
|
{
|
||||||
|
description = ''
|
||||||
|
Belkin RT-3200 / Linksys E8450
|
||||||
|
******************************
|
||||||
|
|
||||||
|
This device is based on a 64 bit Mediatek MT7622 ARM platform,
|
||||||
|
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
|
||||||
|
================
|
||||||
|
|
||||||
|
- MediaTek MT7622BV (1350MHz)
|
||||||
|
- 128MB NAND flash
|
||||||
|
- 512MB RAM
|
||||||
|
- b/g/n wireless using MediaTek MT7622BV (MT7615E driver)
|
||||||
|
- a/n/ac/ax wireless using MediaTek MT7915E
|
||||||
|
|
||||||
|
|
||||||
|
Installation
|
||||||
|
============
|
||||||
|
|
||||||
|
Installation is currently a manual process (you need a :ref:`serial <serial>` conection and
|
||||||
|
TFTP) following the instructions at :ref:`system-outputs-ubimage`
|
||||||
|
|
||||||
|
'';
|
||||||
|
|
||||||
|
system = {
|
||||||
|
crossSystem = {
|
||||||
|
config = "aarch64-unknown-linux-musl";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
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 = {
|
||||||
|
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";
|
||||||
|
|
||||||
|
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";
|
||||||
|
|
||||||
|
REGMAP_MMIO = "y";
|
||||||
|
CLKSRC_MMIO = "y";
|
||||||
|
REGMAP = "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
|
||||||
|
|
||||||
|
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";
|
||||||
|
|
||||||
|
|
||||||
|
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";
|
||||||
|
|
||||||
|
PSTORE = "y";
|
||||||
|
PSTORE_RAM = "y";
|
||||||
|
PSTORE_CONSOLE = "y";
|
||||||
|
PSTORE_DEFLATE_COMPRESS = "n";
|
||||||
|
|
||||||
|
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 "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 ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
57
devices/families/qemu.nix
Normal file
57
devices/families/qemu.nix
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
{ config, pkgs, ... }:
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
../../modules/outputs/jffs2.nix
|
||||||
|
];
|
||||||
|
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";
|
||||||
|
MTD_CMDLINE_PARTS = "y";
|
||||||
|
MTD_PHRAM = "y";
|
||||||
|
|
||||||
|
VIRTIO_MENU = "y";
|
||||||
|
PCI = "y";
|
||||||
|
VIRTIO_PCI = "y";
|
||||||
|
BLOCK = "y";
|
||||||
|
VIRTIO_BLK = "y";
|
||||||
|
VIRTIO_NET = "y";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
hardware =
|
||||||
|
let
|
||||||
|
mac80211 = pkgs.mac80211.override {
|
||||||
|
drivers = ["mac80211_hwsim"];
|
||||||
|
klibBuild = config.system.outputs.kernel.modulesupport;
|
||||||
|
};
|
||||||
|
in {
|
||||||
|
defaultOutput = "vmroot";
|
||||||
|
rootDevice = "/dev/mtdblock0";
|
||||||
|
dts.src = pkgs.lib.mkDefault null;
|
||||||
|
flash.eraseBlockSize = 65536;
|
||||||
|
networkInterfaces =
|
||||||
|
let inherit (config.system.service.network) link;
|
||||||
|
in {
|
||||||
|
wan = link.build {
|
||||||
|
devpath = "/devices/pci0000:00/0000:00:13.0/virtio0";
|
||||||
|
ifname = "wan";
|
||||||
|
};
|
||||||
|
lan = link.build {
|
||||||
|
devpath = "/devices/pci0000:00/0000:00:14.0/virtio1";
|
||||||
|
ifname = "lan";
|
||||||
|
};
|
||||||
|
|
||||||
|
wlan_24 = link.build {
|
||||||
|
ifname = "wlan0";
|
||||||
|
dependencies = [ mac80211 ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
@ -1,11 +1,3 @@
|
|||||||
|
|
||||||
# I like GL.iNet devices because they're relatively accessible to
|
|
||||||
# DIY users: the serial port connections have headers preinstalled
|
|
||||||
# and don't need soldering
|
|
||||||
|
|
||||||
# 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
|
|
||||||
|
|
||||||
{
|
{
|
||||||
system = {
|
system = {
|
||||||
crossSystem = {
|
crossSystem = {
|
||||||
@ -21,6 +13,9 @@
|
|||||||
GL.iNet GL-AR750
|
GL.iNet GL-AR750
|
||||||
****************
|
****************
|
||||||
|
|
||||||
|
Hardware summary
|
||||||
|
================
|
||||||
|
|
||||||
The GL-AR750 "Creta" travel router features:
|
The GL-AR750 "Creta" travel router features:
|
||||||
|
|
||||||
- QCA9531 @650Mhz SoC
|
- QCA9531 @650Mhz SoC
|
||||||
@ -30,29 +25,34 @@
|
|||||||
- 16MB NOR Flash
|
- 16MB NOR Flash
|
||||||
- supported in OpenWrt by the "ath79" SoC family
|
- supported in OpenWrt by the "ath79" SoC family
|
||||||
|
|
||||||
As with many GL.iNet devices, the stock vendor firmware
|
|
||||||
is a fork of OpenWrt, meaning that the plain binary
|
|
||||||
``firmware.bin`` that Liminix builds can be flashed using the
|
|
||||||
vendor web UI and the U-Boot emergency "unbrick" routine
|
|
||||||
|
|
||||||
The GL-AR750 has two distinct sets of wifi hardware. The 2.4GHz
|
The GL-AR750 has two distinct sets of wifi hardware. The 2.4GHz
|
||||||
radio is part of the QCA9531 SoC, i.e. it's on the same silicon as
|
radio is part of the QCA9531 SoC, i.e. it's on the same silicon as
|
||||||
the CPU, the Ethernet, the USB etc. The device is connected to the
|
the CPU, the Ethernet, the USB etc. The device is connected to the
|
||||||
host via AHB, the "Advanced High-Performance Bus" and it is
|
host via `AHB <https://en.wikipedia.org/wiki/Advanced_Microcontroller_Bus_Architecture>`_ and it is
|
||||||
supported in Linux using the ath9k driver. The 5GHz support, on the
|
supported in Linux using the ath9k driver. 5GHz wifi
|
||||||
other hand, is provided by a QCA9887 PCIe (PCI embedded) WLAN chip:
|
is provided by a QCA9887 PCIe (PCI embedded) WLAN chip,
|
||||||
I haven't looked closely at the router innards to see if this is
|
|
||||||
actually physically a separate board that could be unplugged, but
|
|
||||||
as far as Linux is concerned it behaves as one. This is
|
|
||||||
supported by the ath10k driver.
|
supported by the ath10k driver.
|
||||||
|
|
||||||
|
Installation
|
||||||
|
============
|
||||||
|
|
||||||
|
As with many GL.iNet devices, the stock vendor firmware
|
||||||
|
is a fork of OpenWrt, meaning that the binary created by
|
||||||
|
:ref:`system-outputs-mtdimage` can be flashed using the
|
||||||
|
vendor web UI or the U-Boot emergency "unbrick" routine.
|
||||||
|
|
||||||
|
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/
|
Vendor web page: https://www.gl-inet.com/products/gl-ar750/
|
||||||
|
|
||||||
OpenWrt web page: https://openwrt.org/toh/gl.inet/gl-ar750
|
OpenWrt web page: https://openwrt.org/toh/gl.inet/gl-ar750
|
||||||
|
|
||||||
'';
|
'';
|
||||||
|
|
||||||
module = {pkgs, config, ... }:
|
module = {pkgs, config, lim, ... }:
|
||||||
let
|
let
|
||||||
openwrt = pkgs.openwrt;
|
openwrt = pkgs.openwrt;
|
||||||
firmwareBlobs = pkgs.pkgsBuildBuild.fetchFromGitHub {
|
firmwareBlobs = pkgs.pkgsBuildBuild.fetchFromGitHub {
|
||||||
@ -71,14 +71,15 @@
|
|||||||
cp $blobdir/board.bin $out/ath10k/QCA9887/hw1.0/
|
cp $blobdir/board.bin $out/ath10k/QCA9887/hw1.0/
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
mac80211 = pkgs.mac80211.override {
|
mac80211 = pkgs.kmodloader.override {
|
||||||
drivers = ["ath9k" "ath10k_pci"];
|
targets = ["ath9k" "ath10k_pci"];
|
||||||
klibBuild = config.system.outputs.kernel.modulesupport;
|
inherit (config.system.outputs) kernel;
|
||||||
|
dependencies = [ ath10k_cal_data ];
|
||||||
};
|
};
|
||||||
ath10k_cal_data =
|
ath10k_cal_data =
|
||||||
let
|
let
|
||||||
offset = 1024 * 20; # 0x5000
|
offset = lim.parseInt "0x5000";
|
||||||
size = 2048 + 68; # 0x844
|
size = lim.parseInt "0x844";
|
||||||
in pkgs.liminix.services.oneshot rec {
|
in pkgs.liminix.services.oneshot rec {
|
||||||
name = "ath10k_cal_data";
|
name = "ath10k_cal_data";
|
||||||
up = ''
|
up = ''
|
||||||
@ -96,19 +97,22 @@
|
|||||||
imports = [
|
imports = [
|
||||||
../../modules/network
|
../../modules/network
|
||||||
../../modules/arch/mipseb.nix
|
../../modules/arch/mipseb.nix
|
||||||
|
../../modules/outputs/tftpboot.nix
|
||||||
|
../../modules/outputs/mtdimage.nix
|
||||||
|
../../modules/outputs/jffs2.nix
|
||||||
];
|
];
|
||||||
|
|
||||||
programs.busybox.options = {
|
programs.busybox.options = {
|
||||||
FEATURE_DD_IBS_OBS = "y"; # ath10k_cal_data needs skip_bytes,fullblock
|
FEATURE_DD_IBS_OBS = "y"; # ath10k_cal_data needs skip_bytes,fullblock
|
||||||
};
|
};
|
||||||
hardware = {
|
hardware = {
|
||||||
defaultOutput = "flashimage";
|
defaultOutput = "mtdimage";
|
||||||
loadAddress = "0x80060000";
|
loadAddress = lim.parseInt "0x80060000";
|
||||||
entryPoint = "0x80060000";
|
entryPoint = lim.parseInt "0x80060000";
|
||||||
flash = {
|
flash = {
|
||||||
address = "0x9F060000";
|
address = lim.parseInt "0x9F060000";
|
||||||
size ="0xfa0000";
|
size = lim.parseInt "0xfa0000";
|
||||||
eraseBlockSize = "65536";
|
eraseBlockSize = 65536;
|
||||||
};
|
};
|
||||||
rootDevice = "/dev/mtdblock5";
|
rootDevice = "/dev/mtdblock5";
|
||||||
dts = {
|
dts = {
|
||||||
@ -129,7 +133,7 @@
|
|||||||
};
|
};
|
||||||
wlan5 = link.build {
|
wlan5 = link.build {
|
||||||
ifname = "wlan1";
|
ifname = "wlan1";
|
||||||
dependencies = [ mac80211 ath10k_cal_data ];
|
dependencies = [ ath10k_cal_data mac80211 ];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@ -144,17 +148,24 @@
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
boot.tftp = {
|
boot.tftp = {
|
||||||
loadAddress = "0x00A00000";
|
loadAddress = lim.parseInt "0x00A00000";
|
||||||
};
|
};
|
||||||
kernel = {
|
kernel = {
|
||||||
src = pkgs.pkgsBuildBuild.fetchurl {
|
src = pkgs.pkgsBuildBuild.fetchurl {
|
||||||
name = "linux.tar.gz";
|
name = "linux.tar.gz";
|
||||||
url = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.71.tar.gz";
|
url = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.137.tar.gz";
|
||||||
hash = "sha256-yhO2cXIeIgUxkSZf/4aAsF11uxyh+UUZu6D1h92vCD8=";
|
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 = ''
|
extraPatchPhase = ''
|
||||||
${openwrt.applyPatches.ath79}
|
${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 = {
|
config = {
|
||||||
ATH79 = "y";
|
ATH79 = "y";
|
||||||
PCI = "y";
|
PCI = "y";
|
||||||
@ -175,7 +186,6 @@
|
|||||||
CONSOLE_LOGLEVEL_QUIET = "4";
|
CONSOLE_LOGLEVEL_QUIET = "4";
|
||||||
|
|
||||||
NET = "y";
|
NET = "y";
|
||||||
NETDEVICES = "y";
|
|
||||||
ETHERNET = "y";
|
ETHERNET = "y";
|
||||||
NET_VENDOR_ATHEROS = "y";
|
NET_VENDOR_ATHEROS = "y";
|
||||||
AG71XX = "y"; # ethernet (qca,qca9530-eth)
|
AG71XX = "y"; # ethernet (qca,qca9530-eth)
|
||||||
@ -204,14 +214,21 @@
|
|||||||
WATCHDOG = "y";
|
WATCHDOG = "y";
|
||||||
ATH79_WDT = "y"; # watchdog timer
|
ATH79_WDT = "y"; # watchdog timer
|
||||||
|
|
||||||
# this is all copied from nixwrt ath79 config. Clearly not all
|
|
||||||
# of it is device config, some of it is wifi config or
|
|
||||||
# installation method config or ...
|
|
||||||
|
|
||||||
EARLY_PRINTK = "y";
|
EARLY_PRINTK = "y";
|
||||||
|
|
||||||
PRINTK_TIME = "y";
|
PRINTK_TIME = "y";
|
||||||
};
|
};
|
||||||
|
conditionalConfig = {
|
||||||
|
WLAN = {
|
||||||
|
WLAN_VENDOR_ATH = "y";
|
||||||
|
ATH_COMMON = "m";
|
||||||
|
ATH9K = "m";
|
||||||
|
ATH9K_AHB = "y";
|
||||||
|
ATH10K = "m";
|
||||||
|
ATH10K_PCI = "m";
|
||||||
|
ATH10K_DEBUG = "y";
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -13,34 +13,11 @@
|
|||||||
|
|
||||||
description = ''
|
description = ''
|
||||||
GL.iNet GL-MT300A
|
GL.iNet GL-MT300A
|
||||||
********************
|
*****************
|
||||||
|
|
||||||
The GL-MT300A is based on a MT7620 chipset.
|
The GL-MT300A is based on a MT7620 chipset.
|
||||||
|
|
||||||
The GL.iNet pocket router range makes nice cheap hardware for
|
For flashing from U-Boot, the firmware partition is from
|
||||||
playing with Liminix or similar projects. The manufacturers seem
|
|
||||||
open to the DIY market, and the devices have a reasonable amount
|
|
||||||
of RAM and are much easier to get serial connections than many
|
|
||||||
COTS routers.
|
|
||||||
|
|
||||||
Wire up the serial connection: this probably involves opening
|
|
||||||
the box, locating the serial header pins (TX, RX and GND) and
|
|
||||||
connecting a USB TTL converter - e.g. a PL2303 based device - to
|
|
||||||
it. The defunct OpenWRT wiki has a guide with some pictures. (If
|
|
||||||
you don't have a USB TTL converter to hand, other options are
|
|
||||||
available. For example, use the GPIO pins on a Raspberry Pi.)
|
|
||||||
|
|
||||||
Run a terminal emulator such as Minicom on whatever is on the
|
|
||||||
other end of the link. I use 115200 8N1 and find it also helps
|
|
||||||
to set "Line tx delay" to 1ms, "backspace sends DEL" and
|
|
||||||
"lineWrap on".
|
|
||||||
|
|
||||||
When you turn the router on you should be greeted with some
|
|
||||||
messages from U-Boot and a little bit of ASCII art, followed by
|
|
||||||
the instruction to hit SPACE to stop autoboot. Do this and you
|
|
||||||
will get a gl-mt300a> prompt.
|
|
||||||
|
|
||||||
For flashing from uboot, the firmware partition is from
|
|
||||||
0xbc050000 to 0xbcfd0000.
|
0xbc050000 to 0xbcfd0000.
|
||||||
|
|
||||||
WiFi on this device is provided by the rt2800soc module. It
|
WiFi on this device is provided by the rt2800soc module. It
|
||||||
@ -48,6 +25,17 @@
|
|||||||
- assuming we want to use the wireless - we need to build MTD
|
- assuming we want to use the wireless - we need to build MTD
|
||||||
support into the kernel even if we're using TFTP root.
|
support into the kernel even if we're using TFTP root.
|
||||||
|
|
||||||
|
Installation
|
||||||
|
============
|
||||||
|
|
||||||
|
The stock vendor firmware is a fork of OpenWrt, meaning that the
|
||||||
|
binary created by :ref:`system-outputs-mtdimage` can be flashed
|
||||||
|
using the vendor web UI or the U-Boot emergency "unbrick" routine.
|
||||||
|
|
||||||
|
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/
|
Vendor web page: https://www.gl-inet.com/products/gl-mt300a/
|
||||||
|
|
||||||
@ -55,20 +43,25 @@
|
|||||||
|
|
||||||
'';
|
'';
|
||||||
|
|
||||||
module = { pkgs, config, lib, ...}:
|
module = { pkgs, config, lib, lim, ...}:
|
||||||
let
|
let
|
||||||
inherit (pkgs.liminix.networking) interface;
|
inherit (pkgs.liminix.networking) interface;
|
||||||
inherit (pkgs) openwrt;
|
inherit (pkgs) openwrt;
|
||||||
mac80211 = pkgs.mac80211.override {
|
mac80211 = pkgs.kmodloader.override {
|
||||||
drivers = ["rt2800soc"];
|
targets = ["rt2800soc"];
|
||||||
klibBuild = config.system.outputs.kernel.modulesupport;
|
inherit (config.system.outputs) kernel;
|
||||||
};
|
};
|
||||||
in {
|
in {
|
||||||
imports = [ ../../modules/arch/mipsel.nix ];
|
imports = [
|
||||||
|
../../modules/arch/mipsel.nix
|
||||||
|
../../modules/outputs/tftpboot.nix
|
||||||
|
../../modules/outputs/mtdimage.nix
|
||||||
|
../../modules/outputs/jffs2.nix
|
||||||
|
];
|
||||||
hardware = {
|
hardware = {
|
||||||
defaultOutput = "flashimage";
|
defaultOutput = "mtdimage";
|
||||||
loadAddress = "0x80000000";
|
loadAddress = lim.parseInt "0x80000000";
|
||||||
entryPoint = "0x80000000";
|
entryPoint = lim.parseInt "0x80000000";
|
||||||
|
|
||||||
# Creating 5 MTD partitions on "spi0.0":
|
# Creating 5 MTD partitions on "spi0.0":
|
||||||
# 0x000000000000-0x000000030000 : "u-boot"
|
# 0x000000000000-0x000000030000 : "u-boot"
|
||||||
@ -81,9 +74,9 @@
|
|||||||
# 0x000000260000-0x000000f80000 : "rootfs"
|
# 0x000000260000-0x000000f80000 : "rootfs"
|
||||||
|
|
||||||
flash = {
|
flash = {
|
||||||
address = "0xbc050000";
|
address = lim.parseInt "0xbc050000";
|
||||||
size ="0xf80000";
|
size = lim.parseInt "0xf80000";
|
||||||
eraseBlockSize = "65536";
|
eraseBlockSize = 65536;
|
||||||
};
|
};
|
||||||
rootDevice = "/dev/mtdblock5";
|
rootDevice = "/dev/mtdblock5";
|
||||||
|
|
||||||
@ -132,14 +125,14 @@
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
boot.tftp = {
|
boot.tftp = {
|
||||||
loadAddress = "0x00A00000";
|
loadAddress = lim.parseInt "0x00A00000";
|
||||||
};
|
};
|
||||||
|
|
||||||
kernel = {
|
kernel = {
|
||||||
src = pkgs.fetchurl {
|
src = pkgs.fetchurl {
|
||||||
name = "linux.tar.gz";
|
name = "linux.tar.gz";
|
||||||
url = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.71.tar.gz";
|
url = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.137.tar.gz";
|
||||||
hash = "sha256-yhO2cXIeIgUxkSZf/4aAsF11uxyh+UUZu6D1h92vCD8=";
|
hash = "sha256-PkdzUKZ0IpBiWe/RS70J76JKnBFzRblWcKlaIFNxnHQ=";
|
||||||
};
|
};
|
||||||
extraPatchPhase = ''
|
extraPatchPhase = ''
|
||||||
${openwrt.applyPatches.ramips}
|
${openwrt.applyPatches.ramips}
|
||||||
@ -159,7 +152,6 @@
|
|||||||
CONSOLE_LOGLEVEL_QUIET = "4";
|
CONSOLE_LOGLEVEL_QUIET = "4";
|
||||||
|
|
||||||
NET = "y";
|
NET = "y";
|
||||||
NETDEVICES = "y";
|
|
||||||
ETHERNET = "y";
|
ETHERNET = "y";
|
||||||
NET_VENDOR_RALINK = "y";
|
NET_VENDOR_RALINK = "y";
|
||||||
NET_RALINK_MDIO = "y";
|
NET_RALINK_MDIO = "y";
|
||||||
@ -186,6 +178,14 @@
|
|||||||
} // lib.optionalAttrs (config.system.service ? vlan) {
|
} // lib.optionalAttrs (config.system.service ? vlan) {
|
||||||
SWCONFIG = "y";
|
SWCONFIG = "y";
|
||||||
};
|
};
|
||||||
|
conditionalConfig = {
|
||||||
|
WLAN = {
|
||||||
|
WLAN_VENDOR_RALINK = "y";
|
||||||
|
RT2800SOC = "m";
|
||||||
|
RT2X00 = "m";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -13,10 +13,22 @@
|
|||||||
GL.iNet GL-MT300N-v2
|
GL.iNet GL-MT300N-v2
|
||||||
********************
|
********************
|
||||||
|
|
||||||
The GL-MT300N-v2 "Mango" is is very similar to the MT300A, but is
|
The GL-MT300N-v2 "Mango" is is very similar to the :ref:`MT300A <GL.iNet GL-MT300A>, but is
|
||||||
based on MT7628 instead of MT7620. It's also marginally cheaper
|
based on the MT7628 chipset instead of MT7620. It's also marginally cheaper
|
||||||
and comes in a yellow case not a blue one. It's different again
|
and comes in a yellow case not a blue one. Be sure your device is
|
||||||
to the v1, which has only half the RAM.
|
v2 not v1, which is a different animal and has only half as much RAM.
|
||||||
|
|
||||||
|
Installation
|
||||||
|
============
|
||||||
|
|
||||||
|
The stock vendor firmware is a fork of OpenWrt, meaning that the
|
||||||
|
binary created by :ref:`system-outputs-mtdimage` can be flashed
|
||||||
|
using the vendor web UI or the U-Boot emergency "unbrick" routine.
|
||||||
|
|
||||||
|
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/
|
Vendor web page: https://www.gl-inet.com/products/gl-mt300n-v2/
|
||||||
|
|
||||||
@ -24,23 +36,28 @@
|
|||||||
|
|
||||||
'';
|
'';
|
||||||
|
|
||||||
module = { pkgs, config, lib, ...}:
|
module = { pkgs, config, lib, lim, ...}:
|
||||||
let
|
let
|
||||||
inherit (pkgs.liminix.networking) interface;
|
inherit (pkgs.liminix.networking) interface;
|
||||||
inherit (pkgs.liminix.services) oneshot;
|
inherit (pkgs.liminix.services) oneshot;
|
||||||
inherit (pkgs.pseudofile) dir symlink;
|
inherit (pkgs.pseudofile) dir symlink;
|
||||||
inherit (pkgs) openwrt;
|
inherit (pkgs) openwrt;
|
||||||
|
|
||||||
mac80211 = pkgs.mac80211.override {
|
mac80211 = pkgs.kmodloader.override {
|
||||||
drivers = ["mt7603e"];
|
targets = ["mt7603e"];
|
||||||
klibBuild = config.system.outputs.kernel.modulesupport;
|
inherit (config.system.outputs) kernel;
|
||||||
};
|
};
|
||||||
wlan_firmware = pkgs.fetchurl {
|
wlan_firmware = pkgs.fetchurl {
|
||||||
url = "https://github.com/openwrt/mt76/raw/f24b56f935392ca1d35fae5fd6e56ef9deda4aad/firmware/mt7628_e2.bin";
|
url = "https://github.com/openwrt/mt76/raw/f24b56f935392ca1d35fae5fd6e56ef9deda4aad/firmware/mt7628_e2.bin";
|
||||||
hash = "sha256:1dkhfznmdz6s50kwc841x3wj0h6zg6icg5g2bim9pvg66as2vmh9";
|
hash = "sha256:1dkhfznmdz6s50kwc841x3wj0h6zg6icg5g2bim9pvg66as2vmh9";
|
||||||
};
|
};
|
||||||
in {
|
in {
|
||||||
imports = [ ../../modules/arch/mipsel.nix ];
|
imports = [
|
||||||
|
../../modules/arch/mipsel.nix
|
||||||
|
../../modules/outputs/tftpboot.nix
|
||||||
|
../../modules/outputs/mtdimage.nix
|
||||||
|
../../modules/outputs/jffs2.nix
|
||||||
|
];
|
||||||
filesystem = dir {
|
filesystem = dir {
|
||||||
lib = dir {
|
lib = dir {
|
||||||
firmware = dir {
|
firmware = dir {
|
||||||
@ -49,14 +66,14 @@
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
hardware = {
|
hardware = {
|
||||||
defaultOutput = "flashimage";
|
defaultOutput = "mtdimage";
|
||||||
loadAddress = "0x80000000";
|
loadAddress = lim.parseInt "0x80000000";
|
||||||
entryPoint = "0x80000000";
|
entryPoint = lim.parseInt "0x80000000";
|
||||||
|
|
||||||
flash = {
|
flash = {
|
||||||
address = "0xbc050000";
|
address = lim.parseInt "0xbc050000";
|
||||||
size = "0xfb0000";
|
size = lim.parseInt "0xfb0000";
|
||||||
eraseBlockSize = "65536";
|
eraseBlockSize = 65536;
|
||||||
};
|
};
|
||||||
rootDevice = "/dev/mtdblock5";
|
rootDevice = "/dev/mtdblock5";
|
||||||
|
|
||||||
@ -104,14 +121,14 @@
|
|||||||
boot.tftp = {
|
boot.tftp = {
|
||||||
# 20MB seems to give enough room to uncompress the kernel
|
# 20MB seems to give enough room to uncompress the kernel
|
||||||
# without anything getting trodden on. 10MB was too small
|
# without anything getting trodden on. 10MB was too small
|
||||||
loadAddress = "0x1400000";
|
loadAddress = lim.parseInt "0x1400000";
|
||||||
};
|
};
|
||||||
|
|
||||||
kernel = {
|
kernel = {
|
||||||
src = pkgs.fetchurl {
|
src = pkgs.fetchurl {
|
||||||
name = "linux.tar.gz";
|
name = "linux.tar.gz";
|
||||||
url = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.71.tar.gz";
|
url = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.137.tar.gz";
|
||||||
hash = "sha256-yhO2cXIeIgUxkSZf/4aAsF11uxyh+UUZu6D1h92vCD8=";
|
hash = "sha256-PkdzUKZ0IpBiWe/RS70J76JKnBFzRblWcKlaIFNxnHQ=";
|
||||||
};
|
};
|
||||||
extraPatchPhase = ''
|
extraPatchPhase = ''
|
||||||
${openwrt.applyPatches.ramips}
|
${openwrt.applyPatches.ramips}
|
||||||
@ -143,7 +160,6 @@
|
|||||||
REGULATOR_FIXED_VOLTAGE = "y";
|
REGULATOR_FIXED_VOLTAGE = "y";
|
||||||
|
|
||||||
NET = "y";
|
NET = "y";
|
||||||
NETDEVICES = "y";
|
|
||||||
ETHERNET = "y";
|
ETHERNET = "y";
|
||||||
|
|
||||||
PHYLIB = "y";
|
PHYLIB = "y";
|
||||||
@ -169,6 +185,15 @@
|
|||||||
RALINK_WDT = "y"; # watchdog
|
RALINK_WDT = "y"; # watchdog
|
||||||
MT7621_WDT = "y"; # or it might be this one
|
MT7621_WDT = "y"; # or it might be this one
|
||||||
};
|
};
|
||||||
|
conditionalConfig = {
|
||||||
|
WLAN = {
|
||||||
|
WLAN_VENDOR_RALINK = "y";
|
||||||
|
WLAN_VENDOR_MEDIATEK = "y";
|
||||||
|
MT7603E = "m";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -9,64 +9,43 @@
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
description = ''
|
||||||
|
QEMU Aarch64
|
||||||
|
************
|
||||||
|
|
||||||
|
This target produces an image for
|
||||||
|
the `QEMU "virt" platform <https://www.qemu.org/docs/master/system/arm/virt.html>`_ using a 64 bit CPU type.
|
||||||
|
|
||||||
|
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` (MIPS) target for more information.
|
||||||
|
|
||||||
|
'';
|
||||||
|
|
||||||
# this device is described by the "qemu" device
|
# this device is described by the "qemu" device
|
||||||
description = "";
|
installer = "vmroot";
|
||||||
|
|
||||||
|
module = {pkgs, config, lim, ... }: {
|
||||||
module = {pkgs, config, ... }: {
|
imports = [
|
||||||
imports = [ ../../modules/arch/aarch64.nix ];
|
../../modules/arch/aarch64.nix
|
||||||
|
../families/qemu.nix
|
||||||
|
];
|
||||||
kernel = {
|
kernel = {
|
||||||
src = pkgs.pkgsBuildBuild.fetchurl {
|
|
||||||
name = "linux.tar.gz";
|
|
||||||
url = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.71.tar.gz";
|
|
||||||
hash = "sha256-yhO2cXIeIgUxkSZf/4aAsF11uxyh+UUZu6D1h92vCD8=";
|
|
||||||
};
|
|
||||||
config = {
|
config = {
|
||||||
VIRTUALIZATION = "y";
|
VIRTUALIZATION = "y";
|
||||||
PCI_HOST_GENERIC="y";
|
PCI_HOST_GENERIC="y";
|
||||||
|
|
||||||
MTD = "y";
|
|
||||||
MTD_BLOCK2MTD = "y";
|
|
||||||
MTD_BLOCK = "y";
|
|
||||||
|
|
||||||
VIRTIO_MENU = "y";
|
|
||||||
PCI = "y";
|
|
||||||
VIRTIO_PCI = "y";
|
|
||||||
BLOCK = "y";
|
|
||||||
VIRTIO_BLK = "y";
|
|
||||||
NETDEVICES = "y";
|
|
||||||
VIRTIO_NET = "y";
|
|
||||||
|
|
||||||
SERIAL_EARLYCON_ARM_SEMIHOST = "y"; # earlycon=smh
|
|
||||||
SERIAL_AMBA_PL011 = "y";
|
SERIAL_AMBA_PL011 = "y";
|
||||||
SERIAL_AMBA_PL011_CONSOLE = "y";
|
SERIAL_AMBA_PL011_CONSOLE = "y";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
hardware =
|
boot.commandLine = [
|
||||||
let
|
"console=ttyAMA0,38400"
|
||||||
mac80211 = pkgs.mac80211.override {
|
];
|
||||||
drivers = ["mac80211_hwsim"];
|
hardware = let addr = lim.parseInt "0x40010000"; in {
|
||||||
klibBuild = config.system.outputs.kernel.modulesupport;
|
loadAddress = addr;
|
||||||
};
|
entryPoint = addr;
|
||||||
in {
|
};
|
||||||
defaultOutput = "vmroot";
|
|
||||||
loadAddress = "0x0";
|
|
||||||
entryPoint = "0x0";
|
|
||||||
rootDevice = "/dev/mtdblock0";
|
|
||||||
|
|
||||||
flash.eraseBlockSize = "65536"; # c.f. pkgs/mips-vm/mips-vm.sh
|
|
||||||
networkInterfaces =
|
|
||||||
let inherit (config.system.service.network) link;
|
|
||||||
in {
|
|
||||||
wan = link.build { ifname = "eth0"; };
|
|
||||||
lan = link.build { ifname = "eth1"; };
|
|
||||||
|
|
||||||
wlan_24 = link.build {
|
|
||||||
ifname = "wlan0";
|
|
||||||
dependencies = [ mac80211 ];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
53
devices/qemu-armv7l/default.nix
Normal file
53
devices/qemu-armv7l/default.nix
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
# This "device" generates images that can be used with the QEMU
|
||||||
|
# emulator. The default output is a directory containing separate
|
||||||
|
# kernel ("Image" format) and root filesystem (squashfs or jffs2)
|
||||||
|
# images
|
||||||
|
{
|
||||||
|
system = {
|
||||||
|
crossSystem = {
|
||||||
|
config = "armv7l-unknown-linux-musleabihf";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# this device is described by the "qemu" device
|
||||||
|
description = ''
|
||||||
|
QEMU ARM v7
|
||||||
|
***********
|
||||||
|
|
||||||
|
This target produces an image for
|
||||||
|
the `QEMU "virt" platform <https://www.qemu.org/docs/master/system/arm/virt.html>`_ using a 32 bit CPU type.
|
||||||
|
|
||||||
|
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` (MIPS) target for more information.
|
||||||
|
'';
|
||||||
|
installer = "vmroot";
|
||||||
|
|
||||||
|
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";
|
||||||
|
|
||||||
|
SERIAL_AMBA_PL011 = "y";
|
||||||
|
SERIAL_AMBA_PL011_CONSOLE = "y";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
boot.commandLine = [
|
||||||
|
"console=ttyAMA0"
|
||||||
|
];
|
||||||
|
hardware = let addr = lim.parseInt "0x40008000"; in {
|
||||||
|
loadAddress = addr;
|
||||||
|
entryPoint = addr;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
@ -13,24 +13,21 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
description = ''
|
description = ''
|
||||||
QEMU
|
QEMU MIPS
|
||||||
****
|
*********
|
||||||
|
|
||||||
This is not a hardware device. This target produces an image for
|
This target produces an image for
|
||||||
QEMU, the "generic and open source machine emulator and
|
QEMU, the "generic and open source machine emulator and
|
||||||
virtualizer".
|
virtualizer".
|
||||||
|
|
||||||
Liminix can build QEMU for both MIPS (:code:`qemu` device) and Aarch64 (:code:`qemu-aarch64` device)
|
|
||||||
|
|
||||||
MIPS QEMU emulates a "Malta" board, which was an ATX form factor
|
MIPS QEMU emulates a "Malta" board, which was an ATX form factor
|
||||||
evaluation board made by MIPS Technologies, but mostly in Liminix
|
evaluation board made by MIPS Technologies, but mostly in Liminix
|
||||||
we use paravirtualized devices (Virtio) instead of emulating
|
we use paravirtualized devices (Virtio) instead of emulating
|
||||||
hardware. For Aarch64 we use the QEMU "virt" board.
|
hardware.
|
||||||
|
|
||||||
Building an image for QEMU results in a :file:`result/` directory
|
Building an image for QEMU results in a :file:`result/` directory
|
||||||
containing ``run.sh`` ``vmlinux``, ``rootfs`` and possibly
|
containing ``run.sh`` ``vmlinux``, and ``rootfs`` files. To invoke
|
||||||
(architecture-dependent) ``Image``. To invoke the emulator,
|
the emulator, run ``run.sh``.
|
||||||
run ``run.sh``.
|
|
||||||
|
|
||||||
The configuration includes two emulated "hardware" ethernet
|
The configuration includes two emulated "hardware" ethernet
|
||||||
devices and the kernel :code:`mac80211_hwsim` module to
|
devices and the kernel :code:`mac80211_hwsim` module to
|
||||||
@ -39,56 +36,41 @@
|
|||||||
in the Development manual.
|
in the Development manual.
|
||||||
|
|
||||||
'';
|
'';
|
||||||
module = {pkgs, config, ... }: {
|
module = {pkgs, config, lib, lim, ... }: {
|
||||||
imports = [ ../../modules/arch/mipseb.nix ];
|
imports = [
|
||||||
|
../../modules/arch/mipseb.nix
|
||||||
|
../families/qemu.nix
|
||||||
|
];
|
||||||
kernel = {
|
kernel = {
|
||||||
src = pkgs.pkgsBuildBuild.fetchurl {
|
|
||||||
name = "linux.tar.gz";
|
|
||||||
url = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.71.tar.gz";
|
|
||||||
hash = "sha256-yhO2cXIeIgUxkSZf/4aAsF11uxyh+UUZu6D1h92vCD8=";
|
|
||||||
};
|
|
||||||
config = {
|
config = {
|
||||||
MIPS_MALTA= "y";
|
MIPS_MALTA= "y";
|
||||||
CPU_MIPS32_R2= "y";
|
CPU_MIPS32_R2= "y";
|
||||||
|
|
||||||
MTD = "y";
|
POWER_RESET = "y";
|
||||||
MTD_BLOCK2MTD = "y";
|
POWER_RESET_SYSCON = "y";
|
||||||
MTD_BLOCK = "y";
|
|
||||||
|
|
||||||
VIRTIO_MENU = "y";
|
|
||||||
PCI = "y";
|
|
||||||
VIRTIO_PCI = "y";
|
|
||||||
BLOCK = "y";
|
|
||||||
VIRTIO_BLK = "y";
|
|
||||||
NETDEVICES = "y";
|
|
||||||
VIRTIO_NET = "y";
|
|
||||||
|
|
||||||
SERIAL_8250= "y";
|
SERIAL_8250= "y";
|
||||||
SERIAL_8250_CONSOLE= "y";
|
SERIAL_8250_CONSOLE= "y";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
hardware =
|
hardware =
|
||||||
let
|
# from arch/mips/mti-malta/Platform:load-$(CONFIG_MIPS_MALTA) += 0xffffffff80100000
|
||||||
mac80211 = pkgs.mac80211.override {
|
let addr = lim.parseInt "0x80100000";
|
||||||
drivers = ["mac80211_hwsim"];
|
|
||||||
klibBuild = config.system.outputs.kernel.modulesupport;
|
|
||||||
};
|
|
||||||
in {
|
in {
|
||||||
defaultOutput = "vmroot";
|
loadAddress = addr;
|
||||||
rootDevice = "/dev/mtdblock0";
|
entryPoint = addr;
|
||||||
flash.eraseBlockSize = "65536"; # c.f. pkgs/run-liminix-vm/run-liminix-vm.sh
|
|
||||||
networkInterfaces =
|
# Unlike the arm qemu targets, we need a static dts when
|
||||||
let inherit (config.system.service.network) link;
|
# running u-boot-using tests, qemu dumpdtb command doesn't
|
||||||
in {
|
# work for this board. I am not at all sure this dts is
|
||||||
wan = link.build { ifname = "eth0"; };
|
# *correct* but it does at least boot
|
||||||
lan = link.build { ifname = "eth1"; };
|
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/"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
wlan_24 = link.build {
|
|
||||||
ifname = "wlan0";
|
|
||||||
dependencies = [ mac80211 ];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
442
devices/tp-archer-ax23/default.nix
Normal file
442
devices/tp-archer-ax23/default.nix
Normal file
@ -0,0 +1,442 @@
|
|||||||
|
{
|
||||||
|
description = ''
|
||||||
|
TP-Link Archer AX23 / AX1800 Dual Band Wi-Fi 6 Router
|
||||||
|
*****************************************************
|
||||||
|
|
||||||
|
Hardware summary
|
||||||
|
================
|
||||||
|
|
||||||
|
- MediaTek MT7621 (880MHz)
|
||||||
|
- 16MB Flash
|
||||||
|
- 128MB RAM
|
||||||
|
- WLan hardware: Mediatek MT7905, MT7975
|
||||||
|
|
||||||
|
Limitations
|
||||||
|
===========
|
||||||
|
|
||||||
|
Status LEDs do not work yet.
|
||||||
|
|
||||||
|
Uploading an image via tftp doesn't work yet, because the Archer uboot
|
||||||
|
version is so old it doesn't support overriding the DTB from the mboot
|
||||||
|
command. The tftpboot module doesn't support this yet, see
|
||||||
|
https://gti.telent.net/dan/liminix/pulls/5 for the WiP.
|
||||||
|
'';
|
||||||
|
|
||||||
|
system = {
|
||||||
|
crossSystem = {
|
||||||
|
config = "mipsel-unknown-linux-musl";
|
||||||
|
gcc = {
|
||||||
|
abi = "32";
|
||||||
|
# https://openwrt.org/docs/techref/instructionset/mipsel_24kc
|
||||||
|
arch = "24kc";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
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
|
||||||
|
../../modules/outputs/tplink-safeloader.nix
|
||||||
|
];
|
||||||
|
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
|
||||||
|
};
|
||||||
|
conditionalConfig = {
|
||||||
|
WLAN = {
|
||||||
|
MT7915E = "m";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
tplink-safeloader.board = "ARCHER-AX23-V1";
|
||||||
|
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 0x80001000, which suggests the
|
||||||
|
# RAM would start at 0x8000000 and (being 128MB) go to
|
||||||
|
# to 0x8800000. Let's put it at the 100MB mark at
|
||||||
|
# 0x8000000+0x0640000=0x86400000
|
||||||
|
loadAddress = lim.parseInt "0x86400000";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
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 = [
|
||||||
|
"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";
|
||||||
|
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 ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
412
devices/turris-omnia/default.nix
Normal file
412
devices/turris-omnia/default.nix
Normal file
@ -0,0 +1,412 @@
|
|||||||
|
{
|
||||||
|
description = ''
|
||||||
|
Turris Omnia
|
||||||
|
************
|
||||||
|
|
||||||
|
This is a 32 bit ARMv7 MVEBU device, which is usually shipped with
|
||||||
|
TurrisOS, an OpenWrt-based system. Rather than reformatting the
|
||||||
|
builtin storage, we install Liminix on to the existing btrfs
|
||||||
|
filesystem so that the vendor snapshot/recovery system continues
|
||||||
|
to work (and provides you an easy rollback if you decide you don't
|
||||||
|
like Liminix after all).
|
||||||
|
|
||||||
|
The install process has two stages, and is intended that you
|
||||||
|
should not need to open the device and add a serial console
|
||||||
|
(although it may be handy for visibility, and in case anything
|
||||||
|
goes wrong). First we build a minimal installation/recovery
|
||||||
|
system, then we reboot into that recovery image to prepare the
|
||||||
|
device for the full target install.
|
||||||
|
|
||||||
|
Installation using a USB stick
|
||||||
|
==============================
|
||||||
|
|
||||||
|
First, build the image for the USB stick. Review
|
||||||
|
:file:`examples/recovery.nix` in order to change the default
|
||||||
|
root password (which is ``secret``) and/or the SSH keys, then
|
||||||
|
build it with
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
$ nix-build -I liminix-config=./examples/recovery.nix \
|
||||||
|
--arg device "import ./devices/turris-omnia" \
|
||||||
|
-A outputs.mbrimage -o mbrimage
|
||||||
|
$ file -L mbrimage
|
||||||
|
mbrimage: DOS/MBR boot sector; partition 1 : ID=0x83, active, start-CHS (0x0,0,5), end-CHS (0x6,130,26), startsector 4, 104602 sectors
|
||||||
|
|
||||||
|
Next, copy the image from your build machine to a USB storage
|
||||||
|
medium using :command:`dd` or your other most favoured file copying
|
||||||
|
tool, which might be a comand something like this:
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
$ dd if=mbrimage of=/dev/path/to/the/usb/stick \
|
||||||
|
bs=1M conv=fdatasync status=progress
|
||||||
|
|
||||||
|
The Omnia's default boot order only checks USB after it has failed
|
||||||
|
to boot from eMMC, which is not ideal for our purpose. Unless you
|
||||||
|
have a serial cable, the easiest way to change this is by booting
|
||||||
|
to TurrisOS and logging in with ssh:
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
root@turris:/# fw_printenv boot_targets
|
||||||
|
boot_targets=mmc0 nvme0 scsi0 usb0 pxe dhcp
|
||||||
|
root@turris:/# fw_setenv boot_targets usb0 mmc0
|
||||||
|
root@turris:/# fw_printenv boot_targets
|
||||||
|
boot_targets=usb0 mmc0
|
||||||
|
root@turris:/# reboot -f
|
||||||
|
|
||||||
|
It should now boot into the recovery image. It expects a network
|
||||||
|
cable to be plugged into LAN2 with something on the other end of
|
||||||
|
it that serves DHCP requests. Check your DHCP server logs for a
|
||||||
|
request from a ``liminix-recovery`` host and figure out what IP
|
||||||
|
address was assigned.
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
$ ssh liminix-recovery.lan
|
||||||
|
|
||||||
|
You should get a "Busybox" banner and a root prompt. Now you can
|
||||||
|
start preparing the device to install Liminix on it. First we'll
|
||||||
|
mount the root filesystem and take a snapshot:
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
# mkdir /dest && mount /dev/mmcblk0p1 /dest
|
||||||
|
# schnapps -d /dest create "pre liminix"
|
||||||
|
# schnapps -d /dest list
|
||||||
|
ERROR: not a valid btrfs filesystem: /
|
||||||
|
# | Type | Size | Date | Description
|
||||||
|
------+-----------+-------------+---------------------------+------------------------------------
|
||||||
|
1 | single | 16.00KiB | 1970-01-01 00:11:49 +0000 | pre liminix
|
||||||
|
|
||||||
|
(``not a valid btrfs filesystem: /`` is not a real error)
|
||||||
|
|
||||||
|
then we can remove all the files
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
# rm -r /dest/@/*
|
||||||
|
|
||||||
|
and then it's ready to install the real Liminix system onto. On
|
||||||
|
your build system, create the Liminix configuration you wish to
|
||||||
|
install: here we'll use the ``rotuer`` example.
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
build$ nix-build -I liminix-config=./examples/rotuer.nix \
|
||||||
|
--arg device "import ./devices/turris-omnia" \
|
||||||
|
-A outputs.systemConfiguration
|
||||||
|
|
||||||
|
and then use :command:`min-copy-closure` to copy it to the device.
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
build$ nix-shell --run \
|
||||||
|
"min-copy-closure -r /dest/@ root@liminix-recovery.lan result"
|
||||||
|
|
||||||
|
and activate it
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
build$ ssh root@liminix-recovery.lan \
|
||||||
|
"/dest/@/$(readlink result)/bin/install /dest/@"
|
||||||
|
|
||||||
|
The final steps are performed directly on the device again: add
|
||||||
|
a symlink so U-Boot can find :file:`/boot`, then restore the
|
||||||
|
default boot order and reboot into the new configuration.
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
# cd /dest && ln -s @/boot .
|
||||||
|
# fw_setenv boot_targets "mmc0 nvme0 scsi0 usb0 pxe dhcp"
|
||||||
|
# cd / ; umount /dest
|
||||||
|
# reboot
|
||||||
|
|
||||||
|
|
||||||
|
Installation using a TFTP server and serial console
|
||||||
|
===================================================
|
||||||
|
|
||||||
|
If you have a :ref:`serial` console connection and a TFTP server,
|
||||||
|
and would rather use them than fiddling with USB sticks, the
|
||||||
|
:file:`examples/recovery.nix` configuration also works
|
||||||
|
using the ``tftpboot`` output. So you can do
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
build$ nix-build -I liminix-config=./examples/recovery.nix \
|
||||||
|
--arg device "import ./devices/turris-omnia" \
|
||||||
|
-A outputs.tftpboot
|
||||||
|
|
||||||
|
and then paste the generated :file:`result/boot.scr` into
|
||||||
|
U-Boot, and you will end up with the same system as you would
|
||||||
|
have had after booting from USB. If you don't have a serial
|
||||||
|
console connection you could probably even get clever with
|
||||||
|
elaborate use of :command:`fw_setenv`, but that is left as
|
||||||
|
an exercise for the reader.
|
||||||
|
|
||||||
|
'';
|
||||||
|
|
||||||
|
system = {
|
||||||
|
crossSystem = {
|
||||||
|
config = "armv7l-unknown-linux-musleabihf";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
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 {
|
||||||
|
name = "mtd_by_name_links";
|
||||||
|
up = ''
|
||||||
|
mkdir -p /dev/mtd/by-name
|
||||||
|
cd /dev/mtd/by-name
|
||||||
|
for i in /sys/class/mtd/mtd*[0-9]; do
|
||||||
|
ln -s ../../$(basename $i) $(cat $i/name)
|
||||||
|
done
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
in {
|
||||||
|
imports = [
|
||||||
|
../../modules/arch/arm.nix
|
||||||
|
../../modules/outputs/tftpboot.nix
|
||||||
|
../../modules/outputs/mbrimage.nix
|
||||||
|
../../modules/outputs/extlinux.nix
|
||||||
|
];
|
||||||
|
|
||||||
|
config = {
|
||||||
|
services.mtd-name-links = mtd_by_name_links;
|
||||||
|
kernel = {
|
||||||
|
src = pkgs.pkgsBuildBuild.fetchurl {
|
||||||
|
name = "linux.tar.gz";
|
||||||
|
url = "https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.7.4.tar.gz";
|
||||||
|
hash = "sha256-wIrmL0BS63nRwWfm4nw+dRNVPUzGh9M4X7LaHzAn5tU=";
|
||||||
|
};
|
||||||
|
version = "6.7.4";
|
||||||
|
config = {
|
||||||
|
PCI = "y";
|
||||||
|
OF = "y";
|
||||||
|
MEMORY = "y"; # for MVEBU_DEVBUS
|
||||||
|
DMADEVICES = "y"; # for MV_XOR
|
||||||
|
CPU_V7 = "y";
|
||||||
|
ARCH_MULTIPLATFORM = "y";
|
||||||
|
ARCH_MVEBU = "y";
|
||||||
|
ARCH_MULTI_V7= "y";
|
||||||
|
PCI_MVEBU = "y";
|
||||||
|
AHCI_MVEBU = "y";
|
||||||
|
|
||||||
|
RTC_CLASS = "y";
|
||||||
|
RTC_DRV_ARMADA38X = "y"; # this may be useful anyway?
|
||||||
|
|
||||||
|
EXPERT = "y";
|
||||||
|
ALLOW_DEV_COREDUMP = "n";
|
||||||
|
|
||||||
|
|
||||||
|
# dts has a compatible for this but dmesg is not
|
||||||
|
# showing it
|
||||||
|
EEPROM_AT24 = "y"; # atmel,24c64
|
||||||
|
|
||||||
|
I2C = "y";
|
||||||
|
I2C_MUX = "y";
|
||||||
|
I2C_MUX_PCA954x = "y";
|
||||||
|
|
||||||
|
MACH_ARMADA_38X = "y";
|
||||||
|
SMP = "y";
|
||||||
|
# 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";
|
||||||
|
|
||||||
|
# WARNING: unmet direct dependencies detected for ARCH_WANT_LIBATA_LEDS
|
||||||
|
ATA = "y";
|
||||||
|
|
||||||
|
PSTORE = "y";
|
||||||
|
PSTORE_RAM = "y";
|
||||||
|
PSTORE_CONSOLE = "y";
|
||||||
|
# PSTORE_DEFLATE_COMPRESS = "n";
|
||||||
|
|
||||||
|
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_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";
|
||||||
|
|
||||||
|
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";
|
||||||
|
MVNETA = "y";
|
||||||
|
MVNETA_BM = "y";
|
||||||
|
MVNETA_BM_ENABLE = "y";
|
||||||
|
SRAM = "y"; # mmio-sram is "compatible" for bm_bppi reqd by BM
|
||||||
|
PHY_MVEBU_A38X_COMPHY = "y"; # for eth2
|
||||||
|
MARVELL_PHY = "y";
|
||||||
|
|
||||||
|
MVPP2 = "y";
|
||||||
|
MV_XOR = "y";
|
||||||
|
|
||||||
|
# there is NOR flash on this device, which is used for U-Boot
|
||||||
|
# and the rescue system (which we don't interfere with) but
|
||||||
|
# also for the U-Boot environment variables (which we might
|
||||||
|
# need to meddle with)
|
||||||
|
MTD_SPI_NOR = "y";
|
||||||
|
SPI = "y";
|
||||||
|
SPI_MASTER = "y";
|
||||||
|
SPI_ORION = "y";
|
||||||
|
|
||||||
|
NET_DSA = "y";
|
||||||
|
NET_DSA_MV88E6XXX = "y"; # depends on PTP_1588_CLOCK_OPTIONAL
|
||||||
|
};
|
||||||
|
conditionalConfig = {
|
||||||
|
USB = {
|
||||||
|
USB_XHCI_MVEBU = "y";
|
||||||
|
USB_XHCI_HCD = "y";
|
||||||
|
};
|
||||||
|
WLAN = {
|
||||||
|
WLAN_VENDOR_ATH = "y";
|
||||||
|
ATH_COMMON = "m";
|
||||||
|
ATH9K = "m";
|
||||||
|
ATH9K_PCI = "y";
|
||||||
|
ATH10K = "m";
|
||||||
|
ATH10K_PCI = "m";
|
||||||
|
ATH10K_DEBUG = "y";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
boot = {
|
||||||
|
commandLine = [
|
||||||
|
"console=ttyS0,115200"
|
||||||
|
"pcie_aspm=off" # ath9k pci incompatible with PCIe ASPM
|
||||||
|
];
|
||||||
|
};
|
||||||
|
filesystem =
|
||||||
|
let
|
||||||
|
inherit (pkgs.pseudofile) dir symlink;
|
||||||
|
firmware = pkgs.stdenv.mkDerivation {
|
||||||
|
name = "wlan-firmware";
|
||||||
|
phases = ["installPhase"];
|
||||||
|
installPhase = ''
|
||||||
|
mkdir $out
|
||||||
|
cp -r ${pkgs.linux-firmware}/lib/firmware/ath10k/QCA988X $out
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
in dir {
|
||||||
|
lib = dir {
|
||||||
|
firmware = dir {
|
||||||
|
ath10k = symlink firmware;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
boot.tftp = {
|
||||||
|
loadAddress = lim.parseInt "0x1700000";
|
||||||
|
kernelFormat = "zimage";
|
||||||
|
compressRoot = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
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 ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
155
devices/zyxel-nwa50ax/a_image/mt7621_zyxel_nwa-ax-for-ab.dtsi
Normal file
155
devices/zyxel-nwa50ax/a_image/mt7621_zyxel_nwa-ax-for-ab.dtsi
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
#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";
|
||||||
|
};
|
||||||
|
};
|
155
devices/zyxel-nwa50ax/b_image/mt7621_zyxel_nwa-ax-for-ab.dtsi
Normal file
155
devices/zyxel-nwa50ax/b_image/mt7621_zyxel_nwa-ax-for-ab.dtsi
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
#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";
|
||||||
|
};
|
||||||
|
};
|
367
devices/zyxel-nwa50ax/default.nix
Normal file
367
devices/zyxel-nwa50ax/default.nix
Normal file
@ -0,0 +1,367 @@
|
|||||||
|
{
|
||||||
|
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.liminix.networking) interface;
|
||||||
|
inherit (pkgs.liminix.services) oneshot;
|
||||||
|
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;
|
||||||
|
includes = [
|
||||||
|
# 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 = {
|
||||||
|
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 = {
|
||||||
|
|
||||||
|
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
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
56
devices/zyxel-nwa50ax/mt7621_zyxel_nwa50ax.dtsi
Normal file
56
devices/zyxel-nwa50ax/mt7621_zyxel_nwa50ax.dtsi
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
#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>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
ðernet {
|
||||||
|
pinctrl-0 = <&mdio_pins>, <&rgmii1_pins>;
|
||||||
|
};
|
||||||
|
|
||||||
|
&state_default {
|
||||||
|
gpio {
|
||||||
|
groups = "uart3", "rgmii2";
|
||||||
|
function = "gpio";
|
||||||
|
};
|
||||||
|
};
|
@ -12,9 +12,13 @@ BUILDDIR = _build
|
|||||||
help:
|
help:
|
||||||
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||||
|
|
||||||
|
hardware.rst: hardware.nix
|
||||||
|
@rm -f hardware.rst || true
|
||||||
|
@cp $$(nix-build hardware.nix) hardware.rst
|
||||||
|
|
||||||
.PHONY: help Makefile
|
.PHONY: help Makefile
|
||||||
|
|
||||||
# Catch-all target: route all unknown targets to Sphinx using the new
|
# Catch-all target: route all unknown targets to Sphinx using the new
|
||||||
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
|
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
|
||||||
%: Makefile
|
html: Makefile
|
||||||
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||||
|
@ -117,7 +117,7 @@ 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
|
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
|
server to download and flash the image. This is quite
|
||||||
hardware-specific, and sometimes involves soldering: please refer
|
hardware-specific, and sometimes involves soldering: please refer
|
||||||
to the :ref:`development manual <tftp server>`.
|
to :ref:`serial`.
|
||||||
|
|
||||||
|
|
||||||
Flashing from OpenWrt
|
Flashing from OpenWrt
|
||||||
|
@ -27,19 +27,16 @@ To build it,
|
|||||||
|
|
||||||
nix-build -I liminix-config=path/to/your/configuration.nix --arg device "import ./devices/qemu" -A outputs.default
|
nix-build -I liminix-config=path/to/your/configuration.nix --arg device "import ./devices/qemu" -A outputs.default
|
||||||
|
|
||||||
In a ``buildEnv`` nix-shell, you can use the :command:`run-liminix-vm` command
|
This creates a :file:`result/` directory containing a :file:`vmlinux`
|
||||||
to run Qemu with appropriate options. It connects the Liminix
|
and a :file:`rootfs`, and also a shell script :file:`run.sh` which
|
||||||
|
invokes QEMU to run that kernel with that filesystem. It connects the Liminix
|
||||||
serial console and the `QEMU monitor <https://www.qemu.org/docs/master/system/monitor.html>`_ to stdin/stdout. Use ^P (not ^A) to switch to the monitor.
|
serial console and the `QEMU monitor <https://www.qemu.org/docs/master/system/monitor.html>`_ to stdin/stdout. Use ^P (not ^A) to switch to the monitor.
|
||||||
|
|
||||||
.. code-block:: console
|
|
||||||
|
|
||||||
nix-shell --run "run-liminix-vm result/vmlinux result/squashfs"
|
|
||||||
|
|
||||||
If you run with ``--background /path/to/some/directory`` as the first
|
If you run with ``--background /path/to/some/directory`` as the first
|
||||||
parameter, it will fork into the background and open Unix sockets in
|
parameter, it will fork into the background and open Unix sockets in
|
||||||
that directory for console and monitor. Use :command:`connect-vm`
|
that directory for console and monitor. Use :command:`nix-shell --run
|
||||||
(also in the ``buildEnv`` environment) to connect to either of these
|
connect-vm` to connect to either of these sockets, and ^O to
|
||||||
sockets, and ^O to disconnect.
|
disconnect.
|
||||||
|
|
||||||
.. _qemu-networking:
|
.. _qemu-networking:
|
||||||
|
|
||||||
@ -55,9 +52,11 @@ the right way:
|
|||||||
* multicast 230.0.0.1:1235 : lan
|
* multicast 230.0.0.1:1235 : lan
|
||||||
* multicast 230.0.0.1:1236 : world (the internet)
|
* multicast 230.0.0.1:1236 : world (the internet)
|
||||||
|
|
||||||
A VM started with :command:`run-liminix-vm` is connected to "lan" and "access", and
|
Any VM started by a :command:`run.sh` script is connected to "lan" and
|
||||||
the emulated border network gateway (see below) runs PPPoE and is
|
"access", and the emulated border network gateway (see below) runs
|
||||||
connected to "access" and "world".
|
PPPoE and is connected to "access" and "world".
|
||||||
|
|
||||||
|
.. _border-network-gateway:
|
||||||
|
|
||||||
Border Network Gateway
|
Border Network Gateway
|
||||||
----------------------
|
----------------------
|
||||||
@ -89,6 +88,68 @@ time with configurations for RP-PPPoE and/or Accel PPP.`
|
|||||||
Hardware devices
|
Hardware devices
|
||||||
****************
|
****************
|
||||||
|
|
||||||
|
.. _serial:
|
||||||
|
|
||||||
|
U-Boot and serial shenanigans
|
||||||
|
=============================
|
||||||
|
|
||||||
|
Every device that we have so far encountered in Liminix uses `U-Boot,
|
||||||
|
the "Universal Boot Loader" <https://docs.u-boot.org/en/latest/>`_ so
|
||||||
|
it's worth knowing a bit about it. "Universal" is in this context a
|
||||||
|
bit of a misnomer, though: encountering *mainline* U-Boot is very rare
|
||||||
|
and often you'll find it is a fork from some version last updated
|
||||||
|
in 2008. Upgrading U-Boot is more or less complicated depending on the
|
||||||
|
device and is outside scope for Liminix.
|
||||||
|
|
||||||
|
To speak to U-Boot on your device you'll usually need a serial
|
||||||
|
connection to it. This is device-specific. Usually it involves
|
||||||
|
opening the box, locating the serial header pins (TX, RX and GND) and
|
||||||
|
connecting a USB TTL converter to them.
|
||||||
|
|
||||||
|
The Rolls Royce of USB/UART cables is the `FTDI cable
|
||||||
|
<https://cpc.farnell.com/ftdi/ttl-232r-rpi/cable-debug-ttl-232-usb-rpi/dp/SC12825?st=usb%20to%20uart%20cable>`_,
|
||||||
|
but there are cheaper alternatives based on the PL2303 and CP2102 chipsets. Or
|
||||||
|
get creative and use the `UART GPIO pins <https://pinout.xyz/>`_ on a Raspberry Pi. Whatever you do, make sure
|
||||||
|
that the voltages are compatible: if your device is 3.3V (this is
|
||||||
|
typical but not universal), you don't want to be sending it 5v or
|
||||||
|
(even worse) 12v.
|
||||||
|
|
||||||
|
Run a terminal emulator such as Minicom on the computer at other end
|
||||||
|
of the link. 115200 8N1 is the typical speed.
|
||||||
|
|
||||||
|
.. NOTE::
|
||||||
|
|
||||||
|
TTL serial connections typically have no form of flow control and
|
||||||
|
so don't always like having massive chunks of text pasted into
|
||||||
|
them - and U-Boot may drop characters while it's busy. So don't
|
||||||
|
necessarily expect to copy-paste large chunks of text into the
|
||||||
|
terminal emulator and have it work just like that.
|
||||||
|
|
||||||
|
If using Minicom, you may find it helps to bring up the "Termimal
|
||||||
|
settings" dialog (C^A T), then configure "Newline tx delay" to
|
||||||
|
some small but non-zero value.
|
||||||
|
|
||||||
|
When you turn the router on you should be greeted with some messages
|
||||||
|
from U-Boot, followed by the instruction to hit some key to stop
|
||||||
|
autoboot. Do this and you will get to the prompt. If you didn't see
|
||||||
|
anything, the strong likelihood is that TX and RX are the wrong way
|
||||||
|
around. If you see garbage, try a different speed.
|
||||||
|
|
||||||
|
Interesting commands to try first in U-Boot are :command:`help` and
|
||||||
|
:command:`printenv`.
|
||||||
|
|
||||||
|
To do anything useful with U-Boot you will probably need a way to get
|
||||||
|
large binary files onto the device, and the usual way to do this is by
|
||||||
|
adding a network connection and using TFTP to download them. It's
|
||||||
|
quite common that the device's U-Boot doesn't speak DHCP so it will
|
||||||
|
need a static LAN address. You might also want to keep it away from
|
||||||
|
your "real" LAN: see :ref:`bng` for some potentially useful tooling
|
||||||
|
to use it on an isolated network.
|
||||||
|
|
||||||
|
|
||||||
|
TFTP
|
||||||
|
====
|
||||||
|
|
||||||
.. _tftp server:
|
.. _tftp server:
|
||||||
|
|
||||||
How you get your image onto hardware will vary according to the
|
How you get your image onto hardware will vary according to the
|
||||||
@ -119,7 +180,7 @@ Now add the device and server IP addresses to your configuration:
|
|||||||
};
|
};
|
||||||
|
|
||||||
and then build the derivation for ``outputs.default`` or
|
and then build the derivation for ``outputs.default`` or
|
||||||
``outputs.flashimage`` (for which it will be an alias on any device
|
``outputs.mtdimage`` (for which it will be an alias on any device
|
||||||
where this is applicable). You should find it has created
|
where this is applicable). You should find it has created
|
||||||
|
|
||||||
* :file:`result/firmware.bin` which is the file you are going to flash
|
* :file:`result/firmware.bin` which is the file you are going to flash
|
||||||
@ -152,6 +213,8 @@ U-Boot to transfer the kernel and filesystem over TFTP and boot the
|
|||||||
kernel from RAM.
|
kernel from RAM.
|
||||||
|
|
||||||
|
|
||||||
|
.. _bng:
|
||||||
|
|
||||||
Networking
|
Networking
|
||||||
==========
|
==========
|
||||||
|
|
||||||
|
@ -1,31 +1,10 @@
|
|||||||
|
{ eval, lib, pkgs }:
|
||||||
let
|
let
|
||||||
overlay = import ../overlay.nix;
|
|
||||||
pkgs = import <nixpkgs> ( {
|
|
||||||
overlays = [overlay];
|
|
||||||
config = {
|
|
||||||
allowUnsupportedSystem = true; # mipsel
|
|
||||||
permittedInsecurePackages = [
|
|
||||||
"python-2.7.18.6" # kernel backports needs python <3
|
|
||||||
];
|
|
||||||
};
|
|
||||||
});
|
|
||||||
inherit (pkgs) lib;
|
|
||||||
inherit (lib) types;
|
inherit (lib) types;
|
||||||
modulenames =
|
|
||||||
builtins.attrNames
|
|
||||||
(lib.filterAttrsRecursive
|
|
||||||
(n: t:
|
|
||||||
(n != "arch") &&
|
|
||||||
((t=="directory") ||
|
|
||||||
((t=="regular") && ((builtins.match ".*\\.nix$" n) != null))))
|
|
||||||
(builtins.readDir ../modules));
|
|
||||||
modulefiles = builtins.map (n: builtins.toPath "${../modules}/${n}") modulenames;
|
|
||||||
eval = (lib.evalModules {
|
|
||||||
modules = [
|
|
||||||
{ _module.args = { inherit pkgs; lib = pkgs.lib; }; }
|
|
||||||
] ++ modulefiles;
|
|
||||||
});
|
|
||||||
conf = eval.config;
|
conf = eval.config;
|
||||||
|
rootDir = builtins.toPath ./..;
|
||||||
|
stripAnyPrefixes = lib.flip (lib.fold lib.removePrefix)
|
||||||
|
["${rootDir}/"];
|
||||||
optToDoc = name: opt : {
|
optToDoc = name: opt : {
|
||||||
inherit name;
|
inherit name;
|
||||||
description = opt.description or null;
|
description = opt.description or null;
|
||||||
@ -42,16 +21,12 @@ let
|
|||||||
then
|
then
|
||||||
let sd = lib.attrByPath item.loc ["not found"] conf;
|
let sd = lib.attrByPath item.loc ["not found"] conf;
|
||||||
in item // {
|
in item // {
|
||||||
|
declarations = map stripAnyPrefixes item.declarations;
|
||||||
parameters =
|
parameters =
|
||||||
let x = lib.mapAttrsToList optToDoc sd.parameters; in x;
|
let x = lib.mapAttrsToList optToDoc sd.parameters; in x;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
item;
|
item // { declarations = map stripAnyPrefixes item.declarations; };
|
||||||
o = builtins.map spliceServiceDefn
|
in
|
||||||
(pkgs.lib.optionAttrSetToDocList eval.options);
|
builtins.map spliceServiceDefn
|
||||||
in {
|
(pkgs.lib.optionAttrSetToDocList eval.options)
|
||||||
doc = pkgs.writeText "options.yaml" ''
|
|
||||||
# ${./..}
|
|
||||||
${builtins.toJSON o}
|
|
||||||
'';
|
|
||||||
}
|
|
||||||
|
@ -1,18 +1,38 @@
|
|||||||
with import <nixpkgs> {} ;
|
with import <nixpkgs> {} ;
|
||||||
|
|
||||||
let
|
let
|
||||||
devices =
|
inherit (builtins) stringLength readDir filter;
|
||||||
builtins.readDir ../devices;
|
devices = filter (n: n != "families")
|
||||||
texts = lib.mapAttrsToList (n: t:
|
(lib.mapAttrsToList (n: t: n) (readDir ../devices));
|
||||||
|
texts = map (n:
|
||||||
let d = import ../devices/${n}/default.nix;
|
let d = import ../devices/${n}/default.nix;
|
||||||
d' = { description = "no description for ${n}"; } // d;
|
d' = {
|
||||||
in d'.description )
|
description = "${n}\n${substring 0 (stringLength n) "********************************"}\n";
|
||||||
|
} // d;
|
||||||
|
installer =
|
||||||
|
if d ? description && d ? installer
|
||||||
|
then ''
|
||||||
|
|
||||||
|
The default installation route for this device is
|
||||||
|
:ref:`system-outputs-${d.installer}`
|
||||||
|
''
|
||||||
|
else "";
|
||||||
|
in d'.description)
|
||||||
devices;
|
devices;
|
||||||
in
|
in
|
||||||
writeText "hwdoc" ''
|
writeText "hwdoc" ''
|
||||||
Supported hardware
|
Supported hardware
|
||||||
##################
|
##################
|
||||||
|
|
||||||
|
For development, the `GL.iNet GL-MT300A <https://www.gl-inet.com/products/gl-mt300a/>`_
|
||||||
|
is an attractive choice as it has a builtin "debrick" procedure in the
|
||||||
|
boot monitor and is also comparatively simple to
|
||||||
|
attach serial cables to (soldering not required), so it
|
||||||
|
is lower-risk than some devices.
|
||||||
|
|
||||||
|
For a more powerful device, something with an ath10k would be the safe bet,
|
||||||
|
or the Linksys E8450 which seems popular in the openwrt community.
|
||||||
|
|
||||||
${lib.concatStringsSep "\n\n" texts}
|
${lib.concatStringsSep "\n\n" texts}
|
||||||
|
|
||||||
''
|
''
|
||||||
|
@ -12,6 +12,7 @@ Liminix
|
|||||||
development
|
development
|
||||||
modules
|
modules
|
||||||
hardware
|
hardware
|
||||||
|
outputs
|
||||||
|
|
||||||
|
|
||||||
Indices and tables
|
Indices and tables
|
||||||
|
13
doc/outputs.rst
Normal file
13
doc/outputs.rst
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
Outputs
|
||||||
|
#######
|
||||||
|
|
||||||
|
Liminix *outputs* are artefacts that can be installed somehow on a
|
||||||
|
target device, or "installers" which run on the target device to
|
||||||
|
perform the installation.
|
||||||
|
|
||||||
|
There are different outputs because different target devices need
|
||||||
|
different artefacts, or have different ways to get that artefact
|
||||||
|
installed. The options available for a particular device are described in
|
||||||
|
the section for that device.
|
||||||
|
|
||||||
|
.. include:: outputs-generated.rst
|
19
doc/parse-options-outputs.fnl
Normal file
19
doc/parse-options-outputs.fnl
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
(local yaml (require :lyaml))
|
||||||
|
|
||||||
|
;; (local { : view } (require :fennel))
|
||||||
|
|
||||||
|
(fn output? [option]
|
||||||
|
(match option.loc
|
||||||
|
["system" "outputs" & _] true
|
||||||
|
_ false))
|
||||||
|
|
||||||
|
(fn sorted-options [options]
|
||||||
|
(table.sort
|
||||||
|
options
|
||||||
|
(fn [a b] (< a.name b.name)))
|
||||||
|
options)
|
||||||
|
|
||||||
|
(each [_ option (ipairs (sorted-options (yaml.load (io.read "*a"))))]
|
||||||
|
(when (and (output? option) (not option.internal))
|
||||||
|
(print (.. ".. _" (string.gsub option.name "%." "-") ":") "\n")
|
||||||
|
(print option.description)))
|
@ -2,21 +2,25 @@
|
|||||||
|
|
||||||
(local { : view } (require :fennel))
|
(local { : view } (require :fennel))
|
||||||
|
|
||||||
|
(fn basename [str ext]
|
||||||
|
(-> str
|
||||||
|
(string.gsub "(.*/)(.*)" "%2")
|
||||||
|
(string.gsub (.. ext "$") "")))
|
||||||
|
|
||||||
(fn headline [name]
|
(fn headline [name]
|
||||||
(let [(_ _ basename) (string.find name ".*/([^/].*).nix")
|
(let [title (assert (basename name ".nix"))
|
||||||
len (basename:len)]
|
len (title:len)]
|
||||||
(.. basename "\n" (string.rep "=" len))))
|
(.. title "\n" (string.rep "=" len))))
|
||||||
|
|
||||||
(fn read-preamble [pathname]
|
(fn read-preamble [pathname]
|
||||||
(if (= (pathname:sub 1 1) "/")
|
(let [pathname (if (string.match pathname ".nix$")
|
||||||
(let [pathname (if (string.match pathname ".nix$")
|
pathname
|
||||||
pathname
|
(.. pathname "/default.nix"))]
|
||||||
(.. pathname "/default.nix"))]
|
(with-open [f (assert (io.open pathname :r))]
|
||||||
(with-open [f (assert (io.open pathname :r))]
|
(accumulate [lines nil
|
||||||
(accumulate [lines nil
|
l (f:lines)
|
||||||
l (f:lines)
|
:until (not (= (string.sub l 1 2) "##"))]
|
||||||
:until (not (= (string.sub l 1 2) "##"))]
|
(.. (or lines "") (string.gsub l "^## *" "") "\n")))))
|
||||||
(.. (or lines "") (string.gsub l "^## *" "") "\n"))))))
|
|
||||||
|
|
||||||
(fn relative-pathname [pathname]
|
(fn relative-pathname [pathname]
|
||||||
(let [pathname
|
(let [pathname
|
||||||
|
@ -69,10 +69,11 @@ device's serial console and the `QEMU monitor
|
|||||||
stdin/stdout.
|
stdin/stdout.
|
||||||
|
|
||||||
You should now see Linux boot messages and after a few seconds be
|
You should now see Linux boot messages and after a few seconds be
|
||||||
presented with a login prompt. You can login on the console as
|
presented with a root shell prompt. You can run commands to look at
|
||||||
``root`` (password is "secret") and poke around to see what processes are
|
the filesystem, see what processes are running, view log messages (in
|
||||||
running. To kill the emulator, press ^P (Control P) then c to enter the
|
:file:/run/uncaught-logs.current), etc. To kill the emulator, press ^P
|
||||||
"QEMU Monitor", then type ``quit`` at the ``(qemu)`` prompt.
|
(Control P) then c to enter the "QEMU Monitor", then type ``quit`` at
|
||||||
|
the ``(qemu)`` prompt.
|
||||||
|
|
||||||
To see that it's running network services we need to connect to its
|
To see that it's running network services we need to connect to its
|
||||||
emulated network. Start the machine again, if you had stopped it, and
|
emulated network. Start the machine again, if you had stopped it, and
|
||||||
@ -137,20 +138,14 @@ unbrick if necessary.
|
|||||||
work here, but you accept the slightly greater bricking
|
work here, but you accept the slightly greater bricking
|
||||||
risk if it doesn't.
|
risk if it doesn't.
|
||||||
|
|
||||||
You may want to acquire a `USB TTL serial cable
|
See :doc:`hardware` for device support status.
|
||||||
<https://cpc.farnell.com/ftdi/ttl-232r-rpi/cable-debug-ttl-232-usb-rpi/dp/SC12825?st=usb%20to%20uart%20cable>`_
|
|
||||||
when you start working with Liminix on real hardware. You
|
You may want to read and inwardly digest the Develoment Manual section
|
||||||
won't *need* it for this example, assuming it works, but it
|
:ref:`serial` when you start working with Liminix on real hardware. You
|
||||||
|
won't *need* serial access for this example, assuming it works, but it
|
||||||
allows you
|
allows you
|
||||||
to see the boot monitor and kernel messages, and to login directly to
|
to see the boot monitor and kernel messages, and to login directly to
|
||||||
the device if for some reason it doesn't bring its network up. You have options
|
the device if for some reason it doesn't bring its network up.
|
||||||
here: the FTDI-based cables are the Rolls Royce of serial cables,
|
|
||||||
whereas the ones based on PL2303 and CP2102 chipsets are cheaper but
|
|
||||||
also fussier - or you could even get creative and use e.g. a
|
|
||||||
`Raspberry Pi <https://pinout.xyz/#>`_ or other SBC with a UART and
|
|
||||||
TX/RX/GND header pins. Make sure that the voltages are compatible:
|
|
||||||
this is a 3.3v device and you don't want to be sending it 5v or (even
|
|
||||||
worse) 12v.
|
|
||||||
|
|
||||||
Now we can build Liminix. Although we could use the same example
|
Now we can build Liminix. Although we could use the same example
|
||||||
configuration as we did for Qemu, you might not want to plug a DHCP
|
configuration as we did for Qemu, you might not want to plug a DHCP
|
||||||
|
@ -24,7 +24,6 @@ in rec {
|
|||||||
};
|
};
|
||||||
|
|
||||||
imports = [
|
imports = [
|
||||||
../modules/standard.nix
|
|
||||||
../modules/wlan.nix
|
../modules/wlan.nix
|
||||||
../modules/network
|
../modules/network
|
||||||
../modules/vlan
|
../modules/vlan
|
||||||
@ -32,7 +31,6 @@ in rec {
|
|||||||
../modules/watchdog
|
../modules/watchdog
|
||||||
../modules/mount
|
../modules/mount
|
||||||
];
|
];
|
||||||
|
|
||||||
hostname = "arhcive";
|
hostname = "arhcive";
|
||||||
|
|
||||||
kernel = {
|
kernel = {
|
||||||
@ -147,7 +145,7 @@ in rec {
|
|||||||
};
|
};
|
||||||
|
|
||||||
users.root = {
|
users.root = {
|
||||||
passwd = lib.mkForce secrets.root_password;
|
passwd = lib.mkForce secrets.root.passwd;
|
||||||
# openssh.authorizedKeys.keys = [
|
# openssh.authorizedKeys.keys = [
|
||||||
# (builtins.readFile "/home/dan/.ssh/id_rsa.pub")
|
# (builtins.readFile "/home/dan/.ssh/id_rsa.pub")
|
||||||
# ];
|
# ];
|
||||||
|
@ -35,6 +35,7 @@ in {
|
|||||||
(drop "icmpv6 type destination-unreachable ct state invalid,untracked")
|
(drop "icmpv6 type destination-unreachable ct state invalid,untracked")
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
forward-ip6 = {
|
forward-ip6 = {
|
||||||
type = "filter";
|
type = "filter";
|
||||||
family = "ip6";
|
family = "ip6";
|
||||||
@ -95,19 +96,23 @@ in {
|
|||||||
# recognised (outbound-initiated) flow
|
# recognised (outbound-initiated) flow
|
||||||
(accept "oifname \"int\" iifname \"ppp0\" ct state established,related")
|
(accept "oifname \"int\" iifname \"ppp0\" ct state established,related")
|
||||||
(accept "iifname \"int\" oifname \"ppp0\" ")
|
(accept "iifname \"int\" oifname \"ppp0\" ")
|
||||||
|
|
||||||
|
"log prefix \"DENIED CHAIN=forward-ip6 \""
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
input-lan = {
|
|
||||||
|
input-ip6-lan = {
|
||||||
type = "filter";
|
type = "filter";
|
||||||
family = "ip6";
|
family = "ip6";
|
||||||
|
|
||||||
rules = [
|
rules = [
|
||||||
(accept "udp dport 547") # dhcp, could restrict to daddr ff02::1:2
|
(accept "udp dport 547") # dhcp, could restrict to daddr ff02::1:2
|
||||||
|
(accept "udp dport 53") # dns
|
||||||
(accept "tcp dport 22")
|
(accept "tcp dport 22")
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
input-wan = {
|
input-ip6-wan = {
|
||||||
type = "filter";
|
type = "filter";
|
||||||
family = "ip6";
|
family = "ip6";
|
||||||
|
|
||||||
@ -123,8 +128,8 @@ in {
|
|||||||
hook = "input";
|
hook = "input";
|
||||||
rules = [
|
rules = [
|
||||||
(accept "meta l4proto icmpv6")
|
(accept "meta l4proto icmpv6")
|
||||||
"iifname int jump input-lan"
|
"iifname int jump input-ip6-lan"
|
||||||
"iifname ppp0 jump input-wan"
|
"iifname ppp0 jump input-ip6-wan"
|
||||||
(if allow-incoming
|
(if allow-incoming
|
||||||
then accept "oifname \"int\" iifname \"ppp0\""
|
then accept "oifname \"int\" iifname \"ppp0\""
|
||||||
else "oifname \"int\" iifname \"ppp0\" jump incoming-allowed-ip6"
|
else "oifname \"int\" iifname \"ppp0\" jump incoming-allowed-ip6"
|
||||||
@ -132,6 +137,7 @@ in {
|
|||||||
# how does this even make sense in an input chain?
|
# how does this even make sense in an input chain?
|
||||||
(accept "oifname \"int\" iifname \"ppp0\" ct state established,related")
|
(accept "oifname \"int\" iifname \"ppp0\" ct state established,related")
|
||||||
(accept "iifname \"int\" oifname \"ppp0\" ")
|
(accept "iifname \"int\" oifname \"ppp0\" ")
|
||||||
|
"log prefix \"DENIED CHAIN=input-ip6 \""
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -154,6 +160,7 @@ in {
|
|||||||
"oifname \"ppp0\" masquerade"
|
"oifname \"ppp0\" masquerade"
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
nat-rx = {
|
nat-rx = {
|
||||||
type = "nat";
|
type = "nat";
|
||||||
hook = "prerouting";
|
hook = "prerouting";
|
||||||
@ -167,4 +174,71 @@ in {
|
|||||||
# packet replies. "
|
# packet replies. "
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# these chains are for rules that have to be present for things to
|
||||||
|
# basically work at all: for example, the router won't issue DHCP
|
||||||
|
# unless it's allowed to receive DHCP requests. For "site policy"
|
||||||
|
# rules you may prefer to use incoming-allowed-ip[46] instead
|
||||||
|
|
||||||
|
input-ip4-lan = {
|
||||||
|
type = "filter";
|
||||||
|
family = "ip";
|
||||||
|
|
||||||
|
rules = [
|
||||||
|
(accept "udp dport 67") # dhcp
|
||||||
|
(accept "udp dport 53") # dns
|
||||||
|
(accept "tcp dport 22") # ssh
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
input-ip4-wan = {
|
||||||
|
type = "filter";
|
||||||
|
family = "ip";
|
||||||
|
|
||||||
|
rules = [
|
||||||
|
(accept "udp sport 53")
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
input-ip4 = {
|
||||||
|
type = "filter";
|
||||||
|
family = "ip";
|
||||||
|
policy = "drop";
|
||||||
|
hook = "input";
|
||||||
|
rules = [
|
||||||
|
"iifname lo accept"
|
||||||
|
"icmp type { echo-request, echo-reply } accept"
|
||||||
|
"iifname int jump input-ip4-lan"
|
||||||
|
"iifname ppp0 jump input-ip4-wan"
|
||||||
|
"oifname \"int\" iifname \"ppp0\" jump incoming-allowed-ip4"
|
||||||
|
"ct state established,related accept"
|
||||||
|
"log prefix \"DENIED CHAIN=input-ip4 \""
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
forward-ip4 = {
|
||||||
|
type = "filter";
|
||||||
|
family = "ip";
|
||||||
|
policy = "drop";
|
||||||
|
hook = "forward";
|
||||||
|
rules = [
|
||||||
|
"iifname \"int\" accept"
|
||||||
|
"ct state established,related accept"
|
||||||
|
"oifname \"int\" iifname \"ppp0\" jump incoming-allowed-ip4"
|
||||||
|
"log prefix \"DENIED CHAIN=forward-ip4 \""
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
incoming-allowed-ip4 = {
|
||||||
|
type = "filter";
|
||||||
|
family = "ip";
|
||||||
|
rules = [
|
||||||
|
# This is where you put permitted incoming connections. If
|
||||||
|
# you're using NAT and want to forward a port from outside to
|
||||||
|
# devices on the LAN, then you need a DNAT rule in nat-rx chain
|
||||||
|
# *and* to accept the packet in this chain (specifying the
|
||||||
|
# internal (RFC1918) address).
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,6 @@ in rec {
|
|||||||
../modules/ntp
|
../modules/ntp
|
||||||
../modules/ppp
|
../modules/ppp
|
||||||
../modules/ssh
|
../modules/ssh
|
||||||
../modules/standard.nix
|
|
||||||
../modules/vlan
|
../modules/vlan
|
||||||
../modules/wlan.nix
|
../modules/wlan.nix
|
||||||
];
|
];
|
||||||
|
@ -11,10 +11,6 @@
|
|||||||
...
|
...
|
||||||
}: let
|
}: let
|
||||||
secrets = import ./extneder-secrets.nix;
|
secrets = import ./extneder-secrets.nix;
|
||||||
inherit (pkgs.liminix.services) oneshot longrun bundle target;
|
|
||||||
inherit (pkgs.pseudofile) dir symlink;
|
|
||||||
inherit (pkgs) dropbear ifwait serviceFns;
|
|
||||||
svc = config.system.service;
|
|
||||||
in rec {
|
in rec {
|
||||||
boot = {
|
boot = {
|
||||||
tftp = {
|
tftp = {
|
||||||
@ -24,13 +20,8 @@ in rec {
|
|||||||
};
|
};
|
||||||
|
|
||||||
imports = [
|
imports = [
|
||||||
../modules/wlan.nix
|
../modules/profiles/wap.nix
|
||||||
../modules/vlan
|
../modules/vlan
|
||||||
../modules/network
|
|
||||||
../modules/hostapd
|
|
||||||
../modules/bridge
|
|
||||||
../modules/ssh
|
|
||||||
../modules/standard.nix
|
|
||||||
];
|
];
|
||||||
|
|
||||||
hostname = "extneder";
|
hostname = "extneder";
|
||||||
@ -70,68 +61,24 @@ in rec {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
services.hostap = svc.hostapd.build {
|
profile.wap = {
|
||||||
interface = config.hardware.networkInterfaces.wlan;
|
interfaces = with config.hardware.networkInterfaces; [
|
||||||
params = {
|
|
||||||
country_code = "GB";
|
|
||||||
hw_mode = "g";
|
|
||||||
wmm_enabled = 1;
|
|
||||||
ieee80211n = 1;
|
|
||||||
inherit (secrets) ssid channel wpa_passphrase;
|
|
||||||
auth_algs = 1; # 1=wpa2, 2=wep, 3=both
|
|
||||||
wpa = 2; # 1=wpa, 2=wpa2, 3=both
|
|
||||||
wpa_key_mgmt = "WPA-PSK";
|
|
||||||
wpa_pairwise = "TKIP CCMP"; # auth for wpa (may not need this?)
|
|
||||||
rsn_pairwise = "CCMP"; # auth for wpa2
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
services.int = svc.bridge.primary.build {
|
|
||||||
ifname = "int";
|
|
||||||
};
|
|
||||||
|
|
||||||
services.dhcpc = svc.network.dhcp.client.build {
|
|
||||||
interface = services.int;
|
|
||||||
dependencies = [ config.services.hostname ];
|
|
||||||
};
|
|
||||||
|
|
||||||
services.bridge = svc.bridge.members.build {
|
|
||||||
primary = services.int;
|
|
||||||
members = with config.hardware.networkInterfaces; [
|
|
||||||
lan
|
lan
|
||||||
wlan
|
wlan
|
||||||
];
|
];
|
||||||
};
|
|
||||||
|
|
||||||
services.sshd = svc.ssh.build {};
|
wireless = {
|
||||||
|
networks.${secrets.ssid} = {
|
||||||
services.resolvconf = oneshot rec {
|
interface = config.hardware.networkInterfaces.wlan;
|
||||||
dependencies = [ services.dhcpc ];
|
inherit (secrets) channel wpa_passphrase;
|
||||||
name = "resolvconf";
|
country_code = "GB";
|
||||||
# CHECK: https://udhcp.busybox.net/README.udhcpc says
|
hw_mode = "g";
|
||||||
# 'A list of DNS server' but doesn't say what separates the
|
wmm_enabled = 1;
|
||||||
# list members. Assuming it's a space or other IFS character
|
ieee80211n = 1;
|
||||||
up = ''
|
};
|
||||||
. ${serviceFns}
|
|
||||||
( in_outputs ${name}
|
|
||||||
for i in $(output ${services.dhcpc} dns); do
|
|
||||||
echo "nameserver $i" > resolv.conf
|
|
||||||
done
|
|
||||||
)
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
filesystem = dir {
|
|
||||||
etc = dir {
|
|
||||||
"resolv.conf" = symlink "${services.resolvconf}/.outputs/resolv.conf";
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
services.defaultroute4 = svc.network.route.build {
|
users.root.passwd = lib.mkForce secrets.root.passwd;
|
||||||
via = "$(output ${services.dhcpc} router)";
|
|
||||||
target = "default";
|
|
||||||
dependencies = [services.dhcpc];
|
|
||||||
};
|
|
||||||
|
|
||||||
users.root.passwd = lib.mkForce secrets.root_password;
|
|
||||||
defaultProfile.packages = with pkgs; [nftables strace tcpdump swconfig];
|
defaultProfile.packages = with pkgs; [nftables strace tcpdump swconfig];
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,6 @@ in rec {
|
|||||||
../modules/network
|
../modules/network
|
||||||
../modules/ssh
|
../modules/ssh
|
||||||
../modules/vlan
|
../modules/vlan
|
||||||
../modules/flashimage.nix
|
|
||||||
];
|
];
|
||||||
|
|
||||||
boot.tftp = {
|
boot.tftp = {
|
||||||
|
120
examples/nwa50ax-ap.nix
Normal file
120
examples/nwa50ax-ap.nix
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
{ config, pkgs, ... } :
|
||||||
|
let
|
||||||
|
inherit (pkgs.liminix.services) oneshot longrun bundle target;
|
||||||
|
inherit (pkgs) writeText;
|
||||||
|
svc = config.system.service;
|
||||||
|
secrets-1 = {
|
||||||
|
ssid = "Zyxel 2G (N)";
|
||||||
|
wpa_passphrase = "diamond dogs";
|
||||||
|
};
|
||||||
|
secrets-2 = {
|
||||||
|
ssid = "Zyxel 5G (AX)";
|
||||||
|
wpa_passphrase = "diamond dogs";
|
||||||
|
};
|
||||||
|
baseParams = {
|
||||||
|
country_code = "FR";
|
||||||
|
hw_mode = "g";
|
||||||
|
channel = 6;
|
||||||
|
wmm_enabled = 1;
|
||||||
|
ieee80211n = 1;
|
||||||
|
ht_capab = "[LDPC][GF][HT40-][HT40+][SHORT-GI-40][MAX-AMSDU-7935][TX-STBC]";
|
||||||
|
auth_algs = 1;
|
||||||
|
wpa = 2;
|
||||||
|
wpa_key_mgmt = "WPA-PSK";
|
||||||
|
wpa_pairwise = "TKIP CCMP";
|
||||||
|
rsn_pairwise = "CCMP";
|
||||||
|
};
|
||||||
|
|
||||||
|
modernParams = {
|
||||||
|
hw_mode = "a";
|
||||||
|
he_su_beamformer = 1;
|
||||||
|
he_su_beamformee = 1;
|
||||||
|
he_mu_beamformer = 1;
|
||||||
|
preamble = 1;
|
||||||
|
# Allow radar detection.
|
||||||
|
ieee80211d = 1;
|
||||||
|
ieee80211h = 1;
|
||||||
|
ieee80211ac = 1;
|
||||||
|
ieee80211ax = 1;
|
||||||
|
vht_capab = "[MAX-MPDU-7991][SU-BEAMFORMEE][SU-BEAMFORMER][RXLDPC][SHORT-GI-80][MAX-A-MPDU-LEN-EXP3][RX-ANTENNA-PATTERN][TX-ANTENNA-PATTERN][TX-STBC-2BY1][RX-STBC-1][MU-BEAMFORMER]";
|
||||||
|
vht_oper_chwidth = 1;
|
||||||
|
he_oper_chwidth = 1;
|
||||||
|
channel = 36;
|
||||||
|
vht_oper_centr_freq_seg0_idx = 42;
|
||||||
|
he_oper_centr_freq_seg0_idx = 42;
|
||||||
|
require_vht = 1;
|
||||||
|
};
|
||||||
|
mkWifiSta = params: interface: secrets: svc.hostapd.build {
|
||||||
|
inherit interface;
|
||||||
|
params = params // {
|
||||||
|
inherit (secrets) ssid wpa_passphrase;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
in rec {
|
||||||
|
imports = [
|
||||||
|
../modules/wlan.nix
|
||||||
|
../modules/network
|
||||||
|
../modules/hostapd
|
||||||
|
../modules/ssh
|
||||||
|
../modules/ntp
|
||||||
|
../modules/vlan
|
||||||
|
../modules/bridge
|
||||||
|
];
|
||||||
|
|
||||||
|
hostname = "zyxel";
|
||||||
|
|
||||||
|
users.root = {
|
||||||
|
# EDIT: choose a root password and then use
|
||||||
|
# "mkpasswd -m sha512crypt" to determine the hash.
|
||||||
|
# It should start wirh $6$.
|
||||||
|
passwd = "$y$j9T$f8GhLiqYmr3lc58eKhgyD0$z7P/7S9u.kq/cANZExxhS98bze/6i7aBxU6tbl7RMi.";
|
||||||
|
openssh.authorizedKeys.keys = [
|
||||||
|
# EDIT: you can add your ssh pubkey here
|
||||||
|
# "ssh-rsa AAAAB3NzaC1....H6hKd user@example.com";
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
services.int = svc.bridge.primary.build {
|
||||||
|
ifname = "int";
|
||||||
|
};
|
||||||
|
|
||||||
|
services.bridge = svc.bridge.members.build {
|
||||||
|
primary = services.int;
|
||||||
|
members = with config.hardware.networkInterfaces; [
|
||||||
|
lan
|
||||||
|
wlan0
|
||||||
|
wlan1
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
services.dhcpv4 =
|
||||||
|
let iface = services.int;
|
||||||
|
in svc.network.dhcp.client.build { interface = iface; };
|
||||||
|
|
||||||
|
services.defaultroute4 = svc.network.route.build {
|
||||||
|
via = "$(output ${services.dhcpv4} address)";
|
||||||
|
target = "default";
|
||||||
|
dependencies = [ services.dhcpv4 ];
|
||||||
|
};
|
||||||
|
|
||||||
|
services.packet_forwarding = svc.network.forward.build { };
|
||||||
|
services.sshd = svc.ssh.build {
|
||||||
|
allowRoot = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
services.ntp = config.system.service.ntp.build {
|
||||||
|
pools = { "pool.ntp.org" = ["iburst"] ; };
|
||||||
|
};
|
||||||
|
|
||||||
|
boot.tftp = {
|
||||||
|
serverip = "192.0.2.10";
|
||||||
|
ipaddr = "192.0.2.12";
|
||||||
|
};
|
||||||
|
|
||||||
|
# wlan0 is the 2.4GHz interface.
|
||||||
|
services.hostap-1 = mkWifiSta baseParams config.hardware.networkInterfaces.wlan0 secrets-1;
|
||||||
|
# wlan1 is the 5GHz interface, e.g. AX capable.
|
||||||
|
services.hostap-2 = mkWifiSta (baseParams // modernParams) config.hardware.networkInterfaces.wlan1 secrets-2;
|
||||||
|
|
||||||
|
defaultProfile.packages = with pkgs; [ zyxel-bootconfig iw min-collect-garbage mtdutils ];
|
||||||
|
}
|
116
examples/recovery.nix
Normal file
116
examples/recovery.nix
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
{ config, pkgs, lib, ... } :
|
||||||
|
let
|
||||||
|
inherit (pkgs) serviceFns;
|
||||||
|
svc = config.system.service;
|
||||||
|
inherit (pkgs.pseudofile) dir symlink;
|
||||||
|
inherit (pkgs.liminix.services) oneshot longrun bundle target;
|
||||||
|
some-util-linux = pkgs.runCommand "some-util-linux" {} ''
|
||||||
|
mkdir -p $out/bin
|
||||||
|
cd ${pkgs.util-linux-small}/bin
|
||||||
|
cp fdisk sfdisk mkswap $out/bin
|
||||||
|
'';
|
||||||
|
in rec {
|
||||||
|
imports = [
|
||||||
|
../modules/network
|
||||||
|
../modules/ssh
|
||||||
|
../modules/usb.nix
|
||||||
|
../modules/schnapps
|
||||||
|
../modules/outputs/mtdimage.nix
|
||||||
|
../modules/outputs/mbrimage.nix
|
||||||
|
../modules/outputs/tftpboot.nix
|
||||||
|
../modules/outputs/ubifs.nix
|
||||||
|
../modules/outputs/ubimage.nix
|
||||||
|
../modules/outputs/jffs2.nix
|
||||||
|
../modules/outputs/ext4fs.nix
|
||||||
|
../modules/outputs/extlinux.nix
|
||||||
|
];
|
||||||
|
|
||||||
|
kernel.config = {
|
||||||
|
BTRFS_FS = "y";
|
||||||
|
};
|
||||||
|
|
||||||
|
boot.tftp = {
|
||||||
|
ipaddr = "10.0.0.8"; # my address
|
||||||
|
serverip = "10.0.0.1"; # build machine or other tftp server
|
||||||
|
freeSpaceBytes = 1024 * 1024 * 4;
|
||||||
|
};
|
||||||
|
boot.loader.extlinux.enable = true;
|
||||||
|
|
||||||
|
hostname = "liminix-recovery";
|
||||||
|
|
||||||
|
services.dhcpc = svc.network.dhcp.client.build {
|
||||||
|
interface = config.hardware.networkInterfaces.lan2;
|
||||||
|
|
||||||
|
# don't start DHCP until the hostname is configured,
|
||||||
|
# so it can identify itself to the DHCP server
|
||||||
|
dependencies = [ config.services.hostname ];
|
||||||
|
};
|
||||||
|
|
||||||
|
services.sshd = svc.ssh.build {
|
||||||
|
dependencies = [ config.services.growfs ];
|
||||||
|
};
|
||||||
|
|
||||||
|
services.defaultroute4 = svc.network.route.build {
|
||||||
|
via = "$(output ${services.dhcpc} router)";
|
||||||
|
target = "default";
|
||||||
|
dependencies = [services.dhcpc];
|
||||||
|
};
|
||||||
|
|
||||||
|
services.resolvconf = oneshot rec {
|
||||||
|
dependencies = [ services.dhcpc ];
|
||||||
|
name = "resolvconf";
|
||||||
|
up = ''
|
||||||
|
. ${serviceFns}
|
||||||
|
( in_outputs ${name}
|
||||||
|
for i in $(output ${services.dhcpc} dns); do
|
||||||
|
echo "nameserver $i" > resolv.conf
|
||||||
|
done
|
||||||
|
)
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
services.growfs = let name = "growfs"; in oneshot {
|
||||||
|
inherit name;
|
||||||
|
up = ''
|
||||||
|
. ${serviceFns}
|
||||||
|
device=$(grep /persist /proc/1/mountinfo | cut -f9 -d' ')
|
||||||
|
${pkgs.e2fsprogs}/bin/resize2fs $device
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
filesystem = dir {
|
||||||
|
etc = dir {
|
||||||
|
"resolv.conf" = symlink "${services.resolvconf}/.outputs/resolv.conf";
|
||||||
|
};
|
||||||
|
mnt = dir {};
|
||||||
|
};
|
||||||
|
rootfsType = "ext4";
|
||||||
|
|
||||||
|
# sda is most likely correct for the boot-from-USB case. For tftp
|
||||||
|
# it's overridden by the boot.scr anyway, so maybe it all works out
|
||||||
|
hardware.rootDevice = lib.mkForce "/dev/sda1";
|
||||||
|
|
||||||
|
users.root = {
|
||||||
|
# the password is "secret". Use mkpasswd -m sha512crypt to
|
||||||
|
# create this hashed password string
|
||||||
|
passwd = "$6$y7WZ5hM6l5nriLmo$5AJlmzQZ6WA.7uBC7S8L4o19ESR28Dg25v64/vDvvCN01Ms9QoHeGByj8lGlJ4/b.dbwR9Hq2KXurSnLigt1W1";
|
||||||
|
|
||||||
|
|
||||||
|
openssh.authorizedKeys.keys =
|
||||||
|
let fromBuild =
|
||||||
|
(builtins.readFile
|
||||||
|
((builtins.toPath (builtins.getEnv "HOME")) + "/.ssh/authorized_keys")
|
||||||
|
);
|
||||||
|
in lib.splitString "\n" fromBuild;
|
||||||
|
};
|
||||||
|
|
||||||
|
defaultProfile.packages = with pkgs; [
|
||||||
|
e2fsprogs # ext4
|
||||||
|
btrfs-progs
|
||||||
|
mtdutils # mtd, jffs2, ubifs
|
||||||
|
dtc # you never know when you might need device tree stuff
|
||||||
|
some-util-linux
|
||||||
|
libubootenv # fw_{set,print}env
|
||||||
|
pciutils
|
||||||
|
];
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
rec {
|
{
|
||||||
wpa_passphrase = "you bring light in";
|
wpa_passphrase = "you bring light in";
|
||||||
|
ssid = "liminix";
|
||||||
l2tp = {
|
l2tp = {
|
||||||
name = "abcde@a.1";
|
name = "abcde@a.1";
|
||||||
password = "NotMyIspPassword";
|
password = "NotMyIspPassword";
|
||||||
@ -10,5 +11,9 @@ rec {
|
|||||||
openssh.authorizedKeys.keys = [
|
openssh.authorizedKeys.keys = [
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
root_password = root.passwd;
|
|
||||||
|
lan = {
|
||||||
|
prefix = "10.8.0";
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,10 @@
|
|||||||
|
|
||||||
{ config, pkgs, lib, ... } :
|
{ config, pkgs, lib, ... } :
|
||||||
let
|
let
|
||||||
secrets = import ./rotuer-secrets.nix;
|
secrets = {
|
||||||
|
domainName = "fake.liminix.org";
|
||||||
|
firewallRules = {};
|
||||||
|
} // (import ./rotuer-secrets.nix);
|
||||||
inherit (pkgs.liminix.services) oneshot longrun bundle;
|
inherit (pkgs.liminix.services) oneshot longrun bundle;
|
||||||
inherit (pkgs) serviceFns;
|
inherit (pkgs) serviceFns;
|
||||||
svc = config.system.service;
|
svc = config.system.service;
|
||||||
@ -34,7 +37,6 @@ in rec {
|
|||||||
|
|
||||||
imports = [
|
imports = [
|
||||||
../modules/wlan.nix
|
../modules/wlan.nix
|
||||||
../modules/standard.nix
|
|
||||||
../modules/network
|
../modules/network
|
||||||
../modules/ppp
|
../modules/ppp
|
||||||
../modules/dnsmasq
|
../modules/dnsmasq
|
||||||
@ -43,15 +45,20 @@ in rec {
|
|||||||
../modules/hostapd
|
../modules/hostapd
|
||||||
../modules/bridge
|
../modules/bridge
|
||||||
../modules/ntp
|
../modules/ntp
|
||||||
|
../modules/schnapps
|
||||||
../modules/ssh
|
../modules/ssh
|
||||||
|
../modules/outputs/btrfs.nix
|
||||||
|
../modules/outputs/extlinux.nix
|
||||||
];
|
];
|
||||||
rootfsType = "jffs2";
|
|
||||||
hostname = "rotuer";
|
hostname = "rotuer";
|
||||||
|
rootfsType = "btrfs";
|
||||||
|
rootOptions = "subvol=@";
|
||||||
|
boot.loader.extlinux.enable = true;
|
||||||
|
|
||||||
services.hostap = svc.hostapd.build {
|
services.hostap = svc.hostapd.build {
|
||||||
interface = config.hardware.networkInterfaces.wlan;
|
interface = config.hardware.networkInterfaces.wlan;
|
||||||
params = {
|
params = {
|
||||||
ssid = "liminix";
|
ssid = secrets.ssid;
|
||||||
hw_mode="g";
|
hw_mode="g";
|
||||||
channel = "2";
|
channel = "2";
|
||||||
ieee80211n = 1;
|
ieee80211n = 1;
|
||||||
@ -61,19 +68,20 @@ in rec {
|
|||||||
services.hostap5 = svc.hostapd.build {
|
services.hostap5 = svc.hostapd.build {
|
||||||
interface = config.hardware.networkInterfaces.wlan5;
|
interface = config.hardware.networkInterfaces.wlan5;
|
||||||
params = rec {
|
params = rec {
|
||||||
ssid = "liminix_5";
|
ssid = "${secrets.ssid}5";
|
||||||
hw_mode="a";
|
hw_mode="a";
|
||||||
channel = 36;
|
channel = 36;
|
||||||
ht_capab = "[HT40+]";
|
ht_capab = "[HT40+]";
|
||||||
vht_oper_chwidth = 1;
|
vht_oper_chwidth = 1;
|
||||||
vht_oper_centr_freq_seg0_idx = channel + 6;
|
vht_oper_centr_freq_seg0_idx = channel + 6;
|
||||||
|
ieee80211n = 1;
|
||||||
ieee80211ac = 1;
|
ieee80211ac = 1;
|
||||||
} // wirelessConfig;
|
} // wirelessConfig;
|
||||||
};
|
};
|
||||||
|
|
||||||
services.int = svc.network.address.build {
|
services.int = svc.network.address.build {
|
||||||
interface = svc.bridge.primary.build { ifname = "int"; };
|
interface = svc.bridge.primary.build { ifname = "int"; };
|
||||||
family = "inet"; address ="10.8.0.1"; prefixLength = 16;
|
family = "inet"; address ="${secrets.lan.prefix}.1"; prefixLength = 24;
|
||||||
};
|
};
|
||||||
|
|
||||||
services.bridge = svc.bridge.members.build {
|
services.bridge = svc.bridge.members.build {
|
||||||
@ -81,7 +89,12 @@ in rec {
|
|||||||
members = with config.hardware.networkInterfaces;
|
members = with config.hardware.networkInterfaces;
|
||||||
[ wlan
|
[ wlan
|
||||||
wlan5
|
wlan5
|
||||||
lan ];
|
lan0
|
||||||
|
lan1
|
||||||
|
lan2
|
||||||
|
lan3
|
||||||
|
lan4
|
||||||
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
services.ntp = svc.ntp.build {
|
services.ntp = svc.ntp.build {
|
||||||
@ -99,7 +112,7 @@ in rec {
|
|||||||
resolvconf = services.resolvconf;
|
resolvconf = services.resolvconf;
|
||||||
inherit interface;
|
inherit interface;
|
||||||
ranges = [
|
ranges = [
|
||||||
"10.8.0.10,10.8.0.240"
|
"${secrets.lan.prefix}.10,${secrets.lan.prefix}.240"
|
||||||
# ra-stateless: sends router advertisements with the O and A
|
# ra-stateless: sends router advertisements with the O and A
|
||||||
# bits set, and provides a stateless DHCP service. The client
|
# bits set, and provides a stateless DHCP service. The client
|
||||||
# will use a SLAAC address, and use DHCP for other
|
# will use a SLAAC address, and use DHCP for other
|
||||||
@ -110,8 +123,8 @@ in rec {
|
|||||||
# You can add static addresses for the DHCP server here. I'm
|
# You can add static addresses for the DHCP server here. I'm
|
||||||
# not putting my actual MAC addresses in a public git repo ...
|
# not putting my actual MAC addresses in a public git repo ...
|
||||||
hosts = { } // lib.optionalAttrs (builtins.pathExists ./static-leases.nix) (import ./static-leases.nix);
|
hosts = { } // lib.optionalAttrs (builtins.pathExists ./static-leases.nix) (import ./static-leases.nix);
|
||||||
|
upstreams = [ "/${secrets.domainName}/" ];
|
||||||
domain = "fake.liminix.org";
|
domain = secrets.domainName;
|
||||||
};
|
};
|
||||||
|
|
||||||
services.wan = svc.pppoe.build {
|
services.wan = svc.pppoe.build {
|
||||||
@ -157,7 +170,9 @@ in rec {
|
|||||||
};
|
};
|
||||||
|
|
||||||
services.firewall = svc.firewall.build {
|
services.firewall = svc.firewall.build {
|
||||||
ruleset = import ./demo-firewall.nix;
|
ruleset =
|
||||||
|
let defaults = import ./demo-firewall.nix;
|
||||||
|
in lib.recursiveUpdate defaults secrets.firewallRules;
|
||||||
};
|
};
|
||||||
|
|
||||||
services.packet_forwarding = svc.network.forward.build { };
|
services.packet_forwarding = svc.network.forward.build { };
|
||||||
@ -182,5 +197,18 @@ in rec {
|
|||||||
|
|
||||||
defaultProfile.packages = with pkgs; [
|
defaultProfile.packages = with pkgs; [
|
||||||
min-collect-garbage
|
min-collect-garbage
|
||||||
|
nftables
|
||||||
|
strace
|
||||||
|
tcpdump
|
||||||
|
s6
|
||||||
];
|
];
|
||||||
|
|
||||||
|
programs.busybox = {
|
||||||
|
applets = [
|
||||||
|
"fdisk" "sfdisk"
|
||||||
|
];
|
||||||
|
options = {
|
||||||
|
FEATURE_FANCY_TAIL = "y";
|
||||||
|
};
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
109
examples/turris.nix
Normal file
109
examples/turris.nix
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
{ config, pkgs, lib, lim, ... } :
|
||||||
|
let
|
||||||
|
inherit (pkgs) serviceFns;
|
||||||
|
svc = config.system.service;
|
||||||
|
|
||||||
|
in rec {
|
||||||
|
imports = [
|
||||||
|
../modules/network
|
||||||
|
../modules/ssh
|
||||||
|
../modules/vlan
|
||||||
|
../modules/wlan.nix
|
||||||
|
../modules/hostapd
|
||||||
|
../modules/bridge
|
||||||
|
|
||||||
|
../modules/ext4fs.nix
|
||||||
|
../modules/tftpboot.nix
|
||||||
|
];
|
||||||
|
|
||||||
|
rootfsType = "ext4";
|
||||||
|
|
||||||
|
boot.tftp = {
|
||||||
|
# IP addresses to use in the boot monitor when flashing/ booting
|
||||||
|
# over TFTP. If you are flashing using the stock firmware's Web UI
|
||||||
|
# then these dummy values are fine
|
||||||
|
ipaddr = "10.0.0.8"; # my address
|
||||||
|
serverip = "10.0.0.1"; # build machine or other tftp server
|
||||||
|
loadAddress = lim.parseInt "0x40000800";
|
||||||
|
};
|
||||||
|
|
||||||
|
hostname = "omnia";
|
||||||
|
|
||||||
|
services.hostap =
|
||||||
|
let secrets = {
|
||||||
|
ssid = "not-the-internet";
|
||||||
|
channel = 4;
|
||||||
|
wpa_passphrase = "diamond dogs";
|
||||||
|
};
|
||||||
|
in svc.hostapd.build {
|
||||||
|
interface = config.hardware.networkInterfaces.wlan;
|
||||||
|
params = {
|
||||||
|
country_code = "GB";
|
||||||
|
hw_mode = "g";
|
||||||
|
wmm_enabled = 1;
|
||||||
|
ieee80211n = 1;
|
||||||
|
inherit (secrets) ssid channel wpa_passphrase;
|
||||||
|
auth_algs = 1; # 1=wpa2, 2=wep, 3=both
|
||||||
|
wpa = 2; # 1=wpa, 2=wpa2, 3=both
|
||||||
|
wpa_key_mgmt = "WPA-PSK";
|
||||||
|
wpa_pairwise = "TKIP CCMP"; # auth for wpa (may not need this?)
|
||||||
|
rsn_pairwise = "CCMP"; # auth for wpa2
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
services.hostap5 =
|
||||||
|
let secrets = {
|
||||||
|
ssid = "not-the-internet";
|
||||||
|
channel = 36;
|
||||||
|
wpa_passphrase = "diamond dogs";
|
||||||
|
};
|
||||||
|
in svc.hostapd.build {
|
||||||
|
interface = config.hardware.networkInterfaces.wlan5;
|
||||||
|
params = {
|
||||||
|
country_code = "GB";
|
||||||
|
hw_mode = "a";
|
||||||
|
|
||||||
|
ht_capab = "[HT40+]";
|
||||||
|
vht_oper_chwidth = 1;
|
||||||
|
vht_oper_centr_freq_seg0_idx = secrets.channel + 6;
|
||||||
|
ieee80211ac = 1;
|
||||||
|
|
||||||
|
wmm_enabled = 1;
|
||||||
|
inherit (secrets) ssid channel wpa_passphrase;
|
||||||
|
auth_algs = 1; # 1=wpa2, 2=wep, 3=both
|
||||||
|
wpa = 2; # 1=wpa, 2=wpa2, 3=both
|
||||||
|
wpa_key_mgmt = "WPA-PSK";
|
||||||
|
wpa_pairwise = "TKIP CCMP"; # auth for wpa (may not need this?)
|
||||||
|
rsn_pairwise = "CCMP"; # auth for wpa2
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
services.int = svc.bridge.primary.build {
|
||||||
|
ifname = "int";
|
||||||
|
};
|
||||||
|
|
||||||
|
services.dhcpc = svc.network.dhcp.client.build {
|
||||||
|
interface = services.int;
|
||||||
|
dependencies = [ config.services.hostname ];
|
||||||
|
};
|
||||||
|
|
||||||
|
services.bridge = svc.bridge.members.build {
|
||||||
|
primary = services.int;
|
||||||
|
members = with config.hardware.networkInterfaces; [
|
||||||
|
lan
|
||||||
|
wlan
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
services.sshd = svc.ssh.build { };
|
||||||
|
|
||||||
|
users.root = {
|
||||||
|
# the password is "secret". Use mkpasswd -m sha512crypt to
|
||||||
|
# create this hashed password string
|
||||||
|
passwd = "$6$y7WZ5hM6l5nriLmo$5AJlmzQZ6WA.7uBC7S8L4o19ESR28Dg25v64/vDvvCN01Ms9QoHeGByj8lGlJ4/b.dbwR9Hq2KXurSnLigt1W1";
|
||||||
|
};
|
||||||
|
|
||||||
|
defaultProfile.packages = with pkgs; [
|
||||||
|
figlet pciutils
|
||||||
|
];
|
||||||
|
}
|
40
modules/all-modules.nix
Normal file
40
modules/all-modules.nix
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
# Import all of the modules, used in the documentation generator. Not
|
||||||
|
# currently expected to work in an actual configuration, but it would
|
||||||
|
# be nice if it did.
|
||||||
|
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
./base.nix
|
||||||
|
./bridge
|
||||||
|
./busybox.nix
|
||||||
|
./dhcp6c
|
||||||
|
./dnsmasq
|
||||||
|
./outputs/ext4fs.nix
|
||||||
|
./firewall
|
||||||
|
./hardware.nix
|
||||||
|
./hostapd
|
||||||
|
./hostname.nix
|
||||||
|
./outputs/initramfs.nix
|
||||||
|
./outputs/jffs2.nix
|
||||||
|
./kernel
|
||||||
|
./outputs/kexecboot.nix
|
||||||
|
./mount
|
||||||
|
./network
|
||||||
|
./ntp
|
||||||
|
./outputs.nix
|
||||||
|
./outputs/vmroot.nix
|
||||||
|
./outputs/ubimage.nix
|
||||||
|
./outputs/mtdimage.nix
|
||||||
|
./ppp
|
||||||
|
./ramdisk.nix
|
||||||
|
./squashfs.nix
|
||||||
|
./ssh
|
||||||
|
./outputs/tftpboot.nix
|
||||||
|
./outputs/ubifs.nix
|
||||||
|
./ubinize.nix
|
||||||
|
./users.nix
|
||||||
|
./vlan
|
||||||
|
./watchdog
|
||||||
|
./wlan.nix
|
||||||
|
];
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
{ lib, pkgs, config, ...}:
|
{ lib, lim, pkgs, config, ...}:
|
||||||
{
|
{
|
||||||
config = {
|
config = {
|
||||||
kernel.config = {
|
kernel.config = {
|
||||||
@ -6,14 +6,13 @@
|
|||||||
CPU_BIG_ENDIAN= "n";
|
CPU_BIG_ENDIAN= "n";
|
||||||
# CMDLINE_FROM_BOOTLOADER availability is conditional
|
# CMDLINE_FROM_BOOTLOADER availability is conditional
|
||||||
# on CMDLINE being set to something non-empty
|
# on CMDLINE being set to something non-empty
|
||||||
CMDLINE="\"console=ttyAMA0\"";
|
CMDLINE="\"empty=false\"";
|
||||||
CMDLINE_FROM_BOOTLOADER = "y";
|
CMDLINE_FROM_BOOTLOADER = "y";
|
||||||
|
|
||||||
OF = "y";
|
OF = "y";
|
||||||
# USE_OF = "y";
|
# USE_OF = "y";
|
||||||
};
|
};
|
||||||
boot.commandLine = [
|
hardware.ram.startAddress = lim.parseInt "0x40000000";
|
||||||
"console=ttyAMA0,38400"
|
system.outputs.u-boot = pkgs.ubootQemuAarch64;
|
||||||
];
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
11
modules/arch/arm.nix
Normal file
11
modules/arch/arm.nix
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
{ lib, lim, pkgs, config, ...}:
|
||||||
|
{
|
||||||
|
config = {
|
||||||
|
kernel.config = {
|
||||||
|
OF = "y";
|
||||||
|
};
|
||||||
|
kernel.makeTargets = ["arch/arm/boot/zImage"];
|
||||||
|
hardware.ram.startAddress = lim.parseInt "0x40000000";
|
||||||
|
system.outputs.u-boot = pkgs.ubootQemuArm;
|
||||||
|
};
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
{ lib, pkgs, config, ...}:
|
{ lib, pkgs, config, lim, ...}:
|
||||||
{
|
{
|
||||||
config = {
|
config = {
|
||||||
kernel.config = {
|
kernel.config = {
|
||||||
@ -10,6 +10,7 @@
|
|||||||
OF = "y";
|
OF = "y";
|
||||||
USE_OF = "y";
|
USE_OF = "y";
|
||||||
};
|
};
|
||||||
|
hardware.ram.startAddress = lim.parseInt "0x80000000";
|
||||||
boot.commandLine = [
|
boot.commandLine = [
|
||||||
"console=ttyS0,115200" # true of all mips we've yet encountered
|
"console=ttyS0,115200" # true of all mips we've yet encountered
|
||||||
];
|
];
|
||||||
|
@ -5,5 +5,6 @@
|
|||||||
kernel.config = {
|
kernel.config = {
|
||||||
CPU_BIG_ENDIAN = "y";
|
CPU_BIG_ENDIAN = "y";
|
||||||
};
|
};
|
||||||
|
system.outputs.u-boot = pkgs.ubootQemuMips;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ let
|
|||||||
|
|
||||||
in {
|
in {
|
||||||
imports = [
|
imports = [
|
||||||
./kernel.nix # kernel is a separate module for doc purposes
|
./kernel # kernel is a separate module for doc purposes
|
||||||
];
|
];
|
||||||
options = {
|
options = {
|
||||||
defaultProfile = {
|
defaultProfile = {
|
||||||
@ -39,17 +39,41 @@ in {
|
|||||||
};
|
};
|
||||||
rootfsType = mkOption {
|
rootfsType = mkOption {
|
||||||
default = "squashfs";
|
default = "squashfs";
|
||||||
type = types.enum ["squashfs" "jffs2"];
|
type = types.enum [
|
||||||
|
"btrfs"
|
||||||
|
"ext4"
|
||||||
|
"jffs2"
|
||||||
|
"squashfs"
|
||||||
|
"ubifs"
|
||||||
|
];
|
||||||
};
|
};
|
||||||
|
rootOptions = mkOption {
|
||||||
|
type = types.nullOr types.str;
|
||||||
|
default = null;
|
||||||
|
};
|
||||||
|
|
||||||
boot = {
|
boot = {
|
||||||
commandLine = mkOption {
|
commandLine = mkOption {
|
||||||
type = types.listOf types.nonEmptyStr;
|
type = types.listOf types.nonEmptyStr;
|
||||||
default = [];
|
default = [];
|
||||||
description = "Kernel command line";
|
description = "Kernel command line";
|
||||||
};
|
};
|
||||||
|
commandLineDtbNode = mkOption {
|
||||||
|
type = types.enum [ "bootargs" "bootargs-override" ];
|
||||||
|
default = "bootargs";
|
||||||
|
description = "Kernel command line's devicetree node";
|
||||||
|
};
|
||||||
|
imageType = mkOption {
|
||||||
|
type = types.enum [ "primary" "secondary" ];
|
||||||
|
default = "primary";
|
||||||
|
};
|
||||||
|
imageFormat = mkOption {
|
||||||
|
type = types.enum ["fit" "uimage"];
|
||||||
|
default = "uimage";
|
||||||
|
};
|
||||||
tftp = {
|
tftp = {
|
||||||
loadAddress = mkOption {
|
loadAddress = mkOption {
|
||||||
type = types.str;
|
type = types.ints.unsigned;
|
||||||
description = ''
|
description = ''
|
||||||
RAM address at which to load data when transferring via
|
RAM address at which to load data when transferring via
|
||||||
TFTP. This is not the address of the flash storage,
|
TFTP. This is not the address of the flash storage,
|
||||||
@ -85,7 +109,8 @@ in {
|
|||||||
"root=${config.hardware.rootDevice}"
|
"root=${config.hardware.rootDevice}"
|
||||||
"rootfstype=${config.rootfsType}"
|
"rootfstype=${config.rootfsType}"
|
||||||
"fw_devlink=off"
|
"fw_devlink=off"
|
||||||
];
|
] ++ lib.optional (config.rootOptions != null) "rootflags=${config.rootOptions}";
|
||||||
|
|
||||||
users.root = {
|
users.root = {
|
||||||
uid = 0; gid= 0; gecos = "Root of all evaluation";
|
uid = 0; gid= 0; gecos = "Root of all evaluation";
|
||||||
dir = "/home/root/";
|
dir = "/home/root/";
|
||||||
@ -125,6 +150,7 @@ in {
|
|||||||
proc = dir {};
|
proc = dir {};
|
||||||
run = dir {};
|
run = dir {};
|
||||||
sys = dir {};
|
sys = dir {};
|
||||||
|
tmp = dir {};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -32,23 +32,21 @@ let
|
|||||||
(a: symlink "${busybox}/bin/busybox");
|
(a: symlink "${busybox}/bin/busybox");
|
||||||
minimalApplets = [
|
minimalApplets = [
|
||||||
# this is probably less minimal than it could be
|
# this is probably less minimal than it could be
|
||||||
"arch" "ash" "base64" "basename" "bc" "brctl" "bunzip2" "bzcat"
|
"arch" "ash" "base64" "basename" "bc" "brctl" "bunzip2" "bzcat" "bzip2"
|
||||||
"bzip2" "cal" "cat" "chattr" "chgrp" "chmod" "chown" "chpst"
|
"cal" "cat" "chattr" "chgrp" "chmod" "chown" "chpst" "chroot" "clear" "cmp"
|
||||||
"chroot" "clear" "cmp" "comm" "cp" "cpio" "cut" "date" "dd" "df"
|
"comm" "cp" "cpio" "cut" "date" "dhcprelay" "dd" "df" "dirname" "dmesg"
|
||||||
"dirname" "dmesg" "du" "echo" "egrep" "env" "expand" "expr"
|
"du" "echo" "egrep" "env" "expand" "expr" "false" "fdisk" "fgrep" "find"
|
||||||
"false" "fdisk" "fgrep" "find" "free" "fuser" "grep" "gunzip"
|
"free" "fuser" "grep" "gunzip" "gzip" "head" "hexdump" "hostname" "hwclock"
|
||||||
"gzip" "head" "hexdump" "hostname" "hwclock" "ifconfig" "ip"
|
"ifconfig" "ip" "ipaddr" "iplink" "ipneigh" "iproute" "iprule" "kill"
|
||||||
"ipaddr" "iplink" "ipneigh" "iproute" "iprule" "kill" "killall"
|
"killall" "killall5" "less" "ln" "ls" "lsattr" "lsof" "md5sum" "mkdir"
|
||||||
"killall5" "less" "ln" "ls" "lsattr" "lsof" "md5sum" "mkdir"
|
"mknod" "mktemp" "mount" "mv" "nc" "netstat" "nohup" "od" "pgrep" "pidof"
|
||||||
"mknod" "mktemp" "mount" "mv" "nc" "netstat" "nohup" "od" "pgrep"
|
"ping" "ping6" "pkill" "pmap" "printenv" "printf" "ps" "pwd" "readlink"
|
||||||
"pidof" "ping" "ping6" "pkill" "pmap" "printenv" "printf" "ps"
|
"realpath" "reset" "rm" "rmdir" "route" "sed" "seq" "setsid" "sha1sum"
|
||||||
"pwd" "readlink" "realpath" "reset" "rm" "rmdir" "route" "sed"
|
"sha256sum" "sha512sum" "sleep" "sort" "stat" "strings" "stty" "su" "sum"
|
||||||
"seq" "setsid" "sha1sum" "sha256sum" "sha512sum" "sleep" "sort"
|
"swapoff" "swapon" "sync" "tail" "tee" "test" "time" "touch" "tr"
|
||||||
"stat" "strings" "stty" "su" "sum" "swapoff" "swapon" "sync"
|
"traceroute" "traceroute6" "true" "truncate" "tty" "udhcpc" "umount"
|
||||||
"tail" "tee" "test" "time" "touch" "tr" "traceroute" "traceroute6"
|
"uname" "unexpand" "uniq" "unlink" "unlzma" "unxz" "unzip" "uptime" "watch"
|
||||||
"true" "truncate" "tty" "udhcpc" "umount" "uname"
|
"wc" "whoami" "xargs" "xxd" "xz" "xzcat" "yes" "zcat"
|
||||||
"unexpand" "uniq" "unlink" "unlzma" "unxz" "unzip" "uptime"
|
|
||||||
"watch" "wc" "whoami" "xargs" "xxd" "xz" "xzcat" "yes" "zcat"
|
|
||||||
];
|
];
|
||||||
in {
|
in {
|
||||||
options = {
|
options = {
|
||||||
|
@ -1,31 +1,32 @@
|
|||||||
(local { : system } (require :anoia))
|
(local { : system } (require :anoia))
|
||||||
(local svc (require :anoia.svc))
|
(local svc (require :anoia.svc))
|
||||||
|
|
||||||
(fn changes [old-addresses new-addresses]
|
(fn deletions [old-addresses new-addresses]
|
||||||
(let [added {}
|
(let [deleted {}]
|
||||||
deleted {}]
|
|
||||||
(each [n address (pairs new-addresses)]
|
|
||||||
(if (not (. old-addresses n))
|
|
||||||
(table.insert added address)))
|
|
||||||
(each [n address (pairs old-addresses)]
|
(each [n address (pairs old-addresses)]
|
||||||
(if (not (. new-addresses n))
|
(let [now (. new-addresses n)]
|
||||||
(table.insert deleted address)))
|
(if (or (not now) (not (= now.len address.len)))
|
||||||
(values added deleted)))
|
(table.insert deleted address))))
|
||||||
|
deleted))
|
||||||
|
|
||||||
(fn update-prefixes [device prefixes new-prefixes]
|
(fn update-prefixes [wan-device addresses new-addresses exec]
|
||||||
(let [(added deleted) (changes prefixes new-prefixes)]
|
(each [_ p (ipairs (deletions addresses new-addresses))]
|
||||||
(each [_ p (ipairs added)]
|
(exec
|
||||||
(system
|
(.. "ip address del " p.address "1/" p.len " dev " wan-device)))
|
||||||
(.. "ip address add " p.address "1/" p.len " dev " device)))
|
(each [_ p (pairs new-addresses)]
|
||||||
(each [_ p (ipairs deleted)]
|
(exec
|
||||||
(system
|
(.. "ip address change " p.address "1/" p.len
|
||||||
(.. "ip address del " p.address "1/" p.len " dev " device)))))
|
" dev " wan-device
|
||||||
|
" valid_lft " p.valid
|
||||||
|
" preferred_lft " p.preferred
|
||||||
|
)))
|
||||||
|
new-addresses)
|
||||||
|
|
||||||
(fn run []
|
(fn run []
|
||||||
(let [[state-directory lan-device] arg
|
(let [[state-directory lan-device] arg
|
||||||
dir (svc.open state-directory)]
|
dir (svc.open state-directory)]
|
||||||
(accumulate [addresses []
|
(accumulate [addresses []
|
||||||
v (dir:events)]
|
v (dir:events)]
|
||||||
(update-prefixes lan-device addresses (v:output "prefix")))))
|
(update-prefixes lan-device addresses (v:output "prefix") system))))
|
||||||
|
|
||||||
{ : changes : run }
|
{ : changes : run }
|
||||||
|
@ -5,23 +5,45 @@
|
|||||||
|
|
||||||
(local a1
|
(local a1
|
||||||
{
|
{
|
||||||
"2001-ab-cd-ef_hjgKHGhKJH" {
|
"2001-ab-cd-ef" {
|
||||||
:address "2001:ab:cd:ef"
|
:address "2001:ab:cd:ef"
|
||||||
:len "64"
|
:len "64"
|
||||||
:preferred "200"
|
:preferred "3600"
|
||||||
:valid "200"
|
:valid "7200"
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
(local a156
|
||||||
|
{
|
||||||
|
"2001-ab-cd-ef" {
|
||||||
|
:address "2001:ab:cd:ef"
|
||||||
|
:len "56"
|
||||||
|
:preferred "3600"
|
||||||
|
:valid "7200"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
(local a2
|
(local a2
|
||||||
{
|
{
|
||||||
"2001-0-1-2-3_aNteBnb" {
|
"2001-0-1-2-3" {
|
||||||
:address "2001:0:1:2:3"
|
:address "2001:0:1:2:3"
|
||||||
:len "64"
|
:len "64"
|
||||||
:preferred "200"
|
:preferred "3600"
|
||||||
:valid "200"
|
:valid "7200"
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
(local a21
|
||||||
|
{
|
||||||
|
"2001-0-1-2-3" {
|
||||||
|
:address "2001:0:1:2:3"
|
||||||
|
:len "64"
|
||||||
|
:preferred "1800"
|
||||||
|
:valid "5400"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -30,39 +52,85 @@
|
|||||||
`(when (not ,assertion)
|
`(when (not ,assertion)
|
||||||
(assert false ,msg))))
|
(assert false ,msg))))
|
||||||
|
|
||||||
|
(macro expect= [actual expected]
|
||||||
|
`(let [ve# (view ,expected)
|
||||||
|
va# (view ,actual)]
|
||||||
|
(when (not (= ve# va#))
|
||||||
|
(assert false
|
||||||
|
(.. "\nexpected " ve# "\ngot " va#)
|
||||||
|
))))
|
||||||
|
|
||||||
(fn first-address []
|
(fn first-address []
|
||||||
(let [(add del)
|
(let [deleted
|
||||||
(subject.changes
|
(subject.deletions
|
||||||
{ }
|
{ }
|
||||||
a1
|
a1
|
||||||
)]
|
)]
|
||||||
(expect (= (# del) 0))
|
(expect= deleted [])))
|
||||||
(expect (= (# add) 1))
|
|
||||||
(let [[first] add]
|
|
||||||
(expect (= first.address "2001:ab:cd:ef")))))
|
|
||||||
|
|
||||||
(fn second-address []
|
(fn second-address []
|
||||||
(let [(add del)
|
(let [del
|
||||||
(subject.changes
|
(subject.deletions
|
||||||
a1
|
a1
|
||||||
(merge (dup a1) a2)
|
(merge (dup a1) a2)
|
||||||
)]
|
)]
|
||||||
(expect (= (# del) 0))
|
(expect= del [])))
|
||||||
(expect (= (# add) 1))
|
|
||||||
(let [[first] add] (expect (= first.address "2001:0:1:2:3")))))
|
|
||||||
|
|
||||||
(fn less-address []1
|
(fn old-address-is-deleted []
|
||||||
(let [(add del)
|
(let [del
|
||||||
(subject.changes
|
(subject.deletions
|
||||||
(merge (dup a1) a2)
|
(merge (dup a1) a2)
|
||||||
a1
|
a1
|
||||||
)]
|
)]
|
||||||
(expect (= (# add) 0))
|
(expect= (. del 1) (. a2 "2001-0-1-2-3"))
|
||||||
(expect (= (# del) 1))
|
))
|
||||||
|
|
||||||
(let [[first] del] (expect (= first.address "2001:0:1:2:3")))))
|
(fn changed-lifetime-not-deleted []
|
||||||
|
(let [del
|
||||||
|
(subject.deletions
|
||||||
|
(merge (dup a1) a2)
|
||||||
|
(merge (dup a1) a21)
|
||||||
|
)]
|
||||||
|
;; when an address lifetime changes, "ip address change"
|
||||||
|
;; will update that so it need not (should not) be deleted
|
||||||
|
(expect= del [])))
|
||||||
|
|
||||||
|
(fn changed-prefix-is-deleted []
|
||||||
|
(let [del
|
||||||
|
(subject.deletions a1 a156)]
|
||||||
|
;; when an address prefix changes, "ip address change"
|
||||||
|
;; ignores that cjhange, so we have to remove the
|
||||||
|
;; address before reinstating it
|
||||||
|
(expect= del [(. a1 "2001-ab-cd-ef")])))
|
||||||
|
|
||||||
(first-address)
|
(first-address)
|
||||||
(second-address)
|
(second-address)
|
||||||
(less-address)
|
(old-address-is-deleted)
|
||||||
|
(changed-lifetime-not-deleted)
|
||||||
|
(changed-prefix-is-deleted)
|
||||||
|
|
||||||
|
(let [cmds []]
|
||||||
|
(subject.update-addresses
|
||||||
|
"ppp0" a1 (merge (dup a1) a2)
|
||||||
|
(fn [a] (table.insert cmds a)))
|
||||||
|
(expect=
|
||||||
|
(doto cmds table.sort)
|
||||||
|
[
|
||||||
|
;; order of changes is unimportant
|
||||||
|
"ip address change 2001:0:1:2:3/64 dev ppp0 valid_lft 7200 preferred_lft 3600"
|
||||||
|
"ip address change 2001:ab:cd:ef/64 dev ppp0 valid_lft 7200 preferred_lft 3600"
|
||||||
|
]))
|
||||||
|
|
||||||
|
(let [cmds []]
|
||||||
|
(subject.update-addresses
|
||||||
|
"ppp0" (merge (dup a1) a2) a1
|
||||||
|
(fn [a] (table.insert cmds a)))
|
||||||
|
(expect=
|
||||||
|
cmds
|
||||||
|
[
|
||||||
|
;; deletes are executed before changes
|
||||||
|
"ip address del 2001:0:1:2:3/64 dev ppp0"
|
||||||
|
"ip address change 2001:ab:cd:ef/64 dev ppp0 valid_lft 7200 preferred_lft 3600"
|
||||||
|
]))
|
||||||
|
|
||||||
|
(print "OK")
|
||||||
|
@ -1,35 +1,32 @@
|
|||||||
(local { : system } (require :anoia))
|
(local { : system } (require :anoia))
|
||||||
(local svc (require :anoia.svc))
|
(local svc (require :anoia.svc))
|
||||||
|
|
||||||
;; acquire-delegated-prefix has very similar code: we'd like to move
|
(fn deletions [old-addresses new-addresses]
|
||||||
;; this to anoia.svc when we see what the general form would look like
|
(let [deleted {}]
|
||||||
|
|
||||||
(fn changes [old-addresses new-addresses]
|
|
||||||
(let [added {}
|
|
||||||
deleted {}]
|
|
||||||
(each [n address (pairs new-addresses)]
|
|
||||||
(if (not (. old-addresses n))
|
|
||||||
(table.insert added address)))
|
|
||||||
(each [n address (pairs old-addresses)]
|
(each [n address (pairs old-addresses)]
|
||||||
(if (not (. new-addresses n))
|
(let [now (. new-addresses n)]
|
||||||
(table.insert deleted address)))
|
(if (or (not now) (not (= now.len address.len)))
|
||||||
(values added deleted)))
|
(table.insert deleted address))))
|
||||||
|
deleted))
|
||||||
|
|
||||||
(fn update-addresses [wan-device addresses new-addresses]
|
(fn update-addresses [wan-device addresses new-addresses exec]
|
||||||
(let [(added deleted) (changes addresses new-addresses)]
|
(each [_ p (ipairs (deletions addresses new-addresses))]
|
||||||
(each [_ p (ipairs added)]
|
(exec
|
||||||
(system
|
(.. "ip address del " p.address "/" p.len " dev " wan-device)))
|
||||||
(.. "ip address add " p.address "/" p.len " dev " wan-device)))
|
(each [_ p (pairs new-addresses)]
|
||||||
(each [_ p (ipairs deleted)]
|
(exec
|
||||||
(system
|
(.. "ip address change " p.address "/" p.len
|
||||||
(.. "ip address del " p.address "/" p.len " dev " wan-device)))
|
" dev " wan-device
|
||||||
new-addresses))
|
" valid_lft " p.valid
|
||||||
|
" preferred_lft " p.preferred
|
||||||
|
)))
|
||||||
|
new-addresses)
|
||||||
|
|
||||||
(fn run []
|
(fn run []
|
||||||
(let [[state-directory wan-device] arg
|
(let [[state-directory wan-device] arg
|
||||||
dir (svc.open state-directory)]
|
dir (svc.open state-directory)]
|
||||||
(accumulate [addresses []
|
(accumulate [addresses []
|
||||||
v (dir:events)]
|
v (dir:events)]
|
||||||
(update-addresses wan-device addresses (v:output "address")))))
|
(update-addresses wan-device addresses (v:output "address") system))))
|
||||||
|
|
||||||
{ : update-addresses : changes : run }
|
{ : update-addresses : deletions : run }
|
||||||
|
@ -11,6 +11,6 @@ let
|
|||||||
script = callPackage ./acquire-wan-address.nix { };
|
script = callPackage ./acquire-wan-address.nix { };
|
||||||
in longrun {
|
in longrun {
|
||||||
inherit name;
|
inherit name;
|
||||||
run = "${script} /run/service-state/${client.name} $(output ${interface} ifname)";
|
run = "${script} $SERVICE_OUTPUTS/${client.name} $(output ${interface} ifname)";
|
||||||
dependencies = [ client interface ];
|
dependencies = [ client interface ];
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ in longrun {
|
|||||||
inherit name;
|
inherit name;
|
||||||
notification-fd = 10;
|
notification-fd = 10;
|
||||||
run = ''
|
run = ''
|
||||||
export SERVICE_STATE=/run/service-state/${name}
|
export SERVICE_STATE=$SERVICE_OUTPUTS/${name}
|
||||||
${odhcp6c}/bin/odhcp6c -s ${odhcp-script} -e -v -p /run/${name}.pid -P0 $(output ${interface} ifname)
|
${odhcp6c}/bin/odhcp6c -s ${odhcp-script} -e -v -p /run/${name}.pid -P0 $(output ${interface} ifname)
|
||||||
)
|
)
|
||||||
'';
|
'';
|
||||||
|
@ -11,6 +11,6 @@ let
|
|||||||
script = callPackage ./acquire-delegated-prefix.nix { };
|
script = callPackage ./acquire-delegated-prefix.nix { };
|
||||||
in longrun {
|
in longrun {
|
||||||
inherit name;
|
inherit name;
|
||||||
run = "${script} /run/service-state/${client.name} $(output ${interface} ifname)";
|
run = "${script} $SERVICE_OUTPUTS/${client.name} $(output ${interface} ifname)";
|
||||||
dependencies = [ client interface ];
|
dependencies = [ client interface ];
|
||||||
}
|
}
|
||||||
|
@ -41,10 +41,11 @@ longrun {
|
|||||||
--no-hosts \
|
--no-hosts \
|
||||||
--log-dhcp \
|
--log-dhcp \
|
||||||
--enable-ra \
|
--enable-ra \
|
||||||
--log-debug \
|
|
||||||
--log-queries \
|
|
||||||
--log-facility=- \
|
--log-facility=- \
|
||||||
--dhcp-leasefile=/run/${name}.leases \
|
--dhcp-leasefile=$(mkstate ${name})/leases \
|
||||||
--pid-file=/run/${name}.pid
|
--pid-file=/run/${name}.pid
|
||||||
'';
|
'';
|
||||||
|
# --log-debug \
|
||||||
|
# --log-queries \
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -10,34 +10,41 @@ let
|
|||||||
inherit (pkgs) liminix;
|
inherit (pkgs) liminix;
|
||||||
inherit (pkgs.liminix.services) oneshot;
|
inherit (pkgs.liminix.services) oneshot;
|
||||||
|
|
||||||
kconf = isModule :
|
kmodules = pkgs.kmodloader.override {
|
||||||
# setting isModule false is utterly untested and mostly
|
inherit (config.system.outputs) kernel;
|
||||||
# unimplemented: I say this to preempt any "how on earth is this
|
|
||||||
# even supposed to work?" questions
|
|
||||||
let yes = if isModule then "m" else "y";
|
|
||||||
in {
|
|
||||||
NFT_FIB_IPV4 = yes;
|
|
||||||
NFT_FIB_IPV6 = yes;
|
|
||||||
NF_TABLES = yes;
|
|
||||||
NF_CT_PROTO_DCCP = "y";
|
|
||||||
NF_CT_PROTO_SCTP = "y";
|
|
||||||
NF_CT_PROTO_UDPLITE = "y";
|
|
||||||
# NF_CONNTRACK_FTP = yes;
|
|
||||||
NFT_CT = yes;
|
|
||||||
};
|
|
||||||
kmodules = pkgs.kernel-modules.override {
|
|
||||||
kernelSrc = config.system.outputs.kernel.src;
|
|
||||||
modulesupport = config.system.outputs.kernel.modulesupport;
|
|
||||||
targets = [
|
targets = [
|
||||||
"nft_fib_ipv4"
|
"nft_fib_ipv4"
|
||||||
"nft_fib_ipv6"
|
"nft_fib_ipv6"
|
||||||
|
"nf_log_syslog"
|
||||||
|
|
||||||
|
"ip6_tables"
|
||||||
|
"ip_tables"
|
||||||
|
"iptable_nat"
|
||||||
|
"nf_conntrack"
|
||||||
|
"nf_defrag_ipv4"
|
||||||
|
"nf_defrag_ipv6"
|
||||||
|
"nf_log_syslog"
|
||||||
|
"nf_nat"
|
||||||
|
"nf_reject_ipv4"
|
||||||
|
"nf_reject_ipv6"
|
||||||
|
"nf_tables"
|
||||||
|
"nft_chain_nat"
|
||||||
|
"nft_ct"
|
||||||
|
"nft_fib"
|
||||||
|
"nft_fib_ipv4"
|
||||||
|
"nft_fib_ipv6"
|
||||||
|
"nft_log"
|
||||||
|
"nft_masq"
|
||||||
|
"nft_nat"
|
||||||
|
"nft_reject"
|
||||||
|
"nft_reject_inet"
|
||||||
|
"nft_reject_ipv4"
|
||||||
|
"nft_reject_ipv6"
|
||||||
|
"x_tables"
|
||||||
|
"xt_MASQUERADE"
|
||||||
|
"xt_nat"
|
||||||
|
"xt_tcpudp"
|
||||||
];
|
];
|
||||||
kconfig = kconf true;
|
|
||||||
};
|
|
||||||
loadModules = oneshot {
|
|
||||||
name = "firewall-modules";
|
|
||||||
up = "sh ${kmodules}/load.sh";
|
|
||||||
down = "sh ${kmodules}/unload.sh";
|
|
||||||
};
|
};
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
@ -55,38 +62,40 @@ in
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
in svc // {
|
in svc // {
|
||||||
build = args : (svc.build args) // {
|
build = args :
|
||||||
dependencies = [ loadModules ] ++ (svc.dependencies or []);
|
let args' = args // {
|
||||||
};
|
dependencies = (args.dependencies or []) ++ [kmodules];
|
||||||
|
};
|
||||||
|
in svc.build args' ;
|
||||||
};
|
};
|
||||||
|
|
||||||
# For historical reasons the kernel config is split between
|
|
||||||
# monolithic options and modules. TODO: go through this list
|
|
||||||
# and see what can be moved into the "kconf" definiton above
|
|
||||||
kernel.config = {
|
kernel.config = {
|
||||||
NETFILTER_XT_MATCH_CONNTRACK = "y";
|
|
||||||
|
|
||||||
IP6_NF_IPTABLES= "y";
|
|
||||||
IP_NF_IPTABLES= "y";
|
|
||||||
|
|
||||||
IP_NF_NAT = "y";
|
|
||||||
IP_NF_TARGET_MASQUERADE = "y";
|
|
||||||
NETFILTER = "y";
|
NETFILTER = "y";
|
||||||
NETFILTER_ADVANCED = "y";
|
NETFILTER_ADVANCED = "y";
|
||||||
NETFILTER_XTABLES = "y";
|
NETFILTER_NETLINK = "m";
|
||||||
|
NF_CONNTRACK = "m";
|
||||||
|
|
||||||
NFT_COMPAT = "y";
|
IP6_NF_IPTABLES= "m";
|
||||||
NFT_CT = "y";
|
IP_NF_IPTABLES = "m";
|
||||||
NFT_LOG = "y";
|
IP_NF_NAT = "m";
|
||||||
NFT_MASQ = "y";
|
IP_NF_TARGET_MASQUERADE = "m";
|
||||||
NFT_NAT = "y";
|
|
||||||
NFT_REJECT = "y";
|
|
||||||
NFT_REJECT_INET = "y";
|
|
||||||
|
|
||||||
NF_CONNTRACK = "y";
|
NFT_CT = "m";
|
||||||
NF_NAT = "y";
|
NFT_FIB_IPV4 = "m";
|
||||||
NF_NAT_MASQUERADE = "y";
|
NFT_FIB_IPV6 = "m";
|
||||||
NF_TABLES= "y";
|
NFT_LOG = "m";
|
||||||
|
NFT_MASQ = "m";
|
||||||
|
NFT_NAT = "m";
|
||||||
|
NFT_REJECT = "m";
|
||||||
|
NFT_REJECT_INET = "m";
|
||||||
|
|
||||||
|
NF_CT_PROTO_DCCP = "y";
|
||||||
|
NF_CT_PROTO_SCTP = "y";
|
||||||
|
NF_CT_PROTO_UDPLITE = "y";
|
||||||
|
NF_LOG_SYSLOG = "m";
|
||||||
|
NF_NAT = "m";
|
||||||
|
NF_NAT_MASQUERADE = "y";
|
||||||
|
NF_TABLES = "m";
|
||||||
NF_TABLES_INET = "y";
|
NF_TABLES_INET = "y";
|
||||||
NF_TABLES_IPV4 = "y";
|
NF_TABLES_IPV4 = "y";
|
||||||
NF_TABLES_IPV6 = "y";
|
NF_TABLES_IPV6 = "y";
|
||||||
|
@ -16,8 +16,14 @@ in {
|
|||||||
hardware = {
|
hardware = {
|
||||||
dts = {
|
dts = {
|
||||||
src = mkOption {
|
src = mkOption {
|
||||||
type = types.path;
|
type = types.nullOr types.path;
|
||||||
description = "Path to the device tree source (usually from OpenWrt)";
|
description = ''
|
||||||
|
If the device requires an external device tree to be loaded
|
||||||
|
alongside the kernel, this is the path to the device tree source
|
||||||
|
(we usually get these from OpenWrt). This value may be null if the
|
||||||
|
platform creates the device tree - currently this is the case
|
||||||
|
only for QEMU.
|
||||||
|
'';
|
||||||
};
|
};
|
||||||
includes = mkOption {
|
includes = mkOption {
|
||||||
default = [];
|
default = [];
|
||||||
@ -26,9 +32,15 @@ in {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
defaultOutput = mkOption {
|
defaultOutput = mkOption {
|
||||||
description = "\"Default\" output: what gets built for this device when outputs.default is requested. Typically this is \"flashimage\" or \"vmroot\"";
|
description = "\"Default\" output: what gets built for this device when outputs.default is requested. Typically this is \"mtdimage\" or \"vmroot\"";
|
||||||
type = types.nonEmptyStr;
|
type = types.nonEmptyStr;
|
||||||
};
|
};
|
||||||
|
ram = {
|
||||||
|
startAddress = mkOption {
|
||||||
|
type = types.int;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
flash = {
|
flash = {
|
||||||
# start address and size of whichever partition (often
|
# start address and size of whichever partition (often
|
||||||
# called "firmware") we're going to overwrite with our
|
# called "firmware") we're going to overwrite with our
|
||||||
@ -42,19 +54,20 @@ in {
|
|||||||
kernel uimage and root fs. Usually not the entire flash, as
|
kernel uimage and root fs. Usually not the entire flash, as
|
||||||
we don't want to clobber the bootloader, calibration data etc
|
we don't want to clobber the bootloader, calibration data etc
|
||||||
'';
|
'';
|
||||||
type = types.str;
|
type = types.ints.unsigned;
|
||||||
};
|
};
|
||||||
size = mkOption {
|
size = mkOption {
|
||||||
type = types.str;
|
type = types.ints.unsigned;
|
||||||
description = "Size in bytes of the firmware partition";
|
description = "Size in bytes of the firmware partition";
|
||||||
};
|
};
|
||||||
eraseBlockSize = mkOption {
|
eraseBlockSize = mkOption {
|
||||||
description = "Flash erase block size in bytes";
|
description = "Flash erase block size in bytes";
|
||||||
type = types.str;
|
type = types.ints.unsigned;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
loadAddress = mkOption { default = null; };
|
loadAddress = mkOption { type = types.ints.unsigned; default = null; };
|
||||||
entryPoint = mkOption { };
|
entryPoint = mkOption { type = types.ints.unsigned; };
|
||||||
|
alignment = mkOption { type = types.nullOr types.ints.unsigned; default = null; description = "Alignment passed to `mkimage` for FIT"; };
|
||||||
radios = mkOption {
|
radios = mkOption {
|
||||||
description = ''
|
description = ''
|
||||||
Kernel modules (from mac80211 package) required for the
|
Kernel modules (from mac80211 package) required for the
|
||||||
@ -64,7 +77,11 @@ in {
|
|||||||
default = [];
|
default = [];
|
||||||
example = ["ath9k" "ath10k"];
|
example = ["ath9k" "ath10k"];
|
||||||
};
|
};
|
||||||
rootDevice = mkOption { };
|
rootDevice = mkOption {
|
||||||
|
description = "Full path to preferred root device";
|
||||||
|
type = types.str;
|
||||||
|
example = "/dev/mtdblock3";
|
||||||
|
};
|
||||||
networkInterfaces = mkOption {
|
networkInterfaces = mkOption {
|
||||||
type = types.attrsOf types.anything;
|
type = types.attrsOf types.anything;
|
||||||
};
|
};
|
||||||
|
@ -1,54 +0,0 @@
|
|||||||
{
|
|
||||||
config
|
|
||||||
, pkgs
|
|
||||||
, lib
|
|
||||||
, ...
|
|
||||||
}:
|
|
||||||
let
|
|
||||||
inherit (lib) mkIf mkOption types;
|
|
||||||
in
|
|
||||||
{
|
|
||||||
imports = [
|
|
||||||
./initramfs.nix
|
|
||||||
];
|
|
||||||
options.system.outputs = {
|
|
||||||
systemConfiguration = mkOption {
|
|
||||||
type = types.package;
|
|
||||||
description = ''
|
|
||||||
pkgs.systemconfig for the configured filesystem,
|
|
||||||
contains 'activate' and 'init' commands
|
|
||||||
'';
|
|
||||||
internal = true;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
config = mkIf (config.rootfsType == "jffs2") {
|
|
||||||
kernel.config = {
|
|
||||||
JFFS2_FS = "y";
|
|
||||||
JFFS2_LZO = "y";
|
|
||||||
JFFS2_RTIME = "y";
|
|
||||||
JFFS2_COMPRESSION_OPTIONS = "y";
|
|
||||||
JFFS2_ZLIB = "y";
|
|
||||||
JFFS2_CMODE_SIZE = "y";
|
|
||||||
};
|
|
||||||
boot.initramfs.enable = true;
|
|
||||||
system.outputs = rec {
|
|
||||||
systemConfiguration =
|
|
||||||
pkgs.systemconfig config.filesystem.contents;
|
|
||||||
rootfs =
|
|
||||||
let
|
|
||||||
inherit (pkgs.pkgsBuildBuild) runCommand mtdutils;
|
|
||||||
endian = if pkgs.stdenv.isBigEndian
|
|
||||||
then "--big-endian" else "--little-endian";
|
|
||||||
in runCommand "make-jffs2" {
|
|
||||||
depsBuildBuild = [ mtdutils ];
|
|
||||||
} ''
|
|
||||||
mkdir -p $TMPDIR/empty/nix/store/ $TMPDIR/empty/secrets
|
|
||||||
cp ${systemConfiguration}/bin/activate $TMPDIR/empty/activate
|
|
||||||
ln -s ${pkgs.s6-init-bin}/bin/init $TMPDIR/empty/init
|
|
||||||
grafts=$(sed < ${systemConfiguration}/etc/nix-store-paths 's/^\(.*\)$/--graft \1:\1/g')
|
|
||||||
mkfs.jffs2 --compression-mode=size ${endian} -e ${config.hardware.flash.eraseBlockSize} --enable-compressor=lzo --pad --root $TMPDIR/empty --output $out $grafts --squash --faketime
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
@ -9,13 +9,25 @@ let
|
|||||||
inherit (pkgs.pseudofile) dir symlink;
|
inherit (pkgs.pseudofile) dir symlink;
|
||||||
inherit (pkgs.liminix.networking) address interface;
|
inherit (pkgs.liminix.networking) address interface;
|
||||||
inherit (pkgs.liminix.services) bundle;
|
inherit (pkgs.liminix.services) bundle;
|
||||||
|
inherit (pkgs) liminix;
|
||||||
|
|
||||||
type_service = pkgs.liminix.lib.types.service;
|
type_service = pkgs.liminix.lib.types.service;
|
||||||
|
|
||||||
|
mergeConditionals = conf : conditions :
|
||||||
|
# for each key in conditions, if it is present in conf
|
||||||
|
# then merge the associated value into conf
|
||||||
|
lib.foldlAttrs
|
||||||
|
(acc: name: value:
|
||||||
|
if (conf ? ${name}) && (conf.${name} != "n")
|
||||||
|
then acc // value
|
||||||
|
else acc)
|
||||||
|
conf
|
||||||
|
conditions;
|
||||||
in {
|
in {
|
||||||
options = {
|
options = {
|
||||||
kernel = {
|
kernel = {
|
||||||
src = mkOption { type = types.package; } ;
|
src = mkOption { type = types.path; } ;
|
||||||
|
version = mkOption { type = types.str; default = "5.15.137";} ;
|
||||||
modular = mkOption {
|
modular = mkOption {
|
||||||
type = types.bool;
|
type = types.bool;
|
||||||
default = true;
|
default = true;
|
||||||
@ -41,11 +53,44 @@ in {
|
|||||||
};
|
};
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
conditionalConfig = mkOption {
|
||||||
|
description = ''
|
||||||
|
Kernel config options that should only be applied when
|
||||||
|
some other option is present.
|
||||||
|
'';
|
||||||
|
type = types.attrsOf (types.attrsOf types.nonEmptyStr);
|
||||||
|
default = {};
|
||||||
|
example = {
|
||||||
|
USB = {
|
||||||
|
USB_XHCI_MVEBU = "y";
|
||||||
|
USB_XHCI_HCD = "y";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
makeTargets = mkOption {
|
||||||
|
type = types.listOf types.str;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
config = {
|
config = {
|
||||||
|
system.outputs =
|
||||||
|
let
|
||||||
|
mergedConfig = mergeConditionals
|
||||||
|
config.kernel.config
|
||||||
|
config.kernel.conditionalConfig;
|
||||||
|
k = liminix.builders.kernel.override {
|
||||||
|
config = mergedConfig;
|
||||||
|
inherit (config.kernel) version src extraPatchPhase;
|
||||||
|
targets = config.kernel.makeTargets;
|
||||||
|
};
|
||||||
|
in {
|
||||||
|
kernel = k.vmlinux;
|
||||||
|
zimage = k.zImage;
|
||||||
|
};
|
||||||
|
|
||||||
kernel = rec {
|
kernel = rec {
|
||||||
modular = true; # disabling this is not yet supported
|
modular = true; # disabling this is not yet supported
|
||||||
|
makeTargets = ["vmlinux"];
|
||||||
config = {
|
config = {
|
||||||
IKCONFIG = "y";
|
IKCONFIG = "y";
|
||||||
IKCONFIG_PROC = "y";
|
IKCONFIG_PROC = "y";
|
||||||
@ -64,6 +109,8 @@ in {
|
|||||||
PACKET = "y"; # for ppp, tcpdump ...
|
PACKET = "y"; # for ppp, tcpdump ...
|
||||||
SYSVIPC= "y";
|
SYSVIPC= "y";
|
||||||
|
|
||||||
|
NETDEVICES = "y"; # even PPP needs this
|
||||||
|
|
||||||
# disabling this option causes the kernel to use an "empty"
|
# disabling this option causes the kernel to use an "empty"
|
||||||
# initramfs instead: it has a /dev/console node and not much
|
# initramfs instead: it has a /dev/console node and not much
|
||||||
# else. Note that pid 1 is started *before* the root
|
# else. Note that pid 1 is started *before* the root
|
@ -68,7 +68,21 @@ in {
|
|||||||
ifname = mkOption {
|
ifname = mkOption {
|
||||||
type = types.str;
|
type = types.str;
|
||||||
example = "eth0";
|
example = "eth0";
|
||||||
|
description = ''
|
||||||
|
Device name as used by the kernel (as seen in "ip link"
|
||||||
|
or "ifconfig" output). If devpath is also specified, the
|
||||||
|
device will be renamed to the name provided.
|
||||||
|
'';
|
||||||
};
|
};
|
||||||
|
devpath = mkOption {
|
||||||
|
type = types.nullOr types.str;
|
||||||
|
default = null;
|
||||||
|
example = "/devices/platform/soc/soc:internal-regs/f1070000.ethernet";
|
||||||
|
description = ''
|
||||||
|
Path to the sysfs node of the device. If you provide this
|
||||||
|
and the ifname option, the device will be renamed to the
|
||||||
|
name given by ifname.
|
||||||
|
''; };
|
||||||
# other "ip link add" options could go here as well
|
# other "ip link add" options could go here as well
|
||||||
mtu = mkOption {
|
mtu = mkOption {
|
||||||
type = types.nullOr types.int;
|
type = types.nullOr types.int;
|
||||||
|
@ -4,13 +4,27 @@
|
|||||||
, serviceFns
|
, serviceFns
|
||||||
, lib
|
, lib
|
||||||
}:
|
}:
|
||||||
{ifname, mtu} :
|
{
|
||||||
|
ifname
|
||||||
|
, devpath ? null
|
||||||
|
, mtu} :
|
||||||
|
# if devpath is supplied, we rename the interface at that
|
||||||
|
# path to have the specified name.
|
||||||
let
|
let
|
||||||
inherit (liminix.services) longrun oneshot;
|
inherit (liminix.services) longrun oneshot;
|
||||||
inherit (lib) concatStringsSep;
|
inherit (lib) concatStringsSep;
|
||||||
name = "${ifname}.link";
|
name = "${ifname}.link";
|
||||||
up = liminix.networking.ifup name ifname;
|
rename = if devpath != null
|
||||||
|
then ''
|
||||||
|
oldname=$(cd /sys${devpath} && cd net/ && echo *)
|
||||||
|
ip link set ''${oldname} name ${ifname}
|
||||||
|
''
|
||||||
|
else "";
|
||||||
in oneshot {
|
in oneshot {
|
||||||
inherit name up;
|
inherit name;
|
||||||
|
up = ''
|
||||||
|
${rename}
|
||||||
|
${liminix.networking.ifup name ifname}
|
||||||
|
'';
|
||||||
down = "ip link set down dev ${ifname}";
|
down = "ip link set down dev ${ifname}";
|
||||||
}
|
}
|
||||||
|
@ -7,103 +7,136 @@
|
|||||||
let
|
let
|
||||||
inherit (lib) mkOption types concatStringsSep;
|
inherit (lib) mkOption types concatStringsSep;
|
||||||
inherit (pkgs) liminix callPackage writeText;
|
inherit (pkgs) liminix callPackage writeText;
|
||||||
arch = let s = pkgs.stdenv; in
|
o = config.system.outputs;
|
||||||
if s.isAarch64
|
|
||||||
then "aarch64"
|
|
||||||
else if s.isMips
|
|
||||||
then "mips"
|
|
||||||
else throw "can't determine arch";
|
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
imports = [
|
imports = [
|
||||||
./squashfs.nix
|
./squashfs.nix
|
||||||
|
./outputs/vmroot.nix
|
||||||
|
./outputs/extlinux.nix
|
||||||
];
|
];
|
||||||
options = {
|
options = {
|
||||||
system.outputs = {
|
system.outputs = {
|
||||||
|
# the convention here is to mark an output as "internal" if
|
||||||
|
# it's not a complete system (kernel plus userland, or installer)
|
||||||
|
# but only part of one.
|
||||||
kernel = mkOption {
|
kernel = mkOption {
|
||||||
type = types.package;
|
type = types.package;
|
||||||
|
internal = true;
|
||||||
description = ''
|
description = ''
|
||||||
|
kernel
|
||||||
|
******
|
||||||
|
|
||||||
Kernel vmlinux file (usually ELF)
|
Kernel vmlinux file (usually ELF)
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
zimage = mkOption {
|
||||||
|
type = types.package;
|
||||||
|
internal = true;
|
||||||
|
description = ''
|
||||||
|
zimage
|
||||||
|
******
|
||||||
|
|
||||||
|
Kernel in compressed self-extracting package
|
||||||
|
'';
|
||||||
|
};
|
||||||
dtb = mkOption {
|
dtb = mkOption {
|
||||||
type = types.package;
|
type = types.package;
|
||||||
|
internal = true;
|
||||||
description = ''
|
description = ''
|
||||||
|
dtb
|
||||||
|
***
|
||||||
|
|
||||||
Compiled device tree (FDT) for the target device
|
Compiled device tree (FDT) for the target device
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
uimage = mkOption {
|
uimage = mkOption {
|
||||||
type = types.package;
|
type = types.package;
|
||||||
|
internal = true;
|
||||||
description = ''
|
description = ''
|
||||||
|
uimage
|
||||||
|
******
|
||||||
|
|
||||||
Combined kernel and FDT in uImage (U-Boot compatible) format
|
Combined kernel and FDT in uImage (U-Boot compatible) format
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
vmroot = mkOption {
|
tplink-safeloader = mkOption {
|
||||||
|
type = types.package;
|
||||||
|
};
|
||||||
|
u-boot = mkOption {
|
||||||
type = types.package;
|
type = types.package;
|
||||||
description = ''
|
|
||||||
Directory containing separate kernel and rootfs image for
|
|
||||||
use with qemu (see run-liminix-vm)
|
|
||||||
'';
|
|
||||||
};
|
};
|
||||||
manifest = mkOption {
|
manifest = mkOption {
|
||||||
type = types.package;
|
type = types.package;
|
||||||
|
internal = true;
|
||||||
description = ''
|
description = ''
|
||||||
Debugging aid. JSON rendition of config.filesystem, on
|
Debugging aid. JSON rendition of config.filesystem, on
|
||||||
which can run "nix-store -q --tree" on it and find
|
which can run "nix-store -q --tree" on it and find
|
||||||
out what's in the image, which is nice if it's unexpectedly huge
|
out what's in the image, which is nice if it's unexpectedly huge
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
rootdir = mkOption {
|
||||||
|
type = types.package;
|
||||||
|
internal = true;
|
||||||
|
description = ''
|
||||||
|
directory of files to package into root filesystem
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
bootablerootdir = mkOption {
|
||||||
|
type = types.package;
|
||||||
|
internal = true;
|
||||||
|
description = ''
|
||||||
|
directory of files to package into root filesystem, including
|
||||||
|
a kernel and appropriate associated gubbins for the
|
||||||
|
selected bootloader
|
||||||
|
'';
|
||||||
|
};
|
||||||
rootfs = mkOption {
|
rootfs = mkOption {
|
||||||
type = types.package;
|
type = types.package;
|
||||||
|
internal = true;
|
||||||
description = ''
|
description = ''
|
||||||
root filesystem (squashfs or jffs2) image
|
root filesystem (squashfs or jffs2) image
|
||||||
'';
|
'';
|
||||||
internal = true;
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
config = {
|
config = {
|
||||||
system.outputs = rec {
|
system.outputs = rec {
|
||||||
# tftpd = pkgs.buildPackages.tufted;
|
|
||||||
kernel = liminix.builders.kernel.override {
|
|
||||||
inherit (config.kernel) config src extraPatchPhase;
|
|
||||||
};
|
|
||||||
dtb = liminix.builders.dtb {
|
dtb = liminix.builders.dtb {
|
||||||
inherit (config.boot) commandLine;
|
inherit (config.boot) commandLine;
|
||||||
dts = config.hardware.dts.src;
|
dts = config.hardware.dts.src;
|
||||||
includes = config.hardware.dts.includes ++ [
|
includes = config.hardware.dts.includes ++ [
|
||||||
"${kernel.headers}/include"
|
"${o.kernel.headers}/include"
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
uimage = liminix.builders.uimage {
|
uimage = liminix.builders.uimage {
|
||||||
commandLine = concatStringsSep " " config.boot.commandLine;
|
commandLine = concatStringsSep " " config.boot.commandLine;
|
||||||
inherit (config.hardware) loadAddress entryPoint;
|
inherit (config.boot) commandLineDtbNode;
|
||||||
inherit kernel;
|
inherit (config.hardware) loadAddress entryPoint alignment;
|
||||||
inherit dtb;
|
inherit (config.boot) imageFormat;
|
||||||
|
inherit (o) kernel dtb;
|
||||||
};
|
};
|
||||||
# could use trivial-builders.linkFarmFromDrvs here?
|
rootdir =
|
||||||
vmroot =
|
|
||||||
let
|
let
|
||||||
cmdline = builtins.toJSON (concatStringsSep " " config.boot.commandLine);
|
inherit (pkgs.pkgsBuildBuild) runCommand;
|
||||||
makeBootableImage = pkgs.runCommandCC "objcopy" {}
|
in runCommand "mktree" { } ''
|
||||||
(if pkgs.stdenv.isAarch64
|
mkdir -p $out/nix/store/ $out/secrets $out/boot
|
||||||
then "${pkgs.stdenv.cc.targetPrefix}objcopy -O binary -S ${kernel} $out"
|
cp ${o.systemConfiguration}/bin/activate $out/activate
|
||||||
else "cp ${kernel} $out");
|
ln -s ${pkgs.s6-init-bin}/bin/init $out/init
|
||||||
in pkgs.runCommandCC "vmroot" {} ''
|
mkdir -p $out/nix/store
|
||||||
mkdir $out
|
for path in $(cat ${o.systemConfiguration}/etc/nix-store-paths) ; do
|
||||||
cd $out
|
(cd $out && cp -a $path .$path)
|
||||||
ln -s ${config.system.outputs.rootfs} rootfs
|
done
|
||||||
ln -s ${kernel} vmlinux
|
'';
|
||||||
ln -s ${manifest} manifest
|
bootablerootdir =
|
||||||
ln -s ${kernel.headers} build
|
let inherit (pkgs.pkgsBuildBuild) runCommand;
|
||||||
echo ${cmdline} > commandline
|
in runCommand "add-slash-boot" { } ''
|
||||||
cat > run.sh << EOF
|
cp -a ${o.rootdir} $out
|
||||||
#!${pkgs.runtimeShell}
|
${if config.boot.loader.extlinux.enable
|
||||||
CMDLINE=${cmdline} ${pkgs.pkgsBuildBuild.run-liminix-vm}/bin/run-liminix-vm --arch ${arch} \$* ${makeBootableImage} ${config.system.outputs.rootfs}
|
then "(cd $out && chmod -R +w . && rmdir boot && cp -a ${o.extlinux} boot)"
|
||||||
EOF
|
else ""
|
||||||
chmod +x run.sh
|
}
|
||||||
'';
|
'';
|
||||||
|
|
||||||
manifest = writeText "manifest.json" (builtins.toJSON config.filesystem.contents);
|
manifest = writeText "manifest.json" (builtins.toJSON config.filesystem.contents);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
37
modules/outputs/btrfs.nix
Normal file
37
modules/outputs/btrfs.nix
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
{
|
||||||
|
config
|
||||||
|
, pkgs
|
||||||
|
, lib
|
||||||
|
, ...
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
inherit (lib) mkIf mkOption types;
|
||||||
|
o = config.system.outputs;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
./initramfs.nix
|
||||||
|
];
|
||||||
|
config = mkIf (config.rootfsType == "btrfs") {
|
||||||
|
kernel.config = {
|
||||||
|
BTRFS_FS = "y";
|
||||||
|
};
|
||||||
|
boot.initramfs.enable = true;
|
||||||
|
system.outputs = {
|
||||||
|
rootfs =
|
||||||
|
let
|
||||||
|
inherit (pkgs.pkgsBuildBuild) runCommand e2fsprogs;
|
||||||
|
in runCommand "mkfs.btrfs" {
|
||||||
|
depsBuildBuild = [ e2fsprogs ];
|
||||||
|
} ''
|
||||||
|
tree=${o.bootablerootdir}
|
||||||
|
size=$(du -s --apparent-size --block-size 1024 $tree |cut -f1)
|
||||||
|
# add 25% for filesystem overhead
|
||||||
|
size=$(( 5 * $size / 4))
|
||||||
|
dd if=/dev/zero of=$out bs=1024 count=$size
|
||||||
|
echo "not implemented" ; exit 1
|
||||||
|
# mke2fs -t ext4 -j -d $tree $out
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
38
modules/outputs/ext4fs.nix
Normal file
38
modules/outputs/ext4fs.nix
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
{
|
||||||
|
config
|
||||||
|
, pkgs
|
||||||
|
, lib
|
||||||
|
, ...
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
inherit (lib) mkIf mkOption types;
|
||||||
|
o = config.system.outputs;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
./initramfs.nix
|
||||||
|
];
|
||||||
|
config = mkIf (config.rootfsType == "ext4") {
|
||||||
|
kernel.config = {
|
||||||
|
EXT4_FS = "y";
|
||||||
|
EXT4_USE_FOR_EXT2 = "y";
|
||||||
|
FS_ENCRYPTION = "y";
|
||||||
|
};
|
||||||
|
boot.initramfs.enable = true;
|
||||||
|
system.outputs = {
|
||||||
|
rootfs =
|
||||||
|
let
|
||||||
|
inherit (pkgs.pkgsBuildBuild) runCommand e2fsprogs;
|
||||||
|
in runCommand "mkfs.ext4" {
|
||||||
|
depsBuildBuild = [ e2fsprogs ];
|
||||||
|
} ''
|
||||||
|
tree=${o.bootablerootdir}
|
||||||
|
size=$(du -s --apparent-size --block-size 1024 $tree |cut -f1)
|
||||||
|
# add 25% for filesystem overhead
|
||||||
|
size=$(( 5 * $size / 4))
|
||||||
|
dd if=/dev/zero of=$out bs=1024 count=$size
|
||||||
|
mke2fs -t ext4 -j -d $tree $out
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
43
modules/outputs/extlinux.nix
Normal file
43
modules/outputs/extlinux.nix
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
{
|
||||||
|
config
|
||||||
|
, pkgs
|
||||||
|
, lib
|
||||||
|
, ...
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
inherit (lib) mkIf mkEnableOption mkOption types concatStringsSep;
|
||||||
|
inherit (pkgs.pseudofile) dir symlink;
|
||||||
|
cfg = config.boot.loader.extlinux;
|
||||||
|
o = config.system.outputs;
|
||||||
|
cmdline = concatStringsSep " " config.boot.commandLine;
|
||||||
|
wantsDtb = config.hardware.dts ? src && config.hardware.dts.src != null;
|
||||||
|
in {
|
||||||
|
options.system.outputs.extlinux = mkOption {
|
||||||
|
type = types.package;
|
||||||
|
# description = "";
|
||||||
|
};
|
||||||
|
options.boot.loader.extlinux.enable = mkEnableOption "extlinux";
|
||||||
|
|
||||||
|
config = mkIf cfg.enable {
|
||||||
|
system.outputs.extlinux = pkgs.runCommand "extlinux" {} ''
|
||||||
|
mkdir $out
|
||||||
|
cd $out
|
||||||
|
${if wantsDtb then "cp ${o.dtb} dtb" else "true"}
|
||||||
|
cp ${o.initramfs} initramfs
|
||||||
|
cp ${o.zimage} kernel
|
||||||
|
mkdir extlinux
|
||||||
|
cat > extlinux/extlinux.conf << _EOF
|
||||||
|
menu title Liminix
|
||||||
|
timeout 40
|
||||||
|
label Liminix
|
||||||
|
kernel /boot/kernel
|
||||||
|
# initrd /boot/initramfs
|
||||||
|
append ${cmdline}
|
||||||
|
${if wantsDtb then "fdt /boot/dtb" else ""}
|
||||||
|
_EOF
|
||||||
|
'';
|
||||||
|
filesystem = dir {
|
||||||
|
boot = symlink config.system.outputs.extlinux;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
@ -13,13 +13,23 @@ in
|
|||||||
boot.initramfs = {
|
boot.initramfs = {
|
||||||
enable = mkEnableOption "initramfs";
|
enable = mkEnableOption "initramfs";
|
||||||
};
|
};
|
||||||
system.outputs.initramfs = mkOption {
|
system.outputs = {
|
||||||
type = types.package;
|
initramfs = mkOption {
|
||||||
internal = true;
|
type = types.package;
|
||||||
description = ''
|
internal = true;
|
||||||
Initramfs image capable of mounting the jffs2 root
|
description = ''
|
||||||
filesystem
|
Initramfs image capable of mounting the real root
|
||||||
'';
|
filesystem
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
systemConfiguration = mkOption {
|
||||||
|
type = types.package;
|
||||||
|
description = ''
|
||||||
|
pkgs.systemconfig for the configured filesystem,
|
||||||
|
contains 'activate' and 'init' commands
|
||||||
|
'';
|
||||||
|
internal = true;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
config = mkIf config.boot.initramfs.enable {
|
config = mkIf config.boot.initramfs.enable {
|
||||||
@ -37,18 +47,14 @@ in
|
|||||||
dir /proc 0755 0 0
|
dir /proc 0755 0 0
|
||||||
dir /dev 0755 0 0
|
dir /dev 0755 0 0
|
||||||
nod /dev/console 0600 0 0 c 5 1
|
nod /dev/console 0600 0 0 c 5 1
|
||||||
nod /dev/mtdblock0 0600 0 0 b 31 0
|
|
||||||
nod /dev/mtdblock1 0600 0 0 b 31 1
|
|
||||||
nod /dev/mtdblock2 0600 0 0 b 31 2
|
|
||||||
nod /dev/mtdblock3 0600 0 0 b 31 3
|
|
||||||
nod /dev/mtdblock4 0600 0 0 b 31 4
|
|
||||||
nod /dev/mtdblock5 0600 0 0 b 31 5
|
|
||||||
dir /target 0755 0 0
|
dir /target 0755 0 0
|
||||||
dir /target/persist 0755 0 0
|
dir /target/persist 0755 0 0
|
||||||
dir /target/nix 0755 0 0
|
dir /target/nix 0755 0 0
|
||||||
file /init ${pkgs.preinit}/bin/preinit 0755 0 0
|
file /init ${pkgs.preinit}/bin/preinit 0755 0 0
|
||||||
SPECIALS
|
SPECIALS
|
||||||
'';
|
'';
|
||||||
|
systemConfiguration =
|
||||||
|
pkgs.systemconfig config.filesystem.contents;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
40
modules/outputs/jffs2.nix
Normal file
40
modules/outputs/jffs2.nix
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
{
|
||||||
|
config
|
||||||
|
, pkgs
|
||||||
|
, lib
|
||||||
|
, ...
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
inherit (lib) mkIf mkOption types;
|
||||||
|
o = config.system.outputs;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
./initramfs.nix
|
||||||
|
];
|
||||||
|
|
||||||
|
config = mkIf (config.rootfsType == "jffs2") {
|
||||||
|
kernel.config = {
|
||||||
|
JFFS2_FS = "y";
|
||||||
|
JFFS2_LZO = "y";
|
||||||
|
JFFS2_RTIME = "y";
|
||||||
|
JFFS2_COMPRESSION_OPTIONS = "y";
|
||||||
|
JFFS2_ZLIB = "y";
|
||||||
|
JFFS2_CMODE_SIZE = "y";
|
||||||
|
};
|
||||||
|
boot.initramfs.enable = true;
|
||||||
|
system.outputs = {
|
||||||
|
rootfs =
|
||||||
|
let
|
||||||
|
inherit (pkgs.pkgsBuildBuild) runCommand mtdutils;
|
||||||
|
endian = if pkgs.stdenv.isBigEndian
|
||||||
|
then "--big-endian" else "--little-endian";
|
||||||
|
in runCommand "make-jffs2" {
|
||||||
|
depsBuildBuild = [ mtdutils ];
|
||||||
|
} ''
|
||||||
|
tree=${o.bootablerootdir}
|
||||||
|
(cd $tree && mkfs.jffs2 --compression-mode=size ${endian} -e ${toString config.hardware.flash.eraseBlockSize} --enable-compressor=lzo --pad --root . --output $out --squash --faketime )
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
@ -7,7 +7,7 @@
|
|||||||
let
|
let
|
||||||
inherit (lib) mkOption mkForce types concatStringsSep;
|
inherit (lib) mkOption mkForce types concatStringsSep;
|
||||||
in {
|
in {
|
||||||
imports = [ ./ramdisk.nix ];
|
imports = [ ../ramdisk.nix ];
|
||||||
options.system.outputs = {
|
options.system.outputs = {
|
||||||
kexecboot = mkOption {
|
kexecboot = mkOption {
|
||||||
type = types.package;
|
type = types.package;
|
51
modules/outputs/mbrimage.nix
Normal file
51
modules/outputs/mbrimage.nix
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
{
|
||||||
|
config
|
||||||
|
, pkgs
|
||||||
|
, lib
|
||||||
|
, ...
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
inherit (lib) mkOption types concatStringsSep;
|
||||||
|
o = config.system.outputs;
|
||||||
|
phram_address = lib.toHexString (config.hardware.ram.startAddress + 256 * 1024 * 1024);
|
||||||
|
in {
|
||||||
|
options.system.outputs = {
|
||||||
|
mbrimage = mkOption {
|
||||||
|
type = types.package;
|
||||||
|
description = ''
|
||||||
|
mbrimage
|
||||||
|
*********
|
||||||
|
|
||||||
|
This creates a disk image file with a partition table containing
|
||||||
|
the contents of ``outputs.rootfs`` as its only partition.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
vmdisk = mkOption { type = types.package; };
|
||||||
|
};
|
||||||
|
|
||||||
|
config = {
|
||||||
|
system.outputs = {
|
||||||
|
mbrimage =
|
||||||
|
let
|
||||||
|
o = config.system.outputs;
|
||||||
|
in pkgs.runCommand "mbrimage" {
|
||||||
|
depsBuildBuild = [ pkgs.pkgsBuildBuild.util-linux ];
|
||||||
|
} ''
|
||||||
|
# leave 4 sectors at start for partition table
|
||||||
|
# and alignment to 2048 bytes (does that help?)
|
||||||
|
dd if=${o.rootfs} of=$out bs=512 seek=4 conv=sync
|
||||||
|
echo '4,-,L,*' | sfdisk $out
|
||||||
|
'';
|
||||||
|
vmdisk = pkgs.runCommand "vmdisk" {} ''
|
||||||
|
mkdir $out
|
||||||
|
cd $out
|
||||||
|
ln -s ${o.mbrimage} ./mbrimage
|
||||||
|
cat > run.sh <<EOF
|
||||||
|
#!${pkgs.runtimeShell}
|
||||||
|
${pkgs.pkgsBuildBuild.run-liminix-vm}/bin/run-liminix-vm --arch ${pkgs.stdenv.hostPlatform.qemuArch} --u-boot ${o.u-boot}/u-boot.bin --phram-address 0x${phram_address} --disk-image ${o.mbrimage} \$* /dev/null /dev/null
|
||||||
|
EOF
|
||||||
|
chmod +x run.sh
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
@ -11,7 +11,7 @@ in {
|
|||||||
options.system.outputs = {
|
options.system.outputs = {
|
||||||
firmware = mkOption {
|
firmware = mkOption {
|
||||||
type = types.package;
|
type = types.package;
|
||||||
internal = true; # component of flashimage
|
internal = true; # component of mtdimage
|
||||||
description = ''
|
description = ''
|
||||||
Binary image (combining kernel, FDT, rootfs, initramfs
|
Binary image (combining kernel, FDT, rootfs, initramfs
|
||||||
if needed, etc) for the target device.
|
if needed, etc) for the target device.
|
||||||
@ -19,17 +19,40 @@ in {
|
|||||||
};
|
};
|
||||||
flash-scr = mkOption {
|
flash-scr = mkOption {
|
||||||
type = types.package;
|
type = types.package;
|
||||||
internal = true; # component of flashimage
|
internal = true; # component of mtdimage
|
||||||
description = ''
|
description = ''
|
||||||
Copy-pastable U-Boot commands to TFTP download the
|
Copy-pastable U-Boot commands to TFTP download the
|
||||||
image and write it to flash
|
image and write it to flash
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
flashimage = mkOption {
|
mtdimage = mkOption {
|
||||||
type = types.package;
|
type = types.package;
|
||||||
description = ''
|
description = ''
|
||||||
Flashable image for the target device, and the script to
|
mtdimage
|
||||||
install it
|
**********
|
||||||
|
|
||||||
|
This creates an image called :file:`firmware.bin` suitable for
|
||||||
|
squashfs or jffs2 systems. It can be flashed from U-Boot (if
|
||||||
|
you have a serial console connection), or on some devices from
|
||||||
|
the vendor firmware, or from a Liminix kexecboot system.
|
||||||
|
|
||||||
|
If you are flashing from U-Boot, the file
|
||||||
|
:file:`flash.scr` is a sequence of commands
|
||||||
|
which you can paste at the U-Boot prompt to
|
||||||
|
to transfer the firmware file from a TFTP server and
|
||||||
|
write it to flash. **Please read the script before
|
||||||
|
running it: flash operations carry the potential to
|
||||||
|
brick your device**
|
||||||
|
|
||||||
|
.. NOTE::
|
||||||
|
|
||||||
|
TTL serial connections typically have no form of flow
|
||||||
|
control and so don't always like having massive chunks of
|
||||||
|
text pasted into them - and U-Boot may drop characters
|
||||||
|
while it's busy. So don't necessarily expect to copy-paste
|
||||||
|
the whole of :file:`flash.scr` into a terminal emulator and
|
||||||
|
have it work just like that. You may need to paste each
|
||||||
|
line one at a time, or even retype it.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@ -52,15 +75,15 @@ in {
|
|||||||
firmware =
|
firmware =
|
||||||
let
|
let
|
||||||
o = config.system.outputs;
|
o = config.system.outputs;
|
||||||
bs = config.hardware.flash.eraseBlockSize;
|
bs = toString config.hardware.flash.eraseBlockSize;
|
||||||
in pkgs.runCommand "firmware" {} ''
|
in pkgs.runCommand "firmware" {} ''
|
||||||
dd if=${o.uimage} of=$out bs=${bs} conv=sync
|
dd if=${o.uimage} of=$out bs=${bs} conv=sync
|
||||||
dd if=${o.rootfs} of=$out bs=${bs} conv=sync,nocreat,notrunc oflag=append
|
dd if=${o.rootfs} of=$out bs=${bs} conv=sync,nocreat,notrunc oflag=append
|
||||||
'';
|
'';
|
||||||
flashimage =
|
mtdimage =
|
||||||
let o = config.system.outputs; in
|
let o = config.system.outputs; in
|
||||||
# could use trivial-builders.linkFarmFromDrvs here?
|
# could use trivial-builders.linkFarmFromDrvs here?
|
||||||
pkgs.runCommand "flashimage" {} ''
|
pkgs.runCommand "mtdimage" {} ''
|
||||||
mkdir $out
|
mkdir $out
|
||||||
cd $out
|
cd $out
|
||||||
ln -s ${o.firmware} firmware.bin
|
ln -s ${o.firmware} firmware.bin
|
||||||
@ -83,9 +106,9 @@ in {
|
|||||||
cat > $out << EOF
|
cat > $out << EOF
|
||||||
setenv serverip ${tftp.serverip}
|
setenv serverip ${tftp.serverip}
|
||||||
setenv ipaddr ${tftp.ipaddr}
|
setenv ipaddr ${tftp.ipaddr}
|
||||||
tftp 0x$(printf %x ${tftp.loadAddress}) result/firmware.bin
|
tftp 0x${toHexString tftp.loadAddress} result/firmware.bin
|
||||||
erase 0x$(printf %x ${flash.address}) +${flash.size}
|
erase 0x${toHexString flash.address} +0x${toHexString flash.size}
|
||||||
cp.b 0x$(printf %x ${tftp.loadAddress}) 0x$(printf %x ${flash.address}) \''${filesize}
|
cp.b 0x${toHexString tftp.loadAddress} 0x${toHexString flash.address} \''${filesize}
|
||||||
echo command line was ${builtins.toJSON (concatStringsSep " " config.boot.commandLine)}
|
echo command line was ${builtins.toJSON (concatStringsSep " " config.boot.commandLine)}
|
||||||
EOF
|
EOF
|
||||||
'';
|
'';
|
163
modules/outputs/tftpboot.nix
Normal file
163
modules/outputs/tftpboot.nix
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
{
|
||||||
|
config
|
||||||
|
, pkgs
|
||||||
|
, lib
|
||||||
|
, ...
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
inherit (lib) mkOption types concatStringsSep;
|
||||||
|
cfg = config.boot.tftp;
|
||||||
|
hw = config.hardware;
|
||||||
|
arch = pkgs.stdenv.hostPlatform.linuxArch;
|
||||||
|
in {
|
||||||
|
imports = [ ../ramdisk.nix ];
|
||||||
|
options.boot.tftp = {
|
||||||
|
freeSpaceBytes = mkOption {
|
||||||
|
type = types.int;
|
||||||
|
default = 0;
|
||||||
|
};
|
||||||
|
kernelFormat = mkOption {
|
||||||
|
type = types.enum [ "zimage" "uimage" ];
|
||||||
|
default = "uimage";
|
||||||
|
};
|
||||||
|
compressRoot = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = false;
|
||||||
|
};
|
||||||
|
appendDTB = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = false;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
options.system.outputs = {
|
||||||
|
tftpboot = mkOption {
|
||||||
|
type = types.package;
|
||||||
|
description = ''
|
||||||
|
tftpboot
|
||||||
|
********
|
||||||
|
|
||||||
|
This output is intended for developing on a new device.
|
||||||
|
It assumes you have a serial connection and a
|
||||||
|
network connection to the device and that your
|
||||||
|
build machine is running a TFTP server.
|
||||||
|
|
||||||
|
The output is a directory containing kernel and
|
||||||
|
root filesystem image, and a script :file:`boot.scr` of U-Boot
|
||||||
|
commands that will load the images into memory and
|
||||||
|
run them directly,
|
||||||
|
instead of first writing them to flash. This saves
|
||||||
|
time and erase cycles.
|
||||||
|
|
||||||
|
It uses the Linux `phram <https://github.com/torvalds/linux/blob/master/drivers/mtd/devices/phram.c>`_ driver to emulate a flash device using a segment of physical RAM.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
config = {
|
||||||
|
boot.ramdisk.enable = true;
|
||||||
|
|
||||||
|
system.outputs = rec {
|
||||||
|
tftpboot =
|
||||||
|
let
|
||||||
|
inherit (pkgs.lib.trivial) toHexString;
|
||||||
|
o = config.system.outputs;
|
||||||
|
image = let choices = {
|
||||||
|
uimage = o.uimage;
|
||||||
|
zimage = o.zimage;
|
||||||
|
}; in choices.${cfg.kernelFormat};
|
||||||
|
bootCommand = let choices = {
|
||||||
|
uimage = "bootm";
|
||||||
|
zimage = "bootz";
|
||||||
|
}; in choices.${cfg.kernelFormat};
|
||||||
|
|
||||||
|
cmdline = concatStringsSep " " config.boot.commandLine;
|
||||||
|
objcopy = "${pkgs.stdenv.cc.bintools.targetPrefix}objcopy";
|
||||||
|
stripAndZip = ''
|
||||||
|
${objcopy} -O binary -R .reginfo -R .notes -R .note -R .comment -R .mdebug -R .note.gnu.build-id -S vmlinux.elf vmlinux.bin
|
||||||
|
rm -f vmlinux.bin.lzma ; lzma -k -z vmlinux.bin
|
||||||
|
'';
|
||||||
|
in
|
||||||
|
pkgs.runCommand "tftpboot" { nativeBuildInputs = with pkgs.pkgsBuildBuild; [ lzma dtc pkgs.stdenv.cc ubootTools ]; } ''
|
||||||
|
mkdir $out
|
||||||
|
cd $out
|
||||||
|
binsize() { local s=$(stat -L -c %s $1); echo $(($s + 0x1000 &(~0xfff))); }
|
||||||
|
binsize64k() { local s=$(stat -L -c %s $1); echo $(($s + 0x10000 &(~0xffff))); }
|
||||||
|
hex() { printf "0x%x" $1; }
|
||||||
|
|
||||||
|
rootfsStart=${toString cfg.loadAddress}
|
||||||
|
rootfsSize=$(binsize64k ${o.rootfs} )
|
||||||
|
rootfsSize=$(($rootfsSize + ${toString cfg.freeSpaceBytes} ))
|
||||||
|
|
||||||
|
ln -s ${o.manifest} manifest
|
||||||
|
ln -s ${o.kernel} vmlinux # handy for gdb
|
||||||
|
|
||||||
|
# if we are transferring kernel and dtb separately, the
|
||||||
|
# dtb has to precede the kernel in ram, because zimage
|
||||||
|
# decompression code will assume that any memory after the
|
||||||
|
# end of the kernel is free
|
||||||
|
|
||||||
|
dtbStart=$(($rootfsStart + $rootfsSize))
|
||||||
|
${if cfg.compressRoot
|
||||||
|
then ''
|
||||||
|
lzma -z9cv ${o.rootfs} > rootfs.lz
|
||||||
|
rootfsLzStart=$dtbStart
|
||||||
|
rootfsLzSize=$(binsize rootfs.lz)
|
||||||
|
dtbStart=$(($dtbStart + $rootfsLzSize))
|
||||||
|
''
|
||||||
|
else ''
|
||||||
|
ln -s ${o.rootfs} rootfs
|
||||||
|
''
|
||||||
|
}
|
||||||
|
|
||||||
|
cat ${o.dtb} > dtb
|
||||||
|
address_cells=$(fdtget dtb / '#address-cells')
|
||||||
|
size_cells=$(fdtget dtb / '#size-cells')
|
||||||
|
if [ $address_cells -gt 1 ]; then ac_prefix=0; fi
|
||||||
|
if [ $size_cells -gt 1 ]; then sz_prefix=0; fi
|
||||||
|
|
||||||
|
fdtput -p dtb /reserved-memory '#address-cells' $address_cells
|
||||||
|
fdtput -p dtb /reserved-memory '#size-cells' $size_cells
|
||||||
|
fdtput -p dtb /reserved-memory ranges
|
||||||
|
node=$(printf "phram-rootfs@%x" $rootfsStart)
|
||||||
|
fdtput -p -t s dtb /reserved-memory/$node compatible phram
|
||||||
|
fdtput -p -t lx dtb /reserved-memory/$node reg $ac_prefix $(hex $rootfsStart) $sz_prefix $(hex $rootfsSize)
|
||||||
|
|
||||||
|
cmd="liminix ${cmdline} mtdparts=phram0:''${rootfsSize}(rootfs) phram.phram=phram0,''${rootfsStart},''${rootfsSize},${toString config.hardware.flash.eraseBlockSize} root=/dev/mtdblock0";
|
||||||
|
fdtput -t s dtb /chosen bootargs "$cmd"
|
||||||
|
|
||||||
|
dtbSize=$(binsize ./dtb )
|
||||||
|
|
||||||
|
${if cfg.appendDTB then ''
|
||||||
|
imageStart=$dtbStart
|
||||||
|
# re-package image with updated dtb
|
||||||
|
cat ${o.kernel} > vmlinux.elf
|
||||||
|
${objcopy} --update-section .appended_dtb=dtb vmlinux.elf
|
||||||
|
${stripAndZip}
|
||||||
|
mkimage -A ${arch} -O linux -T kernel -C lzma -a $(hex ${toString hw.loadAddress}) -e $(hex ${toString hw.entryPoint}) -n '${lib.toUpper arch} Liminix Linux tftpboot' -d vmlinux.bin.lzma image
|
||||||
|
# dtc -I dtb -O dts -o /dev/stdout dtb | grep -A10 chosen ; exit 1
|
||||||
|
tftpcmd="tftpboot $(hex $imageStart) result/image "
|
||||||
|
bootcmd="bootm $(hex $imageStart)"
|
||||||
|
'' else ''
|
||||||
|
imageStart=$(($dtbStart + $dtbSize))
|
||||||
|
tftpcmd="tftpboot $(hex $imageStart) result/image; tftpboot $(hex $dtbStart) result/dtb "
|
||||||
|
ln -s ${image} image
|
||||||
|
bootcmd="${bootCommand} $(hex $imageStart) - $(hex $dtbStart)"
|
||||||
|
''}
|
||||||
|
|
||||||
|
cat > boot.scr << EOF
|
||||||
|
setenv serverip ${cfg.serverip}
|
||||||
|
setenv ipaddr ${cfg.ipaddr}
|
||||||
|
${
|
||||||
|
if cfg.compressRoot
|
||||||
|
then "tftpboot $(hex $rootfsLzStart) result/rootfs.lz"
|
||||||
|
else "tftpboot $(hex $rootfsStart) result/rootfs"
|
||||||
|
}; $tftpcmd
|
||||||
|
${if cfg.compressRoot
|
||||||
|
then "lzmadec $(hex $rootfsLzStart) $(hex $rootfsStart); "
|
||||||
|
else ""
|
||||||
|
} $bootcmd
|
||||||
|
EOF
|
||||||
|
'';
|
||||||
|
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
61
modules/outputs/tplink-safeloader.nix
Normal file
61
modules/outputs/tplink-safeloader.nix
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
{
|
||||||
|
config
|
||||||
|
, pkgs
|
||||||
|
, lib
|
||||||
|
, ...
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
inherit (lib) mkOption types concatStringsSep;
|
||||||
|
o = config.system.outputs;
|
||||||
|
cfg = config.tplink-safeloader;
|
||||||
|
in {
|
||||||
|
options.tplink-safeloader = {
|
||||||
|
board = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
options.system.outputs = {
|
||||||
|
tplink-safeloader = mkOption {
|
||||||
|
type = types.package;
|
||||||
|
description = ''
|
||||||
|
tplink-safeloader
|
||||||
|
*****************
|
||||||
|
|
||||||
|
For creating 'safeloader' images for tp-link devices.
|
||||||
|
|
||||||
|
These can be flashed to the device using the firmware update feature
|
||||||
|
in the TP-link web UI or the OEM bootloader recovery: Use something
|
||||||
|
sharp to hold the 'reset' button while turning on the router until
|
||||||
|
only the orange LED remains lit. The router will assume IP address
|
||||||
|
192.168.0.1 and expect you to take 192.168.0.5 on one of the LAN ports.
|
||||||
|
On NixOS, use something like::
|
||||||
|
|
||||||
|
networking.interfaces.enp0s20f0u1c2 = {
|
||||||
|
ipv4.addresses = [ {
|
||||||
|
address = "192.168.0.5";
|
||||||
|
prefixLength = 24;
|
||||||
|
} ];
|
||||||
|
};
|
||||||
|
networking.networkmanager = {
|
||||||
|
unmanaged = [ "enp0s20f0u1c2" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
This connection is rather somewhat temperamental, it may take a couple
|
||||||
|
of attempts, possibly re-attaching the USB dongle and running
|
||||||
|
``systemctl restart network-start.service``. The web interface does not
|
||||||
|
give accurate feedback (the progress bar is a lie), so you may want
|
||||||
|
to upload the firmware using ``curl -F firmware=@result http://192.168.0.1/f2.htm``.
|
||||||
|
After this shows a 'success' JSON, the image still needs to be
|
||||||
|
transferred from memory to flash, so be patient.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
config = {
|
||||||
|
system.outputs = rec {
|
||||||
|
tplink-safeloader =
|
||||||
|
pkgs.runCommand "tplink" { nativeBuildInputs = with pkgs.pkgsBuildBuild; [ firmware-utils ]; } ''
|
||||||
|
tplink-safeloader -B "${cfg.board}" -k "${o.uimage}" -r "${o.rootfs}" -o $out
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
49
modules/outputs/ubifs.nix
Normal file
49
modules/outputs/ubifs.nix
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
{
|
||||||
|
config
|
||||||
|
, pkgs
|
||||||
|
, lib
|
||||||
|
, ...
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
inherit (lib) mkIf mkOption types;
|
||||||
|
o = config.system.outputs;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
./initramfs.nix
|
||||||
|
];
|
||||||
|
|
||||||
|
options.system.outputs.rootubifs = mkOption {
|
||||||
|
type = types.package;
|
||||||
|
internal = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
options.hardware.ubi = {
|
||||||
|
minIOSize = mkOption { type = types.str; };
|
||||||
|
logicalEraseBlockSize = mkOption { type = types.str; }; # LEB
|
||||||
|
physicalEraseBlockSize = mkOption { type = types.str; }; # PEB
|
||||||
|
maxLEBcount = mkOption { type = types.str; }; # LEB
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkIf (config.rootfsType == "ubifs") {
|
||||||
|
kernel.config = {
|
||||||
|
MTD_UBI="y";
|
||||||
|
UBIFS_FS = "y";
|
||||||
|
UBIFS_FS_SECURITY = "n";
|
||||||
|
};
|
||||||
|
boot.initramfs.enable = true;
|
||||||
|
system.outputs = {
|
||||||
|
rootubifs =
|
||||||
|
let
|
||||||
|
inherit (pkgs.pkgsBuildBuild) runCommand mtdutils;
|
||||||
|
cfg = config.hardware.ubi;
|
||||||
|
in runCommand "mkfs.ubifs" {
|
||||||
|
depsBuildBuild = [ mtdutils ];
|
||||||
|
} ''
|
||||||
|
mkdir tmp
|
||||||
|
tree=${o.bootablerootdir}
|
||||||
|
mkfs.ubifs -x favor_lzo -c ${cfg.maxLEBcount} -m ${cfg.minIOSize} -e ${cfg.logicalEraseBlockSize} -y -r $tree --output $out --squash-uids -o $out
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
126
modules/outputs/ubimage.nix
Normal file
126
modules/outputs/ubimage.nix
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
{
|
||||||
|
config
|
||||||
|
, pkgs
|
||||||
|
, lib
|
||||||
|
, ...
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
inherit (lib) mkIf mkEnableOption mkOption types concatStringsSep;
|
||||||
|
cfg = config.boot.tftp;
|
||||||
|
instructions = pkgs.writeText "env.scr" ''
|
||||||
|
setenv serverip ${cfg.serverip}
|
||||||
|
setenv ipaddr ${cfg.ipaddr}
|
||||||
|
setenv loadaddr ${lib.toHexString cfg.loadAddress}
|
||||||
|
'';
|
||||||
|
in {
|
||||||
|
options.system.outputs = {
|
||||||
|
ubimage = mkOption {
|
||||||
|
type = types.package;
|
||||||
|
description = ''
|
||||||
|
ubimage
|
||||||
|
*******
|
||||||
|
|
||||||
|
This output provides a UBIFS filesystem image and a small U-Boot script
|
||||||
|
to make the manual installation process very slightly simpler. You will
|
||||||
|
need a serial connection and a network connection to a TFTP server
|
||||||
|
containing the filesystem image it creates.
|
||||||
|
|
||||||
|
.. warning:: These steps were tested on a Belkin RT3200 (also known as
|
||||||
|
Linksys E8450). Other devices may be set up differently,
|
||||||
|
so use them as inspiration and don't just paste them
|
||||||
|
blindly.
|
||||||
|
|
||||||
|
1) determine which MTD device is being used for UBI, and the partition name:
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
uboot> ubi part
|
||||||
|
Device 0: ubi0, MTD partition ubi
|
||||||
|
|
||||||
|
In this case the important value is ``ubi0``
|
||||||
|
|
||||||
|
2) list the available volumes and create a new one on which to install Liminix
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
uboot> ubi info l
|
||||||
|
[ copious output scrolls past ]
|
||||||
|
|
||||||
|
Expect there to be existing volumes and for some or all of them to be
|
||||||
|
important. Unless you know what you're doing, don't remove anything
|
||||||
|
whose name suggests it's related to uboot, or any kind of backup or
|
||||||
|
recovery partition. To see how much space is free:
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
uboot> ubi info
|
||||||
|
[ ... ]
|
||||||
|
UBI: available PEBs: 823
|
||||||
|
|
||||||
|
Now we can make our new root volume
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
uboot> ubi create liminix -
|
||||||
|
|
||||||
|
3) transfer the root filesystem from the build system and write it
|
||||||
|
to the new volume. Paste the environment variable settings from
|
||||||
|
:file:`result/env.scr` into U-Boot, then run
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
uboot> tftpboot ''${loadaddr} result/rootfs
|
||||||
|
uboot> ubi write ''${loadaddr} liminix $filesize
|
||||||
|
|
||||||
|
Now we have the root filesystem installed on the device. You
|
||||||
|
can even mount it and poke around using ``ubifsmount ubi0:liminix;
|
||||||
|
ubifsls /``
|
||||||
|
|
||||||
|
4) optional: before you configure the device to boot into Liminix
|
||||||
|
automatically, you can try booting it by hand to see if it works:
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
uboot> ubifsmount ubi0:liminix
|
||||||
|
uboot> ubifsload ''${loadaddr} boot/uimage
|
||||||
|
uboot> bootm ''${loadaddr}
|
||||||
|
|
||||||
|
Once you've done this and you're happy with it, reset the device to
|
||||||
|
U-Boot. You don't need to recreate the volume but you do need to
|
||||||
|
repeat step 3.
|
||||||
|
|
||||||
|
5) Instructions for configuring autoboot are likely to be very
|
||||||
|
device-dependent. On the Linksys E8450/Belkin RT3200, the environment
|
||||||
|
variable `boot_production` governs what happens on a normal boot, so
|
||||||
|
you could do
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
uboot> setenv boot_production 'led $bootled_pwr on ; ubifsmount ubi0:liminix; ubifsload ''${loadaddr} boot/uimage; bootm ''${loadaddr}'
|
||||||
|
|
||||||
|
On other devices, some detective work may be needed. Try running
|
||||||
|
`printenv` and look for likely commands, try looking at the existing
|
||||||
|
boot process, maybe even try looking for documentation for that device.
|
||||||
|
|
||||||
|
6) Now you can reboot the device into Liminix
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
uboot> reset
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkIf (config.rootfsType == "ubifs") {
|
||||||
|
system.outputs = {
|
||||||
|
ubimage =
|
||||||
|
let o = config.system.outputs; in
|
||||||
|
pkgs.runCommand "ubimage" {} ''
|
||||||
|
mkdir $out
|
||||||
|
cd $out
|
||||||
|
ln -s ${o.rootfs} rootfs
|
||||||
|
ln -s ${instructions} env.scr
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
91
modules/outputs/ubivolume.nix
Normal file
91
modules/outputs/ubivolume.nix
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
{
|
||||||
|
config
|
||||||
|
, pkgs
|
||||||
|
, lib
|
||||||
|
, ...
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
inherit (pkgs) liminix;
|
||||||
|
inherit (lib) mkIf mkOption types concatStringsSep optionalString;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
./initramfs.nix
|
||||||
|
./ubifs.nix
|
||||||
|
];
|
||||||
|
|
||||||
|
options.hardware.ubi = {
|
||||||
|
minIOSize = mkOption { type = types.str; };
|
||||||
|
eraseBlockSize = mkOption { type = types.str; }; # LEB
|
||||||
|
maxLEBcount = mkOption { type = types.str; }; # LEB
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkIf (config.rootfsType == "ubifs") {
|
||||||
|
kernel.config = {
|
||||||
|
MTD_UBI="y";
|
||||||
|
|
||||||
|
UBIFS_FS = "y";
|
||||||
|
UBIFS_FS_SECURITY = "n";
|
||||||
|
};
|
||||||
|
boot.initramfs.enable = true;
|
||||||
|
|
||||||
|
system.outputs.rootfs =
|
||||||
|
let
|
||||||
|
inherit (pkgs.pkgsBuildBuild) runCommand;
|
||||||
|
ubiVolume = ({ name, volumeId, image, flags ? [] }:
|
||||||
|
''
|
||||||
|
[${name}]
|
||||||
|
mode=ubi
|
||||||
|
vol_id=${toString volumeId}
|
||||||
|
vol_type=dynamic
|
||||||
|
vol_name=${name}
|
||||||
|
vol_alignment=1
|
||||||
|
${optionalString (image != null) ''
|
||||||
|
image=${image}
|
||||||
|
''}
|
||||||
|
${optionalString (image == null) ''
|
||||||
|
vol_size=1MiB
|
||||||
|
''}
|
||||||
|
${optionalString (flags != []) ''
|
||||||
|
vol_flags=${concatStringsSep "," flags}
|
||||||
|
''}
|
||||||
|
'');
|
||||||
|
|
||||||
|
ubiImage = (volumes:
|
||||||
|
let
|
||||||
|
ubinizeConfig = pkgs.writeText "ubinize.conf" (concatStringsSep "\n" volumes);
|
||||||
|
inherit (pkgs.pkgsBuildBuild) mtdutils;
|
||||||
|
in
|
||||||
|
runCommand "ubinize" {
|
||||||
|
depsBuildBuild = [ mtdutils ];
|
||||||
|
# block size := 128kb
|
||||||
|
# page size := 2048
|
||||||
|
# ubninize opts := -E 5
|
||||||
|
} ''
|
||||||
|
ubinize -Q "$SOURCE_DATE_EPOCH" -o $out \
|
||||||
|
-p ${config.hardware.ubi.physicalEraseBlockSize} -m ${config.hardware.ubi.minIOSize} \
|
||||||
|
-e ${config.hardware.ubi.logicalEraseBlockSize} \
|
||||||
|
${ubinizeConfig}
|
||||||
|
'');
|
||||||
|
|
||||||
|
ubiDisk = ({ initramfs }:
|
||||||
|
let
|
||||||
|
initramfsUbi = ubiVolume {
|
||||||
|
name = "rootfs";
|
||||||
|
volumeId = 0;
|
||||||
|
image = initramfs;
|
||||||
|
flags = [ "autoresize" ];
|
||||||
|
};
|
||||||
|
in
|
||||||
|
ubiImage [
|
||||||
|
initramfsUbi
|
||||||
|
]);
|
||||||
|
|
||||||
|
disk = ubiDisk {
|
||||||
|
initramfs = config.system.outputs.rootubifs; # liminix.builders.squashfs config.filesystem.contents; # # assert this is a proper FIT.
|
||||||
|
};
|
||||||
|
|
||||||
|
in
|
||||||
|
disk;
|
||||||
|
};
|
||||||
|
}
|
73
modules/outputs/vmroot.nix
Normal file
73
modules/outputs/vmroot.nix
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
{
|
||||||
|
config
|
||||||
|
, pkgs
|
||||||
|
, lib
|
||||||
|
, ...
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
inherit (lib) mkOption types concatStringsSep;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options = {
|
||||||
|
system.outputs = {
|
||||||
|
vmroot = mkOption {
|
||||||
|
type = types.package;
|
||||||
|
description = ''
|
||||||
|
vmroot
|
||||||
|
******
|
||||||
|
|
||||||
|
This target is for use with the qemu, qemu-aarch64, qemu-armv7l
|
||||||
|
devices. It generates an executable :file:`run.sh` which
|
||||||
|
invokes QEMU. It connects the Liminix
|
||||||
|
serial console and the `QEMU monitor <https://www.qemu.org/docs/master/system/monitor.html>`_
|
||||||
|
to stdin/stdout. Use ^P (not ^A) to switch between monitor and
|
||||||
|
stdio.
|
||||||
|
|
||||||
|
If you call :command:`run.sh` with ``--background
|
||||||
|
/path/to/some/directory`` as the first parameter, it will
|
||||||
|
fork into the background and open Unix sockets in that
|
||||||
|
directory for console and monitor. Use :command:`nix-shell
|
||||||
|
--run connect-vm` to connect to either of these sockets, and
|
||||||
|
^O to disconnect.
|
||||||
|
|
||||||
|
Liminix VMs are networked using QEMU socket networking. The
|
||||||
|
default behaviour is to connect
|
||||||
|
|
||||||
|
* multicast 230.0.0.1:1234 ("access") to eth0
|
||||||
|
* multicast 230.0.0.1:1235 ("lan") to eth1
|
||||||
|
|
||||||
|
Refer to :ref:`border-network-gateway` for details of how to
|
||||||
|
start an emulated upstream on the "access" network that
|
||||||
|
your Liminix device can talk to.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
config = {
|
||||||
|
system.outputs = rec {
|
||||||
|
vmroot =
|
||||||
|
let
|
||||||
|
inherit (config.system.outputs) rootfs kernel manifest;
|
||||||
|
cmdline = builtins.toJSON (concatStringsSep " " config.boot.commandLine);
|
||||||
|
makeBootableImage = pkgs.runCommandCC "objcopy" {}
|
||||||
|
(if pkgs.stdenv.hostPlatform.isAarch
|
||||||
|
then "${pkgs.stdenv.cc.targetPrefix}objcopy -O binary -R .comment -S ${kernel} $out"
|
||||||
|
else "cp ${kernel} $out");
|
||||||
|
phram_address = lib.toHexString (config.hardware.ram.startAddress + 256 * 1024 * 1024);
|
||||||
|
in pkgs.runCommand "vmroot" {} ''
|
||||||
|
mkdir $out
|
||||||
|
cd $out
|
||||||
|
ln -s ${rootfs} rootfs
|
||||||
|
ln -s ${kernel} vmlinux
|
||||||
|
ln -s ${manifest} manifest
|
||||||
|
ln -s ${kernel.headers} build
|
||||||
|
echo ${cmdline} > commandline
|
||||||
|
cat > run.sh << EOF
|
||||||
|
#!${pkgs.runtimeShell}
|
||||||
|
${pkgs.pkgsBuildBuild.run-liminix-vm}/bin/run-liminix-vm --command-line ${cmdline} --arch ${pkgs.stdenv.hostPlatform.qemuArch} --phram-address 0x${phram_address} \$* ${makeBootableImage} ${config.system.outputs.rootfs}
|
||||||
|
EOF
|
||||||
|
chmod +x run.sh
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
71
modules/outputs/zyxel-nwa-fit.nix
Normal file
71
modules/outputs/zyxel-nwa-fit.nix
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
{
|
||||||
|
config
|
||||||
|
, pkgs
|
||||||
|
, lib
|
||||||
|
, ...
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
inherit (lib) mkIf mkEnableOption mkOption types concatStringsSep;
|
||||||
|
models = "6b e1 6f e1 ff ff ff ff ff ff";
|
||||||
|
in {
|
||||||
|
options.system.outputs = {
|
||||||
|
zyxel-nwa-fit = mkOption {
|
||||||
|
type = types.package;
|
||||||
|
description = ''
|
||||||
|
zyxel-nwa-fit
|
||||||
|
*************
|
||||||
|
|
||||||
|
This output provides a FIT image for Zyxel NWA series
|
||||||
|
containing a kernel image and an UBIFS rootfs.
|
||||||
|
|
||||||
|
It can usually be used as a factory image to install Liminix
|
||||||
|
on a system with pre-existing firmware and OS.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
imports = [
|
||||||
|
./ubivolume.nix
|
||||||
|
];
|
||||||
|
|
||||||
|
config = mkIf (config.rootfsType == "ubifs") {
|
||||||
|
|
||||||
|
system.outputs.zyxel-nwa-fit =
|
||||||
|
let
|
||||||
|
o = config.system.outputs;
|
||||||
|
# 8129kb padding.
|
||||||
|
paddedKernel = pkgs.runCommand "padded-kernel" {} ''
|
||||||
|
cp --no-preserve=mode ${o.uimage} $out
|
||||||
|
dd if=/dev/zero of=$out bs=1 count=1 seek=8388607
|
||||||
|
'';
|
||||||
|
firmwareImage = pkgs.runCommand "firmware-image" {} ''
|
||||||
|
cat ${paddedKernel} ${o.rootfs} > $out
|
||||||
|
'';
|
||||||
|
dts = pkgs.writeText "image.its" ''
|
||||||
|
/dts-v1/;
|
||||||
|
|
||||||
|
/ {
|
||||||
|
description = "Zyxel FIT (Flattened Image Tree)";
|
||||||
|
compat-models = [${models}];
|
||||||
|
#address-cells = <1>;
|
||||||
|
|
||||||
|
images {
|
||||||
|
firmware {
|
||||||
|
data = /incbin/("${firmwareImage}");
|
||||||
|
type = "firmware";
|
||||||
|
compression = "none";
|
||||||
|
hash@1 {
|
||||||
|
algo = "sha1";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
'';
|
||||||
|
in
|
||||||
|
pkgs.runCommand "zyxel-nwa-fit-${config.boot.imageType}" {
|
||||||
|
nativeBuildInputs = [ pkgs.pkgsBuildBuild.ubootTools pkgs.pkgsBuildBuild.dtc ];
|
||||||
|
} ''
|
||||||
|
mkimage -f ${dts} $out
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
}
|
100
modules/profiles/wap.nix
Normal file
100
modules/profiles/wap.nix
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
{
|
||||||
|
config,
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}: let
|
||||||
|
inherit (pkgs) liminix;
|
||||||
|
inherit (lib) mkEnableOption mkOption types isDerivation hasAttr ;
|
||||||
|
|
||||||
|
inherit (pkgs.liminix.services) oneshot longrun bundle target;
|
||||||
|
inherit (pkgs.pseudofile) dir symlink;
|
||||||
|
inherit (pkgs) serviceFns;
|
||||||
|
svc = config.system.service;
|
||||||
|
cfg = config.profile.wap;
|
||||||
|
|
||||||
|
hostaps =
|
||||||
|
let
|
||||||
|
defaults = {
|
||||||
|
auth_algs = 1; # 1=wpa2, 2=wep, 3=both
|
||||||
|
wpa = 2; # 1=wpa, 2=wpa2, 3=both
|
||||||
|
wpa_key_mgmt = "WPA-PSK";
|
||||||
|
wpa_pairwise = "TKIP CCMP"; # auth for wpa (may not need this?)
|
||||||
|
rsn_pairwise = "CCMP"; # auth for wpa2
|
||||||
|
};
|
||||||
|
in lib.mapAttrs'
|
||||||
|
(name : value :
|
||||||
|
let
|
||||||
|
attrs = defaults // { ssid = name; } // value;
|
||||||
|
in lib.nameValuePair
|
||||||
|
"hostap-${name}"
|
||||||
|
(svc.hostapd.build {
|
||||||
|
interface = attrs.interface;
|
||||||
|
params = lib.filterAttrs (k: v: k != "interface") attrs;
|
||||||
|
}))
|
||||||
|
cfg.wireless.networks;
|
||||||
|
|
||||||
|
in {
|
||||||
|
imports = [
|
||||||
|
../wlan.nix
|
||||||
|
../network
|
||||||
|
../hostapd
|
||||||
|
../bridge
|
||||||
|
../ssh
|
||||||
|
{ config.services = hostaps; }
|
||||||
|
];
|
||||||
|
|
||||||
|
options.profile.wap = {
|
||||||
|
interfaces = mkOption {
|
||||||
|
type = types.listOf liminix.lib.types.interface;
|
||||||
|
default = [];
|
||||||
|
};
|
||||||
|
wireless = mkOption {
|
||||||
|
type = types.attrsOf types.anything;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
config = {
|
||||||
|
services.sshd = svc.ssh.build {};
|
||||||
|
|
||||||
|
services.int = svc.bridge.primary.build {
|
||||||
|
ifname = "int";
|
||||||
|
};
|
||||||
|
|
||||||
|
services.bridge = svc.bridge.members.build {
|
||||||
|
primary = config.services.int;
|
||||||
|
members = cfg.interfaces;
|
||||||
|
};
|
||||||
|
|
||||||
|
services.dhcpc = svc.network.dhcp.client.build {
|
||||||
|
interface = config.services.int;
|
||||||
|
dependencies = [ config.services.hostname ];
|
||||||
|
};
|
||||||
|
|
||||||
|
services.defaultroute4 = svc.network.route.build {
|
||||||
|
via = "$(output ${config.services.dhcpc} router)";
|
||||||
|
target = "default";
|
||||||
|
dependencies = [config.services.dhcpc];
|
||||||
|
};
|
||||||
|
|
||||||
|
services.resolvconf = oneshot rec {
|
||||||
|
dependencies = [ config.services.dhcpc ];
|
||||||
|
name = "resolvconf";
|
||||||
|
# CHECK: https://udhcp.busybox.net/README.udhcpc says
|
||||||
|
# 'A list of DNS server' but doesn't say what separates the
|
||||||
|
# list members. Assuming it's a space or other IFS character
|
||||||
|
up = ''
|
||||||
|
. ${serviceFns}
|
||||||
|
( in_outputs ${name}
|
||||||
|
for i in $(output ${config.services.dhcpc} dns); do
|
||||||
|
echo "nameserver $i" > resolv.conf
|
||||||
|
done
|
||||||
|
)
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
filesystem = dir {
|
||||||
|
etc = dir {
|
||||||
|
"resolv.conf" = symlink "${config.services.resolvconf}/.outputs/resolv.conf";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
@ -55,6 +55,9 @@ let
|
|||||||
run = {
|
run = {
|
||||||
file = ''
|
file = ''
|
||||||
#!${execline}/bin/execlineb -P
|
#!${execline}/bin/execlineb -P
|
||||||
|
importas PATH PATH
|
||||||
|
export PATH ${s6}/bin:''${PATH}
|
||||||
|
foreground { echo path is ''${PATH} }
|
||||||
${s6-linux-init}/bin/s6-linux-init-shutdownd -c "/etc/s6-linux-init/current" -g 3000
|
${s6-linux-init}/bin/s6-linux-init-shutdownd -c "/etc/s6-linux-init/current" -g 3000
|
||||||
'';
|
'';
|
||||||
mode = "0755";
|
mode = "0755";
|
||||||
@ -78,26 +81,44 @@ let
|
|||||||
};
|
};
|
||||||
getty = dir {
|
getty = dir {
|
||||||
run = {
|
run = {
|
||||||
|
# We can't run a useful shell on /dev/console because
|
||||||
|
# /dev/console is not allowed to be the controlling
|
||||||
|
# tty of any process, which means ^C ^Z etc don't work.
|
||||||
|
# So we work out what the *actual* console device is
|
||||||
|
# using sysfs and open our shell there instead.
|
||||||
file = ''
|
file = ''
|
||||||
#!${execline}/bin/execlineb -P
|
#!${execline}/bin/execlineb -P
|
||||||
/bin/getty -l /bin/login 115200 /dev/console
|
${execline}/bin/cd /
|
||||||
'';
|
redirfd -r 0 /sys/devices/virtual/tty/console/active
|
||||||
|
withstdinas CONSOLETTY
|
||||||
|
importas CONSOLETTY CONSOLETTY
|
||||||
|
redirfd -w 2 /dev/''${CONSOLETTY}
|
||||||
|
fdmove -c 1 2
|
||||||
|
redirfd -r 0 /dev/''${CONSOLETTY}
|
||||||
|
/bin/ash -l
|
||||||
|
'';
|
||||||
mode = "0755";
|
mode = "0755";
|
||||||
};
|
};
|
||||||
|
down-signal = {
|
||||||
|
file = "HUP\n";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
".s6-svscan" =
|
".s6-svscan" =
|
||||||
let
|
let
|
||||||
|
openConsole = ''
|
||||||
|
#!${execline}/bin/execlineb -P
|
||||||
|
${execline}/bin/redirfd -w 2 /dev/console
|
||||||
|
${execline}/bin/fdmove -c 1 2
|
||||||
|
'';
|
||||||
quit = message: ''
|
quit = message: ''
|
||||||
#!${execline}/bin/execlineb -P
|
${openConsole}
|
||||||
${execline}/bin/redirfd -w 2 /dev/console
|
${execline}/bin/foreground { ${s6-linux-init}/bin/s6-linux-init-echo -- ${message} }
|
||||||
${execline}/bin/fdmove -c 1 2
|
${s6-linux-init}/bin/s6-linux-init-hpr -fr
|
||||||
${execline}/bin/foreground { ${s6-linux-init}/bin/s6-linux-init-echo -- ${message} }
|
'';
|
||||||
${s6-linux-init}/bin/s6-linux-init-hpr -fr
|
|
||||||
'';
|
|
||||||
shutdown = action: ''
|
shutdown = action: ''
|
||||||
#!${execline}/bin/execlineb -P
|
#!${execline}/bin/execlineb -P
|
||||||
${s6-linux-init}/bin/s6-linux-init-hpr -a #{action} -- now
|
${s6-linux-init}/bin/s6-linux-init-shutdown -a #{action} -- now
|
||||||
'';
|
'';
|
||||||
empty = "#!${execline}/bin/execlineb -P\n";
|
empty = "#!${execline}/bin/execlineb -P\n";
|
||||||
in dir {
|
in dir {
|
||||||
crash = {
|
crash = {
|
||||||
@ -105,7 +126,13 @@ let
|
|||||||
mode = "0755";
|
mode = "0755";
|
||||||
};
|
};
|
||||||
finish = {
|
finish = {
|
||||||
file = quit "s6-svscan exited. Rebooting.";
|
file = ''
|
||||||
|
${openConsole}
|
||||||
|
ifelse { test -x /run/maintenance/exec } { /run/maintenance/exec }
|
||||||
|
foreground { echo "s6-svscan exited. Rebooting." }
|
||||||
|
wait { }
|
||||||
|
${s6-linux-init}/bin/s6-linux-init-hpr -fr
|
||||||
|
'';
|
||||||
mode = "0755";
|
mode = "0755";
|
||||||
};
|
};
|
||||||
SIGINT = {
|
SIGINT = {
|
||||||
@ -141,7 +168,6 @@ let
|
|||||||
};
|
};
|
||||||
in {
|
in {
|
||||||
config = {
|
config = {
|
||||||
programs.busybox.applets = [ "login" "getty" ];
|
|
||||||
filesystem = dir {
|
filesystem = dir {
|
||||||
etc = dir {
|
etc = dir {
|
||||||
s6-rc = dir {
|
s6-rc = dir {
|
||||||
|
@ -17,12 +17,20 @@ shift
|
|||||||
|
|
||||||
mount -t proc none /proc
|
mount -t proc none /proc
|
||||||
mount -t sysfs none /sys
|
mount -t sysfs none /sys
|
||||||
|
mount -t tmpfs none /tmp
|
||||||
# s6-linux-init mounts /dev before this script is called
|
# s6-linux-init mounts /dev before this script is called
|
||||||
mkdir /dev/pts
|
mkdir /dev/pts
|
||||||
mount -t devpts none /dev/pts
|
mount -t devpts none /dev/pts
|
||||||
|
|
||||||
mkdir -m 0751 /run/service-state
|
mkdir -m 0751 -p /run/services/outputs
|
||||||
chgrp system /run/service-state
|
chgrp system /run/services/outputs
|
||||||
|
|
||||||
|
if test -d /persist; then
|
||||||
|
mkdir -m 0751 -p /persist/services/state
|
||||||
|
(cd /run/services && ln -s ../../persist/services/state .)
|
||||||
|
else
|
||||||
|
mkdir -m 0751 -p /run/services/state
|
||||||
|
fi
|
||||||
|
|
||||||
### If your services are managed by s6-rc:
|
### If your services are managed by s6-rc:
|
||||||
### (replace /run/service with your scandir)
|
### (replace /run/service with your scandir)
|
||||||
|
@ -1,18 +1,22 @@
|
|||||||
#!/bin/sh -e
|
#!/bin/sh -e
|
||||||
|
|
||||||
### Things to do *right before* the machine gets rebooted or
|
## s6-linux-init-shutdownd never tells s6-svscan to exit, so if
|
||||||
### powered off, at the very end of the shutdown sequence,
|
## you're running s6-linux-init, it's normal that your
|
||||||
### when all the filesystems are unmounted.
|
## .s6-svscan/finish script is not executed.
|
||||||
|
|
||||||
### This is a last resort hook; normally nothing should be
|
## The place where you want to hack things is /etc/rc.shutdown.final,
|
||||||
### done here (your rc.shutdown script should have taken care
|
## which is run by the stage 4 script right before the hard reboot.
|
||||||
### of everything) and you should leave this script empty.
|
## So you can do dirty stuff [...] which should clean up the
|
||||||
|
## s6-supervise and the foreground, and give control to
|
||||||
|
## .s6-svscan/finish.
|
||||||
|
|
||||||
### Some distributions, however, may need to perform some
|
## -- Laurent Bercot on skaware mailing list,
|
||||||
### actions after unmounting the filesystems: typically if
|
## https://skarnet.org/lists/skaware/1913.html
|
||||||
### an additional teardown action is required on a filesystem
|
|
||||||
### after unmounting it, or if the system needs to be
|
|
||||||
### pivot_rooted before it can be shut down, etc.
|
|
||||||
|
|
||||||
### Those are all exceptional cases. If you don't know for
|
exec >/dev/console 2>&1
|
||||||
### certain that you need to do something here, you don't.
|
|
||||||
|
# down, exit supervisor, wait, stay down
|
||||||
|
s6-svc -dxwD /run/service/s6-linux-init-shutdownd
|
||||||
|
# HUP, exit supervisor, wait, down
|
||||||
|
s6-svc -hxwd /run/service/s6-svscan-log
|
||||||
|
s6-svscanctl -b /run/service # abort
|
||||||
|
19
modules/schnapps/default.nix
Normal file
19
modules/schnapps/default.nix
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
{ config, pkgs, lib, ... } :
|
||||||
|
{
|
||||||
|
config = {
|
||||||
|
programs.busybox = {
|
||||||
|
options = {
|
||||||
|
# schnapps is a shell script that needs
|
||||||
|
# [ command
|
||||||
|
# find -maxdepth -mindepth
|
||||||
|
# head -c
|
||||||
|
# echo -n
|
||||||
|
ASH_TEST = "y";
|
||||||
|
FEATURE_FIND_MAXDEPTH = "y";
|
||||||
|
FEATURE_FANCY_HEAD = "y";
|
||||||
|
FEATURE_FANCY_ECHO = "y";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
defaultProfile.packages = [ pkgs.schnapps ] ;
|
||||||
|
};
|
||||||
|
}
|
@ -29,15 +29,12 @@ let
|
|||||||
in
|
in
|
||||||
longrun {
|
longrun {
|
||||||
name = "sshd";
|
name = "sshd";
|
||||||
|
# we need /run/dropbear to point to hostkey storage, as that
|
||||||
|
# pathname is hardcoded into the binary.
|
||||||
# env -i clears the environment so we don't pass anything weird to
|
# env -i clears the environment so we don't pass anything weird to
|
||||||
# ssh sessions
|
# ssh sessions
|
||||||
run = ''
|
run = ''
|
||||||
if test -d /persist; then
|
ln -s $(mkstate dropbear) /run
|
||||||
mkdir -p /persist/secrets/dropbear
|
|
||||||
ln -s /persist/secrets/dropbear /run
|
|
||||||
else
|
|
||||||
mkdir -p /run/dropbear
|
|
||||||
fi
|
|
||||||
. /etc/profile # sets PATH but do we need this? it's the same file as ashrc
|
. /etc/profile # sets PATH but do we need this? it's the same file as ashrc
|
||||||
exec env -i ENV=/etc/ashrc PATH=$PATH ${dropbear}/bin/dropbear ${concatStringsSep " " options}
|
exec env -i ENV=/etc/ashrc PATH=$PATH ${dropbear}/bin/dropbear ${concatStringsSep " " options}
|
||||||
'';
|
'';
|
||||||
|
@ -1,11 +0,0 @@
|
|||||||
{
|
|
||||||
# "standard" modules that aren't fundamentally required,
|
|
||||||
# but are probably useful in most common workflows and
|
|
||||||
# you should have to opt out of instead of into
|
|
||||||
imports = [
|
|
||||||
./tftpboot.nix
|
|
||||||
./kexecboot.nix
|
|
||||||
./flashimage.nix
|
|
||||||
./jffs2.nix
|
|
||||||
];
|
|
||||||
}
|
|
@ -1,70 +0,0 @@
|
|||||||
{
|
|
||||||
config
|
|
||||||
, pkgs
|
|
||||||
, lib
|
|
||||||
, ...
|
|
||||||
}:
|
|
||||||
let
|
|
||||||
inherit (lib) mkOption types concatStringsSep;
|
|
||||||
cfg = config.boot.tftp;
|
|
||||||
in {
|
|
||||||
imports = [ ./ramdisk.nix ];
|
|
||||||
options.boot.tftp.freeSpaceBytes = mkOption {
|
|
||||||
type = types.int;
|
|
||||||
default = 0;
|
|
||||||
};
|
|
||||||
options.system.outputs = {
|
|
||||||
tftpboot = mkOption {
|
|
||||||
type = types.package;
|
|
||||||
description = ''
|
|
||||||
Directory containing files needed for TFTP booting
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
boot-scr = mkOption {
|
|
||||||
type = types.package;
|
|
||||||
description = ''
|
|
||||||
U-Boot commands to load and boot a kernel and rootfs over TFTP.
|
|
||||||
Copy-paste into the device boot monitor
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
|
||||||
config = {
|
|
||||||
boot.ramdisk.enable = true;
|
|
||||||
|
|
||||||
system.outputs = rec {
|
|
||||||
tftpboot =
|
|
||||||
let o = config.system.outputs; in
|
|
||||||
pkgs.runCommand "tftpboot" {} ''
|
|
||||||
mkdir $out
|
|
||||||
cd $out
|
|
||||||
ln -s ${o.rootfs} rootfs
|
|
||||||
ln -s ${o.kernel} vmlinux
|
|
||||||
ln -s ${o.manifest} manifest
|
|
||||||
ln -s ${o.kernel.headers} build
|
|
||||||
ln -s ${o.uimage} uimage
|
|
||||||
ln -s ${o.boot-scr} boot.scr
|
|
||||||
'';
|
|
||||||
|
|
||||||
boot-scr =
|
|
||||||
let
|
|
||||||
inherit (pkgs.lib.trivial) toHexString;
|
|
||||||
o = config.system.outputs;
|
|
||||||
in
|
|
||||||
pkgs.buildPackages.runCommand "boot-scr" {} ''
|
|
||||||
uimageSize=$(($(stat -L -c %s ${o.uimage}) + 0x1000 &(~0xfff)))
|
|
||||||
rootfsStart=0x$(printf %x $((${cfg.loadAddress} + 0x100000 + $uimageSize)))
|
|
||||||
rootfsBytes=$(($(stat -L -c %s ${o.rootfs}) + 0x100000 &(~0xfffff)))
|
|
||||||
rootfsBytes=$(($rootfsBytes + ${toString cfg.freeSpaceBytes} ))
|
|
||||||
cmd="mtdparts=phram0:''${rootfsMb}M(rootfs) phram.phram=phram0,''${rootfsStart},''${rootfsBytes},${config.hardware.flash.eraseBlockSize} memmap=''${rootfsBytes}\$''${rootfsStart} root=/dev/mtdblock0";
|
|
||||||
|
|
||||||
cat > $out << EOF
|
|
||||||
setenv serverip ${cfg.serverip}
|
|
||||||
setenv ipaddr ${cfg.ipaddr}
|
|
||||||
setenv bootargs 'liminix $cmd'
|
|
||||||
tftp 0x$(printf %x ${cfg.loadAddress}) result/uimage ; tftp 0x$(printf %x $rootfsStart) result/rootfs
|
|
||||||
bootm 0x$(printf %x ${cfg.loadAddress})
|
|
||||||
EOF
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
31
modules/usb.nix
Normal file
31
modules/usb.nix
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
# support for USB block devices and the common filesystems
|
||||||
|
# they're likely to provide
|
||||||
|
|
||||||
|
{lib, config, ... }:
|
||||||
|
{
|
||||||
|
kernel = {
|
||||||
|
config = {
|
||||||
|
USB = "y";
|
||||||
|
USB_EHCI_HCD = "y";
|
||||||
|
USB_EHCI_HCD_PLATFORM = "y";
|
||||||
|
USB_OHCI_HCD = "y";
|
||||||
|
USB_OHCI_HCD_PLATFORM = "y";
|
||||||
|
USB_SUPPORT = "y";
|
||||||
|
USB_COMMON = "y";
|
||||||
|
USB_STORAGE = "y";
|
||||||
|
USB_STORAGE_DEBUG = "n";
|
||||||
|
USB_UAS = "y";
|
||||||
|
USB_ANNOUNCE_NEW_DEVICES = "y";
|
||||||
|
SCSI = "y";
|
||||||
|
BLK_DEV_SD = "y";
|
||||||
|
USB_PRINTER = "y";
|
||||||
|
MSDOS_PARTITION = "y";
|
||||||
|
EFI_PARTITION = "y";
|
||||||
|
EXT4_FS = "y";
|
||||||
|
EXT4_USE_FOR_EXT2 = "y";
|
||||||
|
FS_ENCRYPTION = "y";
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
@ -46,6 +46,14 @@ in {
|
|||||||
CRYPTO_SHA1 = "y";
|
CRYPTO_SHA1 = "y";
|
||||||
ENCRYPTED_KEYS = "y";
|
ENCRYPTED_KEYS = "y";
|
||||||
KEYS = "y";
|
KEYS = "y";
|
||||||
|
|
||||||
|
WLAN = "y";
|
||||||
|
CFG80211 = "m";
|
||||||
|
MAC80211 = "m";
|
||||||
|
EXPERT = "y";
|
||||||
|
CFG80211_CERTIFICATION_ONUS = "y";
|
||||||
|
CFG80211_REQUIRE_SIGNED_REGDB = "n"; # depends on ONUS
|
||||||
|
CFG80211_CRDA_SUPPORT = "n";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
60
modules/zyxel-dual-image/default.nix
Normal file
60
modules/zyxel-dual-image/default.nix
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
## Boot blessing via Zyxel
|
||||||
|
## =======================
|
||||||
|
## Boot blessing is the process to bless a particular boot configuration
|
||||||
|
## It is commonly encountered in devices with redundant partitions
|
||||||
|
## for automatic recovery of broken upgrades.
|
||||||
|
## This is also known as A/B schemas, where A represents the primary partition
|
||||||
|
## and B the secondary partition used for recovery.
|
||||||
|
## To use boot blessing on Liminix, you need to have the support of
|
||||||
|
## your bootloader to help you boot on the secondary partition in case of
|
||||||
|
## failure on the primary partition. The exact details are specifics to your device.
|
||||||
|
## See the Zyxel NWA50AX for an example.
|
||||||
|
## TODO: generalize this module.
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
let
|
||||||
|
inherit (lib) mkOption types;
|
||||||
|
inherit (pkgs) liminix;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.boot.zyxel-dual-image = mkOption {
|
||||||
|
type = liminix.lib.types.serviceDefn;
|
||||||
|
};
|
||||||
|
|
||||||
|
config.boot.zyxel-dual-image = liminix.callService ./service.nix {
|
||||||
|
ensureActiveImage = mkOption {
|
||||||
|
type = types.enum [ "primary" "secondary" ];
|
||||||
|
default = "primary";
|
||||||
|
description = ''At boot, ensure that the active image is the one specified.
|
||||||
|
|
||||||
|
If you are already on a broken image, you need to manually boot
|
||||||
|
into the right image via `atgo <image index>` in U-Boot.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
kernelCommandLineSource = mkOption {
|
||||||
|
type = types.enum [ "/proc/cmdline" "/proc/device-tree/chosen/bootargs" ];
|
||||||
|
default = "/proc/device-tree/chosen/bootargs";
|
||||||
|
description = ''Kernel command line arguments source file.
|
||||||
|
On MIPS, Liminix embeds the kernel command line in /proc/device-tree/chosen/bootargs-override.
|
||||||
|
|
||||||
|
In this instance, it does not get concatenated with `/proc/cmdline`.
|
||||||
|
Therefore you may prefer to source it from another place, like `/proc/device-tree/chosen/bootargs`.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
primaryMtdPartition = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
description = "Primary MTD partition device node, i.e. for image 0.";
|
||||||
|
};
|
||||||
|
|
||||||
|
secondaryMtdPartition = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
description = "Secondary MTD partition device node, i.e. for image 1.";
|
||||||
|
};
|
||||||
|
|
||||||
|
bootConfigurationMtdPartition = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
description = "Boot configuration MTD partition device node.";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
33
modules/zyxel-dual-image/service.nix
Normal file
33
modules/zyxel-dual-image/service.nix
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
{
|
||||||
|
liminix
|
||||||
|
, lib
|
||||||
|
, zyxel-bootconfig
|
||||||
|
}:
|
||||||
|
{ ensureActiveImage, primaryMtdPartition, secondaryMtdPartition, bootConfigurationMtdPartition, kernelCommandLineSource }:
|
||||||
|
let
|
||||||
|
inherit (liminix.services) oneshot;
|
||||||
|
activeImageIndex = if ensureActiveImage == "primary" then 0 else 1;
|
||||||
|
in oneshot {
|
||||||
|
name = "zyxel-boot-configure";
|
||||||
|
up = ''
|
||||||
|
set -- $(cat /proc/device-tree/chosen/bootargs)
|
||||||
|
for x in "$@"; do
|
||||||
|
case "$x" in
|
||||||
|
bootImage=*)
|
||||||
|
BOOT_IMAGE="''${x#bootImage=}"
|
||||||
|
echo "Current boot image is $BOOT_IMAGE."
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
if test -z "$BOOT_IMAGE"; then
|
||||||
|
echo "No valid image was provided in the kernel command line."
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
${lib.getExe zyxel-bootconfig} ${bootConfigurationMtdPartition} set-image-status "$BOOT_IMAGE" valid
|
||||||
|
${lib.getExe zyxel-bootconfig} ${bootConfigurationMtdPartition} set-active-image ${toString activeImageIndex}
|
||||||
|
|
||||||
|
echo "Active image is now ${ensureActiveImage}"
|
||||||
|
fi
|
||||||
|
'';
|
||||||
|
}
|
222
overlay.nix
222
overlay.nix
@ -44,19 +44,17 @@ let
|
|||||||
lua = let s = lua_no_readline.override { self = s; }; in s;
|
lua = let s = lua_no_readline.override { self = s; }; in s;
|
||||||
in
|
in
|
||||||
extraPkgs // {
|
extraPkgs // {
|
||||||
mtdutils = prev.mtdutils.overrideAttrs(o: {
|
# liminix library functions
|
||||||
patches = (if o ? patches then o.patches else []) ++ [
|
lim = {
|
||||||
./pkgs/mtdutils/0001-mkfs.jffs2-add-graft-option.patch
|
parseInt = s : (builtins.fromTOML "r=${s}").r;
|
||||||
];
|
};
|
||||||
});
|
|
||||||
|
|
||||||
rsyncSmall =
|
# keep these alphabetical
|
||||||
let r = prev.rsync.overrideAttrs(o: {
|
|
||||||
configureFlags = o.configureFlags ++ [
|
btrfs-progs = prev.btrfs-progs.override {
|
||||||
"--disable-openssl"
|
udevSupport = false;
|
||||||
];
|
udev = null;
|
||||||
});
|
};
|
||||||
in r.override { openssl = null; };
|
|
||||||
|
|
||||||
chrony =
|
chrony =
|
||||||
let chrony' = prev.chrony.overrideAttrs(o: {
|
let chrony' = prev.chrony.overrideAttrs(o: {
|
||||||
@ -79,7 +77,54 @@ extraPkgs // {
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
strace = prev.strace.override { libunwind = null; };
|
|
||||||
|
dnsmasq =
|
||||||
|
let d = prev.dnsmasq.overrideAttrs(o: {
|
||||||
|
preBuild = ''
|
||||||
|
makeFlagsArray=("COPTS=")
|
||||||
|
'';
|
||||||
|
});
|
||||||
|
in d.override {
|
||||||
|
dbusSupport = false;
|
||||||
|
nettle = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
dropbear = prev.dropbear.overrideAttrs (o: {
|
||||||
|
postPatch = ''
|
||||||
|
(echo '#define DSS_PRIV_FILENAME "/run/dropbear/dropbear_dss_host_key"'
|
||||||
|
echo '#define RSA_PRIV_FILENAME "/run/dropbear/dropbear_rsa_host_key"'
|
||||||
|
echo '#define ECDSA_PRIV_FILENAME "/run/dropbear/dropbear_ecdsa_host_key"'
|
||||||
|
echo '#define ED25519_PRIV_FILENAME "/run/dropbear/dropbear_ed25519_host_key"') > localoptions.h
|
||||||
|
'';
|
||||||
|
});
|
||||||
|
|
||||||
|
hostapd =
|
||||||
|
let
|
||||||
|
config = [
|
||||||
|
"CONFIG_DRIVER_NL80211=y"
|
||||||
|
"CONFIG_IAPP=y"
|
||||||
|
"CONFIG_IEEE80211AC=y"
|
||||||
|
"CONFIG_IEEE80211AX=y"
|
||||||
|
"CONFIG_IEEE80211N=y"
|
||||||
|
"CONFIG_IEEE80211W=y"
|
||||||
|
"CONFIG_INTERNAL_LIBTOMMATH=y"
|
||||||
|
"CONFIG_INTERNAL_LIBTOMMATH_FAST=y"
|
||||||
|
"CONFIG_IPV6=y"
|
||||||
|
"CONFIG_LIBNL32=y"
|
||||||
|
"CONFIG_PKCS12=y"
|
||||||
|
"CONFIG_RSN_PREAUTH=y"
|
||||||
|
"CONFIG_TLS=internal"
|
||||||
|
];
|
||||||
|
h = prev.hostapd.overrideAttrs(o: {
|
||||||
|
extraConfig = "";
|
||||||
|
configurePhase = ''
|
||||||
|
cat > hostapd/defconfig <<EOF
|
||||||
|
${builtins.concatStringsSep "\n" config}
|
||||||
|
EOF
|
||||||
|
${o.configurePhase}
|
||||||
|
'';
|
||||||
|
});
|
||||||
|
in h.override { openssl = null; sqlite = null; };
|
||||||
|
|
||||||
kexec-tools-static = prev.kexec-tools.overrideAttrs(o: {
|
kexec-tools-static = prev.kexec-tools.overrideAttrs(o: {
|
||||||
# For kexecboot we copy kexec into a ramdisk on the system being
|
# For kexecboot we copy kexec into a ramdisk on the system being
|
||||||
@ -102,17 +147,11 @@ extraPkgs // {
|
|||||||
luaFull = prev.lua;
|
luaFull = prev.lua;
|
||||||
inherit lua;
|
inherit lua;
|
||||||
|
|
||||||
inherit s6;
|
mtdutils = prev.mtdutils.overrideAttrs(o: {
|
||||||
s6-linux-init = prev.s6-linux-init.override {
|
patches = (if o ? patches then o.patches else []) ++ [
|
||||||
skawarePackages = prev.skawarePackages // {
|
./pkgs/mtdutils/0001-mkfs.jffs2-add-graft-option.patch
|
||||||
inherit s6;
|
];
|
||||||
};
|
});
|
||||||
};
|
|
||||||
s6-rc = prev.s6-rc.override {
|
|
||||||
skawarePackages = prev.skawarePackages // {
|
|
||||||
inherit s6;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
nftables = prev.nftables.overrideAttrs(o: {
|
nftables = prev.nftables.overrideAttrs(o: {
|
||||||
configureFlags = [
|
configureFlags = [
|
||||||
@ -123,53 +162,6 @@ extraPkgs // {
|
|||||||
];
|
];
|
||||||
});
|
});
|
||||||
|
|
||||||
dnsmasq =
|
|
||||||
let d = prev.dnsmasq.overrideAttrs(o: {
|
|
||||||
preBuild = ''
|
|
||||||
makeFlagsArray=("COPTS=")
|
|
||||||
'';
|
|
||||||
});
|
|
||||||
in d.override {
|
|
||||||
dbusSupport = false;
|
|
||||||
nettle = null;
|
|
||||||
};
|
|
||||||
|
|
||||||
hostapd =
|
|
||||||
let
|
|
||||||
config = [
|
|
||||||
"CONFIG_DRIVER_NL80211=y"
|
|
||||||
"CONFIG_IAPP=y"
|
|
||||||
"CONFIG_IEEE80211AC=y"
|
|
||||||
"CONFIG_IEEE80211N=y"
|
|
||||||
"CONFIG_IEEE80211W=y"
|
|
||||||
"CONFIG_INTERNAL_LIBTOMMATH=y"
|
|
||||||
"CONFIG_INTERNAL_LIBTOMMATH_FAST=y"
|
|
||||||
"CONFIG_IPV6=y"
|
|
||||||
"CONFIG_LIBNL32=y"
|
|
||||||
"CONFIG_PKCS12=y"
|
|
||||||
"CONFIG_RSN_PREAUTH=y"
|
|
||||||
"CONFIG_TLS=internal"
|
|
||||||
];
|
|
||||||
h = prev.hostapd.overrideAttrs(o: {
|
|
||||||
extraConfig = "";
|
|
||||||
configurePhase = ''
|
|
||||||
cat > hostapd/defconfig <<EOF
|
|
||||||
${builtins.concatStringsSep "\n" config}
|
|
||||||
EOF
|
|
||||||
${o.configurePhase}
|
|
||||||
'';
|
|
||||||
});
|
|
||||||
in h.override { openssl = null; sqlite = null; };
|
|
||||||
|
|
||||||
dropbear = prev.dropbear.overrideAttrs (o: {
|
|
||||||
postPatch = ''
|
|
||||||
(echo '#define DSS_PRIV_FILENAME "/run/dropbear/dropbear_dss_host_key"'
|
|
||||||
echo '#define RSA_PRIV_FILENAME "/run/dropbear/dropbear_rsa_host_key"'
|
|
||||||
echo '#define ECDSA_PRIV_FILENAME "/run/dropbear/dropbear_ecdsa_host_key"'
|
|
||||||
echo '#define ED25519_PRIV_FILENAME "/run/dropbear/dropbear_ed25519_host_key"') > localoptions.h
|
|
||||||
'';
|
|
||||||
});
|
|
||||||
|
|
||||||
openssl = prev.openssl.overrideAttrs (o: {
|
openssl = prev.openssl.overrideAttrs (o: {
|
||||||
# we want to apply
|
# we want to apply
|
||||||
# https://patch-diff.githubusercontent.com/raw/openssl/openssl/pull/20273.patch";
|
# https://patch-diff.githubusercontent.com/raw/openssl/openssl/pull/20273.patch";
|
||||||
@ -184,4 +176,92 @@ extraPkgs // {
|
|||||||
});
|
});
|
||||||
|
|
||||||
pppBuild = prev.ppp;
|
pppBuild = prev.ppp;
|
||||||
|
|
||||||
|
qemuLim = let q = prev.qemu.overrideAttrs (o: {
|
||||||
|
patches = o.patches ++ [
|
||||||
|
./pkgs/qemu/arm-image-friendly-load-addr.patch
|
||||||
|
];
|
||||||
|
}); in q.override { nixosTestRunner = true; sdlSupport = false; };
|
||||||
|
|
||||||
|
rsyncSmall =
|
||||||
|
let r = prev.rsync.overrideAttrs(o: {
|
||||||
|
configureFlags = o.configureFlags ++ [
|
||||||
|
"--disable-openssl"
|
||||||
|
];
|
||||||
|
});
|
||||||
|
in r.override { openssl = null; };
|
||||||
|
|
||||||
|
|
||||||
|
inherit s6;
|
||||||
|
s6-linux-init = prev.s6-linux-init.override {
|
||||||
|
skawarePackages = prev.skawarePackages // {
|
||||||
|
inherit s6;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
s6-rc = prev.s6-rc.override {
|
||||||
|
skawarePackages = prev.skawarePackages // {
|
||||||
|
inherit s6;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
strace = prev.strace.override { libunwind = null; };
|
||||||
|
|
||||||
|
ubootQemuAarch64 = final.buildUBoot {
|
||||||
|
defconfig = "qemu_arm64_defconfig";
|
||||||
|
extraMeta.platforms = ["aarch64-linux"];
|
||||||
|
filesToInstall = ["u-boot.bin"];
|
||||||
|
};
|
||||||
|
|
||||||
|
ubootQemuArm = final.buildUBoot {
|
||||||
|
defconfig = "qemu_arm_defconfig";
|
||||||
|
extraMeta.platforms = ["armv7l-linux"];
|
||||||
|
filesToInstall = ["u-boot.bin"];
|
||||||
|
extraConfig = ''
|
||||||
|
CONFIG_CMD_UBI=y
|
||||||
|
CONFIG_CMD_UBIFS=y
|
||||||
|
CONFIG_BOOTSTD=y
|
||||||
|
CONFIG_BOOTMETH_DISTRO=y
|
||||||
|
CONFIG_LZMA=y
|
||||||
|
CONFIG_CMD_LZMADEC=y
|
||||||
|
CONFIG_SYS_BOOTM_LEN=0x1000000
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
ubootQemuMips = final.buildUBoot {
|
||||||
|
defconfig = "malta_defconfig";
|
||||||
|
extraMeta.platforms = ["mips-linux"];
|
||||||
|
filesToInstall = ["u-boot.bin"];
|
||||||
|
# define the prompt to be the same as arm{32,64} so
|
||||||
|
# we can use the same expect script for both
|
||||||
|
extraPatches = [ ./pkgs/u-boot/0002-virtio-init-for-malta.patch ];
|
||||||
|
extraConfig = ''
|
||||||
|
CONFIG_SYS_PROMPT="=> "
|
||||||
|
CONFIG_VIRTIO=y
|
||||||
|
CONFIG_AUTOBOOT=y
|
||||||
|
CONFIG_DM_PCI=y
|
||||||
|
CONFIG_VIRTIO_PCI=y
|
||||||
|
CONFIG_VIRTIO_NET=y
|
||||||
|
CONFIG_VIRTIO_BLK=y
|
||||||
|
CONFIG_VIRTIO_MMIO=y
|
||||||
|
CONFIG_QFW_MMIO=y
|
||||||
|
CONFIG_FIT=y
|
||||||
|
CONFIG_LZMA=y
|
||||||
|
CONFIG_CMD_LZMADEC=y
|
||||||
|
CONFIG_SYS_BOOTM_LEN=0x1000000
|
||||||
|
CONFIG_SYS_MALLOC_LEN=0x400000
|
||||||
|
CONFIG_MIPS_BOOT_FDT=y
|
||||||
|
CONFIG_OF_LIBFDT=y
|
||||||
|
CONFIG_OF_STDOUT_VIA_ALIAS=y
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
util-linux-small = prev.util-linux.override {
|
||||||
|
ncursesSupport = false;
|
||||||
|
pamSupport = false;
|
||||||
|
systemdSupport = false;
|
||||||
|
nlsSupport = false;
|
||||||
|
translateManpages = false;
|
||||||
|
capabilitiesSupport = false;
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
(fn system [s]
|
(fn system [s]
|
||||||
(match (os.execute s)
|
(match (os.execute s)
|
||||||
res res
|
res (do (print (.. "Executed \"" s "\", exit code " (tostring res))) res)
|
||||||
(nil err) (error (.. "Error executing \"" s "\" (" err ")"))))
|
(nil err) (error (.. "Error executing \"" s "\" (" err ")"))))
|
||||||
|
|
||||||
(fn hash [str]
|
(fn hash [str]
|
||||||
|
@ -10,10 +10,7 @@ let
|
|||||||
type' = types.submodule { options = type; };
|
type' = types.submodule { options = type; };
|
||||||
in (mergeDefinitions [] type' defs).mergedValue;
|
in (mergeDefinitions [] type' defs).mergedValue;
|
||||||
in {
|
in {
|
||||||
pseudofile = callPackage ./pseudofile {};
|
|
||||||
liminix = {
|
liminix = {
|
||||||
services = callPackage ./liminix-tools/services {};
|
|
||||||
networking = callPackage ./liminix-tools/networking {};
|
|
||||||
builders = {
|
builders = {
|
||||||
squashfs = callPackage ./liminix-tools/builders/squashfs.nix {};
|
squashfs = callPackage ./liminix-tools/builders/squashfs.nix {};
|
||||||
dtb = callPackage ./kernel/dtb.nix {};
|
dtb = callPackage ./kernel/dtb.nix {};
|
||||||
@ -52,32 +49,27 @@ in {
|
|||||||
};
|
};
|
||||||
inherit typeChecked;
|
inherit typeChecked;
|
||||||
};
|
};
|
||||||
|
networking = callPackage ./liminix-tools/networking {};
|
||||||
|
services = callPackage ./liminix-tools/services {};
|
||||||
};
|
};
|
||||||
writeFennelScript = callPackage ./write-fennel-script {};
|
|
||||||
writeFennel = callPackage ./write-fennel {};
|
|
||||||
writeAshScript = callPackage ./write-ash-script {};
|
|
||||||
systemconfig = callPackage ./systemconfig {};
|
|
||||||
s6-init-bin = callPackage ./s6-init-bin {};
|
|
||||||
s6-rc-database = callPackage ./s6-rc-database {};
|
|
||||||
run-liminix-vm = callPackage ./run-liminix-vm {};
|
|
||||||
ppp = callPackage ./ppp {};
|
|
||||||
pppoe = callPackage ./pppoe {};
|
|
||||||
|
|
||||||
kernel-backport = callPackage ./kernel-backport {};
|
# please keep the rest of this list alphabetised :-)
|
||||||
mac80211 = callPackage ./mac80211 {};
|
|
||||||
netlink-lua = callPackage ./netlink-lua {};
|
|
||||||
linotify = callPackage ./linotify {};
|
|
||||||
ifwait = callPackage ./ifwait {};
|
|
||||||
|
|
||||||
|
anoia = callPackage ./anoia {};
|
||||||
|
fennel = callPackage ./fennel {};
|
||||||
|
fennelrepl = callPackage ./fennelrepl {};
|
||||||
|
firewallgen = callPackage ./firewallgen {};
|
||||||
|
firmware-utils = callPackage ./firmware-utils {};
|
||||||
gen_init_cpio = callPackage ./gen_init_cpio {};
|
gen_init_cpio = callPackage ./gen_init_cpio {};
|
||||||
|
|
||||||
serviceFns = callPackage ./service-fns {};
|
|
||||||
|
|
||||||
# these are packages for the build system not the host/target
|
|
||||||
|
|
||||||
tufted = callPackage ./tufted {};
|
|
||||||
routeros = callPackage ./routeros {};
|
|
||||||
go-l2tp = callPackage ./go-l2tp {};
|
go-l2tp = callPackage ./go-l2tp {};
|
||||||
|
hi = callPackage ./hi {};
|
||||||
|
ifwait = callPackage ./ifwait {};
|
||||||
|
initramfs-peek = callPackage ./initramfs-peek {};
|
||||||
|
kernel-backport = callPackage ./kernel-backport {};
|
||||||
|
kmodloader = callPackage ./kmodloader {};
|
||||||
|
levitate = callPackage ./levitate {};
|
||||||
|
libubootenv = callPackage ./libubootenv {};
|
||||||
|
linotify = callPackage ./linotify {};
|
||||||
|
|
||||||
# we need to build real lzma instead of using xz, because the lzma
|
# we need to build real lzma instead of using xz, because the lzma
|
||||||
# decoder in u-boot doesn't understand streaming lzma archives
|
# decoder in u-boot doesn't understand streaming lzma archives
|
||||||
@ -86,20 +78,34 @@ in {
|
|||||||
# https://sourceforge.net/p/squashfs/mailman/message/26599379/
|
# https://sourceforge.net/p/squashfs/mailman/message/26599379/
|
||||||
lzma = callPackage ./lzma {};
|
lzma = callPackage ./lzma {};
|
||||||
|
|
||||||
preinit = callPackage ./preinit {};
|
mac80211 = callPackage ./mac80211 {};
|
||||||
swconfig = callPackage ./swconfig {};
|
zyxel-bootconfig = callPackage ./zyxel-bootconfig {};
|
||||||
odhcp6c = callPackage ./odhcp6c {};
|
|
||||||
|
|
||||||
openwrt = callPackage ./openwrt {};
|
|
||||||
|
|
||||||
initramfs-peek = callPackage ./initramfs-peek {};
|
|
||||||
min-collect-garbage = callPackage ./min-collect-garbage {};
|
min-collect-garbage = callPackage ./min-collect-garbage {};
|
||||||
min-copy-closure = callPackage ./min-copy-closure {};
|
min-copy-closure = callPackage ./min-copy-closure {};
|
||||||
hi = callPackage ./hi {};
|
netlink-lua = callPackage ./netlink-lua {};
|
||||||
firewallgen = callPackage ./firewallgen {};
|
|
||||||
kernel-modules = callPackage ./kernel-modules {};
|
|
||||||
odhcp-script = callPackage ./odhcp-script {};
|
odhcp-script = callPackage ./odhcp-script {};
|
||||||
fennel = callPackage ./fennel {};
|
odhcp6c = callPackage ./odhcp6c {};
|
||||||
fennelrepl = callPackage ./fennelrepl {};
|
openwrt = callPackage ./openwrt {};
|
||||||
anoia = callPackage ./anoia {};
|
ppp = callPackage ./ppp {};
|
||||||
|
pppoe = callPackage ./pppoe {};
|
||||||
|
preinit = callPackage ./preinit {};
|
||||||
|
pseudofile = callPackage ./pseudofile {};
|
||||||
|
routeros = callPackage ./routeros {};
|
||||||
|
run-liminix-vm = callPackage ./run-liminix-vm {};
|
||||||
|
s6-init-bin = callPackage ./s6-init-bin {};
|
||||||
|
s6-rc-database = callPackage ./s6-rc-database {};
|
||||||
|
|
||||||
|
# schnapps is written by Turris and provides a high-level interface
|
||||||
|
# to btrfs snapshots. It may be useful on the Turris Omnia to
|
||||||
|
# install Liminix while retaining the ability to rollback to the
|
||||||
|
# vendor OS, or even to derisk Liminix updates on that device
|
||||||
|
schnapps = callPackage ./schnapps {};
|
||||||
|
|
||||||
|
serviceFns = callPackage ./service-fns {};
|
||||||
|
swconfig = callPackage ./swconfig {};
|
||||||
|
systemconfig = callPackage ./systemconfig {};
|
||||||
|
tufted = callPackage ./tufted {};
|
||||||
|
writeAshScript = callPackage ./write-ash-script {};
|
||||||
|
writeFennel = callPackage ./write-fennel {};
|
||||||
|
writeFennelScript = callPackage ./write-fennel-script {};
|
||||||
}
|
}
|
||||||
|
24
pkgs/firmware-utils/default.nix
Normal file
24
pkgs/firmware-utils/default.nix
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
{ stdenv
|
||||||
|
, fetchFromGitHub
|
||||||
|
, cmake
|
||||||
|
, zlib
|
||||||
|
, openssl
|
||||||
|
}:
|
||||||
|
|
||||||
|
stdenv.mkDerivation {
|
||||||
|
pname = "firmware-utils";
|
||||||
|
version = "snapshot";
|
||||||
|
|
||||||
|
src = fetchFromGitHub {
|
||||||
|
owner = "openwrt";
|
||||||
|
repo = "firmware-utils";
|
||||||
|
rev = "e87f23849790a7c77b4cd0e8ef0384da188174e5";
|
||||||
|
hash = "sha256-285Isf9sRuUt5S56SozgqpnS0+LOfnvpxpnWLwuWYUk=";
|
||||||
|
};
|
||||||
|
|
||||||
|
nativeBuildInputs = [
|
||||||
|
cmake
|
||||||
|
zlib
|
||||||
|
openssl
|
||||||
|
];
|
||||||
|
}
|
@ -1,3 +0,0 @@
|
|||||||
|
|
||||||
|
|
||||||
# obj-m += net/ipv4/netfilter/nft_fib_ipv4.o
|
|
@ -1,55 +0,0 @@
|
|||||||
{
|
|
||||||
stdenv
|
|
||||||
, buildPackages
|
|
||||||
, kernelSrc ? null
|
|
||||||
, modulesupport ? null
|
|
||||||
, targets ? []
|
|
||||||
, kconfig ? {}
|
|
||||||
, openssl
|
|
||||||
, writeText
|
|
||||||
, lib
|
|
||||||
}:
|
|
||||||
let
|
|
||||||
writeConfig = import ../kernel/write-kconfig.nix { inherit lib writeText; };
|
|
||||||
arch = if stdenv.isMips
|
|
||||||
then "mips"
|
|
||||||
else if stdenv.isAarch64
|
|
||||||
then "arm64"
|
|
||||||
else throw "unknown arch";
|
|
||||||
in stdenv.mkDerivation {
|
|
||||||
name = "kernel-modules";
|
|
||||||
|
|
||||||
nativeBuildInputs = [buildPackages.stdenv.cc] ++
|
|
||||||
(with buildPackages.pkgs; [
|
|
||||||
bc bison flex
|
|
||||||
openssl
|
|
||||||
cpio
|
|
||||||
kmod
|
|
||||||
]);
|
|
||||||
CC = "${stdenv.cc.bintools.targetPrefix}gcc";
|
|
||||||
HOST_EXTRACFLAGS = with buildPackages.pkgs;
|
|
||||||
"-I${buildPackages.openssl.dev}/include -L${buildPackages.openssl.out}/lib";
|
|
||||||
CROSS_COMPILE = stdenv.cc.bintools.targetPrefix;
|
|
||||||
ARCH = arch;
|
|
||||||
KBUILD_BUILD_HOST = "liminix.builder";
|
|
||||||
|
|
||||||
buildPhase = ''
|
|
||||||
cat ${writeConfig "kconfig" kconfig} > .more-config
|
|
||||||
cat .more-config >> .config
|
|
||||||
make olddefconfig
|
|
||||||
for v in $(cat .more-config) ; do grep $v .config || (echo Missing $v && exit 1);done
|
|
||||||
# grep =m .config
|
|
||||||
make modules
|
|
||||||
'';
|
|
||||||
src = modulesupport;
|
|
||||||
installPhase = ''
|
|
||||||
mkdir -p $out/lib/modules/0.0
|
|
||||||
find . -name \*.ko | cpio --verbose --make-directories -p $out/lib/modules/0.0
|
|
||||||
depmod -b $out -v 0.0
|
|
||||||
touch $out/load.sh
|
|
||||||
for i in ${lib.concatStringsSep " " targets}; do
|
|
||||||
modprobe -S 0.0 -d $out --show-depends $i >> $out/load.sh
|
|
||||||
done
|
|
||||||
tac < $out/load.sh | sed 's/^insmod/rmmod/g' > $out/unload.sh
|
|
||||||
'';
|
|
||||||
}
|
|
@ -6,17 +6,15 @@
|
|||||||
|
|
||||||
, config
|
, config
|
||||||
, src
|
, src
|
||||||
|
, version ? "0"
|
||||||
, extraPatchPhase ? "echo"
|
, extraPatchPhase ? "echo"
|
||||||
|
, targets ? ["vmlinux"]
|
||||||
} :
|
} :
|
||||||
let
|
let
|
||||||
writeConfig = import ./write-kconfig.nix { inherit lib writeText; };
|
writeConfig = import ./write-kconfig.nix { inherit lib writeText; };
|
||||||
kconfigFile = writeConfig "kconfig" config;
|
kconfigFile = writeConfig "kconfig" config;
|
||||||
arch = if stdenv.isMips
|
arch = stdenv.hostPlatform.linuxArch;
|
||||||
then "mips"
|
targetNames = map baseNameOf targets;
|
||||||
else if stdenv.isAarch64
|
|
||||||
then "arm64"
|
|
||||||
else throw "unknown arch";
|
|
||||||
|
|
||||||
inherit lib; in
|
inherit lib; in
|
||||||
stdenv.mkDerivation rec {
|
stdenv.mkDerivation rec {
|
||||||
name = "kernel";
|
name = "kernel";
|
||||||
@ -39,7 +37,7 @@ stdenv.mkDerivation rec {
|
|||||||
|
|
||||||
dontStrip = true;
|
dontStrip = true;
|
||||||
dontPatchELF = true;
|
dontPatchELF = true;
|
||||||
outputs = ["out" "headers" "modulesupport"];
|
outputs = ["out" "headers" "modulesupport"] ++ targetNames;
|
||||||
phases = [
|
phases = [
|
||||||
"unpackPhase"
|
"unpackPhase"
|
||||||
"butcherPkgconfig"
|
"butcherPkgconfig"
|
||||||
@ -54,7 +52,9 @@ stdenv.mkDerivation rec {
|
|||||||
|
|
||||||
patches = [
|
patches = [
|
||||||
./cmdline-cookie.patch
|
./cmdline-cookie.patch
|
||||||
];
|
./mips-malta-fdt-from-bootloader.patch
|
||||||
|
] ++ lib.optional (lib.versionOlder version "5.18.0")
|
||||||
|
./phram-allow-cached-mappings.patch;
|
||||||
|
|
||||||
# this is here to work around what I think is a bug in nixpkgs
|
# this is here to work around what I think is a bug in nixpkgs
|
||||||
# packaging of ncurses: it installs pkg-config data files which
|
# packaging of ncurses: it installs pkg-config data files which
|
||||||
@ -94,18 +94,17 @@ stdenv.mkDerivation rec {
|
|||||||
'';
|
'';
|
||||||
|
|
||||||
buildPhase = ''
|
buildPhase = ''
|
||||||
make vmlinux modules_prepare
|
make ${lib.concatStringsSep " " targetNames} modules_prepare -j$NIX_BUILD_CORES
|
||||||
'';
|
'';
|
||||||
|
|
||||||
installPhase = ''
|
installPhase = ''
|
||||||
${CROSS_COMPILE}strip -d vmlinux
|
${CROSS_COMPILE}strip -d vmlinux
|
||||||
|
${lib.concatStringsSep "\n" (map (f: "cp ${f} \$${baseNameOf f}") targets)}
|
||||||
cp vmlinux $out
|
cp vmlinux $out
|
||||||
mkdir -p $headers
|
mkdir -p $headers
|
||||||
cp -a include .config $headers/
|
cp -a include .config $headers/
|
||||||
mkdir -p $modulesupport
|
mkdir -p $modulesupport
|
||||||
cp modules.* $modulesupport
|
make modules
|
||||||
make clean modules_prepare
|
|
||||||
cp -a . $modulesupport
|
cp -a . $modulesupport
|
||||||
'';
|
'';
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/dts-v1/;
|
/dts-v1/;
|
||||||
|
|
||||||
// used on aarch64 to provide a U-bootable image that combines
|
// used on arm/aarch64 to provide a U-bootable image that combines
|
||||||
// kernel and fdt
|
// kernel and fdt
|
||||||
|
|
||||||
/ {
|
/ {
|
||||||
@ -12,7 +12,7 @@
|
|||||||
description = "Vanilla Linux kernel";
|
description = "Vanilla Linux kernel";
|
||||||
// data = /incbin/("./vmlinux.bin.gz");
|
// data = /incbin/("./vmlinux.bin.gz");
|
||||||
type = "kernel";
|
type = "kernel";
|
||||||
arch = "arm64";
|
// arch = "arm64";
|
||||||
os = "linux";
|
os = "linux";
|
||||||
// compression = "gzip";
|
// compression = "gzip";
|
||||||
// load = <00000000>;
|
// load = <00000000>;
|
||||||
@ -28,7 +28,7 @@
|
|||||||
description = "Flattened Device Tree blob";
|
description = "Flattened Device Tree blob";
|
||||||
// data = /incbin/("./target.dtb");
|
// data = /incbin/("./target.dtb");
|
||||||
type = "flat_dt";
|
type = "flat_dt";
|
||||||
arch = "arm64";
|
// arch = "arm64";
|
||||||
compression = "none";
|
compression = "none";
|
||||||
hash-1 {
|
hash-1 {
|
||||||
algo = "crc32";
|
algo = "crc32";
|
||||||
|
15
pkgs/kernel/mips-malta-fdt-from-bootloader.patch
Normal file
15
pkgs/kernel/mips-malta-fdt-from-bootloader.patch
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
diff --git a/arch/mips/mti-malta/malta-setup.c b/arch/mips/mti-malta/malta-setup.c
|
||||||
|
index 21cb3ac1237b..52e731f9b4e2 100644
|
||||||
|
--- a/arch/mips/mti-malta/malta-setup.c
|
||||||
|
+++ b/arch/mips/mti-malta/malta-setup.c
|
||||||
|
@@ -192,7 +192,9 @@ static void __init bonito_quirks_setup(void)
|
||||||
|
|
||||||
|
void __init *plat_get_fdt(void)
|
||||||
|
{
|
||||||
|
- return (void *)__dtb_start;
|
||||||
|
+ return (fw_arg0 == -2) ?
|
||||||
|
+ (void *) (KSEG1ADDR(fw_arg1)) :
|
||||||
|
+ (void *) __dtb_start;
|
||||||
|
}
|
||||||
|
|
||||||
|
void __init plat_mem_setup(void)
|
47
pkgs/kernel/phram-allow-cached-mappings.patch
Normal file
47
pkgs/kernel/phram-allow-cached-mappings.patch
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
From bb7e7aeb3d832059e33b1e76eb85d4680f77abf2 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Ben Hutchings <ben@decadent.org.uk>
|
||||||
|
Date: Fri, 3 Jun 2016 01:08:36 +0100
|
||||||
|
Subject: [PATCH] phram: Use memremap() to allow mapping of system RAM
|
||||||
|
|
||||||
|
Using memremap() instead of ioremap() allows mapping a disk image in
|
||||||
|
system RAM that has somehow been reserved. It should fall back
|
||||||
|
to ioremap() where necessary.
|
||||||
|
|
||||||
|
Entirely untested, and I'm not convinced this is a good idea at all.
|
||||||
|
---
|
||||||
|
drivers/mtd/devices/phram.c | 7 ++++---
|
||||||
|
1 file changed, 4 insertions(+), 3 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/drivers/mtd/devices/phram.c b/drivers/mtd/devices/phram.c
|
||||||
|
index 8b66e52ca3cc..0ea254e2ba51 100644
|
||||||
|
--- a/drivers/mtd/devices/phram.c
|
||||||
|
+++ b/drivers/mtd/devices/phram.c
|
||||||
|
@@ -88,7 +88,7 @@ static void unregister_devices(void)
|
||||||
|
|
||||||
|
list_for_each_entry_safe(this, safe, &phram_list, list) {
|
||||||
|
mtd_device_unregister(&this->mtd);
|
||||||
|
- iounmap(this->mtd.priv);
|
||||||
|
+ memunmap(this->mtd.priv);
|
||||||
|
kfree(this->mtd.name);
|
||||||
|
kfree(this);
|
||||||
|
}
|
||||||
|
@@ -104,7 +104,8 @@ static int register_device(char *name, phys_addr_t start, size_t len)
|
||||||
|
goto out0;
|
||||||
|
|
||||||
|
ret = -EIO;
|
||||||
|
- new->mtd.priv = ioremap(start, len);
|
||||||
|
+ new->mtd.priv = memremap(start, len,
|
||||||
|
+ MEMREMAP_WB | MEMREMAP_WT | MEMREMAP_WC);
|
||||||
|
if (!new->mtd.priv) {
|
||||||
|
pr_err("ioremap failed\n");
|
||||||
|
goto out1;
|
||||||
|
@@ -134,7 +135,7 @@ static int register_device(char *name, phys_addr_t start, size_t len)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
out2:
|
||||||
|
- iounmap(new->mtd.priv);
|
||||||
|
+ memunmap(new->mtd.priv);
|
||||||
|
out1:
|
||||||
|
kfree(new);
|
||||||
|
out0:
|
||||||
|
|
@ -7,21 +7,29 @@
|
|||||||
} :
|
} :
|
||||||
let
|
let
|
||||||
objcopy = "${stdenv.cc.bintools.targetPrefix}objcopy";
|
objcopy = "${stdenv.cc.bintools.targetPrefix}objcopy";
|
||||||
|
arch = stdenv.hostPlatform.linuxArch;
|
||||||
|
stripAndZip = ''
|
||||||
|
${objcopy} -O binary -R .reginfo -R .notes -R .note -R .comment -R .mdebug -R .note.gnu.build-id -S vmlinux.elf vmlinux.bin
|
||||||
|
rm -f vmlinux.bin.lzma ; lzma -k -z vmlinux.bin
|
||||||
|
'';
|
||||||
in {
|
in {
|
||||||
kernel
|
kernel
|
||||||
, commandLine
|
, commandLine
|
||||||
|
, commandLineDtbNode ? "bootargs"
|
||||||
, entryPoint
|
, entryPoint
|
||||||
, extraName ? "" # e.g. socFamily
|
, extraName ? "" # e.g. socFamily
|
||||||
, loadAddress
|
, loadAddress
|
||||||
|
, imageFormat
|
||||||
|
, alignment ? null
|
||||||
, dtb ? null
|
, dtb ? null
|
||||||
} :
|
} : stdenv.mkDerivation {
|
||||||
stdenv.mkDerivation {
|
|
||||||
name = "kernel.image";
|
name = "kernel.image";
|
||||||
phases = [
|
phases = [
|
||||||
"preparePhase"
|
"preparePhase"
|
||||||
(if dtb != null then "dtbPhase" else ":")
|
(if commandLine != null then assert dtb != null; "mungeDtbPhase" else ":")
|
||||||
"buildPhase"
|
(if imageFormat == "fit" then "buildPhaseFIT" else "buildPhaseUImage")
|
||||||
"installPhase" ];
|
"installPhase"
|
||||||
|
];
|
||||||
nativeBuildInputs = [
|
nativeBuildInputs = [
|
||||||
lzma
|
lzma
|
||||||
dtc
|
dtc
|
||||||
@ -31,35 +39,43 @@ stdenv.mkDerivation {
|
|||||||
preparePhase = ''
|
preparePhase = ''
|
||||||
cp ${kernel} vmlinux.elf; chmod +w vmlinux.elf
|
cp ${kernel} vmlinux.elf; chmod +w vmlinux.elf
|
||||||
'';
|
'';
|
||||||
dtbPhase = ''
|
mungeDtbPhase = ''
|
||||||
dtc -I dtb -O dts -o tmp.dts ${dtb}
|
dtc -I dtb -O dts -o tmp.dts ${dtb}
|
||||||
echo '/{ chosen { bootargs = ${builtins.toJSON commandLine}; }; };' >> tmp.dts
|
echo '/{ chosen { ${commandLineDtbNode} = ${builtins.toJSON commandLine}; }; };' >> tmp.dts
|
||||||
dtc -I dts -O dtb -o tmp.dtb tmp.dts
|
dtc -I dts -O dtb -o tmp.dtb tmp.dts
|
||||||
'';
|
'';
|
||||||
|
|
||||||
buildPhase =
|
buildPhaseUImage = ''
|
||||||
let arch =
|
test -f tmp.dtb && ${objcopy} --update-section .appended_dtb=tmp.dtb vmlinux.elf || ${objcopy} --add-section .appended_dtb=tmp.dtb vmlinux.elf
|
||||||
# per output of "mkimage -A list". I *think* these
|
${stripAndZip}
|
||||||
# are the same as the kernel arch convention, but
|
mkimage -A ${arch} -O linux -T kernel -C lzma -a 0x${lib.toHexString loadAddress} -e 0x${lib.toHexString entryPoint} -n '${lib.toUpper arch} Liminix Linux ${extraName}' -d vmlinux.bin.lzma kernel.uimage
|
||||||
# maybe that's coincidence
|
'';
|
||||||
if stdenv.isMips
|
|
||||||
then "mips"
|
buildPhaseFIT = ''
|
||||||
else if stdenv.isAarch64
|
${stripAndZip}
|
||||||
then "arm64"
|
cat ${./kernel_fdt.its} > mkimage.its
|
||||||
else throw "unknown arch";
|
cat << _VARS >> mkimage.its
|
||||||
in ''
|
/ {
|
||||||
${objcopy} -O binary -R .reginfo -R .notes -R .note -R .comment -R .mdebug -R .note.gnu.build-id -S vmlinux.elf vmlinux.bin
|
images {
|
||||||
rm -f vmlinux.bin.lzma ; lzma -k -z vmlinux.bin
|
kernel {
|
||||||
cat ${./kernel_fdt.its} > mkimage.its
|
data = /incbin/("./vmlinux.bin.lzma");
|
||||||
echo '/ { images { kernel { data = /incbin/("./vmlinux.bin.lzma"); }; }; };' >> mkimage.its
|
load = <0x${lib.toHexString loadAddress}>;
|
||||||
echo '/ { images { kernel { load = <${loadAddress}>; }; }; };' >> mkimage.its
|
entry = <0x${lib.toHexString entryPoint}>;
|
||||||
echo '/ { images { kernel { entry = <${entryPoint}>; }; }; };' >> mkimage.its
|
arch = "${arch}";
|
||||||
echo '/ { images { kernel { compression = "lzma"; }; }; };' >> mkimage.its
|
compression = "lzma";
|
||||||
echo '/ { images { fdt-1 { data = /incbin/("./tmp.dtb"); }; }; }; ' >> mkimage.its
|
};
|
||||||
mkimage -f mkimage.its mkimage.itb
|
fdt-1 {
|
||||||
mkimage -l mkimage.itb
|
data = /incbin/("./tmp.dtb");
|
||||||
'';
|
arch = "${arch}";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
_VARS
|
||||||
|
mkimage -f mkimage.its ${lib.optionalString (alignment != null) "-B 0x${lib.toHexString alignment}"} kernel.uimage
|
||||||
|
mkimage -l kernel.uimage
|
||||||
|
'';
|
||||||
|
|
||||||
installPhase = ''
|
installPhase = ''
|
||||||
cp mkimage.itb $out
|
cp kernel.uimage $out
|
||||||
'';
|
'';
|
||||||
}
|
}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user