Compare commits

..

1 commit

Author SHA1 Message Date
Raito Bezarius
f0c4f15cf5 limiswitch: init
All checks were successful
build liminix / build_vm_qemu_mips (pull_request) Successful in 31s
Minimal features:

- Can connect over serial
- Assess the situation wrt to A/B.
- Copy store paths.
- Flash a partition with data, e.g. a kernel.
- Activate the system.

Next steps:

- Boot into a specific image (primary or secondary)
- SSH transport layer
- Agent
- Less hardcoding
- Even better error recovery in the IO layer of the InteractionChannel
- xmodem/ymodem/zmodem for serial file transfers
- U-Boot-based recovery via TFTP or in-bootloader flashing
- Integration with colmena custom activation protocol

Signed-off-by: Raito Bezarius <masterancpp@gmail.com>
2024-09-21 22:26:42 +02:00
56 changed files with 3051 additions and 305 deletions

View file

@ -17,34 +17,4 @@ jobs:
- name: Build VM QEMU MIPS
run: |
# Enter the shell
nix-build ci.nix -A qemu
build_zyxel-nwa50ax_mips:
runs-on: nix
steps:
- uses: actions/checkout@v3
- name: Build VM QEMU MIPS
run: |
# Enter the shell
nix-build ci.nix -A qemu
test_hostapd:
runs-on: nix
steps:
- uses: actions/checkout@v3
- name: Build VM QEMU MIPS
run: |
# Enter the shell
nix-build ci.nix -A wlan
test_shell_customization:
runs-on: nix
steps:
- uses: actions/checkout@v3
- name: Build VM QEMU MIPS
run: |
# Enter the shell
nix-build ci.nix -A custom-shell
nix-build -I liminix-config=./examples/hello-from-qemu.nix --arg device "import ./devices/qemu" -A outputs.default

4
ci.nix
View file

@ -7,7 +7,7 @@
let
pkgs = (import nixpkgs { });
borderVmConf = ./bordervm.conf-example.nix;
inherit (pkgs.lib.attrsets) genAttrs mapAttrs;
inherit (pkgs.lib.attrsets) genAttrs;
devices = [
"qemu"
"zyxel-nwa50ax"
@ -19,7 +19,7 @@ let
device = import (liminix + "/devices/${name}");
liminix-config = vanilla;
}).outputs.default;
tests = mapAttrs (_: v: v { inherit liminix nixpkgs; }) (import ./tests/ci.nix);
tests = import ./tests/ci.nix;
jobs =
(genAttrs devices for-device) //
tests //

View file

