1
0
forked from dan/liminix

Compare commits

..

16 Commits

Author SHA1 Message Date
Arnout Engelen
69429404ab
tftpboot: explicitly mark phram as mappable 2025-01-02 10:47:12 +01:00
Arnout Engelen
f4369c3afb
Comment wrt fit config 2025-01-02 10:19:59 +01:00
Arnout Engelen
cb3c8702d5
small cleanups 2025-01-02 09:51:26 +01:00
Arnout Engelen
43b71201af
drop tftpboot changes
'traditional' uboot tftp boot works fine as well
2025-01-02 09:45:18 +01:00
Arnout Engelen
80df980fcd
remove debug 2024-12-31 17:08:01 +01:00
Arnout Engelen
e2f8082a7b
Allow flashing 2024-12-31 16:48:10 +01:00
Arnout Engelen
996cf4b472
Make sure to load air_en8811h before bringing up eth0
to make the 2.5G ethernet port work
2024-12-31 12:45:05 +01:00
Arnout Engelen
16a1c5101d
Remove experimental leftovers 2024-12-30 22:18:58 +01:00
Arnout Engelen
d1f9b039f2
Update status 2024-12-30 22:03:03 +01:00
Arnout Engelen
25d4f7b6e8
includePaths 2024-12-30 20:32:00 +01:00
Arnout Engelen
cd845ec34a
follow openwrt more closely 2024-12-30 19:46:54 +01:00
Arnout Engelen
9cf2423b4b
wip 2024-12-30 19:46:53 +01:00
Arnout Engelen
db260ef6b0
use the actual init again 2024-12-30 19:46:53 +01:00
Arnout Engelen
5667f11342
more WiP 2024-12-30 19:46:53 +01:00
Arnout Engelen
e2155d5df3
WiP 2024-12-30 19:46:52 +01:00
Arnout Engelen
6414092300
WIP: OpenWrt One support 2024-12-30 19:46:47 +01:00
28 changed files with 175 additions and 449 deletions

View File

@ -6670,128 +6670,3 @@ Mon Dec 23 18:28:50 GMT 2024
it might be worth moving ubi option decls into the hardware module, if it might be worth moving ubi option decls into the hardware module, if
they're hardware-dependent they're hardware-dependent
Tue Dec 24 16:14:50 GMT 2024
Where next?
a config for haproxy would be good
> a connection or request arrives on a frontend, then the
information carried with this request or connection are processed, and
at this point it is possible to write ACLs-based conditions making use
of these information to decide what backend will process the request.
http://docs.haproxy.org/3.1/intro.html#3.4.4
listen foo
bind :443
frontend foo
mode tcp
Thu Dec 26 14:27:26 GMT 2024
What's the plan?
1) build the updater target for rotuer
2) ssh forward through bordervm to install it
3) carve the ngix sni proxy into examples/module-sniproxy
with a fat warning comment
3.5) should we add the examples to ci?
4) see if it builds
5) using curl on bordervm, see if it forwards
5000) swap the real rotuer hardware
Sun Dec 29 18:22:42 GMT 2024
To make sniproxy work it needs dns, which means it needs an upstream.
But if we move the bordervm cable from lan to wan, we won't be able to
rebuild over ssh unless it's sufficiently unbroken for pppoe to be working
... unless we add a "management" address to the wan interface along with pppoe
to permit wan stuff through the firewall, now that we've fixed the
firewall :embarrassed:, do
/nix/store/*nftables*/bin/nft insert rule table-ip input-ip4 position 19 iifname "wan" jump incoming-allowed-ip4
What else do we need to try rt3200 as prod rotuer?
- pstore logging
- log shipping (maybe via wan to bordervm for now)
- enable sniproxy module
zcat /proc/config.gz | grep PSTORE
Tue Dec 31 22:45:33 GMT 2024
/nix/store/i1khbsqpyx020xrhvfbdazc1bnmirc72-kernel-aarch64-unknown-linux-musl-modulesupport/vmlinux
these 3 derivations will be built:
/nix/store/fvxrvyx64cm86cc4na0584qj9xw6s406-kernel-aarch64-unknown-linux-musl.drv
/nix/store/ksg93bd8x2z1xpfmj24ixm2srg547mjx-dtb-aarch64-unknown-linux-musl.drv
/nix/store/n33ij1npzwjmlsw23sz6yhyrh9hgxwaw-kernel.image-aarch64-unknown-linux-musl.drv
building '/nix/store/fvxrvyx64cm86cc4na0584qj9xw6s406-kernel-aarch64-unknown-linux-musl.drv'...
zcat /proc/config.gz | grep PSTORE
we think tftpboot works (check!)
build the FIT from the updater target with squashfs added in rotuer.nix
boot it with tftp by copy-pasting the boot.scr and changing it
setenv serverip 10.0.0.1
setenv ipaddr 10.0.0.8
tftpboot 0x4007ff28 r2/rootfs; tftpboot 0x41086f28 r2/image; tftpboot 0x4107ff28 r2/dtb
bootm 0x41086f28 - 0x4107ff28
tftpboot works
tftpboot with outputs.uimage works
1458ed2cdeaa6bf4c02c6511a6d7369d /nix/store/4n3jc4n7lsp73yc2ccnmgibc7079rxms-kernel.image-aarch64-unknown-linux-musl
$ grep fit /nix/store/ihi7vski37b9ph4xcyqpabymc5nsngjd-system-configuration-aarch64-unknown-linux-musl/etc/nix-store-paths
/nix/store/5jphs9mnb8hzhvwfi2z8h6cnaz6qx4y6-boot-fit
$ md5sum /nix/store/5jphs9mnb8hzhvwfi2z8h6cnaz6qx4y6-boot-fit/fit
1458ed2cdeaa6bf4c02c6511a6d7369d /nix/store/5jphs9mnb8hzhvwfi2z8h6cnaz6qx4y6-boot-fit/fit
something is changing /persist/boot from a symlink to a directory and I don't know what
... plot twist: or is it? maybe it's ubimage that makes it a directory
rt3200 has no pmsg-size according to dtc -I fs /proc/device-tree/ -O dts
should be more like
reserved-memory {
ramoops@03f00000 {
compatible = "ramoops";
reg = <0x03f00000 0x10000>;
pmsg-size = <0x10000>;
};
};
};
Wed Jan 1 14:57:35 GMT 2025
At last I have working persistent logging.
I think we need to do something at boot time to move the persistent logs into
the regular s6 log thing
foreground {
redirfd -w 1 /run/prior-boot2
elglob file /sys/fs/pstore/* cat $file
}
Thu Jan 2 14:31:11 GMT 2025
to change to a previous "generation" we could run any of
"/nix/store/*system-configuration*/bin/install /mnt" from a rescue
system. It would populate /boot and bin/activate
supposing we are in such a rescue system, how do we find *which*
system-configuration is the one we want to revert to? The derivation
should be pure, so if we're going to timestamp anything we have to do
that in the imperative step i.e. update.sh
perhaps a symlink from /persist/configuration/yyyymmddtmmhhss -> /nix/store/eeee-blah

1
ci.nix
View File

@ -13,7 +13,6 @@ let
"tp-archer-ax23" "tp-archer-ax23"
"zyxel-nwa50ax" "zyxel-nwa50ax"
"turris-omnia" "turris-omnia"
"belkin-rt3200"
]; ];
vanilla = ./vanilla-configuration.nix; vanilla = ./vanilla-configuration.nix;
for-device = name: for-device = name:

