forked from dan/liminix
1
0
Fork 0

Compare commits

...

272 Commits

Author SHA1 Message Date
Raito Bezarius d14ee41325 liminix-rebuild: use `-f` flag to reboot effectively
My AP does not reboot upon `reboot` but `reboot -f`… why?

Signed-off-by: Raito Bezarius <masterancpp@gmail.com>
2024-02-17 11:45:17 +00:00
Raito Bezarius 8f814658fe hostapd: enable 802.11ax
For people enjoying WiFi 6 heaven… :>

Signed-off-by: Raito Bezarius <masterancpp@gmail.com>
2024-02-17 11:45:10 +00:00
Daniel Barlow 60508f4d4e update NEWS
* Turris Omnia
* possible wifi regressions
2024-02-16 21:00:59 +00:00
Daniel Barlow ca64e9035e gl-ar750 ath9k needs cal data from MTD 2024-02-16 20:44:56 +00:00
Daniel Barlow 4bcc3d5b28 dhcpc6 scripts: simplify (and improve correctness) 2024-02-16 18:47:12 +00:00
Daniel Barlow 28fe37d555 deep thoughts 2024-02-16 18:30:54 +00:00
Daniel Barlow 175db9f604 tail -F for rotuer 2024-02-16 18:30:24 +00:00
Daniel Barlow b5722a0153 gl-ar750: ath10k wireless depends on firmware
so make sure the firmware is present _first_

the ath10k is still broken anyway, looking into why
2024-02-16 00:38:36 +00:00
Daniel Barlow c373152673 make tftpboot work on devices with old u-boot
Some devices have a U-boot variant that does not accept a third
parameter on the "bootm" command, meaning we can't override the dtb
in the bootloader so have to smush it back into the kernel image

This doesn't work in QEMU but I think the problem is with the
U-Boot configuration for QEMU. It does work on at least one
hardware device so I'm pushing it anyway

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

Co-authored-by:  Arnout Engelen <arnout@bzzt.net>
2024-02-15 23:44:47 +00:00
Daniel Barlow 7e7171556f subdue dnsmasq logs
we need to find a better way of doing this. people might _want_
to have All The Logs from evey dns query
2024-02-15 23:43:54 +00:00
Daniel Barlow 6920ee765d deep thoughts 2024-02-15 09:11:54 +00:00
Daniel Barlow 71a1ef286e deep thoughts 2024-02-13 22:32:57 +00:00
Daniel Barlow ffe0e9d26b use mkstate for dropbear keys 2024-02-13 22:12:26 +00:00
Daniel Barlow 2b22c7aa91 dnsmasq: store dhcp lease file on /persist 2024-02-13 21:54:45 +00:00
Daniel Barlow 3c950704e1 rename /run/service-state to /run/services/outputs 2024-02-13 21:41:43 +00:00
Daniel Barlow 8578a554c7 deep thoughts 2024-02-13 21:11:30 +00:00
Daniel Barlow 3851698d35 fix tftpboot compressed rootfs 2024-02-13 18:16:17 +00:00
Daniel Barlow f69ebbb6f5 fix doc CI target 2024-02-13 15:41:45 +00:00
Daniel Barlow 16e4b05653 dhcp6c: set preferred and valid address lifetimes
also workaround a bug in rebinding/updates where we get an error
from "ip addr add" trying to add an address that's already present
2024-02-13 13:49:12 +00:00
Daniel Barlow 8ac848b1e6 ath10k_pci: wifi modules must be modules 2024-02-13 12:56:03 +00:00
Daniel Barlow b7efbd3e21 update NEWS file 2024-02-12 21:10:52 +00:00
Daniel Barlow a654577ac2 improve port-forwarding comment 2024-02-12 21:05:01 +00:00
Daniel Barlow c50423f689 turris omnia: upgrade to mainline 6.7.4 kernel
On this device we don't need the openwrt kernel or patches. The
newer kernel also fixes the weird one minute pause at boot when
it was doing something with either mmc or switch.
2024-02-12 20:43:01 +00:00
Daniel Barlow 65479e206b use regular kernel not backports for mac80211
the kernel on most devices is now newer than the version that the
backported drivers were backported from
2024-02-12 20:41:10 +00:00
Daniel Barlow 79926c6fe7 remove call to deleted package 2024-02-12 14:56:12 +00:00
Daniel Barlow ae4856ea7c improve firewall comment 2024-02-12 13:56:56 +00:00
Daniel Barlow b9c0d93670 build modules at same time as main kernel vmlinux
This changes the practice for building kernel modules: now we expect
that the appropriate Kconfig symbols are set to =m in
config.kernel.config, and then use pkgs.kmodloader to create
a service that loads and unloads all the modules depended on by
a particular requirement.

Note that modules won't be installed on the target device just by
virue of having been built: only the modules that are referenced by a
kmodloader package will be in the closure.

An example may make this clearer: see modules/firewall/default.nix
in this commit.

Why?

If you have a compiled Linux kernel source tree and you change some
symbol from "is not set" to m and then run make modules, you cannot in
general expect that newly compiled module to work. This is because
there are places in the build of the main kernel where it looks to see
which modules _may_ be defined and uses that information to
accommodate them.

For example in an in-kernel build of

  https://github.com/torvalds/linux/blob/master/net/netfilter/core.c#L689

some symbols are defined only if CONFIG_NF_CONNTRACK is set, meaning
this code won't work if we have it unset initially then try later to
enable it and build modules only. Or see

  https://github.com/torvalds/linux/blob/master/include/linux/netdevice.h#L160