@ -26,13 +26,9 @@ let
eval = evalModules {
modules = [
{
nixpkgs = {
source = nixpkgs;
overlays = [ overlay ];
config.permittedInsecurePackages = [
"python-2.7.18.8"
];
};
nixpkgs.overlays = [
overlay
];
}
device.module
liminix-config

View file

@ -12,7 +12,6 @@ in
"${modulesPath}/hardware.nix"
"${modulesPath}/base.nix"
"${modulesPath}/busybox.nix"
"${modulesPath}/iproute2.nix"
"${modulesPath}/hostname.nix"
"${modulesPath}/kernel"
"${modulesPath}/s6"

View file

@ -4,10 +4,9 @@
{
imports = [
./base.nix
./base.nix
./bridge
./busybox.nix
./iproute2.nix
./dhcp6c
./jitter-rng
./dnsmasq

View file

@ -4,13 +4,11 @@
{ lib, pkgs, config, ...}:
let
inherit (lib) mkEnableOption mkOption types isDerivation hasAttr concatStringsSep mapAttrsToList;
inherit (lib) mkEnableOption mkOption types isDerivation hasAttr ;
inherit (pkgs.pseudofile) dir symlink;
inherit (pkgs.liminix.networking) address interface;
inherit (pkgs.liminix.services) bundle;
# TODO: escape shell argument.
exportVar = name: value: "export ${name}=\"${value}\"";
type_service = pkgs.liminix.lib.types.service;
in {
@ -24,24 +22,6 @@ in {
/run/current-system, we just add the paths in /etc/profile
'';
};
environmentVariables = mkOption {
type = types.attrsOf types.str;
description = ''
Attribute set of environment variables to make available
in a login shell.
The value is assumed to be escaped and the name to be valid.
'';
};
prompt = mkOption {
type = types.str;
default = "$(whoami)@$(hostname) # ";
description = ''
Prompt string (PS1) for the shell.
'';
};
};
services = mkOption {
type = types.attrsOf type_service;
@ -130,9 +110,7 @@ in {
nixpkgs.buildPlatform = lib.mkDefault builtins.currentSystem;
defaultProfile.packages = with pkgs;
[ s6 s6-init-bin execline s6-linux-init s6-rc iproute2 ];
# Set the useful PS1 prompt by default.
defaultProfile.environmentVariables.PS1 = lib.mkDefault config.defaultProfile.prompt;
[ s6 s6-init-bin execline s6-linux-init s6-rc ];
boot.commandLine = [
"panic=10 oops=panic init=/bin/init loglevel=8"
@ -203,10 +181,9 @@ in {
etc = let
profile = symlink
(pkgs.writeScript ".profile" ''
PATH=${lib.makeBinPath config.defaultProfile.packages}:/bin
PATH=${lib.makeBinPath config.defaultProfile.packages}:/bin
export PATH
${concatStringsSep "\n" (mapAttrsToList exportVar config.defaultProfile.environmentVariables)}
'');
'');
in dir {
inherit profile;
ashrc = profile;

View file

@ -9,7 +9,8 @@
{ lib, pkgs, config, ...}:
let
inherit (lib) mkOption types mkEnableOption;
inherit (lib) mkOption types;
inherit (pkgs.liminix.services) oneshot;
inherit (pkgs) liminix;
in
{
@ -34,20 +35,6 @@ in
default = null;
description = "reuse mac address from an existing interface service";
};
untagged = {
enable = mkEnableOption "untagged frames on port VID";
pvid = mkOption {
type = types.nullOr types.int;
default = null;
description = "Port VLAN ID for egress untagged frames";
};
default-pvid = mkOption {
type = types.int;
default = 0;
description = "Default PVID for ingress untagged frames, defaults to 0, which disable untagged frames for ingress";
};
};
};
members = config.system.callService ./members.nix {
primary = mkOption {

View file

@ -3,22 +3,17 @@
, ifwait
, lib
}:
{ ifname, macAddressFromInterface ? null, untagged } :
{ ifname, macAddressFromInterface ? null } :
let
inherit (liminix.services) oneshot;
inherit (lib) optional optionalString;
# This enables vlan_filtering if we do make use of it.
extra = if untagged.enable then " vlan_filtering 1 vlan_default_pvid ${toString untagged.default-pvid}" else "";
inherit (liminix.services) bundle oneshot;
inherit (lib) mkOption types optional;
in oneshot rec {
name = "${ifname}.link";
up = ''
${if macAddressFromInterface == null then
"ip link add name ${ifname} type bridge${extra}"
"ip link add name ${ifname} type bridge"
else
"ip link add name ${ifname} address $(output ${macAddressFromInterface} ether) type bridge${extra}"}
${optionalString untagged.enable
"bridge vlan add vid ${toString untagged.pvid} dev ${ifname} pvid untagged self"}
"ip link add name ${ifname} address $(output ${macAddressFromInterface} ether) type bridge"}
(in_outputs ${name}
echo ${ifname} > ifname

View file

@ -37,7 +37,7 @@ let
"comm" "cp" "cpio" "cut" "date" "dhcprelay" "dd" "df" "dirname" "dmesg"
"du" "echo" "egrep" "env" "expand" "expr" "false" "fdisk" "fgrep" "find"
"free" "fuser" "grep" "gunzip" "gzip" "head" "hexdump" "hostname" "hwclock"
"ifconfig" "ipneigh" "kill"
"ifconfig" "ip" "ipaddr" "iplink" "ipneigh" "iproute" "iprule" "kill"
"killall" "killall5" "less" "ln" "ls" "lsattr" "lsof" "md5sum" "mkdir"
"mknod" "mktemp" "mount" "mv" "nc" "netstat" "nohup" "od" "pgrep" "pidof"
"ping" "ping6" "pkill" "pmap" "printenv" "printf" "ps" "pwd" "readlink"

View file

@ -1,6 +1,7 @@
{ lib, pkgs, config, ...}:
let
inherit (lib) mkOption types;
inherit (pkgs.liminix.services) oneshot;
in {
options = {
hostname = mkOption {
@ -11,21 +12,12 @@ in {
default = "liminix";
type = types.nonEmptyStr;
};
hostname-script = mkOption {
description = ''
Script that outputs the system hostname on stdin.
'';
default = pkgs.writeScript "hostname-gen" ''
#!/bin/sh
echo ${config.hostname}
'';
defaultText = ''
pkgs.writeScript "hostname-gen" '''
#!/bin/sh
echo ''${config.hostname}
'''
'';
type = types.package;
};
config = {
services.hostname = oneshot {
name = "hostname-${builtins.substring 0 12 (builtins.hashString "sha256" config.hostname)}";
up = "echo ${config.hostname} > /proc/sys/kernel/hostname";
down = "true";
};
};
}

View file

@ -1,28 +0,0 @@
{ config, pkgs, lib, ... }:
let
inherit (lib) mkEnableOption mkPackageOption mkIf genAttrs;
inherit (pkgs.pseudofile) dir symlink;
cfg = config.programs.iproute2;
minimalPrograms = [
"ip"
"devlink"
"ss"
"bridge"
"genl"
"ifstat"
"nstat"
];
links = genAttrs minimalPrograms (p: symlink "${cfg.package}/bin/${p}");
in
{
options.programs.iproute2 = {
enable = mkEnableOption "the iproute2 programs instead of busybox variants";
package = mkPackageOption pkgs "iproute2" { };
};
config = mkIf cfg.enable {
filesystem = dir {
bin = dir links;
};
};
}

View file

@ -54,7 +54,7 @@ in
mount -t sysfs none /sys
${busybox}/bin/sh
'';
refs = pkgs.writeClosure [ busybox ];
refs = pkgs.writeReferencesToFile busybox;
in runCommand "initramfs.cpio" {} ''
cat << SPECIALS | ${gen_init_cpio}/bin/gen_init_cpio /dev/stdin > out
dir /proc 0755 0 0

View file

@ -30,8 +30,6 @@ let
installPhase = ''
mkdir $out
cp -r $src $out/scripts
substituteInPlace $out/scripts/rc.init \
--replace-fail 'config.hostname' "${config.hostname-script}"
chmod -R +w $out
'';
};

View file

@ -36,7 +36,6 @@ fi
### (replace /run/service with your scandir)
s6-rc-init -d -c /etc/s6-rc/compiled /run/service
config.hostname > /proc/sys/kernel/hostname
### 2. Starting the wanted set of services
### This is also called every time you change runlevels with telinit.

View file

@ -33,11 +33,6 @@ in
description = "VLAN identifier (VID) in range 1-4094";
type = types.str;
};
untagged.egress = mkOption {
description = "Whether packets from this interface will go out *untagged*";
type = types.bool;
default = false;
};
};
config.kernel.config = {
VLAN_8021Q = "y";

View file

@ -2,15 +2,13 @@
liminix
, lib
}:
{ ifname, primary, vid, untagged } :
{ ifname, primary, vid } :
let
inherit (lib) optionalString;
inherit (liminix.services) oneshot;
in oneshot rec {
name = "${ifname}.link";
up = ''
ip link add link $(output ${primary} ifname) name ${ifname} type vlan id ${vid}
${optionalString untagged.egress "bridge vlan add dev ${ifname} vid ${toString untagged.vid} pvid untagged master"}
${liminix.networking.ifup name ifname}
(in_outputs ${name}
echo ${ifname} > ifname

View file

@ -141,9 +141,7 @@ extraPkgs // {
repo = "hostapd";
rev = "hostap-liminix-integration";
hash = "sha256-5Xi90keCHxvuKR5Q7STuZDzuM9h9ac6aWoXVQYvqkQI=";
};
# Do not take any patch.
patches = [];
};
extraConfig = "";
configurePhase = ''
cat > hostapd/defconfig <<EOF
@ -186,7 +184,6 @@ extraPkgs // {
rev = "hostap-liminix-integration";
hash = "sha256-5Xi90keCHxvuKR5Q7STuZDzuM9h9ac6aWoXVQYvqkQI=";
};
patches = [];
extraConfig = "";
configurePhase = ''
cat > hostapd/defconfig <<EOF
@ -197,35 +194,7 @@ extraPkgs // {
});
in h.override { openssl = null; sqlite = null; };
libnl = prev.libnl.override {
graphviz = null;
};
iproute2 =
let i = prev.iproute2.overrideAttrs (old: {
postInstall = ''
${(old.postInstall or "")}
non_necessary_binaries=("tc" "rdma" "dcb" "tipc" "vdpa")
for needless_binary in "''${non_necessary_binaries[@]}"; do
echo "Removing unnecessary binary $out/sbin/$needless_binary"
rm "$out/sbin/$needless_binary"
done
# No man
rm -rf "$out/share"
# Remove all the data about distributions for tc.
rm -rf "$out/lib"
'';
});
# Don't bring ebpf stuff to the table.
# We also remove tc so we can drop iptables as well.
# Let's try to kill `db` as well.
in i.override { elfutils = null; iptables = null; db = null; };
wpa_supplicant = prev.wpa_supplicant.override {
dbusSupport = false;
withPcsclite = false;
wpa_supplicant_gui = null;
};
kexec-tools-static = prev.kexec-tools.overrideAttrs(o: {
# For kexecboot we copy kexec into a ramdisk on the system being

View file

@ -3,7 +3,7 @@
, pkgsBuildBuild
, runCommand
, cpio
, writeClosure
, writeReferencesToFile
, writeScript
} :
let
@ -18,7 +18,7 @@ let
mount -t sysfs none /sys
${busybox}/bin/sh
'';
refs = writeClosure [ busybox ];
refs = writeReferencesToFile busybox;
in runCommand "initramfs.cpio" { } ''
cat << SPECIALS | ${gen_init_cpio}/bin/gen_init_cpio /dev/stdin > out
dir /proc 0755 0 0

View file

@ -2,7 +2,6 @@
writeScriptBin
, writeScript
, systemconfig
, stdenv
, execline
, lib
, config ? {}
@ -57,19 +56,11 @@ let
};
eval = lib.evalModules {
modules = [
{ _module.args = { inherit pkgs; inherit (pkgs) lim; }; }
../../modules/base.nix
../../modules/users.nix
../../modules/busybox.nix
../../modules/hostname.nix
../../modules/misc/assertions.nix
../../modules/nixpkgs.nix
base
{
# Inherit from that target system host platform.
nixpkgs.hostPlatform = stdenv.hostPlatform;
# Force our own package set.
nixpkgs.pkgs = lib.mkForce pkgs;
}
({ ... } : paramConfig)
../../modules/s6
];

1
pkgs/limiswitch/.envrc Normal file
View file

@ -0,0 +1 @@
use nix

1
pkgs/limiswitch/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
target/

844
pkgs/limiswitch/Cargo.lock generated Normal file
View file

@ -0,0 +1,844 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "aho-corasick"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
dependencies = [
"memchr 2.7.4",
]
[[package]]
name = "anstream"
version = "0.6.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526"
dependencies = [
"anstyle",
"anstyle-parse",
"anstyle-query",
"anstyle-wincon",
"colorchoice",
"is_terminal_polyfill",
"utf8parse",
]
[[package]]
name = "anstyle"
version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1"
[[package]]
name = "anstyle-parse"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb"
dependencies = [
"utf8parse",
]
[[package]]
name = "anstyle-query"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a"
dependencies = [
"windows-sys",
]
[[package]]
name = "anstyle-wincon"
version = "3.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8"
dependencies = [
"anstyle",
"windows-sys",
]
[[package]]
name = "arrayvec"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
[[package]]
name = "byteorder"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "clap"
version = "4.5.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0956a43b323ac1afaffc053ed5c4b7c1f1800bacd1683c353aabbb752515dd3"
dependencies = [
"clap_builder",
"clap_derive",
]
[[package]]
name = "clap_builder"
version = "4.5.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d72166dd41634086d5803a47eb71ae740e61d84709c36f3c34110173db3961b"
dependencies = [
"anstream",
"anstyle",
"clap_lex",
"strsim",
]
[[package]]
name = "clap_derive"
version = "4.5.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab"
dependencies = [
"heck",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "clap_lex"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97"
[[package]]
name = "colorchoice"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0"
[[package]]
name = "console"
version = "0.15.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb"
dependencies = [
"encode_unicode",
"lazy_static",
"libc",
"unicode-width",
"windows-sys",
]
[[package]]
name = "core-foundation-sys"
version = "0.8.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
[[package]]
name = "encode_unicode"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
[[package]]
name = "getrandom"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]]
name = "heck"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "indicatif"
version = "0.17.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "763a5a8f45087d6bcea4222e7b72c291a054edf80e4ef6efd2a4979878c7bea3"
dependencies = [
"console",
"instant",
"number_prefix",
"portable-atomic",
"unicode-width",
"vt100",
]
[[package]]
name = "instant"
version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222"
dependencies = [
"cfg-if",
]
[[package]]
name = "io-kit-sys"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "617ee6cf8e3f66f3b4ea67a4058564628cde41901316e19f559e14c7c72c5e7b"
dependencies = [
"core-foundation-sys",
"mach2",
]
[[package]]
name = "is_terminal_polyfill"
version = "1.70.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
[[package]]
name = "itoa"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
[[package]]
name = "lazy_static"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]]
name = "libc"
version = "0.2.158"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439"
[[package]]
name = "libudev"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78b324152da65df7bb95acfcaab55e3097ceaab02fb19b228a9eb74d55f135e0"
dependencies = [
"libc",
"libudev-sys",
]
[[package]]
name = "libudev-sys"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c8469b4a23b962c1396b9b451dda50ef5b283e8dd309d69033475fa9b334324"
dependencies = [
"libc",
"pkg-config",
]
[[package]]
name = "limiswitch"
version = "0.1.0"
dependencies = [
"clap",
"rand",
"regex",
"serialport",
"thiserror",
"tracing",
"tracing-indicatif",
"tracing-subscriber",
"uri_parser",
"virtual-serialport",
]
[[package]]
name = "log"
version = "0.4.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
[[package]]
name = "mach2"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19b955cdeb2a02b9117f121ce63aa52d08ade45de53e48fe6a38b39c10f6f709"
dependencies = [
"libc",
]
[[package]]
name = "matchers"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558"
dependencies = [
"regex-automata 0.1.10",
]
[[package]]
name = "memchr"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "148fab2e51b4f1cfc66da2a7c32981d1d3c083a803978268bb11fe4b86925e7a"
dependencies = [
"libc",
]
[[package]]
name = "memchr"
version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]]
name = "nix"
version = "0.26.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b"
dependencies = [
"bitflags 1.3.2",
"cfg-if",
"libc",
]
[[package]]
name = "nom"
version = "3.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05aec50c70fd288702bcd93284a8444607f3292dbdf2a30de5ea5dcdbe72287b"
dependencies = [
"memchr 1.0.2",
]
[[package]]
name = "nu-ansi-term"
version = "0.46.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84"
dependencies = [
"overload",
"winapi",
]
[[package]]
name = "number_prefix"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
[[package]]
name = "once_cell"
version = "1.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
[[package]]
name = "overload"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
[[package]]
name = "pin-project-lite"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
[[package]]
name = "pkg-config"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
[[package]]
name = "portable-atomic"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d30538d42559de6b034bc76fd6dd4c38961b1ee5c6c56e3808c50128fdbc22ce"
[[package]]
name = "ppv-lite86"
version = "0.2.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04"
dependencies = [
"zerocopy",
]
[[package]]
name = "proc-macro2"
version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rand"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [
"libc",
"rand_chacha",
"rand_core",
]
[[package]]
name = "rand_chacha"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
dependencies = [
"ppv-lite86",
"rand_core",
]
[[package]]
name = "rand_core"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [
"getrandom",
]
[[package]]
name = "regex"
version = "1.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619"
dependencies = [
"aho-corasick",
"memchr 2.7.4",
"regex-automata 0.4.7",
"regex-syntax 0.8.4",
]
[[package]]
name = "regex-automata"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
dependencies = [
"regex-syntax 0.6.29",
]
[[package]]
name = "regex-automata"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df"
dependencies = [
"aho-corasick",
"memchr 2.7.4",
"regex-syntax 0.8.4",
]
[[package]]
name = "regex-syntax"
version = "0.6.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
[[package]]
name = "regex-syntax"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"
[[package]]
name = "scopeguard"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "serialport"
version = "4.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ba776acc8c373b9175829206229366273225436845c04f9c20aab8099960e2e"
dependencies = [
"bitflags 2.6.0",
"cfg-if",
"core-foundation-sys",
"io-kit-sys",
"libudev",
"mach2",
"nix",
"scopeguard",
"unescaper",
"winapi",
]
[[package]]
name = "sharded-slab"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6"
dependencies = [
"lazy_static",
]
[[package]]
name = "smallvec"
version = "1.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
[[package]]
name = "strsim"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]]
name = "syn"
version = "2.0.77"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "thiserror"
version = "1.0.63"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.63"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "thread_local"
version = "1.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c"
dependencies = [
"cfg-if",
"once_cell",
]
[[package]]
name = "tracing"
version = "0.1.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef"
dependencies = [
"pin-project-lite",
"tracing-attributes",
"tracing-core",
]
[[package]]
name = "tracing-attributes"
version = "0.1.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "tracing-core"
version = "0.1.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54"
dependencies = [
"once_cell",
"valuable",
]
[[package]]
name = "tracing-indicatif"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "069580424efe11d97c3fef4197fa98c004fa26672cc71ad8770d224e23b1951d"
dependencies = [
"indicatif",
"tracing",
"tracing-core",
"tracing-subscriber",
]
[[package]]
name = "tracing-log"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3"
dependencies = [
"log",
"once_cell",
"tracing-core",
]
[[package]]
name = "tracing-subscriber"
version = "0.3.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b"
dependencies = [
"matchers",
"nu-ansi-term",
"once_cell",
"regex",
"sharded-slab",
"smallvec",
"thread_local",
"tracing",
"tracing-core",
"tracing-log",
]
[[package]]
name = "unescaper"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c878a167baa8afd137494101a688ef8c67125089ff2249284bd2b5f9bfedb815"
dependencies = [
"thiserror",
]
[[package]]
name = "unicode-ident"
version = "1.0.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
[[package]]
name = "unicode-width"
version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
[[package]]
name = "uri_parser"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba0090ecd7c64b69e546cda222b4b331877a0e1624a2a39a19e6ea4df29a33f9"
dependencies = [
"nom",
]
[[package]]
name = "utf8parse"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]]
name = "valuable"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
[[package]]
name = "virtual-serialport"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9be4450a7c55fbef57cdfc0b56b17126ea479ede908f1f3e21eebd4ca85687dd"
dependencies = [
"rand",
"serialport",
]
[[package]]
name = "vt100"
version = "0.15.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "84cd863bf0db7e392ba3bd04994be3473491b31e66340672af5d11943c6274de"
dependencies = [
"itoa",
"log",
"unicode-width",
"vte",
]
[[package]]
name = "vte"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f5022b5fbf9407086c180e9557be968742d839e68346af7792b8592489732197"
dependencies = [
"arrayvec",
"utf8parse",
"vte_generate_state_changes",
]
[[package]]
name = "vte_generate_state_changes"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2e369bee1b05d510a7b4ed645f5faa90619e05437111783ea5848f28d97d3c2e"
dependencies = [
"proc-macro2",
"quote",
]
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-sys"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_gnullvm",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_i686_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
name = "zerocopy"
version = "0.7.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
dependencies = [
"byteorder",
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.7.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
dependencies = [
"proc-macro2",
"quote",
"syn",
]

View file

@ -0,0 +1,18 @@
[package]
name = "limiswitch"
version = "0.1.0"
edition = "2021"
[dependencies]
clap = { version = "4.5.17", features = ["derive"] }
rand = "0.8.5"
regex = "1.10.6"
serialport = "4.5.1"
thiserror = "1.0.63"
tracing = { version = "0.1.40", features = ["max_level_debug", "release_max_level_info"] }
tracing-indicatif = "0.3.6"
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
uri_parser = "0.2.0"
[dev-dependencies]
virtual-serialport = "0.1.1"

View file

@ -0,0 +1,11 @@
{ pkgs ? import <nixpkgs> {} }:
{
shell = pkgs.mkShell {
buildInputs = with pkgs; [
cargo
rustc
pkg-config
udev
];
};
}

View file

@ -0,0 +1 @@
(import ./default.nix {}).shell

View file

@ -0,0 +1,99 @@
use std::{num::ParseIntError, path::Path};
use super::state::OSOperState;
use thiserror::Error;
mod serial;
#[derive(Debug, Error)]
pub enum ChannelError {
#[error("This interaction channel requires an executable in PATH: {0}, was not found")]
ExecutableInPathRequired(&'static str),
#[error("This interaction channel suddenly lost its operational state to: {0:?}")]
LossOfOperationalState(Option<OSOperState>),
#[error("This interaction channel was not able to assess a working shell")]
CouldNotFindAWorkingShell,
#[error("This interaction channel got an unexpected breakage during shell execution")]
UnexpectedBreakageDuringShellExecution,
#[error("This interaction channel got an IO error: {0}")]
IOError(#[from] std::io::Error),
#[error("This interaction channel had one of its transport broken while reading it")]
TransportBroke,
#[error("This interaction channel hit a timeout while reading the transport")]
TimeoutDuringRead,
#[error("This interaction channel failed to parse an integer")]
ParseIntFailure(#[from] ParseIntError),
}
pub type Result<V> = std::result::Result<V, ChannelError>;
/// An interaction channel enable the program to communicate with the target device
/// and perform side-effects, e.g. gather information, write bytes to some flash, etc.
///
/// Every operation can fail due to a channel error, depending on their specific implementation.
pub trait InteractionChannel {
fn execute(&mut self, cmd: &str) -> Result<Vec<u8>>;
fn read_file(&mut self, path: &Path) -> Result<Vec<u8>>;
fn has_executable_in_path(&mut self, executable: &str) -> Result<bool>;
fn has_directory(&mut self, path: &Path) -> Result<bool>;
fn infer_operational_state(&mut self) -> Result<Option<OSOperState>>;
fn get_kernel_log(&mut self) -> Result<String>;
}
struct ShellCommandResult {
pub exit_code: u32,
pub stdout: Vec<u8>,
pub stderr: Vec<u8>
}
/// Shell-based interactions are a cheap way to obtain an interaction channel
/// but they rely on POSIX semantics to be sufficiently robust for the implementation code.
/// If you can avoid it, it's preferable to have a high quality implementation using well-crafted
/// primitives.
pub trait ShellBasedInteractionChannel {
fn shell_command_execute(&mut self, cmd: &str) -> Result<ShellCommandResult>;
fn infer_operational_state(&mut self) -> Result<Option<OSOperState>>;
}
impl InteractionChannel for dyn ShellBasedInteractionChannel {
fn infer_operational_state(&mut self) -> Result<Option<OSOperState>> {
ShellBasedInteractionChannel::infer_operational_state(self)
}
fn has_directory(&mut self, path: &Path) -> Result<bool> {
if !self.has_executable_in_path("test")? {
return Err(ChannelError::ExecutableInPathRequired("test"));
}
Ok(self.shell_command_execute(&format!("test -d {}", path.to_string_lossy()))?.exit_code == 0)
}
fn has_executable_in_path(&mut self, executable: &str) -> Result<bool> {
Ok(self.shell_command_execute(&format!("type -P {}", executable))?.exit_code == 0)
}
fn read_file(&mut self, path: &Path) -> Result<Vec<u8>> {
if !self.has_executable_in_path("cat")? {
return Err(ChannelError::ExecutableInPathRequired("cat"));
}
let stdout = self.shell_command_execute(&format!("cat {}", path.to_string_lossy())).unwrap().stdout;
// Do not let binary harm the shell.
self.shell_command_execute("reset")?;
Ok(stdout)
}
fn execute(&mut self, cmd: &str) -> Result<Vec<u8>> {
Ok(self.shell_command_execute(cmd)?.stdout)
}
fn get_kernel_log(&mut self) -> Result<String> {
Ok(String::from_utf8(self.execute("dmesg")?).expect("Kernel log should be valid UTF-8"))
}
}
// struct SSH;
// impl InteractionChannel for SSH {}
//
//
// struct Agent;
// impl InteractionChannel for Agent {}

View file

@ -0,0 +1,445 @@
use tracing::debug;
use std::{io::{BufRead, BufReader, Read}, path::{Path, PathBuf}, str::FromStr, sync::{mpsc::{self, Receiver, RecvError}, Arc, Mutex}, thread, time::Duration};
use rand::{thread_rng, Rng};
use serialport::SerialPort;
use crate::{channels::{Result, ChannelError}, state::OSOperState};
use super::{ShellBasedInteractionChannel, ShellCommandResult};
fn generate_random_filename() -> String {
thread_rng()
.sample_iter(rand::distributions::Alphanumeric)
.take(8)
.map(char::from)
.collect()
}
/// An interaction channel via a serial port.
struct Serial {
port: Box<dyn SerialPort>,
reader: Arc<Mutex<BufReader<Box<dyn SerialPort>>>>,
read_timeout_msec: u64,
oper_state: Option<OSOperState>,
}
impl Serial {
pub fn new(port: Box<dyn SerialPort>, read_timeout_msec: u64) -> Self {
let mut p_reader = port.try_clone().unwrap();
p_reader.set_timeout(Duration::from_millis(2 * read_timeout_msec)).unwrap();
let reader = Arc::new(BufReader::new(p_reader).into());
Self {
port,
reader,
read_timeout_msec,
oper_state: None
}
}
fn spawn_read_channel<F, B>(&self, read_op: F) -> Receiver<B>
where
B: std::marker::Send + 'static + std::fmt::Debug,
F: Fn(&mut Arc<Mutex<BufReader<Box<dyn SerialPort>>>>) -> B + std::marker::Send + 'static
{
debug!("spawning a read channel");
let (tx, rx) = mpsc::channel();
let mut reader = self.reader.clone();
thread::spawn(move || {
debug!("reading via the read channel...");
let buffer = read_op(&mut reader);
debug!("read {:?}", buffer);
// TODO: do something about the io error.
debug!("sending the buffer received");
tx.send(buffer).expect("Failed to send the buffer");
});
rx
}
// TODO: use zmodem, ymodem or xmodem
// but not what I'm doing!
// it depends very highly on the shell prompt marker which is questionable
// no error control, nothing.
fn read_file(&mut self, path: &Path) -> Result<Vec<u8>> {
self.send_line(&format!("cat {}", path.to_string_lossy()))?;
let channel = self.spawn_read_channel(|reader| {
let mut buffer = Vec::new();
let mut reader = reader.lock().expect("Failed to lock the reader");
let mut shell_prompt_reached = false;
while !shell_prompt_reached {
reader
.read_until(b'#', &mut buffer)
.expect("Failed to read until the very end");
let mut one_char: [u8; 1] = [42; 1];
reader.read_exact(&mut one_char).expect("Failed to read a single char");
if one_char[0] == b' ' {
// Pop the last delimiter.
buffer.pop();
shell_prompt_reached = true;
} else {
buffer.push(one_char[0]);
}
}
buffer
});
match channel.recv() {
Ok(buffer) => {
Ok(buffer)
},
Err(RecvError) => {
Err(ChannelError::TransportBroke)
}
}
}
fn send_line(&mut self, s: &str) -> Result<()> {
debug!("send_line via the port >>> {}", s);
Ok(self.port.write_all(format!("{}\n", s).as_bytes())?)
}
fn wait_for_line(&self) -> Result<Option<String>> {
debug!("waiting for a line...");
let channel = self.spawn_read_channel(|reader| {
let mut buffer = String::new();
reader.lock()
.expect("Failed to lock the reader")
.read_line(&mut buffer)
.expect("Failed to read a line");
debug!("line found: {:?}", buffer);
buffer
});
match channel.recv_timeout(Duration::from_millis(self.read_timeout_msec)) {
Ok(line) => Ok(Some(line)),
Err(mpsc::RecvTimeoutError::Timeout) => Ok(None),
Err(mpsc::RecvTimeoutError::Disconnected) => Err(ChannelError::TransportBroke)
}
}
fn wait_for_prompt(&self, s: &str) -> Result<bool> {
debug!("waiting for pattern '{}'...", s);
let pattern = s.to_owned();
let channel = self.spawn_read_channel(move |reader| {
let mut buffer = String::new();
let mut reader = reader.lock().expect("Failed to lock the reader");
while !buffer.starts_with(&pattern) {
reader
.read_line(&mut buffer)
.expect("Failed to read a line");
}
});
match channel.recv_timeout(Duration::from_millis(self.read_timeout_msec)) {
Ok(()) => Ok(true),
Err(mpsc::RecvTimeoutError::Timeout) => Ok(false),
Err(mpsc::RecvTimeoutError::Disconnected) => Err(ChannelError::TransportBroke)
}
}
// Parse a value of type V on the next line
fn wait_for_value<V: FromStr>(&mut self) -> Result<V>
where
<V as FromStr>::Err: Into<ChannelError>
{
// Wait for line and then parse it.
let mut line: String = String::new();
self.reader.lock()
.expect("Failed to lock the reader")
.read_line(&mut line)
.expect("Failed to parse a line");
Ok(line.trim().parse::<V>().map_err(|e| e.into())?)
}
}
impl ShellBasedInteractionChannel for Serial {
fn shell_command_execute(&mut self, cmd: &str) -> Result<ShellCommandResult> {
// 1. Assess we are in the right operational state.
let new_oper_state = self.infer_operational_state()?;
if new_oper_state.is_none() || !new_oper_state.clone().unwrap().is_in_userspace() {
return Err(ChannelError::LossOfOperationalState(new_oper_state));
}
// 2. Assess we do have a shell.
self.send_line("type")?;
if !self.wait_for_prompt("# ")? {
return Err(ChannelError::CouldNotFindAWorkingShell);
}
// 3. Run the command and redirect stdout & stderr in temporary files in RAM.
let stdout_filename = format!("/tmp/stdout_{}", generate_random_filename());
let stderr_filename = format!("/tmp/stderr_{}", generate_random_filename());
self.send_line(&format!("{} >{} 2>{}", cmd, stdout_filename, stderr_filename))?;
if !self.wait_for_prompt("# ")? {
return Err(ChannelError::UnexpectedBreakageDuringShellExecution);
}
let stdout = self.read_file(&PathBuf::from_str(&stdout_filename).unwrap())?;
let stderr = self.read_file(&PathBuf::from_str(&stderr_filename).unwrap())?;
// 4. Fetch the exit code as well.
self.send_line("echo $?")?;
let exit_code = self.wait_for_value()?;
if !self.wait_for_prompt("# ")? {
return Err(ChannelError::UnexpectedBreakageDuringShellExecution);
}
Ok(ShellCommandResult {
exit_code,
stdout,
stderr
})
}
fn infer_operational_state(&mut self) -> super::Result<Option<crate::state::OSOperState>> {
let mut inferred_oper_state = None;
// TODO: if there's no line, send an Enter keystroke.
// While there's a line under the right timeout.
while let Some(line) = self.wait_for_line()? {
// This is a U-Boot prompt.
if line.starts_with("U-Boot") || line.starts_with("==> ") {
inferred_oper_state = Some(crate::state::OSOperState::UBoot);
}
if line.starts_with("BusyBox v") {
inferred_oper_state = Some(crate::state::OSOperState::Userspace(crate::state::DistributionType::Unknown));
}
}
// TODO: read again to verify if we are in the right state.
self.oper_state = inferred_oper_state;
Ok(self.oper_state.clone())
}
}
#[cfg(test)]
mod tests {
use std::{collections::HashMap, io::{BufRead, BufReader, Write}, path::PathBuf, str::FromStr, thread, time::Duration};
use serialport::SerialPort;
use tracing::{debug, level_filters::LevelFilter};
use virtual_serialport::VirtualPort;
use crate::{channels::ShellBasedInteractionChannel, state::OSOperState};
use super::Serial;
const DEFAULT_BAUD_RATE: u32 = 117200;
// TODO: create an argv type
// create an stdout writer type
// create an stderr writer type
type SimulatorCommandHandler = dyn Fn(Vec<&str>) -> u32 + Send;
struct TargetSystemSimulator {
pub boot_log: String,
pub shell_prompt: String,
custom_commands: HashMap<String, Box<SimulatorCommandHandler>>,
serial: VirtualPort
}
impl TargetSystemSimulator {
pub fn new(boot_log: String, shell_prompt: String, serial: VirtualPort) -> Self {
Self {
boot_log,
shell_prompt,
serial,
custom_commands: Default::default(),
}
}
fn send_shell_prompt(&mut self) {
self.serial.write_all(self.shell_prompt.as_bytes()).unwrap();
}
pub fn register_command<H>(&mut self, prefix: &str, handler: H)
where
H: Fn(Vec<&str>) -> u32 + 'static + Send
{
self.custom_commands.insert(prefix.to_string(), Box::new(handler));
}
/// Main handler for the target system simulator, should run in another thread and move
/// itself.
pub fn boot(mut self) {
// 1. Stream the boot log first.
self.serial.write_all(self.boot_log.as_bytes()).unwrap();
// 2. Display the shell prompt
self.send_shell_prompt();
let mut reader = BufReader::new(self.serial.try_clone().unwrap());
loop {
let mut line = String::new();
// Distinguish timeout which is OK from another problem.
let size = reader.read_line(&mut line).expect("Failed to read a line");
// Nothing was read.
if size == 0 {
continue;
}
self.handle_command(line);
}
}
fn handle_command(&self, cmd: String) {
// TODO: parse eventual shell redirections first
// parse shell arguments and perform shell variables expansion
// e.g. $? → last exit code
// match over the prefix if this is a custom command
// if this is a custom command indeed, call the custom command
// with the stdout and stderr objects instantiated with the possible
// shell redirections.
// if it doesn't match the custom,
// pass it over the builtin stuff with the parsed args
// finally, send back the shell prompt
}
fn handle_builtin_command(&self, prefix: &str) {
match prefix {
"echo" => {
// print whatever is passed as args
},
"type" => {
// if no further arg is passed
// type -P cmd should return the path to the executable if it exist.
},
"cat" => {
// look for the given files
// and read them over the serial.
}
_ => unimplemented!("builtin command")
}
}
}
fn init_logging() {
tracing_subscriber::fmt::Subscriber::builder()
.with_max_level(LevelFilter::DEBUG)
.init();
}
fn create_virtual_port() -> (VirtualPort, VirtualPort) {
VirtualPort::open_pair(DEFAULT_BAUD_RATE, 1 * 1024 * 1024).expect("Failed to create virtual serial ports")
}
fn transfer_log(remote: &mut VirtualPort, file_contents: Vec<u8>) {
remote.write_all(&file_contents)
.expect("Failed to transfer all the log");
}
#[test]
fn infer_uboot() {
init_logging();
let (mut remote, local) = create_virtual_port();
// 1 ms of timeout for this scenario.
let mut serial_channel = Serial::new(Box::new(local), 1);
transfer_log(&mut remote, include_bytes!("../tests/uboot-boot-log").to_vec());
let oper_state = serial_channel.infer_operational_state().expect("Failed to infer operational state");
assert!(matches!(oper_state, Some(OSOperState::UBoot)));
}
#[test]
fn infer_possible_shell_prompt() {
let (mut remote, local) = create_virtual_port();
let mut serial_channel = Serial::new(Box::new(local), 1);
transfer_log(&mut remote, include_bytes!("../tests/shell-prompt-log").to_vec());
let oper_state = serial_channel.infer_operational_state().expect("Failed to infer operational state");
assert!(oper_state.unwrap().is_in_userspace());
}
#[test]
fn can_read_files() {
init_logging();
let (mut remote, local) = create_virtual_port();
remote.set_timeout(Duration::from_secs(200)).unwrap();
let mut serial_channel = Serial::new(Box::new(local), 100);
let one_multiline_buffer = "test\nmultiline\na\n\n";
let binary_buffer: Vec<u8> = vec![0x0, 0x1, 0x2, 0x3, 0x4, 0x5];
let copy: Vec<u8> = binary_buffer.clone();
let mut reader = BufReader::new(remote.try_clone().unwrap());
let _responder_handle = thread::spawn(move || {
let mut buffer = String::new();
println!("responder thread started");
let mut resp;
loop {
resp = reader.read_line(&mut buffer);
println!("{:?}", resp);
if let Ok(n) = resp {
if n == 0 {
break;
}
// TODO: generalize this simulator to support shell
println!("[responder thread] received: {:?}", buffer);
if buffer == "cat /etc/passwd\n" {
let resp = format!("{}# ", &one_multiline_buffer);
debug!("[responder thread] sending: {:?} back", resp);
remote.write_all(resp.as_bytes()).unwrap();
}
if buffer == "cat /bin/ls\n" {
debug!("[responder thread] sending {:?} back", &copy);
remote.write_all(&copy).unwrap();
remote.write_all("# ".as_bytes()).unwrap();
}
buffer.clear();
}
}
});
// Non-binary test.
assert_eq!(
String::from_utf8(serial_channel.read_file(&PathBuf::from_str("/etc/passwd").unwrap()).expect("Reading a file should work")).expect("Non binary file should be valid UTF8"),
one_multiline_buffer
);
// Binary test.
assert_eq!(
serial_channel.read_file(
&PathBuf::from_str("/bin/ls").unwrap()
).expect("Reading a file should work"),
binary_buffer
);
}
#[test]
fn can_execute_shell_commands() {
init_logging();
let (remote, local) = create_virtual_port();
let mut serial_channel = Serial::new(Box::new(local), 100);
let mut simulator = TargetSystemSimulator::new(
include_str!("../tests/shell-prompt-log").to_string(),
"# ".to_string(),
remote
);
thread::spawn(move || {
simulator.register_command("any-command", |argv| {
//stdout.write("hello world");
//stderr.write("hello noworld");
127
});
simulator.boot();
});
serial_channel.shell_command_execute("any-command").expect("Failed to run the shell command");
}
// TODO: perturbation tests with noise and send delays
}

View file

@ -0,0 +1,291 @@
use std::path::PathBuf;
use std::str::FromStr;
use crate::channels::ChannelError;
use crate::state::{Partition, PartitionError, PartitionLayout};
use super::channels::InteractionChannel;
use super::state::{OSOperState, DistributionType};
use thiserror::Error;
use uri_parser::parse_uri;
use regex::Regex;
pub struct Device {
channel: Box<dyn InteractionChannel>,
pub operational_state: Option<OSOperState>,
}
#[derive(Debug, Error)]
pub enum DeviceError {
#[error("Malformed connection URI: {0}")]
MalformedConnectionURI(#[source] uri_parser::Error),
#[error("Unsupported connection scheme: {0}")]
UnsupportedConnectionScheme(String),
#[error("The underlying channel encountered an error: {0}")]
ChannelError(#[source] super::channels::ChannelError),
#[error("The device is in an unknown operational state at the operating system level")]
UnknownOperationalState,
#[error("The device is in an unsupported operational state at the operating system level: {0:?}")]
UnsupportedOperationalState(OSOperState),
#[error("The device type could not be inferred: unsupported device?")]
UnknownDeviceType,
#[error("This device does not have a recognizable MTD-based partition layout at {0}")]
MalformedPartitionLayout(&'static str),
#[error("This device does not have a recognizable partition: {0}")]
MalformedPartition(#[from] PartitionError),
#[error("This device does not have a MTD-based partition layout: this is unsupported")]
UnsupportedPartitionLayout,
#[error("This device has an unexpected partition layout with respect to its device type")]
UnexpectedPartitionLayout,
}
impl From<ChannelError> for DeviceError {
fn from(value: ChannelError) -> Self {
DeviceError::ChannelError(value)
}
}
pub type Result<V> = std::result::Result<V, DeviceError>;
impl Device {
pub fn open_uri(uri: &str) -> Result<Self> {
let uri = parse_uri(uri).map_err(DeviceError::MalformedConnectionURI)?;
match uri.scheme {
"serial" => {
todo!();
},
"ssh" => {
todo!();
},
_ => return Err(DeviceError::UnsupportedConnectionScheme(uri.scheme.to_string()))
}
}
pub fn new(channel: Box<dyn InteractionChannel>) -> Self {
Device {
channel,
operational_state: None
}
}
fn assert_linux_style_environment(&self) -> Result<()> {
// Assert we are in Liminix or OpenWRT.
if !matches!(self.operational_state, Some(OSOperState::Userspace(DistributionType::Liminix { .. })) | Some(OSOperState::Userspace(DistributionType::OpenWrt { .. }))) {
if self.operational_state.is_some() {
return Err(DeviceError::UnsupportedOperationalState(self.operational_state.clone().unwrap()));
} else {
return Err(DeviceError::UnknownOperationalState);
}
}
Ok(())
}
fn gather_os_operational_state(&mut self) -> Result<OSOperState> {
// 1. Ask the underlying layer if it can know what is the current operational state.
// Returns it.
let inferred_oper_state = self.channel.infer_operational_state()?;
if let Some(oper_state) = inferred_oper_state {
return Ok(oper_state);
}
// 2. If it cannot guess, it means it's either a recovery or a userspace.
// 3. Run a command to determine if we have a busybox.
let has_busybox: bool = self.channel.has_executable_in_path("busybox")?;
// 4. If we have no busybox, fail by explaining that we have unknown OS oper state.
if !has_busybox {
return Err(DeviceError::UnknownOperationalState);
}
// 5. If we have a busybox,
// (1) check for the existence of /nix/store → Liminix.
let nstore_path = PathBuf::from_str("/nix/store").unwrap();
let has_nix_store: bool = self.channel.has_directory(&nstore_path)?;
if has_nix_store {
let liminix_version_path = PathBuf::from_str("/etc/liminix-version").unwrap();
let nixpkgs_version_path = PathBuf::from_str("/etc/nixpkgs-version").unwrap();
return Ok(OSOperState::Userspace(DistributionType::Liminix {
revision: String::from_utf8(self.channel.read_file(&liminix_version_path)?).expect("Expected valid UTF-8 for revision"),
nixpkgs_revision: String::from_utf8(self.channel.read_file(&nixpkgs_version_path)?).expect("Expected valid UTF-8 for revision"),
}))
}
// TODO: (2) check for the existence of OpenWrt specific → ...
// (3) return unknown.
Ok(OSOperState::Userspace(DistributionType::Unknown))
}
fn gather_device_type(&mut self) -> Result<crate::state::DeviceType> {
self.assert_linux_style_environment()?;
// Read the kernel log and find "Machine is XYZ".
let kernel_log = self.channel.get_kernel_log()?;
let locate_machine_name = Regex::new(r"machine is (?<name>.*)").unwrap();
// Use a regex to find "Machine is ..."
let caps = locate_machine_name.captures(&kernel_log).unwrap();
let machine_name = caps["name"].to_string();
match machine_name.as_str() {
"ZyXEL NWA50AX" => Ok(crate::state::DeviceType::NWA50AX),
_ => Ok(crate::state::DeviceType::Custom(machine_name))
}
}
fn gather_partition_layout(&mut self) -> Result<super::state::PartitionLayout> {
self.assert_linux_style_environment()?;
let mtd_filepath = PathBuf::from_str("/proc/mtd").unwrap();
let mtd_data = String::from_utf8(self.channel.read_file(&mtd_filepath)?).expect("Expected valid UTF-8 for /proc/mtd");
let lines: Vec<&str> = mtd_data.split_terminator("\n").collect();
let header_regex = Regex::new(r"dev: size erasesize name").unwrap();
let line_regex = Regex::new(r#"(?<partname>mtd[0-9]+):\s+(?<size>[0-9a-fA-F]+)\s+(?<erasesize>[0-9a-fA-F]+)\s+"(?<name>[^"]+)""#).unwrap();
let header = lines.first().expect("At least the header should be present in /proc/mtd");
if !header_regex.find(header).is_some() {
return Err(DeviceError::MalformedPartitionLayout("header"));
}
let mut layout = PartitionLayout::new();
for line in &lines[1..] {
let caps = line_regex.captures(line);
if let Some(captures) = caps {
let partname = &captures["partname"];
let size = u64::from_str_radix(&captures["size"], 16).map_err(|_| DeviceError::MalformedPartitionLayout("size"))?;
let partition = Partition::new(&captures["name"],
partname,
u64::from_str_radix(&captures["erasesize"], 16).map_err(|_| DeviceError::MalformedPartitionLayout("erasesize"))?,
size,
).map_err(DeviceError::MalformedPartition)?;
layout.insert(partname.to_string(), partition);
} else {
return Err(DeviceError::MalformedPartitionLayout("body"));
}
}
Ok(layout)
}
fn gather_running_image_type(&self) -> Result<super::state::ImageType> {
// Assert we know at least one ABSchemeConfiguration partition.
// If not, warn about this.
//
// Assume primary.
//
// If we have an ABSchemeConfiguration partition, look for it.
// Perform static dispatch for every device, parse the result.
Ok(super::state::ImageType::Primary)
}
pub fn gather_runtime_state(&mut self) -> Result<super::state::RuntimeState> {
// 1. Determine OS operational state
// If it's in any of the wrong state, report error.
let os_oper_state = self.gather_os_operational_state()?;
match os_oper_state {
OSOperState::UBoot | OSOperState::Recovery | OSOperState::KernelPanicked(_) => return Err(DeviceError::UnsupportedOperationalState(os_oper_state)),
_ => {}
}
self.operational_state = Some(os_oper_state);
// 2. Determine device type.
let dtype = self.gather_device_type()?;
// 3. Determine partition layout
let playout = self.gather_partition_layout()?;
// and match it with one of the known partition layouts for that device type.
if !dtype.is_compatible_with(&playout) {
return Err(DeviceError::UnexpectedPartitionLayout);
}
// 4. Determine running image type given the device type.
let running_itype = self.gather_running_image_type()?;
Ok(crate::state::RuntimeState::new(dtype, playout, running_itype))
}
}
#[cfg(test)]
mod tests {
use std::{collections::{HashMap, HashSet}, path::PathBuf, str::FromStr};
use crate::{channels::InteractionChannel, state::{OSOperState, PartitionType}};
use super::Device;
#[derive(Default)]
struct FakeChannel {
pub oper_state: Option<OSOperState>,
pub file_contents: HashMap<std::path::PathBuf, String>,
pub kernel_log: Option<String>,
pub available_executables: HashSet<String>,
pub available_directories: HashSet<std::path::PathBuf>
}
type Result<V> = std::result::Result<V, crate::channels::ChannelError>;
impl InteractionChannel for FakeChannel {
fn infer_operational_state(&mut self) -> Result<Option<crate::state::OSOperState>> {
Ok(self.oper_state.clone())
}
fn execute(&mut self, cmd: &str) -> Result<Vec<u8>> {
Ok(Vec::new())
}
fn has_executable_in_path(&mut self, executable: &str) -> Result<bool> {
Ok(self.available_executables.contains(executable))
}
fn get_kernel_log(&mut self) -> Result<String> {
Ok(self.kernel_log.clone().expect("Failed to obtain kernel log"))
}
fn read_file(&mut self, path: &std::path::Path) -> Result<Vec<u8>> {
Ok(self.file_contents.get(path).unwrap().as_bytes().to_vec())
}
fn has_directory(&mut self, path: &std::path::Path) -> Result<bool> {
Ok(self.available_directories.contains(path))
}
}
// Create a fake interaction channel that can mock things.
#[test]
fn test_parse_kernel_log_for_machine_type() {
let channel = Box::new(FakeChannel {
oper_state: Some(OSOperState::Userspace(crate::state::DistributionType::Liminix { revision: "aaaa".to_string(), nixpkgs_revision: "bbbb".to_string() })),
kernel_log: Some(include_str!("tests/kernel.log").to_string()),
..Default::default()
});
let mut device = Device::new(channel);
let os_oper_state = device.gather_os_operational_state().expect("Failed to gather the OS operational state");
device.operational_state = Some(os_oper_state);
let dtype = device.gather_device_type().expect("Failed to gather device type");
println!("{:?}", dtype);
assert!(matches!(dtype, crate::state::DeviceType::NWA50AX));
}
#[test]
fn test_parse_mtd_partition_layout() {
let channel = Box::new(FakeChannel {
oper_state: Some(OSOperState::Userspace(crate::state::DistributionType::Liminix { revision: "aaaa".to_string(), nixpkgs_revision: "bbbb".to_string() })),
file_contents: HashMap::from(
[(PathBuf::from_str("/proc/mtd").unwrap(), include_str!("tests/mtd-partitions.log").to_string())]
),
..Default::default()
});
let mut device = Device::new(channel);
let os_oper_state = device.gather_os_operational_state().expect("Failed to gather the OS operational state");
device.operational_state = Some(os_oper_state);
let layout = device.gather_partition_layout().expect("Failed to gather partition layout");
for partition in layout.values() {
assert_eq!(partition.erase_size, 131072);
}
// mtd10 are logs.
assert_eq!(layout.get("mtd10").unwrap().name, "logs");
assert_eq!(layout.get("mtd10").unwrap().size, 13631488);
assert!(matches!(layout.get("mtd10").unwrap().r#type, PartitionType::Logs));
// ~ 128 MiB
assert_eq!(layout.values().filter(|p| !matches!(p.r#type, PartitionType::Image { .. })).map(|p| p.size).sum::<u64>(), 125829120);
}
fn test_parse_disk_state() {
}
fn test_parse_memory_state() {
}
}

View file

@ -0,0 +1,83 @@
use thiserror::Error;
use clap::Parser;
mod channels;
mod interaction;
mod state;
#[derive(Debug, Error)]
enum DeploymentError {
#[error("During information gathering error, we encountered a device-specific error: {0}")]
InformationGatheringError(
#[source]
interaction::DeviceError
),
#[error("Delta closure does not fit on the target partition, levitation is needed but cannot be enabled automatically yet")]
LevitationRequired,
}
struct Toplevel {
made_for: state::DeviceType,
path: String
}
#[derive(Parser, Debug)]
#[command(version, about)]
struct Args {
/// Top-level path for the deployment
toplevel_path: String,
/// Connection URI to the target
/// e.g. `serial:///dev/ttyUSB0`
/// e.g. `ssh://root@...`
connection_uri: String,
#[arg(long, default_value_t = false)]
dry_run: bool,
}
fn main() {
let args = Args::parse();
// 1. Open the toplevel_path
// Obtain the theoretical target information, e.g. what device is it.
// Populate a `Toplevel` structure.
// 2. Connect to the connection URI
let mut device = interaction::Device::open_uri(&args.connection_uri).expect("Failed to open the device");
// Run information gathering procedure.
let runtime_state = device.gather_runtime_state().expect("Failed to gather the runtime state");
// Compare theoretical target information with actual target information.
// toplevel.is_compatible_with(runtime_state);
// Fail if it's wrong.
// 3. Compute the delta closure to send.
// let store_paths = device.get_store_paths_for(ImageState::Secondary);
// let delta = toplevel.delta(store_paths);
// 4. Compute the size of the delta closure
// let size = delta.size();
// Verify if it fits in the RAM, if not, fail.
// Verify if it fits in the target disk, if not, warn.
//
// 5. If it doesn't fit in the target disk, verify if levitation is available.
// If not, fail.
//
// 6. If it doesn't fit and levitation is available, propose levitation as a deployment method
// and go back to 2 with a levitation parameter, i.e. `?actual-system=/mnt` or something
// like that.
//
// 7. If it fits in the target disk, copy the contents of the store in the target.
// Under A/B:
// - Identify which image are we running, whether there's a success image and are we on it, if
// not, propose to reboot in the success image and wait for the device to be available again.
//
// - Instead of writing the contents of the store in the target, propose to mount the B store,
// write the contents over there, there's no need for levitation anymore.
//
// - Write the kernel image to the B partition as well and verify that its size fits the MTD
// sizes.
//
// - Put the new image under test, reboot into it, let the bootloader handle it. Wait for
// successful boot to the new image, if not, signal that deployment failed to pass A/B checks.
tracing::info!("Test {}", args.toplevel_path);
}

View file

@ -0,0 +1,156 @@
use std::collections::HashMap;
use thiserror::Error;
#[derive(Debug, Clone)]
pub enum DistributionType {
Liminix {
revision: String,
nixpkgs_revision: String
},
OpenWrt {
version: String
},
Unknown
}
#[derive(Debug, Clone)]
pub enum OSOperState {
UBoot,
Recovery,
Userspace(DistributionType),
KernelPanicked(String),
}
impl OSOperState {
pub fn is_in_userspace(&self) -> bool {
matches!(self, OSOperState::Userspace(_))
}
}
#[derive(Debug)]
pub enum ImageType {
Primary,
Secondary
}
#[derive(Debug)]
pub enum DeviceType {
NWA50AX,
Custom(String)
}
impl DeviceType {
pub fn is_compatible_with(&self, _: &PartitionLayout) -> bool {
true
}
}
#[derive(Debug)]
pub enum FilesystemType {
UBI,
JFFS2,
}
#[derive(Debug)]
pub enum ABSchemeType {
Zyxel
}
#[derive(Debug)]
pub enum PartitionType {
UBootFirmware,
UBootConfig,
/// kernel + rootfs concatenated.
Image {
variant: ImageType
},
Kernel {
variant: ImageType
},
RootFs {
fs_type: FilesystemType,
variant: ImageType
},
UserData,
Logs,
Vendor,
ABSchemeConfiguration {
variant: ABSchemeType
},
DeviceSpecificData
}
#[derive(Debug, Error)]
pub enum PartitionError {
#[error("The partition name '{0}' was not sufficient to determine the partition type")]
UnknownPartitionType(String),
}
#[derive(Debug)]
pub struct Partition {
pub size: u64,
pub erase_size: u64,
// offset are hard to compute using the /proc/mtd file.
// we need also the DTB file as well because partitions can be overlapping.
pub name: String,
pub partname: String,
pub r#type: PartitionType
}
impl Partition {
pub fn new(name: &str, partname: &str, erase_size: u64, size: u64) -> Result<Self, PartitionError> {
let r#type = match name {
"u-boot" => PartitionType::UBootFirmware,
"u-boot-env" => PartitionType::UBootConfig,
"factory" | "vendor-myzyxel" => PartitionType::Vendor,
"firmware" | "firmware_a" => PartitionType::Image {
variant: ImageType::Primary
},
"firmware_b" => PartitionType::Image {
variant: ImageType::Secondary
},
"kernel" | "kernel_a" => PartitionType::Kernel { variant: ImageType::Primary },
"kernel_b" => PartitionType::Kernel { variant: ImageType::Secondary },
"ubi" | "ubi_a" => PartitionType::RootFs {
fs_type: FilesystemType::UBI,
variant: ImageType::Primary
},
"ubi_b" => PartitionType::RootFs { fs_type: FilesystemType::UBI, variant: ImageType::Secondary },
"rootfs_data" => PartitionType::UserData,
"logs" => PartitionType::Logs,
"bootconfig" => PartitionType::ABSchemeConfiguration { variant: ABSchemeType::Zyxel },
"mrd" => PartitionType::DeviceSpecificData,
_ => return Err(PartitionError::UnknownPartitionType(name.to_string()))
};
Ok(Self {
name: name.to_string(),
partname: partname.to_string(),
size,
erase_size,
r#type
})
}
}
pub type PartitionLayout = HashMap<String, Partition>;
pub struct RuntimeState {
device_type: DeviceType,
partition_layout: PartitionLayout,
running_image: ImageType,
//memory_state: MemoryState,
//disk_state: DiskState
}
impl RuntimeState {
pub fn new(device_type: DeviceType, partition_layout: PartitionLayout, running_image: ImageType) -> Self {
Self {
device_type,
partition_layout,
running_image
}
}
}

View file

@ -0,0 +1,3 @@
total used free shared buff/cache available
Mem: 250920 36056 201556 1452 13308 205368
Swap: 0 0 0

View file

@ -0,0 +1,328 @@
U-Boot SPL 2018.09 (Jan 22 2021 - 07:42:43 +0000)
Trying to boot from NAND
Initializing NMBM ...
Signature found at block 1023 [0x07fe0000]
First info table with writecount 23 found in block 960
Second info table with writecount 23 found in block 963
NMBM has been successfully attached
U-Boot 2018.09 (Jan 22 2021 - 07:42:43 +0000)
CPU: MediaTek MT7621AT ver 1, eco 3
Clocks: CPU: 880MHz, DDR: 600MHz (1200MT/s), Bus: 220MHz, XTAL: 40MHz
Model: MediaTek MT7621 reference board (NAND)
DRAM: 256 MiB
NAND: 128 MiB
Initializing NMBM ...
Signature found at block 1023 [0x07fe0000]
First info table with writecount 23 found in block 960
Second info table with writecount 23 found in block 963
NMBM has been successfully attached
Loading Environment from NMBM... *** Warning - bad CRC, using default environment
In: uartlite0@1e000c00
Out: uartlite0@1e000c00
Err: uartlite0@1e000c00
Net:
Warning: eth@1e100000 (eth0) using random MAC address - fa:26:d7:78:e2:6c
eth0: eth@1e100000
Reading from 0x7700000, size 0x20000
Succeeded
Zyxel version:V1.03
gpio: pin 6 (gpio 6) value is 1
gpio: pin 24 (gpio 24) value is 0
gpio: pin 24 (gpio 24) value is 1
Hit any key to stop autoboot: 0
Loading FIT image at offset 0x180000 to memory 0x83000000, size 0x2c4098 ...
Automatic boot of image at addr 0x83000000 ...
## Loading kernel from FIT Image at 83000000 ...
Using 'conf-1' configuration
Trying 'kernel' kernel subimage
Description: Vanilla Linux kernel
Type: Kernel Image
Compression: lzma compressed
Data Start: 0x83000110
Data Size: 2886231 Bytes = 2.8 MiB
Architecture: MIPS
OS: Linux
Load Address: 0x80001000
Entry Point: 0x80001000
Hash algo: crc32
Hash value: 2b3aa711
Hash algo: sha1
Hash value: c6601a1909011f95acfbfaed2c6c2b4f6703a98a
Verifying Hash Integrity ... crc32+ sha1+ OK
## Loading fdt from FIT Image at 83000000 ...
Using 'conf-1' configuration
Trying 'fdt-1' fdt subimage
Description: Flattened Device Tree blob
Type: Flat Device Tree
Compression: uncompressed
Data Start: 0x832c0c94
Data Size: 12011 Bytes = 11.7 KiB
Architecture: MIPS
Hash algo: crc32
Hash value: e712ab77
Hash algo: sha1
Hash value: 705532a8d74d5d6921aada1572531caf385c4aaf
Verifying Hash Integrity ... crc32+ sha1+ OK
Booting using the fdt blob at 0x832c0c94
Uncompressing Kernel Image ... OK
Loading Device Tree to 8fe67000, end 8fe6ceea ... OK
[ 0.000000] Linux version 5.15.137 (nixbld@liminix.builder) (mipsel-unknown-linux-musl-gcc (GCC) 13.3.0, GNU ld (GNU Binutils) 2.42) #1 SMP Mon Aug 26 18:09:43 UTC 2024
[ 0.000000] SoC Type: MediaTek MT7621 ver:1 eco:3
[ 0.000000] printk: bootconsole [early0] enabled
[ 0.000000] CPU0 revision is: 0001992f (MIPS 1004Kc)
[ 0.000000] MIPS: machine is ZyXEL NWA50AX
[ 0.000000] Initrd not found or empty - disabling initrd
[ 0.000000] Detected 1 available secondary CPU(s)
[ 0.000000] Primary instruction cache 32kB, VIPT, 4-way, linesize 32 bytes.
[ 0.000000] Primary data cache 32kB, 4-way, PIPT, no aliases, linesize 32 bytes
[ 0.000000] MIPS secondary cache 256kB, 8-way, linesize 32 bytes.
[ 0.000000] Zone ranges:
[ 0.000000] Normal [mem 0x0000000000000000-0x000000000fffffff]
[ 0.000000] Movable zone start for each node
[ 0.000000] Early memory node ranges
[ 0.000000] node 0: [mem 0x0000000000000000-0x000000000fffffff]
[ 0.000000] Initmem setup node 0 [mem 0x0000000000000000-0x000000000fffffff]
[ 0.000000] percpu: Embedded 10 pages/cpu s11184 r8192 d21584 u40960
[ 0.000000] pcpu-alloc: s11184 r8192 d21584 u40960 alloc=10*4096
[ 0.000000] pcpu-alloc: [0] 0 [0] 1
[ 0.000000] Built 1 zonelists, mobility grouping on. Total pages: 65024
[ 0.000000] Kernel command line: console=ttyS0,115200 panic=10 oops=panic init=/bin/init loglevel=8 root=ubi0:rootfs rootfstype=ubifs fw_devlink=off ubi.mtd=ubi_a ubi.mtd=ubi_b rootalt=ubi1:rootfs
[ 0.000000] Unknown kernel command line parameters "rootalt=ubi1:rootfs", will be passed to user space.
[ 0.000000] Dentry cache hash table entries: 32768 (order: 5, 131072 bytes, linear)
[ 0.000000] Inode-cache hash table entries: 16384 (order: 4, 65536 bytes, linear)
[ 0.000000] Writing ErrCtl register=000307c0
[ 0.000000] Readback ErrCtl register=000307c0
[ 0.000000] mem auto-init: stack:all(zero), heap alloc:off, heap free:off
[ 0.000000] Memory: 249660K/262144K available (6690K kernel code, 620K rwdata, 1272K rodata, 1260K init, 215K bss, 12484K reserved, 0K cma-reserved)
[ 0.000000] SLUB: HWalign=32, Order=0-3, MinObjects=0, CPUs=2, Nodes=1
[ 0.000000] rcu: Hierarchical RCU implementation.
[ 0.000000] rcu: RCU event tracing is enabled.
[ 0.000000] rcu: RCU calculated value of scheduler-enlistment delay is 25 jiffies.
[ 0.000000] NR_IRQS: 256
[ 0.000000] clocksource: GIC: mask: 0xffffffffffffffff max_cycles: 0xcaf478abb4, max_idle_ns: 440795247997 ns
[ 0.000003] sched_clock: 64 bits at 880MHz, resolution 1ns, wraps every 4398046511103ns
[ 0.008219] Console: colour dummy device 80x25
[ 0.012632] Calibrating delay loop... 583.68 BogoMIPS (lpj=1167360)
[ 0.046815] pid_max: default: 32768 minimum: 301
[ 0.051584] Mount-cache hash table entries: 1024 (order: 0, 4096 bytes, linear)
[ 0.058814] Mountpoint-cache hash table entries: 1024 (order: 0, 4096 bytes, linear)
[ 0.068781] rcu: Hierarchical SRCU implementation.
[ 0.074119] smp: Bringing up secondary CPUs ...
[ 0.079356] Primary instruction cache 32kB, VIPT, 4-way, linesize 32 bytes.
[ 0.079377] Primary data cache 32kB, 4-way, PIPT, no aliases, linesize 32 bytes
[ 0.079391] MIPS secondary cache 256kB, 8-way, linesize 32 bytes.
[ 0.079436] CPU1 revision is: 0001992f (MIPS 1004Kc)
[ 0.106818] Synchronize counters for CPU 1: done.
[ 0.137420] smp: Brought up 1 node, 2 CPUs
[ 0.142178] devtmpfs: initialized
[ 0.149145] clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 7645041785100000 ns
[ 0.158853] futex hash table entries: 512 (order: 2, 16384 bytes, linear)
[ 0.165690] pinctrl core: initialized pinctrl subsystem
[ 0.172367] NET: Registered PF_NETLINK/PF_ROUTE protocol family
[ 0.195333] FPU Affinity set after 4688 emulations
[ 0.210943] vgaarb: loaded
[ 0.213836] pps_core: LinuxPPS API ver. 1 registered
[ 0.218720] pps_core: Software ver. 5.3.6 - Copyright 2005-2007 Rodolfo Giometti <giometti@linux.it>
[ 0.227854] PTP clock support registered
[ 0.232998] clocksource: Switched to clocksource GIC
[ 0.247935] NET: Registered PF_INET protocol family
[ 0.253125] IP idents hash table entries: 4096 (order: 3, 32768 bytes, linear)
[ 0.261130] tcp_listen_portaddr_hash hash table entries: 512 (order: 0, 6144 bytes, linear)
[ 0.269459] Table-perturb hash table entries: 65536 (order: 6, 262144 bytes, linear)
[ 0.277129] TCP established hash table entries: 2048 (order: 1, 8192 bytes, linear)
[ 0.284755] TCP bind hash table entries: 2048 (order: 2, 16384 bytes, linear)
[ 0.291853] TCP: Hash tables configured (established 2048 bind 2048)
[ 0.298251] UDP hash table entries: 256 (order: 1, 8192 bytes, linear)
[ 0.304746] UDP-Lite hash table entries: 256 (order: 1, 8192 bytes, linear)
[ 0.311881] NET: Registered PF_UNIX/PF_LOCAL protocol family
[ 0.317505] PCI: CLS 0 bytes, default 32
[ 0.322026] Initialise system trusted keyrings
[ 0.327035] workingset: timestamp_bits=30 max_order=16 bucket_order=0
[ 0.338742] squashfs: version 4.0 (2009/01/31) Phillip Lougher
[ 0.344665] NET: Registered PF_ALG protocol family
[ 0.349399] Key type asymmetric registered
[ 0.353449] Asymmetric key parser 'x509' registered
[ 0.358358] io scheduler mq-deadline registered
[ 0.362815] io scheduler kyber registered
[ 0.368221] mt7621_gpio 1e000600.gpio: registering 32 gpios
[ 0.374020] mt7621_gpio 1e000600.gpio: registering 32 gpios
[ 0.379793] mt7621_gpio 1e000600.gpio: registering 32 gpios
[ 0.385647] mt7621-pci 1e140000.pcie: host bridge /pcie@1e140000 ranges:
[ 0.392289] mt7621-pci 1e140000.pcie: No bus range found for /pcie@1e140000, using [bus 00-ff]
[ 0.401045] mt7621-pci 1e140000.pcie: MEM 0x0060000000..0x006fffffff -> 0x0060000000
[ 0.409152] mt7621-pci 1e140000.pcie: IO 0x001e160000..0x001e16ffff -> 0x0000000000
[ 0.740955] mt7621-pci 1e140000.pcie: pcie2 no card, disable it (RST & CLK)
[ 0.747846] mt7621-pci 1e140000.pcie: PCIE0 enabled
[ 0.752677] mt7621-pci 1e140000.pcie: PCIE1 enabled
[ 0.757536] PCI coherence region base: 0x60000000, mask/settings: 0xf0000002
[ 0.764608] mt7621-pci 1e140000.pcie: PCI host bridge to bus 0000:00
[ 0.770889] pci_bus 0000:00: root bus resource [bus 00-ff]
[ 0.776322] pci_bus 0000:00: root bus resource [mem 0x60000000-0x6fffffff]
[ 0.783158] pci_bus 0000:00: root bus resource [io 0x0000-0xffff]
[ 0.789335] pci 0000:00:00.0: [0e8d:0801] type 01 class 0x060400
[ 0.795284] pci 0000:00:00.0: reg 0x10: [mem 0x00000000-0x7fffffff]
[ 0.801502] pci 0000:00:00.0: reg 0x14: [mem 0x60600000-0x6060ffff]
[ 0.807783] pci 0000:00:00.0: supports D1
[ 0.811723] pci 0000:00:00.0: PME# supported from D0 D1 D3hot
[ 0.817741] pci 0000:00:01.0: [0e8d:0801] type 01 class 0x060400
[ 0.823690] pci 0000:00:01.0: reg 0x10: [mem 0x00000000-0x7fffffff]
[ 0.829903] pci 0000:00:01.0: reg 0x14: [mem 0x60610000-0x6061ffff]
[ 0.836181] pci 0000:00:01.0: supports D1
[ 0.840120] pci 0000:00:01.0: PME# supported from D0 D1 D3hot
[ 0.847184] pci 0000:01:00.0: [14c3:7916] type 00 class 0x000280
[ 0.853152] pci 0000:01:00.0: reg 0x10: [mem 0x00000000-0x000fffff 64bit pref]
[ 0.860309] pci 0000:01:00.0: reg 0x18: [mem 0x00000000-0x00003fff 64bit pref]
[ 0.867491] pci 0000:01:00.0: reg 0x20: [mem 0x00000000-0x00000fff 64bit pref]
[ 0.874765] pci 0000:01:00.0: supports D1 D2
[ 0.878963] pci 0000:01:00.0: PME# supported from D0 D1 D2 D3hot D3cold
[ 0.885578] pci 0000:01:00.0: 2.000 Gb/s available PCIe bandwidth, limited by 2.5 GT/s PCIe x1 link at 0000:00:00.0 (capable of 4.000 Gb/s with 5.0 GT/s PCIe x1 link)
[ 0.900515] pci 0000:00:00.0: ASPM: current common clock configuration is inconsistent, reconfiguring
[ 0.922059] pci 0000:00:00.0: PCI bridge to [bus 01-ff]
[ 0.927224] pci 0000:00:00.0: bridge window [io 0x0000-0x0fff]
[ 0.933267] pci 0000:00:00.0: bridge window [mem 0x60000000-0x600fffff]
[ 0.940003] pci 0000:00:00.0: bridge window [mem 0x60100000-0x602fffff pref]
[ 0.947180] pci_bus 0000:01: busn_res: [bus 01-ff] end is updated to 01
[ 0.953911] pci 0000:02:00.0: [14c3:7915] type 00 class 0x000280
[ 0.959872] pci 0000:02:00.0: reg 0x10: [mem 0x00000000-0x000fffff 64bit pref]
[ 0.967034] pci 0000:02:00.0: reg 0x18: [mem 0x00000000-0x00003fff 64bit pref]
[ 0.974205] pci 0000:02:00.0: reg 0x20: [mem 0x00000000-0x00000fff 64bit pref]
[ 0.981495] pci 0000:02:00.0: supports D1 D2
[ 0.985693] pci 0000:02:00.0: PME# supported from D0 D1 D2 D3hot D3cold
[ 0.992302] pci 0000:02:00.0: 2.000 Gb/s available PCIe bandwidth, limited by 2.5 GT/s PCIe x1 link at 0000:00:01.0 (capable of 4.000 Gb/s with 5.0 GT/s PCIe x1 link)
[ 1.007243] pci 0000:00:01.0: ASPM: current common clock configuration is inconsistent, reconfiguring
[ 1.026050] pci 0000:00:01.0: PCI bridge to [bus 02-ff]
[ 1.031213] pci 0000:00:01.0: bridge window [io 0x0000-0x0fff]
[ 1.037258] pci 0000:00:01.0: bridge window [mem 0x60300000-0x603fffff]
[ 1.043993] pci 0000:00:01.0: bridge window [mem 0x60400000-0x605fffff pref]
[ 1.051168] pci_bus 0000:02: busn_res: [bus 02-ff] end is updated to 02
[ 1.057783] pci 0000:00:00.0: BAR 0: no space for [mem size 0x80000000]
[ 1.064323] pci 0000:00:00.0: BAR 0: failed to assign [mem size 0x80000000]
[ 1.071237] pci 0000:00:01.0: BAR 0: no space for [mem size 0x80000000]
[ 1.077800] pci 0000:00:01.0: BAR 0: failed to assign [mem size 0x80000000]
[ 1.084712] pci 0000:00:00.0: BAR 8: assigned [mem 0x60000000-0x600fffff]
[ 1.091462] pci 0000:00:00.0: BAR 9: assigned [mem 0x60100000-0x602fffff pref]
[ 1.098632] pci 0000:00:01.0: BAR 8: assigned [mem 0x60300000-0x603fffff]
[ 1.105366] pci 0000:00:01.0: BAR 9: assigned [mem 0x60400000-0x605fffff pref]
[ 1.112532] pci 0000:00:00.0: BAR 1: assigned [mem 0x60600000-0x6060ffff]
[ 1.119279] pci 0000:00:01.0: BAR 1: assigned [mem 0x60610000-0x6061ffff]
[ 1.126017] pci 0000:00:00.0: BAR 7: assigned [io 0x0000-0x0fff]
[ 1.132058] pci 0000:00:01.0: BAR 7: assigned [io 0x1000-0x1fff]
[ 1.138123] pci 0000:01:00.0: BAR 0: assigned [mem 0x60100000-0x601fffff 64bit pref]
[ 1.145814] pci 0000:01:00.0: BAR 2: assigned [mem 0x60200000-0x60203fff 64bit pref]
[ 1.153509] pci 0000:01:00.0: BAR 4: assigned [mem 0x60204000-0x60204fff 64bit pref]
[ 1.161191] pci 0000:00:00.0: PCI bridge to [bus 01]
[ 1.166100] pci 0000:00:00.0: bridge window [io 0x0000-0x0fff]
[ 1.172148] pci 0000:00:00.0: bridge window [mem 0x60000000-0x600fffff]
[ 1.178890] pci 0000:00:00.0: bridge window [mem 0x60100000-0x602fffff pref]
[ 1.186069] pci 0000:02:00.0: BAR 0: assigned [mem 0x60400000-0x604fffff 64bit pref]
[ 1.193765] pci 0000:02:00.0: BAR 2: assigned [mem 0x60500000-0x60503fff 64bit pref]
[ 1.201460] pci 0000:02:00.0: BAR 4: assigned [mem 0x60504000-0x60504fff 64bit pref]
[ 1.209142] pci 0000:00:01.0: PCI bridge to [bus 02]
[ 1.214057] pci 0000:00:01.0: bridge window [io 0x1000-0x1fff]
[ 1.220099] pci 0000:00:01.0: bridge window [mem 0x60300000-0x603fffff]
[ 1.226842] pci 0000:00:01.0: bridge window [mem 0x60400000-0x605fffff pref]
[ 1.293542] Serial: 8250/16550 driver, 3 ports, IRQ sharing disabled
[ 1.301644] printk: console [ttyS0] disabled
[ 1.305976] 1e000c00.uartlite: ttyS0 at MMIO 0x1e000c00 (irq = 15, base_baud = 3125000) is a 16550A
[ 1.314993] printk: console [ttyS0] enabled
[ 1.314993] printk: console [ttyS0] enabled
[ 1.323262] printk: bootconsole [early0] disabled
[ 1.323262] printk: bootconsole [early0] disabled
[ 1.334173] nand: device found, Manufacturer ID: 0xc2, Chip ID: 0xf1
[ 1.340567] nand: Macronix MX30LF1G28AD
[ 1.344406] nand: 128 MiB, SLC, erase size: 128 KiB, page size: 2048, OOB size: 128
[ 1.352063] mt7621-nand 1e003000.nand: ECC strength adjusted to 12 bits
[ 1.361705] Signature found at block 1023 [0x07fe0000]
[ 1.366845] NMBM management region starts at block 960 [0x07800000]
[ 1.378939] First info table with writecount 23 found in block 960
[ 1.402434] Second info table with writecount 23 found in block 963
[ 1.408759] NMBM has been successfully attached
[ 1.413442] 10 fixed-partitions partitions found on MTD device mt7621-nand
[ 1.420708] Creating 10 MTD partitions on "mt7621-nand":
[ 1.426033] 0x000000000000-0x000000080000 : "u-boot"
[ 1.439393] 0x000000080000-0x000000100000 : "u-boot-env"
[ 1.453018] 0x000000100000-0x000000180000 : "factory"
[ 1.466290] 0x000000180000-0x000002980000 : "firmware_a"
[ 2.085192] 2 fixed-partitions partitions found on MTD device firmware_a
[ 2.091913] Creating 2 MTD partitions on "firmware_a":
[ 2.097057] 0x000000000000-0x000000800000 : "kernel_a"
[ 2.225364] 0x000000800000-0x000002800000 : "ubi_a"
[ 2.721502] 0x000002980000-0x000005180000 : "firmware_b"
[ 3.340201] 2 fixed-partitions partitions found on MTD device firmware_b
[ 3.346925] Creating 2 MTD partitions on "firmware_b":
[ 3.352064] 0x000000000000-0x000000800000 : "kernel_b"
[ 3.480209] 0x000000800000-0x000002800000 : "ubi_b"
[ 3.975604] 0x000005180000-0x000006580000 : "rootfs_data"
[ 4.287770] 0x000006580000-0x000007280000 : "logs"
[ 4.492133] 0x000007280000-0x000007700000 : "vendor-myzyxel"
[ 4.567214] 0x000007700000-0x000007780000 : "bootconfig"
[ 4.580694] 0x000007780000-0x000007800000 : "mrd"
[ 4.728864] mt7530-mdio mdio-bus:1f: MT7530 adapts as multi-chip module
[ 4.739458] mtk_soc_eth 1e100000.ethernet eth0: mediatek frame engine at 0xbe100000, irq 17
[ 4.749784] NET: Registered PF_INET6 protocol family
[ 4.756359] Segment Routing with IPv6
[ 4.760159] In-situ OAM (IOAM) with IPv6
[ 4.764195] sit: IPv6, IPv4 and MPLS over IPv4 tunneling driver
[ 4.770813] NET: Registered PF_PACKET protocol family
[ 4.776327] 8021q: 802.1Q VLAN Support v1.8
[ 4.781226] Loading compiled-in X.509 certificates
[ 4.797717] Loaded X.509 cert 'Build time autogenerated kernel key: 3cb1578c6bb232a0582cf98f15a4972f913c1af3'
[ 4.807657] Problem parsing in-kernel X.509 certificate list
[ 4.817384] Key type encrypted registered
[ 4.823997] mt7530-mdio mdio-bus:1f: MT7530 adapts as multi-chip module
[ 4.846401] mt7530-mdio mdio-bus:1f: configuring for fixed/rgmii link mode
[ 4.854160] mt7530-mdio mdio-bus:1f: Link is Up - 1Gbps/Full - flow control rx/tx
[ 4.859153] mt7530-mdio mdio-bus:1f lan (uninitialized): PHY [mt7530-0:04] driver [MediaTek MT7530 PHY] (irq=19)
[ 4.873468] DSA: tree 0 setup
[ 4.876897] ubi0: attaching mtd5
[ 5.863781] ubi0: scanning is finished
[ 5.890797] ubi0: attached mtd5 (name "ubi_a", size 32 MiB)
[ 5.896409] ubi0: PEB size: 131072 bytes (128 KiB), LEB size: 126976 bytes
[ 5.903277] ubi0: min./max. I/O unit sizes: 2048/2048, sub-page size 2048
[ 5.910056] ubi0: VID header offset: 2048 (aligned 2048), data offset: 4096
[ 5.917009] ubi0: good PEBs: 256, bad PEBs: 0, corrupted PEBs: 0
[ 5.923007] ubi0: user volume: 1, internal volumes: 1, max. volumes count: 128
[ 5.930219] ubi0: max/mean erase counter: 126998/126988, WL threshold: 4096, image sequence number: 315532800
[ 5.940115] ubi0: available PEBs: 0, total reserved PEBs: 256, PEBs reserved for bad PEB handling: 19
[ 5.949340] ubi0: background thread "ubi_bgt0d" started, PID 68
[ 5.953018] ubi1: attaching mtd8
[ 6.941910] ubi1: scanning is finished
[ 6.968862] ubi1: attached mtd8 (name "ubi_b", size 32 MiB)
[ 6.974487] ubi1: PEB size: 131072 bytes (128 KiB), LEB size: 126976 bytes
[ 6.981359] ubi1: min./max. I/O unit sizes: 2048/2048, sub-page size 2048
[ 6.988141] ubi1: VID header offset: 2048 (aligned 2048), data offset: 4096
[ 6.995099] ubi1: good PEBs: 256, bad PEBs: 0, corrupted PEBs: 0
[ 7.001112] ubi1: user volume: 1, internal volumes: 1, max. volumes count: 128
[ 7.008326] ubi1: max/mean erase counter: 126977/126976, WL threshold: 4096, image sequence number: 315532800
[ 7.018233] ubi1: available PEBs: 0, total reserved PEBs: 256, PEBs reserved for bad PEB handling: 19
[ 7.027465] ubi1: background thread "ubi_bgt1d" started, PID 69
[ 7.038616] Freeing unused kernel image (initmem) memory: 1260K
[ 7.044603] This architecture does not have kernel memory protection.
[ 7.051061] Run /init as init process
[ 7.054731] with arguments:
[ 7.057703] /init
[ 7.059965] with environment:
[ 7.063110] HOME=/
[ 7.065478] TERM=linux
[ 7.068172] rootalt=ubi1:rootfs
Running pre-init...
cmdline: "console=ttyS0,115[ 7.075377] UBIFS (ubi0:0): Mounting in unauthenticated mode
200 panic=10 oop[ 7.082657] UBIFS (ubi0:0): background thread "ubifs_bgt0_0" started, PID 70
s=panic init=/bin/init loglevel=8 root=ubi0:rootfs rootfstype=ubifs fw_devlink=off ubi.mtd=ubi_a ubi.mtd=ubi_b rootalt=ubi1:rootfs"
rootdevice ubi0:rootfs (ubifs, altdevice=ubi1:rootfs)
[ 7.204958] UBIFS (ubi0:0): recovery needed
[ 7.598521] UBIFS (ubi0:0): recovery completed
[ 7.603217] UBIFS (ubi0:0): UBIFS: mounted UBI device 0, volume 0, name "rootfs"
[ 7.610665] UBIFS (ubi0:0): LEB size: 126976 bytes (124 KiB), min./max. I/O unit sizes: 2048 bytes/2048 bytes
[ 7.620568] UBIFS (ubi0:0): FS size: 28315648 bytes (27 MiB, 223 LEBs), max 256 LEBs, journal size 4444160 bytes (4 MiB, 35 LEBs)
[ 7.632205] UBIFS (ubi0:0): reserved for root: 0 bytes (0 KiB)
[ 7.638040] UBIFS (ubi0:0): media format: w4/r0 (latest is w5/r0), UUID A68EAB38-9D1E-4184-AEFB-63A0740A6A2D, small LPT model
s6-linux-init version 1.1.2.0

View file

@ -0,0 +1,295 @@
<5>[ 0.000000] Linux version 5.15.137 (nixbld@liminix.builder) (mipsel-unknown-linux-musl-gcc (GCC) 13.3.0, GNU ld (GNU Binutils) 2.42) #1 SMP Mon Aug 26 18:09:43 UTC 2024
<6>[ 0.000000] SoC Type: MediaTek MT7621 ver:1 eco:3
<6>[ 0.000000] printk: bootconsole [early0] enabled
<6>[ 0.000000] CPU0 revision is: 0001992f (MIPS 1004Kc)
<6>[ 0.000000] MIPS: machine is ZyXEL NWA50AX
<6>[ 0.000000] Initrd not found or empty - disabling initrd
<6>[ 0.000000] Detected 1 available secondary CPU(s)
<6>[ 0.000000] Primary instruction cache 32kB, VIPT, 4-way, linesize 32 bytes.
<6>[ 0.000000] Primary data cache 32kB, 4-way, PIPT, no aliases, linesize 32 bytes
<4>[ 0.000000] MIPS secondary cache 256kB, 8-way, linesize 32 bytes.
<6>[ 0.000000] Zone ranges:
<6>[ 0.000000] Normal [mem 0x0000000000000000-0x000000000fffffff]
<6>[ 0.000000] Movable zone start for each node
<6>[ 0.000000] Early memory node ranges
<6>[ 0.000000] node 0: [mem 0x0000000000000000-0x000000000fffffff]
<6>[ 0.000000] Initmem setup node 0 [mem 0x0000000000000000-0x000000000fffffff]
<6>[ 0.000000] percpu: Embedded 10 pages/cpu s11184 r8192 d21584 u40960
<7>[ 0.000000] pcpu-alloc: s11184 r8192 d21584 u40960 alloc=10*4096
<7>[ 0.000000] pcpu-alloc: [0] 0 [0] 1
<6>[ 0.000000] Built 1 zonelists, mobility grouping on. Total pages: 65024
<5>[ 0.000000] Kernel command line: console=ttyS0,115200 panic=10 oops=panic init=/bin/init loglevel=8 root=ubi0:rootfs rootfstype=ubifs fw_devlink=off ubi.mtd=ubi_a ubi.mtd=ubi_b rootalt=ubi1:rootfs
<5>[ 0.000000] Unknown kernel command line parameters "rootalt=ubi1:rootfs", will be passed to user space.
<6>[ 0.000000] Dentry cache hash table entries: 32768 (order: 5, 131072 bytes, linear)
<6>[ 0.000000] Inode-cache hash table entries: 16384 (order: 4, 65536 bytes, linear)
<6>[ 0.000000] Writing ErrCtl register=000307c0
<6>[ 0.000000] Readback ErrCtl register=000307c0
<6>[ 0.000000] mem auto-init: stack:all(zero), heap alloc:off, heap free:off
<6>[ 0.000000] Memory: 249660K/262144K available (6690K kernel code, 620K rwdata, 1272K rodata, 1260K init, 215K bss, 12484K reserved, 0K cma-reserved)
<6>[ 0.000000] SLUB: HWalign=32, Order=0-3, MinObjects=0, CPUs=2, Nodes=1
<6>[ 0.000000] rcu: Hierarchical RCU implementation.
<6>[ 0.000000] rcu: RCU event tracing is enabled.
<6>[ 0.000000] rcu: RCU calculated value of scheduler-enlistment delay is 25 jiffies.
<6>[ 0.000000] NR_IRQS: 256
<6>[ 0.000000] clocksource: GIC: mask: 0xffffffffffffffff max_cycles: 0xcaf478abb4, max_idle_ns: 440795247997 ns
<6>[ 0.000004] sched_clock: 64 bits at 880MHz, resolution 1ns, wraps every 4398046511103ns
<6>[ 0.008218] Console: colour dummy device 80x25
<6>[ 0.012632] Calibrating delay loop... 583.68 BogoMIPS (lpj=1167360)
<6>[ 0.046814] pid_max: default: 32768 minimum: 301
<6>[ 0.051583] Mount-cache hash table entries: 1024 (order: 0, 4096 bytes, linear)
<6>[ 0.058813] Mountpoint-cache hash table entries: 1024 (order: 0, 4096 bytes, linear)
<6>[ 0.068777] rcu: Hierarchical SRCU implementation.
<6>[ 0.074116] smp: Bringing up secondary CPUs ...
<6>[ 0.079353] Primary instruction cache 32kB, VIPT, 4-way, linesize 32 bytes.
<6>[ 0.079374] Primary data cache 32kB, 4-way, PIPT, no aliases, linesize 32 bytes
<4>[ 0.079388] MIPS secondary cache 256kB, 8-way, linesize 32 bytes.
<6>[ 0.079433] CPU1 revision is: 0001992f (MIPS 1004Kc)
<6>[ 0.106815] Synchronize counters for CPU 1: done.
<6>[ 0.137415] smp: Brought up 1 node, 2 CPUs
<6>[ 0.142174] devtmpfs: initialized
<6>[ 0.149141] clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 7645041785100000 ns
<6>[ 0.158851] futex hash table entries: 512 (order: 2, 16384 bytes, linear)
<6>[ 0.165686] pinctrl core: initialized pinctrl subsystem
<6>[ 0.172363] NET: Registered PF_NETLINK/PF_ROUTE protocol family
<7>[ 0.195326] FPU Affinity set after 4688 emulations
<6>[ 0.210941] vgaarb: loaded
<6>[ 0.213833] pps_core: LinuxPPS API ver. 1 registered
<6>[ 0.218718] pps_core: Software ver. 5.3.6 - Copyright 2005-2007 Rodolfo Giometti <giometti@linux.it>
<6>[ 0.227852] PTP clock support registered
<6>[ 0.232996] clocksource: Switched to clocksource GIC
<6>[ 0.247916] NET: Registered PF_INET protocol family
<6>[ 0.253106] IP idents hash table entries: 4096 (order: 3, 32768 bytes, linear)
<6>[ 0.261109] tcp_listen_portaddr_hash hash table entries: 512 (order: 0, 6144 bytes, linear)
<6>[ 0.269438] Table-perturb hash table entries: 65536 (order: 6, 262144 bytes, linear)
<6>[ 0.277109] TCP established hash table entries: 2048 (order: 1, 8192 bytes, linear)
<6>[ 0.284734] TCP bind hash table entries: 2048 (order: 2, 16384 bytes, linear)
<6>[ 0.291833] TCP: Hash tables configured (established 2048 bind 2048)
<6>[ 0.298233] UDP hash table entries: 256 (order: 1, 8192 bytes, linear)
<6>[ 0.304728] UDP-Lite hash table entries: 256 (order: 1, 8192 bytes, linear)
<6>[ 0.311863] NET: Registered PF_UNIX/PF_LOCAL protocol family
<6>[ 0.317488] PCI: CLS 0 bytes, default 32
<5>[ 0.322010] Initialise system trusted keyrings
<6>[ 0.326848] workingset: timestamp_bits=30 max_order=16 bucket_order=0
<6>[ 0.338689] squashfs: version 4.0 (2009/01/31) Phillip Lougher
<6>[ 0.344647] NET: Registered PF_ALG protocol family
<5>[ 0.349383] Key type asymmetric registered
<5>[ 0.353437] Asymmetric key parser 'x509' registered
<6>[ 0.358339] io scheduler mq-deadline registered
<6>[ 0.362797] io scheduler kyber registered
<6>[ 0.368367] mt7621_gpio 1e000600.gpio: registering 32 gpios
<6>[ 0.374144] mt7621_gpio 1e000600.gpio: registering 32 gpios
<6>[ 0.379906] mt7621_gpio 1e000600.gpio: registering 32 gpios
<6>[ 0.385758] mt7621-pci 1e140000.pcie: host bridge /pcie@1e140000 ranges:
<6>[ 0.392397] mt7621-pci 1e140000.pcie: No bus range found for /pcie@1e140000, using [bus 00-ff]
<6>[ 0.401153] mt7621-pci 1e140000.pcie: MEM 0x0060000000..0x006fffffff -> 0x0060000000
<6>[ 0.409262] mt7621-pci 1e140000.pcie: IO 0x001e160000..0x001e16ffff -> 0x0000000000
<6>[ 0.740953] mt7621-pci 1e140000.pcie: pcie2 no card, disable it (RST & CLK)
<6>[ 0.747846] mt7621-pci 1e140000.pcie: PCIE0 enabled
<6>[ 0.752676] mt7621-pci 1e140000.pcie: PCIE1 enabled
<6>[ 0.757535] PCI coherence region base: 0x60000000, mask/settings: 0xf0000002
<6>[ 0.764608] mt7621-pci 1e140000.pcie: PCI host bridge to bus 0000:00
<6>[ 0.770890] pci_bus 0000:00: root bus resource [bus 00-ff]
<6>[ 0.776323] pci_bus 0000:00: root bus resource [mem 0x60000000-0x6fffffff]
<6>[ 0.783159] pci_bus 0000:00: root bus resource [io 0x0000-0xffff]
<6>[ 0.789337] pci 0000:00:00.0: [0e8d:0801] type 01 class 0x060400
<6>[ 0.795285] pci 0000:00:00.0: reg 0x10: [mem 0x00000000-0x7fffffff]
<6>[ 0.801504] pci 0000:00:00.0: reg 0x14: [mem 0x60600000-0x6060ffff]
<6>[ 0.807784] pci 0000:00:00.0: supports D1
<6>[ 0.811724] pci 0000:00:00.0: PME# supported from D0 D1 D3hot
<6>[ 0.817750] pci 0000:00:01.0: [0e8d:0801] type 01 class 0x060400
<6>[ 0.823698] pci 0000:00:01.0: reg 0x10: [mem 0x00000000-0x7fffffff]
<6>[ 0.829912] pci 0000:00:01.0: reg 0x14: [mem 0x60610000-0x6061ffff]
<6>[ 0.836183] pci 0000:00:01.0: supports D1
<6>[ 0.840122] pci 0000:00:01.0: PME# supported from D0 D1 D3hot
<6>[ 0.847184] pci 0000:01:00.0: [14c3:7916] type 00 class 0x000280
<6>[ 0.853151] pci 0000:01:00.0: reg 0x10: [mem 0x00000000-0x000fffff 64bit pref]
<6>[ 0.860308] pci 0000:01:00.0: reg 0x18: [mem 0x00000000-0x00003fff 64bit pref]
<6>[ 0.867491] pci 0000:01:00.0: reg 0x20: [mem 0x00000000-0x00000fff 64bit pref]
<6>[ 0.874765] pci 0000:01:00.0: supports D1 D2
<6>[ 0.878963] pci 0000:01:00.0: PME# supported from D0 D1 D2 D3hot D3cold
<6>[ 0.885579] pci 0000:01:00.0: 2.000 Gb/s available PCIe bandwidth, limited by 2.5 GT/s PCIe x1 link at 0000:00:00.0 (capable of 4.000 Gb/s with 5.0 GT/s PCIe x1 link)
<6>[ 0.900515] pci 0000:00:00.0: ASPM: current common clock configuration is inconsistent, reconfiguring
<6>[ 0.922057] pci 0000:00:00.0: PCI bridge to [bus 01-ff]
<6>[ 0.927222] pci 0000:00:00.0: bridge window [io 0x0000-0x0fff]
<6>[ 0.933266] pci 0000:00:00.0: bridge window [mem 0x60000000-0x600fffff]
<6>[ 0.940002] pci 0000:00:00.0: bridge window [mem 0x60100000-0x602fffff pref]
<6>[ 0.947179] pci_bus 0000:01: busn_res: [bus 01-ff] end is updated to 01
<6>[ 0.953911] pci 0000:02:00.0: [14c3:7915] type 00 class 0x000280
<6>[ 0.959871] pci 0000:02:00.0: reg 0x10: [mem 0x00000000-0x000fffff 64bit pref]
<6>[ 0.967032] pci 0000:02:00.0: reg 0x18: [mem 0x00000000-0x00003fff 64bit pref]
<6>[ 0.974204] pci 0000:02:00.0: reg 0x20: [mem 0x00000000-0x00000fff 64bit pref]
<6>[ 0.981494] pci 0000:02:00.0: supports D1 D2
<6>[ 0.985692] pci 0000:02:00.0: PME# supported from D0 D1 D2 D3hot D3cold
<6>[ 0.992301] pci 0000:02:00.0: 2.000 Gb/s available PCIe bandwidth, limited by 2.5 GT/s PCIe x1 link at 0000:00:01.0 (capable of 4.000 Gb/s with 5.0 GT/s PCIe x1 link)
<6>[ 1.007240] pci 0000:00:01.0: ASPM: current common clock configuration is inconsistent, reconfiguring
<6>[ 1.026047] pci 0000:00:01.0: PCI bridge to [bus 02-ff]
<6>[ 1.031209] pci 0000:00:01.0: bridge window [io 0x0000-0x0fff]
<6>[ 1.037254] pci 0000:00:01.0: bridge window [mem 0x60300000-0x603fffff]
<6>[ 1.043989] pci 0000:00:01.0: bridge window [mem 0x60400000-0x605fffff pref]
<6>[ 1.051164] pci_bus 0000:02: busn_res: [bus 02-ff] end is updated to 02
<6>[ 1.057780] pci 0000:00:00.0: BAR 0: no space for [mem size 0x80000000]
<6>[ 1.064319] pci 0000:00:00.0: BAR 0: failed to assign [mem size 0x80000000]
<6>[ 1.071234] pci 0000:00:01.0: BAR 0: no space for [mem size 0x80000000]
<6>[ 1.077796] pci 0000:00:01.0: BAR 0: failed to assign [mem size 0x80000000]
<6>[ 1.084709] pci 0000:00:00.0: BAR 8: assigned [mem 0x60000000-0x600fffff]
<6>[ 1.091459] pci 0000:00:00.0: BAR 9: assigned [mem 0x60100000-0x602fffff pref]
<6>[ 1.098629] pci 0000:00:01.0: BAR 8: assigned [mem 0x60300000-0x603fffff]
<6>[ 1.105363] pci 0000:00:01.0: BAR 9: assigned [mem 0x60400000-0x605fffff pref]
<6>[ 1.112529] pci 0000:00:00.0: BAR 1: assigned [mem 0x60600000-0x6060ffff]
<6>[ 1.119276] pci 0000:00:01.0: BAR 1: assigned [mem 0x60610000-0x6061ffff]
<6>[ 1.126014] pci 0000:00:00.0: BAR 7: assigned [io 0x0000-0x0fff]
<6>[ 1.132055] pci 0000:00:01.0: BAR 7: assigned [io 0x1000-0x1fff]
<6>[ 1.138119] pci 0000:01:00.0: BAR 0: assigned [mem 0x60100000-0x601fffff 64bit pref]
<6>[ 1.145810] pci 0000:01:00.0: BAR 2: assigned [mem 0x60200000-0x60203fff 64bit pref]
<6>[ 1.153506] pci 0000:01:00.0: BAR 4: assigned [mem 0x60204000-0x60204fff 64bit pref]
<6>[ 1.161188] pci 0000:00:00.0: PCI bridge to [bus 01]
<6>[ 1.166096] pci 0000:00:00.0: bridge window [io 0x0000-0x0fff]
<6>[ 1.172144] pci 0000:00:00.0: bridge window [mem 0x60000000-0x600fffff]
<6>[ 1.178887] pci 0000:00:00.0: bridge window [mem 0x60100000-0x602fffff pref]
<6>[ 1.186066] pci 0000:02:00.0: BAR 0: assigned [mem 0x60400000-0x604fffff 64bit pref]
<6>[ 1.193762] pci 0000:02:00.0: BAR 2: assigned [mem 0x60500000-0x60503fff 64bit pref]
<6>[ 1.201457] pci 0000:02:00.0: BAR 4: assigned [mem 0x60504000-0x60504fff 64bit pref]
<6>[ 1.209139] pci 0000:00:01.0: PCI bridge to [bus 02]
<6>[ 1.214053] pci 0000:00:01.0: bridge window [io 0x1000-0x1fff]
<6>[ 1.220095] pci 0000:00:01.0: bridge window [mem 0x60300000-0x603fffff]
<6>[ 1.226838] pci 0000:00:01.0: bridge window [mem 0x60400000-0x605fffff pref]
<6>[ 1.293553] Serial: 8250/16550 driver, 3 ports, IRQ sharing disabled
<6>[ 1.301659] printk: console [ttyS0] disabled
<6>[ 1.305989] 1e000c00.uartlite: ttyS0 at MMIO 0x1e000c00 (irq = 15, base_baud = 3125000) is a 16550A
<6>[ 1.315005] printk: console [ttyS0] enabled
<6>[ 1.323276] printk: bootconsole [early0] disabled
<6>[ 1.334191] nand: device found, Manufacturer ID: 0xc2, Chip ID: 0xf1
<6>[ 1.340589] nand: Macronix MX30LF1G28AD
<6>[ 1.344427] nand: 128 MiB, SLC, erase size: 128 KiB, page size: 2048, OOB size: 128
<6>[ 1.352085] mt7621-nand 1e003000.nand: ECC strength adjusted to 12 bits
<6>[ 1.361726] Signature found at block 1023 [0x07fe0000]
<6>[ 1.366867] NMBM management region starts at block 960 [0x07800000]
<6>[ 1.378961] First info table with writecount 23 found in block 960
<6>[ 1.402451] Second info table with writecount 23 found in block 963
<6>[ 1.408777] NMBM has been successfully attached
<5>[ 1.413459] 10 fixed-partitions partitions found on MTD device mt7621-nand
<5>[ 1.420736] Creating 10 MTD partitions on "mt7621-nand":
<5>[ 1.426060] 0x000000000000-0x000000080000 : "u-boot"
<5>[ 1.439414] 0x000000080000-0x000000100000 : "u-boot-env"
<5>[ 1.453035] 0x000000100000-0x000000180000 : "factory"
<5>[ 1.466309] 0x000000180000-0x000002980000 : "firmware_a"
<5>[ 2.085213] 2 fixed-partitions partitions found on MTD device firmware_a
<5>[ 2.091937] Creating 2 MTD partitions on "firmware_a":
<5>[ 2.097081] 0x000000000000-0x000000800000 : "kernel_a"
<5>[ 2.225386] 0x000000800000-0x000002800000 : "ubi_a"
<5>[ 2.721495] 0x000002980000-0x000005180000 : "firmware_b"
<5>[ 3.340246] 2 fixed-partitions partitions found on MTD device firmware_b
<5>[ 3.346968] Creating 2 MTD partitions on "firmware_b":
<5>[ 3.352107] 0x000000000000-0x000000800000 : "kernel_b"
<5>[ 3.480263] 0x000000800000-0x000002800000 : "ubi_b"
<5>[ 3.975666] 0x000005180000-0x000006580000 : "rootfs_data"
<5>[ 4.287830] 0x000006580000-0x000007280000 : "logs"
<5>[ 4.492219] 0x000007280000-0x000007700000 : "vendor-myzyxel"
<5>[ 4.567305] 0x000007700000-0x000007780000 : "bootconfig"
<5>[ 4.580784] 0x000007780000-0x000007800000 : "mrd"
<6>[ 4.728861] mt7530-mdio mdio-bus:1f: MT7530 adapts as multi-chip module
<6>[ 4.739452] mtk_soc_eth 1e100000.ethernet eth0: mediatek frame engine at 0xbe100000, irq 17
<6>[ 4.749780] NET: Registered PF_INET6 protocol family
<6>[ 4.756356] Segment Routing with IPv6
<6>[ 4.760155] In-situ OAM (IOAM) with IPv6
<6>[ 4.764191] sit: IPv6, IPv4 and MPLS over IPv4 tunneling driver
<6>[ 4.770812] NET: Registered PF_PACKET protocol family
<6>[ 4.776330] 8021q: 802.1Q VLAN Support v1.8
<5>[ 4.781230] Loading compiled-in X.509 certificates
<5>[ 4.797729] Loaded X.509 cert 'Build time autogenerated kernel key: 3cb1578c6bb232a0582cf98f15a4972f913c1af3'
<3>[ 4.807668] Problem parsing in-kernel X.509 certificate list
<5>[ 4.817397] Key type encrypted registered
<6>[ 4.824007] mt7530-mdio mdio-bus:1f: MT7530 adapts as multi-chip module
<6>[ 4.846395] mt7530-mdio mdio-bus:1f: configuring for fixed/rgmii link mode
<6>[ 4.854154] mt7530-mdio mdio-bus:1f: Link is Up - 1Gbps/Full - flow control rx/tx
<6>[ 4.859149] mt7530-mdio mdio-bus:1f lan (uninitialized): PHY [mt7530-0:04] driver [MediaTek MT7530 PHY] (irq=19)
<6>[ 4.873461] DSA: tree 0 setup
<5>[ 4.876884] ubi0: attaching mtd5
<5>[ 5.863729] ubi0: scanning is finished
<5>[ 5.890726] ubi0: attached mtd5 (name "ubi_a", size 32 MiB)
<5>[ 5.896336] ubi0: PEB size: 131072 bytes (128 KiB), LEB size: 126976 bytes
<5>[ 5.903205] ubi0: min./max. I/O unit sizes: 2048/2048, sub-page size 2048
<5>[ 5.909985] ubi0: VID header offset: 2048 (aligned 2048), data offset: 4096
<5>[ 5.916945] ubi0: good PEBs: 256, bad PEBs: 0, corrupted PEBs: 0
<5>[ 5.922942] ubi0: user volume: 1, internal volumes: 1, max. volumes count: 128
<5>[ 5.930154] ubi0: max/mean erase counter: 126998/126988, WL threshold: 4096, image sequence number: 315532800
<5>[ 5.940050] ubi0: available PEBs: 0, total reserved PEBs: 256, PEBs reserved for bad PEB handling: 19
<5>[ 5.949276] ubi0: background thread "ubi_bgt0d" started, PID 68
<5>[ 5.953015] ubi1: attaching mtd8
<5>[ 6.941903] ubi1: scanning is finished
<5>[ 6.968852] ubi1: attached mtd8 (name "ubi_b", size 32 MiB)
<5>[ 6.974477] ubi1: PEB size: 131072 bytes (128 KiB), LEB size: 126976 bytes
<5>[ 6.981349] ubi1: min./max. I/O unit sizes: 2048/2048, sub-page size 2048
<5>[ 6.988131] ubi1: VID header offset: 2048 (aligned 2048), data offset: 4096
<5>[ 6.995089] ubi1: good PEBs: 256, bad PEBs: 0, corrupted PEBs: 0
<5>[ 7.001103] ubi1: user volume: 1, internal volumes: 1, max. volumes count: 128
<5>[ 7.008317] ubi1: max/mean erase counter: 126977/126976, WL threshold: 4096, image sequence number: 315532800
<5>[ 7.018222] ubi1: available PEBs: 0, total reserved PEBs: 256, PEBs reserved for bad PEB handling: 19
<5>[ 7.027455] ubi1: background thread "ubi_bgt1d" started, PID 69
<6>[ 7.038626] Freeing unused kernel image (initmem) memory: 1260K
<4>[ 7.044612] This architecture does not have kernel memory protection.
<6>[ 7.051070] Run /init as init process
<7>[ 7.054740] with arguments:
<7>[ 7.057711] /init
<7>[ 7.059974] with environment:
<7>[ 7.063118] HOME=/
<7>[ 7.065486] TERM=linux
<7>[ 7.068180] rootalt=ubi1:rootfs
<5>[ 7.075382] UBIFS (ubi0:0): Mounting in unauthenticated mode
<5>[ 7.082662] UBIFS (ubi0:0): background thread "ubifs_bgt0_0" started, PID 70
<5>[ 7.204958] UBIFS (ubi0:0): recovery needed
<5>[ 7.601923] UBIFS (ubi0:0): recovery completed
<5>[ 7.606622] UBIFS (ubi0:0): UBIFS: mounted UBI device 0, volume 0, name "rootfs"
<5>[ 7.614056] UBIFS (ubi0:0): LEB size: 126976 bytes (124 KiB), min./max. I/O unit sizes: 2048 bytes/2048 bytes
<5>[ 7.623958] UBIFS (ubi0:0): FS size: 28315648 bytes (27 MiB, 223 LEBs), max 256 LEBs, journal size 4444160 bytes (4 MiB, 35 LEBs)
<5>[ 7.635596] UBIFS (ubi0:0): reserved for root: 0 bytes (0 KiB)
<5>[ 7.641430] UBIFS (ubi0:0): media format: w4/r0 (latest is w5/r0), UUID A68EAB38-9D1E-4184-AEFB-63A0740A6A2D, small LPT model
<4>[ 9.842286] compat: loading out-of-tree module taints kernel.
<5>[ 9.857452] compat: module verification failed: signature and/or required key missing - tainting kernel
<6>[ 9.967488] Loading modules backported from Linux version e2c1a934fd8
<6>[ 9.974025] Backport generated by backports.git dfe0f60ca8a
<5>[ 11.676238] random: chronyd: uninitialized urandom read (1027 bytes read)
<6>[ 11.685221] mtk_soc_eth 1e100000.ethernet eth0: configuring for fixed/rgmii link mode
<6>[ 11.695046] mtk_soc_eth 1e100000.ethernet eth0: Link is Up - 1Gbps/Full - flow control rx/tx
<6>[ 11.723238] mt7530-mdio mdio-bus:1f lan: configuring for phy/gmii link mode
<6>[ 11.747231] IPv6: ADDRCONF(NETDEV_CHANGE): eth0: link becomes ready
<6>[ 12.360030] int: port 1(lan) entered blocking state
<6>[ 12.364996] int: port 1(lan) entered disabled state
<6>[ 12.371531] device lan entered promiscuous mode
<6>[ 12.376119] device eth0 entered promiscuous mode
<6>[ 12.509793] pci 0000:00:00.0: enabling device (0006 -> 0007)
<6>[ 12.515560] mt7915e_hif 0000:01:00.0: enabling device (0000 -> 0002)
<6>[ 12.522443] pci 0000:00:01.0: enabling device (0006 -> 0007)
<6>[ 12.528197] mt7915e 0000:02:00.0: enabling device (0000 -> 0002)
<6>[ 12.630121] mt7915e 0000:02:00.0: HW/SW Version: 0x8a108a10, Build Time: 20220929104113a
<6>[ 12.630121]
<6>[ 13.117498] mt7915e 0000:02:00.0: WM Firmware Version: ____000000, Build Time: 20220929104145
<6>[ 13.225464] mt7915e 0000:02:00.0: WA Firmware Version: DEV_000000, Build Time: 20220929104205
<6>[ 14.924294] mt7530-mdio mdio-bus:1f lan: Link is Up - 1Gbps/Full - flow control off
<5>[ 15.854162] random: crng init done
<6>[ 18.497431] IPv6: ADDRCONF(NETDEV_CHANGE): lan: link becomes ready
<6>[ 18.503953] int: port 1(lan) entered blocking state
<6>[ 18.508961] int: port 1(lan) entered forwarding state
<6>[ 18.520882] IPv6: ADDRCONF(NETDEV_CHANGE): int: link becomes ready
<6>[ 19.726486] int: port 2(wlan0) entered blocking state
<6>[ 19.731712] int: port 2(wlan0) entered disabled state
<6>[ 19.737934] device wlan0 entered promiscuous mode
<6>[ 19.750519] int: port 3(wlan1) entered blocking state
<6>[ 19.755784] int: port 3(wlan1) entered disabled state
<6>[ 19.762121] device wlan1 entered promiscuous mode
<6>[ 19.860627] IPv6: ADDRCONF(NETDEV_CHANGE): wlan1: link becomes ready
<6>[ 19.867243] int: port 3(wlan1) entered blocking state
<6>[ 19.872311] int: port 3(wlan1) entered forwarding state
<6>[ 21.167370] IPv6: ADDRCONF(NETDEV_CHANGE): wlan0: link becomes ready
<6>[ 21.174100] int: port 2(wlan0) entered blocking state
<6>[ 21.179211] int: port 2(wlan0) entered forwarding state
<6>[319860.057754] mt7530-mdio mdio-bus:1f lan: Link is Down
<6>[319860.071078] int: port 1(lan) entered disabled state
<6>[332932.024408] mt7530-mdio mdio-bus:1f lan: Link is Up - 1Gbps/Full - flow control off
<6>[332932.032293] int: port 1(lan) entered blocking state
<6>[332932.037277] int: port 1(lan) entered forwarding state
<6>[658890.171767] mt7530-mdio mdio-bus:1f lan: Link is Down
<6>[658890.177373] int: port 1(lan) entered disabled state
<6>[751678.748021] mt7530-mdio mdio-bus:1f lan: Link is Up - 1Gbps/Full - flow control off
<6>[751678.755994] int: port 1(lan) entered blocking state
<6>[751678.760989] int: port 1(lan) entered forwarding state

View file

@ -0,0 +1,6 @@
Filesystem 1024-blocks Used Available Use% Mounted on
ubi0:rootfs 24884 20216 4668 81% /persist
ubi0:rootfs 24884 20216 4668 81% /nix
dev 124828 0 124828 0% /dev
tmpfs 125460 1452 124008 1% /run
none 125460 0 125460 0% /tmp

View file

@ -0,0 +1,15 @@
dev: size erasesize name
mtd0: 00080000 00020000 "u-boot"
mtd1: 00080000 00020000 "u-boot-env"
mtd2: 00080000 00020000 "factory"
mtd3: 02800000 00020000 "firmware_a"
mtd4: 00800000 00020000 "kernel_a"
mtd5: 02000000 00020000 "ubi_a"
mtd6: 02800000 00020000 "firmware_b"
mtd7: 00800000 00020000 "kernel_b"
mtd8: 02000000 00020000 "ubi_b"
mtd9: 01400000 00020000 "rootfs_data"
mtd10: 00d00000 00020000 "logs"
mtd11: 00480000 00020000 "vendor-myzyxel"
mtd12: 00080000 00020000 "bootconfig"
mtd13: 00080000 00020000 "mrd"

View file

@ -0,0 +1,332 @@
U-Boot SPL 2018.09 (Jan 22 2021 - 07:42:43 +0000)
Trying to boot from NAND
Initializing NMBM ...
Signature found at block 1023 [0x07fe0000]
First info table with writecount 23 found in block 960
Second info table with writecount 23 found in block 963
NMBM has been successfully attached
U-Boot 2018.09 (Jan 22 2021 - 07:42:43 +0000)
CPU: MediaTek MT7621AT ver 1, eco 3
Clocks: CPU: 880MHz, DDR: 600MHz (1200MT/s), Bus: 220MHz, XTAL: 40MHz
Model: MediaTek MT7621 reference board (NAND)
DRAM: 256 MiB
NAND: 128 MiB
Initializing NMBM ...
Signature found at block 1023 [0x07fe0000]
First info table with writecount 23 found in block 960
Second info table with writecount 23 found in block 963
NMBM has been successfully attached
Loading Environment from NMBM... *** Warning - bad CRC, using default environment
In: uartlite0@1e000c00
Out: uartlite0@1e000c00
Err: uartlite0@1e000c00
Net:
Warning: eth@1e100000 (eth0) using random MAC address - fa:26:d7:78:e2:6c
eth0: eth@1e100000
Reading from 0x7700000, size 0x20000
Succeeded
Zyxel version:V1.03
gpio: pin 6 (gpio 6) value is 1
gpio: pin 24 (gpio 24) value is 0
gpio: pin 24 (gpio 24) value is 1
Hit any key to stop autoboot: 0
Loading FIT image at offset 0x180000 to memory 0x83000000, size 0x2c4098 ...
Automatic boot of image at addr 0x83000000 ...
## Loading kernel from FIT Image at 83000000 ...
Using 'conf-1' configuration
Trying 'kernel' kernel subimage
Description: Vanilla Linux kernel
Type: Kernel Image
Compression: lzma compressed
Data Start: 0x83000110
Data Size: 2886231 Bytes = 2.8 MiB
Architecture: MIPS
OS: Linux
Load Address: 0x80001000
Entry Point: 0x80001000
Hash algo: crc32
Hash value: 2b3aa711
Hash algo: sha1
Hash value: c6601a1909011f95acfbfaed2c6c2b4f6703a98a
Verifying Hash Integrity ... crc32+ sha1+ OK
## Loading fdt from FIT Image at 83000000 ...
Using 'conf-1' configuration
Trying 'fdt-1' fdt subimage
Description: Flattened Device Tree blob
Type: Flat Device Tree
Compression: uncompressed
Data Start: 0x832c0c94
Data Size: 12011 Bytes = 11.7 KiB
Architecture: MIPS
Hash algo: crc32
Hash value: e712ab77
Hash algo: sha1
Hash value: 705532a8d74d5d6921aada1572531caf385c4aaf
Verifying Hash Integrity ... crc32+ sha1+ OK
Booting using the fdt blob at 0x832c0c94
Uncompressing Kernel Image ... OK
Loading Device Tree to 8fe67000, end 8fe6ceea ... OK
[ 0.000000] Linux version 5.15.137 (nixbld@liminix.builder) (mipsel-unknown-linux-musl-gcc (GCC) 13.3.0, GNU ld (GNU Binutils) 2.42) #1 SMP Mon Aug 26 18:09:43 UTC 2024
[ 0.000000] SoC Type: MediaTek MT7621 ver:1 eco:3
[ 0.000000] printk: bootconsole [early0] enabled
[ 0.000000] CPU0 revision is: 0001992f (MIPS 1004Kc)
[ 0.000000] MIPS: machine is ZyXEL NWA50AX
[ 0.000000] Initrd not found or empty - disabling initrd
[ 0.000000] Detected 1 available secondary CPU(s)
[ 0.000000] Primary instruction cache 32kB, VIPT, 4-way, linesize 32 bytes.
[ 0.000000] Primary data cache 32kB, 4-way, PIPT, no aliases, linesize 32 bytes
[ 0.000000] MIPS secondary cache 256kB, 8-way, linesize 32 bytes.
[ 0.000000] Zone ranges:
[ 0.000000] Normal [mem 0x0000000000000000-0x000000000fffffff]
[ 0.000000] Movable zone start for each node
[ 0.000000] Early memory node ranges
[ 0.000000] node 0: [mem 0x0000000000000000-0x000000000fffffff]
[ 0.000000] Initmem setup node 0 [mem 0x0000000000000000-0x000000000fffffff]
[ 0.000000] percpu: Embedded 10 pages/cpu s11184 r8192 d21584 u40960
[ 0.000000] pcpu-alloc: s11184 r8192 d21584 u40960 alloc=10*4096
[ 0.000000] pcpu-alloc: [0] 0 [0] 1
[ 0.000000] Built 1 zonelists, mobility grouping on. Total pages: 65024
[ 0.000000] Kernel command line: console=ttyS0,115200 panic=10 oops=panic init=/bin/init loglevel=8 root=ubi0:rootfs rootfstype=ubifs fw_devlink=off ubi.mtd=ubi_a ubi.mtd=ubi_b rootalt=ubi1:rootfs
[ 0.000000] Unknown kernel command line parameters "rootalt=ubi1:rootfs", will be passed to user space.
[ 0.000000] Dentry cache hash table entries: 32768 (order: 5, 131072 bytes, linear)
[ 0.000000] Inode-cache hash table entries: 16384 (order: 4, 65536 bytes, linear)
[ 0.000000] Writing ErrCtl register=000307c0
[ 0.000000] Readback ErrCtl register=000307c0
[ 0.000000] mem auto-init: stack:all(zero), heap alloc:off, heap free:off
[ 0.000000] Memory: 249660K/262144K available (6690K kernel code, 620K rwdata, 1272K rodata, 1260K init, 215K bss, 12484K reserved, 0K cma-reserved)
[ 0.000000] SLUB: HWalign=32, Order=0-3, MinObjects=0, CPUs=2, Nodes=1
[ 0.000000] rcu: Hierarchical RCU implementation.
[ 0.000000] rcu: RCU event tracing is enabled.
[ 0.000000] rcu: RCU calculated value of scheduler-enlistment delay is 25 jiffies.
[ 0.000000] NR_IRQS: 256
[ 0.000000] clocksource: GIC: mask: 0xffffffffffffffff max_cycles: 0xcaf478abb4, max_idle_ns: 440795247997 ns
[ 0.000003] sched_clock: 64 bits at 880MHz, resolution 1ns, wraps every 4398046511103ns
[ 0.008219] Console: colour dummy device 80x25
[ 0.012632] Calibrating delay loop... 583.68 BogoMIPS (lpj=1167360)
[ 0.046815] pid_max: default: 32768 minimum: 301
[ 0.051584] Mount-cache hash table entries: 1024 (order: 0, 4096 bytes, linear)
[ 0.058814] Mountpoint-cache hash table entries: 1024 (order: 0, 4096 bytes, linear)
[ 0.068781] rcu: Hierarchical SRCU implementation.
[ 0.074119] smp: Bringing up secondary CPUs ...
[ 0.079356] Primary instruction cache 32kB, VIPT, 4-way, linesize 32 bytes.
[ 0.079377] Primary data cache 32kB, 4-way, PIPT, no aliases, linesize 32 bytes
[ 0.079391] MIPS secondary cache 256kB, 8-way, linesize 32 bytes.
[ 0.079436] CPU1 revision is: 0001992f (MIPS 1004Kc)
[ 0.106818] Synchronize counters for CPU 1: done.
[ 0.137420] smp: Brought up 1 node, 2 CPUs
[ 0.142178] devtmpfs: initialized
[ 0.149145] clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 7645041785100000 ns
[ 0.158853] futex hash table entries: 512 (order: 2, 16384 bytes, linear)
[ 0.165690] pinctrl core: initialized pinctrl subsystem
[ 0.172367] NET: Registered PF_NETLINK/PF_ROUTE protocol family
[ 0.195333] FPU Affinity set after 4688 emulations
[ 0.210943] vgaarb: loaded
[ 0.213836] pps_core: LinuxPPS API ver. 1 registered
[ 0.218720] pps_core: Software ver. 5.3.6 - Copyright 2005-2007 Rodolfo Giometti <giometti@linux.it>
[ 0.227854] PTP clock support registered
[ 0.232998] clocksource: Switched to clocksource GIC
[ 0.247935] NET: Registered PF_INET protocol family
[ 0.253125] IP idents hash table entries: 4096 (order: 3, 32768 bytes, linear)
[ 0.261130] tcp_listen_portaddr_hash hash table entries: 512 (order: 0, 6144 bytes, linear)
[ 0.269459] Table-perturb hash table entries: 65536 (order: 6, 262144 bytes, linear)
[ 0.277129] TCP established hash table entries: 2048 (order: 1, 8192 bytes, linear)
[ 0.284755] TCP bind hash table entries: 2048 (order: 2, 16384 bytes, linear)
[ 0.291853] TCP: Hash tables configured (established 2048 bind 2048)
[ 0.298251] UDP hash table entries: 256 (order: 1, 8192 bytes, linear)
[ 0.304746] UDP-Lite hash table entries: 256 (order: 1, 8192 bytes, linear)
[ 0.311881] NET: Registered PF_UNIX/PF_LOCAL protocol family
[ 0.317505] PCI: CLS 0 bytes, default 32
[ 0.322026] Initialise system trusted keyrings
[ 0.327035] workingset: timestamp_bits=30 max_order=16 bucket_order=0
[ 0.338742] squashfs: version 4.0 (2009/01/31) Phillip Lougher
[ 0.344665] NET: Registered PF_ALG protocol family
[ 0.349399] Key type asymmetric registered
[ 0.353449] Asymmetric key parser 'x509' registered
[ 0.358358] io scheduler mq-deadline registered
[ 0.362815] io scheduler kyber registered
[ 0.368221] mt7621_gpio 1e000600.gpio: registering 32 gpios
[ 0.374020] mt7621_gpio 1e000600.gpio: registering 32 gpios
[ 0.379793] mt7621_gpio 1e000600.gpio: registering 32 gpios
[ 0.385647] mt7621-pci 1e140000.pcie: host bridge /pcie@1e140000 ranges:
[ 0.392289] mt7621-pci 1e140000.pcie: No bus range found for /pcie@1e140000, using [bus 00-ff]
[ 0.401045] mt7621-pci 1e140000.pcie: MEM 0x0060000000..0x006fffffff -> 0x0060000000
[ 0.409152] mt7621-pci 1e140000.pcie: IO 0x001e160000..0x001e16ffff -> 0x0000000000
[ 0.740955] mt7621-pci 1e140000.pcie: pcie2 no card, disable it (RST & CLK)
[ 0.747846] mt7621-pci 1e140000.pcie: PCIE0 enabled
[ 0.752677] mt7621-pci 1e140000.pcie: PCIE1 enabled
[ 0.757536] PCI coherence region base: 0x60000000, mask/settings: 0xf0000002
[ 0.764608] mt7621-pci 1e140000.pcie: PCI host bridge to bus 0000:00
[ 0.770889] pci_bus 0000:00: root bus resource [bus 00-ff]
[ 0.776322] pci_bus 0000:00: root bus resource [mem 0x60000000-0x6fffffff]
[ 0.783158] pci_bus 0000:00: root bus resource [io 0x0000-0xffff]
[ 0.789335] pci 0000:00:00.0: [0e8d:0801] type 01 class 0x060400
[ 0.795284] pci 0000:00:00.0: reg 0x10: [mem 0x00000000-0x7fffffff]
[ 0.801502] pci 0000:00:00.0: reg 0x14: [mem 0x60600000-0x6060ffff]
[ 0.807783] pci 0000:00:00.0: supports D1
[ 0.811723] pci 0000:00:00.0: PME# supported from D0 D1 D3hot
[ 0.817741] pci 0000:00:01.0: [0e8d:0801] type 01 class 0x060400
[ 0.823690] pci 0000:00:01.0: reg 0x10: [mem 0x00000000-0x7fffffff]
[ 0.829903] pci 0000:00:01.0: reg 0x14: [mem 0x60610000-0x6061ffff]
[ 0.836181] pci 0000:00:01.0: supports D1
[ 0.840120] pci 0000:00:01.0: PME# supported from D0 D1 D3hot
[ 0.847184] pci 0000:01:00.0: [14c3:7916] type 00 class 0x000280
[ 0.853152] pci 0000:01:00.0: reg 0x10: [mem 0x00000000-0x000fffff 64bit pref]
[ 0.860309] pci 0000:01:00.0: reg 0x18: [mem 0x00000000-0x00003fff 64bit pref]
[ 0.867491] pci 0000:01:00.0: reg 0x20: [mem 0x00000000-0x00000fff 64bit pref]
[ 0.874765] pci 0000:01:00.0: supports D1 D2
[ 0.878963] pci 0000:01:00.0: PME# supported from D0 D1 D2 D3hot D3cold
[ 0.885578] pci 0000:01:00.0: 2.000 Gb/s available PCIe bandwidth, limited by 2.5 GT/s PCIe x1 link at 0000:00:00.0 (capable of 4.000 Gb/s with 5.0 GT/s PCIe x1 link)
[ 0.900515] pci 0000:00:00.0: ASPM: current common clock configuration is inconsistent, reconfiguring
[ 0.922059] pci 0000:00:00.0: PCI bridge to [bus 01-ff]
[ 0.927224] pci 0000:00:00.0: bridge window [io 0x0000-0x0fff]
[ 0.933267] pci 0000:00:00.0: bridge window [mem 0x60000000-0x600fffff]
[ 0.940003] pci 0000:00:00.0: bridge window [mem 0x60100000-0x602fffff pref]
[ 0.947180] pci_bus 0000:01: busn_res: [bus 01-ff] end is updated to 01
[ 0.953911] pci 0000:02:00.0: [14c3:7915] type 00 class 0x000280
[ 0.959872] pci 0000:02:00.0: reg 0x10: [mem 0x00000000-0x000fffff 64bit pref]
[ 0.967034] pci 0000:02:00.0: reg 0x18: [mem 0x00000000-0x00003fff 64bit pref]
[ 0.974205] pci 0000:02:00.0: reg 0x20: [mem 0x00000000-0x00000fff 64bit pref]
[ 0.981495] pci 0000:02:00.0: supports D1 D2
[ 0.985693] pci 0000:02:00.0: PME# supported from D0 D1 D2 D3hot D3cold
[ 0.992302] pci 0000:02:00.0: 2.000 Gb/s available PCIe bandwidth, limited by 2.5 GT/s PCIe x1 link at 0000:00:01.0 (capable of 4.000 Gb/s with 5.0 GT/s PCIe x1 link)
[ 1.007243] pci 0000:00:01.0: ASPM: current common clock configuration is inconsistent, reconfiguring
[ 1.026050] pci 0000:00:01.0: PCI bridge to [bus 02-ff]
[ 1.031213] pci 0000:00:01.0: bridge window [io 0x0000-0x0fff]
[ 1.037258] pci 0000:00:01.0: bridge window [mem 0x60300000-0x603fffff]
[ 1.043993] pci 0000:00:01.0: bridge window [mem 0x60400000-0x605fffff pref]
[ 1.051168] pci_bus 0000:02: busn_res: [bus 02-ff] end is updated to 02
[ 1.057783] pci 0000:00:00.0: BAR 0: no space for [mem size 0x80000000]
[ 1.064323] pci 0000:00:00.0: BAR 0: failed to assign [mem size 0x80000000]
[ 1.071237] pci 0000:00:01.0: BAR 0: no space for [mem size 0x80000000]
[ 1.077800] pci 0000:00:01.0: BAR 0: failed to assign [mem size 0x80000000]
[ 1.084712] pci 0000:00:00.0: BAR 8: assigned [mem 0x60000000-0x600fffff]
[ 1.091462] pci 0000:00:00.0: BAR 9: assigned [mem 0x60100000-0x602fffff pref]
[ 1.098632] pci 0000:00:01.0: BAR 8: assigned [mem 0x60300000-0x603fffff]
[ 1.105366] pci 0000:00:01.0: BAR 9: assigned [mem 0x60400000-0x605fffff pref]
[ 1.112532] pci 0000:00:00.0: BAR 1: assigned [mem 0x60600000-0x6060ffff]
[ 1.119279] pci 0000:00:01.0: BAR 1: assigned [mem 0x60610000-0x6061ffff]
[ 1.126017] pci 0000:00:00.0: BAR 7: assigned [io 0x0000-0x0fff]
[ 1.132058] pci 0000:00:01.0: BAR 7: assigned [io 0x1000-0x1fff]
[ 1.138123] pci 0000:01:00.0: BAR 0: assigned [mem 0x60100000-0x601fffff 64bit pref]
[ 1.145814] pci 0000:01:00.0: BAR 2: assigned [mem 0x60200000-0x60203fff 64bit pref]
[ 1.153509] pci 0000:01:00.0: BAR 4: assigned [mem 0x60204000-0x60204fff 64bit pref]
[ 1.161191] pci 0000:00:00.0: PCI bridge to [bus 01]
[ 1.166100] pci 0000:00:00.0: bridge window [io 0x0000-0x0fff]
[ 1.172148] pci 0000:00:00.0: bridge window [mem 0x60000000-0x600fffff]
[ 1.178890] pci 0000:00:00.0: bridge window [mem 0x60100000-0x602fffff pref]
[ 1.186069] pci 0000:02:00.0: BAR 0: assigned [mem 0x60400000-0x604fffff 64bit pref]
[ 1.193765] pci 0000:02:00.0: BAR 2: assigned [mem 0x60500000-0x60503fff 64bit pref]
[ 1.201460] pci 0000:02:00.0: BAR 4: assigned [mem 0x60504000-0x60504fff 64bit pref]
[ 1.209142] pci 0000:00:01.0: PCI bridge to [bus 02]
[ 1.214057] pci 0000:00:01.0: bridge window [io 0x1000-0x1fff]
[ 1.220099] pci 0000:00:01.0: bridge window [mem 0x60300000-0x603fffff]
[ 1.226842] pci 0000:00:01.0: bridge window [mem 0x60400000-0x605fffff pref]
[ 1.293542] Serial: 8250/16550 driver, 3 ports, IRQ sharing disabled
[ 1.301644] printk: console [ttyS0] disabled
[ 1.305976] 1e000c00.uartlite: ttyS0 at MMIO 0x1e000c00 (irq = 15, base_baud = 3125000) is a 16550A
[ 1.314993] printk: console [ttyS0] enabled
[ 1.314993] printk: console [ttyS0] enabled
[ 1.323262] printk: bootconsole [early0] disabled
[ 1.323262] printk: bootconsole [early0] disabled
[ 1.334173] nand: device found, Manufacturer ID: 0xc2, Chip ID: 0xf1
[ 1.340567] nand: Macronix MX30LF1G28AD
[ 1.344406] nand: 128 MiB, SLC, erase size: 128 KiB, page size: 2048, OOB size: 128
[ 1.352063] mt7621-nand 1e003000.nand: ECC strength adjusted to 12 bits
[ 1.361705] Signature found at block 1023 [0x07fe0000]
[ 1.366845] NMBM management region starts at block 960 [0x07800000]
[ 1.378939] First info table with writecount 23 found in block 960
[ 1.402434] Second info table with writecount 23 found in block 963
[ 1.408759] NMBM has been successfully attached
[ 1.413442] 10 fixed-partitions partitions found on MTD device mt7621-nand
[ 1.420708] Creating 10 MTD partitions on "mt7621-nand":
[ 1.426033] 0x000000000000-0x000000080000 : "u-boot"
[ 1.439393] 0x000000080000-0x000000100000 : "u-boot-env"
[ 1.453018] 0x000000100000-0x000000180000 : "factory"
[ 1.466290] 0x000000180000-0x000002980000 : "firmware_a"
[ 2.085192] 2 fixed-partitions partitions found on MTD device firmware_a
[ 2.091913] Creating 2 MTD partitions on "firmware_a":
[ 2.097057] 0x000000000000-0x000000800000 : "kernel_a"
[ 2.225364] 0x000000800000-0x000002800000 : "ubi_a"
[ 2.721502] 0x000002980000-0x000005180000 : "firmware_b"
[ 3.340201] 2 fixed-partitions partitions found on MTD device firmware_b
[ 3.346925] Creating 2 MTD partitions on "firmware_b":
[ 3.352064] 0x000000000000-0x000000800000 : "kernel_b"
[ 3.480209] 0x000000800000-0x000002800000 : "ubi_b"
[ 3.975604] 0x000005180000-0x000006580000 : "rootfs_data"
[ 4.287770] 0x000006580000-0x000007280000 : "logs"
[ 4.492133] 0x000007280000-0x000007700000 : "vendor-myzyxel"
[ 4.567214] 0x000007700000-0x000007780000 : "bootconfig"
[ 4.580694] 0x000007780000-0x000007800000 : "mrd"
[ 4.728864] mt7530-mdio mdio-bus:1f: MT7530 adapts as multi-chip module
[ 4.739458] mtk_soc_eth 1e100000.ethernet eth0: mediatek frame engine at 0xbe100000, irq 17
[ 4.749784] NET: Registered PF_INET6 protocol family
[ 4.756359] Segment Routing with IPv6
[ 4.760159] In-situ OAM (IOAM) with IPv6
[ 4.764195] sit: IPv6, IPv4 and MPLS over IPv4 tunneling driver
[ 4.770813] NET: Registered PF_PACKET protocol family
[ 4.776327] 8021q: 802.1Q VLAN Support v1.8
[ 4.781226] Loading compiled-in X.509 certificates
[ 4.797717] Loaded X.509 cert 'Build time autogenerated kernel key: 3cb1578c6bb232a0582cf98f15a4972f913c1af3'
[ 4.807657] Problem parsing in-kernel X.509 certificate list
[ 4.817384] Key type encrypted registered
[ 4.823997] mt7530-mdio mdio-bus:1f: MT7530 adapts as multi-chip module
[ 4.846401] mt7530-mdio mdio-bus:1f: configuring for fixed/rgmii link mode
[ 4.854160] mt7530-mdio mdio-bus:1f: Link is Up - 1Gbps/Full - flow control rx/tx
[ 4.859153] mt7530-mdio mdio-bus:1f lan (uninitialized): PHY [mt7530-0:04] driver [MediaTek MT7530 PHY] (irq=19)
[ 4.873468] DSA: tree 0 setup
[ 4.876897] ubi0: attaching mtd5
[ 5.863781] ubi0: scanning is finished
[ 5.890797] ubi0: attached mtd5 (name "ubi_a", size 32 MiB)
[ 5.896409] ubi0: PEB size: 131072 bytes (128 KiB), LEB size: 126976 bytes
[ 5.903277] ubi0: min./max. I/O unit sizes: 2048/2048, sub-page size 2048
[ 5.910056] ubi0: VID header offset: 2048 (aligned 2048), data offset: 4096
[ 5.917009] ubi0: good PEBs: 256, bad PEBs: 0, corrupted PEBs: 0
[ 5.923007] ubi0: user volume: 1, internal volumes: 1, max. volumes count: 128
[ 5.930219] ubi0: max/mean erase counter: 126998/126988, WL threshold: 4096, image sequence number: 315532800
[ 5.940115] ubi0: available PEBs: 0, total reserved PEBs: 256, PEBs reserved for bad PEB handling: 19
[ 5.949340] ubi0: background thread "ubi_bgt0d" started, PID 68
[ 5.953018] ubi1: attaching mtd8
[ 6.941910] ubi1: scanning is finished
[ 6.968862] ubi1: attached mtd8 (name "ubi_b", size 32 MiB)
[ 6.974487] ubi1: PEB size: 131072 bytes (128 KiB), LEB size: 126976 bytes
[ 6.981359] ubi1: min./max. I/O unit sizes: 2048/2048, sub-page size 2048
[ 6.988141] ubi1: VID header offset: 2048 (aligned 2048), data offset: 4096
[ 6.995099] ubi1: good PEBs: 256, bad PEBs: 0, corrupted PEBs: 0
[ 7.001112] ubi1: user volume: 1, internal volumes: 1, max. volumes count: 128
[ 7.008326] ubi1: max/mean erase counter: 126977/126976, WL threshold: 4096, image sequence number: 315532800
[ 7.018233] ubi1: available PEBs: 0, total reserved PEBs: 256, PEBs reserved for bad PEB handling: 19
[ 7.027465] ubi1: background thread "ubi_bgt1d" started, PID 69
[ 7.038616] Freeing unused kernel image (initmem) memory: 1260K
[ 7.044603] This architecture does not have kernel memory protection.
[ 7.051061] Run /init as init process
[ 7.054731] with arguments:
[ 7.057703] /init
[ 7.059965] with environment:
[ 7.063110] HOME=/
[ 7.065478] TERM=linux
[ 7.068172] rootalt=ubi1:rootfs
Running pre-init...
cmdline: "console=ttyS0,115[ 7.075377] UBIFS (ubi0:0): Mounting in unauthenticated mode
200 panic=10 oop[ 7.082657] UBIFS (ubi0:0): background thread "ubifs_bgt0_0" started, PID 70
s=panic init=/bin/init loglevel=8 root=ubi0:rootfs rootfstype=ubifs fw_devlink=off ubi.mtd=ubi_a ubi.mtd=ubi_b rootalt=ubi1:rootfs"
rootdevice ubi0:rootfs (ubifs, altdevice=ubi1:rootfs)
[ 7.204958] UBIFS (ubi0:0): recovery needed
[ 7.598521] UBIFS (ubi0:0): recovery completed
[ 7.603217] UBIFS (ubi0:0): UBIFS: mounted UBI device 0, volume 0, name "rootfs"
[ 7.610665] UBIFS (ubi0:0): LEB size: 126976 bytes (124 KiB), min./max. I/O unit sizes: 2048 bytes/2048 bytes
[ 7.620568] UBIFS (ubi0:0): FS size: 28315648 bytes (27 MiB, 223 LEBs), max 256 LEBs, journal size 4444160 bytes (4 MiB, 35 LEBs)
[ 7.632205] UBIFS (ubi0:0): reserved for root: 0 bytes (0 KiB)
[ 7.638040] UBIFS (ubi0:0): media format: w4/r0 (latest is w5/r0), UUID A68EAB38-9D1E-4184-AEFB-63A0740A6A2D, small LPT model
s6-linux-init version 1.1.2.0
BusyBox v1.36.1 () built-in shell (ash)

View file

@ -0,0 +1,75 @@
U-Boot SPL 2018.09 (Jan 22 2021 - 07:42:43 +0000)
Trying to boot from NAND
Initializing NMBM ...
Signature found at block 1023 [0x07fe0000]
First info table with writecount 23 found in block 960
Second info table with writecount 23 found in block 963
NMBM has been successfully attached
U-Boot 2018.09 (Jan 22 2021 - 07:42:43 +0000)
CPU: MediaTek MT7621AT ver 1, eco 3
Clocks: CPU: 880MHz, DDR: 600MHz (1200MT/s), Bus: 220MHz, XTAL: 40MHz
Model: MediaTek MT7621 reference board (NAND)
DRAM: 256 MiB
NAND: 128 MiB
Initializing NMBM ...
Signature found at block 1023 [0x07fe0000]
First info table with writecount 23 found in block 960
Second info table with writecount 23 found in block 963
NMBM has been successfully attached
Loading Environment from NMBM... *** Warning - bad CRC, using default environment
In: uartlite0@1e000c00
Out: uartlite0@1e000c00
Err: uartlite0@1e000c00
Net:
Warning: eth@1e100000 (eth0) using random MAC address - fa:26:d7:78:e2:6c
eth0: eth@1e100000
Reading from 0x7700000, size 0x20000
Succeeded
Zyxel version:V1.03
gpio: pin 6 (gpio 6) value is 1
gpio: pin 24 (gpio 24) value is 0
gpio: pin 24 (gpio 24) value is 1
Hit any key to stop autoboot: 0
Loading FIT image at offset 0x180000 to memory 0x83000000, size 0x2c4098 ...
Automatic boot of image at addr 0x83000000 ...
## Loading kernel from FIT Image at 83000000 ...
Using 'conf-1' configuration
Trying 'kernel' kernel subimage
Description: Vanilla Linux kernel
Type: Kernel Image
Compression: lzma compressed
Data Start: 0x83000110
Data Size: 2886231 Bytes = 2.8 MiB
Architecture: MIPS
OS: Linux
Load Address: 0x80001000
Entry Point: 0x80001000
Hash algo: crc32
Hash value: 2b3aa711
Hash algo: sha1
Hash value: c6601a1909011f95acfbfaed2c6c2b4f6703a98a
Verifying Hash Integrity ... crc32+ sha1+ OK
## Loading fdt from FIT Image at 83000000 ...
Using 'conf-1' configuration
Trying 'fdt-1' fdt subimage
Description: Flattened Device Tree blob
Type: Flat Device Tree
Compression: uncompressed
Data Start: 0x832c0c94
Data Size: 12011 Bytes = 11.7 KiB
Architecture: MIPS
Hash algo: crc32
Hash value: e712ab77
Hash algo: sha1
Hash value: 705532a8d74d5d6921aada1572531caf385c4aaf
Verifying Hash Integrity ... crc32+ sha1+ OK
Booting using the fdt blob at 0x832c0c94
Uncompressing Kernel Image ... OK
Loading Device Tree to 8fe67000, end 8fe6ceea ... OK

View file

@ -10,5 +10,4 @@
tftpboot = import ./tftpboot/test.nix;
updown = import ./updown/test.nix;
inout = import ./inout/test.nix;
custom-shell = import ./custom-shell/test.nix;
}

View file

@ -1,7 +0,0 @@
set timeout 60
spawn socat unix-connect:vm/console -
expect {
"root@liminix blah blah > " { exit 0 }
timeout { exit 1 }
}

View file

@ -1,13 +0,0 @@
{ config, pkgs, lib, ... } :
let
inherit (pkgs.liminix.networking) interface address hostapd route dnsmasq;
inherit (pkgs.liminix.services) oneshot longrun bundle target;
in rec {
imports = [
../../modules/network
];
defaultProfile.prompt = "$(whoami)@$(hostname) blah blah > ";
defaultProfile.packages = with pkgs; [ ];
}

View file

@ -1,21 +0,0 @@
{
liminix
, nixpkgs
}:
let img = (import liminix {
inherit nixpkgs;
device = import "${liminix}/devices/qemu/";
liminix-config = ./configuration.nix;
}).outputs.default;
pkgs = import nixpkgs { overlays = [(import ../../overlay.nix)]; };
in pkgs.runCommand "check" {
nativeBuildInputs = with pkgs; [
expect socat
] ;
} ''
. ${../test-helpers.sh}
mkdir vm
${img}/run.sh --background ./vm
expect ${./check-prompt.expect} |tee output && mv output $out
''

View file

@ -6,7 +6,7 @@ let img = (import liminix {
device = import "${liminix}/devices/qemu/";
liminix-config = ./configuration.nix;
}).outputs.vmroot;
pkgs = import nixpkgs { overlays = [(import ../../overlay.nix)]; };
pkgs = import <nixpkgs> { overlays = [(import ../../overlay.nix)]; };
in pkgs.runCommand "check" {
nativeBuildInputs = with pkgs; [
expect

View file

@ -4,7 +4,7 @@
}:
let
overlay = import "${liminix}/overlay.nix";
pkgs = import nixpkgs { overlays = [overlay]; };
pkgs = import <nixpkgs> { overlays = [overlay]; };
script = pkgs.writeFennelScript "foo" [] ./hello.fnl;
inherit (pkgs.lua.pkgs) fifo;
netlink = pkgs.netlink-lua;

View file

@ -6,7 +6,7 @@ let img = (import liminix {
device = import "${liminix}/devices/qemu/";
liminix-config = ./configuration.nix;
}).outputs.vmroot;
pkgs = import nixpkgs { overlays = [(import ../../overlay.nix)]; };
pkgs = import <nixpkgs> { overlays = [(import ../../overlay.nix)]; };
in pkgs.runCommand "check" {
nativeBuildInputs = with pkgs; [
expect

View file

@ -5,6 +5,7 @@ in {
imports = [
../../vanilla-configuration.nix
../../modules/squashfs.nix
../../modules/outputs/jffs2.nix
];
config.rootfsType = "jffs2";
config.filesystem = dir {

View file

@ -6,7 +6,7 @@ let img = (import liminix {
device = import "${liminix}/devices/qemu/";
liminix-config = ./configuration.nix;
}).outputs.vmroot;
pkgs = import nixpkgs { overlays = [(import ../../overlay.nix)]; };
pkgs = import <nixpkgs> { overlays = [(import ../../overlay.nix)]; };
in pkgs.runCommand "check" {
nativeBuildInputs = with pkgs; [
expect

View file

@ -13,6 +13,7 @@ let
in {
imports = [
../../vanilla-configuration.nix
../../modules/outputs/jffs2.nix
];
config = {
services.sshd = longrun {

View file

@ -8,7 +8,7 @@ let lmx = (import liminix {
});
rogue = lmx.pkgs.rogue;
img = lmx.outputs.vmroot;
pkgs = import nixpkgs { overlays = [(import ../../overlay.nix)]; };
pkgs = import <nixpkgs> { overlays = [(import ../../overlay.nix)]; };
in pkgs.runCommand "check" {
nativeBuildInputs = with pkgs; [
expect

View file

@ -6,7 +6,7 @@ let img = (import liminix {
device = import "${liminix}/devices/qemu";
liminix-config = ./configuration.nix;
}).outputs.default;
pkgs = import nixpkgs { overlays = [(import ../../overlay.nix)]; };
pkgs = import <nixpkgs> { overlays = [(import ../../overlay.nix)]; };
inherit (pkgs.pkgsBuildBuild) routeros;
in pkgs.runCommand "check" {
nativeBuildInputs = with pkgs; [

View file

@ -1,6 +1,5 @@
{
liminix,
...
liminix
}:
let check = deviceName : config :
let derivation = (import liminix {

View file

@ -6,7 +6,7 @@ let img = (import liminix {
device = import "${liminix}/devices/qemu/";
liminix-config = ./configuration.nix;
}).outputs.vmroot;
pkgs = import nixpkgs { overlays = [(import ../../overlay.nix)]; };
pkgs = import <nixpkgs> { overlays = [(import ../../overlay.nix)]; };
in pkgs.runCommand "check" {
nativeBuildInputs = with pkgs; [
expect

View file

@ -7,7 +7,6 @@ in rec {
../../modules/wlan.nix
../../modules/hostapd
../../modules/network
./wpa_supplicant.nix
];
services.hostap = config.system.service.hostapd.build {
@ -28,21 +27,5 @@ in rec {
};
};
services.wpa_supplicant = config.system.service.wpa_supplicant.build {
interface = "wlan1";
driver = "nl80211";
config-file = pkgs.writeText "wpa_supplicant.conf" ''
country=us
update_config=1
ctrl_interface=/run/wpa_supplicant
network={
scan_ssid=1
ssid="liminix"
psk="colourless green ideas"
}
'';
};
defaultProfile.packages = with pkgs; [ tcpdump wpa_supplicant ];
defaultProfile.packages = with pkgs; [ tcpdump ] ;
}

View file

@ -3,11 +3,10 @@
, nixpkgs
}:
let img = (import liminix {
inherit nixpkgs;
device = import "${liminix}/devices/qemu/";
device = import "${liminix}/devices/qemu-armv7l/";
liminix-config = ./configuration.nix;
}).outputs.default;
pkgs = import nixpkgs { overlays = [(import ../../overlay.nix)]; };
pkgs = import <nixpkgs> { overlays = [(import ../../overlay.nix)]; };
in pkgs.runCommand "check" {
nativeBuildInputs = with pkgs; [
expect socat

View file

@ -14,10 +14,10 @@ expect {
}
expect "#"
while { $FINISHED < 10 } {
send "date && grep CTRL-EVENT-CONNECTED /run/uncaught-logs/* || echo \$NOT\r\n"
send "date && grep AP-ENABLED /run/uncaught-logs/* || echo \$NOT\r\n"
expect {
"wlan1: CTRL-EVENT-CONNECTED" { set FINISHED 999; set EXIT 0; }
"wlan0: AP-ENABLED" { set FINISHED 999; set EXIT 0; }
"not_present" { send_user "waiting ...\n" ; sleep 5 }
}
set FINISHED [ expr $FINISHED + 1 ]

View file

@ -1,21 +0,0 @@
{
liminix,
wpa_supplicant,
lib,
}:
{
interface,
driver,
config-file,
}:
let
inherit (liminix.services) longrun;
inherit (lib.strings) escapeShellArg;
in
longrun {
name = "wpa_supplicant";
run =
''
${wpa_supplicant}/bin/wpa_supplicant -D${driver} -i${interface} -c ${config-file}
'';
}

View file

@ -1,15 +0,0 @@
{ config, lib, pkgs, ... }:
with lib; {
options.system.service.wpa_supplicant = mkOption { type = pkgs.liminix.lib.types.serviceDefn; };
config.system.service.wpa_supplicant = config.system.callService ./wpa_service.nix {
interface = mkOption {
type = types.str;
};
driver = mkOption {
type = types.str;
};
config-file = mkOption {
type = types.package;
};
};
}