View File

@ -33,7 +33,6 @@ let
./modules/busybox.nix ./modules/busybox.nix
./modules/hostname.nix ./modules/hostname.nix
./modules/kernel ./modules/kernel
./modules/logging.nix
./modules/klogd.nix ./modules/klogd.nix
device.module device.module
liminix-config liminix-config

View File

@ -86,25 +86,16 @@
Name: liminix Name: liminix
Character device major/minor: 250:8 Character device major/minor: 250:8
root@OpenWrt:~# ubiupdatevol /dev/ubi0_7 /tmp/rootfs root@OpenWrt:~# ubiupdatevol /dev/ubi0_7 /tmp/rootfs
root@OpenWrt:~# fw_setenv orig_boot_production $(fw_printenv boot_production | sed -E 's/.+?=//')
To make the new system bootable we also need to change some U-Boot variables.
``boot_production`` needs to mount the filesystem and boot the FIT image
found there, and :code:`bootcmd` needs to be told _not_ to boot the rescue
image if there are records in pstore, because that interferes with
``config.log.persistent``
root@OpenWrt:~# fw_setenv orig_boot_production $(fw_printenv -n boot_production)
root@OpenWrt:~# fw_setenv orig_bootcmd $(fw_printenv -n bootcmd)
root@OpenWrt:~# fw_setenv boot_production 'led $bootled_pwr on ; ubifsmount ubi0:liminix && ubifsload ''${loadaddr} boot/fit && bootm ''${loadaddr}' root@OpenWrt:~# fw_setenv boot_production 'led $bootled_pwr on ; ubifsmount ubi0:liminix && ubifsload ''${loadaddr} boot/fit && bootm ''${loadaddr}'
root@OpenWrt:~# fw_setenv bootcmd 'run boot_ubi'
For subsequent Liminix reinstalls, just run the
:command:`ubiupdatevol` command again. You don't need to repeat For subsequent Liminix reinstalls, you don't need to repeat the
the "Preparation" step and in fact should seek to avoid it if "Preparation" step and in fact should seek to avoid it if
possible, as it will reset the erase counters used for write possible. Updating volumes with :command:`ubiupdatevol` will
levelling. Using UBI-aware tools is therefore preferred over any preserve the erase counters used for write levelling, so is
kind of "factory" wipe which will reset them. preferred over any kind of "factory" wipe which will reset them.
''; '';
system = { system = {
crossSystem = { crossSystem = {
@ -113,8 +104,7 @@
}; };
module = {pkgs, config, lib, lim, ... }: module = {pkgs, config, lib, lim, ... }:
let inherit (lib) mkIf; let firmware = pkgs.stdenv.mkDerivation {
firmware = pkgs.stdenv.mkDerivation {
name = "wlan-firmware"; name = "wlan-firmware";
phases = ["installPhase"]; phases = ["installPhase"];
installPhase = '' installPhase = ''
@ -122,7 +112,6 @@
cp ${pkgs.linux-firmware}/lib/firmware/mediatek/{mt7915,mt7615,mt7622}* $out cp ${pkgs.linux-firmware}/lib/firmware/mediatek/{mt7915,mt7615,mt7622}* $out
''; '';
}; };
openwrt = pkgs.openwrt_24_10;
in { in {
imports = [ imports = [
../../modules/arch/aarch64.nix ../../modules/arch/aarch64.nix
@ -132,10 +121,8 @@
config = { config = {
kernel = { kernel = {
extraPatchPhase = '' extraPatchPhase = ''
${openwrt.applyPatches.mediatek} ${pkgs.openwrt.applyPatches.mediatek}
''; '';
src = openwrt.kernelSrc;
version = openwrt.kernelVersion;
config = { config = {
PCI = "y"; PCI = "y";
ARCH_MEDIATEK = "y"; ARCH_MEDIATEK = "y";
@ -146,8 +133,8 @@
MTK_INFRACFG = "y"; MTK_INFRACFG = "y";
MTK_PMIC_WRAP = "y"; MTK_PMIC_WRAP = "y";
DMADEVICES = "y"; NVMEM_MTK_EFUSE="y";
MTK_HSDMA="y"; # MTK_HSDMA="y";
MTK_SCPSYS="y"; MTK_SCPSYS="y";
MTK_SCPSYS_PM_DOMAINS="y"; MTK_SCPSYS_PM_DOMAINS="y";
# MTK_THERMAL="y"; # MTK_THERMAL="y";
@ -193,10 +180,6 @@
MTD_SPLIT_FIRMWARE= "y"; MTD_SPLIT_FIRMWARE= "y";
MTD_SPLIT_FIT_FW= "y"; MTD_SPLIT_FIT_FW= "y";
MTD_UBI_NVMEM = "y";
NVMEM_MTK_EFUSE = "y";
NVMEM_BLOCK = "y";
NVMEM_LAYOUT_ADTRAN = "y";
MMC = "y"; MMC = "y";
MMC_BLOCK = "y"; MMC_BLOCK = "y";
@ -208,7 +191,6 @@
NET_DSA="y"; NET_DSA="y";
NET_DSA_MT7530="y"; NET_DSA_MT7530="y";
NET_DSA_TAG_MTK="y"; NET_DSA_TAG_MTK="y";
NET_DSA_MT7530_MDIO="y";
SERIAL_8250 = "y"; SERIAL_8250 = "y";
SERIAL_8250_CONSOLE = "y"; SERIAL_8250_CONSOLE = "y";
@ -231,7 +213,7 @@
}; };
boot = { boot = {
commandLine = [ "console=ttyS0,115200" ]; commandLine = [ "console=ttyS0,115200" ];
tftp.loadAddress = lim.parseInt "0x48000000"; tftp.loadAddress = lim.parseInt "0x4007ff28";
imageFormat = "fit"; imageFormat = "fit";
loader.fit.enable = lib.mkDefault true; # override this if you are building tftpboot loader.fit.enable = lib.mkDefault true; # override this if you are building tftpboot
}; };
@ -249,6 +231,7 @@
hardware = hardware =
let let
openwrt = pkgs.openwrt;
mac80211 = pkgs.kmodloader.override { mac80211 = pkgs.kmodloader.override {
targets = ["mt7615e" "mt7915e"]; targets = ["mt7615e" "mt7915e"];
inherit (config.system.outputs) kernel; inherit (config.system.outputs) kernel;
@ -276,9 +259,6 @@
"${openwrt.src}/target/linux/mediatek/dts" "${openwrt.src}/target/linux/mediatek/dts"
"${config.system.outputs.kernel.modulesupport}/arch/arm64/boot/dts/mediatek/" "${config.system.outputs.kernel.modulesupport}/arch/arm64/boot/dts/mediatek/"
]; ];
includes = mkIf config.logging.persistent.enable [
./pstore-pmsg.dtsi
];
}; };
# - 0x000000000000-0x000008000000 : "spi-nand0" # - 0x000000000000-0x000008000000 : "spi-nand0"

View File

@ -1,8 +0,0 @@
/ {
reserved-memory {
/* make sure address matches upstream */
ramoops@42ff0000 {
pmsg-size = <0x10000>;
};
};
};

View File

@ -50,14 +50,13 @@
module = {pkgs, config, lib, lim, ... }: module = {pkgs, config, lib, lim, ... }:
let let
openwrt = pkgs.openwrt_24_10;
mediatek-firmware = pkgs.stdenv.mkDerivation { mediatek-firmware = pkgs.stdenv.mkDerivation {
name = "wlan-firmware"; name = "wlan-firmware";
phases = ["installPhase"]; phases = ["installPhase"];
installPhase = '' installPhase = ''
mkdir $out mkdir $out
cp ${pkgs.linux-firmware}/lib/firmware/mediatek/{mt7915,mt7615,mt7986_eeprom_mt7976,mt7981}* $out cp ${pkgs.openwrt.linux-firmware}/lib/firmware/mediatek/{mt7915,mt7615,mt7986_eeprom_mt7976,mt7981}* $out
''; '';
}; };
airoha-firmware = pkgs.stdenv.mkDerivation { airoha-firmware = pkgs.stdenv.mkDerivation {
@ -66,7 +65,7 @@
installPhase = '' installPhase = ''
mkdir $out mkdir $out
cp ${pkgs.linux-firmware}/lib/firmware/airoha/* $out cp ${pkgs.openwrt.linux-firmware}/lib/firmware/airoha/* $out
''; '';
}; };
in { in {
@ -76,10 +75,8 @@
]; ];
config = { config = {
kernel = { kernel = {
src = openwrt.kernelSrc;
version = openwrt.kernelVersion;
extraPatchPhase = '' extraPatchPhase = ''
${openwrt.applyPatches.mediatek} ${pkgs.openwrt.applyPatches.mediatek}
''; '';
config = { config = {
NET="y"; # unlock NET_XGRESS NET="y"; # unlock NET_XGRESS
@ -596,6 +593,7 @@
hardware = hardware =
let let
openwrt = pkgs.openwrt;
phy = pkgs.kmodloader.override { phy = pkgs.kmodloader.override {
targets = [ targets = [
"air_en8811h" "air_en8811h"
@ -660,9 +658,7 @@
defaultOutput = "uimage"; defaultOutput = "uimage";
loadAddress = lim.parseInt "0x44000000"; loadAddress = lim.parseInt "0x44000000";
entryPoint = lim.parseInt "0x44000000"; entryPoint = lim.parseInt "0x44000000";
# TODO AFAICT this should be 2048, but I got 'FIT: image rootfs-1 start not aligned to page boundaries' with that... alignment = 2048;
#alignment = 2048;
alignment = 4096;
rootDevice = "/dev/fit0"; rootDevice = "/dev/fit0";
dts = { dts = {
src = "${openwrt.src}/target/linux/mediatek/dts/mt7981b-openwrt-one.dts"; src = "${openwrt.src}/target/linux/mediatek/dts/mt7981b-openwrt-one.dts";

View File

@ -175,9 +175,6 @@
]; ];
config = { config = {
rootfsType = lib.mkDefault "btrfs"; # override this if you are building tftpboot
rootOptions = lib.mkDefault "subvol=@";
services.mtd-name-links = mtd_by_name_links; services.mtd-name-links = mtd_by_name_links;
kernel = { kernel = {
src = pkgs.pkgsBuildBuild.fetchurl { src = pkgs.pkgsBuildBuild.fetchurl {
@ -295,7 +292,6 @@
}; };
}; };
boot = { boot = {
loader.extlinux.enable = lib.mkDefault true; # override this if you are building tftpboot
commandLine = [ commandLine = [
"console=ttyS0,115200" "console=ttyS0,115200"
"pcie_aspm=off" # ath9k pci incompatible with PCIe ASPM "pcie_aspm=off" # ath9k pci incompatible with PCIe ASPM

View File

@ -145,8 +145,17 @@ to :file:`/dev/pmsg0` as well as to the regular log. This is a
circular buffer, so when it fills up newer messages will overwrite the circular buffer, so when it fills up newer messages will overwrite the
oldest messages. oldest messages.
Logs found in pstore after a reboot will be moved at startup to To check the previous messages after a (planned or forced) reboot,
:file:`/run/log/previous-boot` you need to mooun the pstore filesystem.
.. code-block:: console
# mount -t pstore pstore /sys/fs/pstore/
# ls -l /sys/fs/pstore/
-r--r--r-- 1 43071 pmsg-ramoops-0
# cat /sys/fs/pstore/pmsg-ramoops-0
@40000000000000282c997d29 mydevice klogd <6>[ 30.793756] int: port 2(wlan0) entered blocking state
[log messages from before the reboot follow]
@ -188,54 +197,16 @@ the current system closure. Note that Liminix does not have the NixOS
concept of environments or generations, and there is no way back from concept of environments or generations, and there is no way back from
this except for building the previous configuration again. this except for building the previous configuration again.
Caveats Caveats
------- -------
* it needs there to be enough free space on the device for all the new * it needs there to be enough free space on the device for all the new
packages in addition to all the packages already on it - which may packages in addition to all the packages already on it - which may be
be a problem if there is little flash storage or if a lot of things a problem if a lot of things have changed (e.g. a new version of
have changed (e.g. a new version of nixpkgs). nixpkgs).
* it may not be able to upgrade the kernel: this is device-dependent.
If your device boots from a kernel image on a raw MTD partition or
or UBI volume, update.sh is unable to alter the kernel partition.
If your device boots from a kernel inside the filesystem (e.g. using
bootloader.extlinux or bootloder.fit) then the kernel will be
upgraded along with the userland
Recovery/downgrades
-------------------
The :command:`update.sh` script also creates a timestamped symlink on
the device which points to the system configuration it installs. If
you install a configuration that doesn't work, you can revert to any
other installed configuration by
1) booting to some kind of rescue or recovery system (which may be
some vendor-provided rescue option, or your own recovery system
perhaps based on :file:`examples/recovery.nix`) and mounting
your Liminix filesystem on /mnt
2) picking another previously-installed configuration that _did_ work,
and switching back to it:
.. code-block:: console
# ls -ld /mnt/*configuration
lrwxrwxrwx 1 90 /mnt/20252102T182104.configuration -> nix/store/v1w0h4zw65ah4c2r0k7nyy125qrxhq78-system-configuration-aarch64-unknown-linux-musl
lrwxrwxrwx 1 90 /mnt/20251802T181822.configuration -> nix/store/wqjl9s9xljl2wg8257292zghws9ssidk-system-configuration-aarch64-unknown-linux-musl
# : 20251802T181822 is the working system, so reinstall it
# /mnt/20251802T181822.configuration/bin/install /mnt
# umount /mnt
# reboot
This will install the previous configuration's activation binary into
/bin, and copy its kernel and initramfs into /boot. Note that it
depends on the previous system not having been garbage-collected.
* it cannot upgrade the kernel, only userland
.. _levitate: .. _levitate:

View File

@ -116,8 +116,8 @@ TFTP server you're using and so is out of scope for this document.
Building and installing the image Buildiing and installing the image
================================= ==================================
Follow the device-specific instructions for "TFTP install": usually, Follow the device-specific instructions for "TFTP install": usually,
the steps are the steps are

View File

@ -1,19 +0,0 @@
{ config, lib, ... }:
let
inherit (lib) mkIf mkEnableOption mkOption types;
in {
options = {
logging = {
persistent = {
enable = mkEnableOption "store logs across reboots";
};
};
};
config = {
kernel.config = mkIf config.logging.persistent.enable {
PSTORE = "y";
PSTORE_PMSG = "y";
PSTORE_RAM = "y";
};
};
}

View File

@ -11,16 +11,14 @@ let
in in
{ {
imports = [ imports = [
./outputs/squashfs.nix
./outputs/jffs2.nix
./outputs/vmroot.nix
./outputs/boot-extlinux.nix ./outputs/boot-extlinux.nix
./outputs/boot-fit.nix ./outputs/boot-fit.nix
./outputs/btrfs.nix
./outputs/jffs2.nix
# ./outputs/mtdimage.nix
./outputs/squashfs.nix
./outputs/ubimage.nix
./outputs/uimage.nix ./outputs/uimage.nix
./outputs/updater ./outputs/updater
./outputs/vmroot.nix ./outputs/ubimage.nix
]; ];
options = { options = {
system.outputs = { system.outputs = {

View File

@ -60,7 +60,6 @@ in {
config = { config = {
kernel = { kernel = {
config = { config = {
# this needs to be conditional on "not qemu"
MTD_SPLIT_UIMAGE_FW = "y"; MTD_SPLIT_UIMAGE_FW = "y";
} // lib.optionalAttrs (pkgs.stdenv.isMips) { } // lib.optionalAttrs (pkgs.stdenv.isMips) {
# https://stackoverflow.com/questions/26466470/can-the-logical-erase-block-size-of-an-mtd-device-be-increased # https://stackoverflow.com/questions/26466470/can-the-logical-erase-block-size-of-an-mtd-device-be-increased

View File

@ -121,7 +121,7 @@ in {
node=$(printf "phram-rootfs@%x" $rootfsStart) node=$(printf "phram-rootfs@%x" $rootfsStart)
fdtput -p -t s dtb /reserved-memory/$node compatible phram fdtput -p -t s dtb /reserved-memory/$node compatible phram
fdtput -p -t lx dtb /reserved-memory/$node reg $ac_prefix $(hex $rootfsStart) $sz_prefix $(hex $rootfsSize) fdtput -p -t lx dtb /reserved-memory/$node reg $ac_prefix $(hex $rootfsStart) $sz_prefix $(hex $rootfsSize)
fdtput -p dtb /reserved-memory/$node no-map fdtput -p -t i dtb /reserved-memory/$node no-map 0
cmd="liminix ${cmdline} mtdparts=phram0:''${rootfsSize}(rootfs) phram.phram=phram0,''${rootfsStart},''${rootfsSize},${toString config.hardware.flash.eraseBlockSize} root=/dev/mtdblock0"; cmd="liminix ${cmdline} mtdparts=phram0:''${rootfsSize}(rootfs) phram.phram=phram0,''${rootfsStart},''${rootfsSize},${toString config.hardware.flash.eraseBlockSize} root=/dev/mtdblock0";
fdtput -t s dtb /chosen ${config.boot.commandLineDtbNode} "$cmd" fdtput -t s dtb /chosen ${config.boot.commandLineDtbNode} "$cmd"

View File

@ -7,12 +7,10 @@
let let
inherit (lib) mkIf mkOption types; inherit (lib) mkIf mkOption types;
cfg = config.boot.tftp; cfg = config.boot.tftp;
instructions = pkgs.writeText "flash.scr" '' instructions = pkgs.writeText "env.scr" ''
setenv serverip ${cfg.serverip} setenv serverip ${cfg.serverip}
setenv ipaddr ${cfg.ipaddr} setenv ipaddr ${cfg.ipaddr}
setenv loadaddr ${lib.toHexString cfg.loadAddress} setenv loadaddr ${lib.toHexString cfg.loadAddress}
tftpboot $loadaddr result/rootfs
ubi write $loadaddr liminix $filesize
''; '';
in { in {
options.system.outputs = { options.system.outputs = {
@ -65,20 +63,18 @@ Now we can make our new root volume
uboot> ubi create liminix - uboot> ubi create liminix -
3) transfer the root filesystem from the build system and write it to 3) transfer the root filesystem from the build system and write it
the new volume. Paste the contents of :file:`result/flash.scr` one line at a time to the new volume. Paste the environment variable settings from
into U-Boot: :file:`result/env.scr` into U-Boot, then run
.. code-block:: console .. code-block:: console
uboot> setenv serverip 10.0.0.1 uboot> tftpboot ''${loadaddr} result/rootfs
uboot> setenv ipaddr 10.0.0.8 uboot> ubi write ''${loadaddr} liminix $filesize
uboot> setenv loadaddr 4007FF28
uboot> tftpboot $loadaddr result/rootfs
uboot> ubi write $loadaddr liminix $filesize
Now we have the root filesystem installed on the device. You Now we have the root filesystem installed on the device. You
can even mount it and poke around using :command:`ubifsmount ubi0:liminix; ubifsls /` can even mount it and poke around using ``ubifsmount ubi0:liminix;
ubifsls /``
4) optional: before you configure the device to boot into Liminix 4) optional: before you configure the device to boot into Liminix
automatically, you can try booting it by hand to see if it works: automatically, you can try booting it by hand to see if it works:
@ -93,11 +89,20 @@ Once you've done this and you're happy with it, reset the device to
return to U-Boot. return to U-Boot.
5) Instructions for configuring autoboot are likely to be very 5) Instructions for configuring autoboot are likely to be very
device-dependent and you should consult the Liminix documentation for device-dependent. On the Linksys E8450/Belkin RT3200, the environment
your device. (If you're bringing up a new device, some detective work variable `boot_production` governs what happens on a normal boot, so
may be needed. Try running `printenv` and trace through the flow of you could do
execution from (probably) :command:`$bootcmd` and look for a suitable
variable to change) .. code-block:: console
uboot> setenv orig_boot_production $boot_production
uboot> setenv boot_production 'led $bootled_pwr on ; ubifsmount ubi0:liminix && ubifsload ''${loadaddr} boot/fit && bootm ''${loadaddr}'
uboot> saveenv
uboot> reset
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 6) Now you can reboot the device into Liminix
@ -115,6 +120,6 @@ variable to change)
mkdir $out mkdir $out
cd $out cd $out
ln -s ${o.rootfs} rootfs ln -s ${o.rootfs} rootfs
ln -s ${instructions} flash.scr ln -s ${instructions} env.scr
''; '';
} }

View File

@ -27,8 +27,7 @@ in
config.system.outputs.updater = config.system.outputs.updater =
runCommand "buildUpdater" { } '' runCommand "buildUpdater" { } ''
mkdir -p $out/bin $out/etc mkdir -p $out/bin
cp ${o.kernel.config} $out/etc/kconfig
substitute ${./update.sh} $out/bin/update.sh \ substitute ${./update.sh} $out/bin/update.sh \
--subst-var-by toplevel ${o.systemConfiguration} \ --subst-var-by toplevel ${o.systemConfiguration} \
--subst-var-by min_copy_closure ${min-copy-closure} --subst-var-by min_copy_closure ${min-copy-closure}

View File

@ -37,8 +37,8 @@ echo installing from systemConfiguration $toplevel to host $target_host
$ssh_command $target_host uname -a || die "Can't ssh to $target_host" $ssh_command $target_host uname -a || die "Can't ssh to $target_host"
min-copy-closure $target_host $toplevel min-copy-closure $target_host $toplevel
ts=$(date +%Y%m%dT%H%M%S) set -x
$ssh_command $target_host "$toplevel/bin/install && ln -s $(realpath --relative-to / $toplevel) /persist/${ts}.configuration" $ssh_command $target_host $toplevel/bin/install
case "$reboot" in case "$reboot" in
reboot) reboot)
$ssh_command $target_host "sync; source /etc/profile; reboot" $ssh_command $target_host "sync; source /etc/profile; reboot"

View File

@ -17,7 +17,7 @@ let
logger = logger =
let pipecmds = let pipecmds =
["${s6}/bin/s6-log -bpd3 -- ${cfg.script} 1"] ++ ["${s6}/bin/s6-log -bpd3 -- ${cfg.script} 1"] ++
(lib.optional (cfg ? persistent && cfg.persistent.enable) (lib.optional cfg.persistent.enable
"/bin/tee /dev/pmsg0") ++ "/bin/tee /dev/pmsg0") ++
(lib.optional cfg.shipping.enable (lib.optional cfg.shipping.enable
"${pkgs.logshipper}/bin/logtap ${cfg.shipping.socket} logshipper-socket-event"); "${pkgs.logshipper}/bin/logtap ${cfg.shipping.socket} logshipper-socket-event");
@ -215,6 +215,9 @@ let
in { in {
options = { options = {
logging = { logging = {
persistent = {
enable = mkEnableOption "store logs across reboots";
};
shipping = { shipping = {
enable = mkEnableOption "unix socket for log shipping"; enable = mkEnableOption "unix socket for log shipping";
socket = mkOption { socket = mkOption {
@ -266,6 +269,11 @@ in {
)]; )];
config = { config = {
kernel.config = mkIf config.logging.persistent.enable {
PSTORE = "y";
PSTORE_PMSG = "y";
PSTORE_RAM = "y";
};
filesystem = dir { filesystem = dir {
etc = dir { etc = dir {
s6-rc = dir { s6-rc = dir {

View File

@ -22,11 +22,6 @@ mount -t tmpfs none /tmp
mkdir /dev/pts mkdir /dev/pts
mount -t devpts none /dev/pts mount -t devpts none /dev/pts
if test -c /dev/pmsg0 ; then
mount -t pstore none /sys/fs/pstore
(cat /sys/fs/pstore/* && rm /sys/fs/pstore/*) > /run/log/previous-boot
fi
mkdir -m 0751 -p /run/services/outputs mkdir -m 0751 -p /run/services/outputs
chgrp system /run/services/outputs chgrp system /run/services/outputs

View File

@ -100,7 +100,6 @@ in {
odhcp-script = callPackage ./odhcp-script { }; odhcp-script = callPackage ./odhcp-script { };
odhcp6c = callPackage ./odhcp6c { }; odhcp6c = callPackage ./odhcp6c { };
openwrt = callPackage ./openwrt { }; openwrt = callPackage ./openwrt { };
openwrt_24_10 = callPackage ./openwrt/2410.nix { };
output-template = callPackage ./output-template { }; output-template = callPackage ./output-template { };
ppp = callPackage ./ppp { }; ppp = callPackage ./ppp { };
pppoe = callPackage ./pppoe { }; pppoe = callPackage ./pppoe { };

View File

@ -45,7 +45,7 @@ stdenv.mkDerivation rec {
dontStrip = true; dontStrip = true;
dontPatchELF = true; dontPatchELF = true;
outputs = ["out" "headers" "modulesupport" "config"] ++ targetNames; outputs = ["out" "headers" "modulesupport"] ++ targetNames;
phases = [ phases = [
"unpackPhase" "unpackPhase"
"butcherPkgconfig" "butcherPkgconfig"
@ -114,6 +114,5 @@ stdenv.mkDerivation rec {
mkdir -p $modulesupport mkdir -p $modulesupport
make modules make modules
cp -a . $modulesupport cp -a . $modulesupport
cp .config $config
''; '';
} }

View File

@ -40,12 +40,12 @@
}; };
configurations { configurations {
// The OpenWRT One wants this to be 'config-1' specifically. For now it's // The OpenWRT One wants this to be 'conf-1' specifically. For now it's
// easy to just choose that, if there's another device that has a // easy to just choose that, if there's another device that has a
// different restriction then we should probably add 'if not found // different restriction then we should probably add 'if not found
// select default' logic and/or make this configurable. // select default' logic and/or make this configurable.
default = "config-1"; default = "conf-1";
config-1 { conf-1 {
description = "Boot Linux kernel with FDT blob"; description = "Boot Linux kernel with FDT blob";
kernel = "kernel"; kernel = "kernel";
fdt = "fdt-1"; fdt = "fdt-1";

View File

@ -89,7 +89,6 @@ in {
}; };
}; };
_VARS _VARS
echo mkimage -f mkimage.its -E ${lib.optionalString (alignment != null) "-B 0x${lib.toHexString alignment}"} kernel.uimage
mkimage -f mkimage.its -E ${lib.optionalString (alignment != null) "-B 0x${lib.toHexString alignment}"} kernel.uimage mkimage -f mkimage.its -E ${lib.optionalString (alignment != null) "-B 0x${lib.toHexString alignment}"} kernel.uimage
mkimage -l kernel.uimage mkimage -l kernel.uimage
''; '';

View File

@ -35,24 +35,24 @@ int open_shipper_socket(char *pathname) {
static int fail_count = 0; static int fail_count = 0;
struct sockaddr_un sa = { struct sockaddr_un sa = {
.sun_family = AF_LOCAL .sun_family = AF_LOCAL
}; };
strncpy(sa.sun_path, pathname, sizeof(sa.sun_path) - 1); strncpy(sa.sun_path, pathname, sizeof(sa.sun_path) - 1);
fd = socket(AF_LOCAL, SOCK_STREAM, 0); fd = socket(AF_LOCAL, SOCK_STREAM, 0);
if(fd >= 0) { if(fd >= 0) {
if(connect(fd, (struct sockaddr *) &sa, sizeof sa)) { if(connect(fd, (struct sockaddr *) &sa, sizeof sa)) {
if((fail_count % 30) == 0) { if((fail_count % 30) == 0)
printf(PROGRAM_NAME ": cannot connect socket \"%s\": %s\n", printf(PROGRAM_NAME ": cannot connect socket \"%s\": %s\n",
pathname, pathname,
strerror(errno)); strerror(errno));
}
fail_count++; fail_count++;
close(fd); close(fd);
return -1; return -1;
} }
int flags = fcntl(fd, F_GETFL); int flags = fcntl(fd, F_GETFL);
fcntl(fd, F_SETFL, flags | O_NONBLOCK); fcntl(fd, F_SETFL, flags | O_NONBLOCK);
} }
return fd; return fd;
} }
@ -75,7 +75,7 @@ int main(int argc, char * argv[]) {
int tee_bytes = 0; int tee_bytes = 0;
if(argc != 3) { if(argc != 3) {
error(1, 0, "usage: " PROGRAM_NAME " /path/to/socket cookie-text"); error(1, 0, "usage: " PROGRAM_NAME " /path/to/socket cookie-text");
} }
char * socket_pathname = argv[1]; char * socket_pathname = argv[1];
char * cookie = argv[2]; char * cookie = argv[2];
@ -83,8 +83,8 @@ int main(int argc, char * argv[]) {
char * stop_cookie = malloc(strlen(cookie) + 7); char * stop_cookie = malloc(strlen(cookie) + 7);
if(strlen(socket_pathname) > 108) { if(strlen(socket_pathname) > 108) {
error(1, 0, "socket pathname \"%s\" is too long, max 108 bytes", error(1, 0, "socket pathname \"%s\" is too long, max 108 bytes",
socket_pathname); socket_pathname);
}; };
strcpy(start_cookie, cookie); strcat(start_cookie, " START\n"); strcpy(start_cookie, cookie); strcat(start_cookie, " START\n");
@ -97,46 +97,46 @@ int main(int argc, char * argv[]) {
int quitting = 0; int quitting = 0;
while(! quitting) { while(! quitting) {
int nfds = poll(fds, 3, 2000); int nfds = poll(fds, 3, 2000);
if(nfds > 0) { if(nfds > 0) {
if((fds[0].revents & (POLLIN|POLLHUP)) && if((fds[0].revents & (POLLIN|POLLHUP)) &&
(out_bytes == 0) && (out_bytes == 0) &&
(tee_bytes == 0)) { (tee_bytes == 0)) {
out_bytes = read(fds[0].fd, buf, 8192); out_bytes = read(fds[0].fd, buf, 8192);
if(out_bytes == 0) { if(out_bytes == 0) {
quitting = 1; quitting = 1;
buf = PROGRAM_NAME " detected eof of file on stdin, exiting\n"; buf = PROGRAM_NAME " detected eof of file on stdin, exiting\n";
out_bytes = strlen(buf); out_bytes = strlen(buf);
}; };
if(is_connected()) tee_bytes = out_bytes; if(is_connected()) tee_bytes = out_bytes;
}; };
if(out_bytes) { if(out_bytes) {
out_bytes -= write(fds[1].fd, buf, out_bytes); out_bytes -= write(fds[1].fd, buf, out_bytes);
}; };
if(fds[1].revents & (POLLERR|POLLHUP)) { if(fds[1].revents & (POLLERR|POLLHUP)) {
exit(1); // can't even log an error if the logging stream fails exit(1); // can't even log an error if the logging stream fails
}; };
if(is_connected()) { if(is_connected()) {
if(tee_bytes) { if(tee_bytes) {
tee_bytes -= write(fds[2].fd, buf, tee_bytes); tee_bytes -= write(fds[2].fd, buf, tee_bytes);
}; };
if(fds[2].revents & (POLLERR|POLLHUP)) { if(fds[2].revents & (POLLERR|POLLHUP)) {
close(fds[2].fd); close(fds[2].fd);
fds[2].fd = -1; fds[2].fd = -1;
(void) write(1, stop_cookie, strlen(stop_cookie)); (void) write(1, stop_cookie, strlen(stop_cookie));
}; };
}; };
} else { } else {
if(! is_connected()) { if(! is_connected()) {
fds[2].fd = open_shipper_socket(argv[1]); fds[2].fd = open_shipper_socket(argv[1]);
if(is_connected()) { if(is_connected()) {
/* write cookie to stdout so that the backfill /* write cookie to stdout so that the backfill
* process knows we are now logging realtime * process knows we are now logging realtime
*/ */
write(fds[1].fd, start_cookie, strlen(start_cookie)); write(fds[1].fd, start_cookie, strlen(start_cookie));
} }
} }
}; };
}; };
} }