2024-02-11 23:47:11 +00:00
Daniel Barlow 11287a8436 allow lan dns queries (ipv6) 2024-02-11 23:32:46 +00:00
Daniel Barlow 57aece0709 rotuer: don't forward queries for local domain 2024-02-11 23:32:46 +00:00
Daniel Barlow c1d285a220 rotuer: network debugging tools 2024-02-11 23:32:46 +00:00
Daniel Barlow dce983ec79 move kernel module to its own subdir 2024-02-11 18:15:55 +00:00
Daniel Barlow 812f497660 add kernel.version param to allow for version-specific patches
default to 5.15.137 to avoid breaking the devices that don't declare it
2024-02-11 16:19:52 +00:00
Daniel Barlow 1206d02200 rotuer-secrets: remove root_password, add wifi ssid and domainName
this is step one towards getting rid of rotuer-secrets completely and
turning rotuer into a "profile" module that can be less hackily
customised for other people's networks
2024-02-11 15:56:14 +00:00
Daniel Barlow 7c196bf9b4 rotuer: make 5GHz wifi faster
VHT doesn't work unless HT is enabled, apparently
2024-02-11 15:38:19 +00:00
Daniel Barlow 86d19c54b3 turris omnia kernel: add RTC, i2c mux, eeprom 2024-02-09 22:34:46 +00:00
Daniel Barlow aca3e11631 firewall: make ipv4 work 2024-02-08 23:15:48 +00:00
dan 273c66b2d3 Merge pull request 'Add support for TP-Link Archer AX23' (#6) from raboof/liminix:add-archer-ax23-v1-bak into main
Reviewed-on: dan/liminix#6
2024-02-08 17:47:46 +00:00
Daniel Barlow 87f6a31a06 improve firewall log format 2024-02-08 17:21:26 +00:00
Daniel Barlow a9ea01428e firewall: don't drop in conntrack rule
as there are other rules following that might want to accept
2024-02-08 17:20:39 +00:00
Daniel Barlow 92b0bec038 rotuer: add schnapps and the rest of the lan interfaces 2024-02-07 23:48:10 +00:00
Daniel Barlow 82537bbe68 delete commented-out code 2024-02-07 23:47:38 +00:00
Daniel Barlow efb29c5901 demo-firewall: add some rules for ipv4 2024-02-07 23:47:09 +00:00
Daniel Barlow 29e61be26c rotuer: get lan rfc1918 prefix from secrets 2024-02-07 23:46:16 +00:00
Daniel Barlow 6f1f9d6f20 firewall: fix module loading 2024-02-07 23:43:41 +00:00
Daniel Barlow 34291292c0 fix dependency on kernel moduels in firewall service 2024-02-07 16:21:14 +00:00
Daniel Barlow c9e4c1b0da kernel-modules: use linuxArch instead of case expression 2024-02-07 16:20:34 +00:00
Arnout Engelen 63e3f2aa58
Add support for TP-Link Archer AX23 2024-02-06 18:00:55 +01:00
Arnout Engelen 61494fdc0c
Add tplink module for creating 'safeloader' images 2024-02-06 17:59:38 +01:00
Daniel Barlow 891d6e5f20 thenk 2024-02-05 19:20:13 +00:00
dan c4041b00f6 Merge pull request 'docs: add hardware recommendation' (#2) from raboof/liminix:hardware-recommendations into main
Reviewed-on: dan/liminix#2
2024-02-05 15:56:07 +00:00
Daniel Barlow f875622100 improve formatting 2024-02-04 18:24:01 +00:00
Daniel Barlow 49ec4a2961 installation instructions for Turris Omnia
feels like a milestone, or at least a big step towards one
2024-02-04 18:20:04 +00:00
Daniel Barlow c8154a2db9 kernel: add "conditional" config
imagine: you are using a device that requires
CONFIG_MYDEVICE_FROBOZZ_DRIVER but only if CONFIG_FROBOZZ has been
specified elsewhere. Because we check that every requested config
symbol actually appears in .config then it can't be added
unconditionally or the build will fail if CONFIG_FROBOZZ wasn't asked
for.

I'm not 100% happy about this design but it's the best I've thought of
so far.
2024-02-04 18:12:15 +00:00
Daniel Barlow 02cf2c6b80 add ssh keys in recovry image 2024-02-04 18:10:58 +00:00
Daniel Barlow b0709a6443 systemconfig: fix missing backslashes on env vars 2024-02-04 17:19:03 +00:00
Daniel Barlow 86f5c9b568 schnapps needs util-linux for mount
specifically, it expects mount /dev/foo -o blah /dest to work,
but busybox mount expects options to precede all the other
command line args
2024-02-04 15:50:25 +00:00
Daniel Barlow ef707de8b1 add extlinux in recovery example
this needlessly bloats the TFTP image, which is a shame, but is
needed for installing onto usb stick
2024-02-02 19:51:41 +00:00
Daniel Barlow 89c88dd472 specify type for rootDevice module option 2024-02-02 19:50:13 +00:00
Daniel Barlow c1ad139310 whitespace 2024-02-02 19:43:34 +00:00
Daniel Barlow f682b26c29 omnia seems very fussy about tftp load address
when loading with 0x1000000 base address, something was getting
corrupted in the uncompressed rootfs

$ head -c $(printf "%d" 0x2be0000) rootfs | sha1sum
142571fe0436c18191727d1d4c2fd32163c1f2e1  -
=> sha1sum 0x1000000 2be0000
sha1 for 01000000 ... 03bdffff ==> 142571fe0436c18191727d1d4c2fd32163c1f2e1

but!

$  head -c $(printf "%d" 0x2bf0000) rootfs | sha1sum
7aa004ba87c6772bade491fbade164e2dfe100f9  -
=> sha1sum 0x1000000 2bf0000
sha1 for 01000000 ... 03beffff ==> 1a0923a94784d0c0b86006c5e6fff1649770dad3
2024-02-02 19:36:11 +00:00
Daniel Barlow 84ce618213 recovery: grow fs to partition size before starting sshd
sshd expects there to be space in /persist/secrets that it can
use to write host keys, but when we make ext4fs images we don't
put any free space in them
2024-01-28 11:30:19 +00:00
Daniel Barlow 9e199c6957 tftpboot: compute dtbSize *after* changing dtb
Adding the reserved-memory node to the dtb can cause it to grow
by enough that it needs an extra page - this will overlap the start
of the kernel image if we calculate offsets based on the original size

Reported-by: sinavir
Authored-by: sinavir
2024-01-26 22:51:58 +00:00
Daniel Barlow c8e3d84bf4 think 2024-01-26 22:46:36 +00:00
Daniel Barlow dd8ec18881 restore boot.tftp.freeSpaceBytes 2024-01-26 22:46:36 +00:00
Daniel Barlow 1730cf07b1 bug workaround
If we set squashfs rootfsType, the image doesn't rebuild when
the kernel config is changed. Need to figure out why
2024-01-26 22:46:36 +00:00
Daniel Barlow de51bfe13d default root device in recovery to sda1
It will probably work fine for USB-stick boot (except in the case
where there is > 1 usb device plugged in, so maybe don't do that)

It doesn't matter for TFTP boot because boot.scr overrides the root=
param anyway
2024-01-26 22:46:36 +00:00
Daniel Barlow b09723345c don't put all of util-linux in recovery
it adds ~ 5MB to the image size
2024-01-26 22:46:36 +00:00
Daniel Barlow 1781d4b6e4 add lzma to buildenv 2024-01-26 22:46:36 +00:00
Daniel Barlow c219350d7c add usb storage for turris omnia
ideally we would make this a module instead of compiling in
directly
2024-01-26 22:46:36 +00:00
dan 6f83282ff5 Merge pull request 'openwrt: update to v23.05.2' (#4) from raboof/liminix:openwrt-update-to-v23.05.2 into main
Reviewed-on: dan/liminix#4
2024-01-26 22:39:11 +00:00
Arnout Engelen 04895f9cf6
openwrt: update to v23.05.2 2024-01-25 12:29:03 +01:00
dan 5f2d1660bd Merge pull request 'belkin-rt3200: Enable watchdog drivers' (#3) from sinavir/liminix:add_belkin_watchdog into main
Reviewed-on: dan/liminix#3
2024-01-24 14:36:08 +00:00
sinavir 7642e23c0a belkin-rt3200: Enable watchdog drivers 2024-01-24 13:38:55 +01:00
Daniel Barlow 83ee488e4c systemconfig: /boot needs to go inside /persist 2024-01-09 13:10:02 +00:00
Daniel Barlow f19a937eda omnia needs MARVELL_PHY for the WAN port to work
interestingly, we only see this when it boots from mmc, because
for tftpboot the bootloader has already performed negotiation
and therefore it works despite the missing option.
2024-01-09 13:07:14 +00:00
Daniel Barlow f0490f37d5 turris omnia: tidy config, remove dead bits 2024-01-08 19:22:42 +00:00
Daniel Barlow c1101d3af5 make extlinux work with liminix-rebuild
add /boot to the systemConfiguration closure
2024-01-08 18:58:07 +00:00
Daniel Barlow 9a3d7a387e correct turris omnia root device 2024-01-08 18:55:41 +00:00
Daniel Barlow 228c0a1668 pass rootOptions config as rootflags= kernel cmdline opt 2024-01-08 18:54:49 +00:00
Daniel Barlow 63f034e362 preinit: parse rootflags= in kernel command line 2024-01-08 00:35:13 +00:00
Daniel Barlow 6971d03520 preinit: check return from write() 2024-01-07 21:24:16 +00:00
Daniel Barlow 7bc9cb6c55 why is extlink hardcoding root device? 2024-01-07 20:30:23 +00:00
Daniel Barlow a251ceeb99 omnia releng 2024-01-07 16:54:44 +00:00
Daniel Barlow 38a7f0b03b turris omnia: add all lan devices
I think we might turn "lan" into a bridge, but that's for later
2024-01-07 16:54:44 +00:00
Daniel Barlow c0c4752350 systemconfig "install" cmd honours prefix on source 2024-01-07 16:54:44 +00:00
Daniel Barlow 3c941b4ce2 partial btrfs support
doesn't actually know how to make the filesystem, just
kernel config and accept it as a valid option
2024-01-07 16:43:43 +00:00
Daniel Barlow 243295aab8 recovery config for turris omnia 2024-01-07 14:58:46 +00:00
Daniel Barlow 45e8db09e1 liminix-rebuild: escape brackets in usage message 2024-01-07 14:18:19 +00:00
Daniel Barlow 2a93f24a58 add turris "schnapps" tool
in its current state this is useful for turris omnia only, but will
allow us to do installs and rollback to turris os if needed.
2024-01-05 00:07:01 +00:00
Daniel Barlow 64898eada8 mount tmpfs on /tmp
too much stuff doesn't work without it and it's not
all worth patching
2024-01-04 23:22:02 +00:00
Arnout Engelen d5026c2074
docs: add hardware recommendation
Also add infrastructure to also generate the supported hardware
page when building the docs locally
2024-01-04 14:35:00 +01:00
Daniel Barlow 136c5e6f32 alphabetize package list 2024-01-04 10:15:23 +00:00
Daniel Barlow fa9a2c6413 add btrfs-progs 2024-01-04 09:33:44 +00:00
Daniel Barlow 049cdbb610 turris omnia: don't hardcode rootfsType 2024-01-03 20:18:07 +00:00
Daniel Barlow 5ee4adff10 NEWS: we now expect Liminix 23.11 2024-01-03 19:44:49 +00:00
Daniel Barlow 9632a64b47 tftpboot: don't rely on hostname being set 2024-01-03 19:40:00 +00:00
Daniel Barlow fc5def2e15 don't need ubifs u-boot patch now
23.11 has upgraded to a newer u-boot that has ubifs by default
in the qemu-arm config
2024-01-03 19:12:46 +00:00
Daniel Barlow 9369fdf314 use patched qemu only for run-liminix-vm 2024-01-03 17:53:30 +00:00
Daniel Barlow d2e29543e2 bordervm: build wireshark without qt
(we only want tshark anyway)
2024-01-03 17:02:31 +00:00
Daniel Barlow dad7c2c875 don't overlay util-linux, rename to -small
looks like it's used in bootstrapping
2024-01-03 10:45:40 +00:00
Daniel Barlow 3459c04f64 don't need SDL in our custom qemu 2024-01-03 10:09:10 +00:00
Daniel Barlow ff991508ae build kernel only once for multiple outputs
e.g. vmlinux + zImage
2024-01-02 19:40:57 +00:00
Daniel Barlow e4ed9dbec9 delete dead comment 2024-01-02 18:10:56 +00:00
Daniel Barlow 9e0ef68c1f omnia: add MMC block device support 2024-01-02 18:09:44 +00:00
Daniel Barlow 870e4d86cc omnia: support fw_{print,set}env commands 2024-01-02 18:09:12 +00:00
Daniel Barlow d6f96c0448 add libubootenv package 2024-01-02 17:44:56 +00:00
Daniel Barlow e7747832ad turris-omnia: reindent 2024-01-01 20:24:47 +00:00
Daniel Barlow 921b4f24af boot.scr: append ; not \n to lzmadec command
this is simply to make copy-paste slightly more convenient
2024-01-01 20:21:42 +00:00
Daniel Barlow e505e37d9a build util-linux without systemd
this didnt work before but it does now, maybe because we
upgraded nixpkgs 23.05->23.11
2023-12-30 22:26:12 +00:00
Daniel Barlow 2152a3f207 a test for liminix-rebuild
it's hacky as Selby, but it's better than no test
2023-12-29 22:11:04 +00:00
Daniel Barlow ec1ff283da vmdisk output: allow extra params to run.sh 2023-12-29 18:12:57 +00:00
Daniel Barlow 0bf98c5243 add output for u-boot 2023-12-29 17:07:47 +00:00
Daniel Barlow dc42969ef6 dribble 2023-12-29 16:54:35 +00:00
Daniel Barlow 1a041392aa liminix-rebuild: add --no-reboot param 2023-12-27 17:47:42 +00:00
Daniel Barlow 6469408d5f run-liminix-vm: don't reverse order of --flags params 2023-12-26 21:59:00 +00:00
Daniel Barlow f020d5b25d qemu mips: enable rebooting 2023-12-26 21:58:18 +00:00
Daniel Barlow e5cbc2b86b WIP add systemConfiguration "install" command
which copies the init stuff (whatever it is) from store to /persist
instead of making liminix-rebuild have to know what the files are.

This is principally to ease making a system configuration in /mnt or
similar when operating in a rescue/recovery scenario, and we
don't want to liminix-rebuild because it will reboot
2023-12-23 23:53:47 +00:00
Daniel Barlow 29f35cb902 min-copy-closure: add --root to copy to non-standard place 2023-12-23 23:12:40 +00:00
Daniel Barlow dbf1ecdcb7 swap zimage and dtb in ram
kernel uncompression code creates a stack directly
after the compressed payload, which was trashing the dtb
2023-12-23 15:38:32 +00:00
Daniel Barlow aecc44aaa0 run-liminix-vm: --flag parameter passes arg straight to qemu 2023-12-23 15:32:59 +00:00
Daniel Barlow 1042be912c turris omnia: switch to regular tftpboot output
now it does zimage and rootfs compression
2023-12-23 00:05:34 +00:00
Daniel Barlow c931d84828 tftproot: put command line in dtb 2023-12-23 00:05:34 +00:00
Daniel Barlow 64a3f50248 tftpboot: support compressed root 2023-12-23 00:05:34 +00:00
Daniel Barlow c5e9fcecc7 uninit var 2023-12-23 00:05:34 +00:00
Daniel Barlow f25c41b4d2 tftpboot: move things around in memory
new layout has rootfs followed by kernel and dtb, so that we
know the rootfs start and size to embed them into the dtb instead
of having to use dummy values and fill them in afterwards
2023-12-23 00:05:34 +00:00
Daniel Barlow bfa68d9c55 remove unused variable 2023-12-23 00:05:34 +00:00
Daniel Barlow ff0ef825a6 tftpboot: add option for kernel image format 2023-12-23 00:05:34 +00:00
Daniel Barlow 44a0cf364b remove boot-scr output, merge into tftpboot
(1) it creates two things (script and dtb); (2) it's a bit pointless
without the tftpboot output it depends on
2023-12-22 21:37:15 +00:00
Daniel Barlow c7b2733bea tftpbootlz: put command line in dtb
this makes boot.scr substantially shorter, in anticipation of using it
for first boot of the omnia and not wanting to embed an essay in
a setenv value
2023-12-22 20:09:44 +00:00
Daniel Barlow dfbc72dd51 tftpboot test: fix reserved-memory dt for aarch64 2023-12-22 17:37:53 +00:00
Daniel Barlow 9f851b229c inadvertently committed, remove 2023-12-22 16:25:54 +00:00
Daniel Barlow fe2d41a2b1 wlan test: robustify, tail log on failure 2023-12-22 15:49:43 +00:00
Daniel Barlow 9b92bf8447 gazing into the abyss 2023-12-22 15:30:01 +00:00
Daniel Barlow 5f9ffa804f better detect test succeeded 2023-12-22 15:29:33 +00:00
Daniel Barlow 231c2cef03 make reserved-memory work on mips, and improve test 2023-12-21 22:21:20 +00:00
Daniel Barlow dbb82339bd tftpboot test: fail if reserved-memory node is wrong 2023-12-21 21:13:16 +00:00
Daniel Barlow 4a606a4b19 tidy up kernel patch 2023-12-21 21:12:55 +00:00
Daniel Barlow 9c894bdabf add tftpboot test for mips 2023-12-21 19:25:45 +00:00
Daniel Barlow a962f18369 run-liminix-vm: map rootfs file iff --phram-address supplied 2023-12-21 19:25:45 +00:00
Daniel Barlow 9a29a042e8 fix tftpboot test on boards without autoboot, swap wan/lan
This is for MIPS.  I spent a while investigating why the second virtio
net device doesn't function in qemu mips malta u-boot, but with no
success. Use the first one instead.
2023-12-21 19:25:16 +00:00
Daniel Barlow 46926a94db dont need phram-address param for tftpboot test
the phram setup for this test is all passed from
u-boot to the kernel
2023-12-21 19:24:58 +00:00
Daniel Barlow ab0631c555 qemu mips expects different file size for u-boot 2023-12-19 18:48:28 +00:00
Daniel Barlow 32c13c46bb support aarch64 in tftpboot test 2023-12-19 12:12:12 +00:00
Daniel Barlow e5db2691e5 add CI job to test tftpboot 2023-12-18 22:42:29 +00:00
Daniel Barlow 9ca9723c9d make rootfs work with tftpbootlz 2023-12-17 19:39:26 +00:00
Daniel Barlow d1e2d525a4 tftpboot omnia using bootz not bootm
because kernel size is now beyond the u-boot size
limit for bootm
2023-12-16 23:40:55 +00:00
Daniel Barlow f4f4387861 well, we're back to where we can boot again
so that's good
2023-12-16 23:40:55 +00:00
Daniel Barlow 55fa9992d4 WIP 2023-12-13 21:54:15 +00:00
Daniel Barlow 95d9e014fb omnia: fix paths 2023-12-13 21:52:28 +00:00
Daniel Barlow 80528376a2 move o.systemConfiguration to initramfs module
as far as I can tell, we define it identically in every module
that uses initramfs
2023-12-11 21:47:15 +00:00
Daniel Barlow d707345891 rename rootfsFiles to rootdir, add bootablerootdir 2023-12-11 21:21:12 +00:00
Daniel Barlow 133b64613d link to NEWS file 2023-12-11 20:18:28 +00:00
Daniel Barlow c6c41e331e let's have a place to document breaking changes 2023-12-11 19:09:56 +00:00
Daniel Barlow b878d6481a the first rule of thought club 2023-12-11 19:09:19 +00:00
Daniel Barlow 601bb289ee rename diskimage to mbrimage 2023-12-11 19:09:19 +00:00
Daniel Barlow 876bd7d8ce rename flashimage to mtdimage 2023-12-11 19:09:18 +00:00
Daniel Barlow 39c338d710 rm vanilla-configuration-hw.nix, no longer needed 2023-12-11 19:09:18 +00:00
Daniel Barlow 6c8b2bbb83 add retries to wlan test 2023-12-10 18:35:14 +00:00
Daniel Barlow 4ddce6e926 fix the tests we broke 2023-12-10 17:12:57 +00:00
Daniel Barlow 5eeb277564 move output module imports example -> device
The outputs available are a characteristic of the device, not
the example.
2023-12-10 16:38:53 +00:00
Daniel Barlow c81e7c4d35 move all output modules to subdirectory, trash standard.nix
standard.nix isn't, is the essence here. Not all devices
support flashimage as it is currently defined - some
have diskimage, some have neither
2023-12-10 15:23:12 +00:00
Daniel Barlow 53fed8839a fix min-copy-closure for new run-liminix-vm syntax 2023-12-09 17:35:21 +00:00
Daniel Barlow ebaa7b2bcb unbreak fennel test 2023-12-09 17:10:41 +00:00
Daniel Barlow 15d570f749 ignore devices/families when extracting docs 2023-12-09 17:10:41 +00:00
Raito Bezarius aff312bbbe project: Python 2.7 had an upgrade… ! 2023-12-09 17:10:41 +00:00
Daniel Barlow bb8e974c2b hard thinking or hardly thinking 2023-12-09 17:10:41 +00:00
Daniel Barlow 317457f582 extract common config for qemu devices into module 2023-12-09 17:10:41 +00:00
Daniel Barlow 07e66c462b use virtio-bk-pci instead of virtio-bk-device
u-boot is happy with either but Linux can autodetect the PCI-based
hardware
2023-12-09 15:53:40 +00:00
Daniel Barlow 4229b42d82 make config.hardware.dts.src nullable
This is for QEMU where we won't have to provide a dtb because the
device tree is built by the platform according the (emulated) hardware
present.

Maybe in future there will be other hardware devices where we
don't need to provide a dtb.
2023-12-09 15:51:30 +00:00
Daniel Barlow 03b17fa3ed add zImage output 2023-12-07 22:31:26 +00:00
Daniel Barlow a8891461aa use devtmpfs in initramfs
static device nodes don't work with virtio
2023-12-07 20:03:03 +00:00
Daniel Barlow 5adfb0230f WIP generate bootable disk image with partition table 2023-12-05 23:54:09 +00:00
Daniel Barlow b519bd15df pretty-print the qemu command line
well, pretty-ish
2023-12-05 17:32:18 +00:00
Daniel Barlow f2daa0b669 exclude rootfs region from kernel-visible ram 2023-12-05 17:32:18 +00:00
Daniel Barlow 3f74fad966 don't double-json the command line 2023-12-05 17:32:18 +00:00
Daniel Barlow ed925588f7 extract common code to make root filesystem hierarchy
which is then used by the filesystem image creators (ubifs, ext4,
jffs2 etc)
2023-12-05 17:32:18 +00:00
Daniel Barlow f08c10c8ba patch u-boot to add ubifs support
not that we're using it yet
2023-12-04 23:39:27 +00:00
Daniel Barlow d25a804f13 test wlan iun armv7 2023-12-04 23:37:39 +00:00
Daniel Barlow 0242cec977 run-liminix-vm: remove unneeded second copy of pad code 2023-12-04 23:37:39 +00:00
Daniel Barlow 5a2963543e thonk 2023-12-04 23:29:36 +00:00
Raito Bezarius 644f42c35e kernel: make the build FSAT on FSAT computers
I have 128 threads, builds should take only but a moment!
2023-12-03 23:05:12 +00:00
Daniel Barlow 98d3336926 rewrite run-liminix-vm as a fennel program
the effect of shell quoting/word splitting rules was reaching
completely unreasonable, insofar as I was unable to reason about it
2023-12-03 22:51:39 +00:00
Daniel Barlow cb6ebbdc60 alphabetize derivations in overlay 2023-12-02 17:08:59 +00:00
Daniel Barlow bb335050fd derivation that produces /boot 2023-12-02 15:31:55 +00:00
Daniel Barlow 395f624338 think 2023-12-02 15:31:09 +00:00
Daniel Barlow e518ab667b make job control work in console shell 2023-11-29 19:49:51 +00:00
Daniel Barlow 382128b6cf omnia: make wan interface work 2023-11-28 21:38:45 +00:00
Daniel Barlow c803772074 omnia: add hardware ethernet and switch config 2023-11-27 21:37:15 +00:00
Daniel Barlow 32c24f3809 switch pppoe test back to qemu mips
while we find out why it fails
2023-11-26 23:18:24 +00:00
Daniel Barlow cc73a98419 support setting network device names
this means that net devices in devices/foo/default.nix can be
specified by their sysfs paths (instead of by "eth0" and "eth1" that
may change from one kernel version to the next) and given mnenomic
names that are helpful for the hardware. Like "wan" and "lan[1..4]"
2023-11-26 23:15:28 +00:00
Daniel Barlow e2ea145ce5 wip 2023-11-26 22:43:56 +00:00
Daniel Barlow b036a161f5 thonk 2023-11-26 22:43:31 +00:00
Daniel Barlow 31a2969972 omnia: add support for wifi
- ath9k and ath10k, both on PCI bus (which can be enumerated, hence
they don't need to be in device tree)

- need to disable PCIe ASPM for the ath9k to work

- appropriate firmware files added for ath10k
2023-11-26 13:25:01 +00:00
Daniel Barlow 76a370cc92 omnia kernel: add watchdog
it's enabled by u-boot so we need at least this minimal capability
otherwise the system reboots after three minutes
2023-11-26 13:07:44 +00:00
Daniel Barlow bf9f264f0c update TODO 2023-11-25 18:49:26 +00:00
Daniel Barlow e35b61b68c mac80211: support ath9k pci variant
if you ask for "ath9k" you get AHB, but if you ask for "atk9k_pci"
now you get PCI. Note that the kernel module name is the same in
both cases.
2023-11-25 18:39:15 +00:00
Daniel Barlow a8f98ccfe7 use linuxArch instead of case statement 2023-11-25 18:16:20 +00:00
Daniel Barlow 27ce61ae4e add bootable config for Turris Omnia 2023-11-24 23:29:12 +00:00
Daniel Barlow 3f0f621809 openwrt patches for mvebu (armv7l) 2023-11-24 22:43:58 +00:00
Daniel Barlow b0ae314df4 stuff 2023-11-24 22:33:42 +00:00
Daniel Barlow d789a23113 twiddle timeouts 2023-11-24 21:32:53 +00:00
Daniel Barlow 5ba14fd915 add levitate package
sets up a chroot system in tmpfs that will be executed on the next
reboot to enable system maintenance without the regular filesystems
mounted
2023-11-23 22:21:03 +00:00
Daniel Barlow 3df34428d6 remove unneeded login and getty applets 2023-11-23 20:01:13 +00:00
Daniel Barlow 62c788eb86 add hook to run maintenance mode instead of rebooting 2023-11-22 00:05:55 +00:00
Daniel Barlow bab6d346a8 add .../s6/bin to PATH for shutdownd 2023-11-22 00:05:03 +00:00
Daniel Barlow a202ae476a extract console redirection stuff from "quit" function
so we can use it for scripts that don't reboot at their end
2023-11-21 23:32:37 +00:00
Daniel Barlow 7c9297f91d use shotdown instead of hpr in .s6-svscan/SIGFOO
this is to bring them into line with what more recent
s6-init-linux-maker creates
2023-11-21 23:19:00 +00:00
Daniel Barlow a0bd250963 switch from getty to root shell on console
this just makes things marginally simpler
2023-11-21 23:09:48 +00:00
Daniel Barlow c8b2d58dd3 exit 0 on service down even if no outputs to delete 2023-11-21 17:25:50 +00:00
Daniel Barlow e5223f093f kernel.src may be a path not just a package
this makes it easier to hack the kernel locally and test things
2023-11-18 14:21:18 +00:00
Daniel Barlow c563a6451f add missing param 2023-11-18 14:20:59 +00:00
Daniel Barlow f45326b9d3 why we decided not to depend on kexec 2023-11-18 11:51:57 +00:00
Daniel Barlow f9f4d97bb8 convert flash params to int 2023-11-12 20:39:06 +00:00
Daniel Barlow abfb35a231 and entryPoint 2023-11-12 18:50:47 +00:00
Daniel Barlow 315907de98 convert hardware loadAddress to int 2023-11-12 18:47:31 +00:00
Daniel Barlow 185117843b convert tftp.loadAddress from string to int 2023-11-12 18:37:33 +00:00
Daniel Barlow 0131686661 use parseInt for hex values 2023-11-12 18:25:38 +00:00
Daniel Barlow 3da692f7ef don't import flashimage unconditionally, it breaks qemu 2023-11-12 18:11:13 +00:00
Daniel Barlow f61e737b54 improve doc for outputs and hardware
Changed my mind about "installer" as a first-class concept, at least
in the current implementation. Not every documented output is an
installer
2023-11-12 17:15:58 +00:00
Daniel Barlow 262efaabe6 doc: put all the u-boot/serial stuff in one place to link from 2023-11-12 17:14:33 +00:00
Daniel Barlow 7cfb92e3ce more doc 2023-11-10 21:17:20 +00:00
Daniel Barlow 22882dabee think 2023-11-10 21:10:26 +00:00
Daniel Barlow 5e046490de support links from device pages to their installation methods 2023-11-09 23:02:35 +00:00
Daniel Barlow a9760d239c basic doc for flashimage installer 2023-11-09 22:43:50 +00:00
Daniel Barlow 5729cfb4a7 document installation methods (only vmroot yet) 2023-11-09 22:14:31 +00:00
Daniel Barlow 7d5c7b9b44 export evaluation from default.nix and use it for docs 2023-11-09 22:14:31 +00:00
Daniel Barlow 23b3a2baef extract vmroot output into its own file 2023-11-08 23:19:11 +00:00
Daniel Barlow 4cb4f904f8 delete unused kconfig for arm qemus 2023-11-08 21:28:12 +00:00
Daniel Barlow a9d847e2c0 add ext4 as rootfsType 2023-11-06 21:52:31 +00:00
Daniel Barlow 6bbff2f5b3 think think 2023-11-05 23:39:50 +00:00
Daniel Barlow 5c1f5fabe2 switch pppoe test to use armv7l 2023-11-05 23:19:40 +00:00
Daniel Barlow 6489a39424 qemu armv7 2023-11-05 23:19:11 +00:00
Daniel Barlow c94d12934f remove direct use of run-liminix-vm from tests and doc 2023-11-05 20:37:23 +00:00
Daniel Barlow c40eef25d6 qemu: use phram instead of block2mtd 2023-11-05 19:13:51 +00:00
Daniel Barlow 46991e2761 aarch64 ram starts at 0x40000000 2023-11-05 15:33:10 +00:00
Daniel Barlow a135cb1217 introduce lim, the liminix library
so far we have lim.parseInt, which parses an integer from a string
with optional base-selecting-prefix (e.g. 0755, 0x12ab)
2023-11-05 15:13:06 +00:00
Daniel Barlow 863045b86b added hardware.ram.startAddress config
it's not 0 on arm32, so this will be useful for qemu
2023-11-05 15:11:58 +00:00
Daniel Barlow 629624bb25 replace multiway if with pkgs.stdenv.hostPlatform.qemuArch 2023-11-05 11:40:26 +00:00
Daniel Barlow 92b9bf959e options.system.outputs.initramfs -> initramfs module 2023-11-05 11:33:02 +00:00
Daniel Barlow c5c5f1687a patch qemu to load uncompressed ARM kernels at correct offset 2023-11-05 11:32:47 +00:00
Daniel Barlow 80793aa694 belkin rt3200 is a ubifs device 2023-11-05 11:32:23 +00:00
Daniel Barlow 824536f9b3 in uimage FIT, honour ${arch} 2023-11-05 11:31:28 +00:00
Daniel Barlow e6cb5e319b extract NETDEVICES kconfig to kernel.nix module 2023-11-05 11:31:23 +00:00
Daniel Barlow c3ccee6506 preinit: print errno (in hex, it's easier) for failures 2023-11-05 11:27:57 +00:00
Daniel Barlow 6db982f25f preinit: pause before exiting
as explained in the comment, this is to give us a
chance to see error messages before the kernel panics
2023-11-05 11:27:57 +00:00
Daniel Barlow 86a5224f3c preinit: fix compiler warnings 2023-11-05 11:27:43 +00:00
Daniel Barlow 155a29d9b3 preinit: strip trailing newline(s) on /proc/cmdline 2023-11-05 11:27:34 +00:00
Daniel Barlow e6ef4f78bb "ubimage" module contains ubifs image + instructions
Presently either you run this from U-Boot or you figure out for
yourself how to kexecboot into a recovery system :-)
2023-10-21 23:20:53 +01:00
Daniel Barlow d2f517a4e9 preinit.c: reindent 2023-10-19 21:02:18 +01:00
Daniel Barlow 0f38ee0e9c remove PREINIT_USE_LIBC option as it is now the only option 2023-10-19 18:59:02 +01:00
Daniel Barlow 61dc5beca8 preinit: parse rootfstype from kernel command line 2023-10-19 18:56:09 +01:00
Daniel Barlow f3225c2bd5 delete dup outputs.systemConfiguration
perhaps this should go into initramfs.nix not jffs2.nix
2023-10-19 10:09:08 +01:00
Daniel Barlow 8798ee9830 partial fix for timeout handling
1) "Unknown transfer id" message was because the local variable "tid"
is not a transfer id, it is a sequence number  - so the check was
actually comparing expected vs actual acknowledged sequence number,
not TID.  It's still a problem if we get the wrong one, but it
indicates a lost packet (so we should resend) not a packet that was
sent from somewhere else.

2) if the ACK packet has not been received, our retry should involve
_resending_ it, not just trying to wait for it again.

3) I have removed the timeout condition for terminating the resend
loop, because in practice (assuming both ends have the same timeout
setting) all it did was ensure that the loop only ran once. The
timeout is supposed to regulate how long we wait for before retrying
(it doesn't do this, we wait indefinitely), not how long we wait for
before giving up.
2023-10-18 23:35:23 +01:00
Daniel Barlow 629914f65e initial support for ubifs 2023-10-16 19:55:17 +01:00
Daniel Barlow 0693cf23d8 preinit: improve error logging for fork_exec 2023-10-12 19:00:57 +01:00
Daniel Barlow c341eb46b6 use hostPlatform.linuxArch in kernel derivation 2023-10-12 18:59:45 +01:00
Daniel Barlow 1a369ff3bf preinit: remove no-longer-used mips assembly 2023-10-12 18:57:54 +01:00
Daniel Barlow 364c5faf9e tftpboot: fix errors in phram partition size calc 2023-10-10 20:26:27 +01:00
Daniel Barlow 80a09a9a9b rt3200: move the entryPoint 2023-10-10 20:25:42 +01:00
Daniel Barlow 3518e2ecca Merge branch 'hark-how-all-the-belkin-rings' 2023-10-09 19:56:48 +01:00
Daniel Barlow fc2eb6ee4d rt3200 mumble 2023-10-09 19:56:22 +01:00
Daniel Barlow bd20f3e419 uimage: make fit optional 2023-10-09 19:47:57 +01:00
Daniel Barlow f62ad0e1d7 use "tftpboot" instead of "tftp" in u-boot commands
openwrt's u-boot installation doesn't accept the short form
2023-10-09 19:47:57 +01:00
Daniel Barlow ed792e0dc0 rt3200: swap wireless driver load order
mt7515e loads first, so that wlan0 is 2.4GHz
mt7515e loads after, so that 5GHz gets wlan1
2023-10-09 19:47:57 +01:00
Daniel Barlow d025c33d30 rt3200: enable flash/mtd 2023-10-09 19:47:57 +01:00
Daniel Barlow a755c9c3c5 delete some inapplicable kconfig 2023-10-09 19:47:57 +01:00
Daniel Barlow fdf74fa06b add mt7915, 7615 wifi modules
7915 won't work until we have working MTD, because it needs to
read calibration data from flash
2023-10-09 19:47:57 +01:00
Daniel Barlow b8dea2ed34 rt3200: add DSA
this creates a bunch of network interfaces {lan[1234],wan}@eth0
2023-10-09 19:47:57 +01:00
Daniel Barlow c18f07f02f aarch64: make tftpboot work
- patch dtb to add reserved-memory stanza for the phram device to use
  (aarch64 does not accept memmap= command line option)

- patch phram driver to use memremap() instead of ioremap() as
  ioremap can't be used for system ram on arm devices
2023-10-09 19:47:57 +01:00
Daniel Barlow 1c4412a1f4 rt3200: enable serial console 2023-10-09 19:47:57 +01:00
Daniel Barlow dbc16edf96 don't use ttyAMA0 console on all aarch64, just qemu 2023-10-09 19:47:57 +01:00
Daniel Barlow 528d619d76 WIP kernel config for belkin rt3200 2023-10-09 19:47:57 +01:00
140 changed files with 6526 additions and 1191 deletions

1
.gitignore vendored
View File

@ -6,3 +6,4 @@ result-*
_build
*-secrets.nix
examples/static-leases.nix
/doc/hardware.rst

82
NEWS Normal file
View File

@ -0,0 +1,82 @@
A brief guide to backward-incompatible changes
that are likely to break configurations or workflows
2023-07-13
* a significant re-arrangement of modules and services, which will
probably break any configuration written before this time. For a
detailed explanation, see
https://www.liminix.org/doc/configuration.html#modules
2023-12-10
* configurations (usually) need no longer import modules from
modules/outputs because devices are expected to do this instead. This
change is because the outputs that make sense in any given context are
usually a property of the device being installed onto.
2023-12-11
* rename outputs.flashimage to outputs.mtdimage (and also diskimage to
mbrimage). This change is made in the expectation that "fooimage" is
the name of an outputs that gloms together other filesystem-like
outputs with some kind of partition table - so we might in future have
gptimage or lvmimage or ubimage.
2024-01-03
Liminix is now targeted to Nixpkgs 23.11 (not 23.05 as previously).
Upstream changes that have led to incompatible Liminix changes are:
* newer U-Boot version
* util-linux can now be built (previously depended on systemd)
2024-01-30
New port! Thanks to Arnout Engelen <arnout@bzzt.net>, Liminix
now runs on the TP-Link Archer AX23
2024-02-12
* We now build wifi drivers (mac80211) from the same kernel source as
the running kernel, instead of using drivers from the linux-backports
project. This may be a regression on some devices that depend on
OpenWrt patches for wireless functionality: if you have a device that
used to work and now doesn't, refer to OpenWrt
package/kernel/mac80211/patches/ to see if there's something in there
that needs to be applied.
* in general, we build kernel modules (e.g. for nftables) at the same
time as the kernel itself instead of expecting to be able to build
them afterwards as though they were "out of tree". Refer to commit
b9c0d93670275e69df24902b05bf4aa4f0fcbe96 for a fuller explanation
of how this simplifies things.
2024-02-13
So that we can be more consistent about services that would like their
state to be preserved across boots (assuming a writable filesystem)
these changes have been made
* /run/service-state has been moved to /run/services/outputs
to better reflect what it's used for
* /run/services/state is either a symlink to /persist/services/state
(if there's a writeable fs on /persist) or a directory (if there
isn't)
The change will lose your ssh host key(s) unless you copy them from
the old location to the new one before rebooting into the new system
mkdir -m 02751 -p /run/services/state/dropbear
cp /persist/secrets/dropbear/* /run/services/state/dropbear
The `output`, `mkoutputs` functions defined by ${serviceFns}
have been updated for the new location.
2024-02-16
New (or at least, previously unreported) port! Liminix now runs on the
Turris Omnia and has been serving my family's internet needs for most
of this week. Thanks to NGI0 Entrust and the NLnet Foundation for
sponsoring this development (and funding the hardware)

View File

@ -18,22 +18,14 @@ outside word goes across it.
Liminix is pre-1.0. We are still finding new and better ways to do things,
and there is no attempt to maintain backward compatibility with the old
ways. This will change when it settles down.
ways.
_In general:_ development mostly happens on the `main` branch, which is
therefore not guaranteed to build or to work on every commit. For the
latest functioning version, see [the CI system](https://build.liminix.org/jobset/liminix/build) and pick a revision with all jobs green.
The [NEWS](NEWS) file (available wherever you found this README) is
a high-level overview of breaking changes.
_In particular:_ as of July 2023, a significant re-arrangement of
modules and services is ongoing:
* if you are using out-of-tree configurations created before commit
2e50368, especially if they reference things under pkgs.liminix,
they will need updating. Look at changes to examples/rotuer.nix
for guidance
* the same is intermittently true for examples/{extensino,arhcive}.nix
where I've updated rotuer and not updated them to match.
Development mostly happens on the `main` branch, which is therefore
not guaranteed to build or to work on every commit. For the latest
functioning version, see [the CI system](https://build.liminix.org/jobset/liminix/build) and pick a revision with all jobs green.
## Documentation
@ -41,7 +33,7 @@ modules and services is ongoing:
Documentation is in the [doc](doc/) directory. You can build it
by running
nix-shell -p sphinx --run "make -C doc html"
nix-shell -p sphinx --run "make -C doc hardware.rst html"
Rendered documentation corresponding to the latest commit on `main`
is published to [https://www.liminix.org/doc/](https://www.liminix.org/doc/)

File diff suppressed because it is too large Load Diff

View File

@ -99,14 +99,16 @@ in {
};
};
};
environment.systemPackages = with pkgs; [
tcpdump
wireshark
socat
tufted
iptables
usbutils
];
environment.systemPackages =
let wireshark-nogui = pkgs.wireshark.override { withQt = false ; };
in with pkgs; [
tcpdump
wireshark-nogui
socat
tufted
iptables
usbutils
];
security.sudo.wheelNeedsPassword = false;
networking = {
hostName = "border";

74
ci.nix
View File

@ -8,48 +8,64 @@ let
pkgs = (import nixpkgs {});
borderVmConf = ./bordervm.conf-example.nix;
inherit (pkgs.lib.attrsets) genAttrs;
devices = {
virt = [ "qemu" "qemu-aarch64" ];
hw = [ "gl-ar750" "gl-mt300n-v2" "gl-mt300a" ];
};
devices = [
"gl-ar750" "gl-mt300n-v2" "gl-mt300a"
"qemu" "qemu-aarch64" "qemu-armv7l"
"tp-archer-ax23"
];
vanilla = ./vanilla-configuration.nix;
for-device = cfg: name:
for-device = name:
(import liminix {
inherit nixpkgs borderVmConf;
device = import (liminix + "/devices/${name}");
liminix-config = cfg;
liminix-config = vanilla;
}).outputs.default;
tests = import ./tests/ci.nix;
jobs =
(genAttrs devices.hw (name: for-device ./vanilla-configuration-hw.nix name)) //
(genAttrs devices.virt (name: for-device vanilla name)) //
(genAttrs devices for-device) //
tests //
{
buildEnv = (import liminix {
inherit nixpkgs borderVmConf;
inherit nixpkgs borderVmConf;
device = import (liminix + "/devices/qemu");
liminix-config = vanilla;
}).buildEnv;
doc = pkgs.stdenv.mkDerivation {
name = "liminix-doc";
nativeBuildInputs = with pkgs; [
gnumake sphinx
fennel luaPackages.lyaml
];
src = ./doc;
buildPhase = ''
cat ${(import ./doc/extract-options.nix).doc} > options.json
cat options.json | fennel --correlate parse-options.fnl > modules-generated.rst
cp ${(import ./doc/hardware.nix)} hardware.rst
make html
'';
installPhase = ''
mkdir -p $out/nix-support $out/share/doc/
cp modules.rst options.json $out
cp -a _build/html $out/share/doc/liminix
echo "file source-dist \"$out/share/doc/liminix\"" \
> $out/nix-support/hydra-build-products
'';
doc =
let json =
(import liminix {
inherit nixpkgs borderVmConf;
device = import (liminix + "/devices/qemu");
liminix-config = {...} : {
imports = [ ./modules/all-modules.nix ];
};
}).outputs.optionsJson;
installers = map (f: "system.outputs.${f}") [
"vmroot"
"mtdimage"
"ubimage"
];
inherit (pkgs.lib) concatStringsSep;
in pkgs.stdenv.mkDerivation {
name = "liminix-doc";
nativeBuildInputs = with pkgs; [
gnumake sphinx fennel luaPackages.lyaml
];
src = ./.;
buildPhase = ''
cat ${json} | fennel --correlate doc/parse-options.fnl > doc/modules-generated.rst
cat ${json} | fennel --correlate doc/parse-options-outputs.fnl > doc/outputs-generated.rst
cp ${(import ./doc/hardware.nix)} doc/hardware.rst
make -C doc html
'';
installPhase = ''
mkdir -p $out/nix-support $out/share/doc/
cd doc
cp *-generated.rst $out
ln -s ${json} $out/options.json
cp -a _build/html $out/share/doc/liminix
echo "file source-dist \"$out/share/doc/liminix\"" \
> $out/nix-support/hydra-build-products
'';
};
with-unstable = (import liminix {
nixpkgs = unstable;

View File

@ -13,13 +13,14 @@ let
allowUnsupportedSystem = true; # mipsel
permittedInsecurePackages = [
"python-2.7.18.6" # kernel backports needs python <3
"python-2.7.18.7"
];
};
});
config = (pkgs.lib.evalModules {
eval = pkgs.lib.evalModules {
modules = [
{ _module.args = { inherit pkgs; lib = pkgs.lib; }; }
{ _module.args = { inherit pkgs; inherit (pkgs) lim; }; }
./modules/hardware.nix
./modules/base.nix
./modules/busybox.nix
@ -30,7 +31,8 @@ let
./modules/users.nix
./modules/outputs.nix
];
}).config;
};
config = eval.config;
borderVm = ((import <nixpkgs/nixos/lib/eval-config.nix>) {
system = builtins.currentSystem;
@ -43,6 +45,12 @@ let
in {
outputs = config.system.outputs // {
default = config.system.outputs.${config.hardware.defaultOutput};
optionsJson =
let o = import ./doc/extract-options.nix {
inherit pkgs eval;
lib = pkgs.lib;
};
in pkgs.writeText "options.json" (builtins.toJSON o);
};
# this is just here as a convenience, so that we can get a
@ -59,6 +67,7 @@ in {
go-l2tp
min-copy-closure
fennelrepl
lzma
];
};
}

View File

@ -0,0 +1,238 @@
{
description = ''
Belkin RT-3200 / Linksys E8450
******************************
This device is based on a 64 bit Mediatek MT7622 ARM platform,
and is "work in progress" in Liminix.
.. note:: The factory flash image contains ECC errors that make it
incompatible with Liminix: you need to use the `OpenWrt
UBI Installer <https://github.com/dangowrt/owrt-ubi-installer>`_ to
rewrite the partition layout before you can flash
Liminix onto it (or even use it with
:ref:`system-outputs-tftpboot`, if you want the wireless
to work).
Hardware summary
================
- MediaTek MT7622BV (1350MHz)
- 128MB NAND flash
- 512MB RAM
- b/g/n wireless using MediaTek MT7622BV (MT7615E driver)
- a/n/ac/ax wireless using MediaTek MT7915E
Installation
============
Installation is currently a manual process (you need a :ref:`serial <serial>` conection and
TFTP) following the instructions at :ref:`system-outputs-ubimage`
'';
system = {
crossSystem = {
config = "aarch64-unknown-linux-musl";
};
};
module = {pkgs, config, lib, lim, ... }:
let firmware = pkgs.stdenv.mkDerivation {
name = "wlan-firmware";
phases = ["installPhase"];
installPhase = ''
mkdir $out
cp ${pkgs.linux-firmware}/lib/firmware/mediatek/{mt7915,mt7615,mt7622}* $out
'';
};
in {
imports = [
../../modules/arch/aarch64.nix
../../modules/outputs/tftpboot.nix
../../modules/outputs/ubifs.nix
];
config = {
kernel = {
src = pkgs.pkgsBuildBuild.fetchurl {
name = "linux.tar.gz";
url = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.137.tar.gz";
hash = "sha256-PkdzUKZ0IpBiWe/RS70J76JKnBFzRblWcKlaIFNxnHQ=";
};
extraPatchPhase = ''
${pkgs.openwrt.applyPatches.mediatek}
'';
config = {
PCI = "y";
ARCH_MEDIATEK = "y";
# ARM_MEDIATEK_CPUFREQ = "y";
# needed for "Cannot find regmap for /infracfg@10000000"
MFD_SYSCON = "y";
MTK_INFRACFG = "y";
MTK_PMIC_WRAP = "y";
MTK_EFUSE="y";
# MTK_HSDMA="y";
MTK_SCPSYS="y";
MTK_SCPSYS_PM_DOMAINS="y";
# MTK_THERMAL="y";
MTK_TIMER="y";
COMMON_CLK_MT7622 = "y";
COMMON_CLK_MT7622_ETHSYS = "y";
COMMON_CLK_MT7622_HIFSYS = "y";
COMMON_CLK_MT7622_AUDSYS = "y";
PM_CLK="y";
REGMAP_MMIO = "y";
CLKSRC_MMIO = "y";
REGMAP = "y";
MEDIATEK_GE_PHY = "y";
# MEDIATEK_MT6577_AUXADC = "y";
# MEDIATEK_WATCHDOG = "y";
NET_MEDIATEK_SOC = "y";
NET_MEDIATEK_SOC_WED = "y";
NET_MEDIATEK_STAR_EMAC = "y"; # this enables REGMAP_MMIO
NET_VENDOR_MEDIATEK = "y";
PCIE_MEDIATEK = "y";
BLOCK = "y"; # move this to base option
SPI_MASTER = "y";
SPI = "y";
SPI_MEM="y";
SPI_MTK_NOR="y";
SPI_MTK_SNFI = "y";
MTD = "y";
MTD_BLOCK = "y";
MTD_RAW_NAND = "y";
MTD_NAND_MTK = "y";
MTD_NAND_MTK_BMT = "y"; # Bad-block Management Table
MTD_NAND_ECC_MEDIATEK= "y";
MTD_NAND_ECC_SW_HAMMING= "y";
MTD_SPI_NAND= "y";
MTD_OF_PARTS = "y";
MTD_NAND_CORE= "y";
MTD_SPI_NOR= "y";
MTD_SPLIT_FIRMWARE= "y";
MTD_SPLIT_FIT_FW= "y";
MMC = "y";
MMC_BLOCK = "y";
MMC_CQHCI = "y";
MMC_MTK = "y";
# Distributed Switch Architecture is needed
# to make the ethernet ports visible
NET_DSA="y";
NET_DSA_MT7530="y";
NET_DSA_TAG_MTK="y";
PSTORE = "y";
PSTORE_RAM = "y";
PSTORE_CONSOLE = "y";
PSTORE_DEFLATE_COMPRESS = "n";
SERIAL_8250 = "y";
SERIAL_8250_CONSOLE = "y";
SERIAL_8250_MT6577="y";
# SERIAL_8250_NR_UARTS="3";
# SERIAL_8250_RUNTIME_UARTS="3";
SERIAL_OF_PLATFORM="y";
# Must enble hardware watchdog drivers. Else the device reboots after several seconds
WATCHDOG = "y";
MEDIATEK_WATCHDOG = "y";
};
conditionalConfig = {
WLAN= {
MT7615E = "m";
MT7622_WMAC = "y";
MT7915E = "m";
};
};
};
boot = {
commandLine = [ "console=ttyS0,115200" ];
tftp.loadAddress = lim.parseInt "0x4007ff28";
imageFormat = "fit";
};
filesystem =
let inherit (pkgs.pseudofile) dir symlink;
in
dir {
lib = dir {
firmware = dir {
mediatek = symlink firmware;
};
};
};
hardware =
let
openwrt = pkgs.openwrt;
mac80211 = pkgs.kmodloader.override {
targets = ["mt7615e" "mt7915e"];
inherit (config.system.outputs) kernel;
};
in {
ubi = {
minIOSize = "2048";
eraseBlockSize = "126976";
maxLEBcount = "1024"; # guessing
};
defaultOutput = "ubimage";
# the kernel expects this to be on a 2MB boundary. U-Boot
# (I don't know why) has a default of 0x41080000, which isn't.
# We put it at the 32MB mark so that tftpboot can put its rootfs
# image and DTB underneath, but maybe this is a terrible waste of
# RAM unless the kernel is able to reuse it later. Oh well
loadAddress = lim.parseInt "0x42000000";
entryPoint = lim.parseInt "0x42000000";
rootDevice = "ubi0:liminix";
dts = {
src = "${openwrt.src}/target/linux/mediatek/dts/mt7622-linksys-e8450-ubi.dts";
includes = [
"${openwrt.src}/target/linux/mediatek/dts"
"${config.system.outputs.kernel.modulesupport}/arch/arm64/boot/dts/mediatek/"
];
};
# - 0x000000000000-0x000008000000 : "spi-nand0"
# - 0x000000000000-0x000000080000 : "bl2"
# - 0x000000080000-0x0000001c0000 : "fip"
# - 0x0000001c0000-0x0000002c0000 : "factory"
# - 0x0000002c0000-0x000000300000 : "reserved"
# - 0x000000300000-0x000008000000 : "ubi"
networkInterfaces =
let
inherit (config.system.service.network) link;
inherit (config.system.service) bridge;
in rec {
wan = link.build { ifname = "wan"; };
lan1 = link.build { ifname = "lan1"; };
lan2 = link.build { ifname = "lan2"; };
lan3 = link.build { ifname = "lan3"; };
lan4 = link.build { ifname = "lan4"; };
lan = lan3;
wlan = link.build {
ifname = "wlan0";
dependencies = [ mac80211 ];
};
wlan5 = link.build {
ifname = "wlan1";
dependencies = [ mac80211 ];
};
};
};
};
};
}

57
devices/families/qemu.nix Normal file
View File

@ -0,0 +1,57 @@
{ config, pkgs, ... }:
{
imports = [
../../modules/outputs/jffs2.nix
];
config = {
kernel = {
src = pkgs.pkgsBuildBuild.fetchurl {
name = "linux.tar.gz";
url = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.137.tar.gz";
hash = "sha256-PkdzUKZ0IpBiWe/RS70J76JKnBFzRblWcKlaIFNxnHQ=";
};
config = {
MTD = "y";
MTD_BLOCK = "y";
MTD_CMDLINE_PARTS = "y";
MTD_PHRAM = "y";
VIRTIO_MENU = "y";
PCI = "y";
VIRTIO_PCI = "y";
BLOCK = "y";
VIRTIO_BLK = "y";
VIRTIO_NET = "y";
};
};
hardware =
let
mac80211 = pkgs.mac80211.override {
drivers = ["mac80211_hwsim"];
klibBuild = config.system.outputs.kernel.modulesupport;
};
in {
defaultOutput = "vmroot";
rootDevice = "/dev/mtdblock0";
dts.src = pkgs.lib.mkDefault null;
flash.eraseBlockSize = 65536;
networkInterfaces =
let inherit (config.system.service.network) link;
in {
wan = link.build {
devpath = "/devices/pci0000:00/0000:00:13.0/virtio0";
ifname = "wan";
};
lan = link.build {
devpath = "/devices/pci0000:00/0000:00:14.0/virtio1";
ifname = "lan";
};
wlan_24 = link.build {
ifname = "wlan0";
dependencies = [ mac80211 ];
};
};
};
};
}

View File

@ -1,11 +1,3 @@
# I like GL.iNet devices because they're relatively accessible to
# DIY users: the serial port connections have headers preinstalled
# and don't need soldering
# Mainline linux 5.19 doesn't have device-tree support for this device
# or even for the SoC, so we use the extensive OpenWrt kernel patches
{
system = {
crossSystem = {
@ -21,6 +13,9 @@
GL.iNet GL-AR750
****************
Hardware summary
================
The GL-AR750 "Creta" travel router features:
- QCA9531 @650Mhz SoC
@ -30,29 +25,34 @@
- 16MB NOR Flash
- supported in OpenWrt by the "ath79" SoC family
As with many GL.iNet devices, the stock vendor firmware
is a fork of OpenWrt, meaning that the plain binary
``firmware.bin`` that Liminix builds can be flashed using the
vendor web UI and the U-Boot emergency "unbrick" routine
The GL-AR750 has two distinct sets of wifi hardware. The 2.4GHz
radio is part of the QCA9531 SoC, i.e. it's on the same silicon as
the CPU, the Ethernet, the USB etc. The device is connected to the
host via AHB, the "Advanced High-Performance Bus" and it is
supported in Linux using the ath9k driver. The 5GHz support, on the
other hand, is provided by a QCA9887 PCIe (PCI embedded) WLAN chip:
I haven't looked closely at the router innards to see if this is
actually physically a separate board that could be unplugged, but
as far as Linux is concerned it behaves as one. This is
host via `AHB <https://en.wikipedia.org/wiki/Advanced_Microcontroller_Bus_Architecture>`_ and it is
supported in Linux using the ath9k driver. 5GHz wifi
is provided by a QCA9887 PCIe (PCI embedded) WLAN chip,
supported by the ath10k driver.
Installation
============
As with many GL.iNet devices, the stock vendor firmware
is a fork of OpenWrt, meaning that the binary created by
:ref:`system-outputs-mtdimage` can be flashed using the
vendor web UI or the U-Boot emergency "unbrick" routine.
For flashing from an existing Liminix system (we believe that) it
is necessary to first boot into a :ref:`system-outputs-kexecboot`
system, otherwise you'll be overwriting flash partitions while
they're in use - and that might not end well.
Vendor web page: https://www.gl-inet.com/products/gl-ar750/
OpenWrt web page: https://openwrt.org/toh/gl.inet/gl-ar750
'';
module = {pkgs, config, ... }:
module = {pkgs, config, lim, ... }:
let
openwrt = pkgs.openwrt;
firmwareBlobs = pkgs.pkgsBuildBuild.fetchFromGitHub {
@ -71,14 +71,15 @@
cp $blobdir/board.bin $out/ath10k/QCA9887/hw1.0/
'';
};
mac80211 = pkgs.mac80211.override {
drivers = ["ath9k" "ath10k_pci"];
klibBuild = config.system.outputs.kernel.modulesupport;
mac80211 = pkgs.kmodloader.override {
targets = ["ath9k" "ath10k_pci"];
inherit (config.system.outputs) kernel;
dependencies = [ ath10k_cal_data ];
};
ath10k_cal_data =
let
offset = 1024 * 20; # 0x5000
size = 2048 + 68; # 0x844
offset = lim.parseInt "0x5000";
size = lim.parseInt "0x844";
in pkgs.liminix.services.oneshot rec {
name = "ath10k_cal_data";
up = ''
@ -96,19 +97,22 @@
imports = [
../../modules/network
../../modules/arch/mipseb.nix
../../modules/outputs/tftpboot.nix
../../modules/outputs/mtdimage.nix
../../modules/outputs/jffs2.nix
];
programs.busybox.options = {
FEATURE_DD_IBS_OBS = "y"; # ath10k_cal_data needs skip_bytes,fullblock
};
hardware = {
defaultOutput = "flashimage";
loadAddress = "0x80060000";
entryPoint = "0x80060000";
defaultOutput = "mtdimage";
loadAddress = lim.parseInt "0x80060000";
entryPoint = lim.parseInt "0x80060000";
flash = {
address = "0x9F060000";
size ="0xfa0000";
eraseBlockSize = "65536";
address = lim.parseInt "0x9F060000";
size = lim.parseInt "0xfa0000";
eraseBlockSize = 65536;
};
rootDevice = "/dev/mtdblock5";
dts = {
@ -129,7 +133,7 @@
};
wlan5 = link.build {
ifname = "wlan1";
dependencies = [ mac80211 ath10k_cal_data ];
dependencies = [ ath10k_cal_data mac80211 ];
};
};
};
@ -144,17 +148,24 @@
};
};
boot.tftp = {
loadAddress = "0x00A00000";
loadAddress = lim.parseInt "0x00A00000";
};
kernel = {
src = pkgs.pkgsBuildBuild.fetchurl {
name = "linux.tar.gz";
url = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.71.tar.gz";
hash = "sha256-yhO2cXIeIgUxkSZf/4aAsF11uxyh+UUZu6D1h92vCD8=";
url = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.137.tar.gz";
hash = "sha256-PkdzUKZ0IpBiWe/RS70J76JKnBFzRblWcKlaIFNxnHQ=";
};
# Mainline linux 5.19 doesn't have device-tree support for
# this device or even for the SoC, so we use the extensive
# OpenWrt kernel patches
extraPatchPhase = ''
${openwrt.applyPatches.ath79}
sed -i.bak -e '\,include <linux/hw_random.h>,a #include <linux/gpio/driver.h>' drivers/net/wireless/ath/ath9k/ath9k.h # context reqd for next patch
patch -p1 < ${openwrt.src}/package/kernel/mac80211/patches/ath9k/552-ath9k-ahb_of.patch
'';
config = {
ATH79 = "y";
PCI = "y";
@ -175,7 +186,6 @@
CONSOLE_LOGLEVEL_QUIET = "4";
NET = "y";
NETDEVICES = "y";
ETHERNET = "y";
NET_VENDOR_ATHEROS = "y";
AG71XX = "y"; # ethernet (qca,qca9530-eth)
@ -204,14 +214,21 @@
WATCHDOG = "y";
ATH79_WDT = "y"; # watchdog timer
# this is all copied from nixwrt ath79 config. Clearly not all
# of it is device config, some of it is wifi config or
# installation method config or ...
EARLY_PRINTK = "y";
PRINTK_TIME = "y";
};
conditionalConfig = {
WLAN = {
WLAN_VENDOR_ATH = "y";
ATH_COMMON = "m";
ATH9K = "m";
ATH9K_AHB = "y";
ATH10K = "m";
ATH10K_PCI = "m";
ATH10K_DEBUG = "y";
};
};
};
};
}

View File

@ -13,34 +13,11 @@
description = ''
GL.iNet GL-MT300A
********************
*****************
The GL-MT300A is based on a MT7620 chipset.
The GL.iNet pocket router range makes nice cheap hardware for
playing with Liminix or similar projects. The manufacturers seem
open to the DIY market, and the devices have a reasonable amount
of RAM and are much easier to get serial connections than many
COTS routers.
Wire up the serial connection: this probably involves opening
the box, locating the serial header pins (TX, RX and GND) and
connecting a USB TTL converter - e.g. a PL2303 based device - to
it. The defunct OpenWRT wiki has a guide with some pictures. (If
you don't have a USB TTL converter to hand, other options are
available. For example, use the GPIO pins on a Raspberry Pi.)
Run a terminal emulator such as Minicom on whatever is on the
other end of the link. I use 115200 8N1 and find it also helps
to set "Line tx delay" to 1ms, "backspace sends DEL" and
"lineWrap on".
When you turn the router on you should be greeted with some
messages from U-Boot and a little bit of ASCII art, followed by
the instruction to hit SPACE to stop autoboot. Do this and you
will get a gl-mt300a> prompt.
For flashing from uboot, the firmware partition is from
For flashing from U-Boot, the firmware partition is from
0xbc050000 to 0xbcfd0000.
WiFi on this device is provided by the rt2800soc module. It
@ -48,6 +25,17 @@
- assuming we want to use the wireless - we need to build MTD
support into the kernel even if we're using TFTP root.
Installation
============
The stock vendor firmware is a fork of OpenWrt, meaning that the
binary created by :ref:`system-outputs-mtdimage` can be flashed
using the vendor web UI or the U-Boot emergency "unbrick" routine.
For flashing from an existing Liminix system (we think) it
is necessary to first boot into a :ref:`system-outputs-kexecboot`
system, otherwise you'll be overwriting flash partitions while
they're in use - and that might not end well.
Vendor web page: https://www.gl-inet.com/products/gl-mt300a/
@ -55,20 +43,25 @@
'';
module = { pkgs, config, lib, ...}:
module = { pkgs, config, lib, lim, ...}:
let
inherit (pkgs.liminix.networking) interface;
inherit (pkgs) openwrt;
mac80211 = pkgs.mac80211.override {
drivers = ["rt2800soc"];
klibBuild = config.system.outputs.kernel.modulesupport;
mac80211 = pkgs.kmodloader.override {
targets = ["rt2800soc"];
inherit (config.system.outputs) kernel;
};
in {
imports = [ ../../modules/arch/mipsel.nix ];
imports = [
../../modules/arch/mipsel.nix
../../modules/outputs/tftpboot.nix
../../modules/outputs/mtdimage.nix
../../modules/outputs/jffs2.nix
];
hardware = {
defaultOutput = "flashimage";
loadAddress = "0x80000000";
entryPoint = "0x80000000";
defaultOutput = "mtdimage";
loadAddress = lim.parseInt "0x80000000";
entryPoint = lim.parseInt "0x80000000";
# Creating 5 MTD partitions on "spi0.0":
# 0x000000000000-0x000000030000 : "u-boot"
@ -81,9 +74,9 @@
# 0x000000260000-0x000000f80000 : "rootfs"
flash = {
address = "0xbc050000";
size ="0xf80000";
eraseBlockSize = "65536";
address = lim.parseInt "0xbc050000";
size = lim.parseInt "0xf80000";
eraseBlockSize = 65536;
};
rootDevice = "/dev/mtdblock5";
@ -132,14 +125,14 @@
};
};
boot.tftp = {
loadAddress = "0x00A00000";
loadAddress = lim.parseInt "0x00A00000";
};
kernel = {
src = pkgs.fetchurl {
name = "linux.tar.gz";
url = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.71.tar.gz";
hash = "sha256-yhO2cXIeIgUxkSZf/4aAsF11uxyh+UUZu6D1h92vCD8=";
url = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.137.tar.gz";
hash = "sha256-PkdzUKZ0IpBiWe/RS70J76JKnBFzRblWcKlaIFNxnHQ=";
};
extraPatchPhase = ''
${openwrt.applyPatches.ramips}
@ -159,7 +152,6 @@
CONSOLE_LOGLEVEL_QUIET = "4";
NET = "y";
NETDEVICES = "y";
ETHERNET = "y";
NET_VENDOR_RALINK = "y";
NET_RALINK_MDIO = "y";
@ -186,6 +178,14 @@
} // lib.optionalAttrs (config.system.service ? vlan) {
SWCONFIG = "y";
};
conditionalConfig = {
WLAN = {
WLAN_VENDOR_RALINK = "y";
RT2800SOC = "m";
RT2X00 = "m";
};
};
};
};
}

View File

@ -13,10 +13,22 @@
GL.iNet GL-MT300N-v2
********************
The GL-MT300N-v2 "Mango" is is very similar to the MT300A, but is
based on MT7628 instead of MT7620. It's also marginally cheaper
and comes in a yellow case not a blue one. It's different again
to the v1, which has only half the RAM.
The GL-MT300N-v2 "Mango" is is very similar to the :ref:`MT300A <GL.iNet GL-MT300A>, but is
based on the MT7628 chipset instead of MT7620. It's also marginally cheaper
and comes in a yellow case not a blue one. Be sure your device is
v2 not v1, which is a different animal and has only half as much RAM.
Installation
============
The stock vendor firmware is a fork of OpenWrt, meaning that the
binary created by :ref:`system-outputs-mtdimage` can be flashed
using the vendor web UI or the U-Boot emergency "unbrick" routine.
For flashing from an existing Liminix system (we think) it
is necessary to first boot into a :ref:`system-outputs-kexecboot`
system, otherwise you'll be overwriting flash partitions while
they're in use - and that might not end well.
Vendor web page: https://www.gl-inet.com/products/gl-mt300n-v2/
@ -24,23 +36,28 @@
'';
module = { pkgs, config, lib, ...}:
module = { pkgs, config, lib, lim, ...}:
let
inherit (pkgs.liminix.networking) interface;
inherit (pkgs.liminix.services) oneshot;
inherit (pkgs.pseudofile) dir symlink;
inherit (pkgs) openwrt;
mac80211 = pkgs.mac80211.override {
drivers = ["mt7603e"];
klibBuild = config.system.outputs.kernel.modulesupport;
mac80211 = pkgs.kmodloader.override {
targets = ["mt7603e"];
inherit (config.system.outputs) kernel;
};
wlan_firmware = pkgs.fetchurl {
url = "https://github.com/openwrt/mt76/raw/f24b56f935392ca1d35fae5fd6e56ef9deda4aad/firmware/mt7628_e2.bin";
hash = "sha256:1dkhfznmdz6s50kwc841x3wj0h6zg6icg5g2bim9pvg66as2vmh9";
};
in {
imports = [ ../../modules/arch/mipsel.nix ];
imports = [
../../modules/arch/mipsel.nix
../../modules/outputs/tftpboot.nix
../../modules/outputs/mtdimage.nix
../../modules/outputs/jffs2.nix
];
filesystem = dir {
lib = dir {
firmware = dir {
@ -49,14 +66,14 @@
};
};
hardware = {
defaultOutput = "flashimage";
loadAddress = "0x80000000";
entryPoint = "0x80000000";
defaultOutput = "mtdimage";
loadAddress = lim.parseInt "0x80000000";
entryPoint = lim.parseInt "0x80000000";
flash = {
address = "0xbc050000";
size = "0xfb0000";
eraseBlockSize = "65536";
address = lim.parseInt "0xbc050000";
size = lim.parseInt "0xfb0000";
eraseBlockSize = 65536;
};
rootDevice = "/dev/mtdblock5";
@ -104,14 +121,14 @@
boot.tftp = {
# 20MB seems to give enough room to uncompress the kernel
# without anything getting trodden on. 10MB was too small
loadAddress = "0x1400000";
loadAddress = lim.parseInt "0x1400000";
};
kernel = {
src = pkgs.fetchurl {
name = "linux.tar.gz";
url = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.71.tar.gz";
hash = "sha256-yhO2cXIeIgUxkSZf/4aAsF11uxyh+UUZu6D1h92vCD8=";
url = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.137.tar.gz";
hash = "sha256-PkdzUKZ0IpBiWe/RS70J76JKnBFzRblWcKlaIFNxnHQ=";
};
extraPatchPhase = ''
${openwrt.applyPatches.ramips}
@ -143,7 +160,6 @@
REGULATOR_FIXED_VOLTAGE = "y";
NET = "y";
NETDEVICES = "y";
ETHERNET = "y";
PHYLIB = "y";
@ -169,6 +185,15 @@
RALINK_WDT = "y"; # watchdog
MT7621_WDT = "y"; # or it might be this one
};
conditionalConfig = {
WLAN = {
WLAN_VENDOR_RALINK = "y";
WLAN_VENDOR_MEDIATEK = "y";
MT7603E = "m";
};
};
};
};
}

View File

@ -9,64 +9,43 @@
};
};
description = ''
QEMU Aarch64
************
This target produces an image for
the `QEMU "virt" platform <https://www.qemu.org/docs/master/system/arm/virt.html>`_ using a 64 bit CPU type.
ARM targets differ from MIPS in that the kernel format expected
by QEMU is an "Image" (raw binary file) rather than an ELF
file, but this is taken care of by :command:`run.sh`. Check the
documentation for the :ref:`QEMU` (MIPS) target for more information.
'';
# this device is described by the "qemu" device
description = "";
installer = "vmroot";
module = {pkgs, config, ... }: {
imports = [ ../../modules/arch/aarch64.nix ];
module = {pkgs, config, lim, ... }: {
imports = [
../../modules/arch/aarch64.nix
../families/qemu.nix
];
kernel = {
src = pkgs.pkgsBuildBuild.fetchurl {
name = "linux.tar.gz";
url = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.71.tar.gz";
hash = "sha256-yhO2cXIeIgUxkSZf/4aAsF11uxyh+UUZu6D1h92vCD8=";
};
config = {
VIRTUALIZATION = "y";
PCI_HOST_GENERIC="y";
MTD = "y";
MTD_BLOCK2MTD = "y";
MTD_BLOCK = "y";
VIRTIO_MENU = "y";
PCI = "y";
VIRTIO_PCI = "y";
BLOCK = "y";
VIRTIO_BLK = "y";
NETDEVICES = "y";
VIRTIO_NET = "y";
SERIAL_EARLYCON_ARM_SEMIHOST = "y"; # earlycon=smh
SERIAL_AMBA_PL011 = "y";
SERIAL_AMBA_PL011_CONSOLE = "y";
};
};
hardware =
let
mac80211 = pkgs.mac80211.override {
drivers = ["mac80211_hwsim"];
klibBuild = config.system.outputs.kernel.modulesupport;
};
in {
defaultOutput = "vmroot";
loadAddress = "0x0";
entryPoint = "0x0";
rootDevice = "/dev/mtdblock0";
flash.eraseBlockSize = "65536"; # c.f. pkgs/mips-vm/mips-vm.sh
networkInterfaces =
let inherit (config.system.service.network) link;
in {
wan = link.build { ifname = "eth0"; };
lan = link.build { ifname = "eth1"; };
wlan_24 = link.build {
ifname = "wlan0";
dependencies = [ mac80211 ];
};
};
};
boot.commandLine = [
"console=ttyAMA0,38400"
];
hardware = let addr = lim.parseInt "0x40010000"; in {
loadAddress = addr;
entryPoint = addr;
};
};
}

View File

@ -0,0 +1,53 @@
# This "device" generates images that can be used with the QEMU
# emulator. The default output is a directory containing separate
# kernel ("Image" format) and root filesystem (squashfs or jffs2)
# images
{
system = {
crossSystem = {
config = "armv7l-unknown-linux-musleabihf";
};
};
# this device is described by the "qemu" device
description = ''
QEMU ARM v7
***********
This target produces an image for
the `QEMU "virt" platform <https://www.qemu.org/docs/master/system/arm/virt.html>`_ using a 32 bit CPU type.
ARM targets differ from MIPS in that the kernel format expected
by QEMU is an "Image" (raw binary file) rather than an ELF
file, but this is taken care of by :command:`run.sh`. Check the
documentation for the :ref:`QEMU` (MIPS) target for more information.
'';
installer = "vmroot";
module = {pkgs, config, lim, ... }: {
imports = [
../../modules/arch/arm.nix
../families/qemu.nix
];
kernel = {
config = {
PCI_HOST_GENERIC = "y";
ARCH_VIRT = "y";
VFP = "y";
NEON = "y";
AEABI = "y";
SERIAL_AMBA_PL011 = "y";
SERIAL_AMBA_PL011_CONSOLE = "y";
};
};
boot.commandLine = [
"console=ttyAMA0"
];
hardware = let addr = lim.parseInt "0x40008000"; in {
loadAddress = addr;
entryPoint = addr;
};
};
}

View File

@ -13,24 +13,21 @@
};
description = ''
QEMU
****
QEMU MIPS
*********
This is not a hardware device. This target produces an image for
This target produces an image for
QEMU, the "generic and open source machine emulator and
virtualizer".
Liminix can build QEMU for both MIPS (:code:`qemu` device) and Aarch64 (:code:`qemu-aarch64` device)
MIPS QEMU emulates a "Malta" board, which was an ATX form factor
evaluation board made by MIPS Technologies, but mostly in Liminix
we use paravirtualized devices (Virtio) instead of emulating
hardware. For Aarch64 we use the QEMU "virt" board.
hardware.
Building an image for QEMU results in a :file:`result/` directory
containing ``run.sh`` ``vmlinux``, ``rootfs`` and possibly
(architecture-dependent) ``Image``. To invoke the emulator,
run ``run.sh``.
containing ``run.sh`` ``vmlinux``, and ``rootfs`` files. To invoke
the emulator, run ``run.sh``.
The configuration includes two emulated "hardware" ethernet
devices and the kernel :code:`mac80211_hwsim` module to
@ -39,56 +36,41 @@
in the Development manual.
'';
module = {pkgs, config, ... }: {
imports = [ ../../modules/arch/mipseb.nix ];
module = {pkgs, config, lib, lim, ... }: {
imports = [
../../modules/arch/mipseb.nix
../families/qemu.nix
];
kernel = {
src = pkgs.pkgsBuildBuild.fetchurl {
name = "linux.tar.gz";
url = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.71.tar.gz";
hash = "sha256-yhO2cXIeIgUxkSZf/4aAsF11uxyh+UUZu6D1h92vCD8=";
};
config = {
MIPS_MALTA= "y";
CPU_MIPS32_R2= "y";
MTD = "y";
MTD_BLOCK2MTD = "y";
MTD_BLOCK = "y";
VIRTIO_MENU = "y";
PCI = "y";
VIRTIO_PCI = "y";
BLOCK = "y";
VIRTIO_BLK = "y";
NETDEVICES = "y";
VIRTIO_NET = "y";
POWER_RESET = "y";
POWER_RESET_SYSCON = "y";
SERIAL_8250= "y";
SERIAL_8250_CONSOLE= "y";
};
};
hardware =
let
mac80211 = pkgs.mac80211.override {
drivers = ["mac80211_hwsim"];
klibBuild = config.system.outputs.kernel.modulesupport;
};
# from arch/mips/mti-malta/Platform:load-$(CONFIG_MIPS_MALTA) += 0xffffffff80100000
let addr = lim.parseInt "0x80100000";
in {
defaultOutput = "vmroot";
rootDevice = "/dev/mtdblock0";
flash.eraseBlockSize = "65536"; # c.f. pkgs/run-liminix-vm/run-liminix-vm.sh
networkInterfaces =
let inherit (config.system.service.network) link;
in {
wan = link.build { ifname = "eth0"; };
lan = link.build { ifname = "eth1"; };
loadAddress = addr;
entryPoint = addr;
# Unlike the arm qemu targets, we need a static dts when
# running u-boot-using tests, qemu dumpdtb command doesn't
# work for this board. I am not at all sure this dts is
# *correct* but it does at least boot
dts = lib.mkForce {
src = "${config.system.outputs.kernel.modulesupport}/arch/mips/boot/dts/mti/malta.dts";
includes = [
"${config.system.outputs.kernel.modulesupport}/arch/mips/boot/dts/"
];
};
wlan_24 = link.build {
ifname = "wlan0";
dependencies = [ mac80211 ];
};
};
};
};
}

View File

@ -0,0 +1,442 @@
{
description = ''
TP-Link Archer AX23 / AX1800 Dual Band Wi-Fi 6 Router
*****************************************************
Hardware summary
================
- MediaTek MT7621 (880MHz)
- 16MB Flash
- 128MB RAM
- WLan hardware: Mediatek MT7905, MT7975
Limitations
===========
Status LEDs do not work yet.
Uploading an image via tftp doesn't work yet, because the Archer uboot
version is so old it doesn't support overriding the DTB from the mboot
command. The tftpboot module doesn't support this yet, see
https://gti.telent.net/dan/liminix/pulls/5 for the WiP.
'';
system = {
crossSystem = {
config = "mipsel-unknown-linux-musl";
gcc = {
abi = "32";
# https://openwrt.org/docs/techref/instructionset/mipsel_24kc
arch = "24kc";
};
};
};
module = {pkgs, config, lib, lim, ... }:
let firmware = pkgs.stdenv.mkDerivation {
name = "wlan-firmware";
phases = ["installPhase"];
installPhase = ''
mkdir $out
cp ${pkgs.linux-firmware}/lib/firmware/mediatek/{mt7915,mt7615,mt7622}* $out
'';
};
in {
imports = [
../../modules/arch/mipsel.nix
../../modules/outputs/tftpboot.nix
../../modules/outputs/tplink-safeloader.nix
];
config = {
kernel = {
src = pkgs.pkgsBuildBuild.fetchurl {
name = "linux.tar.gz";
url = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.137.tar.gz";
hash = "sha256-PkdzUKZ0IpBiWe/RS70J76JKnBFzRblWcKlaIFNxnHQ=";
};
extraPatchPhase = ''
${pkgs.openwrt.applyPatches.ramips}
'';
config = {
# Initially taken from openwrt's ./target/linux/ramips/mt7621/config-5.15,
# then tweaked here and there
ARCH_32BIT_OFF_T="y";
ARCH_HIBERNATION_POSSIBLE="y";
ARCH_KEEP_MEMBLOCK="y";
ARCH_MMAP_RND_BITS_MAX="15";
ARCH_MMAP_RND_COMPAT_BITS_MAX="15";
ARCH_SUSPEND_POSSIBLE="y";
AT803X_PHY="y";
BLK_MQ_PCI="y";
BOARD_SCACHE="y";
CEVT_R4K="y";
CLKSRC_MIPS_GIC="y";
CLK_MT7621="y";
CLOCKSOURCE_WATCHDOG="y";
CLONE_BACKWARDS="y";
CMDLINE_BOOL="y";
COMMON_CLK="y";
COMPAT_32BIT_TIME="y";
CPU_GENERIC_DUMP_TLB="y";
CPU_HAS_DIEI="y";
CPU_HAS_PREFETCH="y";
CPU_HAS_RIXI="y";
CPU_HAS_SYNC="y";
CPU_LITTLE_ENDIAN="y";
CPU_MIPS32="y";
CPU_MIPS32_R2="y";
CPU_MIPSR2="y";
CPU_MIPSR2_IRQ_EI="y";
CPU_MIPSR2_IRQ_VI="y";
CPU_NEEDS_NO_SMARTMIPS_OR_MICROMIPS="y";
CPU_R4K_CACHE_TLB="y";
CPU_RMAP="y";
CPU_SUPPORTS_32BIT_KERNEL="y";
CPU_SUPPORTS_HIGHMEM="y";
CPU_SUPPORTS_MSA="y";
CRC16="y";
CRYPTO_DEFLATE="y";
CRYPTO_HASH_INFO="y";
CRYPTO_LIB_BLAKE2S_GENERIC="y";
CRYPTO_LIB_POLY1305_RSIZE="2";
CRYPTO_LZO="y";
CRYPTO_ZSTD="y";
CSRC_R4K="y";
DIMLIB="y";
DMA_NONCOHERENT="y";
DTB_RT_NONE="y";
DTC="y";
EARLY_PRINTK="y";
FIXED_PHY="y";
FWNODE_MDIO="y";
FW_LOADER_PAGED_BUF="y";
GENERIC_ATOMIC64="y";
GENERIC_CLOCKEVENTS="y";
GENERIC_CMOS_UPDATE="y";
GENERIC_CPU_AUTOPROBE="y";
GENERIC_FIND_FIRST_BIT="y";
GENERIC_GETTIMEOFDAY="y";
GENERIC_IOMAP="y";
GENERIC_IRQ_CHIP="y";
GENERIC_IRQ_EFFECTIVE_AFF_MASK="y";
GENERIC_IRQ_SHOW="y";
GENERIC_LIB_ASHLDI3="y";
GENERIC_LIB_ASHRDI3="y";
GENERIC_LIB_CMPDI2="y";
GENERIC_LIB_LSHRDI3="y";
GENERIC_LIB_UCMPDI2="y";
GENERIC_PCI_IOMAP="y";
GENERIC_PHY="y";
GENERIC_PINCONF="y";
GENERIC_SCHED_CLOCK="y";
GENERIC_SMP_IDLE_THREAD="y";
GENERIC_TIME_VSYSCALL="y";
GLOB="y";
GPIOLIB_IRQCHIP="y";
GPIO_CDEV="y";
GPIO_GENERIC="y";
GPIO_MT7621="y";
GRO_CELLS="y";
HANDLE_DOMAIN_IRQ="y";
HARDWARE_WATCHPOINTS="y";
HAS_DMA="y";
HAS_IOMEM="y";
HAS_IOPORT_MAP="y";
I2C="y";
I2C_ALGOBIT="y";
I2C_BOARDINFO="y";
I2C_CHARDEV="y";
I2C_GPIO="y";
I2C_MT7621="y";
ICPLUS_PHY="y";
IRQCHIP="y";
IRQ_DOMAIN="y";
IRQ_DOMAIN_HIERARCHY="y";
IRQ_FORCED_THREADING="y";
IRQ_MIPS_CPU="y";
IRQ_WORK="y";
LIBFDT="y";
LOCK_DEBUGGING_SUPPORT="y";
LZO_COMPRESS="y";
LZO_DECOMPRESS="y";
MDIO_BUS="y";
MDIO_DEVICE="y";
MDIO_DEVRES="y";
MEDIATEK_GE_PHY="y";
MEMFD_CREATE="y";
MFD_SYSCON="y";
MIGRATION="y";
MIKROTIK="y";
MIKROTIK_RB_SYSFS="y";
MIPS="y";
MIPS_ASID_BITS="8";
MIPS_ASID_SHIFT="0";
MIPS_CLOCK_VSYSCALL="y";
MIPS_CM="y";
MIPS_CPC="y";
MIPS_CPS="y";
MIPS_CPU_SCACHE="y";
MIPS_GIC="y";
MIPS_L1_CACHE_SHIFT="5";
MIPS_LD_CAN_LINK_VDSO="y";
MIPS_MT="y";
MIPS_MT_FPAFF="y";
MIPS_MT_SMP="y";
MIPS_NR_CPU_NR_MAP="4";
MIPS_PERF_SHARED_TC_COUNTERS="y";
MIPS_SPRAM="y";
MODULES_USE_ELF_REL="y";
MTD_CMDLINE_PARTS="y";
MTD_NAND_CORE="y";
MTD_NAND_ECC="y";
MTD_NAND_ECC_SW_HAMMING="y";
MTD_NAND_MT7621="y";
MTD_NAND_MTK_BMT="y";
MTD_RAW_NAND="y";
MTD_ROUTERBOOT_PARTS="y";
MTD_SERCOMM_PARTS="y";
MTD_SPI_NOR="y";
MTD_SPLIT_FIT_FW="y";
MTD_SPLIT_MINOR_FW="y";
MTD_SPLIT_SEAMA_FW="y";
MTD_SPLIT_TPLINK_FW="y";
MTD_SPLIT_TRX_FW="y";
MTD_SPLIT_UIMAGE_FW="y";
MTD_UBI="y";
MTD_UBI_BEB_LIMIT="20";
MTD_UBI_BLOCK="y";
MTD_UBI_WL_THRESHOLD="4096";
MTD_VIRT_CONCAT="y";
NEED_DMA_MAP_STATE="y";
NET_DEVLINK="y";
NET_DSA="y";
NET_DSA_MT7530="y";
NET_DSA_MT7530_MDIO="y";
NET_DSA_TAG_MTK="y";
NET_FLOW_LIMIT="y";
NET_MEDIATEK_SOC="y";
NET_SELFTESTS="y";
NET_SWITCHDEV="y";
NET_VENDOR_MEDIATEK="y";
NO_HZ_COMMON="y";
NO_HZ_IDLE="y";
NR_CPUS="4";
NVMEM="y";
OF="y";
OF_ADDRESS="y";
OF_EARLY_FLATTREE="y";
OF_FLATTREE="y";
OF_GPIO="y";
OF_IRQ="y";
OF_KOBJ="y";
OF_MDIO="y";
PAGE_POOL="y";
PAGE_POOL_STATS="y";
PCI="y";
PCIE_MT7621="y";
PCI_DISABLE_COMMON_QUIRKS="y";
PCI_DOMAINS="y";
PCI_DOMAINS_GENERIC="y";
PCI_DRIVERS_GENERIC="y";
PCS_MTK_LYNXI="y";
PERF_USE_VMALLOC="y";
PGTABLE_LEVELS="2";
PHYLIB="y";
PHYLINK="y";
PHY_MT7621_PCI="y";
PINCTRL="y";
PINCTRL_AW9523="y";
PINCTRL_MT7621="y";
PINCTRL_RALINK="y";
PINCTRL_SX150X="y";
POWER_RESET="y";
POWER_RESET_GPIO="y";
POWER_SUPPLY="y";
PTP_1588_CLOCK_OPTIONAL="y";
QUEUED_RWLOCKS="y";
QUEUED_SPINLOCKS="y";
RALINK="y";
RATIONAL="y";
REGMAP="y";
REGMAP_I2C="y";
REGMAP_MMIO="y";
REGULATOR="y";
REGULATOR_FIXED_VOLTAGE="y";
RESET_CONTROLLER="y";
RFS_ACCEL="y";
RPS="y";
RTC_CLASS="y";
RTC_DRV_BQ32K="y";
RTC_DRV_PCF8563="y";
RTC_I2C_AND_SPI="y";
SCHED_SMT="y";
SERIAL_8250="y";
SERIAL_8250_CONSOLE="y";
SERIAL_8250_NR_UARTS="3";
SERIAL_8250_RUNTIME_UARTS="3";
SERIAL_MCTRL_GPIO="y";
SERIAL_OF_PLATFORM="y";
SGL_ALLOC="y";
SMP="y";
SMP_UP="y";
SOCK_RX_QUEUE_MAPPING="y";
SOC_BUS="y";
SOC_MT7621="y";
SPI="y";
SPI_MASTER="y";
SPI_MEM="y";
SPI_MT7621="y";
SRCU="y";
SWPHY="y";
SYNC_R4K="y";
SYSCTL_EXCEPTION_TRACE="y";
SYS_HAS_CPU_MIPS32_R1="y";
SYS_HAS_CPU_MIPS32_R2="y";
SYS_HAS_EARLY_PRINTK="y";
SYS_SUPPORTS_32BIT_KERNEL="y";
SYS_SUPPORTS_ARBIT_HZ="y";
SYS_SUPPORTS_HIGHMEM="y";
SYS_SUPPORTS_HOTPLUG_CPU="y";
SYS_SUPPORTS_LITTLE_ENDIAN="y";
SYS_SUPPORTS_MIPS16="y";
SYS_SUPPORTS_MIPS_CPS="y";
SYS_SUPPORTS_MULTITHREADING="y";
SYS_SUPPORTS_SCHED_SMT="y";
SYS_SUPPORTS_SMP="y";
SYS_SUPPORTS_ZBOOT="y";
TARGET_ISA_REV="2";
TICK_CPU_ACCOUNTING="y";
TIMER_OF="y";
TIMER_PROBE="y";
TREE_RCU="y";
TREE_SRCU="y";
UBIFS_FS="y";
USB_SUPPORT="y";
USE_OF="y";
WEAK_ORDERING="y";
XPS="y";
XXHASH="y";
ZLIB_DEFLATE="y";
ZLIB_INFLATE="y";
ZSTD_COMPRESS="y";
ZSTD_DECOMPRESS="y";
} // lib.optionalAttrs (config.system.service ? watchdog) {
RALINK_WDT = "y"; # watchdog
MT7621_WDT = "y"; # or it might be this one
};
conditionalConfig = {
WLAN = {
MT7915E = "m";
};
};
};
tplink-safeloader.board = "ARCHER-AX23-V1";
boot = {
commandLine = [ "console=ttyS0,115200" ];
tftp = {
# Should be a segment of free RAM, where the tftp artifact
# can be stored before unpacking it to the 'hardware.loadAddress'
# The 'hardware.loadAddress' is 0x80001000, which suggests the
# RAM would start at 0x8000000 and (being 128MB) go to
# to 0x8800000. Let's put it at the 100MB mark at
# 0x8000000+0x0640000=0x86400000
loadAddress = lim.parseInt "0x86400000";
};
};
filesystem =
let inherit (pkgs.pseudofile) dir symlink;
in
dir {
lib = dir {
firmware = dir {
mediatek = symlink firmware;
};
};
};
hardware =
let
openwrt = pkgs.openwrt;
mac80211 = pkgs.kmodloader.override {
targets = [
"mt7915e"
];
inherit (config.system.outputs) kernel;
};
in {
# from OEM bootlog (openwrt wiki):
# 4 cmdlinepart partitions found on MTD device raspi
# Creating 4 MTD partitions on "raspi":
# 0x000000000000-0x000000040000 : "uboot"
# 0x000000040000-0x000000440000 : "uImage"
# 0x000000440000-0x000000ff0000 : "rootfs"
# 0x000000ff0000-0x000001000000 : "ART"
# from openwrt bootlog (openwrt wiki):
# 5 fixed-partitions partitions found on MTD device spi0.0
# OF: Bad cell count for /palmbus@1e000000/spi@b00/flash@0/partitions
# OF: Bad cell count for /palmbus@1e000000/spi@b00/flash@0/partitions
# OF: Bad cell count for /palmbus@1e000000/spi@b00/flash@0/partitions
# OF: Bad cell count for /palmbus@1e000000/spi@b00/flash@0/partitions
# Creating 5 MTD partitions on "spi0.0":
# 0x000000000000-0x000000040000 : "u-boot"
# 0x000000040000-0x000000fa0000 : "firmware"
# 2 uimage-fw partitions found on MTD device firmware
# Creating 2 MTD partitions on "firmware":
# 0x000000000000-0x0000002c0000 : "kernel"
# 0x0000002c0000-0x000000f60000 : "rootfs"
# mtd: setting mtd3 (rootfs) as root device
# 1 squashfs-split partitions found on MTD device rootfs
# 0x000000640000-0x000000f60000 : "rootfs_data"
# 0x000000fa0000-0x000000fb0000 : "config"
# 0x000000fb0000-0x000000ff0000 : "tplink"
# 0x000000ff0000-0x000001000000 : "radio"
flash = {
# from the OEM bootlog 'Booting image at bc040000'
# (0x40000 from 0xbc000000)
address = lim.parseInt "0xbc040000";
# 0x000000040000-0x000000fa0000
size = lim.parseInt "0xf60000";
# TODO: find in /proc/mtd on a running system
eraseBlockSize = 65536;
};
# since this is mentioned in the partition table as well?
defaultOutput = "tplink-safeloader";
# taken from openwrt sysupgrade image:
# openwrt-23.05.2-ramips-mt7621-tplink_archer-ax23-v1-squashfs-sysupgrade.bin: u-boot legacy uImage, MIPS OpenWrt Linux-5.15.137, Linux/MIPS, OS Kernel Image (lzma), 2797386 bytes, Tue Nov 14 13:38:11 2023, Load Address: 0X80001000, Entry Point: 0X80001000, Header CRC: 0X19F74C5B, Data CRC: 0XF685563C
loadAddress = lim.parseInt "0x80001000";
entryPoint = lim.parseInt "0x80001000";
rootDevice = "/dev/mtdblock3";
dts = {
src = "${openwrt.src}/target/linux/ramips/dts/mt7621_tplink_archer-ax23-v1.dts";
includes = [
"${openwrt.src}/target/linux/ramips/dts"
"${config.system.outputs.kernel.modulesupport}/arch/arm64/boot/dts/mediatek/"
];
};
networkInterfaces =
let
inherit (config.system.service.network) link;
inherit (config.system.service) bridge;
in rec {
lan1 = link.build { ifname = "lan1"; };
lan2 = link.build { ifname = "lan2"; };
lan3 = link.build { ifname = "lan3"; };
lan4 = link.build { ifname = "lan4"; };
wan = link.build { ifname = "wan"; };
wlan = link.build {
ifname = "wlan0";
dependencies = [ mac80211 ];
};
wlan5 = link.build {
ifname = "wlan1";
dependencies = [ mac80211 ];
};
};
};
};
};
}

View File

@ -0,0 +1,412 @@
{
description = ''
Turris Omnia
************
This is a 32 bit ARMv7 MVEBU device, which is usually shipped with
TurrisOS, an OpenWrt-based system. Rather than reformatting the
builtin storage, we install Liminix on to the existing btrfs
filesystem so that the vendor snapshot/recovery system continues
to work (and provides you an easy rollback if you decide you don't
like Liminix after all).
The install process has two stages, and is intended that you
should not need to open the device and add a serial console
(although it may be handy for visibility, and in case anything
goes wrong). First we build a minimal installation/recovery
system, then we reboot into that recovery image to prepare the
device for the full target install.
Installation using a USB stick
==============================
First, build the image for the USB stick. Review
:file:`examples/recovery.nix` in order to change the default
root password (which is ``secret``) and/or the SSH keys, then
build it with
.. code-block:: console
$ nix-build -I liminix-config=./examples/recovery.nix \
--arg device "import ./devices/turris-omnia" \
-A outputs.mbrimage -o mbrimage
$ file -L mbrimage
mbrimage: DOS/MBR boot sector; partition 1 : ID=0x83, active, start-CHS (0x0,0,5), end-CHS (0x6,130,26), startsector 4, 104602 sectors
Next, copy the image from your build machine to a USB storage
medium using :command:`dd` or your other most favoured file copying
tool, which might be a comand something like this:
.. code-block:: console
$ dd if=mbrimage of=/dev/path/to/the/usb/stick \
bs=1M conv=fdatasync status=progress
The Omnia's default boot order only checks USB after it has failed
to boot from eMMC, which is not ideal for our purpose. Unless you
have a serial cable, the easiest way to change this is by booting
to TurrisOS and logging in with ssh:
.. code-block:: console
root@turris:/# fw_printenv boot_targets
boot_targets=mmc0 nvme0 scsi0 usb0 pxe dhcp
root@turris:/# fw_setenv boot_targets usb0 mmc0
root@turris:/# fw_printenv boot_targets
boot_targets=usb0 mmc0
root@turris:/# reboot -f
It should now boot into the recovery image. It expects a network
cable to be plugged into LAN2 with something on the other end of
it that serves DHCP requests. Check your DHCP server logs for a
request from a ``liminix-recovery`` host and figure out what IP
address was assigned.
.. code-block:: console
$ ssh liminix-recovery.lan
You should get a "Busybox" banner and a root prompt. Now you can
start preparing the device to install Liminix on it. First we'll
mount the root filesystem and take a snapshot:
.. code-block:: console
# mkdir /dest && mount /dev/mmcblk0p1 /dest
# schnapps -d /dest create "pre liminix"
# schnapps -d /dest list
ERROR: not a valid btrfs filesystem: /
# | Type | Size | Date | Description
------+-----------+-------------+---------------------------+------------------------------------
1 | single | 16.00KiB | 1970-01-01 00:11:49 +0000 | pre liminix
(``not a valid btrfs filesystem: /`` is not a real error)
then we can remove all the files
.. code-block:: console
# rm -r /dest/@/*
and then it's ready to install the real Liminix system onto. On
your build system, create the Liminix configuration you wish to
install: here we'll use the ``rotuer`` example.
.. code-block:: console
build$ nix-build -I liminix-config=./examples/rotuer.nix \
--arg device "import ./devices/turris-omnia" \
-A outputs.systemConfiguration
and then use :command:`min-copy-closure` to copy it to the device.
.. code-block:: console
build$ nix-shell --run \
"min-copy-closure -r /dest/@ root@liminix-recovery.lan result"
and activate it
.. code-block:: console
build$ ssh root@liminix-recovery.lan \
"/dest/@/$(readlink result)/bin/install /dest/@"
The final steps are performed directly on the device again: add
a symlink so U-Boot can find :file:`/boot`, then restore the
default boot order and reboot into the new configuration.
.. code-block:: console
# cd /dest && ln -s @/boot .
# fw_setenv boot_targets "mmc0 nvme0 scsi0 usb0 pxe dhcp"
# cd / ; umount /dest
# reboot
Installation using a TFTP server and serial console
===================================================
If you have a :ref:`serial` console connection and a TFTP server,
and would rather use them than fiddling with USB sticks, the
:file:`examples/recovery.nix` configuration also works
using the ``tftpboot`` output. So you can do
.. code-block:: console
build$ nix-build -I liminix-config=./examples/recovery.nix \
--arg device "import ./devices/turris-omnia" \
-A outputs.tftpboot
and then paste the generated :file:`result/boot.scr` into
U-Boot, and you will end up with the same system as you would
have had after booting from USB. If you don't have a serial
console connection you could probably even get clever with
elaborate use of :command:`fw_setenv`, but that is left as
an exercise for the reader.
'';
system = {
crossSystem = {
config = "armv7l-unknown-linux-musleabihf";
};
};
module = {pkgs, config, lib, lim, ... }:
let
openwrt = pkgs.openwrt;
inherit (lib) mkOption types;
inherit (pkgs.liminix.services) oneshot;
inherit (pkgs) liminix;
mtd_by_name_links = pkgs.liminix.services.oneshot rec {
name = "mtd_by_name_links";
up = ''
mkdir -p /dev/mtd/by-name
cd /dev/mtd/by-name
for i in /sys/class/mtd/mtd*[0-9]; do
ln -s ../../$(basename $i) $(cat $i/name)
done
'';
};
in {
imports = [
../../modules/arch/arm.nix
../../modules/outputs/tftpboot.nix
../../modules/outputs/mbrimage.nix
../../modules/outputs/extlinux.nix
];
config = {
services.mtd-name-links = mtd_by_name_links;
kernel = {
src = pkgs.pkgsBuildBuild.fetchurl {
name = "linux.tar.gz";
url = "https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.7.4.tar.gz";
hash = "sha256-wIrmL0BS63nRwWfm4nw+dRNVPUzGh9M4X7LaHzAn5tU=";
};
version = "6.7.4";
config = {
PCI = "y";
OF = "y";
MEMORY = "y"; # for MVEBU_DEVBUS
DMADEVICES = "y"; # for MV_XOR
CPU_V7 = "y";
ARCH_MULTIPLATFORM = "y";
ARCH_MVEBU = "y";
ARCH_MULTI_V7= "y";
PCI_MVEBU = "y";
AHCI_MVEBU = "y";
RTC_CLASS = "y";
RTC_DRV_ARMADA38X = "y"; # this may be useful anyway?
EXPERT = "y";
ALLOW_DEV_COREDUMP = "n";
# dts has a compatible for this but dmesg is not
# showing it
EEPROM_AT24 = "y"; # atmel,24c64
I2C = "y";
I2C_MUX = "y";
I2C_MUX_PCA954x = "y";
MACH_ARMADA_38X = "y";
SMP = "y";
# this is disabled for the moment because it relies on a
# GCC plugin that requires gmp.h to build, and I can't see
# right now how to confgure it to find gmp
STACKPROTECTOR_PER_TASK = "n";
NR_CPUS = "4";
VFP = "y";
NEON= "y";
# WARNING: unmet direct dependencies detected for ARCH_WANT_LIBATA_LEDS
ATA = "y";
PSTORE = "y";
PSTORE_RAM = "y";
PSTORE_CONSOLE = "y";
# PSTORE_DEFLATE_COMPRESS = "n";
BLOCK = "y";
MMC="y";
PWRSEQ_EMMC="y"; # ???
PWRSEQ_SIMPLE="y"; # ???
MMC_BLOCK="y";
MMC_SDHCI= "y";
MMC_SDHCI_PLTFM= "y";
MMC_SDHCI_PXAV3= "y";
MMC_MVSDIO= "y";
SERIAL_8250 = "y";
SERIAL_8250_CONSOLE = "y";
SERIAL_OF_PLATFORM="y";
SERIAL_MVEBU_UART = "y";
SERIAL_MVEBU_CONSOLE = "y";
SERIAL_8250_DMA= "y";
SERIAL_8250_DW= "y";
SERIAL_8250_EXTENDED= "y";
SERIAL_8250_MANY_PORTS= "y";
SERIAL_8250_SHARE_IRQ= "y";
OF_ADDRESS= "y";
OF_MDIO= "y";
WATCHDOG = "y"; # watchdog is enabled by u-boot
ORION_WATCHDOG = "y"; # so is non-optional to keep feeding
MVEBU_DEVBUS = "y"; # "Device Bus controller ... flash devices such as NOR, NAND, SRAM, and FPGA"
MVMDIO = "y";
MVNETA = "y";
MVNETA_BM = "y";
MVNETA_BM_ENABLE = "y";
SRAM = "y"; # mmio-sram is "compatible" for bm_bppi reqd by BM
PHY_MVEBU_A38X_COMPHY = "y"; # for eth2
MARVELL_PHY = "y";
MVPP2 = "y";
MV_XOR = "y";
# there is NOR flash on this device, which is used for U-Boot
# and the rescue system (which we don't interfere with) but
# also for the U-Boot environment variables (which we might
# need to meddle with)
MTD_SPI_NOR = "y";
SPI = "y";
SPI_MASTER = "y";
SPI_ORION = "y";
NET_DSA = "y";
NET_DSA_MV88E6XXX = "y"; # depends on PTP_1588_CLOCK_OPTIONAL
};
conditionalConfig = {
USB = {
USB_XHCI_MVEBU = "y";
USB_XHCI_HCD = "y";
};
WLAN = {
WLAN_VENDOR_ATH = "y";
ATH_COMMON = "m";
ATH9K = "m";
ATH9K_PCI = "y";
ATH10K = "m";
ATH10K_PCI = "m";
ATH10K_DEBUG = "y";
};
};
};
boot = {
commandLine = [
"console=ttyS0,115200"
"pcie_aspm=off" # ath9k pci incompatible with PCIe ASPM
];
};
filesystem =
let
inherit (pkgs.pseudofile) dir symlink;
firmware = pkgs.stdenv.mkDerivation {
name = "wlan-firmware";
phases = ["installPhase"];
installPhase = ''
mkdir $out
cp -r ${pkgs.linux-firmware}/lib/firmware/ath10k/QCA988X $out
'';
};
in dir {
lib = dir {
firmware = dir {
ath10k = symlink firmware;
};
};
etc = dir {
"fw_env.config" =
let f = pkgs.writeText "fw_env.config" ''
/dev/mtd/by-name/u-boot-env 0x0 0x10000 0x10000
'';
in symlink f;
};
};
boot.tftp = {
loadAddress = lim.parseInt "0x1700000";
kernelFormat = "zimage";
compressRoot = true;
};
hardware = let
mac80211 = pkgs.kmodloader.override {
inherit (config.system.outputs) kernel;
targets = ["ath9k" "ath10k_pci"];
};
in {
defaultOutput = "mtdimage";
loadAddress = lim.parseInt "0x00800000"; # "0x00008000";
entryPoint = lim.parseInt "0x00800000"; # "0x00008000";
rootDevice = "/dev/mmcblk0p1";
dts = {
src = "${config.system.outputs.kernel.modulesupport}/arch/arm/boot/dts/marvell/armada-385-turris-omnia.dts";
includes = [
"${config.system.outputs.kernel.modulesupport}/arch/arm/boot/dts/marvell/"
];
};
flash.eraseBlockSize = 65536; # only used for tftpboot
networkInterfaces =
let
inherit (config.system.service.network) link;
inherit (config.system.service) bridge;
in rec {
en70000 = link.build {
# in armada-38x.dtsi this is eth0.
# It's connected to port 5 of the 88E6176 switch
devpath = "/devices/platform/soc/soc:internal-regs/f1070000.ethernet";
# name is unambiguous but not very semantic
ifname = "en70000";
};
en30000 = link.build {
# in armada-38x.dtsi this is eth1
# It's connected to port 6 of the 88E6176 switch
devpath = "/devices/platform/soc/soc:internal-regs/f1030000.ethernet";
# name is unambiguous but not very semantic
ifname = "en30000";
};
# the default (from the dts? I'm guessing) behavour for
# lan ports on the switch is to attach them to
# en30000. It should be possible to do something better,
# per
# https://www.kernel.org/doc/html/latest/networking/dsa/configuration.html#affinity-of-user-ports-to-cpu-ports
# but apparently OpenWrt doesn't either so maybe it's more
# complicated than it looks.
wan = link.build {
# in armada-38x.dtsi this is eth2. It may be connected to
# an ethernet phy or to the SFP cage, depending on a gpio
devpath = "/devices/platform/soc/soc:internal-regs/f1034000.ethernet";
ifname = "wan";
};
lan0 = link.build { ifname = "lan0"; };
lan1 = link.build { ifname = "lan1"; };
lan2 = link.build { ifname = "lan2"; };
lan3 = link.build { ifname = "lan3"; };
lan4 = link.build { ifname = "lan4"; };
lan5 = link.build { ifname = "lan5"; };
lan = lan0; # maybe we should build a bridge?
wlan = link.build {
ifname = "wlan0";
dependencies = [ mac80211 ];
};
wlan5 = link.build {
ifname = "wlan1";
dependencies = [ mac80211 ];
};
};
};
};
};
}

View File

@ -12,9 +12,13 @@ BUILDDIR = _build
help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
hardware.rst: hardware.nix
@rm -f hardware.rst || true
@cp $$(nix-build hardware.nix) hardware.rst
.PHONY: help Makefile
# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
html: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

View File

@ -117,7 +117,7 @@ If you are prepared to open the device and have a TTL serial adaptor
of some kind to connect it to, you can probably use U-Boot and a TFTP
server to download and flash the image. This is quite
hardware-specific, and sometimes involves soldering: please refer
to the :ref:`development manual <tftp server>`.
to :ref:`serial`.
Flashing from OpenWrt

View File

@ -27,19 +27,16 @@ To build it,
nix-build -I liminix-config=path/to/your/configuration.nix --arg device "import ./devices/qemu" -A outputs.default
In a ``buildEnv`` nix-shell, you can use the :command:`run-liminix-vm` command
to run Qemu with appropriate options. It connects the Liminix
This creates a :file:`result/` directory containing a :file:`vmlinux`
and a :file:`rootfs`, and also a shell script :file:`run.sh` which
invokes QEMU to run that kernel with that filesystem. It connects the Liminix
serial console and the `QEMU monitor <https://www.qemu.org/docs/master/system/monitor.html>`_ to stdin/stdout. Use ^P (not ^A) to switch to the monitor.
.. code-block:: console
nix-shell --run "run-liminix-vm result/vmlinux result/squashfs"
If you run with ``--background /path/to/some/directory`` as the first
parameter, it will fork into the background and open Unix sockets in
that directory for console and monitor. Use :command:`connect-vm`
(also in the ``buildEnv`` environment) to connect to either of these
sockets, and ^O to disconnect.
that directory for console and monitor. Use :command:`nix-shell --run
connect-vm` to connect to either of these sockets, and ^O to
disconnect.
.. _qemu-networking:
@ -55,9 +52,11 @@ the right way:
* multicast 230.0.0.1:1235 : lan
* multicast 230.0.0.1:1236 : world (the internet)
A VM started with :command:`run-liminix-vm` is connected to "lan" and "access", and
the emulated border network gateway (see below) runs PPPoE and is
connected to "access" and "world".
Any VM started by a :command:`run.sh` script is connected to "lan" and
"access", and the emulated border network gateway (see below) runs
PPPoE and is connected to "access" and "world".
.. _border-network-gateway:
Border Network Gateway
----------------------
@ -89,6 +88,68 @@ time with configurations for RP-PPPoE and/or Accel PPP.`
Hardware devices
****************
.. _serial:
U-Boot and serial shenanigans
=============================
Every device that we have so far encountered in Liminix uses `U-Boot,
the "Universal Boot Loader" <https://docs.u-boot.org/en/latest/>`_ so
it's worth knowing a bit about it. "Universal" is in this context a
bit of a misnomer, though: encountering *mainline* U-Boot is very rare
and often you'll find it is a fork from some version last updated
in 2008. Upgrading U-Boot is more or less complicated depending on the
device and is outside scope for Liminix.
To speak to U-Boot on your device you'll usually need a serial
connection to it. This is device-specific. Usually it involves
opening the box, locating the serial header pins (TX, RX and GND) and
connecting a USB TTL converter to them.
The Rolls Royce of USB/UART cables is the `FTDI cable
<https://cpc.farnell.com/ftdi/ttl-232r-rpi/cable-debug-ttl-232-usb-rpi/dp/SC12825?st=usb%20to%20uart%20cable>`_,
but there are cheaper alternatives based on the PL2303 and CP2102 chipsets. Or
get creative and use the `UART GPIO pins <https://pinout.xyz/>`_ on a Raspberry Pi. Whatever you do, make sure
that the voltages are compatible: if your device is 3.3V (this is
typical but not universal), you don't want to be sending it 5v or
(even worse) 12v.
Run a terminal emulator such as Minicom on the computer at other end
of the link. 115200 8N1 is the typical speed.
.. NOTE::
TTL serial connections typically have no form of flow control and
so don't always like having massive chunks of text pasted into
them - and U-Boot may drop characters while it's busy. So don't
necessarily expect to copy-paste large chunks of text into the
terminal emulator and have it work just like that.
If using Minicom, you may find it helps to bring up the "Termimal
settings" dialog (C^A T), then configure "Newline tx delay" to
some small but non-zero value.
When you turn the router on you should be greeted with some messages
from U-Boot, followed by the instruction to hit some key to stop
autoboot. Do this and you will get to the prompt. If you didn't see
anything, the strong likelihood is that TX and RX are the wrong way
around. If you see garbage, try a different speed.
Interesting commands to try first in U-Boot are :command:`help` and
:command:`printenv`.
To do anything useful with U-Boot you will probably need a way to get
large binary files onto the device, and the usual way to do this is by
adding a network connection and using TFTP to download them. It's
quite common that the device's U-Boot doesn't speak DHCP so it will
need a static LAN address. You might also want to keep it away from
your "real" LAN: see :ref:`bng` for some potentially useful tooling
to use it on an isolated network.
TFTP
====
.. _tftp server:
How you get your image onto hardware will vary according to the
@ -119,7 +180,7 @@ Now add the device and server IP addresses to your configuration:
};
and then build the derivation for ``outputs.default`` or
``outputs.flashimage`` (for which it will be an alias on any device
``outputs.mtdimage`` (for which it will be an alias on any device
where this is applicable). You should find it has created
* :file:`result/firmware.bin` which is the file you are going to flash
@ -152,6 +213,8 @@ U-Boot to transfer the kernel and filesystem over TFTP and boot the
kernel from RAM.
.. _bng:
Networking
==========

View File

@ -1,31 +1,10 @@
{ eval, lib, pkgs }:
let
overlay = import ../overlay.nix;
pkgs = import <nixpkgs> ( {
overlays = [overlay];
config = {
allowUnsupportedSystem = true; # mipsel
permittedInsecurePackages = [
"python-2.7.18.6" # kernel backports needs python <3
];
};
});
inherit (pkgs) lib;
inherit (lib) types;
modulenames =
builtins.attrNames
(lib.filterAttrsRecursive
(n: t:
(n != "arch") &&
((t=="directory") ||
((t=="regular") && ((builtins.match ".*\\.nix$" n) != null))))
(builtins.readDir ../modules));
modulefiles = builtins.map (n: builtins.toPath "${../modules}/${n}") modulenames;
eval = (lib.evalModules {
modules = [
{ _module.args = { inherit pkgs; lib = pkgs.lib; }; }
] ++ modulefiles;
});
conf = eval.config;
rootDir = builtins.toPath ./..;
stripAnyPrefixes = lib.flip (lib.fold lib.removePrefix)
["${rootDir}/"];
optToDoc = name: opt : {
inherit name;
description = opt.description or null;
@ -42,16 +21,12 @@ let
then
let sd = lib.attrByPath item.loc ["not found"] conf;
in item // {
declarations = map stripAnyPrefixes item.declarations;
parameters =
let x = lib.mapAttrsToList optToDoc sd.parameters; in x;
}
else
item;
o = builtins.map spliceServiceDefn
(pkgs.lib.optionAttrSetToDocList eval.options);
in {
doc = pkgs.writeText "options.yaml" ''
# ${./..}
${builtins.toJSON o}
'';
}
item // { declarations = map stripAnyPrefixes item.declarations; };
in
builtins.map spliceServiceDefn
(pkgs.lib.optionAttrSetToDocList eval.options)

View File

@ -1,18 +1,38 @@
with import <nixpkgs> {} ;
let
devices =
builtins.readDir ../devices;
texts = lib.mapAttrsToList (n: t:
inherit (builtins) stringLength readDir filter;
devices = filter (n: n != "families")
(lib.mapAttrsToList (n: t: n) (readDir ../devices));
texts = map (n:
let d = import ../devices/${n}/default.nix;
d' = { description = "no description for ${n}"; } // d;
in d'.description )
d' = {
description = "${n}\n${substring 0 (stringLength n) "********************************"}\n";
} // d;
installer =
if d ? description && d ? installer
then ''
The default installation route for this device is
:ref:`system-outputs-${d.installer}`
''
else "";
in d'.description)
devices;
in
writeText "hwdoc" ''
Supported hardware
##################
For development, the `GL.iNet GL-MT300A <https://www.gl-inet.com/products/gl-mt300a/>`_
is an attractive choice as it has a builtin "debrick" procedure in the
boot monitor and is also comparatively simple to
attach serial cables to (soldering not required), so it
is lower-risk than some devices.
For a more powerful device, something with an ath10k would be the safe bet,
or the Linksys E8450 which seems popular in the openwrt community.
${lib.concatStringsSep "\n\n" texts}
''

View File

@ -12,6 +12,7 @@ Liminix
development
modules
hardware
outputs
Indices and tables

13
doc/outputs.rst Normal file
View File

@ -0,0 +1,13 @@
Outputs
#######
Liminix *outputs* are artefacts that can be installed somehow on a
target device, or "installers" which run on the target device to
perform the installation.
There are different outputs because different target devices need
different artefacts, or have different ways to get that artefact
installed. The options available for a particular device are described in
the section for that device.
.. include:: outputs-generated.rst

View File

@ -0,0 +1,19 @@
(local yaml (require :lyaml))
;; (local { : view } (require :fennel))
(fn output? [option]
(match option.loc
["system" "outputs" & _] true
_ false))
(fn sorted-options [options]
(table.sort
options
(fn [a b] (< a.name b.name)))
options)
(each [_ option (ipairs (sorted-options (yaml.load (io.read "*a"))))]
(when (and (output? option) (not option.internal))
(print (.. ".. _" (string.gsub option.name "%." "-") ":") "\n")
(print option.description)))

View File

@ -2,21 +2,25 @@
(local { : view } (require :fennel))
(fn basename [str ext]
(-> str
(string.gsub "(.*/)(.*)" "%2")
(string.gsub (.. ext "$") "")))
(fn headline [name]
(let [(_ _ basename) (string.find name ".*/([^/].*).nix")
len (basename:len)]
(.. basename "\n" (string.rep "=" len))))
(let [title (assert (basename name ".nix"))
len (title:len)]
(.. title "\n" (string.rep "=" len))))
(fn read-preamble [pathname]
(if (= (pathname:sub 1 1) "/")
(let [pathname (if (string.match pathname ".nix$")
pathname
(.. pathname "/default.nix"))]
(with-open [f (assert (io.open pathname :r))]
(accumulate [lines nil
l (f:lines)
:until (not (= (string.sub l 1 2) "##"))]
(.. (or lines "") (string.gsub l "^## *" "") "\n"))))))
(let [pathname (if (string.match pathname ".nix$")
pathname
(.. pathname "/default.nix"))]
(with-open [f (assert (io.open pathname :r))]
(accumulate [lines nil
l (f:lines)
:until (not (= (string.sub l 1 2) "##"))]
(.. (or lines "") (string.gsub l "^## *" "") "\n")))))
(fn relative-pathname [pathname]
(let [pathname

View File

@ -69,10 +69,11 @@ device's serial console and the `QEMU monitor
stdin/stdout.
You should now see Linux boot messages and after a few seconds be
presented with a login prompt. You can login on the console as
``root`` (password is "secret") and poke around to see what processes are
running. To kill the emulator, press ^P (Control P) then c to enter the
"QEMU Monitor", then type ``quit`` at the ``(qemu)`` prompt.
presented with a root shell prompt. You can run commands to look at
the filesystem, see what processes are running, view log messages (in
:file:/run/uncaught-logs.current), etc. To kill the emulator, press ^P
(Control P) then c to enter the "QEMU Monitor", then type ``quit`` at
the ``(qemu)`` prompt.
To see that it's running network services we need to connect to its
emulated network. Start the machine again, if you had stopped it, and
@ -137,20 +138,14 @@ unbrick if necessary.
work here, but you accept the slightly greater bricking
risk if it doesn't.
You may want to acquire a `USB TTL serial cable
<https://cpc.farnell.com/ftdi/ttl-232r-rpi/cable-debug-ttl-232-usb-rpi/dp/SC12825?st=usb%20to%20uart%20cable>`_
when you start working with Liminix on real hardware. You
won't *need* it for this example, assuming it works, but it
See :doc:`hardware` for device support status.
You may want to read and inwardly digest the Develoment Manual section
:ref:`serial` when you start working with Liminix on real hardware. You
won't *need* serial access for this example, assuming it works, but it
allows you
to see the boot monitor and kernel messages, and to login directly to
the device if for some reason it doesn't bring its network up. You have options
here: the FTDI-based cables are the Rolls Royce of serial cables,
whereas the ones based on PL2303 and CP2102 chipsets are cheaper but
also fussier - or you could even get creative and use e.g. a
`Raspberry Pi <https://pinout.xyz/#>`_ or other SBC with a UART and
TX/RX/GND header pins. Make sure that the voltages are compatible:
this is a 3.3v device and you don't want to be sending it 5v or (even
worse) 12v.
the device if for some reason it doesn't bring its network up.
Now we can build Liminix. Although we could use the same example
configuration as we did for Qemu, you might not want to plug a DHCP

View File

@ -24,7 +24,6 @@ in rec {
};
imports = [
../modules/standard.nix
../modules/wlan.nix
../modules/network
../modules/vlan
@ -32,7 +31,6 @@ in rec {
../modules/watchdog
../modules/mount
];
hostname = "arhcive";
kernel = {
@ -147,7 +145,7 @@ in rec {
};
users.root = {
passwd = lib.mkForce secrets.root_password;
passwd = lib.mkForce secrets.root.passwd;
# openssh.authorizedKeys.keys = [
# (builtins.readFile "/home/dan/.ssh/id_rsa.pub")
# ];

View File

@ -35,6 +35,7 @@ in {
(drop "icmpv6 type destination-unreachable ct state invalid,untracked")
];
};
forward-ip6 = {
type = "filter";
family = "ip6";
@ -95,19 +96,23 @@ in {
# recognised (outbound-initiated) flow
(accept "oifname \"int\" iifname \"ppp0\" ct state established,related")
(accept "iifname \"int\" oifname \"ppp0\" ")
"log prefix \"DENIED CHAIN=forward-ip6 \""
];
};
input-lan = {
input-ip6-lan = {
type = "filter";
family = "ip6";
rules = [
(accept "udp dport 547") # dhcp, could restrict to daddr ff02::1:2
(accept "udp dport 53") # dns
(accept "tcp dport 22")
];
};
input-wan = {
input-ip6-wan = {
type = "filter";
family = "ip6";
@ -123,8 +128,8 @@ in {
hook = "input";
rules = [
(accept "meta l4proto icmpv6")
"iifname int jump input-lan"
"iifname ppp0 jump input-wan"
"iifname int jump input-ip6-lan"
"iifname ppp0 jump input-ip6-wan"
(if allow-incoming
then accept "oifname \"int\" iifname \"ppp0\""
else "oifname \"int\" iifname \"ppp0\" jump incoming-allowed-ip6"
@ -132,6 +137,7 @@ in {
# how does this even make sense in an input chain?
(accept "oifname \"int\" iifname \"ppp0\" ct state established,related")
(accept "iifname \"int\" oifname \"ppp0\" ")
"log prefix \"DENIED CHAIN=input-ip6 \""
];
};
@ -154,6 +160,7 @@ in {
"oifname \"ppp0\" masquerade"
];
};
nat-rx = {
type = "nat";
hook = "prerouting";
@ -167,4 +174,71 @@ in {
# packet replies. "
];
};
# these chains are for rules that have to be present for things to
# basically work at all: for example, the router won't issue DHCP
# unless it's allowed to receive DHCP requests. For "site policy"
# rules you may prefer to use incoming-allowed-ip[46] instead
input-ip4-lan = {
type = "filter";
family = "ip";
rules = [
(accept "udp dport 67") # dhcp
(accept "udp dport 53") # dns
(accept "tcp dport 22") # ssh
];
};
input-ip4-wan = {
type = "filter";
family = "ip";
rules = [
(accept "udp sport 53")
];
};
input-ip4 = {
type = "filter";
family = "ip";
policy = "drop";
hook = "input";
rules = [
"iifname lo accept"
"icmp type { echo-request, echo-reply } accept"
"iifname int jump input-ip4-lan"
"iifname ppp0 jump input-ip4-wan"
"oifname \"int\" iifname \"ppp0\" jump incoming-allowed-ip4"
"ct state established,related accept"
"log prefix \"DENIED CHAIN=input-ip4 \""
];
};
forward-ip4 = {
type = "filter";
family = "ip";
policy = "drop";
hook = "forward";
rules = [
"iifname \"int\" accept"
"ct state established,related accept"
"oifname \"int\" iifname \"ppp0\" jump incoming-allowed-ip4"
"log prefix \"DENIED CHAIN=forward-ip4 \""
];
};
incoming-allowed-ip4 = {
type = "filter";
family = "ip";
rules = [
# This is where you put permitted incoming connections. If
# you're using NAT and want to forward a port from outside to
# devices on the LAN, then you need a DNAT rule in nat-rx chain
# *and* to accept the packet in this chain (specifying the
# internal (RFC1918) address).
];
};
}

View File

@ -33,7 +33,6 @@ in rec {
../modules/ntp
../modules/ppp
../modules/ssh
../modules/standard.nix
../modules/vlan
../modules/wlan.nix
];

View File

@ -30,7 +30,6 @@ in rec {
../modules/hostapd
../modules/bridge
../modules/ssh
../modules/standard.nix
];
hostname = "extneder";
@ -132,6 +131,6 @@ in rec {
dependencies = [services.dhcpc];
};
users.root.passwd = lib.mkForce secrets.root_password;
users.root.passwd = lib.mkForce secrets.root.passwd;
defaultProfile.packages = with pkgs; [nftables strace tcpdump swconfig];
}

View File

@ -8,7 +8,6 @@ in rec {
../modules/network
../modules/ssh
../modules/vlan
../modules/flashimage.nix
];
boot.tftp = {

116
examples/recovery.nix Normal file
View File

@ -0,0 +1,116 @@
{ config, pkgs, lib, ... } :
let
inherit (pkgs) serviceFns;
svc = config.system.service;
inherit (pkgs.pseudofile) dir symlink;
inherit (pkgs.liminix.services) oneshot longrun bundle target;
some-util-linux = pkgs.runCommand "some-util-linux" {} ''
mkdir -p $out/bin
cd ${pkgs.util-linux-small}/bin
cp fdisk sfdisk mkswap $out/bin
'';
in rec {
imports = [
../modules/network
../modules/ssh
../modules/usb.nix
../modules/schnapps
../modules/outputs/mtdimage.nix
../modules/outputs/mbrimage.nix
../modules/outputs/tftpboot.nix
../modules/outputs/ubifs.nix
../modules/outputs/ubimage.nix
../modules/outputs/jffs2.nix
../modules/outputs/ext4fs.nix
../modules/outputs/extlinux.nix
];
kernel.config = {
BTRFS_FS = "y";
};
boot.tftp = {
ipaddr = "10.0.0.8"; # my address
serverip = "10.0.0.1"; # build machine or other tftp server
freeSpaceBytes = 1024 * 1024 * 4;
};
boot.loader.extlinux.enable = true;
hostname = "liminix-recovery";
services.dhcpc = svc.network.dhcp.client.build {
interface = config.hardware.networkInterfaces.lan2;
# don't start DHCP until the hostname is configured,
# so it can identify itself to the DHCP server
dependencies = [ config.services.hostname ];
};
services.sshd = svc.ssh.build {
dependencies = [ config.services.growfs ];
};
services.defaultroute4 = svc.network.route.build {
via = "$(output ${services.dhcpc} router)";
target = "default";
dependencies = [services.dhcpc];
};
services.resolvconf = oneshot rec {
dependencies = [ services.dhcpc ];
name = "resolvconf";
up = ''
. ${serviceFns}
( in_outputs ${name}
for i in $(output ${services.dhcpc} dns); do
echo "nameserver $i" > resolv.conf
done
)
'';
};
services.growfs = let name = "growfs"; in oneshot {
inherit name;
up = ''
. ${serviceFns}
device=$(grep /persist /proc/1/mountinfo | cut -f9 -d' ')
${pkgs.e2fsprogs}/bin/resize2fs $device
'';
};
filesystem = dir {
etc = dir {
"resolv.conf" = symlink "${services.resolvconf}/.outputs/resolv.conf";
};
mnt = dir {};
};
rootfsType = "ext4";
# sda is most likely correct for the boot-from-USB case. For tftp
# it's overridden by the boot.scr anyway, so maybe it all works out
hardware.rootDevice = lib.mkForce "/dev/sda1";
users.root = {
# the password is "secret". Use mkpasswd -m sha512crypt to
# create this hashed password string
passwd = "$6$y7WZ5hM6l5nriLmo$5AJlmzQZ6WA.7uBC7S8L4o19ESR28Dg25v64/vDvvCN01Ms9QoHeGByj8lGlJ4/b.dbwR9Hq2KXurSnLigt1W1";
openssh.authorizedKeys.keys =
let fromBuild =
(builtins.readFile
((builtins.toPath (builtins.getEnv "HOME")) + "/.ssh/authorized_keys")
);
in lib.splitString "\n" fromBuild;
};
defaultProfile.packages = with pkgs; [
e2fsprogs # ext4
btrfs-progs
mtdutils # mtd, jffs2, ubifs
dtc # you never know when you might need device tree stuff
some-util-linux
libubootenv # fw_{set,print}env
pciutils
];
}

View File

@ -1,5 +1,6 @@
rec {
{
wpa_passphrase = "you bring light in";
ssid = "liminix";
l2tp = {
name = "abcde@a.1";
password = "NotMyIspPassword";
@ -10,5 +11,9 @@ rec {
openssh.authorizedKeys.keys = [
];
};
root_password = root.passwd;
lan = {
prefix = "10.8.0";
};
}

View File

@ -8,7 +8,10 @@
{ config, pkgs, lib, ... } :
let
secrets = import ./rotuer-secrets.nix;
secrets = {
domainName = "fake.liminix.org";
firewallRules = {};
} // (import ./rotuer-secrets.nix);
inherit (pkgs.liminix.services) oneshot longrun bundle;
inherit (pkgs) serviceFns;
svc = config.system.service;
@ -34,7 +37,6 @@ in rec {
imports = [
../modules/wlan.nix
../modules/standard.nix
../modules/network
../modules/ppp
../modules/dnsmasq
@ -43,15 +45,20 @@ in rec {
../modules/hostapd
../modules/bridge
../modules/ntp
../modules/schnapps
../modules/ssh
../modules/outputs/btrfs.nix
../modules/outputs/extlinux.nix
];
rootfsType = "jffs2";
hostname = "rotuer";
rootfsType = "btrfs";
rootOptions = "subvol=@";
boot.loader.extlinux.enable = true;
services.hostap = svc.hostapd.build {
interface = config.hardware.networkInterfaces.wlan;
params = {
ssid = "liminix";
ssid = secrets.ssid;
hw_mode="g";
channel = "2";
ieee80211n = 1;
@ -61,19 +68,20 @@ in rec {
services.hostap5 = svc.hostapd.build {
interface = config.hardware.networkInterfaces.wlan5;
params = rec {
ssid = "liminix_5";
ssid = "${secrets.ssid}5";
hw_mode="a";
channel = 36;
ht_capab = "[HT40+]";
vht_oper_chwidth = 1;
vht_oper_centr_freq_seg0_idx = channel + 6;
ieee80211n = 1;
ieee80211ac = 1;
} // wirelessConfig;
};
services.int = svc.network.address.build {
interface = svc.bridge.primary.build { ifname = "int"; };
family = "inet"; address ="10.8.0.1"; prefixLength = 16;
family = "inet"; address ="${secrets.lan.prefix}.1"; prefixLength = 24;
};
services.bridge = svc.bridge.members.build {
@ -81,7 +89,12 @@ in rec {
members = with config.hardware.networkInterfaces;
[ wlan
wlan5
lan ];
lan0
lan1
lan2
lan3
lan4
];
};
services.ntp = svc.ntp.build {
@ -99,7 +112,7 @@ in rec {
resolvconf = services.resolvconf;
inherit interface;
ranges = [
"10.8.0.10,10.8.0.240"
"${secrets.lan.prefix}.10,${secrets.lan.prefix}.240"
# ra-stateless: sends router advertisements with the O and A
# bits set, and provides a stateless DHCP service. The client
# will use a SLAAC address, and use DHCP for other
@ -110,8 +123,8 @@ in rec {
# You can add static addresses for the DHCP server here. I'm
# not putting my actual MAC addresses in a public git repo ...
hosts = { } // lib.optionalAttrs (builtins.pathExists ./static-leases.nix) (import ./static-leases.nix);
domain = "fake.liminix.org";
upstreams = [ "/${secrets.domainName}/" ];
domain = secrets.domainName;
};
services.wan = svc.pppoe.build {
@ -157,7 +170,9 @@ in rec {
};
services.firewall = svc.firewall.build {
ruleset = import ./demo-firewall.nix;
ruleset =
let defaults = import ./demo-firewall.nix;
in lib.recursiveUpdate defaults secrets.firewallRules;
};
services.packet_forwarding = svc.network.forward.build { };
@ -182,5 +197,18 @@ in rec {
defaultProfile.packages = with pkgs; [
min-collect-garbage
nftables
strace
tcpdump
s6
];
programs.busybox = {
applets = [
"fdisk" "sfdisk"
];
options = {
FEATURE_FANCY_TAIL = "y";
};
};
}

109
examples/turris.nix Normal file
View File

@ -0,0 +1,109 @@
{ config, pkgs, lib, lim, ... } :
let
inherit (pkgs) serviceFns;
svc = config.system.service;
in rec {
imports = [
../modules/network
../modules/ssh
../modules/vlan
../modules/wlan.nix
../modules/hostapd
../modules/bridge
../modules/ext4fs.nix
../modules/tftpboot.nix
];
rootfsType = "ext4";
boot.tftp = {
# IP addresses to use in the boot monitor when flashing/ booting
# over TFTP. If you are flashing using the stock firmware's Web UI
# then these dummy values are fine
ipaddr = "10.0.0.8"; # my address
serverip = "10.0.0.1"; # build machine or other tftp server
loadAddress = lim.parseInt "0x40000800";
};
hostname = "omnia";
services.hostap =
let secrets = {
ssid = "not-the-internet";
channel = 4;
wpa_passphrase = "diamond dogs";
};
in svc.hostapd.build {
interface = config.hardware.networkInterfaces.wlan;
params = {
country_code = "GB";
hw_mode = "g";
wmm_enabled = 1;
ieee80211n = 1;
inherit (secrets) ssid channel wpa_passphrase;
auth_algs = 1; # 1=wpa2, 2=wep, 3=both
wpa = 2; # 1=wpa, 2=wpa2, 3=both
wpa_key_mgmt = "WPA-PSK";
wpa_pairwise = "TKIP CCMP"; # auth for wpa (may not need this?)
rsn_pairwise = "CCMP"; # auth for wpa2
};
};
services.hostap5 =
let secrets = {
ssid = "not-the-internet";
channel = 36;
wpa_passphrase = "diamond dogs";
};
in svc.hostapd.build {
interface = config.hardware.networkInterfaces.wlan5;
params = {
country_code = "GB";
hw_mode = "a";
ht_capab = "[HT40+]";
vht_oper_chwidth = 1;
vht_oper_centr_freq_seg0_idx = secrets.channel + 6;
ieee80211ac = 1;
wmm_enabled = 1;
inherit (secrets) ssid channel wpa_passphrase;
auth_algs = 1; # 1=wpa2, 2=wep, 3=both
wpa = 2; # 1=wpa, 2=wpa2, 3=both
wpa_key_mgmt = "WPA-PSK";
wpa_pairwise = "TKIP CCMP"; # auth for wpa (may not need this?)
rsn_pairwise = "CCMP"; # auth for wpa2
};
};
services.int = svc.bridge.primary.build {
ifname = "int";
};
services.dhcpc = svc.network.dhcp.client.build {
interface = services.int;
dependencies = [ config.services.hostname ];
};
services.bridge = svc.bridge.members.build {
primary = services.int;
members = with config.hardware.networkInterfaces; [
lan
wlan
];
};
services.sshd = svc.ssh.build { };
users.root = {
# the password is "secret". Use mkpasswd -m sha512crypt to
# create this hashed password string
passwd = "$6$y7WZ5hM6l5nriLmo$5AJlmzQZ6WA.7uBC7S8L4o19ESR28Dg25v64/vDvvCN01Ms9QoHeGByj8lGlJ4/b.dbwR9Hq2KXurSnLigt1W1";
};
defaultProfile.packages = with pkgs; [
figlet pciutils
];
}

39
modules/all-modules.nix Normal file
View File

@ -0,0 +1,39 @@
# Import all of the modules, used in the documentation generator. Not
# currently expected to work in an actual configuration, but it would
# be nice if it did.
{
imports = [
./base.nix
./bridge
./busybox.nix
./dhcp6c
./dnsmasq
./outputs/ext4fs.nix
./firewall
./hardware.nix
./hostapd
./hostname.nix
./outputs/initramfs.nix
./outputs/jffs2.nix
./kernel
./outputs/kexecboot.nix
./mount
./network
./ntp
./outputs.nix
./outputs/vmroot.nix
./outputs/ubimage.nix
./outputs/mtdimage.nix
./ppp
./ramdisk.nix
./squashfs.nix
./ssh
./outputs/tftpboot.nix
./outputs/ubifs.nix
./users.nix
./vlan
./watchdog
./wlan.nix
];
}

View File

@ -1,4 +1,4 @@
{ lib, pkgs, config, ...}:
{ lib, lim, pkgs, config, ...}:
{
config = {
kernel.config = {
@ -6,14 +6,13 @@
CPU_BIG_ENDIAN= "n";
# CMDLINE_FROM_BOOTLOADER availability is conditional
# on CMDLINE being set to something non-empty
CMDLINE="\"console=ttyAMA0\"";
CMDLINE="\"empty=false\"";
CMDLINE_FROM_BOOTLOADER = "y";
OF = "y";
# USE_OF = "y";
};
boot.commandLine = [
"console=ttyAMA0,38400"
];
hardware.ram.startAddress = lim.parseInt "0x40000000";
system.outputs.u-boot = pkgs.ubootQemuAarch64;
};
}

11
modules/arch/arm.nix Normal file
View File

@ -0,0 +1,11 @@
{ lib, lim, pkgs, config, ...}:
{
config = {
kernel.config = {
OF = "y";
};
kernel.makeTargets = ["arch/arm/boot/zImage"];
hardware.ram.startAddress = lim.parseInt "0x40000000";
system.outputs.u-boot = pkgs.ubootQemuArm;
};
}

View File

@ -1,4 +1,4 @@
{ lib, pkgs, config, ...}:
{ lib, pkgs, config, lim, ...}:
{
config = {
kernel.config = {
@ -10,6 +10,7 @@
OF = "y";
USE_OF = "y";
};
hardware.ram.startAddress = lim.parseInt "0x80000000";
boot.commandLine = [
"console=ttyS0,115200" # true of all mips we've yet encountered
];

View File

@ -5,5 +5,6 @@
kernel.config = {
CPU_BIG_ENDIAN = "y";
};
system.outputs.u-boot = pkgs.ubootQemuMips;
};
}

View File

@ -13,7 +13,7 @@ let
in {
imports = [
./kernel.nix # kernel is a separate module for doc purposes
./kernel # kernel is a separate module for doc purposes
];
options = {
defaultProfile = {
@ -39,17 +39,32 @@ in {
};
rootfsType = mkOption {
default = "squashfs";
type = types.enum ["squashfs" "jffs2"];
type = types.enum [
"btrfs"
"ext4"
"jffs2"
"squashfs"
"ubifs"
];
};
rootOptions = mkOption {
type = types.nullOr types.str;
default = null;
};
boot = {
commandLine = mkOption {
type = types.listOf types.nonEmptyStr;
default = [];
description = "Kernel command line";
};
imageFormat = mkOption {
type = types.enum ["fit" "uimage"];
default = "uimage";
};
tftp = {
loadAddress = mkOption {
type = types.str;
type = types.ints.unsigned;
description = ''
RAM address at which to load data when transferring via
TFTP. This is not the address of the flash storage,
@ -85,7 +100,8 @@ in {
"root=${config.hardware.rootDevice}"
"rootfstype=${config.rootfsType}"
"fw_devlink=off"
];
] ++ lib.optional (config.rootOptions != null) "rootflags=${config.rootOptions}";
users.root = {
uid = 0; gid= 0; gecos = "Root of all evaluation";
dir = "/home/root/";
@ -125,6 +141,7 @@ in {
proc = dir {};
run = dir {};
sys = dir {};
tmp = dir {};
};
};
}

View File

@ -1,31 +1,32 @@
(local { : system } (require :anoia))
(local svc (require :anoia.svc))
(fn changes [old-addresses new-addresses]
(let [added {}
deleted {}]
(each [n address (pairs new-addresses)]
(if (not (. old-addresses n))
(table.insert added address)))
(fn deletions [old-addresses new-addresses]
(let [deleted {}]
(each [n address (pairs old-addresses)]
(if (not (. new-addresses n))
(table.insert deleted address)))
(values added deleted)))
(let [now (. new-addresses n)]
(if (or (not now) (not (= now.len address.len)))
(table.insert deleted address))))
deleted))
(fn update-prefixes [device prefixes new-prefixes]
(let [(added deleted) (changes prefixes new-prefixes)]
(each [_ p (ipairs added)]
(system
(.. "ip address add " p.address "1/" p.len " dev " device)))
(each [_ p (ipairs deleted)]
(system
(.. "ip address del " p.address "1/" p.len " dev " device)))))
(fn update-prefixes [wan-device addresses new-addresses exec]
(each [_ p (ipairs (deletions addresses new-addresses))]
(exec
(.. "ip address del " p.address "1/" p.len " dev " wan-device)))
(each [_ p (pairs new-addresses)]
(exec
(.. "ip address change " p.address "1/" p.len
" dev " wan-device
" valid_lft " p.valid
" preferred_lft " p.preferred
)))
new-addresses)
(fn run []
(let [[state-directory lan-device] arg
dir (svc.open state-directory)]
(accumulate [addresses []
v (dir:events)]
(update-prefixes lan-device addresses (v:output "prefix")))))
(update-prefixes lan-device addresses (v:output "prefix") system))))
{ : changes : run }

View File

@ -5,23 +5,45 @@
(local a1
{
"2001-ab-cd-ef_hjgKHGhKJH" {
:address "2001:ab:cd:ef"
:len "64"
:preferred "200"
:valid "200"
}
"2001-ab-cd-ef" {
:address "2001:ab:cd:ef"
:len "64"
:preferred "3600"
:valid "7200"
}
}
)
(local a156
{
"2001-ab-cd-ef" {
:address "2001:ab:cd:ef"
:len "56"
:preferred "3600"
:valid "7200"
}
}
)
(local a2
{
"2001-0-1-2-3_aNteBnb" {
:address "2001:0:1:2:3"
:len "64"
:preferred "200"
:valid "200"
}
"2001-0-1-2-3" {
:address "2001:0:1:2:3"
:len "64"
:preferred "3600"
:valid "7200"
}
}
)
(local a21
{
"2001-0-1-2-3" {
:address "2001:0:1:2:3"
:len "64"
:preferred "1800"
:valid "5400"
}
}
)
@ -30,39 +52,85 @@
`(when (not ,assertion)
(assert false ,msg))))
(macro expect= [actual expected]
`(let [ve# (view ,expected)
va# (view ,actual)]
(when (not (= ve# va#))
(assert false
(.. "\nexpected " ve# "\ngot " va#)
))))
(fn first-address []
(let [(add del)
(subject.changes
(let [deleted
(subject.deletions
{ }
a1
)]
(expect (= (# del) 0))
(expect (= (# add) 1))
(let [[first] add]
(expect (= first.address "2001:ab:cd:ef")))))
(expect= deleted [])))
(fn second-address []
(let [(add del)
(subject.changes
(let [del
(subject.deletions
a1
(merge (dup a1) a2)
)]
(expect (= (# del) 0))
(expect (= (# add) 1))
(let [[first] add] (expect (= first.address "2001:0:1:2:3")))))
(expect= del [])))
(fn less-address []1
(let [(add del)
(subject.changes
(fn old-address-is-deleted []
(let [del
(subject.deletions
(merge (dup a1) a2)
a1
)]
(expect (= (# add) 0))
(expect (= (# del) 1))
(expect= (. del 1) (. a2 "2001-0-1-2-3"))
))
(let [[first] del] (expect (= first.address "2001:0:1:2:3")))))
(fn changed-lifetime-not-deleted []
(let [del
(subject.deletions
(merge (dup a1) a2)
(merge (dup a1) a21)
)]
;; when an address lifetime changes, "ip address change"
;; will update that so it need not (should not) be deleted
(expect= del [])))
(fn changed-prefix-is-deleted []
(let [del
(subject.deletions a1 a156)]
;; when an address prefix changes, "ip address change"
;; ignores that cjhange, so we have to remove the
;; address before reinstating it
(expect= del [(. a1 "2001-ab-cd-ef")])))
(first-address)
(second-address)
(less-address)
(old-address-is-deleted)
(changed-lifetime-not-deleted)
(changed-prefix-is-deleted)
(let [cmds []]
(subject.update-addresses
"ppp0" a1 (merge (dup a1) a2)
(fn [a] (table.insert cmds a)))
(expect=
(doto cmds table.sort)
[
;; order of changes is unimportant
"ip address change 2001:0:1:2:3/64 dev ppp0 valid_lft 7200 preferred_lft 3600"
"ip address change 2001:ab:cd:ef/64 dev ppp0 valid_lft 7200 preferred_lft 3600"
]))
(let [cmds []]
(subject.update-addresses
"ppp0" (merge (dup a1) a2) a1
(fn [a] (table.insert cmds a)))
(expect=
cmds
[
;; deletes are executed before changes
"ip address del 2001:0:1:2:3/64 dev ppp0"
"ip address change 2001:ab:cd:ef/64 dev ppp0 valid_lft 7200 preferred_lft 3600"
]))
(print "OK")

View File

@ -1,35 +1,32 @@
(local { : system } (require :anoia))
(local svc (require :anoia.svc))
;; acquire-delegated-prefix has very similar code: we'd like to move
;; this to anoia.svc when we see what the general form would look like
(fn changes [old-addresses new-addresses]
(let [added {}
deleted {}]
(each [n address (pairs new-addresses)]
(if (not (. old-addresses n))
(table.insert added address)))
(fn deletions [old-addresses new-addresses]
(let [deleted {}]
(each [n address (pairs old-addresses)]
(if (not (. new-addresses n))
(table.insert deleted address)))
(values added deleted)))
(let [now (. new-addresses n)]
(if (or (not now) (not (= now.len address.len)))
(table.insert deleted address))))
deleted))
(fn update-addresses [wan-device addresses new-addresses]
(let [(added deleted) (changes addresses new-addresses)]
(each [_ p (ipairs added)]
(system
(.. "ip address add " p.address "/" p.len " dev " wan-device)))
(each [_ p (ipairs deleted)]
(system
(.. "ip address del " p.address "/" p.len " dev " wan-device)))
new-addresses))
(fn update-addresses [wan-device addresses new-addresses exec]
(each [_ p (ipairs (deletions addresses new-addresses))]
(exec
(.. "ip address del " p.address "/" p.len " dev " wan-device)))
(each [_ p (pairs new-addresses)]
(exec
(.. "ip address change " p.address "/" p.len
" dev " wan-device
" valid_lft " p.valid
" preferred_lft " p.preferred
)))
new-addresses)
(fn run []
(let [[state-directory wan-device] arg
dir (svc.open state-directory)]
(accumulate [addresses []
v (dir:events)]
(update-addresses wan-device addresses (v:output "address")))))
(update-addresses wan-device addresses (v:output "address") system))))
{ : update-addresses : changes : run }
{ : update-addresses : deletions : run }

View File

@ -11,6 +11,6 @@ let
script = callPackage ./acquire-wan-address.nix { };
in longrun {
inherit name;
run = "${script} /run/service-state/${client.name} $(output ${interface} ifname)";
run = "${script} $SERVICE_OUTPUTS/${client.name} $(output ${interface} ifname)";
dependencies = [ client interface ];
}

View File

@ -13,7 +13,7 @@ in longrun {
inherit name;
notification-fd = 10;
run = ''
export SERVICE_STATE=/run/service-state/${name}
export SERVICE_STATE=$SERVICE_OUTPUTS/${name}
${odhcp6c}/bin/odhcp6c -s ${odhcp-script} -e -v -p /run/${name}.pid -P0 $(output ${interface} ifname)
)
'';

View File

@ -11,6 +11,6 @@ let
script = callPackage ./acquire-delegated-prefix.nix { };
in longrun {
inherit name;
run = "${script} /run/service-state/${client.name} $(output ${interface} ifname)";
run = "${script} $SERVICE_OUTPUTS/${client.name} $(output ${interface} ifname)";
dependencies = [ client interface ];
}

View File

@ -41,10 +41,11 @@ longrun {
--no-hosts \
--log-dhcp \
--enable-ra \
--log-debug \
--log-queries \
--log-facility=- \
--dhcp-leasefile=/run/${name}.leases \
--dhcp-leasefile=$(mkstate ${name})/leases \
--pid-file=/run/${name}.pid
'';
# --log-debug \
# --log-queries \
}

View File

@ -10,34 +10,41 @@ let
inherit (pkgs) liminix;
inherit (pkgs.liminix.services) oneshot;
kconf = isModule :
# setting isModule false is utterly untested and mostly
# unimplemented: I say this to preempt any "how on earth is this
# even supposed to work?" questions
let yes = if isModule then "m" else "y";
in {
NFT_FIB_IPV4 = yes;
NFT_FIB_IPV6 = yes;
NF_TABLES = yes;
NF_CT_PROTO_DCCP = "y";
NF_CT_PROTO_SCTP = "y";
NF_CT_PROTO_UDPLITE = "y";
# NF_CONNTRACK_FTP = yes;
NFT_CT = yes;
};
kmodules = pkgs.kernel-modules.override {
kernelSrc = config.system.outputs.kernel.src;
modulesupport = config.system.outputs.kernel.modulesupport;
kmodules = pkgs.kmodloader.override {
inherit (config.system.outputs) kernel;
targets = [
"nft_fib_ipv4"
"nft_fib_ipv6"
"nf_log_syslog"
"ip6_tables"
"ip_tables"
"iptable_nat"
"nf_conntrack"
"nf_defrag_ipv4"
"nf_defrag_ipv6"
"nf_log_syslog"
"nf_nat"
"nf_reject_ipv4"
"nf_reject_ipv6"
"nf_tables"
"nft_chain_nat"
"nft_ct"
"nft_fib"
"nft_fib_ipv4"
"nft_fib_ipv6"
"nft_log"
"nft_masq"
"nft_nat"
"nft_reject"
"nft_reject_inet"
"nft_reject_ipv4"
"nft_reject_ipv6"
"x_tables"
"xt_MASQUERADE"
"xt_nat"
"xt_tcpudp"
];
kconfig = kconf true;
};
loadModules = oneshot {
name = "firewall-modules";
up = "sh ${kmodules}/load.sh";
down = "sh ${kmodules}/unload.sh";
};
in
{
@ -55,38 +62,40 @@ in
};
};
in svc // {
build = args : (svc.build args) // {
dependencies = [ loadModules ] ++ (svc.dependencies or []);
};
build = args :
let args' = args // {
dependencies = (args.dependencies or []) ++ [kmodules];
};
in svc.build args' ;
};
# For historical reasons the kernel config is split between
# monolithic options and modules. TODO: go through this list
# and see what can be moved into the "kconf" definiton above
kernel.config = {
NETFILTER_XT_MATCH_CONNTRACK = "y";
IP6_NF_IPTABLES= "y";
IP_NF_IPTABLES= "y";
IP_NF_NAT = "y";
IP_NF_TARGET_MASQUERADE = "y";
NETFILTER = "y";
NETFILTER_ADVANCED = "y";
NETFILTER_XTABLES = "y";
NETFILTER_NETLINK = "m";
NF_CONNTRACK = "m";
NFT_COMPAT = "y";
NFT_CT = "y";
NFT_LOG = "y";
NFT_MASQ = "y";
NFT_NAT = "y";
NFT_REJECT = "y";
NFT_REJECT_INET = "y";
IP6_NF_IPTABLES= "m";
IP_NF_IPTABLES = "m";
IP_NF_NAT = "m";
IP_NF_TARGET_MASQUERADE = "m";
NF_CONNTRACK = "y";
NF_NAT = "y";
NF_NAT_MASQUERADE = "y";
NF_TABLES= "y";
NFT_CT = "m";
NFT_FIB_IPV4 = "m";
NFT_FIB_IPV6 = "m";
NFT_LOG = "m";
NFT_MASQ = "m";
NFT_NAT = "m";
NFT_REJECT = "m";
NFT_REJECT_INET = "m";
NF_CT_PROTO_DCCP = "y";
NF_CT_PROTO_SCTP = "y";
NF_CT_PROTO_UDPLITE = "y";
NF_LOG_SYSLOG = "m";
NF_NAT = "m";
NF_NAT_MASQUERADE = "y";
NF_TABLES = "m";
NF_TABLES_INET = "y";
NF_TABLES_IPV4 = "y";
NF_TABLES_IPV6 = "y";

View File

@ -16,8 +16,14 @@ in {
hardware = {
dts = {
src = mkOption {
type = types.path;
description = "Path to the device tree source (usually from OpenWrt)";
type = types.nullOr types.path;
description = ''
If the device requires an external device tree to be loaded
alongside the kernel, this is the path to the device tree source
(we usually get these from OpenWrt). This value may be null if the
platform creates the device tree - currently this is the case
only for QEMU.
'';
};
includes = mkOption {
default = [];
@ -26,9 +32,15 @@ in {
};
};
defaultOutput = mkOption {
description = "\"Default\" output: what gets built for this device when outputs.default is requested. Typically this is \"flashimage\" or \"vmroot\"";
description = "\"Default\" output: what gets built for this device when outputs.default is requested. Typically this is \"mtdimage\" or \"vmroot\"";
type = types.nonEmptyStr;
};
ram = {
startAddress = mkOption {
type = types.int;
};
};
flash = {
# start address and size of whichever partition (often
# called "firmware") we're going to overwrite with our
@ -42,19 +54,19 @@ in {
kernel uimage and root fs. Usually not the entire flash, as
we don't want to clobber the bootloader, calibration data etc
'';
type = types.str;
type = types.ints.unsigned;
};
size = mkOption {
type = types.str;
type = types.ints.unsigned;
description = "Size in bytes of the firmware partition";
};
eraseBlockSize = mkOption {
description = "Flash erase block size in bytes";
type = types.str;
type = types.ints.unsigned;
};
};
loadAddress = mkOption { default = null; };
entryPoint = mkOption { };
loadAddress = mkOption { type = types.ints.unsigned; default = null; };
entryPoint = mkOption { type = types.ints.unsigned; };
radios = mkOption {
description = ''
Kernel modules (from mac80211 package) required for the
@ -64,7 +76,11 @@ in {
default = [];
example = ["ath9k" "ath10k"];
};
rootDevice = mkOption { };
rootDevice = mkOption {
description = "Full path to preferred root device";
type = types.str;
example = "/dev/mtdblock3";
};
networkInterfaces = mkOption {
type = types.attrsOf types.anything;
};

View File

@ -1,54 +0,0 @@
{
config
, pkgs
, lib
, ...
}:
let
inherit (lib) mkIf mkOption types;
in
{
imports = [
./initramfs.nix
];
options.system.outputs = {
systemConfiguration = mkOption {
type = types.package;
description = ''
pkgs.systemconfig for the configured filesystem,
contains 'activate' and 'init' commands
'';
internal = true;
};
};
config = mkIf (config.rootfsType == "jffs2") {
kernel.config = {
JFFS2_FS = "y";
JFFS2_LZO = "y";
JFFS2_RTIME = "y";
JFFS2_COMPRESSION_OPTIONS = "y";
JFFS2_ZLIB = "y";
JFFS2_CMODE_SIZE = "y";
};
boot.initramfs.enable = true;
system.outputs = rec {
systemConfiguration =
pkgs.systemconfig config.filesystem.contents;
rootfs =
let
inherit (pkgs.pkgsBuildBuild) runCommand mtdutils;
endian = if pkgs.stdenv.isBigEndian
then "--big-endian" else "--little-endian";
in runCommand "make-jffs2" {
depsBuildBuild = [ mtdutils ];
} ''
mkdir -p $TMPDIR/empty/nix/store/ $TMPDIR/empty/secrets
cp ${systemConfiguration}/bin/activate $TMPDIR/empty/activate
ln -s ${pkgs.s6-init-bin}/bin/init $TMPDIR/empty/init
grafts=$(sed < ${systemConfiguration}/etc/nix-store-paths 's/^\(.*\)$/--graft \1:\1/g')
mkfs.jffs2 --compression-mode=size ${endian} -e ${config.hardware.flash.eraseBlockSize} --enable-compressor=lzo --pad --root $TMPDIR/empty --output $out $grafts --squash --faketime
'';
};
};
}

View File

@ -9,13 +9,25 @@ let
inherit (pkgs.pseudofile) dir symlink;
inherit (pkgs.liminix.networking) address interface;
inherit (pkgs.liminix.services) bundle;
inherit (pkgs) liminix;
type_service = pkgs.liminix.lib.types.service;
mergeConditionals = conf : conditions :
# for each key in conditions, if it is present in conf
# then merge the associated value into conf
lib.foldlAttrs
(acc: name: value:
if (conf ? ${name}) && (conf.${name} != "n")
then acc // value
else acc)
conf
conditions;
in {
options = {
kernel = {
src = mkOption { type = types.package; } ;
src = mkOption { type = types.path; } ;
version = mkOption { type = types.str; default = "5.15.137";} ;
modular = mkOption {
type = types.bool;
default = true;
@ -41,11 +53,44 @@ in {
};
'';
};
conditionalConfig = mkOption {
description = ''
Kernel config options that should only be applied when
some other option is present.
'';
type = types.attrsOf (types.attrsOf types.nonEmptyStr);
default = {};
example = {
USB = {
USB_XHCI_MVEBU = "y";
USB_XHCI_HCD = "y";
};
};
};
makeTargets = mkOption {
type = types.listOf types.str;
};
};
};
config = {
system.outputs =
let
mergedConfig = mergeConditionals
config.kernel.config
config.kernel.conditionalConfig;
k = liminix.builders.kernel.override {
config = mergedConfig;
inherit (config.kernel) version src extraPatchPhase;
targets = config.kernel.makeTargets;
};
in {
kernel = k.vmlinux;
zimage = k.zImage;
};
kernel = rec {
modular = true; # disabling this is not yet supported
makeTargets = ["vmlinux"];
config = {
IKCONFIG = "y";
IKCONFIG_PROC = "y";
@ -64,6 +109,8 @@ in {
PACKET = "y"; # for ppp, tcpdump ...
SYSVIPC= "y";
NETDEVICES = "y"; # even PPP needs this
# disabling this option causes the kernel to use an "empty"
# initramfs instead: it has a /dev/console node and not much
# else. Note that pid 1 is started *before* the root

View File

@ -68,7 +68,21 @@ in {
ifname = mkOption {
type = types.str;
example = "eth0";
description = ''
Device name as used by the kernel (as seen in "ip link"
or "ifconfig" output). If devpath is also specified, the
device will be renamed to the name provided.
'';
};
devpath = mkOption {
type = types.nullOr types.str;
default = null;
example = "/devices/platform/soc/soc:internal-regs/f1070000.ethernet";
description = ''
Path to the sysfs node of the device. If you provide this
and the ifname option, the device will be renamed to the
name given by ifname.
''; };
# other "ip link add" options could go here as well
mtu = mkOption {
type = types.nullOr types.int;

View File

@ -4,13 +4,27 @@
, serviceFns
, lib
}:
{ifname, mtu} :
{
ifname
, devpath ? null
, mtu} :
# if devpath is supplied, we rename the interface at that
# path to have the specified name.
let
inherit (liminix.services) longrun oneshot;
inherit (lib) concatStringsSep;
name = "${ifname}.link";
up = liminix.networking.ifup name ifname;
rename = if devpath != null
then ''
oldname=$(cd /sys${devpath} && cd net/ && echo *)
ip link set ''${oldname} name ${ifname}
''
else "";
in oneshot {
inherit name up;
inherit name;
up = ''
${rename}
${liminix.networking.ifup name ifname}
'';
down = "ip link set down dev ${ifname}";
}

View File

@ -7,103 +7,135 @@
let
inherit (lib) mkOption types concatStringsSep;
inherit (pkgs) liminix callPackage writeText;
arch = let s = pkgs.stdenv; in
if s.isAarch64
then "aarch64"
else if s.isMips
then "mips"
else throw "can't determine arch";
o = config.system.outputs;
in
{
imports = [
./squashfs.nix
./outputs/vmroot.nix
./outputs/extlinux.nix
];
options = {
system.outputs = {
# the convention here is to mark an output as "internal" if
# it's not a complete system (kernel plus userland, or installer)
# but only part of one.
kernel = mkOption {
type = types.package;
internal = true;
description = ''
kernel
******
Kernel vmlinux file (usually ELF)
'';
};
zimage = mkOption {
type = types.package;
internal = true;
description = ''
zimage
******
Kernel in compressed self-extracting package
'';
};
dtb = mkOption {
type = types.package;
internal = true;
description = ''
dtb
***
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
'';
};
vmroot = mkOption {
tplink-safeloader = mkOption {
type = types.package;
};
u-boot = mkOption {
type = types.package;
description = ''
Directory containing separate kernel and rootfs image for
use with qemu (see run-liminix-vm)
'';
};
manifest = mkOption {
type = types.package;
internal = true;
description = ''
Debugging aid. JSON rendition of config.filesystem, on
which can run "nix-store -q --tree" on it and find
out what's in the image, which is nice if it's unexpectedly huge
'';
};
rootdir = mkOption {
type = types.package;
internal = true;
description = ''
directory of files to package into root filesystem
'';
};
bootablerootdir = mkOption {
type = types.package;
internal = true;
description = ''
directory of files to package into root filesystem, including
a kernel and appropriate associated gubbins for the
selected bootloader
'';
};
rootfs = mkOption {
type = types.package;
internal = true;
description = ''
root filesystem (squashfs or jffs2) image
'';
internal = true;
};
};
};
config = {
system.outputs = rec {
# tftpd = pkgs.buildPackages.tufted;
kernel = liminix.builders.kernel.override {
inherit (config.kernel) config src extraPatchPhase;
};
dtb = liminix.builders.dtb {
inherit (config.boot) commandLine;
dts = config.hardware.dts.src;
includes = config.hardware.dts.includes ++ [
"${kernel.headers}/include"
"${o.kernel.headers}/include"
];
};
uimage = liminix.builders.uimage {
commandLine = concatStringsSep " " config.boot.commandLine;
inherit (config.hardware) loadAddress entryPoint;
inherit kernel;
inherit dtb;
inherit (config.boot) imageFormat;
inherit (o) kernel dtb;
};
# could use trivial-builders.linkFarmFromDrvs here?
vmroot =
rootdir =
let
cmdline = builtins.toJSON (concatStringsSep " " config.boot.commandLine);
makeBootableImage = pkgs.runCommandCC "objcopy" {}
(if pkgs.stdenv.isAarch64
then "${pkgs.stdenv.cc.targetPrefix}objcopy -O binary -S ${kernel} $out"
else "cp ${kernel} $out");
in pkgs.runCommandCC "vmroot" {} ''
mkdir $out
cd $out
ln -s ${config.system.outputs.rootfs} rootfs
ln -s ${kernel} vmlinux
ln -s ${manifest} manifest
ln -s ${kernel.headers} build
echo ${cmdline} > commandline
cat > run.sh << EOF
#!${pkgs.runtimeShell}
CMDLINE=${cmdline} ${pkgs.pkgsBuildBuild.run-liminix-vm}/bin/run-liminix-vm --arch ${arch} \$* ${makeBootableImage} ${config.system.outputs.rootfs}
EOF
chmod +x run.sh
'';
inherit (pkgs.pkgsBuildBuild) runCommand;
in runCommand "mktree" { } ''
mkdir -p $out/nix/store/ $out/secrets $out/boot
cp ${o.systemConfiguration}/bin/activate $out/activate
ln -s ${pkgs.s6-init-bin}/bin/init $out/init
mkdir -p $out/nix/store
for path in $(cat ${o.systemConfiguration}/etc/nix-store-paths) ; do
(cd $out && cp -a $path .$path)
done
'';
bootablerootdir =
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)"
else ""
}
'';
manifest = writeText "manifest.json" (builtins.toJSON config.filesystem.contents);
};
};

37
modules/outputs/btrfs.nix Normal file
View File

@ -0,0 +1,37 @@
{
config
, pkgs
, lib
, ...
}:
let
inherit (lib) mkIf mkOption types;
o = config.system.outputs;
in
{
imports = [
./initramfs.nix
];
config = mkIf (config.rootfsType == "btrfs") {
kernel.config = {
BTRFS_FS = "y";
};
boot.initramfs.enable = true;
system.outputs = {
rootfs =
let
inherit (pkgs.pkgsBuildBuild) runCommand e2fsprogs;
in runCommand "mkfs.btrfs" {
depsBuildBuild = [ e2fsprogs ];
} ''
tree=${o.bootablerootdir}
size=$(du -s --apparent-size --block-size 1024 $tree |cut -f1)
# add 25% for filesystem overhead
size=$(( 5 * $size / 4))
dd if=/dev/zero of=$out bs=1024 count=$size
echo "not implemented" ; exit 1
# mke2fs -t ext4 -j -d $tree $out
'';
};
};
}

View File

@ -0,0 +1,38 @@
{
config
, pkgs
, lib
, ...
}:
let
inherit (lib) mkIf mkOption types;
o = config.system.outputs;
in
{
imports = [
./initramfs.nix
];
config = mkIf (config.rootfsType == "ext4") {
kernel.config = {
EXT4_FS = "y";
EXT4_USE_FOR_EXT2 = "y";
FS_ENCRYPTION = "y";
};
boot.initramfs.enable = true;
system.outputs = {
rootfs =
let
inherit (pkgs.pkgsBuildBuild) runCommand e2fsprogs;
in runCommand "mkfs.ext4" {
depsBuildBuild = [ e2fsprogs ];
} ''
tree=${o.bootablerootdir}
size=$(du -s --apparent-size --block-size 1024 $tree |cut -f1)
# add 25% for filesystem overhead
size=$(( 5 * $size / 4))
dd if=/dev/zero of=$out bs=1024 count=$size
mke2fs -t ext4 -j -d $tree $out
'';
};
};
}

View File

@ -0,0 +1,43 @@
{
config
, pkgs
, lib
, ...
}:
let
inherit (lib) mkIf mkEnableOption mkOption types concatStringsSep;
inherit (pkgs.pseudofile) dir symlink;
cfg = config.boot.loader.extlinux;
o = config.system.outputs;
cmdline = concatStringsSep " " config.boot.commandLine;
wantsDtb = config.hardware.dts ? src && config.hardware.dts.src != null;
in {
options.system.outputs.extlinux = mkOption {
type = types.package;
# description = "";
};
options.boot.loader.extlinux.enable = mkEnableOption "extlinux";
config = mkIf cfg.enable {
system.outputs.extlinux = pkgs.runCommand "extlinux" {} ''
mkdir $out
cd $out
${if wantsDtb then "cp ${o.dtb} dtb" else "true"}
cp ${o.initramfs} initramfs
cp ${o.zimage} kernel
mkdir extlinux
cat > extlinux/extlinux.conf << _EOF
menu title Liminix
timeout 40
label Liminix
kernel /boot/kernel
# initrd /boot/initramfs
append ${cmdline}
${if wantsDtb then "fdt /boot/dtb" else ""}
_EOF
'';
filesystem = dir {
boot = symlink config.system.outputs.extlinux;
};
};
}

View File

@ -13,13 +13,23 @@ in
boot.initramfs = {
enable = mkEnableOption "initramfs";
};
system.outputs.initramfs = mkOption {
type = types.package;
internal = true;
description = ''
Initramfs image capable of mounting the jffs2 root
filesystem
'';
system.outputs = {
initramfs = mkOption {
type = types.package;
internal = true;
description = ''
Initramfs image capable of mounting the real root
filesystem
'';
};
systemConfiguration = mkOption {
type = types.package;
description = ''
pkgs.systemconfig for the configured filesystem,
contains 'activate' and 'init' commands
'';
internal = true;
};
};
};
config = mkIf config.boot.initramfs.enable {
@ -37,18 +47,14 @@ in
dir /proc 0755 0 0
dir /dev 0755 0 0
nod /dev/console 0600 0 0 c 5 1
nod /dev/mtdblock0 0600 0 0 b 31 0
nod /dev/mtdblock1 0600 0 0 b 31 1
nod /dev/mtdblock2 0600 0 0 b 31 2
nod /dev/mtdblock3 0600 0 0 b 31 3
nod /dev/mtdblock4 0600 0 0 b 31 4
nod /dev/mtdblock5 0600 0 0 b 31 5
dir /target 0755 0 0
dir /target/persist 0755 0 0
dir /target/nix 0755 0 0
file /init ${pkgs.preinit}/bin/preinit 0755 0 0
SPECIALS
'';
systemConfiguration =
pkgs.systemconfig config.filesystem.contents;
};
};
}

40
modules/outputs/jffs2.nix Normal file
View File

@ -0,0 +1,40 @@
{
config
, pkgs
, lib
, ...
}:
let
inherit (lib) mkIf mkOption types;
o = config.system.outputs;
in
{
imports = [
./initramfs.nix
];
config = mkIf (config.rootfsType == "jffs2") {
kernel.config = {
JFFS2_FS = "y";
JFFS2_LZO = "y";
JFFS2_RTIME = "y";
JFFS2_COMPRESSION_OPTIONS = "y";
JFFS2_ZLIB = "y";
JFFS2_CMODE_SIZE = "y";
};
boot.initramfs.enable = true;
system.outputs = {
rootfs =
let
inherit (pkgs.pkgsBuildBuild) runCommand mtdutils;
endian = if pkgs.stdenv.isBigEndian
then "--big-endian" else "--little-endian";
in runCommand "make-jffs2" {
depsBuildBuild = [ mtdutils ];
} ''
tree=${o.bootablerootdir}
(cd $tree && mkfs.jffs2 --compression-mode=size ${endian} -e ${toString config.hardware.flash.eraseBlockSize} --enable-compressor=lzo --pad --root . --output $out --squash --faketime )
'';
};
};
}

View File

@ -7,7 +7,7 @@
let
inherit (lib) mkOption mkForce types concatStringsSep;
in {
imports = [ ./ramdisk.nix ];
imports = [ ../ramdisk.nix ];
options.system.outputs = {
kexecboot = mkOption {
type = types.package;

View File

@ -0,0 +1,51 @@
{
config
, pkgs
, lib
, ...
}:
let
inherit (lib) mkOption types concatStringsSep;
o = config.system.outputs;
phram_address = lib.toHexString (config.hardware.ram.startAddress + 256 * 1024 * 1024);
in {
options.system.outputs = {
mbrimage = mkOption {
type = types.package;
description = ''
mbrimage
*********
This creates a disk image file with a partition table containing
the contents of ``outputs.rootfs`` as its only partition.
'';
};
vmdisk = mkOption { type = types.package; };
};
config = {
system.outputs = {
mbrimage =
let
o = config.system.outputs;
in pkgs.runCommand "mbrimage" {
depsBuildBuild = [ pkgs.pkgsBuildBuild.util-linux ];
} ''
# leave 4 sectors at start for partition table
# and alignment to 2048 bytes (does that help?)
dd if=${o.rootfs} of=$out bs=512 seek=4 conv=sync
echo '4,-,L,*' | sfdisk $out
'';
vmdisk = pkgs.runCommand "vmdisk" {} ''
mkdir $out
cd $out
ln -s ${o.mbrimage} ./mbrimage
cat > run.sh <<EOF
#!${pkgs.runtimeShell}
${pkgs.pkgsBuildBuild.run-liminix-vm}/bin/run-liminix-vm --arch ${pkgs.stdenv.hostPlatform.qemuArch} --u-boot ${o.u-boot}/u-boot.bin --phram-address 0x${phram_address} --disk-image ${o.mbrimage} \$* /dev/null /dev/null
EOF
chmod +x run.sh
'';
};
};
}

View File

@ -11,7 +11,7 @@ in {
options.system.outputs = {
firmware = mkOption {
type = types.package;
internal = true; # component of flashimage
internal = true; # component of mtdimage
description = ''
Binary image (combining kernel, FDT, rootfs, initramfs
if needed, etc) for the target device.
@ -19,17 +19,40 @@ in {
};
flash-scr = mkOption {
type = types.package;
internal = true; # component of flashimage
internal = true; # component of mtdimage
description = ''
Copy-pastable U-Boot commands to TFTP download the
image and write it to flash
'';
};
flashimage = mkOption {
mtdimage = mkOption {
type = types.package;
description = ''
Flashable image for the target device, and the script to
install it
mtdimage
**********
This creates an image called :file:`firmware.bin` suitable for
squashfs or jffs2 systems. It can be flashed from U-Boot (if
you have a serial console connection), or on some devices from
the vendor firmware, or from a Liminix kexecboot system.
If you are flashing from U-Boot, the file
:file:`flash.scr` is a sequence of commands
which you can paste at the U-Boot prompt to
to transfer the firmware file from a TFTP server and
write it to flash. **Please read the script before
running it: flash operations carry the potential to
brick your device**
.. NOTE::
TTL serial connections typically have no form of flow
control and so don't always like having massive chunks of
text pasted into them - and U-Boot may drop characters
while it's busy. So don't necessarily expect to copy-paste
the whole of :file:`flash.scr` into a terminal emulator and
have it work just like that. You may need to paste each
line one at a time, or even retype it.
'';
};
};
@ -52,15 +75,15 @@ in {
firmware =
let
o = config.system.outputs;
bs = config.hardware.flash.eraseBlockSize;
bs = toString config.hardware.flash.eraseBlockSize;
in pkgs.runCommand "firmware" {} ''
dd if=${o.uimage} of=$out bs=${bs} conv=sync
dd if=${o.rootfs} of=$out bs=${bs} conv=sync,nocreat,notrunc oflag=append
'';
flashimage =
mtdimage =
let o = config.system.outputs; in
# could use trivial-builders.linkFarmFromDrvs here?
pkgs.runCommand "flashimage" {} ''
pkgs.runCommand "mtdimage" {} ''
mkdir $out
cd $out
ln -s ${o.firmware} firmware.bin
@ -83,9 +106,9 @@ in {
cat > $out << EOF
setenv serverip ${tftp.serverip}
setenv ipaddr ${tftp.ipaddr}
tftp 0x$(printf %x ${tftp.loadAddress}) result/firmware.bin
erase 0x$(printf %x ${flash.address}) +${flash.size}
cp.b 0x$(printf %x ${tftp.loadAddress}) 0x$(printf %x ${flash.address}) \''${filesize}
tftp 0x${toHexString tftp.loadAddress} result/firmware.bin
erase 0x${toHexString flash.address} +0x${toHexString flash.size}
cp.b 0x${toHexString tftp.loadAddress} 0x${toHexString flash.address} \''${filesize}
echo command line was ${builtins.toJSON (concatStringsSep " " config.boot.commandLine)}
EOF
'';

View File

@ -0,0 +1,163 @@
{
config
, pkgs
, lib
, ...
}:
let
inherit (lib) mkOption types concatStringsSep;
cfg = config.boot.tftp;
hw = config.hardware;
arch = pkgs.stdenv.hostPlatform.linuxArch;
in {
imports = [ ../ramdisk.nix ];
options.boot.tftp = {
freeSpaceBytes = mkOption {
type = types.int;
default = 0;
};
kernelFormat = mkOption {
type = types.enum [ "zimage" "uimage" ];
default = "uimage";
};
compressRoot = mkOption {
type = types.bool;
default = false;
};
appendDTB = mkOption {
type = types.bool;
default = false;
};
};
options.system.outputs = {
tftpboot = mkOption {
type = types.package;
description = ''
tftpboot
********
This output is intended for developing on a new device.
It assumes you have a serial connection and a
network connection to the device and that your
build machine is running a TFTP server.
The output is a directory containing kernel and
root filesystem image, and a script :file:`boot.scr` of U-Boot
commands that will load the images into memory and
run them directly,
instead of first writing them to flash. This saves
time and erase cycles.
It uses the Linux `phram <https://github.com/torvalds/linux/blob/master/drivers/mtd/devices/phram.c>`_ driver to emulate a flash device using a segment of physical RAM.
'';
};
};
config = {
boot.ramdisk.enable = true;
system.outputs = rec {
tftpboot =
let
inherit (pkgs.lib.trivial) toHexString;
o = config.system.outputs;
image = let choices = {
uimage = o.uimage;
zimage = o.zimage;
}; in choices.${cfg.kernelFormat};
bootCommand = let choices = {
uimage = "bootm";
zimage = "bootz";
}; in choices.${cfg.kernelFormat};
cmdline = concatStringsSep " " config.boot.commandLine;
objcopy = "${pkgs.stdenv.cc.bintools.targetPrefix}objcopy";
stripAndZip = ''
${objcopy} -O binary -R .reginfo -R .notes -R .note -R .comment -R .mdebug -R .note.gnu.build-id -S vmlinux.elf vmlinux.bin
rm -f vmlinux.bin.lzma ; lzma -k -z vmlinux.bin
'';
in
pkgs.runCommand "tftpboot" { nativeBuildInputs = with pkgs.pkgsBuildBuild; [ lzma dtc pkgs.stdenv.cc ubootTools ]; } ''
mkdir $out
cd $out
binsize() { local s=$(stat -L -c %s $1); echo $(($s + 0x1000 &(~0xfff))); }
binsize64k() { local s=$(stat -L -c %s $1); echo $(($s + 0x10000 &(~0xffff))); }
hex() { printf "0x%x" $1; }
rootfsStart=${toString cfg.loadAddress}
rootfsSize=$(binsize64k ${o.rootfs} )
rootfsSize=$(($rootfsSize + ${toString cfg.freeSpaceBytes} ))
ln -s ${o.manifest} manifest
ln -s ${o.kernel} vmlinux # handy for gdb
# if we are transferring kernel and dtb separately, the
# dtb has to precede the kernel in ram, because zimage
# decompression code will assume that any memory after the
# end of the kernel is free
dtbStart=$(($rootfsStart + $rootfsSize))
${if cfg.compressRoot
then ''
lzma -z9cv ${o.rootfs} > rootfs.lz
rootfsLzStart=$dtbStart
rootfsLzSize=$(binsize rootfs.lz)
dtbStart=$(($dtbStart + $rootfsLzSize))
''
else ''
ln -s ${o.rootfs} rootfs
''
}
cat ${o.dtb} > dtb
address_cells=$(fdtget dtb / '#address-cells')
size_cells=$(fdtget dtb / '#size-cells')
if [ $address_cells -gt 1 ]; then ac_prefix=0; fi
if [ $size_cells -gt 1 ]; then sz_prefix=0; fi
fdtput -p dtb /reserved-memory '#address-cells' $address_cells
fdtput -p dtb /reserved-memory '#size-cells' $size_cells
fdtput -p dtb /reserved-memory ranges
node=$(printf "phram-rootfs@%x" $rootfsStart)
fdtput -p -t s dtb /reserved-memory/$node compatible phram
fdtput -p -t lx dtb /reserved-memory/$node reg $ac_prefix $(hex $rootfsStart) $sz_prefix $(hex $rootfsSize)
cmd="liminix ${cmdline} mtdparts=phram0:''${rootfsSize}(rootfs) phram.phram=phram0,''${rootfsStart},''${rootfsSize},${toString config.hardware.flash.eraseBlockSize} root=/dev/mtdblock0";
fdtput -t s dtb /chosen bootargs "$cmd"
dtbSize=$(binsize ./dtb )
${if cfg.appendDTB then ''
imageStart=$dtbStart
# re-package image with updated dtb
cat ${o.kernel} > vmlinux.elf
${objcopy} --update-section .appended_dtb=dtb vmlinux.elf
${stripAndZip}
mkimage -A ${arch} -O linux -T kernel -C lzma -a $(hex ${toString hw.loadAddress}) -e $(hex ${toString hw.entryPoint}) -n '${lib.toUpper arch} Liminix Linux tftpboot' -d vmlinux.bin.lzma image
# dtc -I dtb -O dts -o /dev/stdout dtb | grep -A10 chosen ; exit 1
tftpcmd="tftpboot $(hex $imageStart) result/image "
bootcmd="bootm $(hex $imageStart)"
'' else ''
imageStart=$(($dtbStart + $dtbSize))
tftpcmd="tftpboot $(hex $imageStart) result/image; tftpboot $(hex $dtbStart) result/dtb "
ln -s ${image} image
bootcmd="${bootCommand} $(hex $imageStart) - $(hex $dtbStart)"
''}
cat > boot.scr << EOF
setenv serverip ${cfg.serverip}
setenv ipaddr ${cfg.ipaddr}
${
if cfg.compressRoot
then "tftpboot $(hex $rootfsLzStart) result/rootfs.lz"
else "tftpboot $(hex $rootfsStart) result/rootfs"
}; $tftpcmd
${if cfg.compressRoot
then "lzmadec $(hex $rootfsLzStart) $(hex $rootfsStart); "
else ""
} $bootcmd
EOF
'';
};
};
}

View File

@ -0,0 +1,61 @@
{
config
, pkgs
, lib
, ...
}:
let
inherit (lib) mkOption types concatStringsSep;
o = config.system.outputs;
cfg = config.tplink-safeloader;
in {
options.tplink-safeloader = {
board = mkOption {
type = types.str;
};
};
options.system.outputs = {
tplink-safeloader = mkOption {
type = types.package;
description = ''
tplink-safeloader
*****************
For creating 'safeloader' images for tp-link devices.
These can be flashed to the device using the firmware update feature
in the TP-link web UI or the OEM bootloader recovery: Use something
sharp to hold the 'reset' button while turning on the router until
only the orange LED remains lit. The router will assume IP address
192.168.0.1 and expect you to take 192.168.0.5 on one of the LAN ports.
On NixOS, use something like::
networking.interfaces.enp0s20f0u1c2 = {
ipv4.addresses = [ {
address = "192.168.0.5";
prefixLength = 24;
} ];
};
networking.networkmanager = {
unmanaged = [ "enp0s20f0u1c2" ];
};
This connection is rather somewhat temperamental, it may take a couple
of attempts, possibly re-attaching the USB dongle and running
``systemctl restart network-start.service``. The web interface does not
give accurate feedback (the progress bar is a lie), so you may want
to upload the firmware using ``curl -F firmware=@result http://192.168.0.1/f2.htm``.
After this shows a 'success' JSON, the image still needs to be
transferred from memory to flash, so be patient.
'';
};
};
config = {
system.outputs = rec {
tplink-safeloader =
pkgs.runCommand "tplink" { nativeBuildInputs = with pkgs.pkgsBuildBuild; [ firmware-utils ]; } ''
tplink-safeloader -B "${cfg.board}" -k "${o.uimage}" -r "${o.rootfs}" -o $out
'';
};
};
}

42
modules/outputs/ubifs.nix Normal file
View File

@ -0,0 +1,42 @@
{
config
, pkgs
, lib
, ...
}:
let
inherit (lib) mkIf mkOption types;
o = config.system.outputs;
in
{
imports = [
./initramfs.nix
];
options.hardware.ubi = {
minIOSize = mkOption { type = types.str; };
eraseBlockSize = mkOption { type = types.str; }; # LEB
maxLEBcount = mkOption { type = types.str; }; # LEB
};
config = mkIf (config.rootfsType == "ubifs") {
kernel.config = {
MTD_UBI="y";
UBIFS_FS = "y";
UBIFS_FS_SECURITY = "n";
};
boot.initramfs.enable = true;
system.outputs = {
rootfs =
let
inherit (pkgs.pkgsBuildBuild) runCommand mtdutils;
cfg = config.hardware.ubi;
in runCommand "mkfs.ubifs" {
depsBuildBuild = [ mtdutils ];
} ''
mkdir tmp
tree=${o.bootablerootdir}
mkfs.ubifs -x favor_lzo -c ${cfg.maxLEBcount} -m ${cfg.minIOSize} -e ${cfg.eraseBlockSize} -y -r $tree --output $out --squash-uids -o $out
'';
};
};
}

126
modules/outputs/ubimage.nix Normal file
View File

@ -0,0 +1,126 @@
{
config
, pkgs
, lib
, ...
}:
let
inherit (lib) mkIf mkEnableOption mkOption types concatStringsSep;
cfg = config.boot.tftp;
instructions = pkgs.writeText "env.scr" ''
setenv serverip ${cfg.serverip}
setenv ipaddr ${cfg.ipaddr}
setenv loadaddr ${lib.toHexString cfg.loadAddress}
'';
in {
options.system.outputs = {
ubimage = mkOption {
type = types.package;
description = ''
ubimage
*******
This output provides a UBIFS filesystem image and a small U-Boot script
to make the manual installation process very slightly simpler. You will
need a serial connection and a network connection to a TFTP server
containing the filesystem image it creates.
.. warning:: These steps were tested on a Belkin RT3200 (also known as
Linksys E8450). Other devices may be set up differently,
so use them as inspiration and don't just paste them
blindly.
1) determine which MTD device is being used for UBI, and the partition name:
.. code-block:: console
uboot> ubi part
Device 0: ubi0, MTD partition ubi
In this case the important value is ``ubi0``
2) list the available volumes and create a new one on which to install Liminix
.. code-block:: console
uboot> ubi info l
[ copious output scrolls past ]
Expect there to be existing volumes and for some or all of them to be
important. Unless you know what you're doing, don't remove anything
whose name suggests it's related to uboot, or any kind of backup or
recovery partition. To see how much space is free:
.. code-block:: console
uboot> ubi info
[ ... ]
UBI: available PEBs: 823
Now we can make our new root volume
.. code-block:: console
uboot> ubi create liminix -
3) transfer the root filesystem from the build system and write it
to the new volume. Paste the environment variable settings from
:file:`result/env.scr` into U-Boot, then run
.. code-block:: console
uboot> tftpboot ''${loadaddr} result/rootfs
uboot> ubi write ''${loadaddr} liminix $filesize
Now we have the root filesystem installed on the device. You
can even mount it and poke around using ``ubifsmount ubi0:liminix;
ubifsls /``
4) optional: before you configure the device to boot into Liminix
automatically, you can try booting it by hand to see if it works:
.. code-block:: console
uboot> ubifsmount ubi0:liminix
uboot> ubifsload ''${loadaddr} boot/uimage
uboot> bootm ''${loadaddr}
Once you've done this and you're happy with it, reset the device to
U-Boot. You don't need to recreate the volume but you do need to
repeat step 3.
5) Instructions for configuring autoboot are likely to be very
device-dependent. On the Linksys E8450/Belkin RT3200, the environment
variable `boot_production` governs what happens on a normal boot, so
you could do
.. code-block:: console
uboot> setenv boot_production 'led $bootled_pwr on ; ubifsmount ubi0:liminix; ubifsload ''${loadaddr} boot/uimage; bootm ''${loadaddr}'
On other devices, some detective work may be needed. Try running
`printenv` and look for likely commands, try looking at the existing
boot process, maybe even try looking for documentation for that device.
6) Now you can reboot the device into Liminix
.. code-block:: console
uboot> reset
'';
};
};
config = mkIf (config.rootfsType == "ubifs") {
system.outputs = {
ubimage =
let o = config.system.outputs; in
pkgs.runCommand "ubimage" {} ''
mkdir $out
cd $out
ln -s ${o.rootfs} rootfs
ln -s ${instructions} env.scr
'';
};
};
}

View File

@ -0,0 +1,73 @@
{
config
, pkgs
, lib
, ...
}:
let
inherit (lib) mkOption types concatStringsSep;
in
{
options = {
system.outputs = {
vmroot = mkOption {
type = types.package;
description = ''
vmroot
******
This target is for use with the qemu, qemu-aarch64, qemu-armv7l
devices. It generates an executable :file:`run.sh` which
invokes QEMU. It connects the Liminix
serial console and the `QEMU monitor <https://www.qemu.org/docs/master/system/monitor.html>`_
to stdin/stdout. Use ^P (not ^A) to switch between monitor and
stdio.
If you call :command:`run.sh` with ``--background
/path/to/some/directory`` as the first parameter, it will
fork into the background and open Unix sockets in that
directory for console and monitor. Use :command:`nix-shell
--run connect-vm` to connect to either of these sockets, and
^O to disconnect.
Liminix VMs are networked using QEMU socket networking. The
default behaviour is to connect
* multicast 230.0.0.1:1234 ("access") to eth0
* multicast 230.0.0.1:1235 ("lan") to eth1
Refer to :ref:`border-network-gateway` for details of how to
start an emulated upstream on the "access" network that
your Liminix device can talk to.
'';
};
};
};
config = {
system.outputs = rec {
vmroot =
let
inherit (config.system.outputs) rootfs kernel manifest;
cmdline = builtins.toJSON (concatStringsSep " " config.boot.commandLine);
makeBootableImage = pkgs.runCommandCC "objcopy" {}
(if pkgs.stdenv.hostPlatform.isAarch
then "${pkgs.stdenv.cc.targetPrefix}objcopy -O binary -R .comment -S ${kernel} $out"
else "cp ${kernel} $out");
phram_address = lib.toHexString (config.hardware.ram.startAddress + 256 * 1024 * 1024);
in pkgs.runCommand "vmroot" {} ''
mkdir $out
cd $out
ln -s ${rootfs} rootfs
ln -s ${kernel} vmlinux
ln -s ${manifest} manifest
ln -s ${kernel.headers} build
echo ${cmdline} > commandline
cat > run.sh << EOF
#!${pkgs.runtimeShell}
${pkgs.pkgsBuildBuild.run-liminix-vm}/bin/run-liminix-vm --command-line ${cmdline} --arch ${pkgs.stdenv.hostPlatform.qemuArch} --phram-address 0x${phram_address} \$* ${makeBootableImage} ${config.system.outputs.rootfs}
EOF
chmod +x run.sh
'';
};
};
}

View File

@ -55,6 +55,9 @@ let
run = {
file = ''
#!${execline}/bin/execlineb -P
importas PATH PATH
export PATH ${s6}/bin:''${PATH}
foreground { echo path is ''${PATH} }
${s6-linux-init}/bin/s6-linux-init-shutdownd -c "/etc/s6-linux-init/current" -g 3000
'';
mode = "0755";
@ -78,26 +81,44 @@ let
};
getty = dir {
run = {
# We can't run a useful shell on /dev/console because
# /dev/console is not allowed to be the controlling
# tty of any process, which means ^C ^Z etc don't work.
# So we work out what the *actual* console device is
# using sysfs and open our shell there instead.
file = ''
#!${execline}/bin/execlineb -P
/bin/getty -l /bin/login 115200 /dev/console
'';
#!${execline}/bin/execlineb -P
${execline}/bin/cd /
redirfd -r 0 /sys/devices/virtual/tty/console/active
withstdinas CONSOLETTY
importas CONSOLETTY CONSOLETTY
redirfd -w 2 /dev/''${CONSOLETTY}
fdmove -c 1 2
redirfd -r 0 /dev/''${CONSOLETTY}
/bin/ash -l
'';
mode = "0755";
};
down-signal = {
file = "HUP\n";
};
};
".s6-svscan" =
let
openConsole = ''
#!${execline}/bin/execlineb -P
${execline}/bin/redirfd -w 2 /dev/console
${execline}/bin/fdmove -c 1 2
'';
quit = message: ''
#!${execline}/bin/execlineb -P
${execline}/bin/redirfd -w 2 /dev/console
${execline}/bin/fdmove -c 1 2
${execline}/bin/foreground { ${s6-linux-init}/bin/s6-linux-init-echo -- ${message} }
${s6-linux-init}/bin/s6-linux-init-hpr -fr
'';
${openConsole}
${execline}/bin/foreground { ${s6-linux-init}/bin/s6-linux-init-echo -- ${message} }
${s6-linux-init}/bin/s6-linux-init-hpr -fr
'';
shutdown = action: ''
#!${execline}/bin/execlineb -P
${s6-linux-init}/bin/s6-linux-init-hpr -a #{action} -- now
'';
#!${execline}/bin/execlineb -P
${s6-linux-init}/bin/s6-linux-init-shutdown -a #{action} -- now
'';
empty = "#!${execline}/bin/execlineb -P\n";
in dir {
crash = {
@ -105,7 +126,13 @@ let
mode = "0755";
};
finish = {
file = quit "s6-svscan exited. Rebooting.";
file = ''
${openConsole}
ifelse { test -x /run/maintenance/exec } { /run/maintenance/exec }
foreground { echo "s6-svscan exited. Rebooting." }
wait { }
${s6-linux-init}/bin/s6-linux-init-hpr -fr
'';
mode = "0755";
};
SIGINT = {
@ -141,7 +168,6 @@ let
};
in {
config = {
programs.busybox.applets = [ "login" "getty" ];
filesystem = dir {
etc = dir {
s6-rc = dir {

View File

@ -17,12 +17,20 @@ shift
mount -t proc none /proc
mount -t sysfs none /sys
mount -t tmpfs none /tmp
# s6-linux-init mounts /dev before this script is called
mkdir /dev/pts
mount -t devpts none /dev/pts
mkdir -m 0751 /run/service-state
chgrp system /run/service-state
mkdir -m 0751 -p /run/services/outputs
chgrp system /run/services/outputs
if test -d /persist; then
mkdir -m 0751 -p /persist/services/state
(cd /run/services && ln -s ../../persist/services/state .)
else
mkdir -m 0751 -p /run/services/state
fi
### If your services are managed by s6-rc:
### (replace /run/service with your scandir)

View File

@ -1,18 +1,22 @@
#!/bin/sh -e
### Things to do *right before* the machine gets rebooted or
### powered off, at the very end of the shutdown sequence,
### when all the filesystems are unmounted.
## s6-linux-init-shutdownd never tells s6-svscan to exit, so if
## you're running s6-linux-init, it's normal that your
## .s6-svscan/finish script is not executed.
### This is a last resort hook; normally nothing should be
### done here (your rc.shutdown script should have taken care
### of everything) and you should leave this script empty.
## The place where you want to hack things is /etc/rc.shutdown.final,
## which is run by the stage 4 script right before the hard reboot.
## So you can do dirty stuff [...] which should clean up the
## s6-supervise and the foreground, and give control to
## .s6-svscan/finish.
### Some distributions, however, may need to perform some
### actions after unmounting the filesystems: typically if
### an additional teardown action is required on a filesystem
### after unmounting it, or if the system needs to be
### pivot_rooted before it can be shut down, etc.
## -- Laurent Bercot on skaware mailing list,
## https://skarnet.org/lists/skaware/1913.html
### Those are all exceptional cases. If you don't know for
### certain that you need to do something here, you don't.
exec >/dev/console 2>&1
# down, exit supervisor, wait, stay down
s6-svc -dxwD /run/service/s6-linux-init-shutdownd
# HUP, exit supervisor, wait, down
s6-svc -hxwd /run/service/s6-svscan-log
s6-svscanctl -b /run/service # abort

View File

@ -0,0 +1,19 @@
{ config, pkgs, lib, ... } :
{
config = {
programs.busybox = {
options = {
# schnapps is a shell script that needs
# [ command
# find -maxdepth -mindepth
# head -c
# echo -n
ASH_TEST = "y";
FEATURE_FIND_MAXDEPTH = "y";
FEATURE_FANCY_HEAD = "y";
FEATURE_FANCY_ECHO = "y";
};
};
defaultProfile.packages = [ pkgs.schnapps ] ;
};
}

View File

@ -29,15 +29,12 @@ let
in
longrun {
name = "sshd";
# we need /run/dropbear to point to hostkey storage, as that
# pathname is hardcoded into the binary.
# env -i clears the environment so we don't pass anything weird to
# ssh sessions
run = ''
if test -d /persist; then
mkdir -p /persist/secrets/dropbear
ln -s /persist/secrets/dropbear /run
else
mkdir -p /run/dropbear
fi
ln -s $(mkstate dropbear) /run
. /etc/profile # sets PATH but do we need this? it's the same file as ashrc
exec env -i ENV=/etc/ashrc PATH=$PATH ${dropbear}/bin/dropbear ${concatStringsSep " " options}
'';

View File

@ -1,11 +0,0 @@
{
# "standard" modules that aren't fundamentally required,
# but are probably useful in most common workflows and
# you should have to opt out of instead of into
imports = [
./tftpboot.nix
./kexecboot.nix
./flashimage.nix
./jffs2.nix
];
}

View File

@ -1,70 +0,0 @@
{
config
, pkgs
, lib
, ...
}:
let
inherit (lib) mkOption types concatStringsSep;
cfg = config.boot.tftp;
in {
imports = [ ./ramdisk.nix ];
options.boot.tftp.freeSpaceBytes = mkOption {
type = types.int;
default = 0;
};
options.system.outputs = {
tftpboot = mkOption {
type = types.package;
description = ''
Directory containing files needed for TFTP booting
'';
};
boot-scr = mkOption {
type = types.package;
description = ''
U-Boot commands to load and boot a kernel and rootfs over TFTP.
Copy-paste into the device boot monitor
'';
};
};
config = {
boot.ramdisk.enable = true;
system.outputs = rec {
tftpboot =
let o = config.system.outputs; in
pkgs.runCommand "tftpboot" {} ''
mkdir $out
cd $out
ln -s ${o.rootfs} rootfs
ln -s ${o.kernel} vmlinux
ln -s ${o.manifest} manifest
ln -s ${o.kernel.headers} build
ln -s ${o.uimage} uimage
ln -s ${o.boot-scr} boot.scr
'';
boot-scr =
let
inherit (pkgs.lib.trivial) toHexString;
o = config.system.outputs;
in
pkgs.buildPackages.runCommand "boot-scr" {} ''
uimageSize=$(($(stat -L -c %s ${o.uimage}) + 0x1000 &(~0xfff)))
rootfsStart=0x$(printf %x $((${cfg.loadAddress} + 0x100000 + $uimageSize)))
rootfsBytes=$(($(stat -L -c %s ${o.rootfs}) + 0x100000 &(~0xfffff)))
rootfsBytes=$(($rootfsBytes + ${toString cfg.freeSpaceBytes} ))
cmd="mtdparts=phram0:''${rootfsMb}M(rootfs) phram.phram=phram0,''${rootfsStart},''${rootfsBytes},${config.hardware.flash.eraseBlockSize} memmap=''${rootfsBytes}\$''${rootfsStart} root=/dev/mtdblock0";
cat > $out << EOF
setenv serverip ${cfg.serverip}
setenv ipaddr ${cfg.ipaddr}
setenv bootargs 'liminix $cmd'
tftp 0x$(printf %x ${cfg.loadAddress}) result/uimage ; tftp 0x$(printf %x $rootfsStart) result/rootfs
bootm 0x$(printf %x ${cfg.loadAddress})
EOF
'';
};
};
}

31
modules/usb.nix Normal file
View File

@ -0,0 +1,31 @@
# support for USB block devices and the common filesystems
# they're likely to provide
{lib, config, ... }:
{
kernel = {
config = {
USB = "y";
USB_EHCI_HCD = "y";
USB_EHCI_HCD_PLATFORM = "y";
USB_OHCI_HCD = "y";
USB_OHCI_HCD_PLATFORM = "y";
USB_SUPPORT = "y";
USB_COMMON = "y";
USB_STORAGE = "y";
USB_STORAGE_DEBUG = "n";
USB_UAS = "y";
USB_ANNOUNCE_NEW_DEVICES = "y";
SCSI = "y";
BLK_DEV_SD = "y";
USB_PRINTER = "y";
MSDOS_PARTITION = "y";
EFI_PARTITION = "y";
EXT4_FS = "y";
EXT4_USE_FOR_EXT2 = "y";
FS_ENCRYPTION = "y";
};
};
}

View File

@ -46,6 +46,14 @@ in {
CRYPTO_SHA1 = "y";
ENCRYPTED_KEYS = "y";
KEYS = "y";
WLAN = "y";
CFG80211 = "m";
MAC80211 = "m";
EXPERT = "y";
CFG80211_CERTIFICATION_ONUS = "y";
CFG80211_REQUIRE_SIGNED_REGDB = "n"; # depends on ONUS
CFG80211_CRDA_SUPPORT = "n";
};
};
};

View File

@ -44,19 +44,17 @@ let
lua = let s = lua_no_readline.override { self = s; }; in s;
in
extraPkgs // {
mtdutils = prev.mtdutils.overrideAttrs(o: {
patches = (if o ? patches then o.patches else []) ++ [
./pkgs/mtdutils/0001-mkfs.jffs2-add-graft-option.patch
];
});
# liminix library functions
lim = {
parseInt = s : (builtins.fromTOML "r=${s}").r;
};
rsyncSmall =
let r = prev.rsync.overrideAttrs(o: {
configureFlags = o.configureFlags ++ [
"--disable-openssl"
];
});
in r.override { openssl = null; };
# keep these alphabetical
btrfs-progs = prev.btrfs-progs.override {
udevSupport = false;
udev = null;
};
chrony =
let chrony' = prev.chrony.overrideAttrs(o: {
@ -79,7 +77,54 @@ extraPkgs // {
};
strace = prev.strace.override { libunwind = null; };
dnsmasq =
let d = prev.dnsmasq.overrideAttrs(o: {
preBuild = ''
makeFlagsArray=("COPTS=")
'';
});
in d.override {
dbusSupport = false;
nettle = null;
};
dropbear = prev.dropbear.overrideAttrs (o: {
postPatch = ''
(echo '#define DSS_PRIV_FILENAME "/run/dropbear/dropbear_dss_host_key"'
echo '#define RSA_PRIV_FILENAME "/run/dropbear/dropbear_rsa_host_key"'
echo '#define ECDSA_PRIV_FILENAME "/run/dropbear/dropbear_ecdsa_host_key"'
echo '#define ED25519_PRIV_FILENAME "/run/dropbear/dropbear_ed25519_host_key"') > localoptions.h
'';
});
hostapd =
let
config = [
"CONFIG_DRIVER_NL80211=y"
"CONFIG_IAPP=y"
"CONFIG_IEEE80211AC=y"
"CONFIG_IEEE80211AX=y"
"CONFIG_IEEE80211N=y"
"CONFIG_IEEE80211W=y"
"CONFIG_INTERNAL_LIBTOMMATH=y"
"CONFIG_INTERNAL_LIBTOMMATH_FAST=y"
"CONFIG_IPV6=y"
"CONFIG_LIBNL32=y"
"CONFIG_PKCS12=y"
"CONFIG_RSN_PREAUTH=y"
"CONFIG_TLS=internal"
];
h = prev.hostapd.overrideAttrs(o: {
extraConfig = "";
configurePhase = ''
cat > hostapd/defconfig <<EOF
${builtins.concatStringsSep "\n" config}
EOF
${o.configurePhase}
'';
});
in h.override { openssl = null; sqlite = null; };
kexec-tools-static = prev.kexec-tools.overrideAttrs(o: {
# For kexecboot we copy kexec into a ramdisk on the system being
@ -102,17 +147,11 @@ extraPkgs // {
luaFull = prev.lua;
inherit lua;
inherit s6;
s6-linux-init = prev.s6-linux-init.override {
skawarePackages = prev.skawarePackages // {
inherit s6;
};
};
s6-rc = prev.s6-rc.override {
skawarePackages = prev.skawarePackages // {
inherit s6;
};
};
mtdutils = prev.mtdutils.overrideAttrs(o: {
patches = (if o ? patches then o.patches else []) ++ [
./pkgs/mtdutils/0001-mkfs.jffs2-add-graft-option.patch
];
});
nftables = prev.nftables.overrideAttrs(o: {
configureFlags = [
@ -123,53 +162,6 @@ extraPkgs // {
];
});
dnsmasq =
let d = prev.dnsmasq.overrideAttrs(o: {
preBuild = ''
makeFlagsArray=("COPTS=")
'';
});
in d.override {
dbusSupport = false;
nettle = null;
};
hostapd =
let
config = [
"CONFIG_DRIVER_NL80211=y"
"CONFIG_IAPP=y"
"CONFIG_IEEE80211AC=y"
"CONFIG_IEEE80211N=y"
"CONFIG_IEEE80211W=y"
"CONFIG_INTERNAL_LIBTOMMATH=y"
"CONFIG_INTERNAL_LIBTOMMATH_FAST=y"
"CONFIG_IPV6=y"
"CONFIG_LIBNL32=y"
"CONFIG_PKCS12=y"
"CONFIG_RSN_PREAUTH=y"
"CONFIG_TLS=internal"
];
h = prev.hostapd.overrideAttrs(o: {
extraConfig = "";
configurePhase = ''
cat > hostapd/defconfig <<EOF
${builtins.concatStringsSep "\n" config}
EOF
${o.configurePhase}
'';
});
in h.override { openssl = null; sqlite = null; };
dropbear = prev.dropbear.overrideAttrs (o: {
postPatch = ''
(echo '#define DSS_PRIV_FILENAME "/run/dropbear/dropbear_dss_host_key"'
echo '#define RSA_PRIV_FILENAME "/run/dropbear/dropbear_rsa_host_key"'
echo '#define ECDSA_PRIV_FILENAME "/run/dropbear/dropbear_ecdsa_host_key"'
echo '#define ED25519_PRIV_FILENAME "/run/dropbear/dropbear_ed25519_host_key"') > localoptions.h
'';
});
openssl = prev.openssl.overrideAttrs (o: {
# we want to apply
# https://patch-diff.githubusercontent.com/raw/openssl/openssl/pull/20273.patch";
@ -184,4 +176,92 @@ extraPkgs // {
});
pppBuild = prev.ppp;
qemuLim = let q = prev.qemu.overrideAttrs (o: {
patches = o.patches ++ [
./pkgs/qemu/arm-image-friendly-load-addr.patch
];
}); in q.override { nixosTestRunner = true; sdlSupport = false; };
rsyncSmall =
let r = prev.rsync.overrideAttrs(o: {
configureFlags = o.configureFlags ++ [
"--disable-openssl"
];
});
in r.override { openssl = null; };
inherit s6;
s6-linux-init = prev.s6-linux-init.override {
skawarePackages = prev.skawarePackages // {
inherit s6;
};
};
s6-rc = prev.s6-rc.override {
skawarePackages = prev.skawarePackages // {
inherit s6;
};
};
strace = prev.strace.override { libunwind = null; };
ubootQemuAarch64 = final.buildUBoot {
defconfig = "qemu_arm64_defconfig";
extraMeta.platforms = ["aarch64-linux"];
filesToInstall = ["u-boot.bin"];
};
ubootQemuArm = final.buildUBoot {
defconfig = "qemu_arm_defconfig";
extraMeta.platforms = ["armv7l-linux"];
filesToInstall = ["u-boot.bin"];
extraConfig = ''
CONFIG_CMD_UBI=y
CONFIG_CMD_UBIFS=y
CONFIG_BOOTSTD=y
CONFIG_BOOTMETH_DISTRO=y
CONFIG_LZMA=y
CONFIG_CMD_LZMADEC=y
CONFIG_SYS_BOOTM_LEN=0x1000000
'';
};
ubootQemuMips = final.buildUBoot {
defconfig = "malta_defconfig";
extraMeta.platforms = ["mips-linux"];
filesToInstall = ["u-boot.bin"];
# define the prompt to be the same as arm{32,64} so
# we can use the same expect script for both
extraPatches = [ ./pkgs/u-boot/0002-virtio-init-for-malta.patch ];
extraConfig = ''
CONFIG_SYS_PROMPT="=> "
CONFIG_VIRTIO=y
CONFIG_AUTOBOOT=y
CONFIG_DM_PCI=y
CONFIG_VIRTIO_PCI=y
CONFIG_VIRTIO_NET=y
CONFIG_VIRTIO_BLK=y
CONFIG_VIRTIO_MMIO=y
CONFIG_QFW_MMIO=y
CONFIG_FIT=y
CONFIG_LZMA=y
CONFIG_CMD_LZMADEC=y
CONFIG_SYS_BOOTM_LEN=0x1000000
CONFIG_SYS_MALLOC_LEN=0x400000
CONFIG_MIPS_BOOT_FDT=y
CONFIG_OF_LIBFDT=y
CONFIG_OF_STDOUT_VIA_ALIAS=y
'';
};
util-linux-small = prev.util-linux.override {
ncursesSupport = false;
pamSupport = false;
systemdSupport = false;
nlsSupport = false;
translateManpages = false;
capabilitiesSupport = false;
};
}

View File

@ -10,10 +10,7 @@ let
type' = types.submodule { options = type; };
in (mergeDefinitions [] type' defs).mergedValue;
in {
pseudofile = callPackage ./pseudofile {};
liminix = {
services = callPackage ./liminix-tools/services {};
networking = callPackage ./liminix-tools/networking {};
builders = {
squashfs = callPackage ./liminix-tools/builders/squashfs.nix {};
dtb = callPackage ./kernel/dtb.nix {};
@ -52,32 +49,27 @@ in {
};
inherit typeChecked;
};
networking = callPackage ./liminix-tools/networking {};
services = callPackage ./liminix-tools/services {};
};
writeFennelScript = callPackage ./write-fennel-script {};
writeFennel = callPackage ./write-fennel {};
writeAshScript = callPackage ./write-ash-script {};
systemconfig = callPackage ./systemconfig {};
s6-init-bin = callPackage ./s6-init-bin {};
s6-rc-database = callPackage ./s6-rc-database {};
run-liminix-vm = callPackage ./run-liminix-vm {};
ppp = callPackage ./ppp {};
pppoe = callPackage ./pppoe {};
kernel-backport = callPackage ./kernel-backport {};
mac80211 = callPackage ./mac80211 {};
netlink-lua = callPackage ./netlink-lua {};
linotify = callPackage ./linotify {};
ifwait = callPackage ./ifwait {};
# please keep the rest of this list alphabetised :-)
anoia = callPackage ./anoia {};
fennel = callPackage ./fennel {};
fennelrepl = callPackage ./fennelrepl {};
firewallgen = callPackage ./firewallgen {};
firmware-utils = callPackage ./firmware-utils {};
gen_init_cpio = callPackage ./gen_init_cpio {};
serviceFns = callPackage ./service-fns {};
# these are packages for the build system not the host/target
tufted = callPackage ./tufted {};
routeros = callPackage ./routeros {};
go-l2tp = callPackage ./go-l2tp {};
hi = callPackage ./hi {};
ifwait = callPackage ./ifwait {};
initramfs-peek = callPackage ./initramfs-peek {};
kernel-backport = callPackage ./kernel-backport {};
kmodloader = callPackage ./kmodloader {};
levitate = callPackage ./levitate {};
libubootenv = callPackage ./libubootenv {};
linotify = callPackage ./linotify {};
# we need to build real lzma instead of using xz, because the lzma
# decoder in u-boot doesn't understand streaming lzma archives
@ -86,20 +78,33 @@ in {
# https://sourceforge.net/p/squashfs/mailman/message/26599379/
lzma = callPackage ./lzma {};
preinit = callPackage ./preinit {};
swconfig = callPackage ./swconfig {};
odhcp6c = callPackage ./odhcp6c {};
openwrt = callPackage ./openwrt {};
initramfs-peek = callPackage ./initramfs-peek {};
mac80211 = callPackage ./mac80211 {};
min-collect-garbage = callPackage ./min-collect-garbage {};
min-copy-closure = callPackage ./min-copy-closure {};
hi = callPackage ./hi {};
firewallgen = callPackage ./firewallgen {};
kernel-modules = callPackage ./kernel-modules {};
netlink-lua = callPackage ./netlink-lua {};
odhcp-script = callPackage ./odhcp-script {};
fennel = callPackage ./fennel {};
fennelrepl = callPackage ./fennelrepl {};
anoia = callPackage ./anoia {};
odhcp6c = callPackage ./odhcp6c {};
openwrt = callPackage ./openwrt {};
ppp = callPackage ./ppp {};
pppoe = callPackage ./pppoe {};
preinit = callPackage ./preinit {};
pseudofile = callPackage ./pseudofile {};
routeros = callPackage ./routeros {};
run-liminix-vm = callPackage ./run-liminix-vm {};
s6-init-bin = callPackage ./s6-init-bin {};
s6-rc-database = callPackage ./s6-rc-database {};
# schnapps is written by Turris and provides a high-level interface
# to btrfs snapshots. It may be useful on the Turris Omnia to
# install Liminix while retaining the ability to rollback to the
# vendor OS, or even to derisk Liminix updates on that device
schnapps = callPackage ./schnapps {};
serviceFns = callPackage ./service-fns {};
swconfig = callPackage ./swconfig {};
systemconfig = callPackage ./systemconfig {};
tufted = callPackage ./tufted {};
writeAshScript = callPackage ./write-ash-script {};
writeFennel = callPackage ./write-fennel {};
writeFennelScript = callPackage ./write-fennel-script {};
}

View File

@ -0,0 +1,24 @@
{ stdenv
, fetchFromGitHub
, cmake
, zlib
, openssl
}:
stdenv.mkDerivation {
pname = "firmware-utils";
version = "snapshot";
src = fetchFromGitHub {
owner = "openwrt";
repo = "firmware-utils";
rev = "e87f23849790a7c77b4cd0e8ef0384da188174e5";
hash = "sha256-285Isf9sRuUt5S56SozgqpnS0+LOfnvpxpnWLwuWYUk=";
};
nativeBuildInputs = [
cmake
zlib
openssl
];
}

View File

@ -1,3 +0,0 @@
# obj-m += net/ipv4/netfilter/nft_fib_ipv4.o

View File

@ -1,55 +0,0 @@
{
stdenv
, buildPackages
, kernelSrc ? null
, modulesupport ? null
, targets ? []
, kconfig ? {}
, openssl
, writeText
, lib
}:
let
writeConfig = import ../kernel/write-kconfig.nix { inherit lib writeText; };
arch = if stdenv.isMips
then "mips"
else if stdenv.isAarch64
then "arm64"
else throw "unknown arch";
in stdenv.mkDerivation {
name = "kernel-modules";
nativeBuildInputs = [buildPackages.stdenv.cc] ++
(with buildPackages.pkgs; [
bc bison flex
openssl
cpio
kmod
]);
CC = "${stdenv.cc.bintools.targetPrefix}gcc";
HOST_EXTRACFLAGS = with buildPackages.pkgs;
"-I${buildPackages.openssl.dev}/include -L${buildPackages.openssl.out}/lib";
CROSS_COMPILE = stdenv.cc.bintools.targetPrefix;
ARCH = arch;
KBUILD_BUILD_HOST = "liminix.builder";
buildPhase = ''
cat ${writeConfig "kconfig" kconfig} > .more-config
cat .more-config >> .config
make olddefconfig
for v in $(cat .more-config) ; do grep $v .config || (echo Missing $v && exit 1);done
# grep =m .config
make modules
'';
src = modulesupport;
installPhase = ''
mkdir -p $out/lib/modules/0.0
find . -name \*.ko | cpio --verbose --make-directories -p $out/lib/modules/0.0
depmod -b $out -v 0.0
touch $out/load.sh
for i in ${lib.concatStringsSep " " targets}; do
modprobe -S 0.0 -d $out --show-depends $i >> $out/load.sh
done
tac < $out/load.sh | sed 's/^insmod/rmmod/g' > $out/unload.sh
'';
}

View File

@ -6,17 +6,15 @@
, config
, src
, version ? "0"
, extraPatchPhase ? "echo"
, targets ? ["vmlinux"]
} :
let
writeConfig = import ./write-kconfig.nix { inherit lib writeText; };
kconfigFile = writeConfig "kconfig" config;
arch = if stdenv.isMips
then "mips"
else if stdenv.isAarch64
then "arm64"
else throw "unknown arch";
arch = stdenv.hostPlatform.linuxArch;
targetNames = map baseNameOf targets;
inherit lib; in
stdenv.mkDerivation rec {
name = "kernel";
@ -39,7 +37,7 @@ stdenv.mkDerivation rec {
dontStrip = true;
dontPatchELF = true;
outputs = ["out" "headers" "modulesupport"];
outputs = ["out" "headers" "modulesupport"] ++ targetNames;
phases = [
"unpackPhase"
"butcherPkgconfig"
@ -54,7 +52,9 @@ stdenv.mkDerivation rec {
patches = [
./cmdline-cookie.patch
];
./mips-malta-fdt-from-bootloader.patch
] ++ lib.optional (lib.versionOlder version "5.18.0")
./phram-allow-cached-mappings.patch;
# this is here to work around what I think is a bug in nixpkgs
# packaging of ncurses: it installs pkg-config data files which
@ -94,18 +94,17 @@ stdenv.mkDerivation rec {
'';
buildPhase = ''
make vmlinux modules_prepare
make ${lib.concatStringsSep " " targetNames} modules_prepare -j$NIX_BUILD_CORES
'';
installPhase = ''
${CROSS_COMPILE}strip -d vmlinux
${lib.concatStringsSep "\n" (map (f: "cp ${f} \$${baseNameOf f}") targets)}
cp vmlinux $out
mkdir -p $headers
cp -a include .config $headers/
mkdir -p $modulesupport
cp modules.* $modulesupport
make clean modules_prepare
make modules
cp -a . $modulesupport
'';
}

View File

@ -1,6 +1,6 @@
/dts-v1/;
// used on aarch64 to provide a U-bootable image that combines
// used on arm/aarch64 to provide a U-bootable image that combines
// kernel and fdt
/ {
@ -12,7 +12,7 @@
description = "Vanilla Linux kernel";
// data = /incbin/("./vmlinux.bin.gz");
type = "kernel";
arch = "arm64";
// arch = "arm64";
os = "linux";
// compression = "gzip";
// load = <00000000>;
@ -28,7 +28,7 @@
description = "Flattened Device Tree blob";
// data = /incbin/("./target.dtb");
type = "flat_dt";
arch = "arm64";
// arch = "arm64";
compression = "none";
hash-1 {
algo = "crc32";

View File

@ -0,0 +1,15 @@
diff --git a/arch/mips/mti-malta/malta-setup.c b/arch/mips/mti-malta/malta-setup.c
index 21cb3ac1237b..52e731f9b4e2 100644
--- a/arch/mips/mti-malta/malta-setup.c
+++ b/arch/mips/mti-malta/malta-setup.c
@@ -192,7 +192,9 @@ static void __init bonito_quirks_setup(void)
void __init *plat_get_fdt(void)
{
- return (void *)__dtb_start;
+ return (fw_arg0 == -2) ?
+ (void *) (KSEG1ADDR(fw_arg1)) :
+ (void *) __dtb_start;
}
void __init plat_mem_setup(void)

View File

@ -0,0 +1,47 @@
From bb7e7aeb3d832059e33b1e76eb85d4680f77abf2 Mon Sep 17 00:00:00 2001
From: Ben Hutchings <ben@decadent.org.uk>
Date: Fri, 3 Jun 2016 01:08:36 +0100
Subject: [PATCH] phram: Use memremap() to allow mapping of system RAM
Using memremap() instead of ioremap() allows mapping a disk image in
system RAM that has somehow been reserved. It should fall back
to ioremap() where necessary.
Entirely untested, and I'm not convinced this is a good idea at all.
---
drivers/mtd/devices/phram.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/drivers/mtd/devices/phram.c b/drivers/mtd/devices/phram.c
index 8b66e52ca3cc..0ea254e2ba51 100644
--- a/drivers/mtd/devices/phram.c
+++ b/drivers/mtd/devices/phram.c
@@ -88,7 +88,7 @@ static void unregister_devices(void)
list_for_each_entry_safe(this, safe, &phram_list, list) {
mtd_device_unregister(&this->mtd);
- iounmap(this->mtd.priv);
+ memunmap(this->mtd.priv);
kfree(this->mtd.name);
kfree(this);
}
@@ -104,7 +104,8 @@ static int register_device(char *name, phys_addr_t start, size_t len)
goto out0;
ret = -EIO;
- new->mtd.priv = ioremap(start, len);
+ new->mtd.priv = memremap(start, len,
+ MEMREMAP_WB | MEMREMAP_WT | MEMREMAP_WC);
if (!new->mtd.priv) {
pr_err("ioremap failed\n");
goto out1;
@@ -134,7 +135,7 @@ static int register_device(char *name, phys_addr_t start, size_t len)
return 0;
out2:
- iounmap(new->mtd.priv);
+ memunmap(new->mtd.priv);
out1:
kfree(new);
out0:

View File

@ -7,21 +7,27 @@
} :
let
objcopy = "${stdenv.cc.bintools.targetPrefix}objcopy";
arch = stdenv.hostPlatform.linuxArch;
stripAndZip = ''
${objcopy} -O binary -R .reginfo -R .notes -R .note -R .comment -R .mdebug -R .note.gnu.build-id -S vmlinux.elf vmlinux.bin
rm -f vmlinux.bin.lzma ; lzma -k -z vmlinux.bin
'';
in {
kernel
, commandLine
, entryPoint
, extraName ? "" # e.g. socFamily
, loadAddress
, imageFormat
, dtb ? null
} :
stdenv.mkDerivation {
} : stdenv.mkDerivation {
name = "kernel.image";
phases = [
"preparePhase"
(if dtb != null then "dtbPhase" else ":")
"buildPhase"
"installPhase" ];
(if commandLine != null then assert dtb != null; "mungeDtbPhase" else ":")
(if imageFormat == "fit" then "buildPhaseFIT" else "buildPhaseUImage")
"installPhase"
];
nativeBuildInputs = [
lzma
dtc
@ -31,35 +37,43 @@ stdenv.mkDerivation {
preparePhase = ''
cp ${kernel} vmlinux.elf; chmod +w vmlinux.elf
'';
dtbPhase = ''
mungeDtbPhase = ''
dtc -I dtb -O dts -o tmp.dts ${dtb}
echo '/{ chosen { bootargs = ${builtins.toJSON commandLine}; }; };' >> tmp.dts
dtc -I dts -O dtb -o tmp.dtb tmp.dts
'';
buildPhase =
let arch =
# per output of "mkimage -A list". I *think* these
# are the same as the kernel arch convention, but
# maybe that's coincidence
if stdenv.isMips
then "mips"
else if stdenv.isAarch64
then "arm64"
else throw "unknown arch";
in ''
${objcopy} -O binary -R .reginfo -R .notes -R .note -R .comment -R .mdebug -R .note.gnu.build-id -S vmlinux.elf vmlinux.bin
rm -f vmlinux.bin.lzma ; lzma -k -z vmlinux.bin
cat ${./kernel_fdt.its} > mkimage.its
echo '/ { images { kernel { data = /incbin/("./vmlinux.bin.lzma"); }; }; };' >> mkimage.its
echo '/ { images { kernel { load = <${loadAddress}>; }; }; };' >> mkimage.its
echo '/ { images { kernel { entry = <${entryPoint}>; }; }; };' >> mkimage.its
echo '/ { images { kernel { compression = "lzma"; }; }; };' >> mkimage.its
echo '/ { images { fdt-1 { data = /incbin/("./tmp.dtb"); }; }; }; ' >> mkimage.its
mkimage -f mkimage.its mkimage.itb
mkimage -l mkimage.itb
'';
buildPhaseUImage = ''
test -f tmp.dtb && ${objcopy} --update-section .appended_dtb=tmp.dtb vmlinux.elf || ${objcopy} --add-section .appended_dtb=tmp.dtb vmlinux.elf
${stripAndZip}
mkimage -A ${arch} -O linux -T kernel -C lzma -a 0x${lib.toHexString loadAddress} -e 0x${lib.toHexString entryPoint} -n '${lib.toUpper arch} Liminix Linux ${extraName}' -d vmlinux.bin.lzma kernel.uimage
'';
buildPhaseFIT = ''
${stripAndZip}
cat ${./kernel_fdt.its} > mkimage.its
cat << _VARS >> mkimage.its
/ {
images {
kernel {
data = /incbin/("./vmlinux.bin.lzma");
load = <0x${lib.toHexString loadAddress}>;
entry = <0x${lib.toHexString entryPoint}>;
arch = "${arch}";
compression = "lzma";
};
fdt-1 {
data = /incbin/("./tmp.dtb");
arch = "${arch}";
};
};
};
_VARS
mkimage -f mkimage.its kernel.uimage
mkimage -l kernel.uimage
'';
installPhase = ''
cp mkimage.itb $out
cp kernel.uimage $out
'';
}

View File

@ -0,0 +1,43 @@
{
liminix
, lib
, targets ? []
, kernel ? null
, runCommand
, pkgsBuildBuild
, dependencies ? []
} :
let
inherit (liminix.services) oneshot;
inherit (lib) concatStringsSep;
loader = runCommand "modules" {
nativeBuildInputs = with pkgsBuildBuild ;[
kmod cpio gawk
];
} ''
kernel=${kernel.modulesupport}
mkdir -p lib/modules/0.0
(cd $kernel && find . -name \*.ko | cpio --verbose --make-directories -p $NIX_BUILD_TOP/lib/modules/0.0)
cp $kernel/modules.* lib/modules/0.0
depmod -b . 0.0
(for i in ${lib.concatStringsSep " " targets}; do
modprobe -S 0.0 -d $NIX_BUILD_TOP --show-depends $i | sed "s,^insmod $NIX_BUILD_TOP/lib/modules/0.0/,,g"
done) | awk '!a[$0]++' > load-order
mkdir $out
for i in $(cat load-order); do
install -v $NIX_BUILD_TOP/lib/modules/0.0/$i -D $out/$i
done
echo "O=$out" > $out/load.sh
sed "s,^,insmod \$O/,g" < load-order >> $out/load.sh
echo "O=$out" > $out/unload.sh
tac load-order | sed "s,^,rmmod \$O/,g" > $out/unload.sh
'';
in oneshot {
name = "kmodloader-" + (concatStringsSep "-" targets);
up = "sh ${loader}/load.sh";
down = "sh ${loader}/unload.sh";
inherit dependencies;
}

75
pkgs/levitate/default.nix Normal file
View File

@ -0,0 +1,75 @@
{
writeScriptBin
, writeScript
, systemconfig
, execline
, lib
, services ? null
, liminix
, pseudofile
, pkgs
} :
let
inherit (pseudofile) dir symlink;
inherit (liminix.services) oneshot;
newRoot = "/run/maintenance";
sysconfig =
let
doChroot = writeScript "exec" ''
#!${execline}/bin/execlineb -P
cd ${newRoot}
foreground { mount --move ${newRoot} / }
redirfd -r 0 /dev/console
redirfd -w 1 /dev/console
fdmove -c 2 1
emptyenv chroot . /bin/init
'';
base = {...} : {
config = {
services = services // {
banner = oneshot {
name = "banner";
up = "cat /etc/banner > /dev/console";
down = "true";
};
};
filesystem = dir {
exec = symlink doChroot;
etc = dir {
banner = symlink (pkgs.writeText "banner" ''
LADIES AND GENTLEMEN WE ARE FLOATING IN SPACE
Most services are disabled. The system is operating
with a ram-based root filesystem, making it safe to
overwrite the flash devices in order to perform
upgrades and maintenance.
Don't forget to reboot when you have finished.
'');
};
};
};
};
eval = lib.evalModules {
modules = [
{ _module.args = { inherit pkgs; inherit (pkgs) lim; }; }
../../modules/base.nix
../../modules/users.nix
../../modules/busybox.nix
base
../../modules/s6
];
};
in systemconfig eval.config.filesystem.contents;
in writeScriptBin "levitate" ''
#!/bin/sh
destdir=${newRoot}
mkdir -p $destdir $destdir/nix/store
for path in $(cat ${sysconfig}/etc/nix-store-paths) ; do
(cd $destdir && cp -a $path .$path)
done
${sysconfig}/bin/activate $destdir
''

View File

@ -0,0 +1,6 @@
CFLAGS=$(INC) -D_LINUX_TYPES_H -D_LINUX_STRING_H_
fw_printenv: fw_env_main.o fw_env.o \
crc32.o ctype.o linux_string.o \
env_attr.o env_flags.o
$(CC) -o $@ $^

View File

@ -0,0 +1,17 @@
{ stdenv
, cmake
, zlib
, libyaml
, fetchFromGitHub
} :
stdenv.mkDerivation {
name = "libubootenv";
src = fetchFromGitHub {
owner = "sbabic";
repo = "libubootenv";
rev = "3f4d15e36ceb58085b08dd13f3f2788e9299877b"; # v0.3.5
hash = "sha256-i7gUb1A6FTOBCpympQpndhOG9pCDA4P0iH7ZNBqo+PA=";
};
buildInputs = [ zlib libyaml ];
nativeBuildInputs = [ cmake ];
}

View File

@ -15,6 +15,6 @@ for i in run notification-fd up down consumer-for producer-for pipeline-name ; d
test -n "$(printenv $i)" && (echo "$(printenv $i)" > $out/${name}/$i)
done
( cd $out && ln -s /run/service-state/${name} ./.outputs )
( cd $out && ln -s /run/services/outputs/${name} ./.outputs )
for i in $out/${name}/{down,up,run} ; do test -f $i && chmod +x $i; done
true

View File

@ -9,7 +9,7 @@
}:
let
inherit (builtins) concatStringsSep;
prefix = "/run/service-state";
prefix = "/run/services/outputs";
output = service: name: "${prefix}/${service.name}/${name}";
serviceScript = commands : ''
#!/bin/sh
@ -18,8 +18,7 @@ let
${commands}
'';
cleanupScript = name : ''
#!/bin/sh
test -d ${prefix}/${name} && rm -rf ${prefix}/${name}
if test -d ${prefix}/${name} ; then rm -rf ${prefix}/${name} ; fi
'';
service = {
name

View File

@ -14,11 +14,7 @@
, lib
}:
let
arch = if stdenv.isMips
then "mips"
else if stdenv.isAarch64
then "arm64"
else throw "unknown arch";
arch = stdenv.hostPlatform.linuxArch;
openwrtSrc = fetchFromGitHub {
name = "openwrt-source";
repo = "openwrt";
@ -29,47 +25,52 @@ let
inherit (liminix.services) oneshot longrun;
inherit (lib.lists) foldl;
configs = {
ath9k = {
ath9k.kconfig = {
WLAN_VENDOR_ATH = "y";
ATH_COMMON = "m";
ATH9K = "m";
ATH9K_AHB = "y";
# ATH9K_DEBUGFS = "y";
# ATH_DEBUG = "y";
BACKPORTED_ATH9K_AHB = "y";
};
ath10k_pci = {
ath9k_pci = {
module = "ath9k";
kconfig = {
WLAN_VENDOR_ATH = "y";
ATH_COMMON = "m";
ATH9K = "m";
ATH9K_PCI = "y";
};
};
ath10k_pci.kconfig = {
WLAN_VENDOR_ATH = "y";
ATH_COMMON = "m";
ATH10K = "m";
# BACKPORTED_ATH10K_AHB = "y";
# ATH10K_AHB = "y";
ATH10K_PCI = "y";
ATH10K_DEBUG = "y";
};
rt2800soc = {
rt2800soc.kconfig = {
WLAN_VENDOR_RALINK = "y";
RT2800SOC = "m";
RT2X00 = "m";
};
mt7603e = { # XXX find a better name for this
mt7603e.kconfig = { # XXX find a better name for this
WLAN_VENDOR_RALINK = "y";
WLAN_VENDOR_MEDIATEK = "y";
MT7603E = "y";
};
mt7915e = {
mt7915e.kconfig = {
MT7915E = "m";
};
mt7615e = {
mt7615e.kconfig = {
MT7615E = "m";
MT7622_WMAC = "y";
};
mac80211_hwsim = {
mac80211_hwsim.kconfig = {
MAC80211_HWSIM = "y";
};
};
kconfig = (foldl (config: d: (config // configs.${d})) {
kconfig = (foldl (config: d: (config // configs.${d}.kconfig)) {
WLAN = "y";
CFG80211 = "m";
MAC80211 = "m";
@ -86,7 +87,6 @@ let
CFG80211_CRDA_SUPPORT = "n";
MAC80211_MESH = "y";
} drivers) // extraConfig;
writeConfig = name : config: writeText name
@ -166,7 +166,11 @@ let
find . -name \*.ko | cpio --make-directories -p $out/lib/modules/0.0
depmod -b $out -v 0.0
touch $out/load.sh
for i in ${lib.concatStringsSep " " drivers}; do
for i in ${lib.concatStringsSep " "
(map
(d: let c = { module = d; } // configs.${d} ;
in c.module)
drivers)}; do
modprobe -S 0.0 -d $out --show-depends $i >> $out/load.sh
done
tac < $out/load.sh | sed 's/^insmod/rmmod/g' > $out/unload.sh

View File

@ -1,19 +1,26 @@
#!/usr/bin/env bash
ssh_command=${SSH_COMMAND-ssh}
if [ "$1" = "--no-reboot" ] ; then
reboot="true"
shift
else
reboot="reboot"
fi
target_host=$1
shift
if [ -z "$target_host" ] ; then
echo Usage: liminix-rebuild target-host params
echo Usage: liminix-rebuild \[--no-reboot\] target-host params
exit 1
fi
if toplevel=$(nix-build "$@" -A outputs.systemConfiguration --no-out-link); then
echo systemConfiguration $toplevel
min-copy-closure $target_host $toplevel
$ssh_command $target_host cp -v -fP $toplevel/bin/* $toplevel/etc/* /persist
$ssh_command $target_host "sync; source /etc/profile; reboot"
$ssh_command $target_host $toplevel/bin/install
$ssh_command $target_host "sync; source /etc/profile; reboot -f"
else
echo Rebuild failed
fi

View File

@ -1,2 +0,0 @@
(local ssh (io.popen "

View File

@ -1,20 +1,49 @@
#!/usr/bin/env bash
ssh_command=${SSH_COMMAND-ssh}
target_host=$1
shift
root_prefix=/
verbose=true
while [[ $# -gt 0 ]]; do
case $1 in
-r|--root)
root_prefix="$2"
shift
shift
;;
-q|--quiet)
verbose=""
shift
;;
-*|--*)
echo "Unknown option $1"
exit 1
;;
*)
if test -z "$target_host"; then
target_host="$1"
else
paths+=("$1") # save positional arg
fi
shift # past argument
;;
esac
done
progress() {
test -n "$verbose" && echo $*
}
if [ -z "$target_host" ] ; then
echo Usage: min-copy-closure target-host paths
echo Usage: min-copy-closure [--root /mnt] target-host paths
exit 1
fi
if [ -n "$IN_NIX_BUILD" ] ; then
if [ -z "$IN_NIX_BUILD" ] ; then
# can't run nix-store in a derivation, so we have to
# skip the requisites when running tests in hydra
paths=$@
else
paths=$(nix-store -q --requisites "$@")
paths=$(nix-store -q --requisites "$paths")
fi
needed=""
@ -25,16 +54,16 @@ coproc remote {
exec 10>&${remote[1]}
for p in $paths; do
echo -n Checking $(basename $p) ...
echo "test -e $p && echo skip || echo $p" >&10
progress -n Checking $(basename $p) ...
echo "test -e ${root_prefix}$p && echo skip || echo $p" >&10
read n <&${remote[0]}
case $n in
skip)
echo skip
progress skip
;;
*)
needed="${needed} $n"
echo will copy
progress will copy
;;
esac
done
@ -44,10 +73,11 @@ if test -z "$needed" ; then
exit 1
fi
echo "cd / && cpio -i >/dev/console" >&10
echo "cd ${root_prefix} && cpio -d -i >/dev/console" >&10
find $needed | cpio -H newc -o >&10
find $needed | cpio -H newc -o >&10
echo "date" >&10
# make sure the connection hasn't died
echo "echo finished" >&10
read n <&${remote[0]}
echo $n

View File

@ -20,23 +20,21 @@
out))
(let [(address len preferred valid extra)
(string.match str "(.-)/(%d+),(%d+),(%d+)(.*)$")]
(merge {: address : len : preferred : valid} (parse-extra extra))))
(merge {: address : len
:preferred (or preferred "forever")
:valid (or valid "forever")
}
(parse-extra extra))))
(fn write-addresses [prefix addresses]
(each [_ a (ipairs (split " " addresses))]
(let [address (parse-address a)
suffix (base64url (string.pack "n" (hash a)))
;; keydir should be a function of all the address
;; attributes: we want it to change whenever anything changes
;; so that clients can see which addresses are new without
;; deep table comparisons
keydir (..
prefix
(-> address.address
(: :gsub "::$" "")
(: :gsub ":" "-"))
"_"
suffix)]
(: :gsub ":" "-")))]
(mktree (.. state-directory "/" keydir))
(each [k v (pairs address)]
(write-value (.. keydir "/" k) v)))))

View File

@ -7,8 +7,8 @@ let
name = "openwrt-source";
repo = "openwrt";
owner = "openwrt";
rev = "a5265497a4f6da158e95d6a450cb2cb6dc085cab";
hash = "sha256-YYi4gkpLjbOK7bM2MGQjAyEBuXJ9JNXoz/JEmYf8xE8=";
rev = "refs/tags/v23.05.2";
hash = "sha256-kP+cSOB6LiOMWs7g+ji7P7ehiDYDwRdmT4R5jSzw6K4=";
};
doPatch = family : ''
cp -av ${src}/target/linux/generic/files/* .
@ -34,4 +34,5 @@ in {
applyPatches.ath79 = doPatch "ath79";
applyPatches.ramips = doPatch "ramips";
applyPatches.mediatek = doPatch "mediatek"; # aarch64
applyPatches.mvebu = doPatch "mvebu"; # arm
}

Some files were not shown because too many files have changed in this diff Show More