Compare commits
101 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3f889c7119 | |||
| 7f17125039 | |||
| 4bb081ffcf | |||
| 6587813577 | |||
| 1d780de0f1 | |||
| 8cf602da91 | |||
| c92aacc6fd | |||
| eff255fe12 | |||
| 453baede61 | |||
| 2295ed3110 | |||
| e71d92eb3d | |||
| f77da6f14c | |||
| 61eaaa82eb | |||
| 95dd1a1fab | |||
| 2f9b0f12f9 | |||
| 9fd9b8b878 | |||
| 26f206d0e1 | |||
| 8cd068ea68 | |||
| 350ddde260 | |||
| 13cb8d3692 | |||
| 62b7aea8ab | |||
| 76e3fd9a55 | |||
| 92284fa9ba | |||
| a2bb55e885 | |||
| 74027b44d7 | |||
| ea5370b3f4 | |||
| 55ed365920 | |||
| aa2160dd05 | |||
| df414b796f | |||
| 7377f7ceb2 | |||
| 49432aeda5 | |||
| 3caf8a75bb | |||
| cc94ef57fa | |||
| fd28f0ce04 | |||
| 497307588f | |||
| 788169586f | |||
| 3af9e86624 | |||
| 28d39cd66d | |||
| 9dd169d500 | |||
| 2e513eb4a7 | |||
| f2e4e77d73 | |||
| 48dfbe0c01 | |||
| 6f697db57c | |||
| fe1ee12e3d | |||
| 4d273a9469 | |||
| 40db175b41 | |||
| ab07212a7e | |||
| f5e08ac9d9 | |||
| 0cb18eabcd | |||
| 24151425b8 | |||
| e06295ed83 | |||
| 608d3e3abf | |||
| 3e19f1b927 | |||
| 3f6e9b6384 | |||
| 294492a176 | |||
| 67a1cd3718 | |||
| f8a275d1a3 | |||
| 0ee9c76c33 | |||
| 452aaa2f60 | |||
| 52967f746b | |||
| a89f866bf0 | |||
| f3fadd5cd7 | |||
| bc20f4c6b7 | |||
| 848214d104 | |||
| ede8f12d2b | |||
| 6cd5b90678 | |||
| db4f098c02 | |||
| 1347937345 | |||
| a7b5f80674 | |||
| 5c78338d71 | |||
| ed02d02767 | |||
| f07a38b0fd | |||
| ac189f2977 | |||
| ebb4d4a831 | |||
| 6bfbdf352d | |||
| 4ea1cf7f32 | |||
| f60b74f415 | |||
| 812e35b7b9 | |||
| 172f368633 | |||
| 1af9a39db1 | |||
| 420552ce98 | |||
| 56c667cfd5 | |||
| f9b4f0bc9c | |||
| ba5e4704a0 | |||
| 3357d21d7f | |||
| ffaca615ba | |||
| 77cd4492b2 | |||
| 81f5550bf0 | |||
| b52133a28b | |||
| 1ff779c1a9 | |||
| 44caefcd3b | |||
| 6e6b8790eb | |||
| 2e5a8a572e | |||
| 464d046b5a | |||
| ac8b971cc0 | |||
| 13087d17e3 | |||
| 5572c0ecb0 | |||
| 4cbe3ba683 | |||
| 20f4a12689 | |||
| 33e5c436d5 | |||
| cde30bcd54 |
@@ -132,4 +132,28 @@ and then run the generated `install.sh` script
|
||||
|
||||
result/install.sh root@192.168.8.1
|
||||
|
||||
2024-12-16
|
||||
|
||||
Config options changed: if you had set config.hardware.dts.includes
|
||||
(maybe in an out-of-tree device port) to specify the search paths
|
||||
in which dtc finds include files, you will need to change this to
|
||||
hardware.dts.includePaths.
|
||||
|
||||
The "new" hardware.dts.includes option is now for dtsi files which
|
||||
should be merged into the device tree.
|
||||
|
||||
2024-12-19
|
||||
|
||||
Incremental updates changed again (but not massively). From hereon in,
|
||||
the preferred way to do an incremental update on an installed device
|
||||
with a writable filesystem is to build the updater output
|
||||
|
||||
nix-build -I liminix-config=hosts/myhost.nix --argstr deviceName turris-omnia -A outputs.updater
|
||||
|
||||
and then run the generated `update.sh` script. See
|
||||
https://www.liminix.org/doc/admin.html#updating-an-installed-system
|
||||
|
||||
2024-12-22
|
||||
|
||||
outputs.zimage is now outputs.kernel.zImage. This is unlikely to
|
||||
affect many people at all but I mention it anyway.
|
||||
+481
@@ -6539,3 +6539,484 @@ using a Makefile
|
||||
|
||||
idea 2: when a configuration contains levitate, something similar
|
||||
but necessarily more "manual" to do the analogous thing
|
||||
|
||||
|
||||
Sun Dec 15 18:55:55 GMT 2024
|
||||
|
||||
Where we left off with this, rotuer was crashing randomly or failing
|
||||
to boot every time we tried to add log shipping, which is not very
|
||||
ideal. I started doing something with logging to /dev/pmsg0
|
||||
(CONFIG_PSTORE_PMSG) but I think (there seems not to be anything
|
||||
written down :-( ) that the gl-ar750 kernel needs it added to kconfig and device tree
|
||||
|
||||
https://wiki.postmarketos.org/wiki/User:Knuxify/Enabling_pstore_and_ramoops
|
||||
|
||||
we could add a new hardware.dts.dtsi = [] option so that any module
|
||||
could add a new chunk of dts. (Ideally we'd call it `includes`
|
||||
but that conflicts with the existing use of `includes` to specify
|
||||
search path. Maybe rename?)
|
||||
|
||||
would we ever use it except in a hardware device definition?
|
||||
(Or user config?) I guess if we were consistent with names
|
||||
then we could set up nodes in the device file with status="disabled"
|
||||
and enable them in the module, except that dt doesn't consistently
|
||||
use status and in fact there isn't one for reserved-memory
|
||||
|
||||
we could use global config to enable pstore_msg and check it in
|
||||
the device module to enable the needed hw support
|
||||
|
||||
Tue Dec 17 23:39:28 GMT 2024
|
||||
|
||||
I think we can just stick a tee in the fallback logger pipeline that
|
||||
writes to /dev/pmsg0
|
||||
|
||||
Need to check it's a circular buffer
|
||||
|
||||
do we want to do anything about recovering the log on boot?
|
||||
- we could just copy it to /run/log
|
||||
- if we have backfilling for shipped logs (we don't yet)
|
||||
then we might want to ship it - but that may result in duplicate
|
||||
logs if some of it was shipped before the crash
|
||||
|
||||
perhaps we should truncate pmsg0 on orderly shutdown? or maybe it's
|
||||
good to see the late shutdown logs.
|
||||
|
||||
Thu Dec 19 13:40:39 GMT 2024
|
||||
|
||||
although we have PSTORE_foo in the omnia kconfig, I think this might
|
||||
be just because I copied it from RT3200
|
||||
|
||||
Thu Dec 19 14:15:43 GMT 2024
|
||||
|
||||
Omnia is not in ci.nix, and it's not trivial to add it because there
|
||||
is no output in the ci.nix configuration that makes sense for omnia.
|
||||
|
||||
... OK, fixed by adding system-configuration as an independent module
|
||||
and importing in device config
|
||||
|
||||
Thu Dec 19 21:59:47 GMT 2024
|
||||
|
||||
The build-system shell script in outputs.systemConfiguration
|
||||
is ugly and requires we do bad things to avoid sucking build
|
||||
system stuff into the config
|
||||
|
||||
I propose we make it a separate derivation.
|
||||
|
||||
But first maybe we could improve some names
|
||||
|
||||
Sun Dec 22 14:23:02 GMT 2024
|
||||
|
||||
MT7622> echo $boot_default
|
||||
if env exists flag_recover ; then else run bootcmd ; fi ; run boot_recovery ; setenv replacevol 1 ; run boot_tftp_for
|
||||
ever
|
||||
MT7622> echo $bootcmd
|
||||
if pstore check ; then run boot_recovery ; else run boot_ubi ; fi
|
||||
MT7622> echo $boot_ubi
|
||||
ubi part ubi && run boot_production ; run boot_recovery
|
||||
MT7622> echo $boot_production
|
||||
led $bootled_pwr on ; run ubi_read_production && bootm $loadaddr#$bootconf ; led $bootled_pwr off
|
||||
MT7622> echo $ubi_read_production
|
||||
ubi read $loadaddr fit && iminfo $loadaddr && run ubi_prepare_rootfs
|
||||
MT7622> echo $ubi_prepare_rootfs
|
||||
if ubi check rootfs_data ; then else if env exists rootfs_data_max ; then ubi create rootfs_data $rootfs_data_max dynamic || ubi create rootfs_data - dynamic ; else ubi create rootfs_data - dynamic ; fi ; fi
|
||||
MT7622> echo $bootconf
|
||||
config-1
|
||||
MT7622> run boot_ubi
|
||||
UBI partition 'ubi' already selected
|
||||
No size specified -> Using max size (126976)
|
||||
Read 126976 bytes from volume fit to 0000000048000000
|
||||
|
||||
## Checking Image at 48000000 ...
|
||||
Unknown image format!
|
||||
No size specified -> Using max size (7491584)
|
||||
Read 7491584 bytes from volume recovery to 0000000048000000
|
||||
## Loading kernel from FIT Image at 48000000 ...
|
||||
Using 'config-1' configuration
|
||||
Trying 'kernel-1' kernel subimage
|
||||
Description: ARM64 OpenWrt Linux-6.6.45
|
||||
|
||||
Sun Dec 22 17:39:56 GMT 2024
|
||||
|
||||
From the output above it looks like the device I have plugged in has
|
||||
an openwrt "recovery" image but not a "production" image
|
||||
|
||||
It also looks like it will be quite hard work to persuade it to boot
|
||||
from usb or anything. It doesn't have any of the extlinux stuff
|
||||
but it does have uefi for what that's worth
|
||||
|
||||
default boot_production command reads a ubi volume called 'fit' and
|
||||
calls bootm on what it finds
|
||||
|
||||
we could define boot_production to ubifsmount liminix; ubifs load
|
||||
<addr> <filename> (which is a fit) and bootm it. *presumably* we could
|
||||
do this from the openwrt recovery image
|
||||
|
||||
but could we install the whole system using said recovery image? I
|
||||
expect we could do, it only requires getting a tarball onto it and
|
||||
unpacking it
|
||||
|
||||
however, extlinux is not going to be helpful
|
||||
(actually it might be a bit, if we ask it to write the fit as
|
||||
well as/instead of the individual files)
|
||||
|
||||
maybe we need separate concepts of "the filesystem contains
|
||||
stuff we need for boot" and "the stuff we need is the stuff
|
||||
that extlinux needs"
|
||||
|
||||
each bootloader makes an output called bootfiles, and
|
||||
the bootablerootdir output copies from bootfiles
|
||||
|
||||
Mon Dec 23 18:28:50 GMT 2024
|
||||
|
||||
it might be worth moving ubi option decls into the hardware module, if
|
||||
they're hardware-dependent
|
||||
|
||||
Tue Dec 24 16:14:50 GMT 2024
|
||||
|
||||
Where next?
|
||||
|
||||
a config for haproxy would be good
|
||||
|
||||
> a connection or request arrives on a frontend, then the
|
||||
information carried with this request or connection are processed, and
|
||||
at this point it is possible to write ACLs-based conditions making use
|
||||
of these information to decide what backend will process the request.
|
||||
|
||||
http://docs.haproxy.org/3.1/intro.html#3.4.4
|
||||
|
||||
listen foo
|
||||
bind :443
|
||||
|
||||
frontend foo
|
||||
mode tcp
|
||||
|
||||
Thu Dec 26 14:27:26 GMT 2024
|
||||
|
||||
What's the plan?
|
||||
|
||||
1) build the updater target for rotuer
|
||||
2) ssh forward through bordervm to install it
|
||||
3) carve the ngix sni proxy into examples/module-sniproxy
|
||||
with a fat warning comment
|
||||
3.5) should we add the examples to ci?
|
||||
4) see if it builds
|
||||
5) using curl on bordervm, see if it forwards
|
||||
5000) swap the real rotuer hardware
|
||||
|
||||
|
||||
Sun Dec 29 18:22:42 GMT 2024
|
||||
|
||||
To make sniproxy work it needs dns, which means it needs an upstream.
|
||||
But if we move the bordervm cable from lan to wan, we won't be able to
|
||||
rebuild over ssh unless it's sufficiently unbroken for pppoe to be working
|
||||
|
||||
... unless we add a "management" address to the wan interface along with pppoe
|
||||
|
||||
to permit wan stuff through the firewall, now that we've fixed the
|
||||
firewall :embarrassed:, do
|
||||
|
||||
/nix/store/*nftables*/bin/nft insert rule table-ip input-ip4 position 19 iifname "wan" jump incoming-allowed-ip4
|
||||
|
||||
What else do we need to try rt3200 as prod rotuer?
|
||||
|
||||
- pstore logging
|
||||
- log shipping (maybe via wan to bordervm for now)
|
||||
- enable sniproxy module
|
||||
|
||||
zcat /proc/config.gz | grep PSTORE
|
||||
|
||||
Tue Dec 31 22:45:33 GMT 2024
|
||||
|
||||
/nix/store/i1khbsqpyx020xrhvfbdazc1bnmirc72-kernel-aarch64-unknown-linux-musl-modulesupport/vmlinux
|
||||
|
||||
|
||||
these 3 derivations will be built:
|
||||
/nix/store/fvxrvyx64cm86cc4na0584qj9xw6s406-kernel-aarch64-unknown-linux-musl.drv
|
||||
/nix/store/ksg93bd8x2z1xpfmj24ixm2srg547mjx-dtb-aarch64-unknown-linux-musl.drv
|
||||
/nix/store/n33ij1npzwjmlsw23sz6yhyrh9hgxwaw-kernel.image-aarch64-unknown-linux-musl.drv
|
||||
building '/nix/store/fvxrvyx64cm86cc4na0584qj9xw6s406-kernel-aarch64-unknown-linux-musl.drv'...
|
||||
zcat /proc/config.gz | grep PSTORE
|
||||
|
||||
we think tftpboot works (check!)
|
||||
build the FIT from the updater target with squashfs added in rotuer.nix
|
||||
boot it with tftp by copy-pasting the boot.scr and changing it
|
||||
|
||||
setenv serverip 10.0.0.1
|
||||
setenv ipaddr 10.0.0.8
|
||||
tftpboot 0x4007ff28 r2/rootfs; tftpboot 0x41086f28 r2/image; tftpboot 0x4107ff28 r2/dtb
|
||||
bootm 0x41086f28 - 0x4107ff28
|
||||
|
||||
tftpboot works
|
||||
tftpboot with outputs.uimage works
|
||||
1458ed2cdeaa6bf4c02c6511a6d7369d /nix/store/4n3jc4n7lsp73yc2ccnmgibc7079rxms-kernel.image-aarch64-unknown-linux-musl
|
||||
|
||||
$ grep fit /nix/store/ihi7vski37b9ph4xcyqpabymc5nsngjd-system-configuration-aarch64-unknown-linux-musl/etc/nix-store-paths
|
||||
/nix/store/5jphs9mnb8hzhvwfi2z8h6cnaz6qx4y6-boot-fit
|
||||
$ md5sum /nix/store/5jphs9mnb8hzhvwfi2z8h6cnaz6qx4y6-boot-fit/fit
|
||||
1458ed2cdeaa6bf4c02c6511a6d7369d /nix/store/5jphs9mnb8hzhvwfi2z8h6cnaz6qx4y6-boot-fit/fit
|
||||
|
||||
something is changing /persist/boot from a symlink to a directory and I don't know what
|
||||
... plot twist: or is it? maybe it's ubimage that makes it a directory
|
||||
|
||||
rt3200 has no pmsg-size according to dtc -I fs /proc/device-tree/ -O dts
|
||||
|
||||
should be more like
|
||||
|
||||
reserved-memory {
|
||||
ramoops@03f00000 {
|
||||
compatible = "ramoops";
|
||||
reg = <0x03f00000 0x10000>;
|
||||
pmsg-size = <0x10000>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
Wed Jan 1 14:57:35 GMT 2025
|
||||
|
||||
At last I have working persistent logging.
|
||||
|
||||
I think we need to do something at boot time to move the persistent logs into
|
||||
the regular s6 log thing
|
||||
|
||||
foreground {
|
||||
redirfd -w 1 /run/prior-boot2
|
||||
elglob file /sys/fs/pstore/* cat $file
|
||||
}
|
||||
|
||||
Thu Jan 2 14:31:11 GMT 2025
|
||||
|
||||
to change to a previous "generation" we could run any of
|
||||
"/nix/store/*system-configuration*/bin/install /mnt" from a rescue
|
||||
system. It would populate /boot and bin/activate
|
||||
|
||||
supposing we are in such a rescue system, how do we find *which*
|
||||
system-configuration is the one we want to revert to? The derivation
|
||||
should be pure, so if we're going to timestamp anything we have to do
|
||||
that in the imperative step i.e. update.sh
|
||||
|
||||
perhaps a symlink from /persist/configuration/yyyymmddtmmhhss -> /nix/store/eeee-blah
|
||||
|
||||
|
||||
Thu Jan 2 23:38:59 GMT 2025
|
||||
|
||||
Stuff we should tidy up:
|
||||
|
||||
1) all devices to set credible default output, rootfs, etc
|
||||
2) expunge remaining references to kexecboot
|
||||
3) dynamic uid assigment for users
|
||||
4) lessen logging noise from firewall
|
||||
5) update.sh --fast sends wlan services for a spin
|
||||
|
||||
|
||||
|
||||
Fri Jan 3 16:05:10 GMT 2025
|
||||
|
||||
* build actual rotuer config and install on rt3200
|
||||
* find usb ethernet dongle for laptop
|
||||
* plug it in?
|
||||
|
||||
Sat Jan 4 15:32:03 GMT 2025
|
||||
|
||||
didn't work so well, because the installer version is coupled with the
|
||||
dtb and the dtb can't be upgraded without upgrading the kenrel
|
||||
|
||||
kernel 6.6.67 builds and boots but seems to have no wired ethernet.
|
||||
looking through the openwrt config changes ...
|
||||
|
||||
+CONFIG_MTD_UBI_NVMEM=y
|
||||
+CONFIG_NVMEM_BLOCK=y
|
||||
+CONFIG_NVMEM_LAYOUT_ADTRAN=y
|
||||
+CONFIG_PHYLIB_LEDS=y
|
||||
+CONFIG_MTK_REGULATOR_COUPLER=y
|
||||
+CONFIG_FW_LOADER_SYSFS=y
|
||||
|
||||
|
||||
Sun Jan 5 12:58:52 GMT 2025
|
||||
|
||||
We are running with rt3200 and everything appears to work :-)
|
||||
|
||||
Sun Jan 5 20:34:18 GMT 2025
|
||||
|
||||
what customization do we want from the firewall?
|
||||
|
||||
- what's allowed wan->lan
|
||||
- what's allowed lan->wan
|
||||
- which dropped packets get logged or don't
|
||||
|
||||
plus fix whatever it was RoS found
|
||||
plus stop hardcoding the interface names
|
||||
|
||||
Q: if pppd _makes_ an interface, how do we know what the name of it
|
||||
is going to be before it's up and passing packets so that we can
|
||||
have the firewall active before it starts
|
||||
|
||||
or could we have ppp service install a "drop everything" firewall
|
||||
before it starts? what if there's more than one upstream interface,
|
||||
they shouldn't wipe each other out
|
||||
|
||||
so can we have a "default deny" firewall in which every allowed flow
|
||||
is qualified by the interface name, and any service that brings up an
|
||||
interface is required to add firewall rules for it according to its
|
||||
role
|
||||
|
||||
or maybe the firewall service could watch for interfaces being added
|
||||
(and removed) and update the ruleset as appropriate for the interface
|
||||
role (lan, wan, dmz, management, guest, ???). but how does it know
|
||||
the role based on the interface name?
|
||||
|
||||
Tue Jan 14 19:33:28 GMT 2025
|
||||
|
||||
each interface can add its own chain when it comes up, and then we can
|
||||
figure out some way to jump to the correct chain (vmaps) based on
|
||||
interface name
|
||||
|
||||
% nft add map filter mydict { type ipv4_addr : verdict\; }
|
||||
% nft add element filter mydict { 192.168.0.10 : drop, 192.168.0.11 : accept }
|
||||
% nft add rule filter input ip saddr vmap @mydict
|
||||
|
||||
_but_ we might be better off declaring static "zones" (lan, world,
|
||||
dmz, guest, etc etc) with a map for each, and then replace the hardcoded
|
||||
interface names with a map lookup
|
||||
|
||||
% nft add map filter ifzone { type ifname : string ; }
|
||||
|
||||
|
||||
zones { type ifname: ipv4_addr\; }
|
||||
... and presumably we also need identical maps for nat and
|
||||
... any other chain type where we need to distinguish
|
||||
... inside from outside
|
||||
% nft add element nat porttoip { 80 : 192.168.1.100, 8888 : 192.168.1.101 }
|
||||
|
||||
% nft add rule ip nat postrouting snat to tcp dport map @porttoip
|
||||
|
||||
Mon Jan 20 20:32:58 GMT 2025
|
||||
|
||||
1) maybe we can add a type="chain" or type="set" attribute to the
|
||||
firewallgen input, then we cna have sets in the default firewall rules
|
||||
|
||||
2) then we convert the default firewall rules to use sets instead of
|
||||
hardcoding ifname
|
||||
|
||||
3) then find a nice place to hook "new interface is available" and
|
||||
add it to the appropriate zone (separately for ip4 and ip6, gah)
|
||||
|
||||
4) and how do we find
|
||||
|
||||
# nft add element ip table-ip lan { int }
|
||||
# nft add element ip table-ip wan { ppp0 }
|
||||
# nft add element ip6 table-ip6 lan { int }
|
||||
# nft add element ip6 table-ip6 wan { ppp0 }
|
||||
|
||||
Tue Jan 28 21:51:46 GMT 2025
|
||||
|
||||
Going back and forth on the firewall stuff, in respect of where to aim
|
||||
for with "general" vs "useful". Specifically, if we have hooks
|
||||
every time interfaces are added/removed that
|
||||
expect some specific sets to (a) exist and (b) have particular
|
||||
semantics, there is necessary coupling between those hooks and the
|
||||
firewall definition. So, practically speaking, the "a new interface
|
||||
appears" rules need to be bundled with the firewall ruleset
|
||||
|
||||
Which also means that the firewall needs to know which zone the
|
||||
interface is assigned to, which is a problem if it can't tell from the
|
||||
name (for example wg0 wg1 wg2 ... could be wan or lan or dmz or
|
||||
anything)
|
||||
|
||||
So the service that owns the interface needs to communicate "another
|
||||
one for the lan zone" to the firewall and it can't do that by adding
|
||||
to sets directly unless it knows what the sets are called. Implying we
|
||||
need an interface between the interface service that knows "new
|
||||
interface ppp7 added in wan zone" and the firewall service that knows
|
||||
how to accommodate this. For extra credit this actually should be more
|
||||
like pubsub: the interface shouldn't really have to know the firewall
|
||||
exists.
|
||||
|
||||
outputs?
|
||||
|
||||
- what if each interface wrote a "zone" output and the firewall
|
||||
subscribed to them? would need the firewall to know which of all the
|
||||
available services were interfaces
|
||||
|
||||
- a zone service that every interface in the zone depends on. it
|
||||
doesn't do much in itself but it means the interface updown scripts
|
||||
know a service directory where they can touch lan-zone/eth0 or
|
||||
whatever. This could work. The firewall service definition specifies
|
||||
the zone services and uses inotify watcher thingies to update
|
||||
interface sets when contents change.
|
||||
|
||||
Wed Jan 29 17:19:24 GMT 2025
|
||||
|
||||
1) make a zone service defn that can be instantiated for each zone.
|
||||
it should create $output/interfaces
|
||||
|
||||
2) add a `zone` attribute to interface definitions, causing
|
||||
- the zone service to be added to the dependencies
|
||||
- the interface "up" script to include writing to the zone/interfaces output
|
||||
|
||||
2b) any other service that creates an interface (e.g. ppp) needs to also
|
||||
have `zone` and do the same
|
||||
|
||||
3) firewallgen to be able to make sets
|
||||
|
||||
4) firewall service to watch the zone outputs
|
||||
|
||||
Fri Jan 31 17:11:16 GMT 2025
|
||||
|
||||
Do we need zone services? I think we could put zones in the outputs of
|
||||
the firewall service?
|
||||
|
||||
Sun Feb 2 20:59:56 GMT 2025
|
||||
|
||||
What's the smallest first step?
|
||||
|
||||
- [done] how can we make firewallgen output sets (or could we
|
||||
make the firewall service tack them on afterwards)
|
||||
|
||||
- make a longrun that watches its own zones output and updates the
|
||||
appropriate sets
|
||||
|
||||
The sticking point is that if you give the firewall `rules` instead of
|
||||
`extraRules` then the longrun may or may not work depending on (1)
|
||||
whether you made the zone sets; (2) whether your rules use
|
||||
them. Conclusion: if you supply `rules` then you also have to say
|
||||
whether you want the longrun or not. So add a param
|
||||
watchForInterfaceUpdates which defaults true
|
||||
|
||||
Mon Feb 3 21:12:55 GMT 2025
|
||||
|
||||
the thing that updates sets has to know they exist, so the interface watcher
|
||||
service must live in the firewall module
|
||||
|
||||
the firewall service defn should return the firewall service after
|
||||
adding the interface watcher as a dependency of it. Or: the watcher
|
||||
should make the sets and then the firewall service could depend on _it_.
|
||||
That would mean that the firewall service would fail if it used sets
|
||||
that the watcher didn't make, is that good or bad or indifferent?
|
||||
|
||||
the interface services have to know about the watcher as well in order
|
||||
to write into its outputs, so it can't be hidden inside the module
|
||||
|
||||
maybe the watcher service should _be_ the firewall service.
|
||||
|
||||
we could add a "notify" param to an interface which would be an output
|
||||
reference to (the firewall service / zones / lan ) that the interface would
|
||||
write its ifname into when the service is up
|
||||
|
||||
Wed Feb 5 00:14:29 GMT 2025
|
||||
|
||||
another thought: the firewall service could have params to say
|
||||
which interface services are in which zones
|
||||
|
||||
we'd have to ensure that the interface services did not end up as
|
||||
dependencies of the firewall
|
||||
|
||||
then the firewall could
|
||||
|
||||
- create the sets
|
||||
- watch each interface service for the ifname output and add it to the right zone
|
||||
|
||||
Sun Feb 9 21:33:57 GMT 2025
|
||||
|
||||
nft update set @lan
|
||||
|
||||
echo 'flush set table-ip lan; add element table-ip lan { eth0,lo }' | nft -f -
|
||||
|
||||
+31
-9
@@ -2,19 +2,41 @@
|
||||
# use expect as its "Script program" instead of runscript. Try
|
||||
# Ctrl+A O -> Filenames and paths -> D
|
||||
|
||||
fconfigure stderr -buffering none
|
||||
fconfigure stdout -buffering none
|
||||
|
||||
proc waitprompt { } {
|
||||
expect {
|
||||
"BusyBox" { puts stderr "DONE\r"; exit 0 }
|
||||
"READY" { puts stderr ";;; READY\r"; }
|
||||
timeout { puts stderr ";;; timed out waiting after $line\r" }
|
||||
}
|
||||
}
|
||||
|
||||
proc sendline { line } {
|
||||
send "$line; echo \$ready \r"
|
||||
sleep 0.1
|
||||
}
|
||||
|
||||
log_user 0
|
||||
log_file -a -open stderr
|
||||
|
||||
set f [open "result/boot.scr"]
|
||||
send "version\r"
|
||||
set timeout 60
|
||||
|
||||
send "setenv ready REA\r"
|
||||
sleep 0.1
|
||||
send "setenv ready \${ready}DY\r"
|
||||
sleep 0.1
|
||||
|
||||
set timeout 300
|
||||
expect_before timeout abort
|
||||
while {[gets $f line] >= 0} {
|
||||
puts stderr "next line $line\r"
|
||||
puts stderr "waiting for prompt\r"
|
||||
expect {
|
||||
"ath>" {}
|
||||
"BusyBox" { puts stderr "DONE"; exit 0 }
|
||||
}
|
||||
send "$line\r\n"
|
||||
puts stderr ";;; next line $line\r"
|
||||
puts stderr ";;; waiting for prompt\r"
|
||||
puts stderr ";;; sending\r"
|
||||
sendline $line
|
||||
waitprompt
|
||||
}
|
||||
|
||||
puts stderr "done\r\n"
|
||||
close $f
|
||||
@@ -102,12 +102,18 @@ in {
|
||||
systemd.services.sshd.wantedBy = pkgs.lib.mkForce [ "multi-user.target" ];
|
||||
|
||||
virtualisation = {
|
||||
forwardPorts = [ {
|
||||
from = "host";
|
||||
host.port = 7654;
|
||||
# guest.address = "10.0.2.15";
|
||||
guest.port =7654;
|
||||
} ];
|
||||
forwardPorts = [
|
||||
{
|
||||
from = "host";
|
||||
host.port = 7654;
|
||||
# guest.address = "10.0.2.15";
|
||||
guest.port =7654;
|
||||
}
|
||||
{
|
||||
host.port = 2222;
|
||||
guest.address = "10.0.2.15";
|
||||
guest.port = 22;
|
||||
}];
|
||||
qemu = {
|
||||
networkingOptions = [ ];
|
||||
options =
|
||||
|
||||
@@ -11,7 +11,10 @@ let
|
||||
"qemu-aarch64"
|
||||
"qemu-armv7l"
|
||||
"tp-archer-ax23"
|
||||
"openwrt-one"
|
||||
"zyxel-nwa50ax"
|
||||
"turris-omnia"
|
||||
"belkin-rt3200"
|
||||
];
|
||||
vanilla = ./vanilla-configuration.nix;
|
||||
for-device = name:
|
||||
|
||||
@@ -33,6 +33,7 @@ let
|
||||
./modules/busybox.nix
|
||||
./modules/hostname.nix
|
||||
./modules/kernel
|
||||
./modules/logging.nix
|
||||
./modules/klogd.nix
|
||||
device.module
|
||||
liminix-config
|
||||
|
||||
@@ -4,15 +4,8 @@
|
||||
******************************
|
||||
|
||||
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).
|
||||
and is mostly feature-complete in Liminix but as of Dec 2024
|
||||
has seen very little actual use.
|
||||
|
||||
Hardware summary
|
||||
================
|
||||
@@ -27,10 +20,94 @@
|
||||
Installation
|
||||
============
|
||||
|
||||
Installation is currently a manual process (you need a :ref:`serial <serial>` conection and
|
||||
TFTP) following the instructions at :ref:`system-outputs-ubimage`
|
||||
Liminix on this device uses the UBI volume management system to
|
||||
perform wear leveling on the flash. This is not set up from the
|
||||
factory, so a one-time step is needed to prepare it before Liminix
|
||||
can be installed.
|
||||
|
||||
'';
|
||||
|
||||
Preparation
|
||||
-----------
|
||||
|
||||
To prepare the device for Liminix you first need to use the
|
||||
`OpenWrt UBI Installer
|
||||
<https://github.com/dangowrt/owrt-ubi-installer>`_ image to
|
||||
rewrite the flash layout. As of Jan 2025 there are two versions
|
||||
of the installer available: the release version 1.0.2 and the
|
||||
pre-release 1.1.3 and for Liminix you nee the pre-relese.
|
||||
The release version of the installer creates UBI volumes
|
||||
according to an older layout that is not compatible with
|
||||
the Linux 6.6.67 kernel used in Liminix.
|
||||
|
||||
You can run the installer in one of two ways:
|
||||
either follow the instructions to do it through the vendor web
|
||||
interface, or you can drop to U-Boot and use TFTP
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
MT7622> setenv ipaddr 10.0.0.6
|
||||
MT7622> setenv serverip 10.0.0.1
|
||||
MT7622> tftpboot 0x42000000 openwrt-mediatek-mt7622-linksys_e8450-ubi-initramfs-recovery-installer.itb
|
||||
MT7622> bootm 0x42000000
|
||||
|
||||
This will write the new flash layout and then boot into a
|
||||
"recovery" OpenWrt installation.
|
||||
|
||||
Building/installing Liminix
|
||||
----------------
|
||||
|
||||
The default target for this device is ``outputs.ubimage`` which
|
||||
makes a ubifs image suitable for use with :command:`ubiupdatevol`.
|
||||
To write this to the device we use the OpenWrt recovery system
|
||||
installed in the previous step. In this configuration the
|
||||
device assigns itself the IP address 192.168.1.1/24 on its LAN
|
||||
ports and expects the connected computer to have 192.168.1.254
|
||||
|
||||
.. warning:: The `ubi0_7` device in these instructions is correct
|
||||
as of Dec 2024 (dangowrt/owrt-ubi-installer commit
|
||||
d79e7928). If you are installing some time later, it
|
||||
is important to check the output from
|
||||
:command:`ubinfo -a` and make sure you are updating
|
||||
the "liminix" volume and not some other one which had
|
||||
been introduced since I wrote this.
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ nix-build -I liminix-config=./my-configuration.nix --arg device "import ./devices/belkin-rt3200" -A outputs.default
|
||||
$ cat result/rootfs | ssh root@192.168.1.1 "cat > /tmp/rootfs"
|
||||
$ ssh root@192.168.1.1
|
||||
root@OpenWrt:~# ubimkvol /dev/ubi0 --name=liminix --maxavsize
|
||||
root@OpenWrt:~# ubinfo -a
|
||||
[...]
|
||||
Volume ID: 7 (on ubi0)
|
||||
Type: dynamic
|
||||
Alignment: 1
|
||||
Size: 851 LEBs (108056576 bytes, 103.0 MiB)
|
||||
State: OK
|
||||
Name: liminix
|
||||
Character device major/minor: 250:8
|
||||
root@OpenWrt:~# ubiupdatevol /dev/ubi0_7 /tmp/rootfs
|
||||
|
||||
To make the new system bootable we also need to change some U-Boot variables.
|
||||
``boot_production`` needs to mount the filesystem and boot the FIT image
|
||||
found there, and :code:`bootcmd` needs to be told _not_ to boot the rescue
|
||||
image if there are records in pstore, because that interferes with
|
||||
``config.log.persistent``
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
root@OpenWrt:~# fw_setenv orig_boot_production $(fw_printenv -n boot_production)
|
||||
root@OpenWrt:~# fw_setenv orig_bootcmd $(fw_printenv -n bootcmd)
|
||||
root@OpenWrt:~# fw_setenv boot_production 'led $bootled_pwr on ; ubifsmount ubi0:liminix && ubifsload ''${loadaddr} boot/fit && bootm ''${loadaddr}'
|
||||
root@OpenWrt:~# fw_setenv bootcmd 'run boot_ubi'
|
||||
|
||||
For subsequent Liminix reinstalls, just run the
|
||||
:command:`ubiupdatevol` command again. You don't need to repeat
|
||||
the "Preparation" step and in fact should seek to avoid it if
|
||||
possible, as it will reset the erase counters used for write
|
||||
levelling. Using UBI-aware tools is therefore preferred over any
|
||||
kind of "factory" wipe which will reset them.
|
||||
'';
|
||||
|
||||
system = {
|
||||
crossSystem = {
|
||||
@@ -39,7 +116,8 @@
|
||||
};
|
||||
|
||||
module = {pkgs, config, lib, lim, ... }:
|
||||
let firmware = pkgs.stdenv.mkDerivation {
|
||||
let inherit (lib) mkIf;
|
||||
firmware = pkgs.stdenv.mkDerivation {
|
||||
name = "wlan-firmware";
|
||||
phases = ["installPhase"];
|
||||
installPhase = ''
|
||||
@@ -47,6 +125,7 @@
|
||||
cp ${pkgs.linux-firmware}/lib/firmware/mediatek/{mt7915,mt7615,mt7622}* $out
|
||||
'';
|
||||
};
|
||||
openwrt = pkgs.openwrt_24_10;
|
||||
in {
|
||||
imports = [
|
||||
../../modules/arch/aarch64.nix
|
||||
@@ -55,14 +134,11 @@
|
||||
];
|
||||
config = {
|
||||
kernel = {
|
||||
src = pkgs.pkgsBuildBuild.fetchurl {
|
||||
name = "linux.tar.gz";
|
||||
url = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.137.tar.gz";
|
||||
hash = "sha256-PkdzUKZ0IpBiWe/RS70J76JKnBFzRblWcKlaIFNxnHQ=";
|
||||
};
|
||||
extraPatchPhase = ''
|
||||
${pkgs.openwrt.applyPatches.mediatek}
|
||||
${openwrt.applyPatches.mediatek}
|
||||
'';
|
||||
src = openwrt.kernelSrc;
|
||||
version = openwrt.kernelVersion;
|
||||
config = {
|
||||
PCI = "y";
|
||||
ARCH_MEDIATEK = "y";
|
||||
@@ -73,8 +149,8 @@
|
||||
MTK_INFRACFG = "y";
|
||||
|
||||
MTK_PMIC_WRAP = "y";
|
||||
NVMEM_MTK_EFUSE="y";
|
||||
# MTK_HSDMA="y";
|
||||
DMADEVICES = "y";
|
||||
MTK_HSDMA="y";
|
||||
MTK_SCPSYS="y";
|
||||
MTK_SCPSYS_PM_DOMAINS="y";
|
||||
# MTK_THERMAL="y";
|
||||
@@ -120,6 +196,10 @@
|
||||
MTD_SPLIT_FIRMWARE= "y";
|
||||
MTD_SPLIT_FIT_FW= "y";
|
||||
|
||||
MTD_UBI_NVMEM = "y";
|
||||
NVMEM_MTK_EFUSE = "y";
|
||||
NVMEM_BLOCK = "y";
|
||||
NVMEM_LAYOUT_ADTRAN = "y";
|
||||
|
||||
MMC = "y";
|
||||
MMC_BLOCK = "y";
|
||||
@@ -131,11 +211,7 @@
|
||||
NET_DSA="y";
|
||||
NET_DSA_MT7530="y";
|
||||
NET_DSA_TAG_MTK="y";
|
||||
|
||||
PSTORE = "y";
|
||||
PSTORE_RAM = "y";
|
||||
PSTORE_CONSOLE = "y";
|
||||
PSTORE_DEFLATE_COMPRESS = "n";
|
||||
NET_DSA_MT7530_MDIO="y";
|
||||
|
||||
SERIAL_8250 = "y";
|
||||
SERIAL_8250_CONSOLE = "y";
|
||||
@@ -158,9 +234,11 @@
|
||||
};
|
||||
boot = {
|
||||
commandLine = [ "console=ttyS0,115200" ];
|
||||
tftp.loadAddress = lim.parseInt "0x4007ff28";
|
||||
tftp.loadAddress = lim.parseInt "0x48000000";
|
||||
imageFormat = "fit";
|
||||
loader.fit.enable = lib.mkDefault true; # override this if you are building tftpboot
|
||||
};
|
||||
rootfsType = lib.mkDefault "ubifs"; # override this if you are building tftpboot
|
||||
filesystem =
|
||||
let inherit (pkgs.pseudofile) dir symlink;
|
||||
in
|
||||
@@ -174,7 +252,6 @@
|
||||
|
||||
hardware =
|
||||
let
|
||||
openwrt = pkgs.openwrt;
|
||||
mac80211 = pkgs.kmodloader.override {
|
||||
targets = ["mt7615e" "mt7915e"];
|
||||
inherit (config.system.outputs) kernel;
|
||||
@@ -182,7 +259,8 @@
|
||||
in {
|
||||
ubi = {
|
||||
minIOSize = "2048";
|
||||
eraseBlockSize = "126976";
|
||||
logicalEraseBlockSize = "126976";
|
||||
physicalEraseBlockSize = "131072";
|
||||
maxLEBcount = "1024"; # guessing
|
||||
};
|
||||
|
||||
@@ -197,10 +275,13 @@
|
||||
rootDevice = "ubi0:liminix";
|
||||
dts = {
|
||||
src = "${openwrt.src}/target/linux/mediatek/dts/mt7622-linksys-e8450-ubi.dts";
|
||||
includes = [
|
||||
includePaths = [
|
||||
"${openwrt.src}/target/linux/mediatek/dts"
|
||||
"${config.system.outputs.kernel.modulesupport}/arch/arm64/boot/dts/mediatek/"
|
||||
];
|
||||
includes = mkIf config.logging.persistent.enable [
|
||||
./pstore-pmsg.dtsi
|
||||
];
|
||||
};
|
||||
|
||||
# - 0x000000000000-0x000008000000 : "spi-nand0"
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
/ {
|
||||
reserved-memory {
|
||||
/* make sure address matches upstream */
|
||||
ramoops@42ff0000 {
|
||||
pmsg-size = <0x10000>;
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -5,11 +5,6 @@
|
||||
];
|
||||
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";
|
||||
|
||||
@@ -41,10 +41,11 @@
|
||||
: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.
|
||||
Flashing over an existing Liminix system is not possible while
|
||||
that system is running, otherwise you'll be overwriting flash
|
||||
partitions while they're in use - and that might not end well.
|
||||
Configure the system with :ref:`levitate` if you need to
|
||||
make it upgradable.
|
||||
|
||||
Vendor web page: https://www.gl-inet.com/products/gl-ar750/
|
||||
|
||||
@@ -52,8 +53,9 @@
|
||||
|
||||
'';
|
||||
|
||||
module = {pkgs, config, lim, ... }:
|
||||
module = {pkgs, config, lim, lib, ... }:
|
||||
let
|
||||
inherit (lib) mkIf;
|
||||
openwrt = pkgs.openwrt;
|
||||
firmwareBlobs = pkgs.pkgsBuildBuild.fetchFromGitHub {
|
||||
owner = "kvalo";
|
||||
@@ -116,9 +118,12 @@
|
||||
rootDevice = "/dev/mtdblock5";
|
||||
dts = {
|
||||
src = "${openwrt.src}/target/linux/ath79/dts/qca9531_glinet_gl-ar750.dts";
|
||||
includes = [
|
||||
includePaths = [
|
||||
"${openwrt.src}/target/linux/ath79/dts"
|
||||
];
|
||||
includes = mkIf config.logging.persistent.enable [
|
||||
./pstore-ramoops.dtsi
|
||||
];
|
||||
};
|
||||
|
||||
networkInterfaces =
|
||||
@@ -157,12 +162,6 @@
|
||||
appendDTB = true;
|
||||
};
|
||||
kernel = {
|
||||
src = pkgs.pkgsBuildBuild.fetchurl {
|
||||
name = "linux.tar.gz";
|
||||
url = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.137.tar.gz";
|
||||
hash = "sha256-PkdzUKZ0IpBiWe/RS70J76JKnBFzRblWcKlaIFNxnHQ=";
|
||||
};
|
||||
|
||||
# Mainline linux 5.19 doesn't have device-tree support for
|
||||
# this device or even for the SoC, so we use the extensive
|
||||
# OpenWrt kernel patches
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
/ {
|
||||
reserved-memory {
|
||||
ramoops@03f00000 {
|
||||
compatible = "ramoops";
|
||||
reg = <0x03f00000 0x10000>;
|
||||
pmsg-size = <0x10000>;
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -32,10 +32,11 @@
|
||||
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.
|
||||
Flashing over an existing Liminix system is not possible while
|
||||
that system is running, otherwise you'll be overwriting flash
|
||||
partitions while they're in use - and that might not end well.
|
||||
Configure the system with :ref:`levitate` if you need to
|
||||
make it upgradable.
|
||||
|
||||
Vendor web page: https://www.gl-inet.com/products/gl-mt300a/
|
||||
|
||||
@@ -81,7 +82,7 @@
|
||||
|
||||
dts = {
|
||||
src = "${openwrt.src}/target/linux/ramips/dts/mt7620a_glinet_gl-mt300a.dts";
|
||||
includes = [
|
||||
includePaths = [
|
||||
"${openwrt.src}/target/linux/ramips/dts"
|
||||
];
|
||||
};
|
||||
@@ -114,11 +115,6 @@
|
||||
};
|
||||
|
||||
kernel = {
|
||||
src = pkgs.fetchurl {
|
||||
name = "linux.tar.gz";
|
||||
url = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.137.tar.gz";
|
||||
hash = "sha256-PkdzUKZ0IpBiWe/RS70J76JKnBFzRblWcKlaIFNxnHQ=";
|
||||
};
|
||||
extraPatchPhase = ''
|
||||
${openwrt.applyPatches.ramips}
|
||||
${openwrt.applyPatches.rt2x00}
|
||||
|
||||
@@ -25,10 +25,11 @@
|
||||
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.
|
||||
Flashing over an existing Liminix system is not possible while
|
||||
that system is running, otherwise you'll be overwriting flash
|
||||
partitions while they're in use - and that might not end well.
|
||||
Configure the system with :ref:`levitate` if you need to
|
||||
make it upgradable.
|
||||
|
||||
Vendor web page: https://www.gl-inet.com/products/gl-mt300n-v2/
|
||||
|
||||
@@ -78,7 +79,7 @@
|
||||
|
||||
dts = {
|
||||
src = "${openwrt.src}/target/linux/ramips/dts/mt7628an_glinet_gl-mt300n-v2.dts";
|
||||
includes = [
|
||||
includePaths = [
|
||||
"${openwrt.src}/target/linux/ramips/dts"
|
||||
];
|
||||
};
|
||||
@@ -125,11 +126,6 @@
|
||||
};
|
||||
|
||||
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}
|
||||
'';
|
||||
|
||||
@@ -0,0 +1,739 @@
|
||||
{
|
||||
description = ''
|
||||
OpenWrt One
|
||||
***********
|
||||
|
||||
Hardware summary
|
||||
================
|
||||
|
||||
- MediaTek MT7981B (1300MHz)
|
||||
- 256MB NAND Flash
|
||||
- 1024MB RAM
|
||||
- WLan hardware: Mediatek MT7976C
|
||||
|
||||
Status
|
||||
======
|
||||
|
||||
- Only tested over TFTP so far.
|
||||
- WiFi (2.4G and 5G) works.
|
||||
- 2.5G ethernet port works.
|
||||
|
||||
Limitations
|
||||
===========
|
||||
|
||||
- adding `he_bss_color="128"` causes `Invalid argument` for hostap
|
||||
- nvme support untested
|
||||
- I don't think the front LEDs work yet
|
||||
|
||||
Installation
|
||||
============
|
||||
|
||||
TODO: add instructions on how to boot directly from TFTP to memory
|
||||
and how to install from TFTP to flash without going through OpenWrt.
|
||||
|
||||
The instructions below assume you can boot and SSH into OpenWrt:
|
||||
|
||||
Boot into OpenWrt and create a 'liminix' UBI partition:
|
||||
|
||||
root@OpenWrt:~# ubimkvol /dev/ubi0 --name=liminix --maxavsize
|
||||
|
||||
Remember the 'Volume ID' that was created for this new partition
|
||||
|
||||
Build the UBI image and write it to this new partition:
|
||||
|
||||
$ nix-build -I liminix-config=./my-configuration.nix --arg device "import ./devices/openwrt-one" -A outputs.default
|
||||
$ cat result/rootfs | ssh root@192.168.1.1 "cat > /tmp/rootfs"
|
||||
$ ssh root@192.168.1.1
|
||||
root@OpenWrt:~# ubiupdatevol /dev/ubi0_X /tmp/rootfs # replace X with the volume id, if needed check with `ubinfo`
|
||||
|
||||
Reboot into the U-Boot prompt and boot with:
|
||||
|
||||
OpenWrt One> ubifsmount ubi0:liminix && ubifsload ''${loadaddr} boot/fit && bootm ''${loadaddr}'
|
||||
|
||||
If this works, reboot into OpenWrt and configure U-Boot to boot ubifs by default:
|
||||
|
||||
root@OpenWrt:~# fw_setenv orig_boot_production $(fw_printenv -n boot_production)
|
||||
root@OpenWrt:~# fw_setenv boot_production 'led white on ; ubifsmount ubi0:liminix && ubifsload ''${loadaddr} boot/fit && bootm ''${loadaddr}'
|
||||
|
||||
Troubleshooting
|
||||
===============
|
||||
|
||||
The instructions above assume you can boot and SSH into the (recovery)
|
||||
OpenWrt installation. If you have broken your device to the point where that
|
||||
is no longer possible, you could re-install OpenWrt, but probably you could
|
||||
also install directly from U-Boot:
|
||||
|
||||
https://github.com/u-boot/u-boot/blob/master/doc/README.ubi
|
||||
'';
|
||||
|
||||
system = {
|
||||
crossSystem = {
|
||||
config = "aarch64-unknown-linux-musl";
|
||||
gcc = {
|
||||
# https://openwrt.org/docs/techref/instructionset/aarch64_cortex-a53
|
||||
# openwrt ./target/linux/mediatek/filogic/target.mk
|
||||
# https://gcc.gnu.org/onlinedocs/gcc/AArch64-Options.html
|
||||
# https://en.wikipedia.org/wiki/Comparison_of_ARM_processors
|
||||
arch = "armv8-a";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
module = {pkgs, config, lib, lim, ... }:
|
||||
let
|
||||
openwrt = pkgs.openwrt_24_10;
|
||||
mediatek-firmware = pkgs.stdenv.mkDerivation {
|
||||
name = "wlan-firmware";
|
||||
phases = ["installPhase"];
|
||||
installPhase = ''
|
||||
mkdir $out
|
||||
|
||||
cp ${pkgs.linux-firmware}/lib/firmware/mediatek/{mt7915,mt7615,mt7986_eeprom_mt7976,mt7981}* $out
|
||||
'';
|
||||
};
|
||||
airoha-firmware = pkgs.stdenv.mkDerivation {
|
||||
name = "airoha-firmware";
|
||||
phases = ["installPhase"];
|
||||
installPhase = ''
|
||||
mkdir $out
|
||||
|
||||
cp ${pkgs.linux-firmware}/lib/firmware/airoha/* $out
|
||||
'';
|
||||
};
|
||||
in {
|
||||
imports = [
|
||||
../../modules/arch/aarch64.nix
|
||||
../../modules/outputs/tftpboot.nix
|
||||
../../modules/outputs/ubifs.nix
|
||||
];
|
||||
config = {
|
||||
kernel = {
|
||||
src = openwrt.kernelSrc;
|
||||
version = openwrt.kernelVersion;
|
||||
extraPatchPhase = ''
|
||||
${openwrt.applyPatches.mediatek}
|
||||
'';
|
||||
config = {
|
||||
NET="y"; # unlock NET_XGRESS
|
||||
SERIAL_8250="y"; # unlock SERIAL_8250_FSL
|
||||
SERIAL_8250_CONSOLE="y"; # to get the serial console
|
||||
WATCHDOG="y"; # unlock WATCHDOG_CORE
|
||||
NEW_LEDS="y"; # unlock LEDS_PWM
|
||||
LEDS_CLASS="y"; # unlock LEDS_PWM
|
||||
LEDS_TRIGGERS="y"; # unlock LEDS_TRIGGER_PATTERN
|
||||
DEFERRED_STRUCT_PAGE_INIT="y"; # trigger PADATA
|
||||
# Taken from openwrt's ./target/linux/mediatek/filogic/config-6.6
|
||||
"64BIT"="y";
|
||||
AIROHA_EN8801SC_PHY="y";
|
||||
ARCH_BINFMT_ELF_EXTRA_PHDRS="y";
|
||||
ARCH_CORRECT_STACKTRACE_ON_KRETPROBE="y";
|
||||
ARCH_DEFAULT_KEXEC_IMAGE_VERIFY_SIG="y";
|
||||
ARCH_DMA_ADDR_T_64BIT="y";
|
||||
ARCH_FORCE_MAX_ORDER="10";
|
||||
ARCH_KEEP_MEMBLOCK="y";
|
||||
ARCH_MEDIATEK="y";
|
||||
ARCH_MHP_MEMMAP_ON_MEMORY_ENABLE="y";
|
||||
ARCH_MMAP_RND_BITS="18";
|
||||
ARCH_MMAP_RND_BITS_MAX="24";
|
||||
ARCH_MMAP_RND_BITS_MIN="18";
|
||||
ARCH_MMAP_RND_COMPAT_BITS_MIN="11";
|
||||
ARCH_PROC_KCORE_TEXT="y";
|
||||
ARCH_SPARSEMEM_ENABLE="y";
|
||||
ARCH_STACKWALK="y";
|
||||
ARCH_SUSPEND_POSSIBLE="y";
|
||||
ARCH_WANTS_NO_INSTR="y";
|
||||
ARCH_WANTS_THP_SWAP="y";
|
||||
ARM64="y";
|
||||
ARM64_4K_PAGES="y";
|
||||
ARM64_ERRATUM_843419="y";
|
||||
ARM64_LD_HAS_FIX_ERRATUM_843419="y";
|
||||
ARM64_PAGE_SHIFT="12";
|
||||
ARM64_PA_BITS="48";
|
||||
ARM64_PA_BITS_48="y";
|
||||
ARM64_TAGGED_ADDR_ABI="y";
|
||||
ARM64_VA_BITS="39";
|
||||
ARM64_VA_BITS_39="y";
|
||||
ARM_AMBA="y";
|
||||
ARM_ARCH_TIMER="y";
|
||||
ARM_ARCH_TIMER_EVTSTREAM="y";
|
||||
ARM_GIC="y";
|
||||
ARM_GIC_V2M="y";
|
||||
ARM_GIC_V3="y";
|
||||
ARM_GIC_V3_ITS="y";
|
||||
ARM_GIC_V3_ITS_PCI="y";
|
||||
ARM_MEDIATEK_CPUFREQ="y";
|
||||
ARM_PMU="y";
|
||||
ARM_PMUV3="y";
|
||||
ARM_PSCI_FW="y";
|
||||
ATA="y";
|
||||
AUDIT_ARCH_COMPAT_GENERIC="y";
|
||||
BLK_DEV_LOOP="y";
|
||||
BLK_DEV_SD="y";
|
||||
BLK_MQ_PCI="y";
|
||||
BLK_PM="y";
|
||||
BLOCK_NOTIFIERS="y";
|
||||
BSD_PROCESS_ACCT="y";
|
||||
BSD_PROCESS_ACCT_V3="y";
|
||||
BUFFER_HEAD="y";
|
||||
BUILTIN_RETURN_ADDRESS_STRIPS_PAC="y";
|
||||
CC_HAVE_SHADOW_CALL_STACK="y";
|
||||
CC_HAVE_STACKPROTECTOR_SYSREG="y";
|
||||
#CC_IMPLICIT_FALLTHROUGH="-Wimplicit-fallthrough=5";
|
||||
CC_NO_ARRAY_BOUNDS="y";
|
||||
CLKSRC_MMIO="y";
|
||||
CLONE_BACKWARDS="y";
|
||||
CMDLINE_OVERRIDE="y";
|
||||
COMMON_CLK="y";
|
||||
COMMON_CLK_MEDIATEK="y";
|
||||
COMMON_CLK_MT7981="y";
|
||||
COMMON_CLK_MT7981_ETHSYS="y";
|
||||
COMMON_CLK_MT7986="y";
|
||||
COMMON_CLK_MT7986_ETHSYS="y";
|
||||
COMMON_CLK_MT7988="y";
|
||||
COMPACT_UNEVICTABLE_DEFAULT="1";
|
||||
CONFIGFS_FS="y";
|
||||
CONSOLE_LOGLEVEL_DEFAULT="15";
|
||||
CONTEXT_TRACKING="y";
|
||||
CONTEXT_TRACKING_IDLE="y";
|
||||
CPU_FREQ="y";
|
||||
CPU_FREQ_DEFAULT_GOV_USERSPACE="y";
|
||||
CPU_FREQ_GOV_ATTR_SET="y";
|
||||
CPU_FREQ_GOV_COMMON="y";
|
||||
CPU_FREQ_GOV_CONSERVATIVE="y";
|
||||
CPU_FREQ_GOV_ONDEMAND="y";
|
||||
CPU_FREQ_GOV_PERFORMANCE="y";
|
||||
CPU_FREQ_GOV_POWERSAVE="y";
|
||||
CPU_FREQ_GOV_SCHEDUTIL="y";
|
||||
CPU_FREQ_GOV_USERSPACE="y";
|
||||
CPU_FREQ_STAT="y";
|
||||
CPU_LITTLE_ENDIAN="y";
|
||||
CPU_RMAP="y";
|
||||
CPU_THERMAL="y";
|
||||
CRC16="y";
|
||||
CRC_CCITT="y";
|
||||
CRYPTO_AES_ARM64="y";
|
||||
CRYPTO_AES_ARM64_CE="y";
|
||||
CRYPTO_AES_ARM64_CE_BLK="y";
|
||||
CRYPTO_AES_ARM64_CE_CCM="y";
|
||||
CRYPTO_CMAC="y";
|
||||
CRYPTO_CRC32="y";
|
||||
CRYPTO_CRC32C="y";
|
||||
CRYPTO_CRYPTD="y";
|
||||
CRYPTO_DEFLATE="y";
|
||||
CRYPTO_DRBG="y";
|
||||
CRYPTO_DRBG_HMAC="y";
|
||||
CRYPTO_DRBG_MENU="y";
|
||||
CRYPTO_ECB="y";
|
||||
CRYPTO_ECC="y";
|
||||
CRYPTO_ECDH="y";
|
||||
CRYPTO_GHASH_ARM64_CE="y";
|
||||
CRYPTO_HASH_INFO="y";
|
||||
CRYPTO_HMAC="y";
|
||||
CRYPTO_JITTERENTROPY="y";
|
||||
CRYPTO_LIB_BLAKE2S_GENERIC="y";
|
||||
CRYPTO_LIB_GF128MUL="y";
|
||||
CRYPTO_LIB_SHA1="y";
|
||||
CRYPTO_LIB_SHA256="y";
|
||||
CRYPTO_LIB_UTILS="y";
|
||||
CRYPTO_LZO="y";
|
||||
CRYPTO_RNG="y";
|
||||
CRYPTO_RNG2="y";
|
||||
CRYPTO_RNG_DEFAULT="y";
|
||||
CRYPTO_SHA256="y";
|
||||
CRYPTO_SHA256_ARM64="y";
|
||||
CRYPTO_SHA2_ARM64_CE="y";
|
||||
CRYPTO_SHA3="y";
|
||||
CRYPTO_SHA512="y";
|
||||
CRYPTO_SM4="y";
|
||||
CRYPTO_SM4_ARM64_CE_BLK="y";
|
||||
CRYPTO_SM4_ARM64_CE_CCM="y";
|
||||
CRYPTO_SM4_ARM64_CE_GCM="y";
|
||||
CRYPTO_ZSTD="y";
|
||||
DCACHE_WORD_ACCESS="y";
|
||||
#DEBUG_INFO="y";
|
||||
DEBUG_MISC="y";
|
||||
DIMLIB="y";
|
||||
DMADEVICES="y";
|
||||
DMATEST="y";
|
||||
DMA_BOUNCE_UNALIGNED_KMALLOC="y";
|
||||
DMA_DIRECT_REMAP="y";
|
||||
DMA_ENGINE="y";
|
||||
DMA_ENGINE_RAID="y";
|
||||
DMA_OF="y";
|
||||
DMA_VIRTUAL_CHANNELS="y";
|
||||
DTC="y";
|
||||
EDAC_SUPPORT="y";
|
||||
EINT_MTK="y";
|
||||
EXCLUSIVE_SYSTEM_RAM="y";
|
||||
EXT4_FS="y";
|
||||
F2FS_FS="y";
|
||||
FIXED_PHY="y";
|
||||
FIX_EARLYCON_MEM="y";
|
||||
FRAME_POINTER="y";
|
||||
FS_IOMAP="y";
|
||||
FS_MBCACHE="y";
|
||||
FUNCTION_ALIGNMENT="4";
|
||||
FUNCTION_ALIGNMENT_4B="y";
|
||||
FWNODE_MDIO="y";
|
||||
FW_LOADER_PAGED_BUF="y";
|
||||
#FW_LOADER_SYSFS="y";
|
||||
#GCC11_NO_ARRAY_BOUNDS="y";
|
||||
#GCC_ASM_GOTO_OUTPUT_WORKAROUND="y";
|
||||
GCC_SUPPORTS_DYNAMIC_FTRACE_WITH_ARGS="y";
|
||||
GENERIC_ALLOCATOR="y";
|
||||
GENERIC_ARCH_TOPOLOGY="y";
|
||||
GENERIC_BUG="y";
|
||||
GENERIC_BUG_RELATIVE_POINTERS="y";
|
||||
GENERIC_CLOCKEVENTS="y";
|
||||
GENERIC_CLOCKEVENTS_BROADCAST="y";
|
||||
GENERIC_CPU_AUTOPROBE="y";
|
||||
GENERIC_CPU_VULNERABILITIES="y";
|
||||
GENERIC_CSUM="y";
|
||||
GENERIC_EARLY_IOREMAP="y";
|
||||
GENERIC_GETTIMEOFDAY="y";
|
||||
GENERIC_IDLE_POLL_SETUP="y";
|
||||
GENERIC_IOREMAP="y";
|
||||
GENERIC_IRQ_EFFECTIVE_AFF_MASK="y";
|
||||
GENERIC_IRQ_SHOW="y";
|
||||
GENERIC_IRQ_SHOW_LEVEL="y";
|
||||
GENERIC_LIB_DEVMEM_IS_ALLOWED="y";
|
||||
GENERIC_MSI_IRQ="y";
|
||||
GENERIC_PCI_IOMAP="y";
|
||||
GENERIC_PHY="y";
|
||||
GENERIC_PINCONF="y";
|
||||
GENERIC_PINCTRL_GROUPS="y";
|
||||
GENERIC_PINMUX_FUNCTIONS="y";
|
||||
GENERIC_SCHED_CLOCK="y";
|
||||
GENERIC_SMP_IDLE_THREAD="y";
|
||||
GENERIC_STRNCPY_FROM_USER="y";
|
||||
GENERIC_STRNLEN_USER="y";
|
||||
GENERIC_TIME_VSYSCALL="y";
|
||||
GLOB="y";
|
||||
GPIO_CDEV="y";
|
||||
GPIO_WATCHDOG="y";
|
||||
GPIO_WATCHDOG_ARCH_INITCALL="y";
|
||||
GRO_CELLS="y";
|
||||
HARDIRQS_SW_RESEND="y";
|
||||
HAS_DMA="y";
|
||||
HAS_IOMEM="y";
|
||||
HAS_IOPORT="y";
|
||||
HAS_IOPORT_MAP="y";
|
||||
HWMON="y";
|
||||
HW_RANDOM="y";
|
||||
HW_RANDOM_MTK="y";
|
||||
I2C="y";
|
||||
I2C_BOARDINFO="y";
|
||||
I2C_CHARDEV="y";
|
||||
I2C_MT65XX="y";
|
||||
ICPLUS_PHY="y";
|
||||
ILLEGAL_POINTER_VALUE="0xdead000000000000";
|
||||
#INITRAMFS_SOURCE="""";
|
||||
IRQCHIP="y";
|
||||
IRQ_DOMAIN="y";
|
||||
IRQ_DOMAIN_HIERARCHY="y";
|
||||
IRQ_FORCED_THREADING="y";
|
||||
IRQ_TIME_ACCOUNTING="y";
|
||||
IRQ_WORK="y";
|
||||
JBD2="y";
|
||||
JUMP_LABEL="y";
|
||||
LEDS_PWM="y";
|
||||
LEDS_SMARTRG_LED="y";
|
||||
LIBFDT="y";
|
||||
LOCK_DEBUGGING_SUPPORT="y";
|
||||
LOCK_SPIN_ON_OWNER="y";
|
||||
LZO_COMPRESS="y";
|
||||
LZO_DECOMPRESS="y";
|
||||
MAGIC_SYSRQ="y";
|
||||
MAXLINEAR_GPHY="y";
|
||||
MDIO_BUS="y";
|
||||
MDIO_DEVICE="y";
|
||||
MDIO_DEVRES="y";
|
||||
MEDIATEK_2P5GE_PHY="y";
|
||||
MEDIATEK_GE_PHY="y";
|
||||
MEDIATEK_GE_SOC_PHY="y";
|
||||
MEDIATEK_WATCHDOG="y";
|
||||
MESSAGE_LOGLEVEL_DEFAULT="7";
|
||||
MFD_SYSCON="y";
|
||||
MIGRATION="y";
|
||||
MMC="y";
|
||||
MMC_BLOCK="y";
|
||||
MMC_CQHCI="y";
|
||||
MMC_MTK="y";
|
||||
MMU_LAZY_TLB_REFCOUNT="y";
|
||||
MODULES_TREE_LOOKUP="y";
|
||||
MODULES_USE_ELF_RELA="y";
|
||||
MTD_NAND_CORE="y";
|
||||
MTD_NAND_ECC="y";
|
||||
MTD_NAND_ECC_MEDIATEK="y";
|
||||
MTD_NAND_ECC_SW_HAMMING="y";
|
||||
MTD_NAND_MTK="y";
|
||||
MTD_NAND_MTK_BMT="y";
|
||||
MTD_PARSER_TRX="y";
|
||||
MTD_RAW_NAND="y";
|
||||
MTD_SPI_NAND="y";
|
||||
MTD_SPI_NOR="y";
|
||||
MTD_SPLIT_FIRMWARE="y";
|
||||
MTD_SPLIT_FIT_FW="y";
|
||||
MTD_UBI="y";
|
||||
MTD_UBI_BEB_LIMIT="20";
|
||||
MTD_UBI_BLOCK="y";
|
||||
MTD_UBI_FASTMAP="y";
|
||||
MTD_UBI_NVMEM="y";
|
||||
MTD_UBI_WL_THRESHOLD="4096";
|
||||
MTK_CPUX_TIMER="y";
|
||||
MTK_HSDMA="y";
|
||||
MTK_INFRACFG="y";
|
||||
MTK_LVTS_THERMAL="y";
|
||||
MTK_LVTS_THERMAL_DEBUGFS="y";
|
||||
MTK_PMIC_WRAP="y";
|
||||
MTK_REGULATOR_COUPLER="y";
|
||||
MTK_SCPSYS="y";
|
||||
MTK_SCPSYS_PM_DOMAINS="y";
|
||||
MTK_SOC_THERMAL="y";
|
||||
MTK_THERMAL="y";
|
||||
MTK_TIMER="y";
|
||||
MUTEX_SPIN_ON_OWNER="y";
|
||||
NEED_DMA_MAP_STATE="y";
|
||||
NEED_SG_DMA_LENGTH="y";
|
||||
NET_DEVLINK="y";
|
||||
NET_DSA="y";
|
||||
NET_DSA_MT7530="y";
|
||||
NET_DSA_MT7530_MDIO="y";
|
||||
NET_DSA_MT7530_MMIO="y";
|
||||
NET_DSA_TAG_MTK="y";
|
||||
#NET_EGRESS="y";
|
||||
NET_FLOW_LIMIT="y";
|
||||
#NET_INGRESS="y";
|
||||
NET_MEDIATEK_SOC="y";
|
||||
NET_MEDIATEK_SOC_WED="y";
|
||||
NET_SELFTESTS="y";
|
||||
NET_SWITCHDEV="y";
|
||||
NET_VENDOR_MEDIATEK="y";
|
||||
#NET_XGRESS="y";
|
||||
NLS="y";
|
||||
NO_HZ_COMMON="y";
|
||||
NO_HZ_IDLE="y";
|
||||
NR_CPUS="4";
|
||||
NVMEM="y";
|
||||
NVMEM_BLOCK="y";
|
||||
NVMEM_LAYOUTS="y";
|
||||
NVMEM_LAYOUT_ADTRAN="y";
|
||||
NVMEM_MTK_EFUSE="y";
|
||||
NVMEM_SYSFS="y";
|
||||
OF="y";
|
||||
OF_ADDRESS="y";
|
||||
OF_DYNAMIC="y";
|
||||
OF_EARLY_FLATTREE="y";
|
||||
OF_FLATTREE="y";
|
||||
OF_GPIO="y";
|
||||
OF_IRQ="y";
|
||||
OF_KOBJ="y";
|
||||
OF_MDIO="y";
|
||||
OF_OVERLAY="y";
|
||||
OF_RESOLVE="y";
|
||||
PADATA="y";
|
||||
PAGE_POOL="y";
|
||||
PAGE_POOL_STATS="y";
|
||||
PAGE_SIZE_LESS_THAN_256KB="y";
|
||||
PAGE_SIZE_LESS_THAN_64KB="y";
|
||||
#PAHOLE_HAS_LANG_EXCLUDE="y";
|
||||
PARTITION_PERCPU="y";
|
||||
PCI="y";
|
||||
PCIEAER="y";
|
||||
PCIEASPM="y";
|
||||
PCIEASPM_PERFORMANCE="y";
|
||||
PCIEPORTBUS="y";
|
||||
PCIE_MEDIATEK_GEN3="y";
|
||||
PCIE_PME="y";
|
||||
PCI_DEBUG="y";
|
||||
PCI_DOMAINS="y";
|
||||
PCI_DOMAINS_GENERIC="y";
|
||||
PCI_MSI="y";
|
||||
PCS_MTK_LYNXI="y";
|
||||
PCS_MTK_USXGMII="y";
|
||||
PERF_EVENTS="y";
|
||||
PER_VMA_LOCK="y";
|
||||
PGTABLE_LEVELS="3";
|
||||
PHYLIB="y";
|
||||
PHYLIB_LEDS="y";
|
||||
PHYLINK="y";
|
||||
PHYS_ADDR_T_64BIT="y";
|
||||
PHY_MTK_TPHY="y";
|
||||
PHY_MTK_XFI_TPHY="y";
|
||||
PHY_MTK_XSPHY="y";
|
||||
PINCTRL="y";
|
||||
PINCTRL_MT7981="y";
|
||||
PINCTRL_MT7986="y";
|
||||
PINCTRL_MT7988="y";
|
||||
PINCTRL_MTK_MOORE="y";
|
||||
PINCTRL_MTK_V2="y";
|
||||
PM="y";
|
||||
PM_CLK="y";
|
||||
PM_GENERIC_DOMAINS="y";
|
||||
PM_GENERIC_DOMAINS_OF="y";
|
||||
PM_OPP="y";
|
||||
POLYNOMIAL="y";
|
||||
POSIX_CPU_TIMERS_TASK_WORK="y";
|
||||
POWER_RESET="y";
|
||||
POWER_RESET_SYSCON="y";
|
||||
POWER_SUPPLY="y";
|
||||
PREEMPT_NONE_BUILD="y";
|
||||
PRINTK_TIME="y";
|
||||
PSTORE="y";
|
||||
PSTORE_COMPRESS="y";
|
||||
PSTORE_CONSOLE="y";
|
||||
PSTORE_PMSG="y";
|
||||
PSTORE_RAM="y";
|
||||
PTP_1588_CLOCK_OPTIONAL="y";
|
||||
PWM="y";
|
||||
PWM_MEDIATEK="y";
|
||||
PWM_SYSFS="y";
|
||||
QUEUED_RWLOCKS="y";
|
||||
QUEUED_SPINLOCKS="y";
|
||||
RANDSTRUCT_NONE="y";
|
||||
RAS="y";
|
||||
RATIONAL="y";
|
||||
REALTEK_PHY="y";
|
||||
REED_SOLOMON="y";
|
||||
REED_SOLOMON_DEC8="y";
|
||||
REED_SOLOMON_ENC8="y";
|
||||
REGMAP="y";
|
||||
REGMAP_I2C="y";
|
||||
REGMAP_MMIO="y";
|
||||
REGULATOR="y";
|
||||
REGULATOR_FIXED_VOLTAGE="y";
|
||||
REGULATOR_MT6380="y";
|
||||
REGULATOR_RT5190A="y";
|
||||
RESET_CONTROLLER="y";
|
||||
RESET_TI_SYSCON="y";
|
||||
RFS_ACCEL="y";
|
||||
RODATA_FULL_DEFAULT_ENABLED="y";
|
||||
RPS="y";
|
||||
RTC_CLASS="y";
|
||||
RTC_DRV_MT7622="y";
|
||||
RTC_I2C_AND_SPI="y";
|
||||
RWSEM_SPIN_ON_OWNER="y";
|
||||
SCHED_MC="y";
|
||||
SCSI="y";
|
||||
SCSI_COMMON="y";
|
||||
SERIAL_8250_FSL="y";
|
||||
SERIAL_8250_MT6577="y";
|
||||
SERIAL_8250_NR_UARTS="3";
|
||||
SERIAL_8250_RUNTIME_UARTS="3";
|
||||
SERIAL_DEV_BUS="y";
|
||||
SERIAL_DEV_CTRL_TTYPORT="y";
|
||||
SERIAL_MCTRL_GPIO="y";
|
||||
SERIAL_OF_PLATFORM="y";
|
||||
SGL_ALLOC="y";
|
||||
SG_POOL="y";
|
||||
SMP="y";
|
||||
SOCK_RX_QUEUE_MAPPING="y";
|
||||
SOFTIRQ_ON_OWN_STACK="y";
|
||||
SPARSEMEM="y";
|
||||
SPARSEMEM_EXTREME="y";
|
||||
SPARSEMEM_VMEMMAP="y";
|
||||
SPARSEMEM_VMEMMAP_ENABLE="y";
|
||||
SPARSE_IRQ="y";
|
||||
SPI="y";
|
||||
SPI_DYNAMIC="y";
|
||||
SPI_MASTER="y";
|
||||
SPI_MEM="y";
|
||||
SPI_MT65XX="y";
|
||||
SPI_MTK_SNFI="y";
|
||||
#SQUASHFS_DECOMP_MULTI_PERCPU="y";
|
||||
SWIOTLB="y";
|
||||
SWPHY="y";
|
||||
SYSCTL_EXCEPTION_TRACE="y";
|
||||
THERMAL="y";
|
||||
THERMAL_DEFAULT_GOV_STEP_WISE="y";
|
||||
THERMAL_EMERGENCY_POWEROFF_DELAY_MS="0";
|
||||
THERMAL_GOV_BANG_BANG="y";
|
||||
THERMAL_GOV_FAIR_SHARE="y";
|
||||
THERMAL_GOV_STEP_WISE="y";
|
||||
THERMAL_GOV_USER_SPACE="y";
|
||||
THERMAL_HWMON="y";
|
||||
THERMAL_OF="y";
|
||||
THERMAL_WRITABLE_TRIPS="y";
|
||||
THREAD_INFO_IN_TASK="y";
|
||||
TICK_CPU_ACCOUNTING="y";
|
||||
TIMER_OF="y";
|
||||
TIMER_PROBE="y";
|
||||
TRACE_IRQFLAGS_NMI_SUPPORT="y";
|
||||
TREE_RCU="y";
|
||||
TREE_SRCU="y";
|
||||
UBIFS_FS="y";
|
||||
UIMAGE_FIT_BLK="y";
|
||||
USB_SUPPORT="y";
|
||||
VMAP_STACK="y";
|
||||
WATCHDOG_CORE="y";
|
||||
WATCHDOG_PRETIMEOUT_DEFAULT_GOV_PANIC="y";
|
||||
WATCHDOG_PRETIMEOUT_GOV="y";
|
||||
WATCHDOG_PRETIMEOUT_GOV_PANIC="y";
|
||||
WATCHDOG_PRETIMEOUT_GOV_SEL="m";
|
||||
WATCHDOG_SYSFS="y";
|
||||
XPS="y";
|
||||
XXHASH="y";
|
||||
ZLIB_DEFLATE="y";
|
||||
ZLIB_INFLATE="y";
|
||||
ZONE_DMA32="y";
|
||||
ZSTD_COMMON="y";
|
||||
ZSTD_COMPRESS="y";
|
||||
ZSTD_DECOMPRESS="y";
|
||||
# from DEVICE_PACKAGES in the openwrt_one section of
|
||||
# openwrt's ./target/linux/mediatek/image/filogic.mk:
|
||||
# chop off the 'kmod-' prefix and search for 'KernelPackage/...'
|
||||
# in ./package/kernel/linux/modules/*.mk, and remember to add
|
||||
# modules to kmodloader targets below
|
||||
AIR_EN8811H_PHY="m";
|
||||
RTC_DRV_PCF8563="m";
|
||||
NVME_CORE="m";
|
||||
BLK_DEV_NVME="m";
|
||||
NVME_MULTIPATH="n";
|
||||
NVME_HWMON="y";
|
||||
# ???
|
||||
AQUANTIA_PHY="m";
|
||||
MT798X_WMAC="y";
|
||||
} // lib.optionalAttrs (config.system.service ? watchdog) {
|
||||
RALINK_WDT = "y"; # watchdog
|
||||
MT7621_WDT = "y"; # or it might be this one
|
||||
};
|
||||
conditionalConfig = {
|
||||
WLAN = {
|
||||
MT7915E = "m";
|
||||
};
|
||||
};
|
||||
};
|
||||
boot = {
|
||||
commandLine = [ "console=ttyS0,115200" ];
|
||||
tftp = {
|
||||
# Should be a segment of free RAM, where the tftp artifact
|
||||
# can be stored before unpacking it to the 'hardware.loadAddress'
|
||||
# The 'hardware.loadAddress' is 0x44000000, and the bootlog
|
||||
# suggests it loads the fit to 0x46000000
|
||||
loadAddress = lim.parseInt "0x46000000";
|
||||
};
|
||||
imageFormat = "fit";
|
||||
loader.fit.enable = lib.mkDefault true; # override this if you are building tftpboot
|
||||
};
|
||||
rootfsType = lib.mkDefault "ubifs"; # override this if you are building tftpboot
|
||||
filesystem =
|
||||
let inherit (pkgs.pseudofile) dir symlink;
|
||||
in
|
||||
dir {
|
||||
lib = dir {
|
||||
firmware = dir {
|
||||
mediatek = symlink mediatek-firmware;
|
||||
airoha = symlink airoha-firmware;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
hardware =
|
||||
let
|
||||
phy = pkgs.kmodloader.override {
|
||||
targets = [
|
||||
"air_en8811h"
|
||||
];
|
||||
inherit (config.system.outputs) kernel;
|
||||
};
|
||||
mac80211 = pkgs.kmodloader.override {
|
||||
targets = [
|
||||
"mt7915e"
|
||||
"rtc-pcf8563"
|
||||
"nvme_core"
|
||||
"nvme"
|
||||
#"mt7996e"
|
||||
"aquantia"
|
||||
];
|
||||
inherit (config.system.outputs) kernel;
|
||||
};
|
||||
in {
|
||||
# from OEM bootlog
|
||||
# Creating 4 MTD partitions on "spi0.0":
|
||||
# 0x000000000000-0x000000040000 : "bl2-nor"
|
||||
# 0x000000040000-0x000000100000 : "factory"
|
||||
# 0x000000100000-0x000000180000 : "fip-nor"
|
||||
# 0x000000180000-0x000000e00000 : "recovery"
|
||||
# spi-nand spi1.1: calibration result: 0x3
|
||||
# spi-nand spi1.1: Winbond SPI NAND was found.
|
||||
# spi-nand spi1.1: 256 MiB, block size: 128 KiB, page size: 2048, OOB size: 128
|
||||
# 2 fixed-partitions partitions found on MTD device spi1.1
|
||||
# Creating 2 MTD partitions on "spi1.1":
|
||||
# 0x000000000000-0x000000100000 : "bl2"
|
||||
# 0x000000100000-0x000010000000 : "ubi"
|
||||
|
||||
flash = {
|
||||
# from the OEM bootlog:
|
||||
# ## Checking Image at 46000000 ...
|
||||
# FIT image found
|
||||
# FIT description: ARM64 OpenWrt FIT (Flattened Image Tree)
|
||||
# Image 0 (kernel-1)
|
||||
# Description: ARM64 OpenWrt Linux-6.6.57
|
||||
# Type: Kernel Image
|
||||
# Compression: gzip compressed
|
||||
# Data Start: 0x46001000
|
||||
# Data Size: 5751840 Bytes = 5.5 MiB
|
||||
# Architecture: AArch64
|
||||
# OS: Linux
|
||||
# Load Address: 0x44000000
|
||||
# Entry Point: 0x44000000
|
||||
|
||||
address = lim.parseInt "0x44000000";
|
||||
size = lim.parseInt "0xf60000";
|
||||
# /proc/mtd on a running system:
|
||||
# dev: size erasesize name
|
||||
# mtd0: 00040000 00010000 "bl2-nor"
|
||||
# mtd1: 000c0000 00010000 "factory"
|
||||
# mtd2: 00080000 00010000 "fip-nor"
|
||||
# mtd3: 00c80000 00010000 "recovery"
|
||||
# mtd4: 00100000 00020000 "bl2"
|
||||
# mtd5: 0ff00000 00020000 "ubi"
|
||||
eraseBlockSize = 65536;
|
||||
};
|
||||
ubi = {
|
||||
# TODO taken from belkin-rt3200, to review
|
||||
minIOSize = "2048";
|
||||
logicalEraseBlockSize = "126976";
|
||||
physicalEraseBlockSize = "131072";
|
||||
maxLEBcount = "1024"; # guessing
|
||||
};
|
||||
|
||||
|
||||
defaultOutput = "ubimage";
|
||||
loadAddress = lim.parseInt "0x44000000";
|
||||
entryPoint = lim.parseInt "0x44000000";
|
||||
# TODO AFAICT this should be 2048, but I got 'FIT: image rootfs-1 start not aligned to page boundaries' with that...
|
||||
#alignment = 2048;
|
||||
alignment = 4096;
|
||||
rootDevice = "ubi0:liminix";
|
||||
dts = {
|
||||
src = "${openwrt.src}/target/linux/mediatek/dts/mt7981b-openwrt-one.dts";
|
||||
includePaths = [
|
||||
"${openwrt.src}/target/linux/mediatek/dts"
|
||||
"${config.system.outputs.kernel.modulesupport}/arch/arm64/boot/dts/mediatek/"
|
||||
];
|
||||
};
|
||||
|
||||
networkInterfaces =
|
||||
let
|
||||
inherit (config.system.service.network) link;
|
||||
in rec {
|
||||
eth0 = link.build {
|
||||
ifname = "eth0";
|
||||
dependencies = [ phy ];
|
||||
};
|
||||
eth1 = link.build { ifname = "eth1"; };
|
||||
|
||||
wlan0 = link.build {
|
||||
ifname = "wlan0";
|
||||
dependencies = [ mac80211 ];
|
||||
};
|
||||
wlan1 = link.build {
|
||||
ifname = "wlan1";
|
||||
dependencies = [ mac80211 ];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -66,7 +66,7 @@
|
||||
# *correct* but it does at least boot
|
||||
dts = lib.mkForce {
|
||||
src = "${config.system.outputs.kernel.modulesupport}/arch/mips/boot/dts/mti/malta.dts";
|
||||
includes = [
|
||||
includePaths = [
|
||||
"${config.system.outputs.kernel.modulesupport}/arch/mips/boot/dts/"
|
||||
];
|
||||
};
|
||||
|
||||
@@ -50,11 +50,6 @@
|
||||
];
|
||||
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}
|
||||
'';
|
||||
@@ -410,7 +405,7 @@
|
||||
rootDevice = "/dev/mtdblock3";
|
||||
dts = {
|
||||
src = "${openwrt.src}/target/linux/ramips/dts/mt7621_tplink_archer-ax23-v1.dts";
|
||||
includes = [
|
||||
includePaths = [
|
||||
"${openwrt.src}/target/linux/ramips/dts"
|
||||
"${config.system.outputs.kernel.modulesupport}/arch/arm64/boot/dts/mediatek/"
|
||||
];
|
||||
|
||||
@@ -172,10 +172,12 @@
|
||||
../../modules/arch/arm.nix
|
||||
../../modules/outputs/tftpboot.nix
|
||||
../../modules/outputs/mbrimage.nix
|
||||
../../modules/outputs/extlinux.nix
|
||||
];
|
||||
|
||||
config = {
|
||||
rootfsType = lib.mkDefault "btrfs"; # override this if you are building tftpboot
|
||||
rootOptions = lib.mkDefault "subvol=@";
|
||||
|
||||
services.mtd-name-links = mtd_by_name_links;
|
||||
kernel = {
|
||||
src = pkgs.pkgsBuildBuild.fetchurl {
|
||||
@@ -224,11 +226,6 @@
|
||||
# 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"; # ???
|
||||
@@ -298,6 +295,7 @@
|
||||
};
|
||||
};
|
||||
boot = {
|
||||
loader.extlinux.enable = lib.mkDefault true; # override this if you are building tftpboot
|
||||
commandLine = [
|
||||
"console=ttyS0,115200"
|
||||
"pcie_aspm=off" # ath9k pci incompatible with PCIe ASPM
|
||||
@@ -341,14 +339,14 @@
|
||||
targets = ["ath9k" "ath10k_pci"];
|
||||
};
|
||||
in {
|
||||
defaultOutput = "mtdimage";
|
||||
defaultOutput = "updater";
|
||||
loadAddress = lim.parseInt "0x00800000"; # "0x00008000";
|
||||
entryPoint = lim.parseInt "0x00800000"; # "0x00008000";
|
||||
rootDevice = "/dev/mmcblk0p1";
|
||||
|
||||
dts = {
|
||||
src = "${config.system.outputs.kernel.modulesupport}/arch/arm/boot/dts/marvell/armada-385-turris-omnia.dts";
|
||||
includes = [
|
||||
includePaths = [
|
||||
"${config.system.outputs.kernel.modulesupport}/arch/arm/boot/dts/marvell/"
|
||||
];
|
||||
};
|
||||
|
||||
@@ -124,7 +124,7 @@
|
||||
hash = "sha256-ifriAjWzFACrxVWCANZpUaEZgB/0pdbhnTVQytx6ddg=";
|
||||
};
|
||||
in {
|
||||
imports = [
|
||||
imports = [
|
||||
# We include it to ensure the bridge functionality
|
||||
# is available on the target kernel.
|
||||
../../modules/bridge
|
||||
@@ -184,7 +184,7 @@
|
||||
# Actually, this is not what we want.
|
||||
# This DTS is insufficient.
|
||||
src = ./mt7621_zyxel_nwa50ax.dtsi;
|
||||
includes = [
|
||||
includePaths = [
|
||||
# Here's one weird trick to make `ubi` detection
|
||||
# out of the box.
|
||||
# We will write ubi on /dev/firmware_a:rootfs location
|
||||
@@ -233,7 +233,7 @@
|
||||
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
|
||||
# primary and secondary are always /dev/mtd3 by virtue of the
|
||||
# dtb being not too wrong…
|
||||
# TODO: remove this hack.
|
||||
primaryMtdPartition = "/dev/mtd3";
|
||||
@@ -250,14 +250,8 @@
|
||||
# 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 = {
|
||||
|
||||
|
||||
+91
-39
@@ -131,50 +131,45 @@ human-readable format, use :command:`s6-tai64nlocal`.
|
||||
1970-01-02 21:51:48.832588765 wan.link.pppoe sent [LCP ConfReq id=0x1 <asyncmap 0x0> <magic 0x667a9594> <pcomp> <accom
|
||||
p>]
|
||||
|
||||
Log persistence
|
||||
---------------
|
||||
|
||||
Logs written to :file:`/run/log/` will not survive a reboot or crash,
|
||||
as it is an ephemeral filesystem.
|
||||
|
||||
On supported hardware you can enable logging to `pstore
|
||||
<https://www.kernel.org/doc/Documentation/ABI/testing/pstore>`_ which
|
||||
means the most recent log messages will be preserved on reboot. Set
|
||||
the config option ``logging.persistent.enable = true`` to log messages
|
||||
to :file:`/dev/pmsg0` as well as to the regular log. This is a
|
||||
circular buffer, so when it fills up newer messages will overwrite the
|
||||
oldest messages.
|
||||
|
||||
Logs found in pstore after a reboot will be moved at startup to
|
||||
:file:`/run/log/previous-boot`
|
||||
|
||||
|
||||
Updating an installed system (JFFS2)
|
||||
************************************
|
||||
|
||||
Updating an installed system
|
||||
****************************
|
||||
|
||||
Adding packages
|
||||
===============
|
||||
If your system has a writable root filesystem (JFFS2, btrfs etc -
|
||||
anything but squashfs), we have mechanisms for in-places updates
|
||||
analogous to :command:`nixos-rebuild`, but the operation is a bit
|
||||
different because it expects to run on a build machine and then copy
|
||||
to the host device using :command:`ssh`.
|
||||
|
||||
If your device is running a JFFS2 root filesystem, you can build
|
||||
extra packages for it on your build system and copy them to the
|
||||
device: any package in Nixpkgs or in the Liminix overlay is available
|
||||
with the ``pkgs`` prefix:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
nix-build -I liminix-config=./my-configuration.nix \
|
||||
--arg device "import ./devices/mydevice" -A pkgs.tcpdump
|
||||
|
||||
nix-shell -p min-copy-closure root@the-device result/
|
||||
|
||||
Note that this only copies the package to the device: it doesn't update
|
||||
any profile to add it to ``$PATH``
|
||||
|
||||
|
||||
.. _rebuilding the system:
|
||||
|
||||
Rebuilding the system
|
||||
=====================
|
||||
|
||||
Liminix has a mechanism for in-place updates of a running system which
|
||||
is analogous to :command:`nixos-rebuild`, but its operation is a
|
||||
bit different because it expects to run on a build machine and then
|
||||
copy to the host device. To use this, build the `outputs.systemConfiguration`
|
||||
target and then run the :command:`result/install.sh` script it generates.
|
||||
To use this, build the ``outputs.updater``
|
||||
target and then run the :command:`update.sh` script it generates.
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
nix-build -I liminix-config=./my-configuration.nix \
|
||||
--arg device "import ./devices/mydevice" \
|
||||
-A outputs.systemConfiguration
|
||||
./result/install.sh root@the-device
|
||||
-A outputs.updater
|
||||
./result/bin/update.sh root@the-device
|
||||
|
||||
The install script uses min-copy-closure to copy new or changed
|
||||
The update script uses min-copy-closure to copy new or changed
|
||||
packages to the device, then (perhaps) reboots it. The reboot
|
||||
behaviour can be affected by flags:
|
||||
|
||||
@@ -187,26 +182,83 @@ behaviour can be affected by flags:
|
||||
the services that have updated store paths (and anything that
|
||||
depends on them), but will not affect services that haven't changed.
|
||||
|
||||
|
||||
It doesn't delete old packages automatically: to do that run
|
||||
:command:`min-collect-garbage`, which will delete any packages not in
|
||||
the current system closure. Note that Liminix does not have the NixOS
|
||||
concept of environments or generations, and there is no way back from
|
||||
this except for building the previous configuration again.
|
||||
|
||||
|
||||
Caveats
|
||||
-------
|
||||
|
||||
* it needs there to be enough free space on the device for all the new
|
||||
packages in addition to all the packages already on it - which may be
|
||||
a problem if a lot of things have changed (e.g. a new version of
|
||||
nixpkgs).
|
||||
packages in addition to all the packages already on it - which may
|
||||
be a problem if there is little flash storage or if a lot of things
|
||||
have changed (e.g. a new version of nixpkgs).
|
||||
|
||||
* it may not be able to upgrade the kernel: this is device-dependent.
|
||||
If your device boots from a kernel image on a raw MTD partition or
|
||||
or UBI volume, update.sh is unable to alter the kernel partition.
|
||||
If your device boots from a kernel inside the filesystem (e.g. using
|
||||
bootloader.extlinux or bootloder.fit) then the kernel will be
|
||||
upgraded along with the userland
|
||||
|
||||
|
||||
Recovery/downgrades
|
||||
-------------------
|
||||
|
||||
The :command:`update.sh` script also creates a timestamped symlink on
|
||||
the device which points to the system configuration it installs. If
|
||||
you install a configuration that doesn't work, you can revert to any
|
||||
other installed configuration by
|
||||
|
||||
1) booting to some kind of rescue or recovery system (which may be
|
||||
some vendor-provided rescue option, or your own recovery system
|
||||
perhaps based on :file:`examples/recovery.nix`) and mounting
|
||||
your Liminix filesystem on /mnt
|
||||
|
||||
2) picking another previously-installed configuration that _did_ work,
|
||||
and switching back to it:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
# ls -ld /mnt/*configuration
|
||||
lrwxrwxrwx 1 90 /mnt/20252102T182104.configuration -> nix/store/v1w0h4zw65ah4c2r0k7nyy125qrxhq78-system-configuration-aarch64-unknown-linux-musl
|
||||
lrwxrwxrwx 1 90 /mnt/20251802T181822.configuration -> nix/store/wqjl9s9xljl2wg8257292zghws9ssidk-system-configuration-aarch64-unknown-linux-musl
|
||||
# : 20251802T181822 is the working system, so reinstall it
|
||||
# /mnt/20251802T181822.configuration/bin/install /mnt
|
||||
# umount /mnt
|
||||
# reboot
|
||||
|
||||
This will install the previous configuration's activation binary into
|
||||
/bin, and copy its kernel and initramfs into /boot. Note that it
|
||||
depends on the previous system not having been garbage-collected.
|
||||
|
||||
|
||||
|
||||
* it cannot upgrade the kernel, only userland
|
||||
|
||||
.. _levitate:
|
||||
|
||||
Adding packages
|
||||
===============
|
||||
|
||||
If you simply wish to add a package without any change to services,
|
||||
you can call :command:`min-copy-closure` directly to install
|
||||
any package in Nixpkgs or in the Liminix overlay
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
nix-build -I liminix-config=./my-configuration.nix \
|
||||
--arg device "import ./devices/mydevice" -A pkgs.tcpdump
|
||||
|
||||
nix-shell -p min-copy-closure root@the-device result/
|
||||
|
||||
Note that this only copies the package and its dependencies to the
|
||||
device: it doesn't update any profile to add it to ``$PATH``
|
||||
|
||||
|
||||
.. _rebuilding the system:
|
||||
|
||||
Reinstalling on a running system
|
||||
********************************
|
||||
|
||||
|
||||
@@ -116,8 +116,8 @@ TFTP server you're using and so is out of scope for this document.
|
||||
|
||||
|
||||
|
||||
Buildiing and installing the image
|
||||
==================================
|
||||
Building and installing the image
|
||||
=================================
|
||||
|
||||
Follow the device-specific instructions for "TFTP install": usually,
|
||||
the steps are
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
# This is "contrib"-level code. This module solves a particular
|
||||
# problem for my particular setup and is provided as is, as an example
|
||||
# of how you might write something similar if you had a similar
|
||||
# problem. Don't expect it to work unmolested in your setup (you will
|
||||
# at the absolute minimum have to change the domain name), nor even to
|
||||
# continue to exist without possibly being changed beyond recognition.
|
||||
|
||||
# The computers on my LAN have globally unique routable IPv6
|
||||
# addresses, but I have only one public IPv4 address. I want to expose
|
||||
# HTTPS services to the Internet _whatever_ machine is hosting them,
|
||||
# so I publish an AAAA record to the machine itself, and an A record
|
||||
# to the public v4 address of the router which is running this nginx.
|
||||
# This nginx checks the SNI in the incoming connection and forwards
|
||||
# the connection to the (IPv6 address of the) same hostname
|
||||
|
||||
# See https://ww.telent.net/2020/12/2/six_into_4_won_t_go for
|
||||
# the original solution to this problem, which used sniproxy (now
|
||||
# unmaintained) instead of nginx
|
||||
|
||||
{ config, pkgs, ... }:
|
||||
let
|
||||
inherit (pkgs.liminix.services) longrun;
|
||||
inherit (pkgs) writeText;
|
||||
nginx_uid = 62;
|
||||
in {
|
||||
config = {
|
||||
users.nginx = {
|
||||
uid = nginx_uid; gid= nginx_uid;
|
||||
dir = "/run/";
|
||||
shell = "/bin/false";
|
||||
};
|
||||
groups.nginx = {
|
||||
gid= nginx_uid;
|
||||
usernames = ["nginx"];
|
||||
};
|
||||
|
||||
services.sniproxy =
|
||||
let
|
||||
nginx = pkgs.nginx-small.override {
|
||||
pcre = null;
|
||||
zlib = null;
|
||||
options = [
|
||||
"stream"
|
||||
"stream_ssl_module" "stream_ssl_preread_module"
|
||||
"stream_map_module"
|
||||
];
|
||||
};
|
||||
conf = writeText "nginx.conf" ''
|
||||
worker_processes auto;
|
||||
error_log /proc/self/fd/1 info;
|
||||
pid /dev/null;
|
||||
user nginx;
|
||||
daemon off;
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
stream {
|
||||
log_format proxy '$remote_addr -> $ssl_target';
|
||||
access_log /proc/self/fd/1 proxy;
|
||||
map $ssl_preread_server_name $ssl_target {
|
||||
hostnames;
|
||||
.telent.net $ssl_preread_server_name:443;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 443;
|
||||
resolver 127.0.0.1 ipv6=on ipv4=off;
|
||||
resolver_timeout 1s;
|
||||
proxy_pass $ssl_target;
|
||||
ssl_preread on;
|
||||
}
|
||||
}
|
||||
'';
|
||||
in longrun {
|
||||
name = "sniproxy";
|
||||
run = ''
|
||||
${nginx}/bin/nginx -c ${conf}
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -22,7 +22,6 @@ in rec {
|
||||
../modules/outputs/ubimage.nix
|
||||
../modules/outputs/jffs2.nix
|
||||
../modules/outputs/ext4fs.nix
|
||||
../modules/outputs/extlinux.nix
|
||||
];
|
||||
|
||||
kernel.config = {
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
./outputs/ext4fs.nix
|
||||
./outputs/initramfs.nix
|
||||
./outputs/jffs2.nix
|
||||
./outputs/kexecboot.nix
|
||||
./outputs/mtdimage.nix
|
||||
./outputs/tftpboot.nix
|
||||
./outputs/ubifs.nix
|
||||
@@ -30,7 +29,6 @@
|
||||
./outputs/vmroot.nix
|
||||
./ppp
|
||||
./ramdisk.nix
|
||||
./squashfs.nix
|
||||
./ssh
|
||||
./users.nix
|
||||
./vlan
|
||||
|
||||
@@ -62,8 +62,8 @@ in {
|
||||
# https://www.mankier.com/8/nft#Payload_Expressions-Raw_Payload_Expression
|
||||
"@nh,192,8 eq 0xff @nh,204,4 le ${toString mcast-scope}")
|
||||
|
||||
(accept "oifname \"int\" iifname \"ppp0\" meta l4proto udp ct state established,related")
|
||||
(accept "iifname \"int\" oifname \"ppp0\" meta l4proto udp")
|
||||
(accept "oifname @lan iifname @wan meta l4proto udp ct state established,related")
|
||||
(accept "iifname @lan oifname @wan meta l4proto udp")
|
||||
|
||||
(accept "meta l4proto icmpv6")
|
||||
(accept "meta l4proto ah")
|
||||
@@ -71,31 +71,31 @@ in {
|
||||
|
||||
# does this ever get used or does the preceding general udp accept
|
||||
# already grab anything that might get here?
|
||||
(accept "oifname \"ppp0\" udp dport 500") # IKE Protocol [RFC5996]. haha zyxel
|
||||
(accept "oifname @wan udp dport 500") # IKE Protocol [RFC5996]. haha zyxel
|
||||
(accept "ip6 nexthdr 139") # Host Identity Protocol
|
||||
|
||||
## FIXME no support yet for recs 27-30 Mobility Header
|
||||
|
||||
(accept "oifname \"int\" iifname \"ppp0\" meta l4proto tcp ct state established,related")
|
||||
(accept "iifname \"int\" oifname \"ppp0\" meta l4proto tcp")
|
||||
(accept "oifname @lan iifname @wan meta l4proto tcp ct state established,related")
|
||||
(accept "iifname @lan oifname @wan meta l4proto tcp")
|
||||
|
||||
(accept "oifname \"int\" iifname \"ppp0\" meta l4proto sctp ct state established,related")
|
||||
(accept "iifname \"int\" oifname \"ppp0\" meta l4proto sctp")
|
||||
(accept "oifname @lan iifname @wan meta l4proto sctp ct state established,related")
|
||||
(accept "iifname @lan oifname @wan meta l4proto sctp")
|
||||
|
||||
(accept "oifname \"int\" iifname \"ppp0\" meta l4proto dccp ct state established,related")
|
||||
(accept "iifname \"int\" oifname \"ppp0\" meta l4proto dccp")
|
||||
(accept "oifname @lan iifname @wan meta l4proto dccp ct state established,related")
|
||||
(accept "iifname @lan oifname @wan meta l4proto dccp")
|
||||
|
||||
# we can allow all reasonable inbound, or we can use an explicit
|
||||
# allowlist to enumerate the endpoints that are allowed to
|
||||
# accept inbound from the WAN
|
||||
(if allow-incoming
|
||||
then accept "oifname \"int\" iifname \"ppp0\""
|
||||
else "iifname \"ppp0\" jump incoming-allowed-ip6"
|
||||
then accept "oifname @lan iifname @wan"
|
||||
else "iifname @wan jump incoming-allowed-ip6"
|
||||
)
|
||||
# allow all outbound and any inbound that's part of a
|
||||
# recognised (outbound-initiated) flow
|
||||
(accept "oifname \"int\" iifname \"ppp0\" ct state established,related")
|
||||
(accept "iifname \"int\" oifname \"ppp0\" ")
|
||||
(accept "oifname @lan iifname @wan ct state established,related")
|
||||
(accept "iifname @lan oifname @wan ")
|
||||
|
||||
"log prefix \"DENIED CHAIN=forward-ip6 \""
|
||||
];
|
||||
@@ -128,15 +128,15 @@ in {
|
||||
hook = "input";
|
||||
rules = [
|
||||
(accept "meta l4proto icmpv6")
|
||||
"iifname int jump input-ip6-lan"
|
||||
"iifname ppp0 jump input-ip6-wan"
|
||||
"iifname @lan jump input-ip6-lan"
|
||||
"iifname @wan jump input-ip6-wan"
|
||||
(if allow-incoming
|
||||
then accept "oifname \"int\" iifname \"ppp0\""
|
||||
else "oifname \"int\" iifname \"ppp0\" jump incoming-allowed-ip6"
|
||||
then accept "iifname @wan"
|
||||
else "iifname @wan jump incoming-allowed-ip6"
|
||||
)
|
||||
# how does this even make sense in an input chain?
|
||||
(accept "oifname \"int\" iifname \"ppp0\" ct state established,related")
|
||||
(accept "iifname \"int\" oifname \"ppp0\" ")
|
||||
(accept "iifname @wan ct state established,related")
|
||||
(accept "iifname @lan ")
|
||||
"log prefix \"DENIED CHAIN=input-ip6 \""
|
||||
];
|
||||
};
|
||||
@@ -146,7 +146,7 @@ in {
|
||||
family = "ip6";
|
||||
rules = [
|
||||
# this is where you put permitted incoming connections
|
||||
# "oifname \"int\" ip6 daddr 2001:8b0:de3a:40de::e9d tcp dport 22"
|
||||
# "oifname @lan ip6 daddr 2001:8b0:de3a:40de::e9d tcp dport 22"
|
||||
];
|
||||
};
|
||||
|
||||
@@ -157,7 +157,7 @@ in {
|
||||
policy = "accept";
|
||||
family = "ip";
|
||||
rules = [
|
||||
"oifname \"ppp0\" masquerade"
|
||||
"oifname @wan masquerade"
|
||||
];
|
||||
};
|
||||
|
||||
@@ -208,9 +208,9 @@ in {
|
||||
rules = [
|
||||
"iifname lo accept"
|
||||
"icmp type { echo-request, echo-reply } accept"
|
||||
"iifname int jump input-ip4-lan"
|
||||
"iifname ppp0 jump input-ip4-wan"
|
||||
"iifname ppp0 jump incoming-allowed-ip4"
|
||||
"iifname @lan jump input-ip4-lan"
|
||||
"iifname @wan jump input-ip4-wan"
|
||||
"iifname @wan jump incoming-allowed-ip4"
|
||||
"ct state established,related accept"
|
||||
"log prefix \"DENIED CHAIN=input-ip4 \""
|
||||
];
|
||||
@@ -222,9 +222,9 @@ in {
|
||||
policy = "drop";
|
||||
hook = "forward";
|
||||
rules = [
|
||||
"iifname \"int\" accept"
|
||||
"iifname @lan accept"
|
||||
"ct state established,related accept"
|
||||
"oifname \"int\" iifname \"ppp0\" jump incoming-allowed-ip4"
|
||||
"oifname @lan iifname @wan jump incoming-allowed-ip4"
|
||||
"log prefix \"DENIED CHAIN=forward-ip4 \""
|
||||
];
|
||||
};
|
||||
|
||||
@@ -60,6 +60,16 @@ in
|
||||
description = "firewall ruleset";
|
||||
default = {};
|
||||
};
|
||||
zones = mkOption {
|
||||
type = types.attrsOf (types.listOf liminix.lib.types.service);
|
||||
default = {};
|
||||
example = lib.literalExpression ''
|
||||
{
|
||||
lan = with config.hardware.networkInterfaces; [ int ];
|
||||
wan = [ config.services.ppp0 ];
|
||||
}
|
||||
'';
|
||||
};
|
||||
rules = mkOption {
|
||||
type = types.attrsOf types.attrs; # we could usefully tighten this a bit :-)
|
||||
default = import ./default-rules.nix;
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
(local { : system : join } (require :anoia))
|
||||
(local svc (require :anoia.svc))
|
||||
(local ll (require :lualinux))
|
||||
|
||||
;; ifwatch.fnl wan:/nix/store/eee/.outputs/ifname wan:/nix/store/ffff/.outputs/ifname lan:/nix/store/abc123/.outputs/ifname
|
||||
|
||||
(fn parse-options [cmdline]
|
||||
(let [interfaces {}]
|
||||
(each [_ s (ipairs cmdline)]
|
||||
(let [(zone service) (string.match s "(.-):(.+)")]
|
||||
(tset interfaces (svc.open service) zone)))
|
||||
interfaces))
|
||||
|
||||
(local POLLIN 1)
|
||||
(local POLLHUP 16)
|
||||
|
||||
(fn zone-contents [interfaces]
|
||||
(accumulate [zones {}
|
||||
intf zone (pairs interfaces)]
|
||||
(let [ifs (or (. zones zone) [])]
|
||||
(table.insert ifs (intf:output "ifname"))
|
||||
(tset zones zone ifs)
|
||||
zones)))
|
||||
|
||||
(fn wait-for-change [interfaces]
|
||||
(let [pollfds (icollect [k _ (pairs interfaces)]
|
||||
(bor (lshift (k:fileno) 32)
|
||||
(lshift (bor POLLIN POLLHUP) 16)))]
|
||||
(ll.poll pollfds)))
|
||||
|
||||
(fn fail [msg]
|
||||
(io.stderr:write (.. "ERROR: " msg "\n")))
|
||||
|
||||
(macro with-popen [[handle command mode] & body]
|
||||
`(let [,handle (assert (io.popen ,command ,mode))
|
||||
val# (do ,(unpack body))]
|
||||
(case (: ,handle :close)
|
||||
ok# val#
|
||||
(nil :exit code#) (fail (.. ,command " exited " code#))
|
||||
(nil :signal sig#) (fail (.. ,command " killed by " sig#)))))
|
||||
|
||||
(fn update-zone-str [zone ifnames]
|
||||
(if (> (# ifnames) 0)
|
||||
(..
|
||||
"flush set ip table-ip " zone " ; add element ip table-ip " zone " { " (table.concat ifnames ", ") " };\n"
|
||||
"flush set ip6 table-ip6 " zone " ; add element ip6 table-ip6 " zone " { " (table.concat ifnames ", ") " };\n"
|
||||
)
|
||||
(..
|
||||
"flush set ip table-ip " zone "; \n"
|
||||
"flush set ip6 table-ip6 " zone "; \n"
|
||||
)))
|
||||
|
||||
(fn run []
|
||||
(while true
|
||||
(let [interfaces (parse-options arg)]
|
||||
(with-popen [nft "nft -f -" :w]
|
||||
(each [zone ifnames (pairs (zone-contents interfaces))]
|
||||
(nft:write (update-zone-str zone ifnames))))
|
||||
(wait-for-change interfaces)
|
||||
(each [k _ (pairs interfaces)]
|
||||
(k:close)))))
|
||||
|
||||
{ : run }
|
||||
@@ -3,13 +3,40 @@
|
||||
, lib
|
||||
, firewallgen
|
||||
, nftables
|
||||
, writeFennel
|
||||
, anoia
|
||||
, lualinux
|
||||
, linotify
|
||||
}:
|
||||
{ rules, extraRules }:
|
||||
{ rules, extraRules, zones }:
|
||||
let
|
||||
inherit (liminix.services) oneshot;
|
||||
script = firewallgen "firewall.nft" (lib.recursiveUpdate rules extraRules);
|
||||
in oneshot {
|
||||
inherit (liminix.services) longrun;
|
||||
inherit (lib.attrsets) mapAttrs' nameValuePair mapAttrsToList;
|
||||
inherit (lib.strings) concatStringsSep;
|
||||
inherit (lib.lists) flatten;
|
||||
mkSet = family : name :
|
||||
nameValuePair
|
||||
"${name}-set-${family}"
|
||||
{
|
||||
kind = "set";
|
||||
inherit name family;
|
||||
type = "ifname";
|
||||
};
|
||||
sets = (mapAttrs' (n : _ : mkSet "ip" n) zones) //
|
||||
(mapAttrs' (n : _ : mkSet "ip6" n) zones);
|
||||
allRules = lib.recursiveUpdate extraRules (lib.recursiveUpdate (builtins.trace sets sets) rules);
|
||||
script = firewallgen "firewall1.nft" allRules;
|
||||
ifwatch = writeFennel "ifwatch" {
|
||||
packages = [anoia lualinux linotify];
|
||||
mainFunction = "run";
|
||||
} ./ifwatch.fnl ;
|
||||
watchArg = z : intfs : map (i: "${z}:${i}/.outputs") intfs;
|
||||
in longrun {
|
||||
name = "firewall";
|
||||
up = script;
|
||||
down = "${nftables}/bin/nft flush ruleset";
|
||||
run = ''
|
||||
${script}
|
||||
PATH=${nftables}/bin:$PATH
|
||||
${ifwatch} ${concatStringsSep " " (flatten (mapAttrsToList watchArg zones))}
|
||||
'';
|
||||
finish = "${nftables}/bin/nft flush ruleset";
|
||||
}
|
||||
|
||||
+12
-1
@@ -13,6 +13,12 @@ in
|
||||
options = {
|
||||
boot = { };
|
||||
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
|
||||
};
|
||||
dts = {
|
||||
src = mkOption {
|
||||
type = types.nullOr types.path;
|
||||
@@ -24,11 +30,16 @@ in
|
||||
only for QEMU.
|
||||
'';
|
||||
};
|
||||
includes = mkOption {
|
||||
includePaths = mkOption {
|
||||
default = [ ];
|
||||
description = "List of directories to search for DTS includes (.dtsi files)";
|
||||
type = types.listOf types.path;
|
||||
};
|
||||
includes = mkOption {
|
||||
default = [ ];
|
||||
description = "\"dtsi\" fragments to include in the generated device tree";
|
||||
type = types.listOf types.path;
|
||||
};
|
||||
};
|
||||
defaultOutput = mkOption {
|
||||
description = "\"Default\" output: what gets built for this device when outputs.default is requested. Typically this is \"mtdimage\" or \"vmroot\"";
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
{ lib, pkgs, config, ...}:
|
||||
let
|
||||
inherit (lib) mkOption types ;
|
||||
inherit (pkgs) liminix;
|
||||
inherit (pkgs) liminix openwrt;
|
||||
|
||||
mergeConditionals = conf : conditions :
|
||||
# for each key in conditions, if it is present in conf
|
||||
@@ -21,8 +21,8 @@ let
|
||||
in {
|
||||
options = {
|
||||
kernel = {
|
||||
src = mkOption { type = types.path; } ;
|
||||
version = mkOption { type = types.str; default = "5.15.137";} ;
|
||||
src = mkOption { type = types.path; default = openwrt.kernelSrc; } ;
|
||||
version = mkOption { type = types.str; default = openwrt.kernelVersion;} ;
|
||||
modular = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
@@ -68,19 +68,15 @@ in {
|
||||
};
|
||||
};
|
||||
config = {
|
||||
system.outputs =
|
||||
system.outputs.kernel =
|
||||
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;
|
||||
in liminix.builders.kernel.override {
|
||||
config = mergedConfig;
|
||||
inherit (config.kernel) version src extraPatchPhase;
|
||||
targets = config.kernel.makeTargets;
|
||||
};
|
||||
|
||||
kernel = rec {
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
{ config, lib, ... }:
|
||||
let
|
||||
inherit (lib) mkIf mkEnableOption mkOption types;
|
||||
in {
|
||||
options = {
|
||||
logging = {
|
||||
persistent = {
|
||||
enable = mkEnableOption "store logs across reboots";
|
||||
};
|
||||
};
|
||||
};
|
||||
config = {
|
||||
kernel.config = mkIf config.logging.persistent.enable {
|
||||
PSTORE = "y";
|
||||
PSTORE_PMSG = "y";
|
||||
PSTORE_RAM = "y";
|
||||
};
|
||||
};
|
||||
}
|
||||
+20
-34
@@ -11,9 +11,16 @@ let
|
||||
in
|
||||
{
|
||||
imports = [
|
||||
./squashfs.nix
|
||||
./outputs/boot-extlinux.nix
|
||||
./outputs/boot-fit.nix
|
||||
./outputs/btrfs.nix
|
||||
./outputs/jffs2.nix
|
||||
# ./outputs/mtdimage.nix
|
||||
./outputs/squashfs.nix
|
||||
./outputs/ubimage.nix
|
||||
./outputs/uimage.nix
|
||||
./outputs/updater
|
||||
./outputs/vmroot.nix
|
||||
./outputs/extlinux.nix
|
||||
];
|
||||
options = {
|
||||
system.outputs = {
|
||||
@@ -27,17 +34,7 @@ in
|
||||
kernel
|
||||
******
|
||||
|
||||
Kernel vmlinux file (usually ELF)
|
||||
'';
|
||||
};
|
||||
zimage = mkOption {
|
||||
type = types.package;
|
||||
internal = true;
|
||||
description = ''
|
||||
zimage
|
||||
******
|
||||
|
||||
Kernel in compressed self-extracting package
|
||||
Kernel package (multi-output derivation)
|
||||
'';
|
||||
};
|
||||
dtb = mkOption {
|
||||
@@ -50,16 +47,6 @@ in
|
||||
Compiled device tree (FDT) for the target device
|
||||
'';
|
||||
};
|
||||
uimage = mkOption {
|
||||
type = types.package;
|
||||
internal = true;
|
||||
description = ''
|
||||
uimage
|
||||
******
|
||||
|
||||
Combined kernel and FDT in uImage (U-Boot compatible) format
|
||||
'';
|
||||
};
|
||||
tplink-safeloader = mkOption {
|
||||
type = types.package;
|
||||
};
|
||||
@@ -82,6 +69,12 @@ in
|
||||
directory of files to package into root filesystem
|
||||
'';
|
||||
};
|
||||
bootfiles = mkOption {
|
||||
type = types.nullOr types.package;
|
||||
internal = true;
|
||||
default = null;
|
||||
# description = "";
|
||||
};
|
||||
bootablerootdir = mkOption {
|
||||
type = types.package;
|
||||
internal = true;
|
||||
@@ -104,18 +97,11 @@ in
|
||||
system.outputs = rec {
|
||||
dtb = liminix.builders.dtb {
|
||||
inherit (config.boot) commandLine;
|
||||
dts = config.hardware.dts.src;
|
||||
includes = config.hardware.dts.includes ++ [
|
||||
dts = [config.hardware.dts.src] ++ config.hardware.dts.includes;
|
||||
includes = config.hardware.dts.includePaths ++ [
|
||||
"${o.kernel.headers}/include"
|
||||
];
|
||||
};
|
||||
uimage = liminix.builders.uimage {
|
||||
commandLine = concatStringsSep " " config.boot.commandLine;
|
||||
inherit (config.boot) commandLineDtbNode;
|
||||
inherit (config.hardware) loadAddress entryPoint alignment;
|
||||
inherit (config.boot) imageFormat;
|
||||
inherit (o) kernel dtb;
|
||||
};
|
||||
rootdir =
|
||||
let
|
||||
inherit (pkgs.pkgsBuildBuild) runCommand;
|
||||
@@ -132,8 +118,8 @@ in
|
||||
let inherit (pkgs.pkgsBuildBuild) runCommand;
|
||||
in runCommand "add-slash-boot" { } ''
|
||||
cp -a ${o.rootdir} $out
|
||||
${if config.boot.loader.extlinux.enable
|
||||
then "(cd $out && chmod -R +w . && rmdir boot && cp -a ${o.extlinux} boot)"
|
||||
${if o.bootfiles != null
|
||||
then "(cd $out && chmod -R +w . && rmdir boot && cp -a ${o.bootfiles} boot)"
|
||||
else ""
|
||||
}
|
||||
'';
|
||||
|
||||
@@ -12,19 +12,15 @@ let
|
||||
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" {} ''
|
||||
system.outputs.bootfiles = pkgs.runCommand "extlinux" {} ''
|
||||
mkdir $out
|
||||
cd $out
|
||||
${if wantsDtb then "cp ${o.dtb} dtb" else "true"}
|
||||
cp ${o.initramfs} initramfs
|
||||
cp ${o.zimage} kernel
|
||||
cp ${o.kernel.zImage} kernel
|
||||
mkdir extlinux
|
||||
cat > extlinux/extlinux.conf << _EOF
|
||||
menu title Liminix
|
||||
@@ -37,7 +33,7 @@ in {
|
||||
_EOF
|
||||
'';
|
||||
filesystem = dir {
|
||||
boot = symlink config.system.outputs.extlinux;
|
||||
boot = symlink config.system.outputs.bootfiles;
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
{
|
||||
config
|
||||
, pkgs
|
||||
, lib
|
||||
, ...
|
||||
}:
|
||||
let
|
||||
inherit (lib) mkIf mkEnableOption mkOption types concatStringsSep;
|
||||
inherit (pkgs.pseudofile) dir symlink;
|
||||
cfg = config.boot.loader.fit;
|
||||
o = config.system.outputs;
|
||||
cmdline = concatStringsSep " " config.boot.commandLine;
|
||||
wantsDtb = config.hardware.dts ? src && config.hardware.dts.src != null;
|
||||
in {
|
||||
options.boot.loader.fit.enable = mkEnableOption "FIT in /boot";
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
system.outputs.bootfiles = pkgs.runCommand "boot-fit" {} ''
|
||||
mkdir $out
|
||||
cd $out
|
||||
cp ${o.uimage} fit
|
||||
'';
|
||||
filesystem = dir {
|
||||
boot = symlink config.system.outputs.bootfiles;
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -9,6 +9,7 @@ let
|
||||
inherit (pkgs) runCommand;
|
||||
in
|
||||
{
|
||||
imports = [ ./system-configuration.nix ];
|
||||
options = {
|
||||
boot.initramfs = {
|
||||
enable = mkEnableOption "initramfs";
|
||||
@@ -22,14 +23,6 @@ in
|
||||
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 {
|
||||
@@ -53,8 +46,6 @@ in
|
||||
file /init ${pkgs.preinit}/bin/preinit 0755 0 0
|
||||
SPECIALS
|
||||
'';
|
||||
systemConfiguration =
|
||||
pkgs.systemconfig config.filesystem.contents;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
{
|
||||
config
|
||||
, pkgs
|
||||
, lib
|
||||
, ...
|
||||
}:
|
||||
let
|
||||
inherit (lib) mkOption types concatStringsSep;
|
||||
in {
|
||||
imports = [ ../ramdisk.nix ];
|
||||
options.system.outputs = {
|
||||
kexecboot = mkOption {
|
||||
type = types.package;
|
||||
description = ''
|
||||
kexecboot
|
||||
*********
|
||||
|
||||
Directory containing files needed for kexec booting.
|
||||
Can be copied onto the target device using ssh or similar
|
||||
'';
|
||||
};
|
||||
boot-sh = mkOption {
|
||||
type = types.package;
|
||||
description = ''
|
||||
Shell script to run on the target device that invokes
|
||||
kexec with appropriate options
|
||||
'';
|
||||
};
|
||||
};
|
||||
config = {
|
||||
boot.ramdisk.enable = true;
|
||||
system.outputs = {
|
||||
kexecboot =
|
||||
let o = config.system.outputs; in
|
||||
pkgs.runCommand "kexecboot" {} ''
|
||||
mkdir $out
|
||||
cd $out
|
||||
ln -s ${o.rootfs} rootfs
|
||||
ln -s ${o.kernel} kernel
|
||||
ln -s ${o.manifest} manifest
|
||||
ln -s ${o.boot-sh} boot.sh
|
||||
ln -s ${pkgs.kexec-tools-static}/bin/kexec ./kexec
|
||||
ln -s ${o.dtb} dtb
|
||||
'';
|
||||
|
||||
boot-sh =
|
||||
let
|
||||
inherit (config.system.outputs) rootfs;
|
||||
cmdline = concatStringsSep " " config.boot.commandLine;
|
||||
in
|
||||
pkgs.buildPackages.runCommand "boot.sh.sh" {
|
||||
} ''
|
||||
rootfsStart=${toString (100 * 1024 * 1024)}
|
||||
rootfsBytes=$(stat -L -c %s ${rootfs})
|
||||
append_cmd="mtdparts=phram0:''${rootfsBytes}(rootfs) phram.phram=phram0,''${rootfsStart},''${rootfsBytes} memmap=''${rootfsBytes}\$''${rootfsStart}";
|
||||
cat > $out <<EOF
|
||||
#!/bin/sh
|
||||
test -d \$1
|
||||
cd \$1
|
||||
./kexec -f -d --map-file rootfs@$rootfsStart --dtb dtb --command-line '${cmdline} $append_cmd' kernel
|
||||
EOF
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -34,7 +34,8 @@ in {
|
||||
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.
|
||||
the vendor firmware, or from Liminix when using
|
||||
:ref:`levitate`
|
||||
|
||||
If you are flashing from U-Boot, the file
|
||||
:file:`flash.scr` is a sequence of commands
|
||||
@@ -60,6 +61,7 @@ in {
|
||||
config = {
|
||||
kernel = {
|
||||
config = {
|
||||
# this needs to be conditional on "not qemu"
|
||||
MTD_SPLIT_UIMAGE_FW = "y";
|
||||
} // lib.optionalAttrs (pkgs.stdenv.isMips) {
|
||||
# https://stackoverflow.com/questions/26466470/can-the-logical-erase-block-size-of-an-mtd-device-be-increased
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
{
|
||||
config
|
||||
, pkgs
|
||||
, lib
|
||||
, ...
|
||||
}:
|
||||
let
|
||||
inherit (lib) mkEnableOption mkOption mkIf types;
|
||||
inherit (pkgs) runCommand;
|
||||
in
|
||||
{
|
||||
options = {
|
||||
system.outputs = {
|
||||
systemConfiguration = mkOption {
|
||||
type = types.package;
|
||||
description = ''
|
||||
pkgs.systemconfig for the configured filesystem,
|
||||
contains 'activate' and 'init' commands
|
||||
'';
|
||||
internal = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
config = {
|
||||
system.outputs.systemConfiguration =
|
||||
pkgs.systemconfig config.filesystem.contents;
|
||||
};
|
||||
}
|
||||
@@ -57,11 +57,13 @@ in {
|
||||
|
||||
system.outputs = rec {
|
||||
tftpboot =
|
||||
# no ubifs on an mtd directly, it needs ubi volumes
|
||||
assert config.rootfsType != "ubifs";
|
||||
let
|
||||
o = config.system.outputs;
|
||||
image = let choices = {
|
||||
uimage = o.uimage;
|
||||
zimage = o.zimage;
|
||||
zimage = o.kernel.zImage;
|
||||
}; in choices.${cfg.kernelFormat};
|
||||
bootCommand = let choices = {
|
||||
uimage = "bootm";
|
||||
@@ -119,6 +121,7 @@ in {
|
||||
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)
|
||||
fdtput -p dtb /reserved-memory/$node no-map
|
||||
|
||||
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 ${config.boot.commandLineDtbNode} "$cmd"
|
||||
|
||||
@@ -13,18 +13,6 @@ in
|
||||
./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";
|
||||
@@ -33,7 +21,7 @@ in
|
||||
};
|
||||
boot.initramfs.enable = true;
|
||||
system.outputs = {
|
||||
rootubifs =
|
||||
rootfs =
|
||||
let
|
||||
inherit (pkgs.pkgsBuildBuild) runCommand mtdutils;
|
||||
cfg = config.hardware.ubi;
|
||||
|
||||
+28
-34
@@ -7,10 +7,12 @@
|
||||
let
|
||||
inherit (lib) mkIf mkOption types;
|
||||
cfg = config.boot.tftp;
|
||||
instructions = pkgs.writeText "env.scr" ''
|
||||
instructions = pkgs.writeText "flash.scr" ''
|
||||
setenv serverip ${cfg.serverip}
|
||||
setenv ipaddr ${cfg.ipaddr}
|
||||
setenv loadaddr ${lib.toHexString cfg.loadAddress}
|
||||
tftpboot $loadaddr result/rootfs
|
||||
ubi write $loadaddr liminix $filesize
|
||||
'';
|
||||
in {
|
||||
options.system.outputs = {
|
||||
@@ -63,18 +65,20 @@ Now we can make our new root volume
|
||||
|
||||
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
|
||||
3) transfer the root filesystem from the build system and write it to
|
||||
the new volume. Paste the contents of :file:`result/flash.scr` one line at a time
|
||||
into U-Boot:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
uboot> tftpboot ''${loadaddr} result/rootfs
|
||||
uboot> ubi write ''${loadaddr} liminix $filesize
|
||||
uboot> setenv serverip 10.0.0.1
|
||||
uboot> setenv ipaddr 10.0.0.8
|
||||
uboot> setenv loadaddr 4007FF28
|
||||
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 /``
|
||||
can even mount it and poke around using :command:`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:
|
||||
@@ -82,25 +86,18 @@ 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> ubifsload ''${loadaddr} boot/fit
|
||||
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.
|
||||
return to U-Boot.
|
||||
|
||||
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.
|
||||
device-dependent and you should consult the Liminix documentation for
|
||||
your device. (If you're bringing up a new device, some detective work
|
||||
may be needed. Try running `printenv` and trace through the flow of
|
||||
execution from (probably) :command:`$bootcmd` and look for a suitable
|
||||
variable to change)
|
||||
|
||||
6) Now you can reboot the device into Liminix
|
||||
|
||||
@@ -111,16 +108,13 @@ boot process, maybe even try looking for documentation for that device.
|
||||
};
|
||||
};
|
||||
|
||||
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
|
||||
'';
|
||||
};
|
||||
};
|
||||
config.system.outputs.ubimage =
|
||||
assert config.rootfsType == "ubifs";
|
||||
let o = config.system.outputs; in
|
||||
pkgs.runCommand "ubimage" {} ''
|
||||
mkdir $out
|
||||
cd $out
|
||||
ln -s ${o.rootfs} rootfs
|
||||
ln -s ${instructions} flash.scr
|
||||
'';
|
||||
}
|
||||
|
||||
@@ -18,6 +18,9 @@ in
|
||||
eraseBlockSize = mkOption { type = types.str; }; # LEB
|
||||
maxLEBcount = mkOption { type = types.str; }; # LEB
|
||||
};
|
||||
options.system.outputs.ubivolume = mkOption {
|
||||
type = types.package;
|
||||
};
|
||||
|
||||
config = mkIf (config.rootfsType == "ubifs") {
|
||||
kernel.config = {
|
||||
@@ -28,7 +31,7 @@ in
|
||||
};
|
||||
boot.initramfs.enable = true;
|
||||
|
||||
system.outputs.rootfs =
|
||||
system.outputs.ubivolume =
|
||||
let
|
||||
inherit (pkgs.pkgsBuildBuild) runCommand;
|
||||
ubiVolume = ({ name, volumeId, image, flags ? [] }:
|
||||
@@ -81,7 +84,7 @@ in
|
||||
]);
|
||||
|
||||
disk = ubiDisk {
|
||||
initramfs = config.system.outputs.rootubifs; # liminix.builders.squashfs config.filesystem.contents; # # assert this is a proper FIT.
|
||||
initramfs = config.system.outputs.rootfs; # ???
|
||||
};
|
||||
|
||||
in
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
{
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (lib) mkOption types concatStringsSep;
|
||||
inherit (pkgs) liminix writeText;
|
||||
o = config.system.outputs;
|
||||
in
|
||||
{
|
||||
options.system.outputs.uimage = mkOption {
|
||||
type = types.package;
|
||||
internal = true;
|
||||
description = ''
|
||||
uimage
|
||||
******
|
||||
|
||||
Combined kernel and FDT in uImage (U-Boot compatible) format
|
||||
'';
|
||||
};
|
||||
config.system.outputs.uimage = liminix.builders.uimage {
|
||||
commandLine = concatStringsSep " " config.boot.commandLine;
|
||||
inherit (config.boot) commandLineDtbNode;
|
||||
inherit (config.hardware) loadAddress entryPoint alignment;
|
||||
inherit (config.boot) imageFormat;
|
||||
inherit (o) kernel dtb;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
{
|
||||
config
|
||||
, pkgs
|
||||
, lib
|
||||
, ...
|
||||
}:
|
||||
let
|
||||
inherit (lib) mkIf;
|
||||
o = config.system.outputs;
|
||||
inherit (pkgs) runCommand;
|
||||
inherit (lib) mkOption types;
|
||||
inherit (pkgs.buildPackages) min-copy-closure;
|
||||
in
|
||||
{
|
||||
imports = [ ../system-configuration.nix ];
|
||||
options.system.outputs.updater = mkOption {
|
||||
type = types.package;
|
||||
description = ''
|
||||
updater
|
||||
******
|
||||
|
||||
For configurations with a writable filesystem, create a shell
|
||||
script that runs on the build system and updates the device
|
||||
over the network to the new configuration
|
||||
'';
|
||||
};
|
||||
|
||||
config.system.outputs.updater =
|
||||
runCommand "buildUpdater" { } ''
|
||||
mkdir -p $out/bin $out/etc
|
||||
cp ${o.kernel.config} $out/etc/kconfig
|
||||
substitute ${./update.sh} $out/bin/update.sh \
|
||||
--subst-var-by toplevel ${o.systemConfiguration} \
|
||||
--subst-var-by min_copy_closure ${min-copy-closure}
|
||||
chmod +x $out/bin/update.sh
|
||||
'';
|
||||
}
|
||||
@@ -1,22 +1,19 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# this shell script can be run on the build system to
|
||||
# min-copy-closure the system configuration onto the device
|
||||
# and reboot/restart services as requested
|
||||
# this shell script is run on the build system to min-copy-closure the
|
||||
# system configuration onto the device and reboot/restart services as
|
||||
# requested
|
||||
|
||||
die() {
|
||||
echo "$@"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# add min-copy-closure to the path. removing junk characters
|
||||
# inserted by default.nix (q.v.)
|
||||
min_copy_closure=@min-copy-closure@; PATH=${min_copy_closure//_/}/bin:$PATH
|
||||
|
||||
PATH=@min_copy_closure@/bin:$PATH
|
||||
ssh_command=${SSH_COMMAND-ssh}
|
||||
|
||||
reboot="reboot"
|
||||
|
||||
case "$1" in
|
||||
"--no-reboot")
|
||||
unset reboot
|
||||
@@ -34,13 +31,14 @@ shift
|
||||
test -n "$target_host" || \
|
||||
die "Usage: $0 [--no-reboot] [--fast] target-host"
|
||||
|
||||
toplevel=$(cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && readlink `pwd` )
|
||||
toplevel=$(realpath @toplevel@)
|
||||
test -e $toplevel/etc/nix-store-paths || die "missing etc/nix-store-paths, is this really a system configuration?"
|
||||
echo installing from systemConfiguration $toplevel to host $target_host
|
||||
|
||||
$ssh_command $target_host uname -a || die "Can't ssh to $target_host"
|
||||
min-copy-closure $target_host $toplevel
|
||||
set -x
|
||||
$ssh_command $target_host $toplevel/bin/install
|
||||
ts=$(date +%Y%m%dT%H%M%S)
|
||||
$ssh_command $target_host "$toplevel/bin/install && ln -s $(realpath --relative-to / $toplevel) /persist/${ts}.configuration"
|
||||
case "$reboot" in
|
||||
reboot)
|
||||
$ssh_command $target_host "sync; source /etc/profile; reboot"
|
||||
@@ -31,7 +31,7 @@ on a system with pre-existing firmware and OS.
|
||||
config = mkIf (config.rootfsType == "ubifs") {
|
||||
|
||||
system.outputs.zyxel-nwa-fit =
|
||||
let
|
||||
let
|
||||
o = config.system.outputs;
|
||||
# 8129kb padding.
|
||||
paddedKernel = pkgs.runCommand "padded-kernel" {} ''
|
||||
@@ -39,7 +39,7 @@ on a system with pre-existing firmware and OS.
|
||||
dd if=/dev/zero of=$out bs=1 count=1 seek=8388607
|
||||
'';
|
||||
firmwareImage = pkgs.runCommand "firmware-image" {} ''
|
||||
cat ${paddedKernel} ${o.rootfs} > $out
|
||||
cat ${paddedKernel} ${o.ubivolume} > $out
|
||||
'';
|
||||
dts = pkgs.writeText "image.its" ''
|
||||
/dts-v1/;
|
||||
|
||||
@@ -48,6 +48,13 @@ in {
|
||||
firewall = {
|
||||
enable = mkEnableOption "firewall";
|
||||
rules = mkOption { type = types.attrsOf types.attrs; };
|
||||
zones = mkOption {
|
||||
type = types.attrsOf (types.listOf liminix.lib.types.service);
|
||||
default = {
|
||||
lan = [ config.services.int ];
|
||||
wan = [ config.services.wan ];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
wan = {
|
||||
@@ -143,6 +150,7 @@ in {
|
||||
services.firewall = mkIf cfg.firewall.enable
|
||||
(svc.firewall.build {
|
||||
extraRules = cfg.firewall.rules;
|
||||
inherit (cfg.firewall) zones;
|
||||
});
|
||||
|
||||
services.resolvconf = oneshot rec {
|
||||
|
||||
+1
-2
@@ -7,8 +7,7 @@ in {
|
||||
ramdisk = {
|
||||
enable = mkEnableOption ''
|
||||
reserving part of memory as
|
||||
an MTD-based RAM disk. Needed for TFTP booting or for
|
||||
kexec-based revertable upgrade
|
||||
an MTD-based RAM disk. Needed for TFTP booting
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
+18
-15
@@ -7,10 +7,27 @@ let
|
||||
s6-linux-init
|
||||
stdenvNoCC;
|
||||
inherit (lib.lists) unique concatMap;
|
||||
inherit (lib) concatStrings;
|
||||
inherit (builtins) map;
|
||||
inherit (pkgs.pseudofile) dir symlink;
|
||||
inherit (pkgs.liminix.services) oneshot bundle longrun;
|
||||
inherit (lib) mkIf mkEnableOption mkOption types;
|
||||
cfg = config.logging;
|
||||
|
||||
logger =
|
||||
let pipecmds =
|
||||
["${s6}/bin/s6-log -bpd3 -- ${cfg.script} 1"] ++
|
||||
(lib.optional (cfg ? persistent && cfg.persistent.enable)
|
||||
"/bin/tee /dev/pmsg0") ++
|
||||
(lib.optional cfg.shipping.enable
|
||||
"${pkgs.logshipper}/bin/logtap ${cfg.shipping.socket} logshipper-socket-event");
|
||||
in ''
|
||||
#!${execline}/bin/execlineb -P
|
||||
${execline}/bin/redirfd -w 1 /dev/null
|
||||
${execline}/bin/redirfd -rnb 0 fifo
|
||||
${concatStrings (map (l: "pipeline { ${l} }\n") pipecmds)}
|
||||
${s6}/bin/s6-log -- ${cfg.directory}
|
||||
'';
|
||||
s6-rc-db =
|
||||
let
|
||||
# In the default bundle we need to have all the services
|
||||
@@ -106,21 +123,7 @@ let
|
||||
mode = "0600";
|
||||
};
|
||||
notification-fd = { file = "3"; };
|
||||
run = {
|
||||
file = ''
|
||||
#!${execline}/bin/execlineb -P
|
||||
${execline}/bin/redirfd -w 1 /dev/null
|
||||
${execline}/bin/redirfd -rnb 0 fifo
|
||||
${if cfg.shipping.enable then ''
|
||||
pipeline { ${s6}/bin/s6-log -bpd3 -- ${cfg.script} 1 }
|
||||
pipeline { ${pkgs.logshipper}/bin/logtap ${cfg.shipping.socket} logshipper-socket-event }
|
||||
${s6}/bin/s6-log -- ${cfg.directory}
|
||||
'' else ''
|
||||
${s6}/bin/s6-log -bpd3 -- ${cfg.script} ${cfg.directory}
|
||||
''}
|
||||
'';
|
||||
mode = "0755";
|
||||
};
|
||||
run = { file = logger; mode = "0755"; };
|
||||
};
|
||||
getty = dir {
|
||||
run = {
|
||||
|
||||
@@ -22,6 +22,11 @@ mount -t tmpfs none /tmp
|
||||
mkdir /dev/pts
|
||||
mount -t devpts none /dev/pts
|
||||
|
||||
if test -c /dev/pmsg0 ; then
|
||||
mount -t pstore none /sys/fs/pstore
|
||||
(cat /sys/fs/pstore/* && rm /sys/fs/pstore/*) > /run/log/previous-boot
|
||||
fi
|
||||
|
||||
mkdir -m 0751 -p /run/services/outputs
|
||||
chgrp system /run/services/outputs
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
let
|
||||
inherit (lib) mkOption types;
|
||||
inherit (pkgs) liminix;
|
||||
inherit (pkgs.pseudofile) dir file;
|
||||
mkBoolOption = description : mkOption {
|
||||
type = types.bool;
|
||||
inherit description;
|
||||
@@ -20,6 +21,13 @@ in {
|
||||
};
|
||||
};
|
||||
config.programs.busybox.options.FEATURE_FANCY_ECHO = "y";
|
||||
config.filesystem = dir {
|
||||
etc = dir {
|
||||
shells = {
|
||||
file = "/bin/sh\n";
|
||||
};
|
||||
};
|
||||
};
|
||||
config.system.service = {
|
||||
ssh = config.system.callService ./ssh.nix {
|
||||
address = mkOption {
|
||||
|
||||
+7
-6
@@ -5,7 +5,7 @@ let
|
||||
extraPkgs = import ./pkgs/default.nix {
|
||||
inherit (final) lib callPackage;
|
||||
};
|
||||
inherit (final) fetchpatch;
|
||||
inherit (final) fetchpatch lib;
|
||||
luaHost =
|
||||
let
|
||||
l = prev.lua5_3.overrideAttrs(o: {
|
||||
@@ -73,14 +73,15 @@ extraPkgs // {
|
||||
});
|
||||
in chrony'.override {
|
||||
gnutls = null;
|
||||
nss = null;
|
||||
nspr = null;
|
||||
readline = null;
|
||||
libedit = null;
|
||||
libseccomp = null;
|
||||
# should texinfo be in nativeBuildInputs instead of
|
||||
# buildInputs?
|
||||
texinfo = null;
|
||||
} // lib.optionalAttrs (lib.versionOlder lib.version "24.10") {
|
||||
nss = null;
|
||||
nspr = null;
|
||||
readline = null;
|
||||
};
|
||||
|
||||
# clevis without luks/tpm
|
||||
@@ -217,11 +218,11 @@ extraPkgs // {
|
||||
] ++ final.lib.optionals (o ? patches) o.patches;
|
||||
});
|
||||
|
||||
mtdutils = prev.mtdutils.overrideAttrs(o: {
|
||||
mtdutils = (prev.mtdutils.overrideAttrs(o: {
|
||||
patches = (if o ? patches then o.patches else []) ++ [
|
||||
./pkgs/mtdutils/0001-mkfs.jffs2-add-graft-option.patch
|
||||
];
|
||||
});
|
||||
})).override { util-linux = final.util-linux-small ; };
|
||||
|
||||
nftables = prev.nftables.overrideAttrs(o: {
|
||||
configureFlags = [
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
;; e.g. (import-macros { : expect= } :anoia.assert)
|
||||
|
||||
|
||||
(fn expect [assertion]
|
||||
(let [msg (.. "expectation failed: " (view assertion))]
|
||||
`(when (not ,assertion)
|
||||
|
||||
@@ -82,7 +82,6 @@
|
||||
(let [p (find-executable "yes" (os.getenv "PATH"))]
|
||||
(expect (string.match p "coreutils.+bin/yes$"))))
|
||||
|
||||
|
||||
{
|
||||
: mktree
|
||||
: rmtree
|
||||
|
||||
+41
-22
@@ -1,8 +1,4 @@
|
||||
;; importing assert.fnl macros here would be circular, so we can't use
|
||||
;; the full test functionality
|
||||
(macro define-tests [& body]
|
||||
(when _G.RUNNING_TESTS
|
||||
`(do ,(unpack body))))
|
||||
(import-macros { : define-tests : expect : expect= } :anoia.assert)
|
||||
|
||||
(fn assoc [tbl k v & more]
|
||||
(tset tbl k v)
|
||||
@@ -32,6 +28,18 @@
|
||||
(fn dirname [path]
|
||||
(string.match path "(.*)/[^/]-$"))
|
||||
|
||||
(fn append-path [dirname filename]
|
||||
(let [base (or (string.match dirname "(.*)/$") dirname)
|
||||
result []]
|
||||
(each [component (string.gmatch filename "([^/]+)")]
|
||||
(if (and (= component "..") (> (# result) 0))
|
||||
(table.remove result)
|
||||
(= component "..")
|
||||
(error "path traversal attempt")
|
||||
true
|
||||
(table.insert result component)))
|
||||
(.. base "/" (table.concat result "/"))))
|
||||
|
||||
(fn system [s]
|
||||
(match (os.execute s)
|
||||
res (do (print (.. "Executed \"" s "\", exit code " (tostring res))) res)
|
||||
@@ -59,16 +67,28 @@
|
||||
(and present (. a k))))))
|
||||
|
||||
(define-tests
|
||||
(assert (table= {:a 1 :b 2} {:b 2 :a 1}))
|
||||
(assert (not (table= {:a 1 :b 2 :k :l} {:b 2 :a 1})))
|
||||
(assert (not (table= {:a 1 :b 2} {:b 2 :a 1 :k :l})))
|
||||
(expect (table= {:a 1 :b 2} {:b 2 :a 1}))
|
||||
(expect (not (table= {:a 1 :b 2 :k :l} {:b 2 :a 1})))
|
||||
(expect (not (table= {:a 1 :b 2} {:b 2 :a 1 :k :l})))
|
||||
|
||||
(assert (table= {:a 1 :b {:l 17}} {:b {:l 17} :a 1}))
|
||||
(assert (table= {:a [4 5 6 7] } {:a [4 5 6 7]}))
|
||||
(assert (not (table= {:a [4 5 6 7] } {:a [4 5 6 7 8]})))
|
||||
(assert (not (table= {:a [4 5 7 6] } {:a [4 5 6 7 ]})))
|
||||
(expect (table= {:a 1 :b {:l 17}} {:b {:l 17} :a 1}))
|
||||
(expect (table= {:a [4 5 6 7] } {:a [4 5 6 7]}))
|
||||
(expect (not (table= {:a [4 5 6 7] } {:a [4 5 6 7 8]})))
|
||||
(expect (not (table= {:a [4 5 7 6] } {:a [4 5 6 7 ]})))
|
||||
|
||||
(assert (table= {} {}))
|
||||
(expect (table= {} {}))
|
||||
|
||||
(let [traps (fn [b p]
|
||||
(match (pcall append-path b p)
|
||||
(true f) (error "didn't trap path traversal")
|
||||
(false err) (expect (string.match err "path traversal"))))]
|
||||
(expect= (append-path "/tmp" "hello") "/tmp/hello")
|
||||
(expect= (append-path "/tmp/" "hello") "/tmp/hello")
|
||||
(expect= (append-path "/tmp/" "///hello") "/tmp/hello")
|
||||
(expect= (append-path "/tmp/" "///hello/../fish") "/tmp/fish")
|
||||
(traps "/tmp/" "../hello")
|
||||
(expect= (append-path "/tmp/" "hello/../goodbye") "/tmp/goodbye")
|
||||
(traps "/tmp/" "hello/../../goodbye"))
|
||||
)
|
||||
|
||||
(fn dig [tree path]
|
||||
@@ -177,17 +197,17 @@
|
||||
b64 (base64 :url)]
|
||||
|
||||
(let [a (b64:decode "YWxsIHlvdXIgYmFzZQ==")]
|
||||
(assert (= a "all your base") (view a)))
|
||||
(expect= a "all your base"))
|
||||
(let [a (b64:decode "ZmVubmVsIHRoaW5n")]
|
||||
(assert (= a "fennel thing") a))
|
||||
(expect= a "fennel thing"))
|
||||
(let [a (b64:decode "TWFueSBoYW5kcyBtYWtlIGxpZ2h0IHdvcms=")]
|
||||
(assert (= a "Many hands make light work") (view a)))
|
||||
(expect= a "Many hands make light work"))
|
||||
(let [a (b64:encode "hello world")]
|
||||
(assert (= a "aGVsbG8gd29ybGQ=") a))
|
||||
(expect= a "aGVsbG8gd29ybGQ="))
|
||||
|
||||
(fn check [plain enc]
|
||||
(let [a (b64:encode plain)] (assert (= a enc) (.. "encode " a)))
|
||||
(let [a (b64:decode enc)] (assert (= a plain) (.. "decode " a))))
|
||||
(let [a (b64:encode plain)] (expect (= a enc) (.. "encode " a)))
|
||||
(let [a (b64:decode enc)] (expect (= a plain) (.. "decode " a))))
|
||||
|
||||
(check "" "")
|
||||
(check "f" "Zg==")
|
||||
@@ -198,12 +218,10 @@
|
||||
(check "foobar" "Zm9vYmFy")
|
||||
|
||||
(let [x (b64:decode "REtOdUtNS05BNEJWLXdfcUhtNU9YV2liOUxkX3RTdVJTQWVUR0dkWldBdVEyaURObDZ2b3pSbEJwMzlzOEltdkhWdmpzZmMiLCJ5IjoiQVlDY1QwOGZrNFZWZ2lZSVIxbkU4UlJGaGZOSGdBUEFzckRITmJtRGNfUGtWZmdDR0xTMTIweU5SNncwdjd5RUY4WDN1OGpvazhkU0pqN0hnWjZCZHAzcSJ9LCJraWQiOiJlalVDaXBCUE9BeDRWQ1dQdUtkVGlYNDNadW5XTDNjSWN6V1h1RVZyTVNFIn0")]
|
||||
(assert (string.match x "}$") x))
|
||||
(expect (string.match x "}$") x))
|
||||
|
||||
))
|
||||
|
||||
|
||||
|
||||
;; doesn't work if the padding is missing
|
||||
;; (let [a (from-base64 "TWFueSBoYW5kcyBtYWtlIGxpZ2h0IHdvcms")]
|
||||
;; (assert (= a "Many hands make light work") (view a)))
|
||||
@@ -212,6 +230,7 @@
|
||||
|
||||
|
||||
{
|
||||
: append-path
|
||||
: assoc
|
||||
: base64
|
||||
: base64url
|
||||
|
||||
@@ -60,6 +60,7 @@
|
||||
(write-value (.. directory "/" filename) new-value)
|
||||
(read-value (.. directory "/" filename))))
|
||||
:close #(watcher:close)
|
||||
:fileno #(watcher:fileno)
|
||||
: events
|
||||
}))
|
||||
|
||||
|
||||
@@ -96,9 +96,11 @@ in {
|
||||
minisock = callPackage ./minisock { };
|
||||
nellie = callPackage ./nellie { };
|
||||
netlink-lua = callPackage ./netlink-lua { };
|
||||
nginx-small = callPackage ./nginx-small { };
|
||||
odhcp-script = callPackage ./odhcp-script { };
|
||||
odhcp6c = callPackage ./odhcp6c { };
|
||||
openwrt = callPackage ./openwrt { };
|
||||
openwrt_24_10 = callPackage ./openwrt/2410.nix { };
|
||||
output-template = callPackage ./output-template { };
|
||||
ppp = callPackage ./ppp { };
|
||||
pppoe = callPackage ./pppoe { };
|
||||
|
||||
@@ -1,20 +1,28 @@
|
||||
commit bd51aae2e40814ac2ae5801fd9f83f6a4a886fb1
|
||||
Author: Daniel Barlow <dan@telent.net>
|
||||
Date: Fri Aug 23 11:33:24 2024 +0100
|
||||
From 9c0ac9e41a393e0f16a57e36d9369d61d39e9aa5 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Barlow <dan@telent.net>
|
||||
Date: Fri, 23 Aug 2024 11:33:24 +0100
|
||||
Subject: [PATCH] add -U otion to set path to authorized_keys file
|
||||
|
||||
add -U otion to set path to authorized_keys file
|
||||
|
||||
based on https://github.com/mkj/dropbear/pull/35
|
||||
by Salvador Fandino sfandino@yahoo.com
|
||||
|
||||
- Allow authorized keys inside dirs with the sticky bit set
|
||||
|
||||
- Add option -U for customizing authorized_keys path
|
||||
|
||||
- Updated for dropbear 2024.85 (source files moved to src/)
|
||||
|
||||
- allow %u, %d, %n "format specifiers" in pathname so that the user's
|
||||
username/homedir/uid can be embedded into the path
|
||||
based on https://github.com/mkj/dropbear/pull/35
|
||||
by Salvador Fandino sfandino@yahoo.com
|
||||
|
||||
- Allow authorized keys inside dirs with the sticky bit set
|
||||
|
||||
- Add option -U for customizing authorized_keys path
|
||||
|
||||
- Updated for dropbear 2024.85 (source files moved to src/)
|
||||
|
||||
- allow %u, %d, %n "format specifiers" in pathname so that the user's
|
||||
username/homedir/uid can be embedded into the path
|
||||
---
|
||||
Makefile.in | 2 +-
|
||||
manpages/dropbear.8 | 3 +
|
||||
src/pathexpand.c | 149 +++++++++++++++++++++++++++++++++++++++++++
|
||||
src/runopts.h | 3 +-
|
||||
src/svr-authpubkey.c | 86 +++++++++++--------------
|
||||
src/svr-runopts.c | 10 +++
|
||||
6 files changed, 203 insertions(+), 50 deletions(-)
|
||||
create mode 100644 src/pathexpand.c
|
||||
|
||||
diff --git a/Makefile.in b/Makefile.in
|
||||
index 5ebfca2..686fbfb 100644
|
||||
@@ -45,15 +53,16 @@ index bdb2ea0..c8d450d 100644
|
||||
.TP
|
||||
diff --git a/src/pathexpand.c b/src/pathexpand.c
|
||||
new file mode 100644
|
||||
index 0000000..2028733
|
||||
index 0000000..07e6955
|
||||
--- /dev/null
|
||||
+++ b/src/pathexpand.c
|
||||
@@ -0,0 +1,132 @@
|
||||
@@ -0,0 +1,149 @@
|
||||
+#include <limits.h>
|
||||
+#include <string.h>
|
||||
+#include <stdio.h>
|
||||
+
|
||||
+#ifdef TEST_PATHEXPAND
|
||||
+#include <stdlib.h>
|
||||
+
|
||||
+/* to run tests:
|
||||
+ gcc -Wall -o pathexpand -D TEST_PATHEXPAND=1 src/pathexpand.c && ./pathexpand
|
||||
@@ -64,6 +73,17 @@ index 0000000..2028733
|
||||
+
|
||||
+#define m_malloc(c) malloc(c)
|
||||
+#define m_strdup(c) strdup(c)
|
||||
+#define TRACE(c) dropbear_trace1 c
|
||||
+#include <stdarg.h>
|
||||
+
|
||||
+inline static void dropbear_trace1(const char* format, ...) {
|
||||
+ va_list param;
|
||||
+
|
||||
+ va_start(param, format);
|
||||
+ /* vfprintf(stderr, format, param); */
|
||||
+ /* fprintf(stderr, "\n"); */
|
||||
+}
|
||||
+
|
||||
+
|
||||
+struct session {
|
||||
+ struct AuthState {
|
||||
@@ -124,6 +144,8 @@ index 0000000..2028733
|
||||
+ /* unrecognised specifiers are discarded */
|
||||
+ expect_expansion("/hi/%q/.ssh", "/hi//.ssh");
|
||||
+
|
||||
+
|
||||
+ expect_expansion("%d/.ssh/authorized_keys", "/home/dan/.ssh/authorized_keys");
|
||||
+ exit(exit_status);
|
||||
+}
|
||||
+
|
||||
@@ -155,10 +177,13 @@ index 0000000..2028733
|
||||
+ char *out = filename;
|
||||
+ char *p = relfilename;
|
||||
+ do {
|
||||
+ p = strchrnul(start, '%');
|
||||
+ strncat(out, start, p - start);
|
||||
+ p = strchr(start, '%');
|
||||
+
|
||||
+ if(*p == '\0') break;
|
||||
+ if(!p) {
|
||||
+ strcat(out, start);
|
||||
+ break;
|
||||
+ }
|
||||
+ strncat(out, start, p - start);
|
||||
+
|
||||
+ switch(*(p+1)) {
|
||||
+ case '\0':
|
||||
@@ -384,3 +409,6 @@ index c4f83c1..faddfa2 100644
|
||||
}
|
||||
}
|
||||
|
||||
--
|
||||
2.47.0
|
||||
|
||||
|
||||
@@ -43,15 +43,33 @@ let
|
||||
${concatStringsSep "\n" rules}
|
||||
}
|
||||
'';
|
||||
|
||||
doset = { name, type, elements ? [], ... } : ''
|
||||
set ${name} {
|
||||
type ${type}
|
||||
${if elements != []
|
||||
then "elements = { ${concatStringsSep ", " elements } }"
|
||||
else ""
|
||||
}
|
||||
}
|
||||
'';
|
||||
|
||||
dochainorset =
|
||||
{ kind ? "chain", ... } @ params :
|
||||
{
|
||||
chain = dochain;
|
||||
set = doset;
|
||||
}.${kind} params;
|
||||
|
||||
dotable = family : chains : ''
|
||||
table ${family} table-${family} {
|
||||
${concatStringsSep "\n" (map dochain chains)}
|
||||
${concatStringsSep "\n" (map dochainorset chains)}
|
||||
}
|
||||
'';
|
||||
categorise = chains :
|
||||
groupBy
|
||||
({ family, ... } : family)
|
||||
(mapAttrsToList (n : v : v // { name = n; }) chains);
|
||||
(mapAttrsToList (n : v : { name = n; } // v ) chains);
|
||||
in writeScript name ''
|
||||
#!${nftables}/sbin/nft -f
|
||||
|
||||
|
||||
@@ -121,4 +121,23 @@ let
|
||||
};
|
||||
in {
|
||||
inherit input-ip6 forward-ip6 bogons-ip6 incoming-allowed-ip6;
|
||||
lan-set-ip = {
|
||||
kind = "set";
|
||||
family = "ip";
|
||||
type = "ifname";
|
||||
elements = [
|
||||
"eth0" "eth1"
|
||||
];
|
||||
|
||||
};
|
||||
# honours timeout flags gc-interval size policy counter auto-merge
|
||||
lan-set-ip6 = {
|
||||
kind = "set";
|
||||
family = "ip6";
|
||||
type = "ifname";
|
||||
elements = [
|
||||
"eth0" "eth1"
|
||||
];
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ stdenv.mkDerivation rec {
|
||||
|
||||
dontStrip = true;
|
||||
dontPatchELF = true;
|
||||
outputs = ["out" "headers" "modulesupport"] ++ targetNames;
|
||||
outputs = ["out" "headers" "modulesupport" "config"] ++ targetNames;
|
||||
phases = [
|
||||
"unpackPhase"
|
||||
"butcherPkgconfig"
|
||||
@@ -114,5 +114,6 @@ stdenv.mkDerivation rec {
|
||||
mkdir -p $modulesupport
|
||||
make modules
|
||||
cp -a . $modulesupport
|
||||
cp .config $config
|
||||
'';
|
||||
}
|
||||
|
||||
+10
-2
@@ -2,6 +2,8 @@
|
||||
stdenv
|
||||
, dtc
|
||||
, lib
|
||||
, runCommand
|
||||
, writeText
|
||||
}:
|
||||
{ dts
|
||||
, includes
|
||||
@@ -10,14 +12,20 @@
|
||||
cppDtSearchFlags = builtins.concatStringsSep " " (map (f: "-I${f}") includes);
|
||||
dtcSearchFlags = builtins.concatStringsSep " " (map (f: "-i${f}") includes);
|
||||
cmdline = lib.concatStringsSep " " commandLine;
|
||||
chosen = writeText "chosen.dtsi" "/{ chosen { bootargs = ${builtins.toJSON cmdline}; }; };";
|
||||
combined = writeText "combined-dts-fragments"
|
||||
(lib.concatStrings
|
||||
(builtins.map
|
||||
(f: "#include \"${f}\"\n")
|
||||
(dts ++ [ chosen ])));
|
||||
in stdenv.mkDerivation {
|
||||
name = "dtb";
|
||||
phases = [ "buildPhase" ];
|
||||
nativeBuildInputs = [ dtc ];
|
||||
buildPhase = ''
|
||||
${stdenv.cc.targetPrefix}cpp -nostdinc -x assembler-with-cpp ${cppDtSearchFlags} -undef -D__DTS__ -o dtb.tmp ${dts}
|
||||
echo '/{ chosen { bootargs = ${builtins.toJSON cmdline}; }; };' >> dtb.tmp
|
||||
${stdenv.cc.targetPrefix}cpp -nostdinc -x assembler-with-cpp ${cppDtSearchFlags} -undef -D__DTS__ -o dtb.tmp ${combined}
|
||||
dtc ${dtcSearchFlags} -I dts -O dtb -o $out dtb.tmp
|
||||
# dtc -I dtb -O dts $out
|
||||
test -e $out
|
||||
'';
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
hash-2 {
|
||||
algo = "sha1";
|
||||
};
|
||||
};
|
||||
};
|
||||
fdt-1 {
|
||||
description = "Flattened Device Tree blob";
|
||||
// data = /incbin/("./target.dtb");
|
||||
@@ -40,8 +40,12 @@
|
||||
};
|
||||
|
||||
configurations {
|
||||
default = "conf-1";
|
||||
conf-1 {
|
||||
// The OpenWRT One wants this to be 'config-1' specifically. For now it's
|
||||
// easy to just choose that, if there's another device that has a
|
||||
// different restriction then we should probably add 'if not found
|
||||
// select default' logic and/or make this configurable.
|
||||
default = "config-1";
|
||||
config-1 {
|
||||
description = "Boot Linux kernel with FDT blob";
|
||||
kernel = "kernel";
|
||||
fdt = "fdt-1";
|
||||
|
||||
@@ -71,7 +71,7 @@ in {
|
||||
};
|
||||
};
|
||||
_VARS
|
||||
mkimage -f mkimage.its ${lib.optionalString (alignment != null) "-B 0x${lib.toHexString alignment}"} kernel.uimage
|
||||
mkimage -f mkimage.its -E ${lib.optionalString (alignment != null) "-B 0x${lib.toHexString alignment}"} kernel.uimage
|
||||
mkimage -l kernel.uimage
|
||||
'';
|
||||
|
||||
|
||||
+56
-56
@@ -35,24 +35,24 @@ int open_shipper_socket(char *pathname) {
|
||||
static int fail_count = 0;
|
||||
|
||||
struct sockaddr_un sa = {
|
||||
.sun_family = AF_LOCAL
|
||||
.sun_family = AF_LOCAL
|
||||
};
|
||||
strncpy(sa.sun_path, pathname, sizeof(sa.sun_path) - 1);
|
||||
|
||||
fd = socket(AF_LOCAL, SOCK_STREAM, 0);
|
||||
if(fd >= 0) {
|
||||
if(connect(fd, (struct sockaddr *) &sa, sizeof sa)) {
|
||||
if((fail_count % 30) == 0)
|
||||
printf(PROGRAM_NAME ": cannot connect socket \"%s\": %s\n",
|
||||
pathname,
|
||||
strerror(errno));
|
||||
|
||||
fail_count++;
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
int flags = fcntl(fd, F_GETFL);
|
||||
fcntl(fd, F_SETFL, flags | O_NONBLOCK);
|
||||
if(connect(fd, (struct sockaddr *) &sa, sizeof sa)) {
|
||||
if((fail_count % 30) == 0) {
|
||||
printf(PROGRAM_NAME ": cannot connect socket \"%s\": %s\n",
|
||||
pathname,
|
||||
strerror(errno));
|
||||
}
|
||||
fail_count++;
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
int flags = fcntl(fd, F_GETFL);
|
||||
fcntl(fd, F_SETFL, flags | O_NONBLOCK);
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
@@ -75,7 +75,7 @@ int main(int argc, char * argv[]) {
|
||||
int tee_bytes = 0;
|
||||
|
||||
if(argc != 3) {
|
||||
error(1, 0, "usage: " PROGRAM_NAME " /path/to/socket cookie-text");
|
||||
error(1, 0, "usage: " PROGRAM_NAME " /path/to/socket cookie-text");
|
||||
}
|
||||
char * socket_pathname = argv[1];
|
||||
char * cookie = argv[2];
|
||||
@@ -83,8 +83,8 @@ int main(int argc, char * argv[]) {
|
||||
char * stop_cookie = malloc(strlen(cookie) + 7);
|
||||
|
||||
if(strlen(socket_pathname) > 108) {
|
||||
error(1, 0, "socket pathname \"%s\" is too long, max 108 bytes",
|
||||
socket_pathname);
|
||||
error(1, 0, "socket pathname \"%s\" is too long, max 108 bytes",
|
||||
socket_pathname);
|
||||
};
|
||||
|
||||
strcpy(start_cookie, cookie); strcat(start_cookie, " START\n");
|
||||
@@ -97,46 +97,46 @@ int main(int argc, char * argv[]) {
|
||||
|
||||
int quitting = 0;
|
||||
while(! quitting) {
|
||||
int nfds = poll(fds, 3, 2000);
|
||||
if(nfds > 0) {
|
||||
if((fds[0].revents & (POLLIN|POLLHUP)) &&
|
||||
(out_bytes == 0) &&
|
||||
(tee_bytes == 0)) {
|
||||
out_bytes = read(fds[0].fd, buf, 8192);
|
||||
if(out_bytes == 0) {
|
||||
quitting = 1;
|
||||
buf = PROGRAM_NAME " detected eof of file on stdin, exiting\n";
|
||||
out_bytes = strlen(buf);
|
||||
};
|
||||
if(is_connected()) tee_bytes = out_bytes;
|
||||
};
|
||||
int nfds = poll(fds, 3, 2000);
|
||||
if(nfds > 0) {
|
||||
if((fds[0].revents & (POLLIN|POLLHUP)) &&
|
||||
(out_bytes == 0) &&
|
||||
(tee_bytes == 0)) {
|
||||
out_bytes = read(fds[0].fd, buf, 8192);
|
||||
if(out_bytes == 0) {
|
||||
quitting = 1;
|
||||
buf = PROGRAM_NAME " detected eof of file on stdin, exiting\n";
|
||||
out_bytes = strlen(buf);
|
||||
};
|
||||
if(is_connected()) tee_bytes = out_bytes;
|
||||
};
|
||||
|
||||
if(out_bytes) {
|
||||
out_bytes -= write(fds[1].fd, buf, out_bytes);
|
||||
};
|
||||
if(fds[1].revents & (POLLERR|POLLHUP)) {
|
||||
exit(1); // can't even log an error if the logging stream fails
|
||||
};
|
||||
if(is_connected()) {
|
||||
if(tee_bytes) {
|
||||
tee_bytes -= write(fds[2].fd, buf, tee_bytes);
|
||||
};
|
||||
if(fds[2].revents & (POLLERR|POLLHUP)) {
|
||||
close(fds[2].fd);
|
||||
fds[2].fd = -1;
|
||||
(void) write(1, stop_cookie, strlen(stop_cookie));
|
||||
};
|
||||
};
|
||||
} else {
|
||||
if(! is_connected()) {
|
||||
fds[2].fd = open_shipper_socket(argv[1]);
|
||||
if(is_connected()) {
|
||||
/* write cookie to stdout so that the backfill
|
||||
* process knows we are now logging realtime
|
||||
*/
|
||||
write(fds[1].fd, start_cookie, strlen(start_cookie));
|
||||
}
|
||||
}
|
||||
};
|
||||
if(out_bytes) {
|
||||
out_bytes -= write(fds[1].fd, buf, out_bytes);
|
||||
};
|
||||
if(fds[1].revents & (POLLERR|POLLHUP)) {
|
||||
exit(1); // can't even log an error if the logging stream fails
|
||||
};
|
||||
if(is_connected()) {
|
||||
if(tee_bytes) {
|
||||
tee_bytes -= write(fds[2].fd, buf, tee_bytes);
|
||||
};
|
||||
if(fds[2].revents & (POLLERR|POLLHUP)) {
|
||||
close(fds[2].fd);
|
||||
fds[2].fd = -1;
|
||||
(void) write(1, stop_cookie, strlen(stop_cookie));
|
||||
};
|
||||
};
|
||||
} else {
|
||||
if(! is_connected()) {
|
||||
fds[2].fd = open_shipper_socket(argv[1]);
|
||||
if(is_connected()) {
|
||||
/* write cookie to stdout so that the backfill
|
||||
* process knows we are now logging realtime
|
||||
*/
|
||||
write(fds[1].fd, start_cookie, strlen(start_cookie));
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
# There is stuff in the nixpkgs nginx that's quite difficult to
|
||||
# disable if you want the smallest possible nginx for a single use, so
|
||||
# herewith a derivation that allows fine-grained control of all the
|
||||
# --with and --without options. The patches are from nixpkgs (or from
|
||||
# openwrt via nixpkgs, it looks like) and at least one of them is
|
||||
# essential for making the package cross-compilable
|
||||
|
||||
{
|
||||
stdenv
|
||||
, openssl
|
||||
, fetchzip
|
||||
, fetchpatch
|
||||
, pcre
|
||||
, zlib
|
||||
, lib
|
||||
, options ? []
|
||||
}:
|
||||
let
|
||||
# nginx configure script does not accept a with-foo_module flag for
|
||||
# a foo_module that's already included, nor a without-foo_module
|
||||
# for a module that isn't. Ho hum
|
||||
# grep -E 'without.+\)' auto/options | sed -e 's/).*$//g' -e 's/.*--without-//g'
|
||||
defaultEnabled = [
|
||||
"select_module"
|
||||
"poll_module"
|
||||
"quic_bpf_module"
|
||||
"http"
|
||||
"http-cache"
|
||||
"http_charset_module"
|
||||
"http_gzip_module"
|
||||
"http_ssi_module"
|
||||
"http_userid_module"
|
||||
"http_access_module"
|
||||
"http_auth_basic_module"
|
||||
"http_mirror_module"
|
||||
"http_autoindex_module"
|
||||
"http_status_module"
|
||||
"http_geo_module"
|
||||
"http_map_module"
|
||||
"http_split_clients_module"
|
||||
"http_referer_module"
|
||||
"http_rewrite_module"
|
||||
"http_proxy_module"
|
||||
"http_fastcgi_module"
|
||||
"http_uwsgi_module"
|
||||
"http_scgi_module"
|
||||
"http_grpc_module"
|
||||
"http_memcached_module"
|
||||
"http_limit_conn_module"
|
||||
"http_limit_req_module"
|
||||
"http_empty_gif_module"
|
||||
"http_browser_module"
|
||||
"http_upstream_hash_module"
|
||||
"http_upstream_ip_hash_module"
|
||||
"http_upstream_least_conn_module"
|
||||
"http_upstream_random_module"
|
||||
"http_upstream_keepalive_module"
|
||||
"http_upstream_zone_module"
|
||||
"mail_pop3_module"
|
||||
"mail_imap_module"
|
||||
"mail_smtp_module"
|
||||
"stream_limit_conn_module"
|
||||
"stream_access_module"
|
||||
"stream_geo_module"
|
||||
"stream_map_module"
|
||||
"stream_split_clients_module"
|
||||
"stream_return_module"
|
||||
"stream_pass_module"
|
||||
"stream_set_module"
|
||||
"stream_upstream_hash_module"
|
||||
"stream_upstream_least_conn_module"
|
||||
"stream_upstream_random_module"
|
||||
"stream_upstream_zone_module"
|
||||
"pcre"
|
||||
"pcre2"
|
||||
];
|
||||
# for each in defaultEnabled that are not in withFlags,
|
||||
# add a --without option
|
||||
# for each in withFlags that are not in defaultEnabled,
|
||||
# add a --with option
|
||||
withouts = lib.subtractLists options defaultEnabled;
|
||||
withs = lib.subtractLists defaultEnabled options;
|
||||
|
||||
in stdenv.mkDerivation {
|
||||
pname = "nginx-small";
|
||||
version = "";
|
||||
buildInputs = [ openssl pcre zlib ];
|
||||
configureFlags =
|
||||
(map (f: "--with-${f}") withs)
|
||||
++ (map (f: "--without-${f}") withouts)
|
||||
++ lib.optional (pcre == null)
|
||||
"--without-http_rewrite_module"
|
||||
++ lib.optional (zlib == null)
|
||||
"--without-http_gzip_module";
|
||||
|
||||
env.NIX_CFLAGS_COMPILE = "-Wno-error=cpp"; # musl
|
||||
|
||||
configurePlatforms = [];
|
||||
patches = [
|
||||
(fetchpatch {
|
||||
url = "https://raw.githubusercontent.com/openwrt/packages/c057dfb09c7027287c7862afab965a4cd95293a3/net/nginx/patches/102-sizeof_test_fix.patch";
|
||||
sha256 = "0i2k30ac8d7inj9l6bl0684kjglam2f68z8lf3xggcc2i5wzhh8a";
|
||||
})
|
||||
(fetchpatch {
|
||||
url = "https://raw.githubusercontent.com/openwrt/packages/c057dfb09c7027287c7862afab965a4cd95293a3/net/nginx/patches/101-feature_test_fix.patch";
|
||||
sha256 = "0v6890a85aqmw60pgj3mm7g8nkaphgq65dj4v9c6h58wdsrc6f0y";
|
||||
})
|
||||
(fetchpatch {
|
||||
url = "https://raw.githubusercontent.com/openwrt/packages/c057dfb09c7027287c7862afab965a4cd95293a3/net/nginx/patches/103-sys_nerr.patch";
|
||||
sha256 = "0s497x6mkz947aw29wdy073k8dyjq8j99lax1a1mzpikzr4rxlmd";
|
||||
})
|
||||
];
|
||||
|
||||
src = fetchzip {
|
||||
url = "https://nginx.org/download/nginx-1.26.2.tar.gz";
|
||||
hash = "sha256-CQbvqISgca+LBpmTUuF8IuJZC9GNn8kT0hQwzfz+wH8=";
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
{ fetchFromGitHub, pkgsBuildBuild, lib }:
|
||||
let
|
||||
src = fetchFromGitHub {
|
||||
name = "openwrt-source";
|
||||
repo = "openwrt";
|
||||
owner = "openwrt";
|
||||
rev = "refs/tags/v24.10.0-rc4";
|
||||
hash = "sha256-7edkUCTfGnZeMWr/aXoQrP4I47iXhMi/gUxO2SR+Ylc=";
|
||||
};
|
||||
kernelVersion = "6.6.67";
|
||||
kernelSeries = lib.versions.majorMinor kernelVersion;
|
||||
doPatch = family: ''
|
||||
cp -av ${src}/target/linux/generic/files/* .
|
||||
chmod -R u+w .
|
||||
cp -av ${src}/target/linux/${family}/files/* .
|
||||
chmod -R u+w .
|
||||
test -d ${src}/target/linux/${family}/files-${kernelSeries}/ && cp -av ${src}/target/linux/${family}/files-${kernelSeries}/* .
|
||||
chmod -R u+w .
|
||||
patches() {
|
||||
for i in $* ; do patch --batch --forward -p1 < $i ;done
|
||||
}
|
||||
patches ${src}/target/linux/generic/backport-${kernelSeries}/*.patch
|
||||
patches ${src}/target/linux/generic/pending-${kernelSeries}/*.patch
|
||||
patches ${src}/target/linux/generic/hack-${kernelSeries}/*.patch
|
||||
patches ${src}/target/linux/${family}/patches-${kernelSeries}/*.patch
|
||||
patches \
|
||||
${./make-mtdsplit-jffs2-endian-agnostic.patch} \
|
||||
${./fix-mtk-wed-bm-desc-ptr.patch}
|
||||
'';
|
||||
in {
|
||||
inherit src;
|
||||
|
||||
# The kernel sources typically used with this version of openwrt
|
||||
# You can find this in `include/kernel-5.15` or similar in the
|
||||
# openwrt sources
|
||||
kernelSrc = pkgsBuildBuild.fetchurl {
|
||||
name = "linux.tar.gz";
|
||||
url = "https://cdn.kernel.org/pub/linux/kernel/v${lib.versions.major kernelVersion}.x/linux-${kernelVersion}.tar.gz";
|
||||
hash = "sha256-Vj6O6oa83xzAF3FPl6asQK2Zrl7PaBCVjcUDq93caL4=";
|
||||
};
|
||||
inherit kernelVersion;
|
||||
|
||||
applyPatches.ath79 = doPatch "ath79";
|
||||
applyPatches.ramips = doPatch "ramips";
|
||||
applyPatches.mediatek = doPatch "mediatek"; # aarch64
|
||||
applyPatches.mvebu = doPatch "mvebu"; # arm
|
||||
|
||||
applyPatches.rt2x00 = ''
|
||||
PATH=${pkgsBuildBuild.patchutils}/bin:$PATH
|
||||
for i in ${src}/package/kernel/mac80211/patches/rt2x00/6*.patch ; do
|
||||
fixed=$(basename $i).fixed
|
||||
sed '/depends on m/d' < $i | sed 's/CPTCFG_/CONFIG_/g' | recountdiff | filterdiff -x '*/local-symbols' > $fixed
|
||||
case $fixed in
|
||||
606-*)
|
||||
;;
|
||||
611-*)
|
||||
filterdiff -x '*/rt2x00.h' < $fixed | patch --forward -p1
|
||||
;;
|
||||
601-*|607-*)
|
||||
filterdiff -x '*/rt2x00_platform.h' < $fixed | patch --forward -p1
|
||||
;;
|
||||
*)
|
||||
cat $fixed | patch --forward -p1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
'';
|
||||
}
|
||||
@@ -29,6 +29,17 @@ let
|
||||
'';
|
||||
in {
|
||||
inherit src;
|
||||
|
||||
# The kernel sources typically used with this version of openwrt
|
||||
# You can find this in `include/kernel-5.15` or similar in the
|
||||
# openwrt sources
|
||||
kernelSrc = 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=";
|
||||
};
|
||||
kernelVersion = "5.15.137";
|
||||
|
||||
applyPatches.ath79 = doPatch "ath79";
|
||||
applyPatches.ramips = doPatch "ramips";
|
||||
applyPatches.mediatek = doPatch "mediatek"; # aarch64
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
From: Arnout Engelen <arnout@bzzt.net>
|
||||
Date: Wed, 18 Dec 2024 14:17:46 +0100
|
||||
|
||||
Partial patch from https://gti.telent.net/raboof/liminix/commit/641409230051b82616c6feb35f2c0e730e46f614
|
||||
|
||||
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c 2024-12-18 11:08:00.598231122 +0100
|
||||
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c 2024-12-18 11:08:29.845100034 +0100
|
||||
@@ -625,7 +625,7 @@
|
||||
|
||||
static u32 mt7915_mmio_wed_init_rx_buf(struct mtk_wed_device *wed, int size)
|
||||
{
|
||||
- struct mtk_rxbm_desc *desc = wed->rx_buf_ring.desc;
|
||||
+ struct mtk_wed_bm_desc *desc = wed->rx_buf_ring.desc;
|
||||
struct mt76_txwi_cache *t = NULL;
|
||||
struct mt7915_dev *dev;
|
||||
struct mt76_queue *q;
|
||||
@@ -56,38 +56,33 @@ let
|
||||
else "";
|
||||
in "unlink(${qpathname}); ${cmd} ${chown}";
|
||||
in mapAttrsToList (makeFile prefix) attrset;
|
||||
activateScript = attrset: writeText "makedevs.c" ''
|
||||
#include "defs.h"
|
||||
int main(int argc, char* argv[]) {
|
||||
chdir(argv[1]);
|
||||
${(builtins.concatStringsSep "\n" (visit "." attrset))}
|
||||
}
|
||||
'';
|
||||
in attrset:
|
||||
let makedevs = activateScript attrset;
|
||||
let
|
||||
activateScript = writeText "activate.c" ''
|
||||
#include "defs.h"
|
||||
int main(int argc, char* argv[]) {
|
||||
chdir(argv[1]);
|
||||
${(builtins.concatStringsSep "\n" (visit "." attrset))}
|
||||
}
|
||||
'';
|
||||
in stdenv.mkDerivation {
|
||||
name="make-stuff";
|
||||
name="system-configuration";
|
||||
src = ./.;
|
||||
|
||||
CFLAGS = "-Os";
|
||||
LDFLAGS = "-static -Xlinker -static";
|
||||
|
||||
postConfigure = ''
|
||||
cp ${makedevs} makedevs.c
|
||||
cp ${activateScript} activate.c
|
||||
'';
|
||||
makeFlags = ["makedevs"];
|
||||
makeFlags = ["activate"];
|
||||
installPhase = ''
|
||||
closure=${closureInfo { rootPaths = [ makedevs ]; }}
|
||||
closure=${closureInfo { rootPaths = [ activateScript ]; }}
|
||||
mkdir -p $out/bin $out/etc
|
||||
cp $closure/store-paths $out/etc/nix-store-paths
|
||||
$STRIP --remove-section=.note --remove-section=.comment --strip-all makedevs -o $out/bin/activate
|
||||
$STRIP --remove-section=.note --remove-section=.comment --strip-all activate -o $out/bin/activate
|
||||
ln -s ${s6-init-bin}/bin/init $out/bin/init
|
||||
cp -p ${writeFennel "restart-services" {} ./restart-services.fnl} $out/bin/restart-services
|
||||
# obfuscate the store path of min-copy-closure so that the output
|
||||
# closure doesn't include a bunch of build system stuff
|
||||
f=${buildPackages.min-copy-closure}; f=$(echo $f | sed 's/\(.....\)/\1_/g')
|
||||
substitute ${./build-system-install.sh} $out/install.sh --subst-var-by min-copy-closure $f
|
||||
chmod +x $out/install.sh
|
||||
cat > $out/bin/install <<EOF
|
||||
#!/bin/sh -e
|
||||
prefix=\''${1-/}
|
||||
@@ -104,8 +99,10 @@ in attrset:
|
||||
cp -v -fP \$src/bin/* \$src/etc/* \$dest
|
||||
${if attrset ? boot then ''
|
||||
(cd \$dest
|
||||
if test -e boot ; then rm boot ; fi
|
||||
ln -sf ${lib.strings.removePrefix "/" attrset.boot.target} ./boot
|
||||
test -d boot || mkdir boot
|
||||
cd boot
|
||||
cp ../${lib.strings.removePrefix "/" attrset.boot.target}/* .
|
||||
sync; sync
|
||||
)
|
||||
'' else ""}
|
||||
EOF
|
||||
|
||||
+12
-4
@@ -16,10 +16,18 @@
|
||||
|
||||
(print (.. "TFTP serving from " options.base-directory))
|
||||
|
||||
(fn merge-pathname [directory filename]
|
||||
(if (directory:match "/$")
|
||||
(.. directory filename)
|
||||
(.. directory "/" filename)))
|
||||
;; this is a copy of anoia append-path
|
||||
(fn merge-pathname [dirname filename]
|
||||
(let [base (or (string.match dirname "(.*)/$") dirname)
|
||||
result []]
|
||||
(each [component (string.gmatch filename "([^/]+)")]
|
||||
(if (and (= component "..") (> (# result) 0))
|
||||
(table.remove result)
|
||||
(= component "..")
|
||||
(error "path traversal attempt")
|
||||
true
|
||||
(table.insert result component)))
|
||||
(.. base "/" (table.concat result "/"))))
|
||||
|
||||
(->
|
||||
(tftp:listen
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
(local { : system : assoc : split : dup : table= : dig } (require :anoia))
|
||||
(local { : system : assoc : split : dup : table= : dig : append-path } (require :anoia))
|
||||
(local svc (require :anoia.svc))
|
||||
(import-macros { : define-tests : expect : expect= } :anoia.assert)
|
||||
|
||||
@@ -13,14 +13,14 @@
|
||||
(when (not (table= old-tree new-tree))
|
||||
(io.stderr:write "new ssh keys\n")
|
||||
(each [username pubkeys (pairs new-tree)]
|
||||
(with-open [f (assert (io.open (.. path "/" username) :w))]
|
||||
(with-open [f (assert (io.open (append-path path username) :w))]
|
||||
;; the keys are "1" "2" "3" etc, so pairs not ipairs
|
||||
(each [_ k (pairs pubkeys)]
|
||||
(f:write k)
|
||||
(f:write "\n")))))
|
||||
(each [k v (pairs old-tree)]
|
||||
(when (not (. new-tree k))
|
||||
(os.remove (.. path "/" k))))
|
||||
(os.remove (append-path path k))))
|
||||
new-tree)
|
||||
|
||||
(define-tests
|
||||
|
||||
@@ -3,7 +3,6 @@ let
|
||||
liminix = (import ./default.nix {
|
||||
device = (import ./devices/qemu);
|
||||
liminix-config = ./vanilla-configuration.nix;
|
||||
inherit nixpkgs;
|
||||
});
|
||||
here = builtins.toString ./.;
|
||||
in liminix.buildEnv.overrideAttrs (o: {
|
||||
|
||||
+29
-12
@@ -1,12 +1,18 @@
|
||||
set timeout 10
|
||||
set timeout 40
|
||||
fconfigure stdout -buffering none
|
||||
|
||||
set when [lindex $argv 0];
|
||||
|
||||
send_user "\n\n\n\n#################################\n running $when"
|
||||
|
||||
|
||||
spawn socat -,echo=0,icanon=1 unix-connect:vm/monitor
|
||||
set monitor_id $spawn_id
|
||||
fconfigure $monitor_id -buffering none
|
||||
|
||||
spawn socat unix-connect:vm/console -
|
||||
set console_id $spawn_id
|
||||
fconfigure $console_id -buffering none
|
||||
|
||||
proc chat {instr outstr} {
|
||||
expect {
|
||||
@@ -19,14 +25,20 @@ proc adddevice { } {
|
||||
global monitor_id console_id spawn_id
|
||||
set spawn_id $monitor_id
|
||||
|
||||
send_user "\n#### inserting usb device"
|
||||
send "\r\n"
|
||||
chat "QEMU" "device_add usb-storage,bus=xhci.0,drive=usbstick\n"
|
||||
chat "(qemu)" "version\r"
|
||||
|
||||
set spawn_id $console_id
|
||||
|
||||
expect {
|
||||
"sda: sda1" { }
|
||||
timeout { exit 1 }
|
||||
timeout {
|
||||
puts stderr "timeout waiting for disk"
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
send_user "done inserting usb device"
|
||||
}
|
||||
|
||||
if { $when eq "early" } {
|
||||
@@ -35,20 +47,25 @@ if { $when eq "early" } {
|
||||
|
||||
expect "BusyBox"
|
||||
chat "#" "PS1=RE\\ADY_\\ ; stty -echo \r"
|
||||
# script needs klogd output to tell when sda1 appears. Then
|
||||
# run s6-rc -b -a list to wait for booting to finish
|
||||
chat "READY_" "tail -f /run/log/current & \rs6-rc -b -a list\r"
|
||||
|
||||
chat "mount" "\r"
|
||||
|
||||
if { $when eq "late" } {
|
||||
adddevice
|
||||
}
|
||||
|
||||
send "\r"
|
||||
set timeout 20
|
||||
send_user "\n\n\nwaiting for mount to happen"
|
||||
|
||||
chat "READY_" "sleep 5; grep /srv /proc/mounts && hostname\r"
|
||||
|
||||
expect {
|
||||
"inout" { }
|
||||
timeout { exit 1 }
|
||||
set FINISHED 0
|
||||
set EXIT "1"
|
||||
while { $FINISHED < 10 } {
|
||||
chat "READY_" "grep /srv /proc/mounts\r\n"
|
||||
expect {
|
||||
"backup-disk" { set FINISHED 20; set EXIT 0; }
|
||||
"READY_" { send_user "waiting ...\n" ; send "\r\n"; sleep 6 }
|
||||
}
|
||||
set FINISHED [ expr $FINISHED + 1 ]
|
||||
}
|
||||
|
||||
exit $EXIT
|
||||
|
||||
@@ -18,13 +18,17 @@ mkfs.ext2 -L backup-disk ./vm/stick.e2fs
|
||||
dd if=/dev/zero of=./vm/stick.img bs=1M count=38
|
||||
dd if=./vm/stick.e2fs of=./vm/stick.img bs=512 seek=34 conv=notrunc
|
||||
parted -s ./vm/stick.img -- mklabel gpt mkpart backup-disk ext2 34s -0M
|
||||
sync
|
||||
cp ./vm/stick.img ./vm/stick.img.orig
|
||||
|
||||
{
|
||||
|
||||
|
||||
${img}/run.sh --background ./vm --flag -device --flag usb-ehci,id=xhci --flag -drive --flag if=none,id=usbstick,format=raw,file=$(pwd)/vm/stick.img
|
||||
expect ${./script.expect} late
|
||||
kill $(cat ./vm/pid)
|
||||
|
||||
cp ./vm/stick.img.orig ./vm/stick.img
|
||||
${img}/run.sh --background ./vm --flag -device --flag usb-ehci,id=xhci --flag -drive --flag if=none,id=usbstick,format=raw,file=$(pwd)/vm/stick.img
|
||||
expect ${./script.expect} early
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ let
|
||||
in {
|
||||
imports = [
|
||||
../../vanilla-configuration.nix
|
||||
../../modules/squashfs.nix
|
||||
../../modules/outputs/squashfs.nix
|
||||
../../modules/outputs/jffs2.nix
|
||||
];
|
||||
config.rootfsType = "jffs2";
|
||||
|
||||
@@ -17,6 +17,8 @@ serverstatedir=$(mktemp -d -t routeros-XXXXXX)
|
||||
# python scapy drags in matplotlib which doesn't enjoy running in
|
||||
# a sandbox with no $HOME, hence this environment variable
|
||||
export MPLCONFIGDIR=$(mktemp -d -t routeros-XXXXXX)
|
||||
export XDG_CONFIG_HOME=/tmp
|
||||
export XDG_CACHE_HOME=/tmp
|
||||
|
||||
. ${../test-helpers.sh}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user