View File

@ -1,68 +0,0 @@
{ fetchFromGitHub, pkgsBuildBuild, lib }:
let
src = fetchFromGitHub {
name = "openwrt-source";
repo = "openwrt";
owner = "openwrt";
rev = "refs/tags/v24.10.0-rc4";
hash = "sha256-7edkUCTfGnZeMWr/aXoQrP4I47iXhMi/gUxO2SR+Ylc=";
};
kernelVersion = "6.6.67";
kernelSeries = lib.versions.majorMinor kernelVersion;
doPatch = family: ''
cp -av ${src}/target/linux/generic/files/* .
chmod -R u+w .
cp -av ${src}/target/linux/${family}/files/* .
chmod -R u+w .
test -d ${src}/target/linux/${family}/files-${kernelSeries}/ && cp -av ${src}/target/linux/${family}/files-${kernelSeries}/* .
chmod -R u+w .
patches() {
for i in $* ; do patch --batch --forward -p1 < $i ;done
}
patches ${src}/target/linux/generic/backport-${kernelSeries}/*.patch
patches ${src}/target/linux/generic/pending-${kernelSeries}/*.patch
patches ${src}/target/linux/generic/hack-${kernelSeries}/*.patch
patches ${src}/target/linux/${family}/patches-${kernelSeries}/*.patch
patches \
${./make-mtdsplit-jffs2-endian-agnostic.patch} \
${./fix-mtk-wed-bm-desc-ptr.patch}
'';
in {
inherit src;
# The kernel sources typically used with this version of openwrt
# You can find this in `include/kernel-5.15` or similar in the
# openwrt sources
kernelSrc = pkgsBuildBuild.fetchurl {
name = "linux.tar.gz";
url = "https://cdn.kernel.org/pub/linux/kernel/v${lib.versions.major kernelVersion}.x/linux-${kernelVersion}.tar.gz";
hash = "sha256-Vj6O6oa83xzAF3FPl6asQK2Zrl7PaBCVjcUDq93caL4=";
};
inherit kernelVersion;
applyPatches.ath79 = doPatch "ath79";
applyPatches.ramips = doPatch "ramips";
applyPatches.mediatek = doPatch "mediatek"; # aarch64
applyPatches.mvebu = doPatch "mvebu"; # arm
applyPatches.rt2x00 = ''
PATH=${pkgsBuildBuild.patchutils}/bin:$PATH
for i in ${src}/package/kernel/mac80211/patches/rt2x00/6*.patch ; do
fixed=$(basename $i).fixed
sed '/depends on m/d' < $i | sed 's/CPTCFG_/CONFIG_/g' | recountdiff | filterdiff -x '*/local-symbols' > $fixed
case $fixed in
606-*)
;;
611-*)
filterdiff -x '*/rt2x00.h' < $fixed | patch --forward -p1
;;
601-*|607-*)
filterdiff -x '*/rt2x00_platform.h' < $fixed | patch --forward -p1
;;
*)
cat $fixed | patch --forward -p1
;;
esac
done
'';
}

View File

@ -1,44 +1,55 @@
{ fetchFromGitHub, pkgsBuildBuild }: { fetchFromGitHub, pkgsBuildBuild, linux-firmware, fetchzip }:
let let
src = fetchFromGitHub { src = fetchFromGitHub {
name = "openwrt-source"; name = "openwrt-source";
repo = "openwrt"; repo = "openwrt";
owner = "openwrt"; owner = "openwrt";
rev = "refs/tags/v23.05.2"; # snapshot my OpenWRT One came with
hash = "sha256-kP+cSOB6LiOMWs7g+ji7P7ehiDYDwRdmT4R5jSzw6K4="; rev = "3098b4bf0725509aee13fe1560ce5a9188ea2fc7";
hash = "sha256-we61HQ+XppOOw1AhQjNZtmN4IJDsV+dmKT/d9341jJs=";
}; };
doPatch = family: '' doPatch = family: ''
cp -av ${src}/target/linux/generic/files/* . cp -av ${src}/target/linux/generic/files/* .
chmod -R u+w . chmod -R u+w .
cp -av ${src}/target/linux/${family}/files/* . cp -av ${src}/target/linux/${family}/files/* .
chmod -R u+w . chmod -R u+w .
test -d ${src}/target/linux/${family}/files-5.15/ && cp -av ${src}/target/linux/${family}/files-5.15/* . test -d ${src}/target/linux/${family}/files-6.6/ && cp -av ${src}/target/linux/${family}/files-6.6/* .
chmod -R u+w . chmod -R u+w .
patches() { patches() {
for i in $* ; do patch --batch --forward -p1 < $i ;done for i in $* ; do patch --batch --forward -p1 < $i || exit 1;done
} }
patches ${src}/target/linux/generic/backport-5.15/*.patch patches ${src}/target/linux/generic/backport-6.6/*.patch
patches ${src}/target/linux/generic/pending-5.15/*.patch # missing from backport-6.6/752-*?
patch -p0 < ${./mtk_rename.patch}
patches ${src}/target/linux/generic/pending-6.6/*.patch
# This patch breaks passing the DTB to kexeced kernel, so let's # This patch breaks passing the DTB to kexeced kernel, so let's
# get rid of it. It's not needed anyway as we pass the cmdline # get rid of it. It's not needed anyway as we pass the cmdline
# in the dtb # in the dtb
patch --batch -p1 --reverse < ${src}/target/linux/generic/pending-5.15/330-MIPS-kexec-Accept-command-line-parameters-from-users.patch patch --batch -p1 --reverse < ${src}/target/linux/generic/pending-6.6/330-MIPS-kexec-Accept-command-line-parameters-from-users.patch
patches ${src}/target/linux/generic/hack-5.15/*.patch patches ${src}/target/linux/generic/hack-6.6/*.patch
patches ${src}/target/linux/${family}/patches-5.15/*.patch patches ${src}/target/linux/${family}/patches-6.6/*.patch
patches ${./make-mtdsplit-jffs2-endian-agnostic.patch} patches ${./make-mtdsplit-jffs2-endian-agnostic.patch}
''; '';
in { in {
inherit src; inherit src;
# The kernel sources typically used with this version of openwrt # The kernel sources typically used with this version of openwrt
# You can find this in `include/kernel-5.15` or similar in the # You can find this in `include/kernel-6.6` or similar in the
# openwrt sources # openwrt sources
kernelSrc = pkgsBuildBuild.fetchurl { kernelSrc = pkgsBuildBuild.fetchurl {
name = "linux.tar.gz"; name = "linux.tar.gz";
url = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.137.tar.gz"; url = "https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.6.57.tar.gz";
hash = "sha256-PkdzUKZ0IpBiWe/RS70J76JKnBFzRblWcKlaIFNxnHQ="; hash = "sha256-LP9tktb/HX5LPZt6m7FO9k38g31tyl714kqV0j4NTmc=";
}; };
kernelVersion = "5.15.137"; kernelVersion = "6.6.57";
# From package/firmware/linux-firmware/Makefile
linux-firmware = linux-firmware.overrideAttrs(a: {
src = fetchzip {
url = "https://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git/snapshot/linux-firmware-20241017.tar.gz";
hash = "sha256-q4StJdoLCHQThFTzhxETDYlQP/ywmb3vwCr13xtrQzc=";
};
});
applyPatches.ath79 = doPatch "ath79"; applyPatches.ath79 = doPatch "ath79";
applyPatches.ramips = doPatch "ramips"; applyPatches.ramips = doPatch "ramips";

View File

@ -1,16 +0,0 @@
From: Arnout Engelen <arnout@bzzt.net>
Date: Wed, 18 Dec 2024 14:17:46 +0100
Partial patch from https://gti.telent.net/raboof/liminix/commit/641409230051b82616c6feb35f2c0e730e46f614
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c 2024-12-18 11:08:00.598231122 +0100
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c 2024-12-18 11:08:29.845100034 +0100
@@ -625,7 +625,7 @@
static u32 mt7915_mmio_wed_init_rx_buf(struct mtk_wed_device *wed, int size)
{
- struct mtk_rxbm_desc *desc = wed->rx_buf_ring.desc;
+ struct mtk_wed_bm_desc *desc = wed->rx_buf_ring.desc;
struct mt76_txwi_cache *t = NULL;
struct mt7915_dev *dev;
struct mt76_queue *q;

View File

@ -0,0 +1,11 @@
--- drivers/net/wireless/mediatek/mt76/mt7915/mmio.c 2024-12-18 11:08:00.598231122 +0100
+++ drivers/net/wireless/mediatek/mt76/mt7915/mmio.c 2024-12-18 11:08:29.845100034 +0100
@@ -625,7 +625,7 @@
static u32 mt7915_mmio_wed_init_rx_buf(struct mtk_wed_device *wed, int size)
{
- struct mtk_rxbm_desc *desc = wed->rx_buf_ring.desc;
+ struct mtk_wed_bm_desc *desc = wed->rx_buf_ring.desc;
struct mt76_txwi_cache *t = NULL;
struct mt7915_dev *dev;
struct mt76_queue *q;

View File

@ -99,10 +99,8 @@ in attrset:
cp -v -fP \$src/bin/* \$src/etc/* \$dest cp -v -fP \$src/bin/* \$src/etc/* \$dest
${if attrset ? boot then '' ${if attrset ? boot then ''
(cd \$dest (cd \$dest
test -d boot || mkdir boot if test -e boot ; then rm boot ; fi
cd boot ln -sf ${lib.strings.removePrefix "/" attrset.boot.target} ./boot
cp ../${lib.strings.removePrefix "/" attrset.boot.target}/* .
sync; sync
) )
'' else ""} '' else ""}
EOF EOF