forked from dan/liminix
Compare commits
10 Commits
main
...
hark-how-a
Author | SHA1 | Date | |
---|---|---|---|
503c8526d1 | |||
32237467b3 | |||
b213e39756 | |||
42bfadc059 | |||
9bb475386c | |||
8ecaad7945 | |||
124bd404bf | |||
07ff405339 | |||
1a58501cb1 | |||
e4b14bf15c |
27
NEWS
27
NEWS
@ -1,27 +0,0 @@
|
|||||||
A brief guide to backward-incompatible changes
|
|
||||||
that are likely to break configurations or workflows
|
|
||||||
|
|
||||||
2023-07-13
|
|
||||||
|
|
||||||
* a significant re-arrangement of modules and services, which will
|
|
||||||
probably break any configuration written before this time. For a
|
|
||||||
detailed explanation, see
|
|
||||||
https://www.liminix.org/doc/configuration.html#modules
|
|
||||||
|
|
||||||
2023-12-10
|
|
||||||
|
|
||||||
* configurations (usually) need no longer import modules from
|
|
||||||
modules/outputs because devices are expected to do this instead. This
|
|
||||||
change is because the outputs that make sense in any given context are
|
|
||||||
usually a property of the device being installed onto.
|
|
||||||
|
|
||||||
2023-12-11
|
|
||||||
|
|
||||||
* rename outputs.flashimage to outputs.mtdimage (and also diskimage to
|
|
||||||
mbrimage). This change is made in the expectation that "fooimage" is
|
|
||||||
the name of an outputs that gloms together other filesystem-like
|
|
||||||
outputs with some kind of partition table - so we might in future have
|
|
||||||
gptimage or lvmimage or ubimage.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
20
README.md
20
README.md
@ -18,14 +18,22 @@ outside word goes across it.
|
|||||||
|
|
||||||
Liminix is pre-1.0. We are still finding new and better ways to do things,
|
Liminix is pre-1.0. We are still finding new and better ways to do things,
|
||||||
and there is no attempt to maintain backward compatibility with the old
|
and there is no attempt to maintain backward compatibility with the old
|
||||||
ways.
|
ways. This will change when it settles down.
|
||||||
|
|
||||||
The [NEWS](NEWS) file (available wherever you found this README) is
|
_In general:_ development mostly happens on the `main` branch, which is
|
||||||
a high-level overview of breaking changes.
|
therefore not guaranteed to build or to work on every commit. For the
|
||||||
|
latest functioning version, see [the CI system](https://build.liminix.org/jobset/liminix/build) and pick a revision with all jobs green.
|
||||||
|
|
||||||
Development mostly happens on the `main` branch, which is therefore
|
_In particular:_ as of July 2023, a significant re-arrangement of
|
||||||
not guaranteed to build or to work on every commit. For the latest
|
modules and services is ongoing:
|
||||||
functioning version, see [the CI system](https://build.liminix.org/jobset/liminix/build) and pick a revision with all jobs green.
|
|
||||||
|
* if you are using out-of-tree configurations created before commit
|
||||||
|
2e50368, especially if they reference things under pkgs.liminix,
|
||||||
|
they will need updating. Look at changes to examples/rotuer.nix
|
||||||
|
for guidance
|
||||||
|
|
||||||
|
* the same is intermittently true for examples/{extensino,arhcive}.nix
|
||||||
|
where I've updated rotuer and not updated them to match.
|
||||||
|
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
1317
THOUGHTS.txt
1317
THOUGHTS.txt
File diff suppressed because it is too large
Load Diff
@ -99,16 +99,14 @@ in {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
environment.systemPackages =
|
environment.systemPackages = with pkgs; [
|
||||||
let wireshark-nogui = pkgs.wireshark.override { withQt = false ; };
|
tcpdump
|
||||||
in with pkgs; [
|
wireshark
|
||||||
tcpdump
|
socat
|
||||||
wireshark-nogui
|
tufted
|
||||||
socat
|
iptables
|
||||||
tufted
|
usbutils
|
||||||
iptables
|
];
|
||||||
usbutils
|
|
||||||
];
|
|
||||||
security.sudo.wheelNeedsPassword = false;
|
security.sudo.wheelNeedsPassword = false;
|
||||||
networking = {
|
networking = {
|
||||||
hostName = "border";
|
hostName = "border";
|
||||||
|
73
ci.nix
73
ci.nix
@ -8,63 +8,48 @@ let
|
|||||||
pkgs = (import nixpkgs {});
|
pkgs = (import nixpkgs {});
|
||||||
borderVmConf = ./bordervm.conf-example.nix;
|
borderVmConf = ./bordervm.conf-example.nix;
|
||||||
inherit (pkgs.lib.attrsets) genAttrs;
|
inherit (pkgs.lib.attrsets) genAttrs;
|
||||||
devices = [
|
devices = {
|
||||||
"gl-ar750" "gl-mt300n-v2" "gl-mt300a"
|
virt = [ "qemu" "qemu-aarch64" ];
|
||||||
"qemu" "qemu-aarch64" "qemu-armv7l"
|
hw = [ "gl-ar750" "gl-mt300n-v2" "gl-mt300a" ];
|
||||||
];
|
};
|
||||||
vanilla = ./vanilla-configuration.nix;
|
vanilla = ./vanilla-configuration.nix;
|
||||||
for-device = name:
|
for-device = cfg: name:
|
||||||
(import liminix {
|
(import liminix {
|
||||||
inherit nixpkgs borderVmConf;
|
inherit nixpkgs borderVmConf;
|
||||||
device = import (liminix + "/devices/${name}");
|
device = import (liminix + "/devices/${name}");
|
||||||
liminix-config = vanilla;
|
liminix-config = cfg;
|
||||||
}).outputs.default;
|
}).outputs.default;
|
||||||
tests = import ./tests/ci.nix;
|
tests = import ./tests/ci.nix;
|
||||||
jobs =
|
jobs =
|
||||||
(genAttrs devices for-device) //
|
(genAttrs devices.hw (name: for-device ./vanilla-configuration-hw.nix name)) //
|
||||||
|
(genAttrs devices.virt (name: for-device vanilla name)) //
|
||||||
tests //
|
tests //
|
||||||
{
|
{
|
||||||
buildEnv = (import liminix {
|
buildEnv = (import liminix {
|
||||||
inherit nixpkgs borderVmConf;
|
inherit nixpkgs borderVmConf;
|
||||||
device = import (liminix + "/devices/qemu");
|
device = import (liminix + "/devices/qemu");
|
||||||
liminix-config = vanilla;
|
liminix-config = vanilla;
|
||||||
}).buildEnv;
|
}).buildEnv;
|
||||||
doc =
|
doc = pkgs.stdenv.mkDerivation {
|
||||||
let json =
|
name = "liminix-doc";
|
||||||
(import liminix {
|
nativeBuildInputs = with pkgs; [
|
||||||
inherit nixpkgs borderVmConf;
|
gnumake sphinx
|
||||||
device = import (liminix + "/devices/qemu");
|
fennel luaPackages.lyaml
|
||||||
liminix-config = {...} : {
|
];
|
||||||
imports = [ ./modules/all-modules.nix ];
|
src = ./doc;
|
||||||
};
|
buildPhase = ''
|
||||||
}).outputs.optionsJson;
|
cat ${(import ./doc/extract-options.nix).doc} > options.json
|
||||||
installers = map (f: "system.outputs.${f}") [
|
cat options.json | fennel --correlate parse-options.fnl > modules-generated.rst
|
||||||
"vmroot"
|
cp ${(import ./doc/hardware.nix)} hardware.rst
|
||||||
"mtdimage"
|
make html
|
||||||
"ubimage"
|
'';
|
||||||
];
|
installPhase = ''
|
||||||
inherit (pkgs.lib) concatStringsSep;
|
mkdir -p $out/nix-support $out/share/doc/
|
||||||
in pkgs.stdenv.mkDerivation {
|
cp modules.rst options.json $out
|
||||||
name = "liminix-doc";
|
cp -a _build/html $out/share/doc/liminix
|
||||||
nativeBuildInputs = with pkgs; [
|
echo "file source-dist \"$out/share/doc/liminix\"" \
|
||||||
gnumake sphinx fennel luaPackages.lyaml
|
> $out/nix-support/hydra-build-products
|
||||||
];
|
'';
|
||||||
src = ./.;
|
|
||||||
buildPhase = ''
|
|
||||||
cat ${json} | fennel --correlate doc/parse-options.fnl > doc/modules-generated.rst
|
|
||||||
cat ${json} | fennel --correlate doc/parse-options-outputs.fnl > doc/outputs-generated.rst
|
|
||||||
cp ${(import ./doc/hardware.nix)} doc/hardware.rst
|
|
||||||
make -C doc html
|
|
||||||
'';
|
|
||||||
installPhase = ''
|
|
||||||
mkdir -p $out/nix-support $out/share/doc/
|
|
||||||
cd doc
|
|
||||||
cp *-generated.rst $out
|
|
||||||
ln -s ${json} $out/options.json
|
|
||||||
cp -a _build/html $out/share/doc/liminix
|
|
||||||
echo "file source-dist \"$out/share/doc/liminix\"" \
|
|
||||||
> $out/nix-support/hydra-build-products
|
|
||||||
'';
|
|
||||||
};
|
};
|
||||||
with-unstable = (import liminix {
|
with-unstable = (import liminix {
|
||||||
nixpkgs = unstable;
|
nixpkgs = unstable;
|
||||||
|
14
default.nix
14
default.nix
@ -13,14 +13,13 @@ let
|
|||||||
allowUnsupportedSystem = true; # mipsel
|
allowUnsupportedSystem = true; # mipsel
|
||||||
permittedInsecurePackages = [
|
permittedInsecurePackages = [
|
||||||
"python-2.7.18.6" # kernel backports needs python <3
|
"python-2.7.18.6" # kernel backports needs python <3
|
||||||
"python-2.7.18.7"
|
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
eval = pkgs.lib.evalModules {
|
config = (pkgs.lib.evalModules {
|
||||||
modules = [
|
modules = [
|
||||||
{ _module.args = { inherit pkgs; inherit (pkgs) lim; }; }
|
{ _module.args = { inherit pkgs; lib = pkgs.lib; }; }
|
||||||
./modules/hardware.nix
|
./modules/hardware.nix
|
||||||
./modules/base.nix
|
./modules/base.nix
|
||||||
./modules/busybox.nix
|
./modules/busybox.nix
|
||||||
@ -31,8 +30,7 @@ let
|
|||||||
./modules/users.nix
|
./modules/users.nix
|
||||||
./modules/outputs.nix
|
./modules/outputs.nix
|
||||||
];
|
];
|
||||||
};
|
}).config;
|
||||||
config = eval.config;
|
|
||||||
|
|
||||||
borderVm = ((import <nixpkgs/nixos/lib/eval-config.nix>) {
|
borderVm = ((import <nixpkgs/nixos/lib/eval-config.nix>) {
|
||||||
system = builtins.currentSystem;
|
system = builtins.currentSystem;
|
||||||
@ -45,12 +43,6 @@ let
|
|||||||
in {
|
in {
|
||||||
outputs = config.system.outputs // {
|
outputs = config.system.outputs // {
|
||||||
default = config.system.outputs.${config.hardware.defaultOutput};
|
default = config.system.outputs.${config.hardware.defaultOutput};
|
||||||
optionsJson =
|
|
||||||
let o = import ./doc/extract-options.nix {
|
|
||||||
inherit pkgs eval;
|
|
||||||
lib = pkgs.lib;
|
|
||||||
};
|
|
||||||
in pkgs.writeText "options.json" (builtins.toJSON o);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
# this is just here as a convenience, so that we can get a
|
# this is just here as a convenience, so that we can get a
|
||||||
|
@ -1,44 +1,15 @@
|
|||||||
|
# This "device" generates images that can be used with the QEMU
|
||||||
|
# emulator. The default output is a directory containing separate
|
||||||
|
# kernel ("Image" format) and root filesystem (squashfs or jffs2)
|
||||||
|
# images
|
||||||
{
|
{
|
||||||
description = ''
|
|
||||||
Belkin RT-3200 / Linksys E8450
|
|
||||||
******************************
|
|
||||||
|
|
||||||
This device is based on a 64 bit Mediatek MT7622 ARM platform,
|
|
||||||
and is "work in progress" in Liminix.
|
|
||||||
|
|
||||||
.. note:: The factory flash image contains ECC errors that make it
|
|
||||||
incompatible with Liminix: you need to use the `OpenWrt
|
|
||||||
UBI Installer <https://github.com/dangowrt/owrt-ubi-installer>`_ to
|
|
||||||
rewrite the partition layout before you can flash
|
|
||||||
Liminix onto it (or even use it with
|
|
||||||
:ref:`system-outputs-tftpboot`, if you want the wireless
|
|
||||||
to work).
|
|
||||||
|
|
||||||
Hardware summary
|
|
||||||
================
|
|
||||||
|
|
||||||
- MediaTek MT7622BV (1350MHz)
|
|
||||||
- 128MB NAND flash
|
|
||||||
- 512MB RAM
|
|
||||||
- b/g/n wireless using MediaTek MT7622BV (MT7615E driver)
|
|
||||||
- a/n/ac/ax wireless using MediaTek MT7915E
|
|
||||||
|
|
||||||
|
|
||||||
Installation
|
|
||||||
============
|
|
||||||
|
|
||||||
Installation is currently a manual process (you need a :ref:`serial <serial>` conection and
|
|
||||||
TFTP) following the instructions at :ref:`system-outputs-ubimage`
|
|
||||||
|
|
||||||
'';
|
|
||||||
|
|
||||||
system = {
|
system = {
|
||||||
crossSystem = {
|
crossSystem = {
|
||||||
config = "aarch64-unknown-linux-musl";
|
config = "aarch64-unknown-linux-musl";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
module = {pkgs, config, lib, lim, ... }:
|
module = {pkgs, config, lib, ... }:
|
||||||
let firmware = pkgs.stdenv.mkDerivation {
|
let firmware = pkgs.stdenv.mkDerivation {
|
||||||
name = "wlan-firmware";
|
name = "wlan-firmware";
|
||||||
phases = ["installPhase"];
|
phases = ["installPhase"];
|
||||||
@ -48,12 +19,7 @@
|
|||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
in {
|
in {
|
||||||
imports = [
|
imports = [ ../../modules/arch/aarch64.nix ];
|
||||||
../../modules/arch/aarch64.nix
|
|
||||||
../../modules/outputs/tftpboot.nix
|
|
||||||
../../modules/outputs/ubifs.nix
|
|
||||||
];
|
|
||||||
config = {
|
|
||||||
kernel = {
|
kernel = {
|
||||||
src = pkgs.pkgsBuildBuild.fetchurl {
|
src = pkgs.pkgsBuildBuild.fetchurl {
|
||||||
name = "linux.tar.gz";
|
name = "linux.tar.gz";
|
||||||
@ -100,6 +66,7 @@
|
|||||||
PCIE_MEDIATEK = "y";
|
PCIE_MEDIATEK = "y";
|
||||||
|
|
||||||
BLOCK = "y"; # move this to base option
|
BLOCK = "y"; # move this to base option
|
||||||
|
NETDEVICES = "y"; # and this probably also
|
||||||
|
|
||||||
SPI_MASTER = "y";
|
SPI_MASTER = "y";
|
||||||
SPI = "y";
|
SPI = "y";
|
||||||
@ -120,7 +87,10 @@
|
|||||||
MTD_SPI_NOR= "y";
|
MTD_SPI_NOR= "y";
|
||||||
MTD_SPLIT_FIRMWARE= "y";
|
MTD_SPLIT_FIRMWARE= "y";
|
||||||
MTD_SPLIT_FIT_FW= "y";
|
MTD_SPLIT_FIT_FW= "y";
|
||||||
|
MTD_UBI="y";
|
||||||
|
MTD_UBI_BEB_LIMIT="20";
|
||||||
|
MTD_UBI_BLOCK="y";
|
||||||
|
MTD_UBI_WL_THRESHOLD="4096";
|
||||||
|
|
||||||
MMC = "y";
|
MMC = "y";
|
||||||
MMC_BLOCK = "y";
|
MMC_BLOCK = "y";
|
||||||
@ -146,11 +116,9 @@
|
|||||||
SERIAL_OF_PLATFORM="y";
|
SERIAL_OF_PLATFORM="y";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
boot = {
|
boot.commandLine = [
|
||||||
commandLine = [ "console=ttyS0,115200" ];
|
"console=ttyS0,115200"
|
||||||
tftp.loadAddress = lim.parseInt "0x4007ff28";
|
];
|
||||||
imageFormat = "fit";
|
|
||||||
};
|
|
||||||
filesystem =
|
filesystem =
|
||||||
let inherit (pkgs.pseudofile) dir symlink;
|
let inherit (pkgs.pseudofile) dir symlink;
|
||||||
in
|
in
|
||||||
@ -173,36 +141,19 @@
|
|||||||
klibBuild = config.system.outputs.kernel.modulesupport;
|
klibBuild = config.system.outputs.kernel.modulesupport;
|
||||||
};
|
};
|
||||||
in {
|
in {
|
||||||
ubi = {
|
defaultOutput = "flashimage";
|
||||||
minIOSize = "2048";
|
loadAddress = "0x41080000";
|
||||||
eraseBlockSize = "126976";
|
entryPoint = "0x41080000";
|
||||||
maxLEBcount = "1024"; # guessing
|
rootDevice = "/dev/mtdblock0";
|
||||||
};
|
|
||||||
|
|
||||||
defaultOutput = "ubimage";
|
|
||||||
# the kernel expects this to be on a 2MB boundary. U-Boot
|
|
||||||
# (I don't know why) has a default of 0x41080000, which isn't.
|
|
||||||
# We put it at the 32MB mark so that tftpboot can put its rootfs
|
|
||||||
# image and DTB underneath, but maybe this is a terrible waste of
|
|
||||||
# RAM unless the kernel is able to reuse it later. Oh well
|
|
||||||
loadAddress = lim.parseInt "0x42000000";
|
|
||||||
entryPoint = lim.parseInt "0x42000000";
|
|
||||||
rootDevice = "ubi0:liminix";
|
|
||||||
dts = {
|
dts = {
|
||||||
src = "${openwrt.src}/target/linux/mediatek/dts/mt7622-linksys-e8450-ubi.dts";
|
src = "${openwrt.src}/target/linux/mediatek/dts/mt7622-linksys-e8450.dts";
|
||||||
includes = [
|
includes = [
|
||||||
"${openwrt.src}/target/linux/mediatek/dts"
|
"${openwrt.src}/target/linux/mediatek/dts"
|
||||||
"${config.system.outputs.kernel.modulesupport}/arch/arm64/boot/dts/mediatek/"
|
"${config.system.outputs.kernel.modulesupport}/arch/arm64/boot/dts/mediatek/"
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
# - 0x000000000000-0x000008000000 : "spi-nand0"
|
flash.eraseBlockSize = "65536"; # c.f. pkgs/mips-vm/mips-vm.sh
|
||||||
# - 0x000000000000-0x000000080000 : "bl2"
|
|
||||||
# - 0x000000080000-0x0000001c0000 : "fip"
|
|
||||||
# - 0x0000001c0000-0x0000002c0000 : "factory"
|
|
||||||
# - 0x0000002c0000-0x000000300000 : "reserved"
|
|
||||||
# - 0x000000300000-0x000008000000 : "ubi"
|
|
||||||
|
|
||||||
networkInterfaces =
|
networkInterfaces =
|
||||||
let
|
let
|
||||||
inherit (config.system.service.network) link;
|
inherit (config.system.service.network) link;
|
||||||
@ -225,6 +176,6 @@
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,57 +0,0 @@
|
|||||||
{ config, pkgs, ... }:
|
|
||||||
{
|
|
||||||
imports = [
|
|
||||||
../../modules/outputs/jffs2.nix
|
|
||||||
];
|
|
||||||
config = {
|
|
||||||
kernel = {
|
|
||||||
src = pkgs.pkgsBuildBuild.fetchurl {
|
|
||||||
name = "linux.tar.gz";
|
|
||||||
url = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.71.tar.gz";
|
|
||||||
hash = "sha256-yhO2cXIeIgUxkSZf/4aAsF11uxyh+UUZu6D1h92vCD8=";
|
|
||||||
};
|
|
||||||
config = {
|
|
||||||
MTD = "y";
|
|
||||||
MTD_BLOCK = "y";
|
|
||||||
MTD_CMDLINE_PARTS = "y";
|
|
||||||
MTD_PHRAM = "y";
|
|
||||||
|
|
||||||
VIRTIO_MENU = "y";
|
|
||||||
PCI = "y";
|
|
||||||
VIRTIO_PCI = "y";
|
|
||||||
BLOCK = "y";
|
|
||||||
VIRTIO_BLK = "y";
|
|
||||||
VIRTIO_NET = "y";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
hardware =
|
|
||||||
let
|
|
||||||
mac80211 = pkgs.mac80211.override {
|
|
||||||
drivers = ["mac80211_hwsim"];
|
|
||||||
klibBuild = config.system.outputs.kernel.modulesupport;
|
|
||||||
};
|
|
||||||
in {
|
|
||||||
defaultOutput = "vmroot";
|
|
||||||
rootDevice = "/dev/mtdblock0";
|
|
||||||
dts.src = pkgs.lib.mkDefault null;
|
|
||||||
flash.eraseBlockSize = 65536;
|
|
||||||
networkInterfaces =
|
|
||||||
let inherit (config.system.service.network) link;
|
|
||||||
in {
|
|
||||||
wan = link.build {
|
|
||||||
devpath = "/devices/pci0000:00/0000:00:13.0/virtio0";
|
|
||||||
ifname = "wan";
|
|
||||||
};
|
|
||||||
lan = link.build {
|
|
||||||
devpath = "/devices/pci0000:00/0000:00:14.0/virtio1";
|
|
||||||
ifname = "lan";
|
|
||||||
};
|
|
||||||
|
|
||||||
wlan_24 = link.build {
|
|
||||||
ifname = "wlan0";
|
|
||||||
dependencies = [ mac80211 ];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
@ -1,3 +1,11 @@
|
|||||||
|
|
||||||
|
# I like GL.iNet devices because they're relatively accessible to
|
||||||
|
# DIY users: the serial port connections have headers preinstalled
|
||||||
|
# and don't need soldering
|
||||||
|
|
||||||
|
# Mainline linux 5.19 doesn't have device-tree support for this device
|
||||||
|
# or even for the SoC, so we use the extensive OpenWrt kernel patches
|
||||||
|
|
||||||
{
|
{
|
||||||
system = {
|
system = {
|
||||||
crossSystem = {
|
crossSystem = {
|
||||||
@ -13,9 +21,6 @@
|
|||||||
GL.iNet GL-AR750
|
GL.iNet GL-AR750
|
||||||
****************
|
****************
|
||||||
|
|
||||||
Hardware summary
|
|
||||||
================
|
|
||||||
|
|
||||||
The GL-AR750 "Creta" travel router features:
|
The GL-AR750 "Creta" travel router features:
|
||||||
|
|
||||||
- QCA9531 @650Mhz SoC
|
- QCA9531 @650Mhz SoC
|
||||||
@ -25,34 +30,29 @@
|
|||||||
- 16MB NOR Flash
|
- 16MB NOR Flash
|
||||||
- supported in OpenWrt by the "ath79" SoC family
|
- supported in OpenWrt by the "ath79" SoC family
|
||||||
|
|
||||||
|
As with many GL.iNet devices, the stock vendor firmware
|
||||||
|
is a fork of OpenWrt, meaning that the plain binary
|
||||||
|
``firmware.bin`` that Liminix builds can be flashed using the
|
||||||
|
vendor web UI and the U-Boot emergency "unbrick" routine
|
||||||
|
|
||||||
The GL-AR750 has two distinct sets of wifi hardware. The 2.4GHz
|
The GL-AR750 has two distinct sets of wifi hardware. The 2.4GHz
|
||||||
radio is part of the QCA9531 SoC, i.e. it's on the same silicon as
|
radio is part of the QCA9531 SoC, i.e. it's on the same silicon as
|
||||||
the CPU, the Ethernet, the USB etc. The device is connected to the
|
the CPU, the Ethernet, the USB etc. The device is connected to the
|
||||||
host via `AHB <https://en.wikipedia.org/wiki/Advanced_Microcontroller_Bus_Architecture>`_ and it is
|
host via AHB, the "Advanced High-Performance Bus" and it is
|
||||||
supported in Linux using the ath9k driver. 5GHz wifi
|
supported in Linux using the ath9k driver. The 5GHz support, on the
|
||||||
is provided by a QCA9887 PCIe (PCI embedded) WLAN chip,
|
other hand, is provided by a QCA9887 PCIe (PCI embedded) WLAN chip:
|
||||||
|
I haven't looked closely at the router innards to see if this is
|
||||||
|
actually physically a separate board that could be unplugged, but
|
||||||
|
as far as Linux is concerned it behaves as one. This is
|
||||||
supported by the ath10k driver.
|
supported by the ath10k driver.
|
||||||
|
|
||||||
Installation
|
|
||||||
============
|
|
||||||
|
|
||||||
As with many GL.iNet devices, the stock vendor firmware
|
|
||||||
is a fork of OpenWrt, meaning that the binary created by
|
|
||||||
:ref:`system-outputs-mtdimage` can be flashed using the
|
|
||||||
vendor web UI or the U-Boot emergency "unbrick" routine.
|
|
||||||
|
|
||||||
For flashing from an existing Liminix system (we believe that) it
|
|
||||||
is necessary to first boot into a :ref:`system-outputs-kexecboot`
|
|
||||||
system, otherwise you'll be overwriting flash partitions while
|
|
||||||
they're in use - and that might not end well.
|
|
||||||
|
|
||||||
Vendor web page: https://www.gl-inet.com/products/gl-ar750/
|
Vendor web page: https://www.gl-inet.com/products/gl-ar750/
|
||||||
|
|
||||||
OpenWrt web page: https://openwrt.org/toh/gl.inet/gl-ar750
|
OpenWrt web page: https://openwrt.org/toh/gl.inet/gl-ar750
|
||||||
|
|
||||||
'';
|
'';
|
||||||
|
|
||||||
module = {pkgs, config, lim, ... }:
|
module = {pkgs, config, ... }:
|
||||||
let
|
let
|
||||||
openwrt = pkgs.openwrt;
|
openwrt = pkgs.openwrt;
|
||||||
firmwareBlobs = pkgs.pkgsBuildBuild.fetchFromGitHub {
|
firmwareBlobs = pkgs.pkgsBuildBuild.fetchFromGitHub {
|
||||||
@ -77,8 +77,8 @@
|
|||||||
};
|
};
|
||||||
ath10k_cal_data =
|
ath10k_cal_data =
|
||||||
let
|
let
|
||||||
offset = lim.parseInt "0x5000";
|
offset = 1024 * 20; # 0x5000
|
||||||
size = lim.parseInt "0x844";
|
size = 2048 + 68; # 0x844
|
||||||
in pkgs.liminix.services.oneshot rec {
|
in pkgs.liminix.services.oneshot rec {
|
||||||
name = "ath10k_cal_data";
|
name = "ath10k_cal_data";
|
||||||
up = ''
|
up = ''
|
||||||
@ -96,22 +96,19 @@
|
|||||||
imports = [
|
imports = [
|
||||||
../../modules/network
|
../../modules/network
|
||||||
../../modules/arch/mipseb.nix
|
../../modules/arch/mipseb.nix
|
||||||
../../modules/outputs/tftpboot.nix
|
|
||||||
../../modules/outputs/mtdimage.nix
|
|
||||||
../../modules/outputs/jffs2.nix
|
|
||||||
];
|
];
|
||||||
|
|
||||||
programs.busybox.options = {
|
programs.busybox.options = {
|
||||||
FEATURE_DD_IBS_OBS = "y"; # ath10k_cal_data needs skip_bytes,fullblock
|
FEATURE_DD_IBS_OBS = "y"; # ath10k_cal_data needs skip_bytes,fullblock
|
||||||
};
|
};
|
||||||
hardware = {
|
hardware = {
|
||||||
defaultOutput = "mtdimage";
|
defaultOutput = "flashimage";
|
||||||
loadAddress = lim.parseInt "0x80060000";
|
loadAddress = "0x80060000";
|
||||||
entryPoint = lim.parseInt "0x80060000";
|
entryPoint = "0x80060000";
|
||||||
flash = {
|
flash = {
|
||||||
address = lim.parseInt "0x9F060000";
|
address = "0x9F060000";
|
||||||
size = lim.parseInt "0xfa0000";
|
size ="0xfa0000";
|
||||||
eraseBlockSize = 65536;
|
eraseBlockSize = "65536";
|
||||||
};
|
};
|
||||||
rootDevice = "/dev/mtdblock5";
|
rootDevice = "/dev/mtdblock5";
|
||||||
dts = {
|
dts = {
|
||||||
@ -147,7 +144,7 @@
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
boot.tftp = {
|
boot.tftp = {
|
||||||
loadAddress = lim.parseInt "0x00A00000";
|
loadAddress = "0x00A00000";
|
||||||
};
|
};
|
||||||
kernel = {
|
kernel = {
|
||||||
src = pkgs.pkgsBuildBuild.fetchurl {
|
src = pkgs.pkgsBuildBuild.fetchurl {
|
||||||
@ -155,14 +152,9 @@
|
|||||||
url = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.71.tar.gz";
|
url = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.71.tar.gz";
|
||||||
hash = "sha256-yhO2cXIeIgUxkSZf/4aAsF11uxyh+UUZu6D1h92vCD8=";
|
hash = "sha256-yhO2cXIeIgUxkSZf/4aAsF11uxyh+UUZu6D1h92vCD8=";
|
||||||
};
|
};
|
||||||
|
|
||||||
# Mainline linux 5.19 doesn't have device-tree support for
|
|
||||||
# this device or even for the SoC, so we use the extensive
|
|
||||||
# OpenWrt kernel patches
|
|
||||||
extraPatchPhase = ''
|
extraPatchPhase = ''
|
||||||
${openwrt.applyPatches.ath79}
|
${openwrt.applyPatches.ath79}
|
||||||
'';
|
'';
|
||||||
|
|
||||||
config = {
|
config = {
|
||||||
ATH79 = "y";
|
ATH79 = "y";
|
||||||
PCI = "y";
|
PCI = "y";
|
||||||
@ -183,6 +175,7 @@
|
|||||||
CONSOLE_LOGLEVEL_QUIET = "4";
|
CONSOLE_LOGLEVEL_QUIET = "4";
|
||||||
|
|
||||||
NET = "y";
|
NET = "y";
|
||||||
|
NETDEVICES = "y";
|
||||||
ETHERNET = "y";
|
ETHERNET = "y";
|
||||||
NET_VENDOR_ATHEROS = "y";
|
NET_VENDOR_ATHEROS = "y";
|
||||||
AG71XX = "y"; # ethernet (qca,qca9530-eth)
|
AG71XX = "y"; # ethernet (qca,qca9530-eth)
|
||||||
|
@ -13,11 +13,34 @@
|
|||||||
|
|
||||||
description = ''
|
description = ''
|
||||||
GL.iNet GL-MT300A
|
GL.iNet GL-MT300A
|
||||||
*****************
|
********************
|
||||||
|
|
||||||
The GL-MT300A is based on a MT7620 chipset.
|
The GL-MT300A is based on a MT7620 chipset.
|
||||||
|
|
||||||
For flashing from U-Boot, the firmware partition is from
|
The GL.iNet pocket router range makes nice cheap hardware for
|
||||||
|
playing with Liminix or similar projects. The manufacturers seem
|
||||||
|
open to the DIY market, and the devices have a reasonable amount
|
||||||
|
of RAM and are much easier to get serial connections than many
|
||||||
|
COTS routers.
|
||||||
|
|
||||||
|
Wire up the serial connection: this probably involves opening
|
||||||
|
the box, locating the serial header pins (TX, RX and GND) and
|
||||||
|
connecting a USB TTL converter - e.g. a PL2303 based device - to
|
||||||
|
it. The defunct OpenWRT wiki has a guide with some pictures. (If
|
||||||
|
you don't have a USB TTL converter to hand, other options are
|
||||||
|
available. For example, use the GPIO pins on a Raspberry Pi.)
|
||||||
|
|
||||||
|
Run a terminal emulator such as Minicom on whatever is on the
|
||||||
|
other end of the link. I use 115200 8N1 and find it also helps
|
||||||
|
to set "Line tx delay" to 1ms, "backspace sends DEL" and
|
||||||
|
"lineWrap on".
|
||||||
|
|
||||||
|
When you turn the router on you should be greeted with some
|
||||||
|
messages from U-Boot and a little bit of ASCII art, followed by
|
||||||
|
the instruction to hit SPACE to stop autoboot. Do this and you
|
||||||
|
will get a gl-mt300a> prompt.
|
||||||
|
|
||||||
|
For flashing from uboot, the firmware partition is from
|
||||||
0xbc050000 to 0xbcfd0000.
|
0xbc050000 to 0xbcfd0000.
|
||||||
|
|
||||||
WiFi on this device is provided by the rt2800soc module. It
|
WiFi on this device is provided by the rt2800soc module. It
|
||||||
@ -25,17 +48,6 @@
|
|||||||
- assuming we want to use the wireless - we need to build MTD
|
- assuming we want to use the wireless - we need to build MTD
|
||||||
support into the kernel even if we're using TFTP root.
|
support into the kernel even if we're using TFTP root.
|
||||||
|
|
||||||
Installation
|
|
||||||
============
|
|
||||||
|
|
||||||
The stock vendor firmware is a fork of OpenWrt, meaning that the
|
|
||||||
binary created by :ref:`system-outputs-mtdimage` can be flashed
|
|
||||||
using the vendor web UI or the U-Boot emergency "unbrick" routine.
|
|
||||||
|
|
||||||
For flashing from an existing Liminix system (we think) it
|
|
||||||
is necessary to first boot into a :ref:`system-outputs-kexecboot`
|
|
||||||
system, otherwise you'll be overwriting flash partitions while
|
|
||||||
they're in use - and that might not end well.
|
|
||||||
|
|
||||||
Vendor web page: https://www.gl-inet.com/products/gl-mt300a/
|
Vendor web page: https://www.gl-inet.com/products/gl-mt300a/
|
||||||
|
|
||||||
@ -43,7 +55,7 @@
|
|||||||
|
|
||||||
'';
|
'';
|
||||||
|
|
||||||
module = { pkgs, config, lib, lim, ...}:
|
module = { pkgs, config, lib, ...}:
|
||||||
let
|
let
|
||||||
inherit (pkgs.liminix.networking) interface;
|
inherit (pkgs.liminix.networking) interface;
|
||||||
inherit (pkgs) openwrt;
|
inherit (pkgs) openwrt;
|
||||||
@ -52,16 +64,11 @@
|
|||||||
klibBuild = config.system.outputs.kernel.modulesupport;
|
klibBuild = config.system.outputs.kernel.modulesupport;
|
||||||
};
|
};
|
||||||
in {
|
in {
|
||||||
imports = [
|
imports = [ ../../modules/arch/mipsel.nix ];
|
||||||
../../modules/arch/mipsel.nix
|
|
||||||
../../modules/outputs/tftpboot.nix
|
|
||||||
../../modules/outputs/mtdimage.nix
|
|
||||||
../../modules/outputs/jffs2.nix
|
|
||||||
];
|
|
||||||
hardware = {
|
hardware = {
|
||||||
defaultOutput = "mtdimage";
|
defaultOutput = "flashimage";
|
||||||
loadAddress = lim.parseInt "0x80000000";
|
loadAddress = "0x80000000";
|
||||||
entryPoint = lim.parseInt "0x80000000";
|
entryPoint = "0x80000000";
|
||||||
|
|
||||||
# Creating 5 MTD partitions on "spi0.0":
|
# Creating 5 MTD partitions on "spi0.0":
|
||||||
# 0x000000000000-0x000000030000 : "u-boot"
|
# 0x000000000000-0x000000030000 : "u-boot"
|
||||||
@ -74,9 +81,9 @@
|
|||||||
# 0x000000260000-0x000000f80000 : "rootfs"
|
# 0x000000260000-0x000000f80000 : "rootfs"
|
||||||
|
|
||||||
flash = {
|
flash = {
|
||||||
address = lim.parseInt "0xbc050000";
|
address = "0xbc050000";
|
||||||
size = lim.parseInt "0xf80000";
|
size ="0xf80000";
|
||||||
eraseBlockSize = 65536;
|
eraseBlockSize = "65536";
|
||||||
};
|
};
|
||||||
rootDevice = "/dev/mtdblock5";
|
rootDevice = "/dev/mtdblock5";
|
||||||
|
|
||||||
@ -125,7 +132,7 @@
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
boot.tftp = {
|
boot.tftp = {
|
||||||
loadAddress = lim.parseInt "0x00A00000";
|
loadAddress = "0x00A00000";
|
||||||
};
|
};
|
||||||
|
|
||||||
kernel = {
|
kernel = {
|
||||||
@ -152,6 +159,7 @@
|
|||||||
CONSOLE_LOGLEVEL_QUIET = "4";
|
CONSOLE_LOGLEVEL_QUIET = "4";
|
||||||
|
|
||||||
NET = "y";
|
NET = "y";
|
||||||
|
NETDEVICES = "y";
|
||||||
ETHERNET = "y";
|
ETHERNET = "y";
|
||||||
NET_VENDOR_RALINK = "y";
|
NET_VENDOR_RALINK = "y";
|
||||||
NET_RALINK_MDIO = "y";
|
NET_RALINK_MDIO = "y";
|
||||||
|
@ -13,22 +13,10 @@
|
|||||||
GL.iNet GL-MT300N-v2
|
GL.iNet GL-MT300N-v2
|
||||||
********************
|
********************
|
||||||
|
|
||||||
The GL-MT300N-v2 "Mango" is is very similar to the :ref:`MT300A <GL.iNet GL-MT300A>, but is
|
The GL-MT300N-v2 "Mango" is is very similar to the MT300A, but is
|
||||||
based on the MT7628 chipset instead of MT7620. It's also marginally cheaper
|
based on MT7628 instead of MT7620. It's also marginally cheaper
|
||||||
and comes in a yellow case not a blue one. Be sure your device is
|
and comes in a yellow case not a blue one. It's different again
|
||||||
v2 not v1, which is a different animal and has only half as much RAM.
|
to the v1, which has only half the RAM.
|
||||||
|
|
||||||
Installation
|
|
||||||
============
|
|
||||||
|
|
||||||
The stock vendor firmware is a fork of OpenWrt, meaning that the
|
|
||||||
binary created by :ref:`system-outputs-mtdimage` can be flashed
|
|
||||||
using the vendor web UI or the U-Boot emergency "unbrick" routine.
|
|
||||||
|
|
||||||
For flashing from an existing Liminix system (we think) it
|
|
||||||
is necessary to first boot into a :ref:`system-outputs-kexecboot`
|
|
||||||
system, otherwise you'll be overwriting flash partitions while
|
|
||||||
they're in use - and that might not end well.
|
|
||||||
|
|
||||||
Vendor web page: https://www.gl-inet.com/products/gl-mt300n-v2/
|
Vendor web page: https://www.gl-inet.com/products/gl-mt300n-v2/
|
||||||
|
|
||||||
@ -36,7 +24,7 @@
|
|||||||
|
|
||||||
'';
|
'';
|
||||||
|
|
||||||
module = { pkgs, config, lib, lim, ...}:
|
module = { pkgs, config, lib, ...}:
|
||||||
let
|
let
|
||||||
inherit (pkgs.liminix.networking) interface;
|
inherit (pkgs.liminix.networking) interface;
|
||||||
inherit (pkgs.liminix.services) oneshot;
|
inherit (pkgs.liminix.services) oneshot;
|
||||||
@ -52,12 +40,7 @@
|
|||||||
hash = "sha256:1dkhfznmdz6s50kwc841x3wj0h6zg6icg5g2bim9pvg66as2vmh9";
|
hash = "sha256:1dkhfznmdz6s50kwc841x3wj0h6zg6icg5g2bim9pvg66as2vmh9";
|
||||||
};
|
};
|
||||||
in {
|
in {
|
||||||
imports = [
|
imports = [ ../../modules/arch/mipsel.nix ];
|
||||||
../../modules/arch/mipsel.nix
|
|
||||||
../../modules/outputs/tftpboot.nix
|
|
||||||
../../modules/outputs/mtdimage.nix
|
|
||||||
../../modules/outputs/jffs2.nix
|
|
||||||
];
|
|
||||||
filesystem = dir {
|
filesystem = dir {
|
||||||
lib = dir {
|
lib = dir {
|
||||||
firmware = dir {
|
firmware = dir {
|
||||||
@ -66,14 +49,14 @@
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
hardware = {
|
hardware = {
|
||||||
defaultOutput = "mtdimage";
|
defaultOutput = "flashimage";
|
||||||
loadAddress = lim.parseInt "0x80000000";
|
loadAddress = "0x80000000";
|
||||||
entryPoint = lim.parseInt "0x80000000";
|
entryPoint = "0x80000000";
|
||||||
|
|
||||||
flash = {
|
flash = {
|
||||||
address = lim.parseInt "0xbc050000";
|
address = "0xbc050000";
|
||||||
size = lim.parseInt "0xfb0000";
|
size = "0xfb0000";
|
||||||
eraseBlockSize = 65536;
|
eraseBlockSize = "65536";
|
||||||
};
|
};
|
||||||
rootDevice = "/dev/mtdblock5";
|
rootDevice = "/dev/mtdblock5";
|
||||||
|
|
||||||
@ -121,7 +104,7 @@
|
|||||||
boot.tftp = {
|
boot.tftp = {
|
||||||
# 20MB seems to give enough room to uncompress the kernel
|
# 20MB seems to give enough room to uncompress the kernel
|
||||||
# without anything getting trodden on. 10MB was too small
|
# without anything getting trodden on. 10MB was too small
|
||||||
loadAddress = lim.parseInt "0x1400000";
|
loadAddress = "0x1400000";
|
||||||
};
|
};
|
||||||
|
|
||||||
kernel = {
|
kernel = {
|
||||||
@ -160,6 +143,7 @@
|
|||||||
REGULATOR_FIXED_VOLTAGE = "y";
|
REGULATOR_FIXED_VOLTAGE = "y";
|
||||||
|
|
||||||
NET = "y";
|
NET = "y";
|
||||||
|
NETDEVICES = "y";
|
||||||
ETHERNET = "y";
|
ETHERNET = "y";
|
||||||
|
|
||||||
PHYLIB = "y";
|
PHYLIB = "y";
|
||||||
|
@ -9,33 +9,35 @@
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
description = ''
|
|
||||||
QEMU Aarch64
|
|
||||||
************
|
|
||||||
|
|
||||||
This target produces an image for
|
|
||||||
the `QEMU "virt" platform <https://www.qemu.org/docs/master/system/arm/virt.html>`_ using a 64 bit CPU type.
|
|
||||||
|
|
||||||
ARM targets differ from MIPS in that the kernel format expected
|
|
||||||
by QEMU is an "Image" (raw binary file) rather than an ELF
|
|
||||||
file, but this is taken care of by :command:`run.sh`. Check the
|
|
||||||
documentation for the :ref:`QEMU` (MIPS) target for more information.
|
|
||||||
|
|
||||||
'';
|
|
||||||
|
|
||||||
# this device is described by the "qemu" device
|
# this device is described by the "qemu" device
|
||||||
installer = "vmroot";
|
description = "";
|
||||||
|
|
||||||
module = {pkgs, config, lim, ... }: {
|
|
||||||
imports = [
|
module = {pkgs, config, ... }: {
|
||||||
../../modules/arch/aarch64.nix
|
imports = [ ../../modules/arch/aarch64.nix ];
|
||||||
../families/qemu.nix
|
|
||||||
];
|
|
||||||
kernel = {
|
kernel = {
|
||||||
|
src = pkgs.pkgsBuildBuild.fetchurl {
|
||||||
|
name = "linux.tar.gz";
|
||||||
|
url = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.71.tar.gz";
|
||||||
|
hash = "sha256-yhO2cXIeIgUxkSZf/4aAsF11uxyh+UUZu6D1h92vCD8=";
|
||||||
|
};
|
||||||
config = {
|
config = {
|
||||||
VIRTUALIZATION = "y";
|
VIRTUALIZATION = "y";
|
||||||
PCI_HOST_GENERIC="y";
|
PCI_HOST_GENERIC="y";
|
||||||
|
|
||||||
|
MTD = "y";
|
||||||
|
MTD_BLOCK2MTD = "y";
|
||||||
|
MTD_BLOCK = "y";
|
||||||
|
|
||||||
|
VIRTIO_MENU = "y";
|
||||||
|
PCI = "y";
|
||||||
|
VIRTIO_PCI = "y";
|
||||||
|
BLOCK = "y";
|
||||||
|
VIRTIO_BLK = "y";
|
||||||
|
NETDEVICES = "y";
|
||||||
|
VIRTIO_NET = "y";
|
||||||
|
|
||||||
|
SERIAL_EARLYCON_ARM_SEMIHOST = "y"; # earlycon=smh
|
||||||
SERIAL_AMBA_PL011 = "y";
|
SERIAL_AMBA_PL011 = "y";
|
||||||
SERIAL_AMBA_PL011_CONSOLE = "y";
|
SERIAL_AMBA_PL011_CONSOLE = "y";
|
||||||
};
|
};
|
||||||
@ -43,9 +45,31 @@
|
|||||||
boot.commandLine = [
|
boot.commandLine = [
|
||||||
"console=ttyAMA0,38400"
|
"console=ttyAMA0,38400"
|
||||||
];
|
];
|
||||||
hardware = let addr = lim.parseInt "0x40010000"; in {
|
hardware =
|
||||||
loadAddress = addr;
|
let
|
||||||
entryPoint = addr;
|
mac80211 = pkgs.mac80211.override {
|
||||||
};
|
drivers = ["mac80211_hwsim"];
|
||||||
|
klibBuild = config.system.outputs.kernel.modulesupport;
|
||||||
|
};
|
||||||
|
in {
|
||||||
|
defaultOutput = "vmroot";
|
||||||
|
loadAddress = "0x0";
|
||||||
|
entryPoint = "0x0";
|
||||||
|
rootDevice = "/dev/mtdblock0";
|
||||||
|
|
||||||
|
flash.eraseBlockSize = "65536"; # c.f. pkgs/mips-vm/mips-vm.sh
|
||||||
|
networkInterfaces =
|
||||||
|
let inherit (config.system.service.network) link;
|
||||||
|
in {
|
||||||
|
wan = link.build { ifname = "eth0"; };
|
||||||
|
lan = link.build { ifname = "eth1"; };
|
||||||
|
|
||||||
|
wlan_24 = link.build {
|
||||||
|
ifname = "wlan0";
|
||||||
|
dependencies = [ mac80211 ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,53 +0,0 @@
|
|||||||
# This "device" generates images that can be used with the QEMU
|
|
||||||
# emulator. The default output is a directory containing separate
|
|
||||||
# kernel ("Image" format) and root filesystem (squashfs or jffs2)
|
|
||||||
# images
|
|
||||||
{
|
|
||||||
system = {
|
|
||||||
crossSystem = {
|
|
||||||
config = "armv7l-unknown-linux-musleabihf";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
# this device is described by the "qemu" device
|
|
||||||
description = ''
|
|
||||||
QEMU ARM v7
|
|
||||||
***********
|
|
||||||
|
|
||||||
This target produces an image for
|
|
||||||
the `QEMU "virt" platform <https://www.qemu.org/docs/master/system/arm/virt.html>`_ using a 32 bit CPU type.
|
|
||||||
|
|
||||||
ARM targets differ from MIPS in that the kernel format expected
|
|
||||||
by QEMU is an "Image" (raw binary file) rather than an ELF
|
|
||||||
file, but this is taken care of by :command:`run.sh`. Check the
|
|
||||||
documentation for the :ref:`QEMU` (MIPS) target for more information.
|
|
||||||
'';
|
|
||||||
installer = "vmroot";
|
|
||||||
|
|
||||||
module = {pkgs, config, lim, ... }: {
|
|
||||||
imports = [
|
|
||||||
../../modules/arch/arm.nix
|
|
||||||
../families/qemu.nix
|
|
||||||
];
|
|
||||||
kernel = {
|
|
||||||
config = {
|
|
||||||
PCI_HOST_GENERIC = "y";
|
|
||||||
ARCH_VIRT = "y";
|
|
||||||
|
|
||||||
VFP = "y";
|
|
||||||
NEON = "y";
|
|
||||||
AEABI = "y";
|
|
||||||
|
|
||||||
SERIAL_AMBA_PL011 = "y";
|
|
||||||
SERIAL_AMBA_PL011_CONSOLE = "y";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
boot.commandLine = [
|
|
||||||
"console=ttyAMA0"
|
|
||||||
];
|
|
||||||
hardware = let addr = lim.parseInt "0x40008000"; in {
|
|
||||||
loadAddress = addr;
|
|
||||||
entryPoint = addr;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
@ -13,21 +13,24 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
description = ''
|
description = ''
|
||||||
QEMU MIPS
|
QEMU
|
||||||
*********
|
****
|
||||||
|
|
||||||
This target produces an image for
|
This is not a hardware device. This target produces an image for
|
||||||
QEMU, the "generic and open source machine emulator and
|
QEMU, the "generic and open source machine emulator and
|
||||||
virtualizer".
|
virtualizer".
|
||||||
|
|
||||||
|
Liminix can build QEMU for both MIPS (:code:`qemu` device) and Aarch64 (:code:`qemu-aarch64` device)
|
||||||
|
|
||||||
MIPS QEMU emulates a "Malta" board, which was an ATX form factor
|
MIPS QEMU emulates a "Malta" board, which was an ATX form factor
|
||||||
evaluation board made by MIPS Technologies, but mostly in Liminix
|
evaluation board made by MIPS Technologies, but mostly in Liminix
|
||||||
we use paravirtualized devices (Virtio) instead of emulating
|
we use paravirtualized devices (Virtio) instead of emulating
|
||||||
hardware.
|
hardware. For Aarch64 we use the QEMU "virt" board.
|
||||||
|
|
||||||
Building an image for QEMU results in a :file:`result/` directory
|
Building an image for QEMU results in a :file:`result/` directory
|
||||||
containing ``run.sh`` ``vmlinux``, and ``rootfs`` files. To invoke
|
containing ``run.sh`` ``vmlinux``, ``rootfs`` and possibly
|
||||||
the emulator, run ``run.sh``.
|
(architecture-dependent) ``Image``. To invoke the emulator,
|
||||||
|
run ``run.sh``.
|
||||||
|
|
||||||
The configuration includes two emulated "hardware" ethernet
|
The configuration includes two emulated "hardware" ethernet
|
||||||
devices and the kernel :code:`mac80211_hwsim` module to
|
devices and the kernel :code:`mac80211_hwsim` module to
|
||||||
@ -36,41 +39,56 @@
|
|||||||
in the Development manual.
|
in the Development manual.
|
||||||
|
|
||||||
'';
|
'';
|
||||||
module = {pkgs, config, lib, lim, ... }: {
|
module = {pkgs, config, ... }: {
|
||||||
imports = [
|
imports = [ ../../modules/arch/mipseb.nix ];
|
||||||
../../modules/arch/mipseb.nix
|
|
||||||
../families/qemu.nix
|
|
||||||
];
|
|
||||||
kernel = {
|
kernel = {
|
||||||
|
src = pkgs.pkgsBuildBuild.fetchurl {
|
||||||
|
name = "linux.tar.gz";
|
||||||
|
url = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.71.tar.gz";
|
||||||
|
hash = "sha256-yhO2cXIeIgUxkSZf/4aAsF11uxyh+UUZu6D1h92vCD8=";
|
||||||
|
};
|
||||||
config = {
|
config = {
|
||||||
MIPS_MALTA= "y";
|
MIPS_MALTA= "y";
|
||||||
CPU_MIPS32_R2= "y";
|
CPU_MIPS32_R2= "y";
|
||||||
|
|
||||||
POWER_RESET = "y";
|
MTD = "y";
|
||||||
POWER_RESET_SYSCON = "y";
|
MTD_BLOCK2MTD = "y";
|
||||||
|
MTD_BLOCK = "y";
|
||||||
|
|
||||||
|
VIRTIO_MENU = "y";
|
||||||
|
PCI = "y";
|
||||||
|
VIRTIO_PCI = "y";
|
||||||
|
BLOCK = "y";
|
||||||
|
VIRTIO_BLK = "y";
|
||||||
|
NETDEVICES = "y";
|
||||||
|
VIRTIO_NET = "y";
|
||||||
|
|
||||||
SERIAL_8250= "y";
|
SERIAL_8250= "y";
|
||||||
SERIAL_8250_CONSOLE= "y";
|
SERIAL_8250_CONSOLE= "y";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
hardware =
|
hardware =
|
||||||
# from arch/mips/mti-malta/Platform:load-$(CONFIG_MIPS_MALTA) += 0xffffffff80100000
|
let
|
||||||
let addr = lim.parseInt "0x80100000";
|
mac80211 = pkgs.mac80211.override {
|
||||||
in {
|
drivers = ["mac80211_hwsim"];
|
||||||
loadAddress = addr;
|
klibBuild = config.system.outputs.kernel.modulesupport;
|
||||||
entryPoint = addr;
|
|
||||||
|
|
||||||
# Unlike the arm qemu targets, we need a static dts when
|
|
||||||
# running u-boot-using tests, qemu dumpdtb command doesn't
|
|
||||||
# work for this board. I am not at all sure this dts is
|
|
||||||
# *correct* but it does at least boot
|
|
||||||
dts = lib.mkForce {
|
|
||||||
src = "${config.system.outputs.kernel.modulesupport}/arch/mips/boot/dts/mti/malta.dts";
|
|
||||||
includes = [
|
|
||||||
"${config.system.outputs.kernel.modulesupport}/arch/mips/boot/dts/"
|
|
||||||
];
|
|
||||||
};
|
};
|
||||||
|
in {
|
||||||
|
defaultOutput = "vmroot";
|
||||||
|
rootDevice = "/dev/mtdblock0";
|
||||||
|
flash.eraseBlockSize = "65536"; # c.f. pkgs/run-liminix-vm/run-liminix-vm.sh
|
||||||
|
networkInterfaces =
|
||||||
|
let inherit (config.system.service.network) link;
|
||||||
|
in {
|
||||||
|
wan = link.build { ifname = "eth0"; };
|
||||||
|
lan = link.build { ifname = "eth1"; };
|
||||||
|
|
||||||
|
wlan_24 = link.build {
|
||||||
|
ifname = "wlan0";
|
||||||
|
dependencies = [ mac80211 ];
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,238 +0,0 @@
|
|||||||
{
|
|
||||||
description = ''
|
|
||||||
Turris Omnia
|
|
||||||
************
|
|
||||||
'';
|
|
||||||
|
|
||||||
system = {
|
|
||||||
crossSystem = {
|
|
||||||
config = "armv7l-unknown-linux-musleabihf";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
module = {pkgs, config, lib, lim, ... }:
|
|
||||||
let
|
|
||||||
openwrt = pkgs.openwrt;
|
|
||||||
inherit (lib) mkOption types;
|
|
||||||
inherit (pkgs.liminix.services) oneshot;
|
|
||||||
inherit (pkgs) liminix;
|
|
||||||
mtd_by_name_links = pkgs.liminix.services.oneshot rec {
|
|
||||||
name = "mtd_by_name_links";
|
|
||||||
up = ''
|
|
||||||
mkdir -p /dev/mtd/by-name
|
|
||||||
cd /dev/mtd/by-name
|
|
||||||
for i in /sys/class/mtd/mtd*[0-9]; do
|
|
||||||
ln -s ../../$(basename $i) $(cat $i/name)
|
|
||||||
done
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
in {
|
|
||||||
imports = [
|
|
||||||
../../modules/arch/arm.nix
|
|
||||||
../../modules/outputs/tftpboot.nix
|
|
||||||
../../modules/outputs/ext4fs.nix
|
|
||||||
../../modules/outputs/mbrimage.nix
|
|
||||||
../../modules/outputs/extlinux.nix
|
|
||||||
];
|
|
||||||
|
|
||||||
config = {
|
|
||||||
services.mtd-name-links = mtd_by_name_links;
|
|
||||||
kernel = {
|
|
||||||
src = pkgs.pkgsBuildBuild.fetchurl {
|
|
||||||
name = "linux.tar.gz";
|
|
||||||
url = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.71.tar.gz";
|
|
||||||
hash = "sha256-yhO2cXIeIgUxkSZf/4aAsF11uxyh+UUZu6D1h92vCD8=";
|
|
||||||
};
|
|
||||||
extraPatchPhase = ''
|
|
||||||
${pkgs.openwrt.applyPatches.mvebu}
|
|
||||||
'';
|
|
||||||
config = {
|
|
||||||
PCI = "y";
|
|
||||||
OF = "y";
|
|
||||||
MEMORY = "y"; # for MVEBU_DEVBUS
|
|
||||||
DMADEVICES = "y"; # for MV_XOR
|
|
||||||
CPU_V7 = "y";
|
|
||||||
ARCH_MULTIPLATFORM = "y";
|
|
||||||
ARCH_MVEBU = "y";
|
|
||||||
ARCH_MULTI_V7= "y";
|
|
||||||
PCI_MVEBU = "y";
|
|
||||||
AHCI_MVEBU = "y";
|
|
||||||
MACH_ARMADA_38X = "y";
|
|
||||||
SMP = "y";
|
|
||||||
# this is disabled for the moment because it relies on a GCC
|
|
||||||
# plugin that requires gmp.h to build, and I can't see right now
|
|
||||||
# how to confgure it to find gmp
|
|
||||||
STACKPROTECTOR_PER_TASK = "n";
|
|
||||||
NR_CPUS = "4";
|
|
||||||
VFP = "y";
|
|
||||||
NEON= "y";
|
|
||||||
|
|
||||||
# WARNING: unmet direct dependencies detected for ARCH_WANT_LIBATA_LEDS
|
|
||||||
ATA = "y";
|
|
||||||
|
|
||||||
PSTORE = "y";
|
|
||||||
PSTORE_RAM = "y";
|
|
||||||
PSTORE_CONSOLE = "y";
|
|
||||||
PSTORE_DEFLATE_COMPRESS = "n";
|
|
||||||
|
|
||||||
BLOCK = "y";
|
|
||||||
MMC="y";
|
|
||||||
PWRSEQ_EMMC="y"; # ???
|
|
||||||
PWRSEQ_SIMPLE="y"; # ???
|
|
||||||
MMC_BLOCK="y";
|
|
||||||
|
|
||||||
MMC_SDHCI= "y";
|
|
||||||
MMC_SDHCI_PLTFM= "y";
|
|
||||||
MMC_SDHCI_PXAV3= "y";
|
|
||||||
MMC_MVSDIO= "y";
|
|
||||||
|
|
||||||
SERIAL_8250 = "y";
|
|
||||||
SERIAL_8250_CONSOLE = "y";
|
|
||||||
SERIAL_OF_PLATFORM="y";
|
|
||||||
SERIAL_MVEBU_UART = "y";
|
|
||||||
SERIAL_MVEBU_CONSOLE = "y";
|
|
||||||
|
|
||||||
SERIAL_8250_DMA= "y";
|
|
||||||
SERIAL_8250_DW= "y";
|
|
||||||
SERIAL_8250_EXTENDED= "y";
|
|
||||||
SERIAL_8250_MANY_PORTS= "y";
|
|
||||||
SERIAL_8250_SHARE_IRQ= "y";
|
|
||||||
OF_ADDRESS= "y";
|
|
||||||
OF_MDIO= "y";
|
|
||||||
|
|
||||||
WATCHDOG = "y"; # watchdog is enabled by u-boot
|
|
||||||
ORION_WATCHDOG = "y"; # so is non-optional to keep feeding
|
|
||||||
|
|
||||||
MVEBU_DEVBUS = "y"; # "Device Bus controller ... flash devices such as NOR, NAND, SRAM, and FPGA"
|
|
||||||
MVMDIO = "y";
|
|
||||||
MVNETA = "y";
|
|
||||||
MVNETA_BM = "y";
|
|
||||||
MVNETA_BM_ENABLE = "y";
|
|
||||||
SRAM = "y"; # mmio-sram is "compatible" for bm_bppi reqd by BM
|
|
||||||
PHY_MVEBU_A38X_COMPHY = "y"; # for eth2
|
|
||||||
|
|
||||||
MVPP2 = "y";
|
|
||||||
MV_XOR = "y";
|
|
||||||
|
|
||||||
# there is NOR flash on this device, which is used for U-Boot
|
|
||||||
# and the rescue system (which we don't interfere with) but
|
|
||||||
# also for the U-Boot environment variables (which we might
|
|
||||||
# need to meddle with)
|
|
||||||
MTD_SPI_NOR = "y";
|
|
||||||
SPI = "y";
|
|
||||||
SPI_MASTER = "y";
|
|
||||||
SPI_ORION = "y";
|
|
||||||
|
|
||||||
NET_DSA = "y";
|
|
||||||
NET_DSA_MV88E6XXX = "y"; # depends on PTP_1588_CLOCK_OPTIONAL
|
|
||||||
};
|
|
||||||
};
|
|
||||||
rootfsType = "ext4";
|
|
||||||
boot = {
|
|
||||||
commandLine = [
|
|
||||||
"console=ttyS0,115200"
|
|
||||||
"pcie_aspm=off" # ath9k pci incompatible with PCIe ASPM
|
|
||||||
];
|
|
||||||
imageFormat = "fit";
|
|
||||||
};
|
|
||||||
filesystem =
|
|
||||||
let
|
|
||||||
inherit (pkgs.pseudofile) dir symlink;
|
|
||||||
firmware = pkgs.stdenv.mkDerivation {
|
|
||||||
name = "wlan-firmware";
|
|
||||||
phases = ["installPhase"];
|
|
||||||
installPhase = ''
|
|
||||||
mkdir $out
|
|
||||||
cp -r ${pkgs.linux-firmware}/lib/firmware/ath10k/QCA988X $out
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
in dir {
|
|
||||||
lib = dir {
|
|
||||||
firmware = dir {
|
|
||||||
ath10k = symlink firmware;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
etc = dir {
|
|
||||||
"fw_env.config" =
|
|
||||||
let f = pkgs.writeText "fw_env.config" ''
|
|
||||||
/dev/mtd/by-name/u-boot-env 0x0 0x10000 0x10000
|
|
||||||
'';
|
|
||||||
in symlink f;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
boot.tftp = {
|
|
||||||
loadAddress = lim.parseInt "0x1000000";
|
|
||||||
kernelFormat = "zimage";
|
|
||||||
compressRoot = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
hardware = let
|
|
||||||
mac80211 = pkgs.mac80211.override {
|
|
||||||
drivers = ["ath9k_pci" "ath10k_pci"];
|
|
||||||
klibBuild = config.system.outputs.kernel.modulesupport;
|
|
||||||
};
|
|
||||||
in {
|
|
||||||
defaultOutput = "mtdimage";
|
|
||||||
loadAddress = lim.parseInt "0x00800000"; # "0x00008000";
|
|
||||||
entryPoint = lim.parseInt "0x00800000"; # "0x00008000";
|
|
||||||
rootDevice = "/dev/mtdblock0";
|
|
||||||
|
|
||||||
dts = {
|
|
||||||
src = "${config.system.outputs.kernel.modulesupport}/arch/arm/boot/dts/armada-385-turris-omnia.dts";
|
|
||||||
includes = [
|
|
||||||
"${config.system.outputs.kernel.modulesupport}/arch/arm/boot/dts/"
|
|
||||||
];
|
|
||||||
};
|
|
||||||
flash.eraseBlockSize = 65536; # only used for tftpboot
|
|
||||||
networkInterfaces =
|
|
||||||
let
|
|
||||||
inherit (config.system.service.network) link;
|
|
||||||
inherit (config.system.service) bridge;
|
|
||||||
in rec {
|
|
||||||
en70000 = link.build {
|
|
||||||
# in armada-38x.dtsi this is eth0.
|
|
||||||
# It's connected to port 5 of the 88E6176 switch
|
|
||||||
devpath = "/devices/platform/soc/soc:internal-regs/f1070000.ethernet";
|
|
||||||
# name is unambiguous but not very semantic
|
|
||||||
ifname = "en70000";
|
|
||||||
};
|
|
||||||
en30000 = link.build {
|
|
||||||
# in armada-38x.dtsi this is eth1
|
|
||||||
# It's connected to port 6 of the 88E6176 switch
|
|
||||||
devpath = "/devices/platform/soc/soc:internal-regs/f1030000.ethernet";
|
|
||||||
# name is unambiguous but not very semantic
|
|
||||||
ifname = "en30000";
|
|
||||||
};
|
|
||||||
# the default (from the dts? I'm guessing) behavour for
|
|
||||||
# lan ports on the switch is to attach them to
|
|
||||||
# en30000. It should be possible to do something better,
|
|
||||||
# per
|
|
||||||
# https://www.kernel.org/doc/html/latest/networking/dsa/configuration.html#affinity-of-user-ports-to-cpu-ports
|
|
||||||
# but apparently OpenWrt doesn't either so maybe it's more
|
|
||||||
# complicated than it looks
|
|
||||||
|
|
||||||
wan = link.build {
|
|
||||||
# in armada-38x.dtsi this is eth2. It may be connected to
|
|
||||||
# an ethernet phy or to the SFP cage, depending on a gpio
|
|
||||||
devpath = "/devices/platform/soc/soc:internal-regs/f1034000.ethernet";
|
|
||||||
ifname = "wan";
|
|
||||||
};
|
|
||||||
|
|
||||||
lan = link.build {
|
|
||||||
ifname = "lan1";
|
|
||||||
};
|
|
||||||
|
|
||||||
wlan = link.build {
|
|
||||||
ifname = "wlan0";
|
|
||||||
dependencies = [ mac80211 ];
|
|
||||||
};
|
|
||||||
wlan5 = link.build {
|
|
||||||
ifname = "wlan1";
|
|
||||||
dependencies = [ mac80211 ];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
@ -117,7 +117,7 @@ If you are prepared to open the device and have a TTL serial adaptor
|
|||||||
of some kind to connect it to, you can probably use U-Boot and a TFTP
|
of some kind to connect it to, you can probably use U-Boot and a TFTP
|
||||||
server to download and flash the image. This is quite
|
server to download and flash the image. This is quite
|
||||||
hardware-specific, and sometimes involves soldering: please refer
|
hardware-specific, and sometimes involves soldering: please refer
|
||||||
to :ref:`serial`.
|
to the :ref:`development manual <tftp server>`.
|
||||||
|
|
||||||
|
|
||||||
Flashing from OpenWrt
|
Flashing from OpenWrt
|
||||||
|
@ -27,16 +27,19 @@ To build it,
|
|||||||
|
|
||||||
nix-build -I liminix-config=path/to/your/configuration.nix --arg device "import ./devices/qemu" -A outputs.default
|
nix-build -I liminix-config=path/to/your/configuration.nix --arg device "import ./devices/qemu" -A outputs.default
|
||||||
|
|
||||||
This creates a :file:`result/` directory containing a :file:`vmlinux`
|
In a ``buildEnv`` nix-shell, you can use the :command:`run-liminix-vm` command
|
||||||
and a :file:`rootfs`, and also a shell script :file:`run.sh` which
|
to run Qemu with appropriate options. It connects the Liminix
|
||||||
invokes QEMU to run that kernel with that filesystem. It connects the Liminix
|
|
||||||
serial console and the `QEMU monitor <https://www.qemu.org/docs/master/system/monitor.html>`_ to stdin/stdout. Use ^P (not ^A) to switch to the monitor.
|
serial console and the `QEMU monitor <https://www.qemu.org/docs/master/system/monitor.html>`_ to stdin/stdout. Use ^P (not ^A) to switch to the monitor.
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
nix-shell --run "run-liminix-vm result/vmlinux result/squashfs"
|
||||||
|
|
||||||
If you run with ``--background /path/to/some/directory`` as the first
|
If you run with ``--background /path/to/some/directory`` as the first
|
||||||
parameter, it will fork into the background and open Unix sockets in
|
parameter, it will fork into the background and open Unix sockets in
|
||||||
that directory for console and monitor. Use :command:`nix-shell --run
|
that directory for console and monitor. Use :command:`connect-vm`
|
||||||
connect-vm` to connect to either of these sockets, and ^O to
|
(also in the ``buildEnv`` environment) to connect to either of these
|
||||||
disconnect.
|
sockets, and ^O to disconnect.
|
||||||
|
|
||||||
.. _qemu-networking:
|
.. _qemu-networking:
|
||||||
|
|
||||||
@ -52,11 +55,9 @@ the right way:
|
|||||||
* multicast 230.0.0.1:1235 : lan
|
* multicast 230.0.0.1:1235 : lan
|
||||||
* multicast 230.0.0.1:1236 : world (the internet)
|
* multicast 230.0.0.1:1236 : world (the internet)
|
||||||
|
|
||||||
Any VM started by a :command:`run.sh` script is connected to "lan" and
|
A VM started with :command:`run-liminix-vm` is connected to "lan" and "access", and
|
||||||
"access", and the emulated border network gateway (see below) runs
|
the emulated border network gateway (see below) runs PPPoE and is
|
||||||
PPPoE and is connected to "access" and "world".
|
connected to "access" and "world".
|
||||||
|
|
||||||
.. _border-network-gateway:
|
|
||||||
|
|
||||||
Border Network Gateway
|
Border Network Gateway
|
||||||
----------------------
|
----------------------
|
||||||
@ -88,68 +89,6 @@ time with configurations for RP-PPPoE and/or Accel PPP.`
|
|||||||
Hardware devices
|
Hardware devices
|
||||||
****************
|
****************
|
||||||
|
|
||||||
.. _serial:
|
|
||||||
|
|
||||||
U-Boot and serial shenanigans
|
|
||||||
=============================
|
|
||||||
|
|
||||||
Every device that we have so far encountered in Liminix uses `U-Boot,
|
|
||||||
the "Universal Boot Loader" <https://docs.u-boot.org/en/latest/>`_ so
|
|
||||||
it's worth knowing a bit about it. "Universal" is in this context a
|
|
||||||
bit of a misnomer, though: encountering *mainline* U-Boot is very rare
|
|
||||||
and often you'll find it is a fork from some version last updated
|
|
||||||
in 2008. Upgrading U-Boot is more or less complicated depending on the
|
|
||||||
device and is outside scope for Liminix.
|
|
||||||
|
|
||||||
To speak to U-Boot on your device you'll usually need a serial
|
|
||||||
connection to it. This is device-specific. Usually it involves
|
|
||||||
opening the box, locating the serial header pins (TX, RX and GND) and
|
|
||||||
connecting a USB TTL converter to them.
|
|
||||||
|
|
||||||
The Rolls Royce of USB/UART cables is the `FTDI cable
|
|
||||||
<https://cpc.farnell.com/ftdi/ttl-232r-rpi/cable-debug-ttl-232-usb-rpi/dp/SC12825?st=usb%20to%20uart%20cable>`_,
|
|
||||||
but there are cheaper alternatives based on the PL2303 and CP2102 chipsets. Or
|
|
||||||
get creative and use the `UART GPIO pins <https://pinout.xyz/>`_ on a Raspberry Pi. Whatever you do, make sure
|
|
||||||
that the voltages are compatible: if your device is 3.3V (this is
|
|
||||||
typical but not universal), you don't want to be sending it 5v or
|
|
||||||
(even worse) 12v.
|
|
||||||
|
|
||||||
Run a terminal emulator such as Minicom on the computer at other end
|
|
||||||
of the link. 115200 8N1 is the typical speed.
|
|
||||||
|
|
||||||
.. NOTE::
|
|
||||||
|
|
||||||
TTL serial connections typically have no form of flow control and
|
|
||||||
so don't always like having massive chunks of text pasted into
|
|
||||||
them - and U-Boot may drop characters while it's busy. So don't
|
|
||||||
necessarily expect to copy-paste large chunks of text into the
|
|
||||||
terminal emulator and have it work just like that.
|
|
||||||
|
|
||||||
If using Minicom, you may find it helps to bring up the "Termimal
|
|
||||||
settings" dialog (C^A T), then configure "Newline tx delay" to
|
|
||||||
some small but non-zero value.
|
|
||||||
|
|
||||||
When you turn the router on you should be greeted with some messages
|
|
||||||
from U-Boot, followed by the instruction to hit some key to stop
|
|
||||||
autoboot. Do this and you will get to the prompt. If you didn't see
|
|
||||||
anything, the strong likelihood is that TX and RX are the wrong way
|
|
||||||
around. If you see garbage, try a different speed.
|
|
||||||
|
|
||||||
Interesting commands to try first in U-Boot are :command:`help` and
|
|
||||||
:command:`printenv`.
|
|
||||||
|
|
||||||
To do anything useful with U-Boot you will probably need a way to get
|
|
||||||
large binary files onto the device, and the usual way to do this is by
|
|
||||||
adding a network connection and using TFTP to download them. It's
|
|
||||||
quite common that the device's U-Boot doesn't speak DHCP so it will
|
|
||||||
need a static LAN address. You might also want to keep it away from
|
|
||||||
your "real" LAN: see :ref:`bng` for some potentially useful tooling
|
|
||||||
to use it on an isolated network.
|
|
||||||
|
|
||||||
|
|
||||||
TFTP
|
|
||||||
====
|
|
||||||
|
|
||||||
.. _tftp server:
|
.. _tftp server:
|
||||||
|
|
||||||
How you get your image onto hardware will vary according to the
|
How you get your image onto hardware will vary according to the
|
||||||
@ -180,7 +119,7 @@ Now add the device and server IP addresses to your configuration:
|
|||||||
};
|
};
|
||||||
|
|
||||||
and then build the derivation for ``outputs.default`` or
|
and then build the derivation for ``outputs.default`` or
|
||||||
``outputs.mtdimage`` (for which it will be an alias on any device
|
``outputs.flashimage`` (for which it will be an alias on any device
|
||||||
where this is applicable). You should find it has created
|
where this is applicable). You should find it has created
|
||||||
|
|
||||||
* :file:`result/firmware.bin` which is the file you are going to flash
|
* :file:`result/firmware.bin` which is the file you are going to flash
|
||||||
@ -213,8 +152,6 @@ U-Boot to transfer the kernel and filesystem over TFTP and boot the
|
|||||||
kernel from RAM.
|
kernel from RAM.
|
||||||
|
|
||||||
|
|
||||||
.. _bng:
|
|
||||||
|
|
||||||
Networking
|
Networking
|
||||||
==========
|
==========
|
||||||
|
|
||||||
|
@ -1,10 +1,31 @@
|
|||||||
{ eval, lib, pkgs }:
|
|
||||||
let
|
let
|
||||||
|
overlay = import ../overlay.nix;
|
||||||
|
pkgs = import <nixpkgs> ( {
|
||||||
|
overlays = [overlay];
|
||||||
|
config = {
|
||||||
|
allowUnsupportedSystem = true; # mipsel
|
||||||
|
permittedInsecurePackages = [
|
||||||
|
"python-2.7.18.6" # kernel backports needs python <3
|
||||||
|
];
|
||||||
|
};
|
||||||
|
});
|
||||||
|
inherit (pkgs) lib;
|
||||||
inherit (lib) types;
|
inherit (lib) types;
|
||||||
|
modulenames =
|
||||||
|
builtins.attrNames
|
||||||
|
(lib.filterAttrsRecursive
|
||||||
|
(n: t:
|
||||||
|
(n != "arch") &&
|
||||||
|
((t=="directory") ||
|
||||||
|
((t=="regular") && ((builtins.match ".*\\.nix$" n) != null))))
|
||||||
|
(builtins.readDir ../modules));
|
||||||
|
modulefiles = builtins.map (n: builtins.toPath "${../modules}/${n}") modulenames;
|
||||||
|
eval = (lib.evalModules {
|
||||||
|
modules = [
|
||||||
|
{ _module.args = { inherit pkgs; lib = pkgs.lib; }; }
|
||||||
|
] ++ modulefiles;
|
||||||
|
});
|
||||||
conf = eval.config;
|
conf = eval.config;
|
||||||
rootDir = builtins.toPath ./..;
|
|
||||||
stripAnyPrefixes = lib.flip (lib.fold lib.removePrefix)
|
|
||||||
["${rootDir}/"];
|
|
||||||
optToDoc = name: opt : {
|
optToDoc = name: opt : {
|
||||||
inherit name;
|
inherit name;
|
||||||
description = opt.description or null;
|
description = opt.description or null;
|
||||||
@ -21,12 +42,16 @@ let
|
|||||||
then
|
then
|
||||||
let sd = lib.attrByPath item.loc ["not found"] conf;
|
let sd = lib.attrByPath item.loc ["not found"] conf;
|
||||||
in item // {
|
in item // {
|
||||||
declarations = map stripAnyPrefixes item.declarations;
|
|
||||||
parameters =
|
parameters =
|
||||||
let x = lib.mapAttrsToList optToDoc sd.parameters; in x;
|
let x = lib.mapAttrsToList optToDoc sd.parameters; in x;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
item // { declarations = map stripAnyPrefixes item.declarations; };
|
item;
|
||||||
in
|
o = builtins.map spliceServiceDefn
|
||||||
builtins.map spliceServiceDefn
|
(pkgs.lib.optionAttrSetToDocList eval.options);
|
||||||
(pkgs.lib.optionAttrSetToDocList eval.options)
|
in {
|
||||||
|
doc = pkgs.writeText "options.yaml" ''
|
||||||
|
# ${./..}
|
||||||
|
${builtins.toJSON o}
|
||||||
|
'';
|
||||||
|
}
|
||||||
|
@ -1,23 +1,12 @@
|
|||||||
with import <nixpkgs> {} ;
|
with import <nixpkgs> {} ;
|
||||||
|
|
||||||
let
|
let
|
||||||
inherit (builtins) stringLength readDir filter;
|
devices =
|
||||||
devices = filter (n: n != "families")
|
builtins.readDir ../devices;
|
||||||
(lib.mapAttrsToList (n: t: n) (readDir ../devices));
|
texts = lib.mapAttrsToList (n: t:
|
||||||
texts = map (n:
|
|
||||||
let d = import ../devices/${n}/default.nix;
|
let d = import ../devices/${n}/default.nix;
|
||||||
d' = {
|
d' = { description = "no description for ${n}"; } // d;
|
||||||
description = "${n}\n${substring 0 (stringLength n) "********************************"}\n";
|
in d'.description )
|
||||||
} // d;
|
|
||||||
installer =
|
|
||||||
if d ? description && d ? installer
|
|
||||||
then ''
|
|
||||||
|
|
||||||
The default installation route for this device is
|
|
||||||
:ref:`system-outputs-${d.installer}`
|
|
||||||
''
|
|
||||||
else "";
|
|
||||||
in d'.description)
|
|
||||||
devices;
|
devices;
|
||||||
in
|
in
|
||||||
writeText "hwdoc" ''
|
writeText "hwdoc" ''
|
||||||
|
@ -12,7 +12,6 @@ Liminix
|
|||||||
development
|
development
|
||||||
modules
|
modules
|
||||||
hardware
|
hardware
|
||||||
outputs
|
|
||||||
|
|
||||||
|
|
||||||
Indices and tables
|
Indices and tables
|
||||||
|
@ -1,13 +0,0 @@
|
|||||||
Outputs
|
|
||||||
#######
|
|
||||||
|
|
||||||
Liminix *outputs* are artefacts that can be installed somehow on a
|
|
||||||
target device, or "installers" which run on the target device to
|
|
||||||
perform the installation.
|
|
||||||
|
|
||||||
There are different outputs because different target devices need
|
|
||||||
different artefacts, or have different ways to get that artefact
|
|
||||||
installed. The options available for a particular device are described in
|
|
||||||
the section for that device.
|
|
||||||
|
|
||||||
.. include:: outputs-generated.rst
|
|
@ -1,19 +0,0 @@
|
|||||||
(local yaml (require :lyaml))
|
|
||||||
|
|
||||||
;; (local { : view } (require :fennel))
|
|
||||||
|
|
||||||
(fn output? [option]
|
|
||||||
(match option.loc
|
|
||||||
["system" "outputs" & _] true
|
|
||||||
_ false))
|
|
||||||
|
|
||||||
(fn sorted-options [options]
|
|
||||||
(table.sort
|
|
||||||
options
|
|
||||||
(fn [a b] (< a.name b.name)))
|
|
||||||
options)
|
|
||||||
|
|
||||||
(each [_ option (ipairs (sorted-options (yaml.load (io.read "*a"))))]
|
|
||||||
(when (and (output? option) (not option.internal))
|
|
||||||
(print (.. ".. _" (string.gsub option.name "%." "-") ":") "\n")
|
|
||||||
(print option.description)))
|
|
@ -2,25 +2,21 @@
|
|||||||
|
|
||||||
(local { : view } (require :fennel))
|
(local { : view } (require :fennel))
|
||||||
|
|
||||||
(fn basename [str ext]
|
|
||||||
(-> str
|
|
||||||
(string.gsub "(.*/)(.*)" "%2")
|
|
||||||
(string.gsub (.. ext "$") "")))
|
|
||||||
|
|
||||||
(fn headline [name]
|
(fn headline [name]
|
||||||
(let [title (assert (basename name ".nix"))
|
(let [(_ _ basename) (string.find name ".*/([^/].*).nix")
|
||||||
len (title:len)]
|
len (basename:len)]
|
||||||
(.. title "\n" (string.rep "=" len))))
|
(.. basename "\n" (string.rep "=" len))))
|
||||||
|
|
||||||
(fn read-preamble [pathname]
|
(fn read-preamble [pathname]
|
||||||
(let [pathname (if (string.match pathname ".nix$")
|
(if (= (pathname:sub 1 1) "/")
|
||||||
pathname
|
(let [pathname (if (string.match pathname ".nix$")
|
||||||
(.. pathname "/default.nix"))]
|
pathname
|
||||||
(with-open [f (assert (io.open pathname :r))]
|
(.. pathname "/default.nix"))]
|
||||||
(accumulate [lines nil
|
(with-open [f (assert (io.open pathname :r))]
|
||||||
l (f:lines)
|
(accumulate [lines nil
|
||||||
:until (not (= (string.sub l 1 2) "##"))]
|
l (f:lines)
|
||||||
(.. (or lines "") (string.gsub l "^## *" "") "\n")))))
|
:until (not (= (string.sub l 1 2) "##"))]
|
||||||
|
(.. (or lines "") (string.gsub l "^## *" "") "\n"))))))
|
||||||
|
|
||||||
(fn relative-pathname [pathname]
|
(fn relative-pathname [pathname]
|
||||||
(let [pathname
|
(let [pathname
|
||||||
|
@ -69,11 +69,10 @@ device's serial console and the `QEMU monitor
|
|||||||
stdin/stdout.
|
stdin/stdout.
|
||||||
|
|
||||||
You should now see Linux boot messages and after a few seconds be
|
You should now see Linux boot messages and after a few seconds be
|
||||||
presented with a root shell prompt. You can run commands to look at
|
presented with a login prompt. You can login on the console as
|
||||||
the filesystem, see what processes are running, view log messages (in
|
``root`` (password is "secret") and poke around to see what processes are
|
||||||
:file:/run/uncaught-logs.current), etc. To kill the emulator, press ^P
|
running. To kill the emulator, press ^P (Control P) then c to enter the
|
||||||
(Control P) then c to enter the "QEMU Monitor", then type ``quit`` at
|
"QEMU Monitor", then type ``quit`` at the ``(qemu)`` prompt.
|
||||||
the ``(qemu)`` prompt.
|
|
||||||
|
|
||||||
To see that it's running network services we need to connect to its
|
To see that it's running network services we need to connect to its
|
||||||
emulated network. Start the machine again, if you had stopped it, and
|
emulated network. Start the machine again, if you had stopped it, and
|
||||||
@ -138,12 +137,20 @@ unbrick if necessary.
|
|||||||
work here, but you accept the slightly greater bricking
|
work here, but you accept the slightly greater bricking
|
||||||
risk if it doesn't.
|
risk if it doesn't.
|
||||||
|
|
||||||
You may want to read and inwardly digest the Develoment Manual section
|
You may want to acquire a `USB TTL serial cable
|
||||||
:ref:`serial` when you start working with Liminix on real hardware. You
|
<https://cpc.farnell.com/ftdi/ttl-232r-rpi/cable-debug-ttl-232-usb-rpi/dp/SC12825?st=usb%20to%20uart%20cable>`_
|
||||||
won't *need* serial access for this example, assuming it works, but it
|
when you start working with Liminix on real hardware. You
|
||||||
|
won't *need* it for this example, assuming it works, but it
|
||||||
allows you
|
allows you
|
||||||
to see the boot monitor and kernel messages, and to login directly to
|
to see the boot monitor and kernel messages, and to login directly to
|
||||||
the device if for some reason it doesn't bring its network up.
|
the device if for some reason it doesn't bring its network up. You have options
|
||||||
|
here: the FTDI-based cables are the Rolls Royce of serial cables,
|
||||||
|
whereas the ones based on PL2303 and CP2102 chipsets are cheaper but
|
||||||
|
also fussier - or you could even get creative and use e.g. a
|
||||||
|
`Raspberry Pi <https://pinout.xyz/#>`_ or other SBC with a UART and
|
||||||
|
TX/RX/GND header pins. Make sure that the voltages are compatible:
|
||||||
|
this is a 3.3v device and you don't want to be sending it 5v or (even
|
||||||
|
worse) 12v.
|
||||||
|
|
||||||
Now we can build Liminix. Although we could use the same example
|
Now we can build Liminix. Although we could use the same example
|
||||||
configuration as we did for Qemu, you might not want to plug a DHCP
|
configuration as we did for Qemu, you might not want to plug a DHCP
|
||||||
|
@ -24,6 +24,7 @@ in rec {
|
|||||||
};
|
};
|
||||||
|
|
||||||
imports = [
|
imports = [
|
||||||
|
../modules/standard.nix
|
||||||
../modules/wlan.nix
|
../modules/wlan.nix
|
||||||
../modules/network
|
../modules/network
|
||||||
../modules/vlan
|
../modules/vlan
|
||||||
@ -31,6 +32,7 @@ in rec {
|
|||||||
../modules/watchdog
|
../modules/watchdog
|
||||||
../modules/mount
|
../modules/mount
|
||||||
];
|
];
|
||||||
|
|
||||||
hostname = "arhcive";
|
hostname = "arhcive";
|
||||||
|
|
||||||
kernel = {
|
kernel = {
|
||||||
|
@ -33,6 +33,7 @@ in rec {
|
|||||||
../modules/ntp
|
../modules/ntp
|
||||||
../modules/ppp
|
../modules/ppp
|
||||||
../modules/ssh
|
../modules/ssh
|
||||||
|
../modules/standard.nix
|
||||||
../modules/vlan
|
../modules/vlan
|
||||||
../modules/wlan.nix
|
../modules/wlan.nix
|
||||||
];
|
];
|
||||||
|
@ -30,6 +30,7 @@ in rec {
|
|||||||
../modules/hostapd
|
../modules/hostapd
|
||||||
../modules/bridge
|
../modules/bridge
|
||||||
../modules/ssh
|
../modules/ssh
|
||||||
|
../modules/standard.nix
|
||||||
];
|
];
|
||||||
|
|
||||||
hostname = "extneder";
|
hostname = "extneder";
|
||||||
|
@ -8,6 +8,7 @@ in rec {
|
|||||||
../modules/network
|
../modules/network
|
||||||
../modules/ssh
|
../modules/ssh
|
||||||
../modules/vlan
|
../modules/vlan
|
||||||
|
../modules/flashimage.nix
|
||||||
];
|
];
|
||||||
|
|
||||||
boot.tftp = {
|
boot.tftp = {
|
||||||
|
@ -34,6 +34,7 @@ in rec {
|
|||||||
|
|
||||||
imports = [
|
imports = [
|
||||||
../modules/wlan.nix
|
../modules/wlan.nix
|
||||||
|
../modules/standard.nix
|
||||||
../modules/network
|
../modules/network
|
||||||
../modules/ppp
|
../modules/ppp
|
||||||
../modules/dnsmasq
|
../modules/dnsmasq
|
||||||
@ -44,6 +45,7 @@ in rec {
|
|||||||
../modules/ntp
|
../modules/ntp
|
||||||
../modules/ssh
|
../modules/ssh
|
||||||
];
|
];
|
||||||
|
rootfsType = "jffs2";
|
||||||
hostname = "rotuer";
|
hostname = "rotuer";
|
||||||
|
|
||||||
services.hostap = svc.hostapd.build {
|
services.hostap = svc.hostapd.build {
|
||||||
@ -181,8 +183,4 @@ in rec {
|
|||||||
defaultProfile.packages = with pkgs; [
|
defaultProfile.packages = with pkgs; [
|
||||||
min-collect-garbage
|
min-collect-garbage
|
||||||
];
|
];
|
||||||
|
|
||||||
programs.busybox.applets = [
|
|
||||||
"fdisk" "sfdisk"
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
@ -1,109 +0,0 @@
|
|||||||
{ config, pkgs, lib, lim, ... } :
|
|
||||||
let
|
|
||||||
inherit (pkgs) serviceFns;
|
|
||||||
svc = config.system.service;
|
|
||||||
|
|
||||||
in rec {
|
|
||||||
imports = [
|
|
||||||
../modules/network
|
|
||||||
../modules/ssh
|
|
||||||
../modules/vlan
|
|
||||||
../modules/wlan.nix
|
|
||||||
../modules/hostapd
|
|
||||||
../modules/bridge
|
|
||||||
|
|
||||||
../modules/ext4fs.nix
|
|
||||||
../modules/tftpboot.nix
|
|
||||||
];
|
|
||||||
|
|
||||||
rootfsType = "ext4";
|
|
||||||
|
|
||||||
boot.tftp = {
|
|
||||||
# IP addresses to use in the boot monitor when flashing/ booting
|
|
||||||
# over TFTP. If you are flashing using the stock firmware's Web UI
|
|
||||||
# then these dummy values are fine
|
|
||||||
ipaddr = "10.0.0.8"; # my address
|
|
||||||
serverip = "10.0.0.1"; # build machine or other tftp server
|
|
||||||
loadAddress = lim.parseInt "0x40000800";
|
|
||||||
};
|
|
||||||
|
|
||||||
hostname = "omnia";
|
|
||||||
|
|
||||||
services.hostap =
|
|
||||||
let secrets = {
|
|
||||||
ssid = "not-the-internet";
|
|
||||||
channel = 4;
|
|
||||||
wpa_passphrase = "diamond dogs";
|
|
||||||
};
|
|
||||||
in svc.hostapd.build {
|
|
||||||
interface = config.hardware.networkInterfaces.wlan;
|
|
||||||
params = {
|
|
||||||
country_code = "GB";
|
|
||||||
hw_mode = "g";
|
|
||||||
wmm_enabled = 1;
|
|
||||||
ieee80211n = 1;
|
|
||||||
inherit (secrets) ssid channel wpa_passphrase;
|
|
||||||
auth_algs = 1; # 1=wpa2, 2=wep, 3=both
|
|
||||||
wpa = 2; # 1=wpa, 2=wpa2, 3=both
|
|
||||||
wpa_key_mgmt = "WPA-PSK";
|
|
||||||
wpa_pairwise = "TKIP CCMP"; # auth for wpa (may not need this?)
|
|
||||||
rsn_pairwise = "CCMP"; # auth for wpa2
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
services.hostap5 =
|
|
||||||
let secrets = {
|
|
||||||
ssid = "not-the-internet";
|
|
||||||
channel = 36;
|
|
||||||
wpa_passphrase = "diamond dogs";
|
|
||||||
};
|
|
||||||
in svc.hostapd.build {
|
|
||||||
interface = config.hardware.networkInterfaces.wlan5;
|
|
||||||
params = {
|
|
||||||
country_code = "GB";
|
|
||||||
hw_mode = "a";
|
|
||||||
|
|
||||||
ht_capab = "[HT40+]";
|
|
||||||
vht_oper_chwidth = 1;
|
|
||||||
vht_oper_centr_freq_seg0_idx = secrets.channel + 6;
|
|
||||||
ieee80211ac = 1;
|
|
||||||
|
|
||||||
wmm_enabled = 1;
|
|
||||||
inherit (secrets) ssid channel wpa_passphrase;
|
|
||||||
auth_algs = 1; # 1=wpa2, 2=wep, 3=both
|
|
||||||
wpa = 2; # 1=wpa, 2=wpa2, 3=both
|
|
||||||
wpa_key_mgmt = "WPA-PSK";
|
|
||||||
wpa_pairwise = "TKIP CCMP"; # auth for wpa (may not need this?)
|
|
||||||
rsn_pairwise = "CCMP"; # auth for wpa2
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
services.int = svc.bridge.primary.build {
|
|
||||||
ifname = "int";
|
|
||||||
};
|
|
||||||
|
|
||||||
services.dhcpc = svc.network.dhcp.client.build {
|
|
||||||
interface = services.int;
|
|
||||||
dependencies = [ config.services.hostname ];
|
|
||||||
};
|
|
||||||
|
|
||||||
services.bridge = svc.bridge.members.build {
|
|
||||||
primary = services.int;
|
|
||||||
members = with config.hardware.networkInterfaces; [
|
|
||||||
lan
|
|
||||||
wlan
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
services.sshd = svc.ssh.build { };
|
|
||||||
|
|
||||||
users.root = {
|
|
||||||
# the password is "secret". Use mkpasswd -m sha512crypt to
|
|
||||||
# create this hashed password string
|
|
||||||
passwd = "$6$y7WZ5hM6l5nriLmo$5AJlmzQZ6WA.7uBC7S8L4o19ESR28Dg25v64/vDvvCN01Ms9QoHeGByj8lGlJ4/b.dbwR9Hq2KXurSnLigt1W1";
|
|
||||||
};
|
|
||||||
|
|
||||||
defaultProfile.packages = with pkgs; [
|
|
||||||
figlet pciutils
|
|
||||||
];
|
|
||||||
}
|
|
@ -1,39 +0,0 @@
|
|||||||
# Import all of the modules, used in the documentation generator. Not
|
|
||||||
# currently expected to work in an actual configuration, but it would
|
|
||||||
# be nice if it did.
|
|
||||||
|
|
||||||
{
|
|
||||||
imports = [
|
|
||||||
./base.nix
|
|
||||||
./bridge
|
|
||||||
./busybox.nix
|
|
||||||
./dhcp6c
|
|
||||||
./dnsmasq
|
|
||||||
./outputs/ext4fs.nix
|
|
||||||
./firewall
|
|
||||||
./hardware.nix
|
|
||||||
./hostapd
|
|
||||||
./hostname.nix
|
|
||||||
./outputs/initramfs.nix
|
|
||||||
./outputs/jffs2.nix
|
|
||||||
./kernel.nix
|
|
||||||
./outputs/kexecboot.nix
|
|
||||||
./mount
|
|
||||||
./network
|
|
||||||
./ntp
|
|
||||||
./outputs.nix
|
|
||||||
./outputs/vmroot.nix
|
|
||||||
./outputs/ubimage.nix
|
|
||||||
./outputs/mtdimage.nix
|
|
||||||
./ppp
|
|
||||||
./ramdisk.nix
|
|
||||||
./squashfs.nix
|
|
||||||
./ssh
|
|
||||||
./outputs/tftpboot.nix
|
|
||||||
./outputs/ubifs.nix
|
|
||||||
./users.nix
|
|
||||||
./vlan
|
|
||||||
./watchdog
|
|
||||||
./wlan.nix
|
|
||||||
];
|
|
||||||
}
|
|
@ -1,4 +1,4 @@
|
|||||||
{ lib, lim, pkgs, config, ...}:
|
{ lib, pkgs, config, ...}:
|
||||||
{
|
{
|
||||||
config = {
|
config = {
|
||||||
kernel.config = {
|
kernel.config = {
|
||||||
@ -12,7 +12,5 @@
|
|||||||
OF = "y";
|
OF = "y";
|
||||||
# USE_OF = "y";
|
# USE_OF = "y";
|
||||||
};
|
};
|
||||||
hardware.ram.startAddress = lim.parseInt "0x40000000";
|
|
||||||
system.outputs.u-boot = pkgs.ubootQemuAarch64;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,11 +0,0 @@
|
|||||||
{ lib, lim, pkgs, config, ...}:
|
|
||||||
{
|
|
||||||
config = {
|
|
||||||
kernel.config = {
|
|
||||||
OF = "y";
|
|
||||||
};
|
|
||||||
kernel.makeTargets = ["arch/arm/boot/zImage"];
|
|
||||||
hardware.ram.startAddress = lim.parseInt "0x40000000";
|
|
||||||
system.outputs.u-boot = pkgs.ubootQemuArm;
|
|
||||||
};
|
|
||||||
}
|
|
@ -1,4 +1,4 @@
|
|||||||
{ lib, pkgs, config, lim, ...}:
|
{ lib, pkgs, config, ...}:
|
||||||
{
|
{
|
||||||
config = {
|
config = {
|
||||||
kernel.config = {
|
kernel.config = {
|
||||||
@ -10,7 +10,6 @@
|
|||||||
OF = "y";
|
OF = "y";
|
||||||
USE_OF = "y";
|
USE_OF = "y";
|
||||||
};
|
};
|
||||||
hardware.ram.startAddress = lim.parseInt "0x80000000";
|
|
||||||
boot.commandLine = [
|
boot.commandLine = [
|
||||||
"console=ttyS0,115200" # true of all mips we've yet encountered
|
"console=ttyS0,115200" # true of all mips we've yet encountered
|
||||||
];
|
];
|
||||||
|
@ -5,6 +5,5 @@
|
|||||||
kernel.config = {
|
kernel.config = {
|
||||||
CPU_BIG_ENDIAN = "y";
|
CPU_BIG_ENDIAN = "y";
|
||||||
};
|
};
|
||||||
system.outputs.u-boot = pkgs.ubootQemuMips;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -39,12 +39,7 @@ in {
|
|||||||
};
|
};
|
||||||
rootfsType = mkOption {
|
rootfsType = mkOption {
|
||||||
default = "squashfs";
|
default = "squashfs";
|
||||||
type = types.enum [
|
type = types.enum ["squashfs" "jffs2"];
|
||||||
"ext4"
|
|
||||||
"jffs2"
|
|
||||||
"squashfs"
|
|
||||||
"ubifs"
|
|
||||||
];
|
|
||||||
};
|
};
|
||||||
boot = {
|
boot = {
|
||||||
commandLine = mkOption {
|
commandLine = mkOption {
|
||||||
@ -52,13 +47,9 @@ in {
|
|||||||
default = [];
|
default = [];
|
||||||
description = "Kernel command line";
|
description = "Kernel command line";
|
||||||
};
|
};
|
||||||
imageFormat = mkOption {
|
|
||||||
type = types.enum ["fit" "uimage"];
|
|
||||||
default = "uimage";
|
|
||||||
};
|
|
||||||
tftp = {
|
tftp = {
|
||||||
loadAddress = mkOption {
|
loadAddress = mkOption {
|
||||||
type = types.ints.unsigned;
|
type = types.str;
|
||||||
description = ''
|
description = ''
|
||||||
RAM address at which to load data when transferring via
|
RAM address at which to load data when transferring via
|
||||||
TFTP. This is not the address of the flash storage,
|
TFTP. This is not the address of the flash storage,
|
||||||
|
@ -11,7 +11,7 @@ in {
|
|||||||
options.system.outputs = {
|
options.system.outputs = {
|
||||||
firmware = mkOption {
|
firmware = mkOption {
|
||||||
type = types.package;
|
type = types.package;
|
||||||
internal = true; # component of mtdimage
|
internal = true; # component of flashimage
|
||||||
description = ''
|
description = ''
|
||||||
Binary image (combining kernel, FDT, rootfs, initramfs
|
Binary image (combining kernel, FDT, rootfs, initramfs
|
||||||
if needed, etc) for the target device.
|
if needed, etc) for the target device.
|
||||||
@ -19,40 +19,17 @@ in {
|
|||||||
};
|
};
|
||||||
flash-scr = mkOption {
|
flash-scr = mkOption {
|
||||||
type = types.package;
|
type = types.package;
|
||||||
internal = true; # component of mtdimage
|
internal = true; # component of flashimage
|
||||||
description = ''
|
description = ''
|
||||||
Copy-pastable U-Boot commands to TFTP download the
|
Copy-pastable U-Boot commands to TFTP download the
|
||||||
image and write it to flash
|
image and write it to flash
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
mtdimage = mkOption {
|
flashimage = mkOption {
|
||||||
type = types.package;
|
type = types.package;
|
||||||
description = ''
|
description = ''
|
||||||
mtdimage
|
Flashable image for the target device, and the script to
|
||||||
**********
|
install it
|
||||||
|
|
||||||
This creates an image called :file:`firmware.bin` suitable for
|
|
||||||
squashfs or jffs2 systems. It can be flashed from U-Boot (if
|
|
||||||
you have a serial console connection), or on some devices from
|
|
||||||
the vendor firmware, or from a Liminix kexecboot system.
|
|
||||||
|
|
||||||
If you are flashing from U-Boot, the file
|
|
||||||
:file:`flash.scr` is a sequence of commands
|
|
||||||
which you can paste at the U-Boot prompt to
|
|
||||||
to transfer the firmware file from a TFTP server and
|
|
||||||
write it to flash. **Please read the script before
|
|
||||||
running it: flash operations carry the potential to
|
|
||||||
brick your device**
|
|
||||||
|
|
||||||
.. NOTE::
|
|
||||||
|
|
||||||
TTL serial connections typically have no form of flow
|
|
||||||
control and so don't always like having massive chunks of
|
|
||||||
text pasted into them - and U-Boot may drop characters
|
|
||||||
while it's busy. So don't necessarily expect to copy-paste
|
|
||||||
the whole of :file:`flash.scr` into a terminal emulator and
|
|
||||||
have it work just like that. You may need to paste each
|
|
||||||
line one at a time, or even retype it.
|
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@ -75,15 +52,15 @@ in {
|
|||||||
firmware =
|
firmware =
|
||||||
let
|
let
|
||||||
o = config.system.outputs;
|
o = config.system.outputs;
|
||||||
bs = toString config.hardware.flash.eraseBlockSize;
|
bs = config.hardware.flash.eraseBlockSize;
|
||||||
in pkgs.runCommand "firmware" {} ''
|
in pkgs.runCommand "firmware" {} ''
|
||||||
dd if=${o.uimage} of=$out bs=${bs} conv=sync
|
dd if=${o.uimage} of=$out bs=${bs} conv=sync
|
||||||
dd if=${o.rootfs} of=$out bs=${bs} conv=sync,nocreat,notrunc oflag=append
|
dd if=${o.rootfs} of=$out bs=${bs} conv=sync,nocreat,notrunc oflag=append
|
||||||
'';
|
'';
|
||||||
mtdimage =
|
flashimage =
|
||||||
let o = config.system.outputs; in
|
let o = config.system.outputs; in
|
||||||
# could use trivial-builders.linkFarmFromDrvs here?
|
# could use trivial-builders.linkFarmFromDrvs here?
|
||||||
pkgs.runCommand "mtdimage" {} ''
|
pkgs.runCommand "flashimage" {} ''
|
||||||
mkdir $out
|
mkdir $out
|
||||||
cd $out
|
cd $out
|
||||||
ln -s ${o.firmware} firmware.bin
|
ln -s ${o.firmware} firmware.bin
|
||||||
@ -106,9 +83,9 @@ in {
|
|||||||
cat > $out << EOF
|
cat > $out << EOF
|
||||||
setenv serverip ${tftp.serverip}
|
setenv serverip ${tftp.serverip}
|
||||||
setenv ipaddr ${tftp.ipaddr}
|
setenv ipaddr ${tftp.ipaddr}
|
||||||
tftp 0x${toHexString tftp.loadAddress} result/firmware.bin
|
tftp 0x$(printf %x ${tftp.loadAddress}) result/firmware.bin
|
||||||
erase 0x${toHexString flash.address} +0x${toHexString flash.size}
|
erase 0x$(printf %x ${flash.address}) +${flash.size}
|
||||||
cp.b 0x${toHexString tftp.loadAddress} 0x${toHexString flash.address} \''${filesize}
|
cp.b 0x$(printf %x ${tftp.loadAddress}) 0x$(printf %x ${flash.address}) \''${filesize}
|
||||||
echo command line was ${builtins.toJSON (concatStringsSep " " config.boot.commandLine)}
|
echo command line was ${builtins.toJSON (concatStringsSep " " config.boot.commandLine)}
|
||||||
EOF
|
EOF
|
||||||
'';
|
'';
|
@ -16,14 +16,8 @@ in {
|
|||||||
hardware = {
|
hardware = {
|
||||||
dts = {
|
dts = {
|
||||||
src = mkOption {
|
src = mkOption {
|
||||||
type = types.nullOr types.path;
|
type = types.path;
|
||||||
description = ''
|
description = "Path to the device tree source (usually from OpenWrt)";
|
||||||
If the device requires an external device tree to be loaded
|
|
||||||
alongside the kernel, this is the path to the device tree source
|
|
||||||
(we usually get these from OpenWrt). This value may be null if the
|
|
||||||
platform creates the device tree - currently this is the case
|
|
||||||
only for QEMU.
|
|
||||||
'';
|
|
||||||
};
|
};
|
||||||
includes = mkOption {
|
includes = mkOption {
|
||||||
default = [];
|
default = [];
|
||||||
@ -32,15 +26,9 @@ in {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
defaultOutput = mkOption {
|
defaultOutput = mkOption {
|
||||||
description = "\"Default\" output: what gets built for this device when outputs.default is requested. Typically this is \"mtdimage\" or \"vmroot\"";
|
description = "\"Default\" output: what gets built for this device when outputs.default is requested. Typically this is \"flashimage\" or \"vmroot\"";
|
||||||
type = types.nonEmptyStr;
|
type = types.nonEmptyStr;
|
||||||
};
|
};
|
||||||
ram = {
|
|
||||||
startAddress = mkOption {
|
|
||||||
type = types.int;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
flash = {
|
flash = {
|
||||||
# start address and size of whichever partition (often
|
# start address and size of whichever partition (often
|
||||||
# called "firmware") we're going to overwrite with our
|
# called "firmware") we're going to overwrite with our
|
||||||
@ -54,19 +42,19 @@ in {
|
|||||||
kernel uimage and root fs. Usually not the entire flash, as
|
kernel uimage and root fs. Usually not the entire flash, as
|
||||||
we don't want to clobber the bootloader, calibration data etc
|
we don't want to clobber the bootloader, calibration data etc
|
||||||
'';
|
'';
|
||||||
type = types.ints.unsigned;
|
type = types.str;
|
||||||
};
|
};
|
||||||
size = mkOption {
|
size = mkOption {
|
||||||
type = types.ints.unsigned;
|
type = types.str;
|
||||||
description = "Size in bytes of the firmware partition";
|
description = "Size in bytes of the firmware partition";
|
||||||
};
|
};
|
||||||
eraseBlockSize = mkOption {
|
eraseBlockSize = mkOption {
|
||||||
description = "Flash erase block size in bytes";
|
description = "Flash erase block size in bytes";
|
||||||
type = types.ints.unsigned;
|
type = types.str;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
loadAddress = mkOption { type = types.ints.unsigned; default = null; };
|
loadAddress = mkOption { default = null; };
|
||||||
entryPoint = mkOption { type = types.ints.unsigned; };
|
entryPoint = mkOption { };
|
||||||
radios = mkOption {
|
radios = mkOption {
|
||||||
description = ''
|
description = ''
|
||||||
Kernel modules (from mac80211 package) required for the
|
Kernel modules (from mac80211 package) required for the
|
||||||
|
@ -13,23 +13,13 @@ in
|
|||||||
boot.initramfs = {
|
boot.initramfs = {
|
||||||
enable = mkEnableOption "initramfs";
|
enable = mkEnableOption "initramfs";
|
||||||
};
|
};
|
||||||
system.outputs = {
|
system.outputs.initramfs = mkOption {
|
||||||
initramfs = mkOption {
|
type = types.package;
|
||||||
type = types.package;
|
internal = true;
|
||||||
internal = true;
|
description = ''
|
||||||
description = ''
|
Initramfs image capable of mounting the jffs2 root
|
||||||
Initramfs image capable of mounting the real root
|
filesystem
|
||||||
filesystem
|
'';
|
||||||
'';
|
|
||||||
};
|
|
||||||
systemConfiguration = mkOption {
|
|
||||||
type = types.package;
|
|
||||||
description = ''
|
|
||||||
pkgs.systemconfig for the configured filesystem,
|
|
||||||
contains 'activate' and 'init' commands
|
|
||||||
'';
|
|
||||||
internal = true;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
config = mkIf config.boot.initramfs.enable {
|
config = mkIf config.boot.initramfs.enable {
|
||||||
@ -47,14 +37,18 @@ in
|
|||||||
dir /proc 0755 0 0
|
dir /proc 0755 0 0
|
||||||
dir /dev 0755 0 0
|
dir /dev 0755 0 0
|
||||||
nod /dev/console 0600 0 0 c 5 1
|
nod /dev/console 0600 0 0 c 5 1
|
||||||
|
nod /dev/mtdblock0 0600 0 0 b 31 0
|
||||||
|
nod /dev/mtdblock1 0600 0 0 b 31 1
|
||||||
|
nod /dev/mtdblock2 0600 0 0 b 31 2
|
||||||
|
nod /dev/mtdblock3 0600 0 0 b 31 3
|
||||||
|
nod /dev/mtdblock4 0600 0 0 b 31 4
|
||||||
|
nod /dev/mtdblock5 0600 0 0 b 31 5
|
||||||
dir /target 0755 0 0
|
dir /target 0755 0 0
|
||||||
dir /target/persist 0755 0 0
|
dir /target/persist 0755 0 0
|
||||||
dir /target/nix 0755 0 0
|
dir /target/nix 0755 0 0
|
||||||
file /init ${pkgs.preinit}/bin/preinit 0755 0 0
|
file /init ${pkgs.preinit}/bin/preinit 0755 0 0
|
||||||
SPECIALS
|
SPECIALS
|
||||||
'';
|
'';
|
||||||
systemConfiguration =
|
|
||||||
pkgs.systemconfig config.filesystem.contents;
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
54
modules/jffs2.nix
Normal file
54
modules/jffs2.nix
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
{
|
||||||
|
config
|
||||||
|
, pkgs
|
||||||
|
, lib
|
||||||
|
, ...
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
inherit (lib) mkIf mkOption types;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
./initramfs.nix
|
||||||
|
];
|
||||||
|
options.system.outputs = {
|
||||||
|
systemConfiguration = mkOption {
|
||||||
|
type = types.package;
|
||||||
|
description = ''
|
||||||
|
pkgs.systemconfig for the configured filesystem,
|
||||||
|
contains 'activate' and 'init' commands
|
||||||
|
'';
|
||||||
|
internal = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkIf (config.rootfsType == "jffs2") {
|
||||||
|
kernel.config = {
|
||||||
|
JFFS2_FS = "y";
|
||||||
|
JFFS2_LZO = "y";
|
||||||
|
JFFS2_RTIME = "y";
|
||||||
|
JFFS2_COMPRESSION_OPTIONS = "y";
|
||||||
|
JFFS2_ZLIB = "y";
|
||||||
|
JFFS2_CMODE_SIZE = "y";
|
||||||
|
};
|
||||||
|
boot.initramfs.enable = true;
|
||||||
|
system.outputs = rec {
|
||||||
|
systemConfiguration =
|
||||||
|
pkgs.systemconfig config.filesystem.contents;
|
||||||
|
rootfs =
|
||||||
|
let
|
||||||
|
inherit (pkgs.pkgsBuildBuild) runCommand mtdutils;
|
||||||
|
endian = if pkgs.stdenv.isBigEndian
|
||||||
|
then "--big-endian" else "--little-endian";
|
||||||
|
in runCommand "make-jffs2" {
|
||||||
|
depsBuildBuild = [ mtdutils ];
|
||||||
|
} ''
|
||||||
|
mkdir -p $TMPDIR/empty/nix/store/ $TMPDIR/empty/secrets
|
||||||
|
cp ${systemConfiguration}/bin/activate $TMPDIR/empty/activate
|
||||||
|
ln -s ${pkgs.s6-init-bin}/bin/init $TMPDIR/empty/init
|
||||||
|
grafts=$(sed < ${systemConfiguration}/etc/nix-store-paths 's/^\(.*\)$/--graft \1:\1/g')
|
||||||
|
mkfs.jffs2 --compression-mode=size ${endian} -e ${config.hardware.flash.eraseBlockSize} --enable-compressor=lzo --pad --root $TMPDIR/empty --output $out $grafts --squash --faketime
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
@ -9,14 +9,13 @@ let
|
|||||||
inherit (pkgs.pseudofile) dir symlink;
|
inherit (pkgs.pseudofile) dir symlink;
|
||||||
inherit (pkgs.liminix.networking) address interface;
|
inherit (pkgs.liminix.networking) address interface;
|
||||||
inherit (pkgs.liminix.services) bundle;
|
inherit (pkgs.liminix.services) bundle;
|
||||||
inherit (pkgs) liminix;
|
|
||||||
|
|
||||||
type_service = pkgs.liminix.lib.types.service;
|
type_service = pkgs.liminix.lib.types.service;
|
||||||
|
|
||||||
in {
|
in {
|
||||||
options = {
|
options = {
|
||||||
kernel = {
|
kernel = {
|
||||||
src = mkOption { type = types.path; } ;
|
src = mkOption { type = types.package; } ;
|
||||||
modular = mkOption {
|
modular = mkOption {
|
||||||
type = types.bool;
|
type = types.bool;
|
||||||
default = true;
|
default = true;
|
||||||
@ -42,25 +41,11 @@ in {
|
|||||||
};
|
};
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
makeTargets = mkOption {
|
|
||||||
type = types.listOf types.str;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
config = {
|
config = {
|
||||||
system.outputs =
|
|
||||||
let k = liminix.builders.kernel.override {
|
|
||||||
inherit (config.kernel) config src extraPatchPhase;
|
|
||||||
targets = config.kernel.makeTargets;
|
|
||||||
};
|
|
||||||
in {
|
|
||||||
kernel = k.vmlinux;
|
|
||||||
zimage = k.zImage;
|
|
||||||
};
|
|
||||||
|
|
||||||
kernel = rec {
|
kernel = rec {
|
||||||
modular = true; # disabling this is not yet supported
|
modular = true; # disabling this is not yet supported
|
||||||
makeTargets = ["vmlinux"];
|
|
||||||
config = {
|
config = {
|
||||||
IKCONFIG = "y";
|
IKCONFIG = "y";
|
||||||
IKCONFIG_PROC = "y";
|
IKCONFIG_PROC = "y";
|
||||||
@ -79,8 +64,6 @@ in {
|
|||||||
PACKET = "y"; # for ppp, tcpdump ...
|
PACKET = "y"; # for ppp, tcpdump ...
|
||||||
SYSVIPC= "y";
|
SYSVIPC= "y";
|
||||||
|
|
||||||
NETDEVICES = "y"; # even PPP needs this
|
|
||||||
|
|
||||||
# disabling this option causes the kernel to use an "empty"
|
# disabling this option causes the kernel to use an "empty"
|
||||||
# initramfs instead: it has a /dev/console node and not much
|
# initramfs instead: it has a /dev/console node and not much
|
||||||
# else. Note that pid 1 is started *before* the root
|
# else. Note that pid 1 is started *before* the root
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
let
|
let
|
||||||
inherit (lib) mkOption mkForce types concatStringsSep;
|
inherit (lib) mkOption mkForce types concatStringsSep;
|
||||||
in {
|
in {
|
||||||
imports = [ ../ramdisk.nix ];
|
imports = [ ./ramdisk.nix ];
|
||||||
options.system.outputs = {
|
options.system.outputs = {
|
||||||
kexecboot = mkOption {
|
kexecboot = mkOption {
|
||||||
type = types.package;
|
type = types.package;
|
@ -68,21 +68,7 @@ in {
|
|||||||
ifname = mkOption {
|
ifname = mkOption {
|
||||||
type = types.str;
|
type = types.str;
|
||||||
example = "eth0";
|
example = "eth0";
|
||||||
description = ''
|
|
||||||
Device name as used by the kernel (as seen in "ip link"
|
|
||||||
or "ifconfig" output). If devpath is also specified, the
|
|
||||||
device will be renamed to the name provided.
|
|
||||||
'';
|
|
||||||
};
|
};
|
||||||
devpath = mkOption {
|
|
||||||
type = types.nullOr types.str;
|
|
||||||
default = null;
|
|
||||||
example = "/devices/platform/soc/soc:internal-regs/f1070000.ethernet";
|
|
||||||
description = ''
|
|
||||||
Path to the sysfs node of the device. If you provide this
|
|
||||||
and the ifname option, the device will be renamed to the
|
|
||||||
name given by ifname.
|
|
||||||
''; };
|
|
||||||
# other "ip link add" options could go here as well
|
# other "ip link add" options could go here as well
|
||||||
mtu = mkOption {
|
mtu = mkOption {
|
||||||
type = types.nullOr types.int;
|
type = types.nullOr types.int;
|
||||||
|
@ -4,27 +4,13 @@
|
|||||||
, serviceFns
|
, serviceFns
|
||||||
, lib
|
, lib
|
||||||
}:
|
}:
|
||||||
{
|
{ifname, mtu} :
|
||||||
ifname
|
|
||||||
, devpath ? null
|
|
||||||
, mtu} :
|
|
||||||
# if devpath is supplied, we rename the interface at that
|
|
||||||
# path to have the specified name.
|
|
||||||
let
|
let
|
||||||
inherit (liminix.services) longrun oneshot;
|
inherit (liminix.services) longrun oneshot;
|
||||||
inherit (lib) concatStringsSep;
|
inherit (lib) concatStringsSep;
|
||||||
name = "${ifname}.link";
|
name = "${ifname}.link";
|
||||||
rename = if devpath != null
|
up = liminix.networking.ifup name ifname;
|
||||||
then ''
|
|
||||||
oldname=$(cd /sys${devpath} && cd net/ && echo *)
|
|
||||||
ip link set ''${oldname} name ${ifname}
|
|
||||||
''
|
|
||||||
else "";
|
|
||||||
in oneshot {
|
in oneshot {
|
||||||
inherit name;
|
inherit name up;
|
||||||
up = ''
|
|
||||||
${rename}
|
|
||||||
${liminix.networking.ifup name ifname}
|
|
||||||
'';
|
|
||||||
down = "ip link set down dev ${ifname}";
|
down = "ip link set down dev ${ifname}";
|
||||||
}
|
}
|
||||||
|
@ -7,132 +7,103 @@
|
|||||||
let
|
let
|
||||||
inherit (lib) mkOption types concatStringsSep;
|
inherit (lib) mkOption types concatStringsSep;
|
||||||
inherit (pkgs) liminix callPackage writeText;
|
inherit (pkgs) liminix callPackage writeText;
|
||||||
o = config.system.outputs;
|
arch = let s = pkgs.stdenv; in
|
||||||
|
if s.isAarch64
|
||||||
|
then "aarch64"
|
||||||
|
else if s.isMips
|
||||||
|
then "mips"
|
||||||
|
else throw "can't determine arch";
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
imports = [
|
imports = [
|
||||||
./squashfs.nix
|
./squashfs.nix
|
||||||
./outputs/vmroot.nix
|
|
||||||
./outputs/extlinux.nix
|
|
||||||
];
|
];
|
||||||
options = {
|
options = {
|
||||||
system.outputs = {
|
system.outputs = {
|
||||||
# the convention here is to mark an output as "internal" if
|
|
||||||
# it's not a complete system (kernel plus userland, or installer)
|
|
||||||
# but only part of one.
|
|
||||||
kernel = mkOption {
|
kernel = mkOption {
|
||||||
type = types.package;
|
type = types.package;
|
||||||
internal = true;
|
|
||||||
description = ''
|
description = ''
|
||||||
kernel
|
|
||||||
******
|
|
||||||
|
|
||||||
Kernel vmlinux file (usually ELF)
|
Kernel vmlinux file (usually ELF)
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
zimage = mkOption {
|
|
||||||
type = types.package;
|
|
||||||
internal = true;
|
|
||||||
description = ''
|
|
||||||
zimage
|
|
||||||
******
|
|
||||||
|
|
||||||
Kernel in compressed self-extracting package
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
dtb = mkOption {
|
dtb = mkOption {
|
||||||
type = types.package;
|
type = types.package;
|
||||||
internal = true;
|
|
||||||
description = ''
|
description = ''
|
||||||
dtb
|
|
||||||
***
|
|
||||||
|
|
||||||
Compiled device tree (FDT) for the target device
|
Compiled device tree (FDT) for the target device
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
uimage = mkOption {
|
uimage = mkOption {
|
||||||
type = types.package;
|
type = types.package;
|
||||||
internal = true;
|
|
||||||
description = ''
|
description = ''
|
||||||
uimage
|
|
||||||
******
|
|
||||||
|
|
||||||
Combined kernel and FDT in uImage (U-Boot compatible) format
|
Combined kernel and FDT in uImage (U-Boot compatible) format
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
u-boot = mkOption {
|
vmroot = mkOption {
|
||||||
type = types.package;
|
type = types.package;
|
||||||
|
description = ''
|
||||||
|
Directory containing separate kernel and rootfs image for
|
||||||
|
use with qemu (see run-liminix-vm)
|
||||||
|
'';
|
||||||
};
|
};
|
||||||
manifest = mkOption {
|
manifest = mkOption {
|
||||||
type = types.package;
|
type = types.package;
|
||||||
internal = true;
|
|
||||||
description = ''
|
description = ''
|
||||||
Debugging aid. JSON rendition of config.filesystem, on
|
Debugging aid. JSON rendition of config.filesystem, on
|
||||||
which can run "nix-store -q --tree" on it and find
|
which can run "nix-store -q --tree" on it and find
|
||||||
out what's in the image, which is nice if it's unexpectedly huge
|
out what's in the image, which is nice if it's unexpectedly huge
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
rootdir = mkOption {
|
|
||||||
type = types.package;
|
|
||||||
internal = true;
|
|
||||||
description = ''
|
|
||||||
directory of files to package into root filesystem
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
bootablerootdir = mkOption {
|
|
||||||
type = types.package;
|
|
||||||
internal = true;
|
|
||||||
description = ''
|
|
||||||
directory of files to package into root filesystem, including
|
|
||||||
a kernel and appropriate associated gubbins for the
|
|
||||||
selected bootloader
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
rootfs = mkOption {
|
rootfs = mkOption {
|
||||||
type = types.package;
|
type = types.package;
|
||||||
internal = true;
|
|
||||||
description = ''
|
description = ''
|
||||||
root filesystem (squashfs or jffs2) image
|
root filesystem (squashfs or jffs2) image
|
||||||
'';
|
'';
|
||||||
|
internal = true;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
config = {
|
config = {
|
||||||
system.outputs = rec {
|
system.outputs = rec {
|
||||||
|
# tftpd = pkgs.buildPackages.tufted;
|
||||||
|
kernel = liminix.builders.kernel.override {
|
||||||
|
inherit (config.kernel) config src extraPatchPhase;
|
||||||
|
};
|
||||||
dtb = liminix.builders.dtb {
|
dtb = liminix.builders.dtb {
|
||||||
inherit (config.boot) commandLine;
|
inherit (config.boot) commandLine;
|
||||||
dts = config.hardware.dts.src;
|
dts = config.hardware.dts.src;
|
||||||
includes = config.hardware.dts.includes ++ [
|
includes = config.hardware.dts.includes ++ [
|
||||||
"${o.kernel.headers}/include"
|
"${kernel.headers}/include"
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
uimage = liminix.builders.uimage {
|
uimage = liminix.builders.uimage {
|
||||||
commandLine = concatStringsSep " " config.boot.commandLine;
|
commandLine = concatStringsSep " " config.boot.commandLine;
|
||||||
inherit (config.hardware) loadAddress entryPoint;
|
inherit (config.hardware) loadAddress entryPoint;
|
||||||
inherit (config.boot) imageFormat;
|
inherit kernel;
|
||||||
inherit (o) kernel dtb;
|
inherit dtb;
|
||||||
};
|
};
|
||||||
rootdir =
|
# could use trivial-builders.linkFarmFromDrvs here?
|
||||||
|
vmroot =
|
||||||
let
|
let
|
||||||
inherit (pkgs.pkgsBuildBuild) runCommand;
|
cmdline = builtins.toJSON (concatStringsSep " " config.boot.commandLine);
|
||||||
in runCommand "mktree" { } ''
|
makeBootableImage = pkgs.runCommandCC "objcopy" {}
|
||||||
mkdir -p $out/nix/store/ $out/secrets $out/boot
|
(if pkgs.stdenv.isAarch64
|
||||||
cp ${o.systemConfiguration}/bin/activate $out/activate
|
then "${pkgs.stdenv.cc.targetPrefix}objcopy -O binary -S ${kernel} $out"
|
||||||
ln -s ${pkgs.s6-init-bin}/bin/init $out/init
|
else "cp ${kernel} $out");
|
||||||
mkdir -p $out/nix/store
|
in pkgs.runCommandCC "vmroot" {} ''
|
||||||
for path in $(cat ${o.systemConfiguration}/etc/nix-store-paths) ; do
|
mkdir $out
|
||||||
(cd $out && cp -a $path .$path)
|
cd $out
|
||||||
done
|
ln -s ${config.system.outputs.rootfs} rootfs
|
||||||
'';
|
ln -s ${kernel} vmlinux
|
||||||
bootablerootdir =
|
ln -s ${manifest} manifest
|
||||||
let inherit (pkgs.pkgsBuildBuild) runCommand;
|
ln -s ${kernel.headers} build
|
||||||
in runCommand "add-slash-boot" { } ''
|
echo ${cmdline} > commandline
|
||||||
cp -a ${o.rootdir} $out
|
cat > run.sh << EOF
|
||||||
${if config.boot.loader.extlinux.enable
|
#!${pkgs.runtimeShell}
|
||||||
then "(cd $out && chmod -R +w . && rmdir boot && cp -a ${o.extlinux} boot)"
|
CMDLINE=${cmdline} ${pkgs.pkgsBuildBuild.run-liminix-vm}/bin/run-liminix-vm --arch ${arch} \$* ${makeBootableImage} ${config.system.outputs.rootfs}
|
||||||
else ""
|
EOF
|
||||||
}
|
chmod +x run.sh
|
||||||
'';
|
'';
|
||||||
|
|
||||||
manifest = writeText "manifest.json" (builtins.toJSON config.filesystem.contents);
|
manifest = writeText "manifest.json" (builtins.toJSON config.filesystem.contents);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -1,38 +0,0 @@
|
|||||||
{
|
|
||||||
config
|
|
||||||
, pkgs
|
|
||||||
, lib
|
|
||||||
, ...
|
|
||||||
}:
|
|
||||||
let
|
|
||||||
inherit (lib) mkIf mkOption types;
|
|
||||||
o = config.system.outputs;
|
|
||||||
in
|
|
||||||
{
|
|
||||||
imports = [
|
|
||||||
./initramfs.nix
|
|
||||||
];
|
|
||||||
config = mkIf (config.rootfsType == "ext4") {
|
|
||||||
kernel.config = {
|
|
||||||
EXT4_FS = "y";
|
|
||||||
EXT4_USE_FOR_EXT2 = "y";
|
|
||||||
FS_ENCRYPTION = "y";
|
|
||||||
};
|
|
||||||
boot.initramfs.enable = true;
|
|
||||||
system.outputs = {
|
|
||||||
rootfs =
|
|
||||||
let
|
|
||||||
inherit (pkgs.pkgsBuildBuild) runCommand e2fsprogs;
|
|
||||||
in runCommand "mkfs.ext4" {
|
|
||||||
depsBuildBuild = [ e2fsprogs ];
|
|
||||||
} ''
|
|
||||||
tree=${o.bootablerootdir}
|
|
||||||
size=$(du -s --apparent-size --block-size 1024 $tree |cut -f1)
|
|
||||||
# add 25% for filesystem overhead
|
|
||||||
size=$(( 5 * $size / 4))
|
|
||||||
dd if=/dev/zero of=$out bs=1024 count=$size
|
|
||||||
mke2fs -t ext4 -j -d $tree $out
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
@ -1,39 +0,0 @@
|
|||||||
{
|
|
||||||
config
|
|
||||||
, pkgs
|
|
||||||
, lib
|
|
||||||
, ...
|
|
||||||
}:
|
|
||||||
let
|
|
||||||
inherit (lib) mkIf mkEnableOption mkOption types concatStringsSep;
|
|
||||||
cfg = config.boot.loader.extlinux;
|
|
||||||
o = config.system.outputs;
|
|
||||||
cmdline = concatStringsSep " " config.boot.commandLine;
|
|
||||||
wantsDtb = config.hardware.dts ? src && config.hardware.dts.src != null;
|
|
||||||
in {
|
|
||||||
options.system.outputs.extlinux = mkOption {
|
|
||||||
type = types.package;
|
|
||||||
# description = "";
|
|
||||||
};
|
|
||||||
options.boot.loader.extlinux.enable = mkEnableOption "extlinux";
|
|
||||||
|
|
||||||
config = { # mkIf cfg.enable {
|
|
||||||
system.outputs.extlinux = pkgs.runCommand "extlinux" {} ''
|
|
||||||
mkdir $out
|
|
||||||
cd $out
|
|
||||||
${if wantsDtb then "cp ${o.dtb} dtb" else "true"}
|
|
||||||
cp ${o.initramfs} initramfs
|
|
||||||
cp ${o.zimage} kernel
|
|
||||||
mkdir extlinux
|
|
||||||
cat > extlinux/extlinux.conf << _EOF
|
|
||||||
menu title Liminix
|
|
||||||
timeout 100
|
|
||||||
label Liminix
|
|
||||||
kernel /boot/kernel
|
|
||||||
# initrd /boot/initramfs
|
|
||||||
append ${cmdline} root=/dev/vda1
|
|
||||||
${if wantsDtb then "fdt /boot/dtb" else ""}
|
|
||||||
_EOF
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
}
|
|
@ -1,40 +0,0 @@
|
|||||||
{
|
|
||||||
config
|
|
||||||
, pkgs
|
|
||||||
, lib
|
|
||||||
, ...
|
|
||||||
}:
|
|
||||||
let
|
|
||||||
inherit (lib) mkIf mkOption types;
|
|
||||||
o = config.system.outputs;
|
|
||||||
in
|
|
||||||
{
|
|
||||||
imports = [
|
|
||||||
./initramfs.nix
|
|
||||||
];
|
|
||||||
|
|
||||||
config = mkIf (config.rootfsType == "jffs2") {
|
|
||||||
kernel.config = {
|
|
||||||
JFFS2_FS = "y";
|
|
||||||
JFFS2_LZO = "y";
|
|
||||||
JFFS2_RTIME = "y";
|
|
||||||
JFFS2_COMPRESSION_OPTIONS = "y";
|
|
||||||
JFFS2_ZLIB = "y";
|
|
||||||
JFFS2_CMODE_SIZE = "y";
|
|
||||||
};
|
|
||||||
boot.initramfs.enable = true;
|
|
||||||
system.outputs = {
|
|
||||||
rootfs =
|
|
||||||
let
|
|
||||||
inherit (pkgs.pkgsBuildBuild) runCommand mtdutils;
|
|
||||||
endian = if pkgs.stdenv.isBigEndian
|
|
||||||
then "--big-endian" else "--little-endian";
|
|
||||||
in runCommand "make-jffs2" {
|
|
||||||
depsBuildBuild = [ mtdutils ];
|
|
||||||
} ''
|
|
||||||
tree=${o.bootablerootdir}
|
|
||||||
(cd $tree && mkfs.jffs2 --compression-mode=size ${endian} -e ${toString config.hardware.flash.eraseBlockSize} --enable-compressor=lzo --pad --root . --output $out --squash --faketime )
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
@ -1,51 +0,0 @@
|
|||||||
{
|
|
||||||
config
|
|
||||||
, pkgs
|
|
||||||
, lib
|
|
||||||
, ...
|
|
||||||
}:
|
|
||||||
let
|
|
||||||
inherit (lib) mkOption types concatStringsSep;
|
|
||||||
o = config.system.outputs;
|
|
||||||
phram_address = lib.toHexString (config.hardware.ram.startAddress + 256 * 1024 * 1024);
|
|
||||||
in {
|
|
||||||
options.system.outputs = {
|
|
||||||
mbrimage = mkOption {
|
|
||||||
type = types.package;
|
|
||||||
description = ''
|
|
||||||
mbrimage
|
|
||||||
*********
|
|
||||||
|
|
||||||
This creates a disk image file with a partition table containing
|
|
||||||
the contents of ``outputs.rootfs`` as its only partition.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
vmdisk = mkOption { type = types.package; };
|
|
||||||
};
|
|
||||||
|
|
||||||
config = {
|
|
||||||
system.outputs = {
|
|
||||||
mbrimage =
|
|
||||||
let
|
|
||||||
o = config.system.outputs;
|
|
||||||
in pkgs.runCommand "mbrimage" {
|
|
||||||
depsBuildBuild = [ pkgs.pkgsBuildBuild.util-linux ];
|
|
||||||
} ''
|
|
||||||
# leave 4 sectors at start for partition table
|
|
||||||
# and alignment to 2048 bytes (does that help?)
|
|
||||||
dd if=${o.rootfs} of=$out bs=512 seek=4 conv=sync
|
|
||||||
echo '4,-,L,*' | sfdisk $out
|
|
||||||
'';
|
|
||||||
vmdisk = pkgs.runCommand "vmdisk" {} ''
|
|
||||||
mkdir $out
|
|
||||||
cd $out
|
|
||||||
ln -s ${o.mbrimage} ./mbrimage
|
|
||||||
cat > run.sh <<EOF
|
|
||||||
#!${pkgs.runtimeShell}
|
|
||||||
${pkgs.pkgsBuildBuild.run-liminix-vm}/bin/run-liminix-vm --arch ${pkgs.stdenv.hostPlatform.qemuArch} --u-boot ${o.u-boot}/u-boot.bin --phram-address 0x${phram_address} --disk-image ${o.mbrimage} \$* /dev/null /dev/null
|
|
||||||
EOF
|
|
||||||
chmod +x run.sh
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
@ -1,127 +0,0 @@
|
|||||||
{
|
|
||||||
config
|
|
||||||
, pkgs
|
|
||||||
, lib
|
|
||||||
, ...
|
|
||||||
}:
|
|
||||||
let
|
|
||||||
inherit (lib) mkOption types concatStringsSep;
|
|
||||||
cfg = config.boot.tftp;
|
|
||||||
in {
|
|
||||||
imports = [ ../ramdisk.nix ];
|
|
||||||
options.boot.tftp = {
|
|
||||||
freeSpaceBytes = mkOption {
|
|
||||||
type = types.int;
|
|
||||||
default = 0;
|
|
||||||
};
|
|
||||||
kernelFormat = mkOption {
|
|
||||||
type = types.enum [ "zimage" "uimage" ];
|
|
||||||
default = "uimage";
|
|
||||||
};
|
|
||||||
compressRoot = mkOption {
|
|
||||||
type = types.bool;
|
|
||||||
default = false;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
options.system.outputs = {
|
|
||||||
tftpboot = mkOption {
|
|
||||||
type = types.package;
|
|
||||||
description = ''
|
|
||||||
tftpboot
|
|
||||||
********
|
|
||||||
|
|
||||||
This output is intended for developing on a new device.
|
|
||||||
It assumes you have a serial connection and a
|
|
||||||
network connection to the device and that your
|
|
||||||
build machine is running a TFTP server.
|
|
||||||
|
|
||||||
The output is a directory containing kernel and
|
|
||||||
root filesystem image, and a script :file:`boot.scr` of U-Boot
|
|
||||||
commands that will load the images into memory and
|
|
||||||
run them directly,
|
|
||||||
instead of first writing them to flash. This saves
|
|
||||||
time and erase cycles.
|
|
||||||
|
|
||||||
It uses the Linux `phram <https://github.com/torvalds/linux/blob/master/drivers/mtd/devices/phram.c>`_ driver to emulate a flash device using a segment of physical RAM.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
|
||||||
config = {
|
|
||||||
boot.ramdisk.enable = true;
|
|
||||||
|
|
||||||
system.outputs = rec {
|
|
||||||
tftpboot =
|
|
||||||
let
|
|
||||||
inherit (pkgs.lib.trivial) toHexString;
|
|
||||||
o = config.system.outputs;
|
|
||||||
image = let choices = {
|
|
||||||
uimage = o.uimage;
|
|
||||||
zimage = o.zimage;
|
|
||||||
}; in choices.${cfg.kernelFormat};
|
|
||||||
bootCommand = let choices = {
|
|
||||||
uimage = "bootm";
|
|
||||||
zimage = "bootz";
|
|
||||||
}; in choices.${cfg.kernelFormat};
|
|
||||||
cmdline = concatStringsSep " " config.boot.commandLine;
|
|
||||||
in
|
|
||||||
pkgs.runCommand "tftpboot" { nativeBuildInputs = with pkgs.pkgsBuildBuild; [ lzma dtc ]; } ''
|
|
||||||
mkdir $out
|
|
||||||
cd $out
|
|
||||||
binsize() { local s=$(stat -L -c %s $1); echo $(($s + 0x1000 &(~0xfff))); }
|
|
||||||
binsize64k() { local s=$(stat -L -c %s $1); echo $(($s + 0x10000 &(~0xffff))); }
|
|
||||||
hex() { printf "0x%x" $1; }
|
|
||||||
rootfsStart=${toString cfg.loadAddress}
|
|
||||||
rootfsSize=$(binsize64k ${o.rootfs} )
|
|
||||||
dtbStart=$(($rootfsStart + $rootfsSize))
|
|
||||||
dtbSize=$(binsize ${o.dtb} )
|
|
||||||
imageStart=$(($dtbStart + $dtbSize))
|
|
||||||
imageSize=$(binsize ${image})
|
|
||||||
|
|
||||||
ln -s ${o.manifest} manifest
|
|
||||||
ln -s ${image} image
|
|
||||||
ln -s ${o.kernel} vmlinux # handy for gdb
|
|
||||||
|
|
||||||
${if cfg.compressRoot
|
|
||||||
then ''
|
|
||||||
lzma -z9cv ${o.rootfs} > rootfs.lz
|
|
||||||
rootfsLzStart=$(($imageStart + $imageSize))
|
|
||||||
rootfsLzSize=$(binsize rootfs.lz)
|
|
||||||
''
|
|
||||||
else "ln -s ${o.rootfs} rootfs"
|
|
||||||
}
|
|
||||||
cat ${o.dtb} > dtb
|
|
||||||
address_cells=$(fdtget dtb / '#address-cells')
|
|
||||||
size_cells=$(fdtget dtb / '#size-cells')
|
|
||||||
if [ $address_cells -gt 1 ]; then ac_prefix=0; fi
|
|
||||||
if [ $size_cells -gt 1 ]; then sz_prefix=0; fi
|
|
||||||
|
|
||||||
fdtput -p dtb /reserved-memory '#address-cells' $address_cells
|
|
||||||
fdtput -p dtb /reserved-memory '#size-cells' $size_cells
|
|
||||||
fdtput -p dtb /reserved-memory ranges
|
|
||||||
node=$(printf "phram-rootfs@%x" $rootfsStart)
|
|
||||||
fdtput -p -t s dtb /reserved-memory/$node compatible phram
|
|
||||||
fdtput -p -t lx dtb /reserved-memory/$node reg $ac_prefix $(hex $rootfsStart) $sz_prefix $(hex $rootfsSize)
|
|
||||||
|
|
||||||
cmd="liminix ${cmdline} mtdparts=phram0:''${rootfsSize}(rootfs) phram.phram=phram0,''${rootfsStart},''${rootfsSize},${toString config.hardware.flash.eraseBlockSize} root=/dev/mtdblock0";
|
|
||||||
fdtput -t s dtb /chosen bootargs "$cmd"
|
|
||||||
|
|
||||||
# dtc -I dtb -O dts -o /dev/stdout dtb | grep -A10 chosen ; exit 1
|
|
||||||
|
|
||||||
cat > boot.scr << EOF
|
|
||||||
setenv serverip ${cfg.serverip}
|
|
||||||
setenv ipaddr ${cfg.ipaddr}
|
|
||||||
tftpboot $(hex $imageStart) result/image ; ${
|
|
||||||
if cfg.compressRoot
|
|
||||||
then "tftpboot $(hex $rootfsLzStart) result/rootfs.lz"
|
|
||||||
else "tftpboot $(hex $rootfsStart) result/rootfs"
|
|
||||||
}; tftpboot $(hex $dtbStart) result/dtb
|
|
||||||
${if cfg.compressRoot
|
|
||||||
then "lzmadec $(hex $rootfsLzStart) $(hex $rootfsStart); "
|
|
||||||
else ""
|
|
||||||
} ${bootCommand} $(hex $imageStart) - $(hex $dtbStart)
|
|
||||||
EOF
|
|
||||||
'';
|
|
||||||
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
@ -1,42 +0,0 @@
|
|||||||
{
|
|
||||||
config
|
|
||||||
, pkgs
|
|
||||||
, lib
|
|
||||||
, ...
|
|
||||||
}:
|
|
||||||
let
|
|
||||||
inherit (lib) mkIf mkOption types;
|
|
||||||
o = config.system.outputs;
|
|
||||||
in
|
|
||||||
{
|
|
||||||
imports = [
|
|
||||||
./initramfs.nix
|
|
||||||
];
|
|
||||||
options.hardware.ubi = {
|
|
||||||
minIOSize = mkOption { type = types.str; };
|
|
||||||
eraseBlockSize = mkOption { type = types.str; }; # LEB
|
|
||||||
maxLEBcount = mkOption { type = types.str; }; # LEB
|
|
||||||
};
|
|
||||||
|
|
||||||
config = mkIf (config.rootfsType == "ubifs") {
|
|
||||||
kernel.config = {
|
|
||||||
MTD_UBI="y";
|
|
||||||
UBIFS_FS = "y";
|
|
||||||
UBIFS_FS_SECURITY = "n";
|
|
||||||
};
|
|
||||||
boot.initramfs.enable = true;
|
|
||||||
system.outputs = {
|
|
||||||
rootfs =
|
|
||||||
let
|
|
||||||
inherit (pkgs.pkgsBuildBuild) runCommand mtdutils;
|
|
||||||
cfg = config.hardware.ubi;
|
|
||||||
in runCommand "mkfs.ubifs" {
|
|
||||||
depsBuildBuild = [ mtdutils ];
|
|
||||||
} ''
|
|
||||||
mkdir tmp
|
|
||||||
tree=${o.bootablerootdir}
|
|
||||||
mkfs.ubifs -x favor_lzo -c ${cfg.maxLEBcount} -m ${cfg.minIOSize} -e ${cfg.eraseBlockSize} -y -r $tree --output $out --squash-uids -o $out
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
@ -1,126 +0,0 @@
|
|||||||
{
|
|
||||||
config
|
|
||||||
, pkgs
|
|
||||||
, lib
|
|
||||||
, ...
|
|
||||||
}:
|
|
||||||
let
|
|
||||||
inherit (lib) mkIf mkEnableOption mkOption types concatStringsSep;
|
|
||||||
cfg = config.boot.tftp;
|
|
||||||
instructions = pkgs.writeText "env.scr" ''
|
|
||||||
setenv serverip ${cfg.serverip}
|
|
||||||
setenv ipaddr ${cfg.ipaddr}
|
|
||||||
setenv loadaddr ${lib.toHexString cfg.loadAddress}
|
|
||||||
'';
|
|
||||||
in {
|
|
||||||
options.system.outputs = {
|
|
||||||
ubimage = mkOption {
|
|
||||||
type = types.package;
|
|
||||||
description = ''
|
|
||||||
ubimage
|
|
||||||
*******
|
|
||||||
|
|
||||||
This output provides a UBIFS filesystem image and a small U-Boot script
|
|
||||||
to make the manual installation process very slightly simpler. You will
|
|
||||||
need a serial connection and a network connection to a TFTP server
|
|
||||||
containing the filesystem image it creates.
|
|
||||||
|
|
||||||
.. warning:: These steps were tested on a Belkin RT3200 (also known as
|
|
||||||
Linksys E8450). Other devices may be set up differently,
|
|
||||||
so use them as inspiration and don't just paste them
|
|
||||||
blindly.
|
|
||||||
|
|
||||||
1) determine which MTD device is being used for UBI, and the partition name:
|
|
||||||
|
|
||||||
.. code-block:: console
|
|
||||||
|
|
||||||
uboot> ubi part
|
|
||||||
Device 0: ubi0, MTD partition ubi
|
|
||||||
|
|
||||||
In this case the important value is ``ubi0``
|
|
||||||
|
|
||||||
2) list the available volumes and create a new one on which to install Liminix
|
|
||||||
|
|
||||||
.. code-block:: console
|
|
||||||
|
|
||||||
uboot> ubi info l
|
|
||||||
[ copious output scrolls past ]
|
|
||||||
|
|
||||||
Expect there to be existing volumes and for some or all of them to be
|
|
||||||
important. Unless you know what you're doing, don't remove anything
|
|
||||||
whose name suggests it's related to uboot, or any kind of backup or
|
|
||||||
recovery partition. To see how much space is free:
|
|
||||||
|
|
||||||
.. code-block:: console
|
|
||||||
|
|
||||||
uboot> ubi info
|
|
||||||
[ ... ]
|
|
||||||
UBI: available PEBs: 823
|
|
||||||
|
|
||||||
Now we can make our new root volume
|
|
||||||
|
|
||||||
.. code-block:: console
|
|
||||||
|
|
||||||
uboot> ubi create liminix -
|
|
||||||
|
|
||||||
3) transfer the root filesystem from the build system and write it
|
|
||||||
to the new volume. Paste the environment variable settings from
|
|
||||||
:file:`result/env.scr` into U-Boot, then run
|
|
||||||
|
|
||||||
.. code-block:: console
|
|
||||||
|
|
||||||
uboot> tftpboot ''${loadaddr} result/rootfs
|
|
||||||
uboot> ubi write ''${loadaddr} liminix $filesize
|
|
||||||
|
|
||||||
Now we have the root filesystem installed on the device. You
|
|
||||||
can even mount it and poke around using ``ubifsmount ubi0:liminix;
|
|
||||||
ubifsls /``
|
|
||||||
|
|
||||||
4) optional: before you configure the device to boot into Liminix
|
|
||||||
automatically, you can try booting it by hand to see if it works:
|
|
||||||
|
|
||||||
.. code-block:: console
|
|
||||||
|
|
||||||
uboot> ubifsmount ubi0:liminix
|
|
||||||
uboot> ubifsload ''${loadaddr} boot/uimage
|
|
||||||
uboot> bootm ''${loadaddr}
|
|
||||||
|
|
||||||
Once you've done this and you're happy with it, reset the device to
|
|
||||||
U-Boot. You don't need to recreate the volume but you do need to
|
|
||||||
repeat step 3.
|
|
||||||
|
|
||||||
5) Instructions for configuring autoboot are likely to be very
|
|
||||||
device-dependent. On the Linksys E8450/Belkin RT3200, the environment
|
|
||||||
variable `boot_production` governs what happens on a normal boot, so
|
|
||||||
you could do
|
|
||||||
|
|
||||||
.. code-block:: console
|
|
||||||
|
|
||||||
uboot> setenv boot_production 'led $bootled_pwr on ; ubifsmount ubi0:liminix; ubifsload ''${loadaddr} boot/uimage; bootm ''${loadaddr}'
|
|
||||||
|
|
||||||
On other devices, some detective work may be needed. Try running
|
|
||||||
`printenv` and look for likely commands, try looking at the existing
|
|
||||||
boot process, maybe even try looking for documentation for that device.
|
|
||||||
|
|
||||||
6) Now you can reboot the device into Liminix
|
|
||||||
|
|
||||||
.. code-block:: console
|
|
||||||
|
|
||||||
uboot> reset
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
config = mkIf (config.rootfsType == "ubifs") {
|
|
||||||
system.outputs = {
|
|
||||||
ubimage =
|
|
||||||
let o = config.system.outputs; in
|
|
||||||
pkgs.runCommand "ubimage" {} ''
|
|
||||||
mkdir $out
|
|
||||||
cd $out
|
|
||||||
ln -s ${o.rootfs} rootfs
|
|
||||||
ln -s ${instructions} env.scr
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
@ -1,73 +0,0 @@
|
|||||||
{
|
|
||||||
config
|
|
||||||
, pkgs
|
|
||||||
, lib
|
|
||||||
, ...
|
|
||||||
}:
|
|
||||||
let
|
|
||||||
inherit (lib) mkOption types concatStringsSep;
|
|
||||||
in
|
|
||||||
{
|
|
||||||
options = {
|
|
||||||
system.outputs = {
|
|
||||||
vmroot = mkOption {
|
|
||||||
type = types.package;
|
|
||||||
description = ''
|
|
||||||
vmroot
|
|
||||||
******
|
|
||||||
|
|
||||||
This target is for use with the qemu, qemu-aarch64, qemu-armv7l
|
|
||||||
devices. It generates an executable :file:`run.sh` which
|
|
||||||
invokes QEMU. It connects the Liminix
|
|
||||||
serial console and the `QEMU monitor <https://www.qemu.org/docs/master/system/monitor.html>`_
|
|
||||||
to stdin/stdout. Use ^P (not ^A) to switch between monitor and
|
|
||||||
stdio.
|
|
||||||
|
|
||||||
If you call :command:`run.sh` with ``--background
|
|
||||||
/path/to/some/directory`` as the first parameter, it will
|
|
||||||
fork into the background and open Unix sockets in that
|
|
||||||
directory for console and monitor. Use :command:`nix-shell
|
|
||||||
--run connect-vm` to connect to either of these sockets, and
|
|
||||||
^O to disconnect.
|
|
||||||
|
|
||||||
Liminix VMs are networked using QEMU socket networking. The
|
|
||||||
default behaviour is to connect
|
|
||||||
|
|
||||||
* multicast 230.0.0.1:1234 ("access") to eth0
|
|
||||||
* multicast 230.0.0.1:1235 ("lan") to eth1
|
|
||||||
|
|
||||||
Refer to :ref:`border-network-gateway` for details of how to
|
|
||||||
start an emulated upstream on the "access" network that
|
|
||||||
your Liminix device can talk to.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
config = {
|
|
||||||
system.outputs = rec {
|
|
||||||
vmroot =
|
|
||||||
let
|
|
||||||
inherit (config.system.outputs) rootfs kernel manifest;
|
|
||||||
cmdline = builtins.toJSON (concatStringsSep " " config.boot.commandLine);
|
|
||||||
makeBootableImage = pkgs.runCommandCC "objcopy" {}
|
|
||||||
(if pkgs.stdenv.hostPlatform.isAarch
|
|
||||||
then "${pkgs.stdenv.cc.targetPrefix}objcopy -O binary -R .comment -S ${kernel} $out"
|
|
||||||
else "cp ${kernel} $out");
|
|
||||||
phram_address = lib.toHexString (config.hardware.ram.startAddress + 256 * 1024 * 1024);
|
|
||||||
in pkgs.runCommand "vmroot" {} ''
|
|
||||||
mkdir $out
|
|
||||||
cd $out
|
|
||||||
ln -s ${rootfs} rootfs
|
|
||||||
ln -s ${kernel} vmlinux
|
|
||||||
ln -s ${manifest} manifest
|
|
||||||
ln -s ${kernel.headers} build
|
|
||||||
echo ${cmdline} > commandline
|
|
||||||
cat > run.sh << EOF
|
|
||||||
#!${pkgs.runtimeShell}
|
|
||||||
${pkgs.pkgsBuildBuild.run-liminix-vm}/bin/run-liminix-vm --command-line ${cmdline} --arch ${pkgs.stdenv.hostPlatform.qemuArch} --phram-address 0x${phram_address} \$* ${makeBootableImage} ${config.system.outputs.rootfs}
|
|
||||||
EOF
|
|
||||||
chmod +x run.sh
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
@ -55,9 +55,6 @@ let
|
|||||||
run = {
|
run = {
|
||||||
file = ''
|
file = ''
|
||||||
#!${execline}/bin/execlineb -P
|
#!${execline}/bin/execlineb -P
|
||||||
importas PATH PATH
|
|
||||||
export PATH ${s6}/bin:''${PATH}
|
|
||||||
foreground { echo path is ''${PATH} }
|
|
||||||
${s6-linux-init}/bin/s6-linux-init-shutdownd -c "/etc/s6-linux-init/current" -g 3000
|
${s6-linux-init}/bin/s6-linux-init-shutdownd -c "/etc/s6-linux-init/current" -g 3000
|
||||||
'';
|
'';
|
||||||
mode = "0755";
|
mode = "0755";
|
||||||
@ -81,44 +78,26 @@ let
|
|||||||
};
|
};
|
||||||
getty = dir {
|
getty = dir {
|
||||||
run = {
|
run = {
|
||||||
# We can't run a useful shell on /dev/console because
|
|
||||||
# /dev/console is not allowed to be the controlling
|
|
||||||
# tty of any process, which means ^C ^Z etc don't work.
|
|
||||||
# So we work out what the *actual* console device is
|
|
||||||
# using sysfs and open our shell there instead.
|
|
||||||
file = ''
|
file = ''
|
||||||
#!${execline}/bin/execlineb -P
|
#!${execline}/bin/execlineb -P
|
||||||
${execline}/bin/cd /
|
/bin/getty -l /bin/login 115200 /dev/console
|
||||||
redirfd -r 0 /sys/devices/virtual/tty/console/active
|
'';
|
||||||
withstdinas CONSOLETTY
|
|
||||||
importas CONSOLETTY CONSOLETTY
|
|
||||||
redirfd -w 2 /dev/''${CONSOLETTY}
|
|
||||||
fdmove -c 1 2
|
|
||||||
redirfd -r 0 /dev/''${CONSOLETTY}
|
|
||||||
/bin/ash -l
|
|
||||||
'';
|
|
||||||
mode = "0755";
|
mode = "0755";
|
||||||
};
|
};
|
||||||
down-signal = {
|
|
||||||
file = "HUP\n";
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
".s6-svscan" =
|
".s6-svscan" =
|
||||||
let
|
let
|
||||||
openConsole = ''
|
|
||||||
#!${execline}/bin/execlineb -P
|
|
||||||
${execline}/bin/redirfd -w 2 /dev/console
|
|
||||||
${execline}/bin/fdmove -c 1 2
|
|
||||||
'';
|
|
||||||
quit = message: ''
|
quit = message: ''
|
||||||
${openConsole}
|
#!${execline}/bin/execlineb -P
|
||||||
${execline}/bin/foreground { ${s6-linux-init}/bin/s6-linux-init-echo -- ${message} }
|
${execline}/bin/redirfd -w 2 /dev/console
|
||||||
${s6-linux-init}/bin/s6-linux-init-hpr -fr
|
${execline}/bin/fdmove -c 1 2
|
||||||
'';
|
${execline}/bin/foreground { ${s6-linux-init}/bin/s6-linux-init-echo -- ${message} }
|
||||||
|
${s6-linux-init}/bin/s6-linux-init-hpr -fr
|
||||||
|
'';
|
||||||
shutdown = action: ''
|
shutdown = action: ''
|
||||||
#!${execline}/bin/execlineb -P
|
#!${execline}/bin/execlineb -P
|
||||||
${s6-linux-init}/bin/s6-linux-init-shutdown -a #{action} -- now
|
${s6-linux-init}/bin/s6-linux-init-hpr -a #{action} -- now
|
||||||
'';
|
'';
|
||||||
empty = "#!${execline}/bin/execlineb -P\n";
|
empty = "#!${execline}/bin/execlineb -P\n";
|
||||||
in dir {
|
in dir {
|
||||||
crash = {
|
crash = {
|
||||||
@ -126,13 +105,7 @@ let
|
|||||||
mode = "0755";
|
mode = "0755";
|
||||||
};
|
};
|
||||||
finish = {
|
finish = {
|
||||||
file = ''
|
file = quit "s6-svscan exited. Rebooting.";
|
||||||
${openConsole}
|
|
||||||
ifelse { test -x /run/maintenance/exec } { /run/maintenance/exec }
|
|
||||||
foreground { echo "s6-svscan exited. Rebooting." }
|
|
||||||
wait { }
|
|
||||||
${s6-linux-init}/bin/s6-linux-init-hpr -fr
|
|
||||||
'';
|
|
||||||
mode = "0755";
|
mode = "0755";
|
||||||
};
|
};
|
||||||
SIGINT = {
|
SIGINT = {
|
||||||
@ -168,6 +141,7 @@ let
|
|||||||
};
|
};
|
||||||
in {
|
in {
|
||||||
config = {
|
config = {
|
||||||
|
programs.busybox.applets = [ "login" "getty" ];
|
||||||
filesystem = dir {
|
filesystem = dir {
|
||||||
etc = dir {
|
etc = dir {
|
||||||
s6-rc = dir {
|
s6-rc = dir {
|
||||||
|
@ -1,22 +1,18 @@
|
|||||||
#!/bin/sh -e
|
#!/bin/sh -e
|
||||||
|
|
||||||
## s6-linux-init-shutdownd never tells s6-svscan to exit, so if
|
### Things to do *right before* the machine gets rebooted or
|
||||||
## you're running s6-linux-init, it's normal that your
|
### powered off, at the very end of the shutdown sequence,
|
||||||
## .s6-svscan/finish script is not executed.
|
### when all the filesystems are unmounted.
|
||||||
|
|
||||||
## The place where you want to hack things is /etc/rc.shutdown.final,
|
### This is a last resort hook; normally nothing should be
|
||||||
## which is run by the stage 4 script right before the hard reboot.
|
### done here (your rc.shutdown script should have taken care
|
||||||
## So you can do dirty stuff [...] which should clean up the
|
### of everything) and you should leave this script empty.
|
||||||
## s6-supervise and the foreground, and give control to
|
|
||||||
## .s6-svscan/finish.
|
|
||||||
|
|
||||||
## -- Laurent Bercot on skaware mailing list,
|
### Some distributions, however, may need to perform some
|
||||||
## https://skarnet.org/lists/skaware/1913.html
|
### actions after unmounting the filesystems: typically if
|
||||||
|
### an additional teardown action is required on a filesystem
|
||||||
|
### after unmounting it, or if the system needs to be
|
||||||
|
### pivot_rooted before it can be shut down, etc.
|
||||||
|
|
||||||
exec >/dev/console 2>&1
|
### Those are all exceptional cases. If you don't know for
|
||||||
|
### certain that you need to do something here, you don't.
|
||||||
# down, exit supervisor, wait, stay down
|
|
||||||
s6-svc -dxwD /run/service/s6-linux-init-shutdownd
|
|
||||||
# HUP, exit supervisor, wait, down
|
|
||||||
s6-svc -hxwd /run/service/s6-svscan-log
|
|
||||||
s6-svscanctl -b /run/service # abort
|
|
||||||
|
11
modules/standard.nix
Normal file
11
modules/standard.nix
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
# "standard" modules that aren't fundamentally required,
|
||||||
|
# but are probably useful in most common workflows and
|
||||||
|
# you should have to opt out of instead of into
|
||||||
|
imports = [
|
||||||
|
./tftpboot.nix
|
||||||
|
./kexecboot.nix
|
||||||
|
./flashimage.nix
|
||||||
|
./jffs2.nix
|
||||||
|
];
|
||||||
|
}
|
84
modules/tftpboot.nix
Normal file
84
modules/tftpboot.nix
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
{
|
||||||
|
config
|
||||||
|
, pkgs
|
||||||
|
, lib
|
||||||
|
, ...
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
inherit (lib) mkOption types concatStringsSep;
|
||||||
|
cfg = config.boot.tftp;
|
||||||
|
in {
|
||||||
|
imports = [ ./ramdisk.nix ];
|
||||||
|
options.boot.tftp.freeSpaceBytes = mkOption {
|
||||||
|
type = types.int;
|
||||||
|
default = 0;
|
||||||
|
};
|
||||||
|
options.system.outputs = {
|
||||||
|
tftpboot = mkOption {
|
||||||
|
type = types.package;
|
||||||
|
description = ''
|
||||||
|
Directory containing files needed for TFTP booting
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
boot-scr = mkOption {
|
||||||
|
type = types.package;
|
||||||
|
description = ''
|
||||||
|
U-Boot commands to load and boot a kernel and rootfs over TFTP.
|
||||||
|
Copy-paste into the device boot monitor
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
config = {
|
||||||
|
boot.ramdisk.enable = true;
|
||||||
|
|
||||||
|
system.outputs = rec {
|
||||||
|
tftpboot =
|
||||||
|
let o = config.system.outputs; in
|
||||||
|
pkgs.runCommand "tftpboot" {} ''
|
||||||
|
mkdir $out
|
||||||
|
cd $out
|
||||||
|
ln -s ${o.rootfs} rootfs
|
||||||
|
ln -s ${o.kernel} vmlinux
|
||||||
|
ln -s ${o.manifest} manifest
|
||||||
|
ln -s ${o.kernel.headers} build
|
||||||
|
ln -s ${o.uimage} uimage
|
||||||
|
ln -s ${o.boot-scr}/dtb dtb
|
||||||
|
ln -s ${o.boot-scr}/script boot.scr
|
||||||
|
'';
|
||||||
|
|
||||||
|
boot-scr =
|
||||||
|
let
|
||||||
|
inherit (pkgs.lib.trivial) toHexString;
|
||||||
|
o = config.system.outputs;
|
||||||
|
cmdline = concatStringsSep " " config.boot.commandLine;
|
||||||
|
in
|
||||||
|
pkgs.buildPackages.runCommand "boot-scr" { nativeBuildInputs = [ pkgs.pkgsBuildBuild.dtc ]; } ''
|
||||||
|
uimageSize=$(($(stat -L -c %s ${o.uimage}) + 0x1000 &(~0xfff)))
|
||||||
|
rootfsStart=0x$(printf %x $((${cfg.loadAddress} + 0x100000 + $uimageSize &(~0xfffff) )))
|
||||||
|
rootfsBytes=$(($(stat -L -c %s ${o.rootfs}) + 0x100000 &(~0xfffff)))
|
||||||
|
rootfsMb=$(($rootfsBytes >> 20))
|
||||||
|
rootfsBytes=$(($rootfsBytes + ${toString cfg.freeSpaceBytes} ))
|
||||||
|
cmd="mtdparts=phram0:''${rootfsMb}M(rootfs) phram.phram=phram0,''${rootfsStart},''${rootfsBytes},${config.hardware.flash.eraseBlockSize} root=/dev/mtdblock0";
|
||||||
|
|
||||||
|
dtbStart=$(printf %x $((${cfg.loadAddress} + $rootfsBytes + 0x100000 + $uimageSize )))
|
||||||
|
|
||||||
|
mkdir $out
|
||||||
|
dtc -I dtb -O dts -o tmp.dts ${o.dtb}
|
||||||
|
echo "/ { reserved-memory { phram: phram@$rootfsStart {compatible = \"phram\"; reg = <0x0 $rootfsStart 0x0 $(printf "0x%x" $rootfsBytes )>; }; }; } ;" >> tmp.dts
|
||||||
|
cat tmp.dts
|
||||||
|
|
||||||
|
dtc -I dts -O dtb -o $out/dtb tmp.dts
|
||||||
|
dtbBytes=$(($(stat -L -c %s $out/dtb) + 0x1000 &(~0xfff)))
|
||||||
|
|
||||||
|
cat > $out/script << EOF
|
||||||
|
setenv serverip ${cfg.serverip}
|
||||||
|
setenv ipaddr ${cfg.ipaddr}
|
||||||
|
setenv bootargs 'liminix ${cmdline} $cmd'
|
||||||
|
tftpboot 0x$(printf %x ${cfg.loadAddress}) result/uimage ; tftpboot 0x$(printf %x $rootfsStart) result/rootfs ; tftpboot 0x$dtbStart result/dtb
|
||||||
|
bootm 0x$(printf %x ${cfg.loadAddress}) - 0x$dtbStart
|
||||||
|
#
|
||||||
|
EOF
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
199
overlay.nix
199
overlay.nix
@ -44,12 +44,20 @@ let
|
|||||||
lua = let s = lua_no_readline.override { self = s; }; in s;
|
lua = let s = lua_no_readline.override { self = s; }; in s;
|
||||||
in
|
in
|
||||||
extraPkgs // {
|
extraPkgs // {
|
||||||
# liminix library functions
|
mtdutils = prev.mtdutils.overrideAttrs(o: {
|
||||||
lim = {
|
patches = (if o ? patches then o.patches else []) ++ [
|
||||||
parseInt = s : (builtins.fromTOML "r=${s}").r;
|
./pkgs/mtdutils/0001-mkfs.jffs2-add-graft-option.patch
|
||||||
};
|
];
|
||||||
|
});
|
||||||
|
|
||||||
|
rsyncSmall =
|
||||||
|
let r = prev.rsync.overrideAttrs(o: {
|
||||||
|
configureFlags = o.configureFlags ++ [
|
||||||
|
"--disable-openssl"
|
||||||
|
];
|
||||||
|
});
|
||||||
|
in r.override { openssl = null; };
|
||||||
|
|
||||||
# keep these alphabetical
|
|
||||||
chrony =
|
chrony =
|
||||||
let chrony' = prev.chrony.overrideAttrs(o: {
|
let chrony' = prev.chrony.overrideAttrs(o: {
|
||||||
configureFlags = [
|
configureFlags = [
|
||||||
@ -71,6 +79,49 @@ extraPkgs // {
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
strace = prev.strace.override { libunwind = null; };
|
||||||
|
|
||||||
|
kexec-tools-static = prev.kexec-tools.overrideAttrs(o: {
|
||||||
|
# For kexecboot we copy kexec into a ramdisk on the system being
|
||||||
|
# upgraded from. This is more likely to work if kexec is
|
||||||
|
# statically linked so doesn't have dependencies on store paths that
|
||||||
|
# may not exist on that machine. (We can't nix-copy-closure as
|
||||||
|
# the store may not be on a writable filesystem)
|
||||||
|
LDFLAGS = "-static";
|
||||||
|
|
||||||
|
patches = o.patches ++ [
|
||||||
|
(fetchpatch {
|
||||||
|
# merge user command line options into DTB chosen
|
||||||
|
url = "https://patch-diff.githubusercontent.com/raw/horms/kexec-tools/pull/3.patch";
|
||||||
|
hash = "sha256-MvlJhuex9dlawwNZJ1sJ33YPWn1/q4uKotqkC/4d2tk=";
|
||||||
|
})
|
||||||
|
pkgs/kexec-map-file.patch
|
||||||
|
];
|
||||||
|
});
|
||||||
|
|
||||||
|
luaFull = prev.lua;
|
||||||
|
inherit lua;
|
||||||
|
|
||||||
|
inherit s6;
|
||||||
|
s6-linux-init = prev.s6-linux-init.override {
|
||||||
|
skawarePackages = prev.skawarePackages // {
|
||||||
|
inherit s6;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
s6-rc = prev.s6-rc.override {
|
||||||
|
skawarePackages = prev.skawarePackages // {
|
||||||
|
inherit s6;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
nftables = prev.nftables.overrideAttrs(o: {
|
||||||
|
configureFlags = [
|
||||||
|
"--disable-debug"
|
||||||
|
"--disable-python"
|
||||||
|
"--with-mini-gmp"
|
||||||
|
"--without-cli"
|
||||||
|
];
|
||||||
|
});
|
||||||
|
|
||||||
dnsmasq =
|
dnsmasq =
|
||||||
let d = prev.dnsmasq.overrideAttrs(o: {
|
let d = prev.dnsmasq.overrideAttrs(o: {
|
||||||
@ -83,15 +134,6 @@ extraPkgs // {
|
|||||||
nettle = null;
|
nettle = null;
|
||||||
};
|
};
|
||||||
|
|
||||||
dropbear = prev.dropbear.overrideAttrs (o: {
|
|
||||||
postPatch = ''
|
|
||||||
(echo '#define DSS_PRIV_FILENAME "/run/dropbear/dropbear_dss_host_key"'
|
|
||||||
echo '#define RSA_PRIV_FILENAME "/run/dropbear/dropbear_rsa_host_key"'
|
|
||||||
echo '#define ECDSA_PRIV_FILENAME "/run/dropbear/dropbear_ecdsa_host_key"'
|
|
||||||
echo '#define ED25519_PRIV_FILENAME "/run/dropbear/dropbear_ed25519_host_key"') > localoptions.h
|
|
||||||
'';
|
|
||||||
});
|
|
||||||
|
|
||||||
hostapd =
|
hostapd =
|
||||||
let
|
let
|
||||||
config = [
|
config = [
|
||||||
@ -119,40 +161,13 @@ extraPkgs // {
|
|||||||
});
|
});
|
||||||
in h.override { openssl = null; sqlite = null; };
|
in h.override { openssl = null; sqlite = null; };
|
||||||
|
|
||||||
kexec-tools-static = prev.kexec-tools.overrideAttrs(o: {
|
dropbear = prev.dropbear.overrideAttrs (o: {
|
||||||
# For kexecboot we copy kexec into a ramdisk on the system being
|
postPatch = ''
|
||||||
# upgraded from. This is more likely to work if kexec is
|
(echo '#define DSS_PRIV_FILENAME "/run/dropbear/dropbear_dss_host_key"'
|
||||||
# statically linked so doesn't have dependencies on store paths that
|
echo '#define RSA_PRIV_FILENAME "/run/dropbear/dropbear_rsa_host_key"'
|
||||||
# may not exist on that machine. (We can't nix-copy-closure as
|
echo '#define ECDSA_PRIV_FILENAME "/run/dropbear/dropbear_ecdsa_host_key"'
|
||||||
# the store may not be on a writable filesystem)
|
echo '#define ED25519_PRIV_FILENAME "/run/dropbear/dropbear_ed25519_host_key"') > localoptions.h
|
||||||
LDFLAGS = "-static";
|
'';
|
||||||
|
|
||||||
patches = o.patches ++ [
|
|
||||||
(fetchpatch {
|
|
||||||
# merge user command line options into DTB chosen
|
|
||||||
url = "https://patch-diff.githubusercontent.com/raw/horms/kexec-tools/pull/3.patch";
|
|
||||||
hash = "sha256-MvlJhuex9dlawwNZJ1sJ33YPWn1/q4uKotqkC/4d2tk=";
|
|
||||||
})
|
|
||||||
pkgs/kexec-map-file.patch
|
|
||||||
];
|
|
||||||
});
|
|
||||||
|
|
||||||
luaFull = prev.lua;
|
|
||||||
inherit lua;
|
|
||||||
|
|
||||||
mtdutils = prev.mtdutils.overrideAttrs(o: {
|
|
||||||
patches = (if o ? patches then o.patches else []) ++ [
|
|
||||||
./pkgs/mtdutils/0001-mkfs.jffs2-add-graft-option.patch
|
|
||||||
];
|
|
||||||
});
|
|
||||||
|
|
||||||
nftables = prev.nftables.overrideAttrs(o: {
|
|
||||||
configureFlags = [
|
|
||||||
"--disable-debug"
|
|
||||||
"--disable-python"
|
|
||||||
"--with-mini-gmp"
|
|
||||||
"--without-cli"
|
|
||||||
];
|
|
||||||
});
|
});
|
||||||
|
|
||||||
openssl = prev.openssl.overrideAttrs (o: {
|
openssl = prev.openssl.overrideAttrs (o: {
|
||||||
@ -169,92 +184,4 @@ extraPkgs // {
|
|||||||
});
|
});
|
||||||
|
|
||||||
pppBuild = prev.ppp;
|
pppBuild = prev.ppp;
|
||||||
|
|
||||||
qemuLim = let q = prev.qemu.overrideAttrs (o: {
|
|
||||||
patches = o.patches ++ [
|
|
||||||
./pkgs/qemu/arm-image-friendly-load-addr.patch
|
|
||||||
];
|
|
||||||
}); in q.override { nixosTestRunner = true; sdlSupport = false; };
|
|
||||||
|
|
||||||
rsyncSmall =
|
|
||||||
let r = prev.rsync.overrideAttrs(o: {
|
|
||||||
configureFlags = o.configureFlags ++ [
|
|
||||||
"--disable-openssl"
|
|
||||||
];
|
|
||||||
});
|
|
||||||
in r.override { openssl = null; };
|
|
||||||
|
|
||||||
|
|
||||||
inherit s6;
|
|
||||||
s6-linux-init = prev.s6-linux-init.override {
|
|
||||||
skawarePackages = prev.skawarePackages // {
|
|
||||||
inherit s6;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
s6-rc = prev.s6-rc.override {
|
|
||||||
skawarePackages = prev.skawarePackages // {
|
|
||||||
inherit s6;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
strace = prev.strace.override { libunwind = null; };
|
|
||||||
|
|
||||||
ubootQemuAarch64 = final.buildUBoot {
|
|
||||||
defconfig = "qemu_arm64_defconfig";
|
|
||||||
extraMeta.platforms = ["aarch64-linux"];
|
|
||||||
filesToInstall = ["u-boot.bin"];
|
|
||||||
};
|
|
||||||
|
|
||||||
ubootQemuArm = final.buildUBoot {
|
|
||||||
defconfig = "qemu_arm_defconfig";
|
|
||||||
extraMeta.platforms = ["armv7l-linux"];
|
|
||||||
filesToInstall = ["u-boot.bin"];
|
|
||||||
extraConfig = ''
|
|
||||||
CONFIG_CMD_UBI=y
|
|
||||||
CONFIG_CMD_UBIFS=y
|
|
||||||
CONFIG_BOOTSTD=y
|
|
||||||
CONFIG_BOOTMETH_DISTRO=y
|
|
||||||
CONFIG_LZMA=y
|
|
||||||
CONFIG_CMD_LZMADEC=y
|
|
||||||
CONFIG_SYS_BOOTM_LEN=0x1000000
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
ubootQemuMips = final.buildUBoot {
|
|
||||||
defconfig = "malta_defconfig";
|
|
||||||
extraMeta.platforms = ["mips-linux"];
|
|
||||||
filesToInstall = ["u-boot.bin"];
|
|
||||||
# define the prompt to be the same as arm{32,64} so
|
|
||||||
# we can use the same expect script for both
|
|
||||||
extraPatches = [ ./pkgs/u-boot/0002-virtio-init-for-malta.patch ];
|
|
||||||
extraConfig = ''
|
|
||||||
CONFIG_SYS_PROMPT="=> "
|
|
||||||
CONFIG_VIRTIO=y
|
|
||||||
CONFIG_AUTOBOOT=y
|
|
||||||
CONFIG_DM_PCI=y
|
|
||||||
CONFIG_VIRTIO_PCI=y
|
|
||||||
CONFIG_VIRTIO_NET=y
|
|
||||||
CONFIG_VIRTIO_BLK=y
|
|
||||||
CONFIG_VIRTIO_MMIO=y
|
|
||||||
CONFIG_QFW_MMIO=y
|
|
||||||
CONFIG_FIT=y
|
|
||||||
CONFIG_LZMA=y
|
|
||||||
CONFIG_CMD_LZMADEC=y
|
|
||||||
CONFIG_SYS_BOOTM_LEN=0x1000000
|
|
||||||
CONFIG_SYS_MALLOC_LEN=0x400000
|
|
||||||
CONFIG_MIPS_BOOT_FDT=y
|
|
||||||
CONFIG_OF_LIBFDT=y
|
|
||||||
CONFIG_OF_STDOUT_VIA_ALIAS=y
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
util-linux-small = prev.util-linux.override {
|
|
||||||
ncursesSupport = false;
|
|
||||||
pamSupport = false;
|
|
||||||
systemdSupport = false;
|
|
||||||
nlsSupport = false;
|
|
||||||
translateManpages = false;
|
|
||||||
capabilitiesSupport = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -102,8 +102,4 @@ in {
|
|||||||
fennel = callPackage ./fennel {};
|
fennel = callPackage ./fennel {};
|
||||||
fennelrepl = callPackage ./fennelrepl {};
|
fennelrepl = callPackage ./fennelrepl {};
|
||||||
anoia = callPackage ./anoia {};
|
anoia = callPackage ./anoia {};
|
||||||
|
|
||||||
levitate = callPackage ./levitate {};
|
|
||||||
|
|
||||||
libubootenv = callPackage ./libubootenv {};
|
|
||||||
}
|
}
|
||||||
|
@ -7,13 +7,16 @@
|
|||||||
, config
|
, config
|
||||||
, src
|
, src
|
||||||
, extraPatchPhase ? "echo"
|
, extraPatchPhase ? "echo"
|
||||||
, targets ? ["vmlinux"]
|
|
||||||
} :
|
} :
|
||||||
let
|
let
|
||||||
writeConfig = import ./write-kconfig.nix { inherit lib writeText; };
|
writeConfig = import ./write-kconfig.nix { inherit lib writeText; };
|
||||||
kconfigFile = writeConfig "kconfig" config;
|
kconfigFile = writeConfig "kconfig" config;
|
||||||
arch = stdenv.hostPlatform.linuxArch;
|
arch = if stdenv.isMips
|
||||||
targetNames = map baseNameOf targets;
|
then "mips"
|
||||||
|
else if stdenv.isAarch64
|
||||||
|
then "arm64"
|
||||||
|
else throw "unknown arch";
|
||||||
|
|
||||||
inherit lib; in
|
inherit lib; in
|
||||||
stdenv.mkDerivation rec {
|
stdenv.mkDerivation rec {
|
||||||
name = "kernel";
|
name = "kernel";
|
||||||
@ -36,7 +39,7 @@ stdenv.mkDerivation rec {
|
|||||||
|
|
||||||
dontStrip = true;
|
dontStrip = true;
|
||||||
dontPatchELF = true;
|
dontPatchELF = true;
|
||||||
outputs = ["out" "headers" "modulesupport"] ++ targetNames;
|
outputs = ["out" "headers" "modulesupport"];
|
||||||
phases = [
|
phases = [
|
||||||
"unpackPhase"
|
"unpackPhase"
|
||||||
"butcherPkgconfig"
|
"butcherPkgconfig"
|
||||||
@ -52,7 +55,6 @@ stdenv.mkDerivation rec {
|
|||||||
patches = [
|
patches = [
|
||||||
./cmdline-cookie.patch
|
./cmdline-cookie.patch
|
||||||
./phram-allow-cached-mappings.patch
|
./phram-allow-cached-mappings.patch
|
||||||
./mips-malta-fdt-from-bootloader.patch
|
|
||||||
];
|
];
|
||||||
|
|
||||||
# this is here to work around what I think is a bug in nixpkgs
|
# this is here to work around what I think is a bug in nixpkgs
|
||||||
@ -93,12 +95,11 @@ stdenv.mkDerivation rec {
|
|||||||
'';
|
'';
|
||||||
|
|
||||||
buildPhase = ''
|
buildPhase = ''
|
||||||
make ${lib.concatStringsSep " " targetNames} modules_prepare -j$NIX_BUILD_CORES
|
make vmlinux modules_prepare
|
||||||
'';
|
'';
|
||||||
|
|
||||||
installPhase = ''
|
installPhase = ''
|
||||||
${CROSS_COMPILE}strip -d vmlinux
|
${CROSS_COMPILE}strip -d vmlinux
|
||||||
${lib.concatStringsSep "\n" (map (f: "cp ${f} \$${baseNameOf f}") targets)}
|
|
||||||
cp vmlinux $out
|
cp vmlinux $out
|
||||||
mkdir -p $headers
|
mkdir -p $headers
|
||||||
cp -a include .config $headers/
|
cp -a include .config $headers/
|
||||||
@ -107,4 +108,5 @@ stdenv.mkDerivation rec {
|
|||||||
make clean modules_prepare
|
make clean modules_prepare
|
||||||
cp -a . $modulesupport
|
cp -a . $modulesupport
|
||||||
'';
|
'';
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/dts-v1/;
|
/dts-v1/;
|
||||||
|
|
||||||
// used on arm/aarch64 to provide a U-bootable image that combines
|
// used on aarch64 to provide a U-bootable image that combines
|
||||||
// kernel and fdt
|
// kernel and fdt
|
||||||
|
|
||||||
/ {
|
/ {
|
||||||
@ -12,7 +12,7 @@
|
|||||||
description = "Vanilla Linux kernel";
|
description = "Vanilla Linux kernel";
|
||||||
// data = /incbin/("./vmlinux.bin.gz");
|
// data = /incbin/("./vmlinux.bin.gz");
|
||||||
type = "kernel";
|
type = "kernel";
|
||||||
// arch = "arm64";
|
arch = "arm64";
|
||||||
os = "linux";
|
os = "linux";
|
||||||
// compression = "gzip";
|
// compression = "gzip";
|
||||||
// load = <00000000>;
|
// load = <00000000>;
|
||||||
@ -28,7 +28,7 @@
|
|||||||
description = "Flattened Device Tree blob";
|
description = "Flattened Device Tree blob";
|
||||||
// data = /incbin/("./target.dtb");
|
// data = /incbin/("./target.dtb");
|
||||||
type = "flat_dt";
|
type = "flat_dt";
|
||||||
// arch = "arm64";
|
arch = "arm64";
|
||||||
compression = "none";
|
compression = "none";
|
||||||
hash-1 {
|
hash-1 {
|
||||||
algo = "crc32";
|
algo = "crc32";
|
||||||
|
@ -1,15 +0,0 @@
|
|||||||
diff --git a/arch/mips/mti-malta/malta-setup.c b/arch/mips/mti-malta/malta-setup.c
|
|
||||||
index 21cb3ac1237b..52e731f9b4e2 100644
|
|
||||||
--- a/arch/mips/mti-malta/malta-setup.c
|
|
||||||
+++ b/arch/mips/mti-malta/malta-setup.c
|
|
||||||
@@ -192,7 +192,9 @@ static void __init bonito_quirks_setup(void)
|
|
||||||
|
|
||||||
void __init *plat_get_fdt(void)
|
|
||||||
{
|
|
||||||
- return (void *)__dtb_start;
|
|
||||||
+ return (fw_arg0 == -2) ?
|
|
||||||
+ (void *) (KSEG1ADDR(fw_arg1)) :
|
|
||||||
+ (void *) __dtb_start;
|
|
||||||
}
|
|
||||||
|
|
||||||
void __init plat_mem_setup(void)
|
|
@ -7,27 +7,21 @@
|
|||||||
} :
|
} :
|
||||||
let
|
let
|
||||||
objcopy = "${stdenv.cc.bintools.targetPrefix}objcopy";
|
objcopy = "${stdenv.cc.bintools.targetPrefix}objcopy";
|
||||||
arch = stdenv.hostPlatform.linuxArch;
|
|
||||||
stripAndZip = ''
|
|
||||||
${objcopy} -O binary -R .reginfo -R .notes -R .note -R .comment -R .mdebug -R .note.gnu.build-id -S vmlinux.elf vmlinux.bin
|
|
||||||
rm -f vmlinux.bin.lzma ; lzma -k -z vmlinux.bin
|
|
||||||
'';
|
|
||||||
in {
|
in {
|
||||||
kernel
|
kernel
|
||||||
, commandLine
|
, commandLine
|
||||||
, entryPoint
|
, entryPoint
|
||||||
, extraName ? "" # e.g. socFamily
|
, extraName ? "" # e.g. socFamily
|
||||||
, loadAddress
|
, loadAddress
|
||||||
, imageFormat
|
|
||||||
, dtb ? null
|
, dtb ? null
|
||||||
} : stdenv.mkDerivation {
|
} :
|
||||||
|
stdenv.mkDerivation {
|
||||||
name = "kernel.image";
|
name = "kernel.image";
|
||||||
phases = [
|
phases = [
|
||||||
"preparePhase"
|
"preparePhase"
|
||||||
(if commandLine != null then assert dtb != null; "mungeDtbPhase" else ":")
|
(if dtb != null then "dtbPhase" else ":")
|
||||||
(if imageFormat == "fit" then "buildPhaseFIT" else "buildPhaseUImage")
|
"buildPhase"
|
||||||
"installPhase"
|
"installPhase" ];
|
||||||
];
|
|
||||||
nativeBuildInputs = [
|
nativeBuildInputs = [
|
||||||
lzma
|
lzma
|
||||||
dtc
|
dtc
|
||||||
@ -37,43 +31,35 @@ in {
|
|||||||
preparePhase = ''
|
preparePhase = ''
|
||||||
cp ${kernel} vmlinux.elf; chmod +w vmlinux.elf
|
cp ${kernel} vmlinux.elf; chmod +w vmlinux.elf
|
||||||
'';
|
'';
|
||||||
mungeDtbPhase = ''
|
dtbPhase = ''
|
||||||
dtc -I dtb -O dts -o tmp.dts ${dtb}
|
dtc -I dtb -O dts -o tmp.dts ${dtb}
|
||||||
echo '/{ chosen { bootargs = ${builtins.toJSON commandLine}; }; };' >> tmp.dts
|
echo '/{ chosen { bootargs = ${builtins.toJSON commandLine}; }; };' >> tmp.dts
|
||||||
dtc -I dts -O dtb -o tmp.dtb tmp.dts
|
dtc -I dts -O dtb -o tmp.dtb tmp.dts
|
||||||
'';
|
'';
|
||||||
|
|
||||||
buildPhaseUImage = ''
|
buildPhase =
|
||||||
test -f tmp.dtb && ${objcopy} --update-section .appended_dtb=tmp.dtb vmlinux.elf || ${objcopy} --add-section .appended_dtb=tmp.dtb vmlinux.elf
|
let arch =
|
||||||
${stripAndZip}
|
# per output of "mkimage -A list". I *think* these
|
||||||
mkimage -A ${arch} -O linux -T kernel -C lzma -a 0x${lib.toHexString loadAddress} -e 0x${lib.toHexString entryPoint} -n '${lib.toUpper arch} Liminix Linux ${extraName}' -d vmlinux.bin.lzma kernel.uimage
|
# are the same as the kernel arch convention, but
|
||||||
'';
|
# maybe that's coincidence
|
||||||
|
if stdenv.isMips
|
||||||
buildPhaseFIT = ''
|
then "mips"
|
||||||
${stripAndZip}
|
else if stdenv.isAarch64
|
||||||
cat ${./kernel_fdt.its} > mkimage.its
|
then "arm64"
|
||||||
cat << _VARS >> mkimage.its
|
else throw "unknown arch";
|
||||||
/ {
|
in ''
|
||||||
images {
|
${objcopy} -O binary -R .reginfo -R .notes -R .note -R .comment -R .mdebug -R .note.gnu.build-id -S vmlinux.elf vmlinux.bin
|
||||||
kernel {
|
rm -f vmlinux.bin.lzma ; lzma -k -z vmlinux.bin
|
||||||
data = /incbin/("./vmlinux.bin.lzma");
|
cat ${./kernel_fdt.its} > mkimage.its
|
||||||
load = <0x${lib.toHexString loadAddress}>;
|
echo '/ { images { kernel { data = /incbin/("./vmlinux.bin.lzma"); }; }; };' >> mkimage.its
|
||||||
entry = <0x${lib.toHexString entryPoint}>;
|
echo '/ { images { kernel { load = <${loadAddress}>; }; }; };' >> mkimage.its
|
||||||
arch = "${arch}";
|
echo '/ { images { kernel { entry = <${entryPoint}>; }; }; };' >> mkimage.its
|
||||||
compression = "lzma";
|
echo '/ { images { kernel { compression = "lzma"; }; }; };' >> mkimage.its
|
||||||
};
|
echo '/ { images { fdt-1 { data = /incbin/("./tmp.dtb"); }; }; }; ' >> mkimage.its
|
||||||
fdt-1 {
|
mkimage -f mkimage.its mkimage.itb
|
||||||
data = /incbin/("./tmp.dtb");
|
mkimage -l mkimage.itb
|
||||||
arch = "${arch}";
|
'';
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
_VARS
|
|
||||||
mkimage -f mkimage.its kernel.uimage
|
|
||||||
mkimage -l kernel.uimage
|
|
||||||
'';
|
|
||||||
|
|
||||||
installPhase = ''
|
installPhase = ''
|
||||||
cp kernel.uimage $out
|
cp mkimage.itb $out
|
||||||
'';
|
'';
|
||||||
}
|
}
|
||||||
|
@ -1,75 +0,0 @@
|
|||||||
{
|
|
||||||
writeScriptBin
|
|
||||||
, writeScript
|
|
||||||
, systemconfig
|
|
||||||
, execline
|
|
||||||
, lib
|
|
||||||
, services ? null
|
|
||||||
, liminix
|
|
||||||
, pseudofile
|
|
||||||
, pkgs
|
|
||||||
} :
|
|
||||||
let
|
|
||||||
inherit (pseudofile) dir symlink;
|
|
||||||
inherit (liminix.services) oneshot;
|
|
||||||
newRoot = "/run/maintenance";
|
|
||||||
sysconfig =
|
|
||||||
let
|
|
||||||
doChroot = writeScript "exec" ''
|
|
||||||
#!${execline}/bin/execlineb -P
|
|
||||||
cd ${newRoot}
|
|
||||||
foreground { mount --move ${newRoot} / }
|
|
||||||
redirfd -r 0 /dev/console
|
|
||||||
redirfd -w 1 /dev/console
|
|
||||||
fdmove -c 2 1
|
|
||||||
emptyenv chroot . /bin/init
|
|
||||||
'';
|
|
||||||
base = {...} : {
|
|
||||||
config = {
|
|
||||||
services = services // {
|
|
||||||
banner = oneshot {
|
|
||||||
name = "banner";
|
|
||||||
up = "cat /etc/banner > /dev/console";
|
|
||||||
down = "true";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
filesystem = dir {
|
|
||||||
exec = symlink doChroot;
|
|
||||||
etc = dir {
|
|
||||||
banner = symlink (pkgs.writeText "banner" ''
|
|
||||||
|
|
||||||
LADIES AND GENTLEMEN WE ARE FLOATING IN SPACE
|
|
||||||
|
|
||||||
Most services are disabled. The system is operating
|
|
||||||
with a ram-based root filesystem, making it safe to
|
|
||||||
overwrite the flash devices in order to perform
|
|
||||||
upgrades and maintenance.
|
|
||||||
|
|
||||||
Don't forget to reboot when you have finished.
|
|
||||||
|
|
||||||
'');
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
eval = lib.evalModules {
|
|
||||||
modules = [
|
|
||||||
{ _module.args = { inherit pkgs; inherit (pkgs) lim; }; }
|
|
||||||
../../modules/base.nix
|
|
||||||
../../modules/users.nix
|
|
||||||
../../modules/busybox.nix
|
|
||||||
base
|
|
||||||
../../modules/s6
|
|
||||||
];
|
|
||||||
};
|
|
||||||
in systemconfig eval.config.filesystem.contents;
|
|
||||||
in writeScriptBin "levitate" ''
|
|
||||||
#!/bin/sh
|
|
||||||
destdir=${newRoot}
|
|
||||||
mkdir -p $destdir $destdir/nix/store
|
|
||||||
for path in $(cat ${sysconfig}/etc/nix-store-paths) ; do
|
|
||||||
(cd $destdir && cp -a $path .$path)
|
|
||||||
done
|
|
||||||
${sysconfig}/bin/activate $destdir
|
|
||||||
''
|
|
@ -1,6 +0,0 @@
|
|||||||
CFLAGS=$(INC) -D_LINUX_TYPES_H -D_LINUX_STRING_H_
|
|
||||||
|
|
||||||
fw_printenv: fw_env_main.o fw_env.o \
|
|
||||||
crc32.o ctype.o linux_string.o \
|
|
||||||
env_attr.o env_flags.o
|
|
||||||
$(CC) -o $@ $^
|
|
@ -1,17 +0,0 @@
|
|||||||
{ stdenv
|
|
||||||
, cmake
|
|
||||||
, zlib
|
|
||||||
, libyaml
|
|
||||||
, fetchFromGitHub
|
|
||||||
} :
|
|
||||||
stdenv.mkDerivation {
|
|
||||||
name = "libubootenv";
|
|
||||||
src = fetchFromGitHub {
|
|
||||||
owner = "sbabic";
|
|
||||||
repo = "libubootenv";
|
|
||||||
rev = "3f4d15e36ceb58085b08dd13f3f2788e9299877b"; # v0.3.5
|
|
||||||
hash = "sha256-i7gUb1A6FTOBCpympQpndhOG9pCDA4P0iH7ZNBqo+PA=";
|
|
||||||
};
|
|
||||||
buildInputs = [ zlib libyaml ];
|
|
||||||
nativeBuildInputs = [ cmake ];
|
|
||||||
}
|
|
@ -18,7 +18,8 @@ let
|
|||||||
${commands}
|
${commands}
|
||||||
'';
|
'';
|
||||||
cleanupScript = name : ''
|
cleanupScript = name : ''
|
||||||
if test -d ${prefix}/${name} ; then rm -rf ${prefix}/${name} ; fi
|
#!/bin/sh
|
||||||
|
test -d ${prefix}/${name} && rm -rf ${prefix}/${name}
|
||||||
'';
|
'';
|
||||||
service = {
|
service = {
|
||||||
name
|
name
|
||||||
|
@ -14,7 +14,11 @@
|
|||||||
, lib
|
, lib
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
arch = stdenv.hostPlatform.linuxArch;
|
arch = if stdenv.isMips
|
||||||
|
then "mips"
|
||||||
|
else if stdenv.isAarch64
|
||||||
|
then "arm64"
|
||||||
|
else throw "unknown arch";
|
||||||
openwrtSrc = fetchFromGitHub {
|
openwrtSrc = fetchFromGitHub {
|
||||||
name = "openwrt-source";
|
name = "openwrt-source";
|
||||||
repo = "openwrt";
|
repo = "openwrt";
|
||||||
@ -25,52 +29,47 @@ let
|
|||||||
inherit (liminix.services) oneshot longrun;
|
inherit (liminix.services) oneshot longrun;
|
||||||
inherit (lib.lists) foldl;
|
inherit (lib.lists) foldl;
|
||||||
configs = {
|
configs = {
|
||||||
ath9k.kconfig = {
|
ath9k = {
|
||||||
WLAN_VENDOR_ATH = "y";
|
WLAN_VENDOR_ATH = "y";
|
||||||
ATH_COMMON = "m";
|
ATH_COMMON = "m";
|
||||||
ATH9K = "m";
|
ATH9K = "m";
|
||||||
ATH9K_AHB = "y";
|
ATH9K_AHB = "y";
|
||||||
|
# ATH9K_DEBUGFS = "y";
|
||||||
|
# ATH_DEBUG = "y";
|
||||||
BACKPORTED_ATH9K_AHB = "y";
|
BACKPORTED_ATH9K_AHB = "y";
|
||||||
};
|
};
|
||||||
ath9k_pci = {
|
ath10k_pci = {
|
||||||
module = "ath9k";
|
|
||||||
kconfig = {
|
|
||||||
WLAN_VENDOR_ATH = "y";
|
|
||||||
ATH_COMMON = "m";
|
|
||||||
ATH9K = "m";
|
|
||||||
ATH9K_PCI = "y";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
ath10k_pci.kconfig = {
|
|
||||||
WLAN_VENDOR_ATH = "y";
|
WLAN_VENDOR_ATH = "y";
|
||||||
ATH_COMMON = "m";
|
ATH_COMMON = "m";
|
||||||
ATH10K = "m";
|
ATH10K = "m";
|
||||||
|
# BACKPORTED_ATH10K_AHB = "y";
|
||||||
|
# ATH10K_AHB = "y";
|
||||||
ATH10K_PCI = "y";
|
ATH10K_PCI = "y";
|
||||||
ATH10K_DEBUG = "y";
|
ATH10K_DEBUG = "y";
|
||||||
};
|
};
|
||||||
rt2800soc.kconfig = {
|
rt2800soc = {
|
||||||
WLAN_VENDOR_RALINK = "y";
|
WLAN_VENDOR_RALINK = "y";
|
||||||
RT2800SOC = "m";
|
RT2800SOC = "m";
|
||||||
RT2X00 = "m";
|
RT2X00 = "m";
|
||||||
};
|
};
|
||||||
mt7603e.kconfig = { # XXX find a better name for this
|
mt7603e = { # XXX find a better name for this
|
||||||
WLAN_VENDOR_RALINK = "y";
|
WLAN_VENDOR_RALINK = "y";
|
||||||
WLAN_VENDOR_MEDIATEK = "y";
|
WLAN_VENDOR_MEDIATEK = "y";
|
||||||
MT7603E = "y";
|
MT7603E = "y";
|
||||||
};
|
};
|
||||||
|
|
||||||
mt7915e.kconfig = {
|
mt7915e = {
|
||||||
MT7915E = "m";
|
MT7915E = "m";
|
||||||
};
|
};
|
||||||
mt7615e.kconfig = {
|
mt7615e = {
|
||||||
MT7615E = "m";
|
MT7615E = "m";
|
||||||
MT7622_WMAC = "y";
|
MT7622_WMAC = "y";
|
||||||
};
|
};
|
||||||
mac80211_hwsim.kconfig = {
|
mac80211_hwsim = {
|
||||||
MAC80211_HWSIM = "y";
|
MAC80211_HWSIM = "y";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
kconfig = (foldl (config: d: (config // configs.${d}.kconfig)) {
|
kconfig = (foldl (config: d: (config // configs.${d})) {
|
||||||
WLAN = "y";
|
WLAN = "y";
|
||||||
CFG80211 = "m";
|
CFG80211 = "m";
|
||||||
MAC80211 = "m";
|
MAC80211 = "m";
|
||||||
@ -87,6 +86,7 @@ let
|
|||||||
CFG80211_CRDA_SUPPORT = "n";
|
CFG80211_CRDA_SUPPORT = "n";
|
||||||
|
|
||||||
MAC80211_MESH = "y";
|
MAC80211_MESH = "y";
|
||||||
|
|
||||||
} drivers) // extraConfig;
|
} drivers) // extraConfig;
|
||||||
|
|
||||||
writeConfig = name : config: writeText name
|
writeConfig = name : config: writeText name
|
||||||
@ -166,11 +166,7 @@ let
|
|||||||
find . -name \*.ko | cpio --make-directories -p $out/lib/modules/0.0
|
find . -name \*.ko | cpio --make-directories -p $out/lib/modules/0.0
|
||||||
depmod -b $out -v 0.0
|
depmod -b $out -v 0.0
|
||||||
touch $out/load.sh
|
touch $out/load.sh
|
||||||
for i in ${lib.concatStringsSep " "
|
for i in ${lib.concatStringsSep " " drivers}; do
|
||||||
(map
|
|
||||||
(d: let c = { module = d; } // configs.${d} ;
|
|
||||||
in c.module)
|
|
||||||
drivers)}; do
|
|
||||||
modprobe -S 0.0 -d $out --show-depends $i >> $out/load.sh
|
modprobe -S 0.0 -d $out --show-depends $i >> $out/load.sh
|
||||||
done
|
done
|
||||||
tac < $out/load.sh | sed 's/^insmod/rmmod/g' > $out/unload.sh
|
tac < $out/load.sh | sed 's/^insmod/rmmod/g' > $out/unload.sh
|
||||||
|
@ -1,25 +1,18 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
ssh_command=${SSH_COMMAND-ssh}
|
ssh_command=${SSH_COMMAND-ssh}
|
||||||
if [ "$1" = "--no-reboot" ] ; then
|
|
||||||
reboot="true"
|
|
||||||
shift
|
|
||||||
else
|
|
||||||
reboot="reboot"
|
|
||||||
fi
|
|
||||||
|
|
||||||
target_host=$1
|
target_host=$1
|
||||||
shift
|
shift
|
||||||
|
|
||||||
if [ -z "$target_host" ] ; then
|
if [ -z "$target_host" ] ; then
|
||||||
echo Usage: liminix-rebuild [--no-reboot] target-host params
|
echo Usage: liminix-rebuild target-host params
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if toplevel=$(nix-build "$@" -A outputs.systemConfiguration --no-out-link); then
|
if toplevel=$(nix-build "$@" -A outputs.systemConfiguration --no-out-link); then
|
||||||
echo systemConfiguration $toplevel
|
echo systemConfiguration $toplevel
|
||||||
min-copy-closure $target_host $toplevel
|
min-copy-closure $target_host $toplevel
|
||||||
$ssh_command $target_host $toplevel/bin/install
|
$ssh_command $target_host cp -v -fP $toplevel/bin/* $toplevel/etc/* /persist
|
||||||
$ssh_command $target_host "sync; source /etc/profile; reboot"
|
$ssh_command $target_host "sync; source /etc/profile; reboot"
|
||||||
else
|
else
|
||||||
echo Rebuild failed
|
echo Rebuild failed
|
||||||
|
2
pkgs/min-copy-closure/min-copy-closure.fnl
Normal file
2
pkgs/min-copy-closure/min-copy-closure.fnl
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
|
||||||
|
(local ssh (io.popen "
|
@ -1,49 +1,20 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
ssh_command=${SSH_COMMAND-ssh}
|
ssh_command=${SSH_COMMAND-ssh}
|
||||||
|
target_host=$1
|
||||||
root_prefix=/
|
shift
|
||||||
verbose=true
|
|
||||||
|
|
||||||
while [[ $# -gt 0 ]]; do
|
|
||||||
case $1 in
|
|
||||||
-r|--root)
|
|
||||||
root_prefix="$2"
|
|
||||||
shift
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
-q|--quiet)
|
|
||||||
verbose=""
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
-*|--*)
|
|
||||||
echo "Unknown option $1"
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
if test -z "$target_host"; then
|
|
||||||
target_host="$1"
|
|
||||||
else
|
|
||||||
paths+=("$1") # save positional arg
|
|
||||||
fi
|
|
||||||
shift # past argument
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
progress() {
|
|
||||||
test -n "$verbose" && echo $*
|
|
||||||
}
|
|
||||||
|
|
||||||
if [ -z "$target_host" ] ; then
|
if [ -z "$target_host" ] ; then
|
||||||
echo Usage: min-copy-closure [--root /mnt] target-host paths
|
echo Usage: min-copy-closure target-host paths
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -z "$IN_NIX_BUILD" ] ; then
|
if [ -n "$IN_NIX_BUILD" ] ; then
|
||||||
# can't run nix-store in a derivation, so we have to
|
# can't run nix-store in a derivation, so we have to
|
||||||
# skip the requisites when running tests in hydra
|
# skip the requisites when running tests in hydra
|
||||||
paths=$(nix-store -q --requisites "$paths")
|
paths=$@
|
||||||
|
else
|
||||||
|
paths=$(nix-store -q --requisites "$@")
|
||||||
fi
|
fi
|
||||||
needed=""
|
needed=""
|
||||||
|
|
||||||
@ -54,16 +25,16 @@ coproc remote {
|
|||||||
exec 10>&${remote[1]}
|
exec 10>&${remote[1]}
|
||||||
|
|
||||||
for p in $paths; do
|
for p in $paths; do
|
||||||
progress -n Checking $(basename $p) ...
|
echo -n Checking $(basename $p) ...
|
||||||
echo "test -e ${root_prefix}$p && echo skip || echo $p" >&10
|
echo "test -e $p && echo skip || echo $p" >&10
|
||||||
read n <&${remote[0]}
|
read n <&${remote[0]}
|
||||||
case $n in
|
case $n in
|
||||||
skip)
|
skip)
|
||||||
progress skip
|
echo skip
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
needed="${needed} $n"
|
needed="${needed} $n"
|
||||||
progress will copy
|
echo will copy
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
@ -73,11 +44,10 @@ if test -z "$needed" ; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "cd ${root_prefix} && cpio -d -i >/dev/console" >&10
|
echo "cd / && cpio -i >/dev/console" >&10
|
||||||
|
|
||||||
find $needed | cpio -H newc -o >&10
|
find $needed | cpio -H newc -o >&10
|
||||||
|
|
||||||
# make sure the connection hasn't died
|
echo "date" >&10
|
||||||
echo "echo finished" >&10
|
|
||||||
read n <&${remote[0]}
|
read n <&${remote[0]}
|
||||||
echo $n
|
echo $n
|
||||||
|
@ -34,5 +34,4 @@ in {
|
|||||||
applyPatches.ath79 = doPatch "ath79";
|
applyPatches.ath79 = doPatch "ath79";
|
||||||
applyPatches.ramips = doPatch "ramips";
|
applyPatches.ramips = doPatch "ramips";
|
||||||
applyPatches.mediatek = doPatch "mediatek"; # aarch64
|
applyPatches.mediatek = doPatch "mediatek"; # aarch64
|
||||||
applyPatches.mvebu = doPatch "mvebu"; # arm
|
|
||||||
}
|
}
|
||||||
|
@ -1,5 +0,0 @@
|
|||||||
CFLAGS+=-Os -fno-stack-protector -fpic -fPIC
|
|
||||||
LDFLAGS=-static
|
|
||||||
CFLAGS+=-Wall -Werror
|
|
||||||
|
|
||||||
preinit: preinit.o parseopts.o
|
|
@ -15,6 +15,7 @@ stdenv.mkDerivation {
|
|||||||
|
|
||||||
# NIX_DEBUG=2;
|
# NIX_DEBUG=2;
|
||||||
hardeningDisable = [ "all" ];
|
hardeningDisable = [ "all" ];
|
||||||
|
CFLAGS = "-Os -static -DPREINIT_USE_LIBC -fno-stack-protector -fpic -fPIC -I ./ -I ${kernel}/tools/include/nolibc";
|
||||||
|
|
||||||
postBuild = ''
|
postBuild = ''
|
||||||
$STRIP --remove-section=.note --remove-section=.comment preinit
|
$STRIP --remove-section=.note --remove-section=.comment preinit
|
||||||
|
@ -1,132 +0,0 @@
|
|||||||
#include <unistd.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
static int begins_with(char * str, char * prefix)
|
|
||||||
{
|
|
||||||
while(*prefix) {
|
|
||||||
if(*str == '\0') return 0;
|
|
||||||
if(*str != *prefix) return 0;
|
|
||||||
str++;
|
|
||||||
prefix++;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
char * pr_u32(int32_t input) {
|
|
||||||
static char buf[9];
|
|
||||||
const char *digits = "0123456789abcdef";
|
|
||||||
int i=0;
|
|
||||||
|
|
||||||
buf[i] = digits[(input & 0xf0000000) >> 28];
|
|
||||||
buf[i+1] = digits[(input & 0x0f000000) >> 24];
|
|
||||||
if(buf[i] != '0' || buf[i+1] != '0') i+=2;
|
|
||||||
|
|
||||||
buf[i] = digits[(input & 0x00f00000) >> 20];
|
|
||||||
buf[i+1] = digits[(input & 0x000f0000) >> 16];
|
|
||||||
if(buf[i] != '0' || buf[i+1] != '0') i+=2;
|
|
||||||
|
|
||||||
buf[i] = digits[(input & 0x0000f000) >> 12];
|
|
||||||
buf[i+1] = digits[(input & 0x00000f00) >> 8];
|
|
||||||
if(buf[i] != '0' || buf[i+1] != '0') i+=2;
|
|
||||||
|
|
||||||
buf[i] = digits[(input & 0x000000f0) >> 4];
|
|
||||||
buf[i+1] = digits[(input & 0x0000000f)];
|
|
||||||
i+=2;
|
|
||||||
|
|
||||||
buf[i] ='\0';
|
|
||||||
write(2, buf, i);
|
|
||||||
|
|
||||||
return buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void parseopts(char * cmdline, char **root, char **rootfstype) {
|
|
||||||
*root = 0;
|
|
||||||
*rootfstype = 0;
|
|
||||||
|
|
||||||
for(char *p = cmdline; *p; p++) {
|
|
||||||
if(begins_with(p, "root=")) {
|
|
||||||
*root = p + strlen("root=");
|
|
||||||
while(*p && (*p != ' ')) p++;
|
|
||||||
|
|
||||||
if(*p) {
|
|
||||||
*p = '\0';
|
|
||||||
p++;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
if(begins_with(p, "rootfstype=")) {
|
|
||||||
*rootfstype = p + strlen("rootfstype=");
|
|
||||||
while(*p && (*p != ' ')) p++;
|
|
||||||
if(*p) {
|
|
||||||
*p = '\0';
|
|
||||||
p++;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef TESTS
|
|
||||||
#include <assert.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
// cc -DTESTS -o parseopts parseopts.c && ./parseopts
|
|
||||||
|
|
||||||
#define die(fmt, ...) do { printf(fmt, __VA_ARGS__); exit(1); } while(0)
|
|
||||||
#define S(x) #x
|
|
||||||
#define expect_equal(actual, expected) \
|
|
||||||
if(!actual || strcmp(actual, expected)) die("%d: expected \"%s\", got \"%s\"", __LINE__, expected, actual);
|
|
||||||
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
char * root = "/dev/hda1";
|
|
||||||
char * rootfstype = "xiafs";
|
|
||||||
char *buf;
|
|
||||||
|
|
||||||
// finds root= and rootfstype= options
|
|
||||||
buf = strdup("liminix console=ttyS0,115200 panic=10 oops=panic init=/bin/init loglevel=8 root=/dev/ubi0_4 rootfstype=ubifs fw_devlink=off mtdparts=phram0:18M(rootfs) phram.phram=phram0,0x40400000,18874368,65536 root=/dev/mtdblock0 foo");
|
|
||||||
parseopts(buf, &root, &rootfstype);
|
|
||||||
expect_equal(root, "/dev/mtdblock0");
|
|
||||||
expect_equal(rootfstype, "ubifs");
|
|
||||||
|
|
||||||
// in case of duplicates, chooses the latter
|
|
||||||
// also: works if the option is end of string
|
|
||||||
buf = strdup("liminix console=ttyS0,115200 panic=10 oops=panic init=/bin/init loglevel=8 root=/dev/ubi0_4 rootfstype=ubifs fw_devlink=off mtdparts=phram0:18M(rootfs) phram.phram=phram0,0x40400000,18874368,65536 root=/dev/mtdblock0");
|
|
||||||
parseopts(buf, &root, &rootfstype);
|
|
||||||
expect_equal(root, "/dev/mtdblock0");
|
|
||||||
expect_equal(rootfstype, "ubifs");
|
|
||||||
|
|
||||||
// options may appear in either order
|
|
||||||
buf = strdup("liminix fw_devlink=off root=/dev/hda1 rootfstype=ubifs foo");
|
|
||||||
parseopts(buf, &root, &rootfstype);
|
|
||||||
expect_equal(root, "/dev/hda1");
|
|
||||||
expect_equal(rootfstype, "ubifs");
|
|
||||||
|
|
||||||
buf = strdup("liminix rootfstype=ubifs fw_devlink=off root=/dev/hda1 foo");
|
|
||||||
parseopts(buf, &root, &rootfstype);
|
|
||||||
expect_equal(rootfstype, "ubifs");
|
|
||||||
expect_equal(root, "/dev/hda1");
|
|
||||||
|
|
||||||
// provides NULL for missing options
|
|
||||||
buf = strdup("liminix rufustype=ubifs fw_devlink=off foot=/dev/hda1");
|
|
||||||
parseopts(buf, &root, &rootfstype);
|
|
||||||
if(rootfstype) die("expected null rootfstype, got \"%s\"", rootfstype);
|
|
||||||
if(root) die("expected null root, got \"%s\"", root);
|
|
||||||
|
|
||||||
// provides empty strings for empty options
|
|
||||||
buf = strdup("liminix rootfstype= fw_devlink=off root= /dev/hda1");
|
|
||||||
parseopts(buf, &root, &rootfstype);
|
|
||||||
if(strlen(rootfstype)) die("expected empty rootfstype, got \"%s\"", rootfstype);
|
|
||||||
if(strlen(root)) die("expected null root, got \"%s\"", root);
|
|
||||||
|
|
||||||
expect_equal("01", pr_u32(1));
|
|
||||||
expect_equal("ab", pr_u32(0xab));
|
|
||||||
expect_equal("0abc", pr_u32(0xabc));
|
|
||||||
expect_equal("aabc", pr_u32(0xaabc));
|
|
||||||
expect_equal("deadcafe", pr_u32(0xdeadcafe));
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,47 +1,37 @@
|
|||||||
|
#ifdef PREINIT_USE_LIBC
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <sys/mount.h>
|
#include <sys/mount.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdint.h>
|
#else
|
||||||
#include <errno.h>
|
#include <nolibc.h>
|
||||||
|
#endif
|
||||||
#include <asm/setup.h> /* for COMMAND_LINE_SIZE */
|
#include <asm/setup.h>
|
||||||
|
|
||||||
void parseopts(char * cmdline, char **root, char **rootfstype);
|
|
||||||
|
|
||||||
#define ERR(x) write(2, x, strlen(x))
|
#define ERR(x) write(2, x, strlen(x))
|
||||||
#define AVER(c) do { if(c < 0) { ERR("failed: " #c ": error=0x" ); pr_u32(errno); ERR("\n"); } } while(0)
|
#define AVER(c) do { if(c < 0) ERR("failed: " #c); } while(0)
|
||||||
|
|
||||||
char * pr_u32(int32_t input);
|
static int begins_with(char * str, char * prefix)
|
||||||
|
{
|
||||||
static void die() {
|
while(*prefix) {
|
||||||
/* if init exits, it causes a kernel panic. On the Turris
|
if(*str == '\0') return 0;
|
||||||
* Omnia (and maybe other hardware, I don't know), the kernel
|
if(*str != *prefix) return 0;
|
||||||
* panics _before_ any of the messages from AVER are printed,
|
str++;
|
||||||
* which makes it really hard to tell what went wrong. So
|
prefix++;
|
||||||
* let's wait a little here to give the console a chance to
|
}
|
||||||
* catch up.
|
return 1;
|
||||||
*
|
|
||||||
* Yes, I know that file descriptor IO is supposedly
|
|
||||||
* non-buffered. Empirical observation suggests that there
|
|
||||||
* must be a buffer of some kind somewhere though.
|
|
||||||
*/
|
|
||||||
|
|
||||||
sleep(10);
|
|
||||||
exit(1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int fork_exec(char * command, char *args[])
|
static void fork_exec(char * command, char *args[])
|
||||||
{
|
{
|
||||||
int fork_pid = fork();
|
int fork_pid = fork();
|
||||||
AVER(fork_pid);
|
AVER(fork_pid);
|
||||||
if(fork_pid > 0)
|
if(fork_pid > 0)
|
||||||
return wait(NULL);
|
wait(NULL);
|
||||||
else
|
else
|
||||||
return execve(command, args, NULL);
|
AVER(execve(command, args, NULL));
|
||||||
}
|
}
|
||||||
|
|
||||||
char banner[] = "Running pre-init...\n";
|
char banner[] = "Running pre-init...\n";
|
||||||
@ -49,53 +39,52 @@ char buf[COMMAND_LINE_SIZE];
|
|||||||
|
|
||||||
int main(int argc, char *argv[], char *envp[])
|
int main(int argc, char *argv[], char *envp[])
|
||||||
{
|
{
|
||||||
char *rootdevice = 0;
|
#ifndef PREINIT_USE_LIBC
|
||||||
char *rootfstype = 0;
|
asm("la $gp, _gp\nsw $gp,16($sp)");
|
||||||
|
#endif
|
||||||
|
char *rootdevice = 0;
|
||||||
|
char *p = buf;
|
||||||
|
write(1, banner, strlen(banner));
|
||||||
|
|
||||||
write(1, banner, strlen(banner));
|
mount("none", "/proc", "proc", 0, NULL);
|
||||||
|
|
||||||
AVER(mount("none", "/proc", "proc", 0, NULL));
|
int cmdline = open("/proc/cmdline", O_RDONLY, 0);
|
||||||
AVER(mount("none", "/dev", "devtmpfs", 0, NULL));
|
|
||||||
|
|
||||||
int cmdline = open("/proc/cmdline", O_RDONLY, 0);
|
if(cmdline>=0) {
|
||||||
|
int len = read(cmdline, buf, sizeof buf - 1);
|
||||||
|
buf[len]='\0';
|
||||||
|
write(1, "cmdline ", 8);
|
||||||
|
write(1, buf, len);
|
||||||
|
};
|
||||||
|
|
||||||
if(cmdline>=0) {
|
while(*p) {
|
||||||
int len = read(cmdline, buf, sizeof buf - 1);
|
if(begins_with(p, "root=")) {
|
||||||
buf[len]='\0';
|
rootdevice = p + 5;
|
||||||
while(buf[len-1]=='\n') {
|
while(*p && (*p != ' ')) p++;
|
||||||
buf[len-1]='\0';
|
*p= '\0';
|
||||||
len--;
|
}
|
||||||
|
while(*p && (*p != ' ')) p++;
|
||||||
|
p++;
|
||||||
}
|
}
|
||||||
write(1, "cmdline: \"", 10);
|
|
||||||
write(1, buf, len);
|
|
||||||
write(1, "\"\n", 2);
|
|
||||||
} else {
|
|
||||||
ERR("failed: open(\"/proc/cmdline\")\n");
|
|
||||||
die();
|
|
||||||
}
|
|
||||||
parseopts(buf, &rootdevice, &rootfstype);
|
|
||||||
|
|
||||||
if(rootdevice) {
|
if(rootdevice) {
|
||||||
if(!rootfstype) rootfstype = "jffs2"; /* backward compatibility */
|
write(1, "rootdevice ", 11);
|
||||||
write(1, "rootdevice ", 11);
|
write(1, rootdevice, strlen(rootdevice));
|
||||||
write(1, rootdevice, strlen(rootdevice));
|
write(1, "\n", 1);
|
||||||
write(1, " (", 2);
|
|
||||||
write(1, rootfstype, strlen(rootfstype));
|
|
||||||
write(1, ")\n", 2);
|
|
||||||
AVER(mount(rootdevice, "/target/persist", rootfstype, 0, NULL));
|
|
||||||
AVER(mount("/target/persist/nix", "/target/nix",
|
|
||||||
"bind", MS_BIND, NULL));
|
|
||||||
|
|
||||||
char *exec_args[] = { "activate", "/target", NULL };
|
AVER(mount(rootdevice, "/target/persist", "jffs2", 0, NULL));
|
||||||
AVER(fork_exec("/target/persist/activate", exec_args));
|
AVER(mount("/target/persist/nix", "/target/nix",
|
||||||
AVER(chdir("/target"));
|
"bind", MS_BIND, NULL));
|
||||||
|
|
||||||
AVER(mount("/target", "/", "bind", MS_BIND | MS_REC, NULL));
|
char *exec_args[] = { "activate", "/target", NULL };
|
||||||
AVER(chroot("."));
|
fork_exec("/target/persist/activate", exec_args);
|
||||||
|
AVER(chdir("/target"));
|
||||||
|
|
||||||
argv[0] = "init";
|
AVER(mount("/target", "/", "bind", MS_BIND | MS_REC, NULL));
|
||||||
argv[1] = NULL;
|
AVER(chroot("."));
|
||||||
AVER(execve("/persist/init", argv, envp));
|
argv[0] = "init";
|
||||||
}
|
argv[1] = NULL;
|
||||||
die();
|
|
||||||
|
AVER(execve("/persist/init", argv, envp));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +0,0 @@
|
|||||||
with import <nixpkgs> {};
|
|
||||||
mkShell {
|
|
||||||
name = "preinit-env";
|
|
||||||
src = ./.;
|
|
||||||
}
|
|
@ -1,31 +0,0 @@
|
|||||||
Loading kernel at offset 0x10000 works only for zImage, but not for Image,
|
|
||||||
because the kernel expect the start of decompressed kernel (.head.text) to be
|
|
||||||
at an address that's a distance that's 16MB aligned from PAGE_OFFSET +
|
|
||||||
TEXT_OFFSET (see vmlinux.lds.S). This check is enfornced in __fixup_pv_table in
|
|
||||||
arch/arm/kernel/head.S TEXT_OFFSET is 0x00008000, so a 16MB alignment needs to
|
|
||||||
have a "0x8000" in the lower 16 bits so that they cancel out. Currently the
|
|
||||||
offset Qemu loads it at is 0x10000.
|
|
||||||
|
|
||||||
With zImage, this need is met because zImage loads the uncompressed Image
|
|
||||||
correctly, however when loading an Image and executing directly Qemu is
|
|
||||||
required it to load it at the correct location. Doing so, doesn't break Qemu's
|
|
||||||
zImage loading. With this patch, both zImage and Image work correctly.
|
|
||||||
|
|
||||||
Original patch from https://patchwork.kernel.org/project/linux-arm-kernel/patch/1395718484-20424-1-git-send-email-joelf@ti.com/ was
|
|
||||||
Signed-off-by: Joel Fernandes <joelf@ti.com>
|
|
||||||
|
|
||||||
(Edited by Daniel Barlow to apply cleanly to more recent QEMU)
|
|
||||||
|
|
||||||
diff --git a/hw/arm/boot.c b/hw/arm/boot.c
|
|
||||||
index ada2717f76..18bcdd45d2 100644
|
|
||||||
--- a/hw/arm/boot.c
|
|
||||||
+++ b/hw/arm/boot.c
|
|
||||||
@@ -32,7 +32,7 @@
|
|
||||||
*/
|
|
||||||
#define KERNEL_ARGS_ADDR 0x100
|
|
||||||
#define KERNEL_NOLOAD_ADDR 0x02000000
|
|
||||||
-#define KERNEL_LOAD_ADDR 0x00010000
|
|
||||||
+#define KERNEL_LOAD_ADDR 0x00008000
|
|
||||||
#define KERNEL64_LOAD_ADDR 0x00080000
|
|
||||||
|
|
||||||
#define ARM64_TEXT_OFFSET_OFFSET 8
|
|
@ -1,23 +1,19 @@
|
|||||||
{
|
{
|
||||||
qemuLim
|
qemu
|
||||||
, socat
|
, socat
|
||||||
, writeShellScript
|
, writeShellScriptBin
|
||||||
, writeFennel
|
, symlinkJoin
|
||||||
, runCommand
|
|
||||||
, lib
|
, lib
|
||||||
, lua
|
|
||||||
, pkgsBuildBuild
|
|
||||||
}: let
|
}: let
|
||||||
run-liminix-vm = pkgsBuildBuild.writeFennel "run-liminix-vm" {
|
run-liminix-vm = writeShellScriptBin "run-liminix-vm" ''
|
||||||
packages = [ qemuLim lua.pkgs.luaposix lua.pkgs.fennel ];
|
export PATH="${lib.makeBinPath [qemu]}:$PATH"
|
||||||
} ./run-liminix-vm.fnl;
|
${builtins.readFile ./run-liminix-vm.sh}
|
||||||
connect = writeShellScript "connect-vm" ''
|
'';
|
||||||
|
connect = writeShellScriptBin "connect-vm" ''
|
||||||
export PATH="${lib.makeBinPath [socat]}:$PATH"
|
export PATH="${lib.makeBinPath [socat]}:$PATH"
|
||||||
socat -,raw,echo=0,icanon=0,isig=0,icrnl=0,escape=0x0f unix-connect:$1
|
socat -,raw,echo=0,icanon=0,isig=0,icrnl=0,escape=0x0f unix-connect:$1
|
||||||
'';
|
'';
|
||||||
in runCommand "vm" {} ''
|
in symlinkJoin {
|
||||||
mkdir -p $out/bin
|
name = "run-liminix-vm";
|
||||||
cd $out/bin
|
paths = [ run-liminix-vm connect ];
|
||||||
ln -s ${connect} ./connect-vm
|
}
|
||||||
ln -s ${run-liminix-vm} ./run-liminix-vm
|
|
||||||
''
|
|
||||||
|
@ -1,145 +0,0 @@
|
|||||||
(local { : fork : execp : unlink } (require :posix.unistd))
|
|
||||||
(local { : wait } (require :posix.sys.wait))
|
|
||||||
(local { : mkstemp : setenv } (require :posix.stdlib))
|
|
||||||
(local { : fdopen } (require :posix.stdio))
|
|
||||||
|
|
||||||
(fn pad-file [name kb chr]
|
|
||||||
(let [(fd out) (mkstemp "run-vm-XXXXXX")
|
|
||||||
pad-string (string.rep (or chr "\0") 1024)]
|
|
||||||
(with-open [f (fdopen fd :w)]
|
|
||||||
(for [i 1 kb] (f:write pad-string))
|
|
||||||
(f:seek :set 0)
|
|
||||||
(with-open [input (assert (io.open name :rb))]
|
|
||||||
(f:write (input:read "*a")))
|
|
||||||
(f:seek :end 0))
|
|
||||||
out))
|
|
||||||
|
|
||||||
(fn spawn [command args]
|
|
||||||
(match (fork)
|
|
||||||
(nil msg) (error (.. "couldn't fork: " msg))
|
|
||||||
0 (execp command args)
|
|
||||||
pid (wait pid)))
|
|
||||||
|
|
||||||
(fn appendm [t2 t1]
|
|
||||||
(table.move t1 1 (# t1) (+ 1 (# t2)) t2)
|
|
||||||
t2)
|
|
||||||
|
|
||||||
(fn merge [table1 table2]
|
|
||||||
(collect [k v (pairs table2) &into table1]
|
|
||||||
k v))
|
|
||||||
|
|
||||||
(fn assoc [tbl k v]
|
|
||||||
(tset tbl k v)
|
|
||||||
tbl)
|
|
||||||
|
|
||||||
(fn parse-args [args]
|
|
||||||
(match args
|
|
||||||
["--background" dir & rest] (assoc (parse-args rest) :background dir)
|
|
||||||
["--u-boot" bin & rest]
|
|
||||||
(assoc (parse-args rest) :u-boot bin)
|
|
||||||
["--disk-image" image & rest ] (assoc (parse-args rest)
|
|
||||||
:disk-image (pad-file image 1024))
|
|
||||||
["--arch" arch & rest] (assoc (parse-args rest) :arch arch)
|
|
||||||
["--phram-address" addr & rest] (assoc (parse-args rest) :phram-address addr)
|
|
||||||
["--lan" spec & rest] (assoc (parse-args rest) :lan spec)
|
|
||||||
["--wan" spec & rest] (assoc (parse-args rest) :wan spec)
|
|
||||||
["--command-line" cmd & rest] (assoc (parse-args rest) :command-line cmd)
|
|
||||||
["--flag" flag & rest] (let [o (parse-args rest)]
|
|
||||||
(assoc o :flags (doto o.flags (table.insert 1 flag))))
|
|
||||||
[kernel rootfsimg]
|
|
||||||
{ :flags [] :kernel kernel :rootfs (pad-file rootfsimg (* 16 1024)) }
|
|
||||||
))
|
|
||||||
|
|
||||||
(fn pad-u-boot [options]
|
|
||||||
(if options.u-boot
|
|
||||||
(let [size (.
|
|
||||||
{
|
|
||||||
:mips (* 4 1024)
|
|
||||||
:aarch64 (* 64 1024)
|
|
||||||
:arm (* 64 1024)
|
|
||||||
}
|
|
||||||
options.arch)]
|
|
||||||
(assoc options
|
|
||||||
:u-boot
|
|
||||||
(pad-file options.u-boot size "\xff")))
|
|
||||||
options))
|
|
||||||
|
|
||||||
(local options
|
|
||||||
(assert
|
|
||||||
(pad-u-boot
|
|
||||||
(merge { :arch "mips" } (parse-args arg)))
|
|
||||||
(.. "Usage: " (. arg 0) " blah bah")))
|
|
||||||
|
|
||||||
(fn background [dir]
|
|
||||||
(let [pid (.. dir "/pid")
|
|
||||||
sock (.. dir "/console")
|
|
||||||
monitor (.. dir "/monitor")]
|
|
||||||
["--daemonize"
|
|
||||||
"--pidfile" pid
|
|
||||||
"-serial" (.. "unix:" sock ",server,nowait")
|
|
||||||
"-monitor" (.. "unix:" monitor ",server,nowait")]))
|
|
||||||
|
|
||||||
(fn access-net [override]
|
|
||||||
[
|
|
||||||
"-netdev" (.. (or override
|
|
||||||
"socket,mcast=230.0.0.1:1234,localaddr=127.0.0.1")
|
|
||||||
",id=access")
|
|
||||||
"-device" "virtio-net,disable-legacy=on,disable-modern=off,netdev=access,mac=ba:ad:1d:ea:21:02"
|
|
||||||
])
|
|
||||||
|
|
||||||
(fn local-net [override]
|
|
||||||
[
|
|
||||||
"-netdev" (.. (or override "socket,mcast=230.0.0.1:1235,localaddr=127.0.0.1")
|
|
||||||
",id=lan")
|
|
||||||
"-device" "virtio-net,disable-legacy=on,disable-modern=off,netdev=lan,mac=ba:ad:1d:ea:21:01"
|
|
||||||
])
|
|
||||||
|
|
||||||
|
|
||||||
(fn bootable [cmdline uboot disk]
|
|
||||||
(if uboot
|
|
||||||
["-drive" (.. "if=pflash,format=raw,file=" uboot )
|
|
||||||
"-drive" (.. "if=none,format=raw,id=hd0,file=" disk)
|
|
||||||
"-device" "virtio-blk-pci,drive=hd0"
|
|
||||||
]
|
|
||||||
(let [cmdline (.. "root=/dev/mtdblock0" " " cmdline " mem=256M liminix mtdparts=phram0:16M(rootfs) phram.phram=phram0," options.phram-address ",16Mi,65536")]
|
|
||||||
["-kernel" options.kernel "-append" cmdline])))
|
|
||||||
|
|
||||||
(local bin {
|
|
||||||
:mips ["qemu-system-mips" "-M" "malta"]
|
|
||||||
:aarch64 ["qemu-system-aarch64" "-M" "virt"
|
|
||||||
"-cpu" "cortex-a72"]
|
|
||||||
:arm ["qemu-system-arm" "-M" "virt,highmem=off"
|
|
||||||
"-cpu" "cortex-a15"]
|
|
||||||
})
|
|
||||||
|
|
||||||
(local exec-args
|
|
||||||
(-> []
|
|
||||||
(appendm (. bin options.arch))
|
|
||||||
(appendm ["-echr" "16"])
|
|
||||||
(appendm options.flags)
|
|
||||||
(appendm (if options.phram-address
|
|
||||||
[
|
|
||||||
"-m" "272"
|
|
||||||
"-device"
|
|
||||||
(.. "loader,file=" options.rootfs ",addr=" options.phram-address)
|
|
||||||
]
|
|
||||||
["-m" "256"]))
|
|
||||||
(appendm
|
|
||||||
(if options.background
|
|
||||||
(background options.background)
|
|
||||||
["-serial" "mon:stdio"]))
|
|
||||||
(appendm (bootable (or options.command-line "")
|
|
||||||
options.u-boot options.disk-image))
|
|
||||||
(appendm (access-net options.wan))
|
|
||||||
(appendm (local-net options.lan))
|
|
||||||
(appendm ["-display" "none"])))
|
|
||||||
|
|
||||||
(each [n a (ipairs exec-args)]
|
|
||||||
(print (.. (if (> n 1) " " "") (string.format "%q" a))))
|
|
||||||
|
|
||||||
(match exec-args
|
|
||||||
[cmd & params] (print (spawn cmd params)))
|
|
||||||
|
|
||||||
(if options.rootfs (unlink options.rootfs))
|
|
||||||
(if options.u-boot (unlink options.u-boot))
|
|
||||||
(if options.disk-image (unlink options.disk-image))
|
|
69
pkgs/run-liminix-vm/run-liminix-vm.sh
Executable file
69
pkgs/run-liminix-vm/run-liminix-vm.sh
Executable file
@ -0,0 +1,69 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
cleanup(){
|
||||||
|
test -n "$rootfs" && test -f $rootfs && rm $rootfs
|
||||||
|
}
|
||||||
|
trap 'exit 1' INT HUP QUIT TERM ALRM USR1
|
||||||
|
trap 'cleanup' EXIT
|
||||||
|
|
||||||
|
usage(){
|
||||||
|
echo "usage: $(basename $0) [--background /path/to/state_directory] kernel rootimg [initramfs]"
|
||||||
|
echo -e "\nWithout --background, use C-p c (not C-a c) to switch to the monitor"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
arch="mips"
|
||||||
|
if test "$1" = "--arch" ; then
|
||||||
|
arch=$2
|
||||||
|
shift;shift
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test "$1" = "--background" ; then
|
||||||
|
statedir=$2
|
||||||
|
if test -z "$statedir" || ! test -d $statedir ; then
|
||||||
|
usage
|
||||||
|
fi
|
||||||
|
pid="${statedir}/pid"
|
||||||
|
socket="${statedir}/console"
|
||||||
|
monitor="${statedir}/monitor"
|
||||||
|
echo "running in background, socket is $socket, pid $pid"
|
||||||
|
flags="--daemonize --pidfile $pid -serial unix:$socket,server,nowait -monitor unix:$monitor,server,nowait"
|
||||||
|
shift;shift
|
||||||
|
else
|
||||||
|
flags="-serial mon:stdio"
|
||||||
|
fi
|
||||||
|
|
||||||
|
test -n "$2" || usage
|
||||||
|
|
||||||
|
lan=${LAN-"socket,mcast=230.0.0.1:1235,localaddr=127.0.0.1"}
|
||||||
|
|
||||||
|
rootfs=$(mktemp run-liminix-vm-fs-XXXXXX)
|
||||||
|
dd if=/dev/zero of=$rootfs bs=1M count=16 conv=sync
|
||||||
|
dd if=$2 of=$rootfs bs=65536 conv=sync,nocreat,notrunc
|
||||||
|
|
||||||
|
if test -n "$3"; then
|
||||||
|
initramfs="-initrd $3"
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$arch" in
|
||||||
|
mips)
|
||||||
|
QEMU="qemu-system-mips -M malta"
|
||||||
|
;;
|
||||||
|
aarch64)
|
||||||
|
QEMU="qemu-system-aarch64 -M virt -semihosting -cpu cortex-a72"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
INIT=${INIT-/bin/init}
|
||||||
|
set -x
|
||||||
|
$QEMU \
|
||||||
|
-m 256 \
|
||||||
|
-echr 16 \
|
||||||
|
-append "$CMDLINE liminix root=/dev/mtdblock0 block2mtd.block2mtd=/dev/vda,65536" \
|
||||||
|
-drive file=$rootfs,format=raw,readonly=off,if=virtio,index=0 \
|
||||||
|
${initramfs} \
|
||||||
|
-netdev socket,id=access,mcast=230.0.0.1:1234,localaddr=127.0.0.1 \
|
||||||
|
-device virtio-net,disable-legacy=on,disable-modern=off,netdev=access,mac=ba:ad:1d:ea:21:02 \
|
||||||
|
-netdev ${lan},id=lan \
|
||||||
|
-device virtio-net,disable-legacy=on,disable-modern=off,netdev=lan,mac=ba:ad:1d:ea:21:01 \
|
||||||
|
-kernel $1 -display none $flags ${QEMU_OPTIONS}
|
@ -68,7 +68,7 @@ in attrset:
|
|||||||
src = ./.;
|
src = ./.;
|
||||||
|
|
||||||
CFLAGS = "-Os";
|
CFLAGS = "-Os";
|
||||||
LDFLAGS = "-static -Xlinker -static";
|
LDFLAGS = "-static";
|
||||||
|
|
||||||
postConfigure = ''
|
postConfigure = ''
|
||||||
cp ${makedevs} makedevs.c
|
cp ${makedevs} makedevs.c
|
||||||
@ -80,10 +80,5 @@ in attrset:
|
|||||||
cp $closure/store-paths $out/etc/nix-store-paths
|
cp $closure/store-paths $out/etc/nix-store-paths
|
||||||
$STRIP --remove-section=.note --remove-section=.comment --strip-all makedevs -o $out/bin/activate
|
$STRIP --remove-section=.note --remove-section=.comment --strip-all makedevs -o $out/bin/activate
|
||||||
ln -s ${s6-init-bin}/bin/init $out/bin/init
|
ln -s ${s6-init-bin}/bin/init $out/bin/init
|
||||||
cat > $out/bin/install <<EOF
|
|
||||||
#!/bin/sh
|
|
||||||
cp -v -fP $out/bin/* $out/etc/* \''${1-/}/persist
|
|
||||||
EOF
|
|
||||||
chmod +x $out/bin/install
|
|
||||||
'';
|
'';
|
||||||
}
|
}
|
||||||
|
@ -195,22 +195,19 @@ function tftp:handle_RRQ(socket, host, port, source, options)
|
|||||||
]]
|
]]
|
||||||
yield(false, true)
|
yield(false, true)
|
||||||
end
|
end
|
||||||
|
socket:sendto(self.DATA(data, tid), host, port)
|
||||||
|
--[[ Now check for an ACK.
|
||||||
|
RFC1350 requires that for every packet sent, an ACK is received
|
||||||
|
before the next packet can be sent.
|
||||||
|
]]
|
||||||
local acked
|
local acked
|
||||||
local retried = 0
|
local retried = 0
|
||||||
local timeout = time() + timeout_secs
|
local timeout = time() + timeout_secs
|
||||||
local timedout = false
|
local timedout = false
|
||||||
repeat
|
repeat
|
||||||
socket:sendto(self.DATA(data, tid), host, port)
|
|
||||||
--[[ Now check for an ACK.
|
|
||||||
RFC1350 requires that for every packet sent, an ACK is received
|
|
||||||
before the next packet can be sent.
|
|
||||||
]]
|
|
||||||
yield(true, false) -- we need to wait until the socket is readable again
|
yield(true, false) -- we need to wait until the socket is readable again
|
||||||
local ack, ackhost, ackport = socket:recvfrom(ACKSIZE)
|
local ack, ackhost, ackport = socket:recvfrom(ACKSIZE)
|
||||||
local ack_sequence = self.parse_ACK(ack)
|
if ackhost ~= host or ackport ~= port or self.parse_ACK(ack) ~= tid then
|
||||||
|
|
||||||
if ackhost ~= host or ackport ~= port then
|
|
||||||
--[[https://tools.ietf.org/html/rfc1350#page-5
|
--[[https://tools.ietf.org/html/rfc1350#page-5
|
||||||
"If a source TID does not match, the packet should be
|
"If a source TID does not match, the packet should be
|
||||||
discarded as erroneously sent from somewhere else.
|
discarded as erroneously sent from somewhere else.
|
||||||
@ -219,21 +216,13 @@ function tftp:handle_RRQ(socket, host, port, source, options)
|
|||||||
]]
|
]]
|
||||||
socket:sendto(err(ERR_UNKNOWN_ID), ackhost, ackport)
|
socket:sendto(err(ERR_UNKNOWN_ID), ackhost, ackport)
|
||||||
yield(true, false)
|
yield(true, false)
|
||||||
elseif ack_sequence ~= tid then
|
else
|
||||||
-- this looks confusing, but the local variable
|
acked = true
|
||||||
-- "tid" here is actually block number (aka
|
end
|
||||||
-- sequence number), not tid at all.
|
|
||||||
log(("ack received for old block %d (expecting %d)"):format(ack_sequence, tid))
|
|
||||||
acked = false
|
|
||||||
else
|
|
||||||
acked = true
|
|
||||||
end
|
|
||||||
|
|
||||||
if not acked then log("resending") end
|
|
||||||
retried = retried + 1
|
retried = retried + 1
|
||||||
timedout = time() > timeout
|
timedout = time() > timeout
|
||||||
until acked or retried > ACK_RETRIES
|
until acked or retried > ACK_RETRIES or timedout
|
||||||
if retried > ACK_RETRIES then
|
if timedout or retried > ACK_RETRIES then
|
||||||
--There doesn't seem to be a standard error for timeout.
|
--There doesn't seem to be a standard error for timeout.
|
||||||
socket:sendto(err("Ack timeout"), host, port)
|
socket:sendto(err("Ack timeout"), host, port)
|
||||||
error("Timeout waiting for ACK")
|
error("Timeout waiting for ACK")
|
||||||
|
@ -1,12 +0,0 @@
|
|||||||
diff --git a/include/configs/qemu-arm.h b/include/configs/qemu-arm.h
|
|
||||||
index 535762ecb2..a947bae2e8 100644
|
|
||||||
--- a/include/configs/qemu-arm.h
|
|
||||||
+++ b/include/configs/qemu-arm.h
|
|
||||||
@@ -72,6 +72,7 @@
|
|
||||||
BOOT_TARGET_SCSI(func) \
|
|
||||||
BOOT_TARGET_VIRTIO(func) \
|
|
||||||
BOOT_TARGET_NVME(func) \
|
|
||||||
+ func(UBIFS, ubifs, 0, UBI, boot) \
|
|
||||||
BOOT_TARGET_DHCP(func)
|
|
||||||
|
|
||||||
#include <config_distro_bootcmd.h>
|
|
@ -1,15 +0,0 @@
|
|||||||
diff --git a/board/imgtec/malta/malta.c b/board/imgtec/malta/malta.c
|
|
||||||
index 9853a0ba82..d95e332d6d 100644
|
|
||||||
--- a/board/imgtec/malta/malta.c
|
|
||||||
+++ b/board/imgtec/malta/malta.c
|
|
||||||
@@ -169,7 +169,9 @@ int board_early_init_f(void)
|
|
||||||
int misc_init_r(void)
|
|
||||||
{
|
|
||||||
rtc_reset();
|
|
||||||
-
|
|
||||||
+#if IS_ENABLED(CONFIG_VIRTIO)
|
|
||||||
+ virtio_init();
|
|
||||||
+#endif
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
@ -27,7 +27,6 @@ name :
|
|||||||
echo "#!${lua}/bin/lua ${luaFlags}"
|
echo "#!${lua}/bin/lua ${luaFlags}"
|
||||||
echo "package.path = ${lib.strings.escapeShellArg (builtins.concatStringsSep "" luapath)} .. package.path"
|
echo "package.path = ${lib.strings.escapeShellArg (builtins.concatStringsSep "" luapath)} .. package.path"
|
||||||
echo "package.cpath = ${lib.strings.escapeShellArg (builtins.concatStringsSep "" luacpath)} .. package.cpath"
|
echo "package.cpath = ${lib.strings.escapeShellArg (builtins.concatStringsSep "" luacpath)} .. package.cpath"
|
||||||
echo "local ok, stdlib = pcall(require,'posix.stdlib'); if ok then stdlib.setenv('PATH',${lib.escapeShellArg (lib.makeBinPath packages)} .. \":\" .. os.getenv('PATH')) end"
|
|
||||||
fennel ${if correlate then "--correlate" else ""} --compile ${source}
|
fennel ${if correlate then "--correlate" else ""} --compile ${source}
|
||||||
) > ${name}.lua
|
) > ${name}.lua
|
||||||
'';
|
'';
|
||||||
|
@ -3,9 +3,7 @@
|
|||||||
pseudofiles = import ./pseudofiles/test.nix;
|
pseudofiles = import ./pseudofiles/test.nix;
|
||||||
wlan = import ./wlan/test.nix;
|
wlan = import ./wlan/test.nix;
|
||||||
pppoe = import ./pppoe/test.nix;
|
pppoe = import ./pppoe/test.nix;
|
||||||
jffs2 = import ./jffs2/test.nix;
|
jffs2 = import ./jffs2/test.nix;
|
||||||
ext4 = import ./ext4/test.nix;
|
|
||||||
min-copy-closure = import ./min-copy-closure/test.nix;
|
min-copy-closure = import ./min-copy-closure/test.nix;
|
||||||
fennel = import ./fennel/test.nix;
|
fennel = import ./fennel/test.nix;
|
||||||
tftpboot = import ./tftpboot/test.nix;
|
|
||||||
}
|
}
|
||||||
|
@ -1,19 +0,0 @@
|
|||||||
{ config, pkgs, lib, ... } :
|
|
||||||
let
|
|
||||||
inherit (pkgs.pseudofile) dir symlink;
|
|
||||||
in {
|
|
||||||
imports = [
|
|
||||||
../../modules/outputs/ext4fs.nix
|
|
||||||
];
|
|
||||||
config = {
|
|
||||||
rootfsType = "ext4";
|
|
||||||
filesystem = dir {
|
|
||||||
hello = {
|
|
||||||
type = "f";
|
|
||||||
uid = 7;
|
|
||||||
gid = 24;
|
|
||||||
file = "hello world";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
@ -1,10 +0,0 @@
|
|||||||
set timeout 10
|
|
||||||
|
|
||||||
spawn socat unix-connect:vm/console -
|
|
||||||
send "\r\n"
|
|
||||||
expect "#"
|
|
||||||
send "echo HELLO WORLD > /hello\r\n"
|
|
||||||
expect "#"
|
|
||||||
send "cat /hello\r\n"
|
|
||||||
expect 'HELLO WORLD'
|
|
||||||
close
|
|
@ -1,19 +0,0 @@
|
|||||||
{
|
|
||||||
liminix
|
|
||||||
, nixpkgs
|
|
||||||
}:
|
|
||||||
let img = (import liminix {
|
|
||||||
device = import "${liminix}/devices/qemu/";
|
|
||||||
liminix-config = ./configuration.nix;
|
|
||||||
}).outputs.vmroot;
|
|
||||||
pkgs = import <nixpkgs> { overlays = [(import ../../overlay.nix)]; };
|
|
||||||
in pkgs.runCommand "check" {
|
|
||||||
nativeBuildInputs = with pkgs; [
|
|
||||||
expect
|
|
||||||
socat
|
|
||||||
] ;
|
|
||||||
} ''
|
|
||||||
mkdir vm
|
|
||||||
${img}/run.sh --background ./vm
|
|
||||||
expect ${./script.expect} >$out
|
|
||||||
''
|
|
@ -5,7 +5,7 @@ in {
|
|||||||
imports = [
|
imports = [
|
||||||
../../vanilla-configuration.nix
|
../../vanilla-configuration.nix
|
||||||
../../modules/squashfs.nix
|
../../modules/squashfs.nix
|
||||||
../../modules/outputs/jffs2.nix
|
../../modules/jffs2.nix
|
||||||
];
|
];
|
||||||
config.rootfsType = "jffs2";
|
config.rootfsType = "jffs2";
|
||||||
config.filesystem = dir {
|
config.filesystem = dir {
|
||||||
|
@ -2,6 +2,7 @@ set timeout 10
|
|||||||
|
|
||||||
spawn socat unix-connect:vm/console -
|
spawn socat unix-connect:vm/console -
|
||||||
send "\r\n"
|
send "\r\n"
|
||||||
|
expect "login:" { send "root\r\n" }
|
||||||
expect "#"
|
expect "#"
|
||||||
send "echo HELLO WORLD > /hello\r\n"
|
send "echo HELLO WORLD > /hello\r\n"
|
||||||
expect "#"
|
expect "#"
|
||||||
|
@ -1,8 +0,0 @@
|
|||||||
{ config, pkgs, lib, ... } :
|
|
||||||
{
|
|
||||||
imports= [
|
|
||||||
./configuration.nix
|
|
||||||
../../modules/outputs/ext4fs.nix
|
|
||||||
];
|
|
||||||
rootfsType = lib.mkForce "ext4";
|
|
||||||
}
|
|
@ -13,7 +13,7 @@ let
|
|||||||
in {
|
in {
|
||||||
imports = [
|
imports = [
|
||||||
../../vanilla-configuration.nix
|
../../vanilla-configuration.nix
|
||||||
../../modules/outputs/jffs2.nix
|
../../modules/jffs2.nix
|
||||||
];
|
];
|
||||||
config = {
|
config = {
|
||||||
services.sshd = longrun {
|
services.sshd = longrun {
|
||||||
|
@ -1,58 +0,0 @@
|
|||||||
# This is a test for liminix-rebuild. It's not a CI test because
|
|
||||||
# liminix-rebuild calls nix-build so won't run inside a derivation,
|
|
||||||
# meaning you have to remember to run it manually when changing
|
|
||||||
# liminix-rebuild
|
|
||||||
|
|
||||||
# nix-shell -p expect socat --run "sh ./tests/min-copy-closure/test-liminix-rebuild.sh "
|
|
||||||
|
|
||||||
. tests/test-helpers.sh
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
here=$(pwd)/tests/min-copy-closure
|
|
||||||
top=$(pwd)
|
|
||||||
|
|
||||||
work=$(mktemp -d -t "test-lim-rebuild-XXXXXX")
|
|
||||||
echo $work
|
|
||||||
cd $work
|
|
||||||
|
|
||||||
deriv(){
|
|
||||||
(cd $top && nix-build -I liminix-config=${here}/config-ext4.nix --arg device "import ./devices/qemu-armv7l" -A $1 );
|
|
||||||
}
|
|
||||||
|
|
||||||
PATH=$(deriv pkgs.pkgsBuildBuild.min-copy-closure)/bin:$(deriv pkgs.pkgsBuildBuild.run-liminix-vm)/bin:$PATH
|
|
||||||
|
|
||||||
rootfs=$(deriv outputs.rootfs)
|
|
||||||
kernel=$(deriv outputs.zimage)
|
|
||||||
uboot=$(deriv outputs.u-boot)
|
|
||||||
|
|
||||||
test -d ./vm && rm -rf vm
|
|
||||||
mkdir ./vm
|
|
||||||
|
|
||||||
cat ${rootfs} > rootfs
|
|
||||||
|
|
||||||
truncate -s 24M rootfs
|
|
||||||
resize2fs rootfs
|
|
||||||
|
|
||||||
dd if=rootfs of=disk-image bs=512 seek=4 conv=sync
|
|
||||||
echo '4,-,L,*' | sfdisk disk-image
|
|
||||||
|
|
||||||
run-liminix-vm --background vm \
|
|
||||||
--command-line "console=ttyAMA0 panic=10 oops=panic loglevel=8 root=/dev/vda1 rootfstype=ext4" \
|
|
||||||
--phram-address 0x50000000 --arch arm \
|
|
||||||
--lan "user,hostfwd=tcp::2022-:22" \
|
|
||||||
--flag -append --flag "root=/dev/vda1" --flag -hda \
|
|
||||||
--flag disk-image $kernel /dev/null
|
|
||||||
|
|
||||||
expect ${here}/wait-until-ready.expect
|
|
||||||
echo "READY"
|
|
||||||
|
|
||||||
touch known_hosts
|
|
||||||
export SSH_COMMAND="ssh -o UserKnownHostsFile=${work}/known_hosts -o StrictHostKeyChecking=no -p 2022 -i ${here}/id"
|
|
||||||
|
|
||||||
(cd ${top} && liminix-rebuild root@localhost -I liminix-config=${here}/with-figlet.nix --arg device "import ./devices/qemu-armv7l")
|
|
||||||
|
|
||||||
ls -l vm
|
|
||||||
|
|
||||||
cd ${work} && expect $here/wait-for-reboot.expect
|
|
||||||
cd / ; rm -rf $work
|
|
@ -9,9 +9,11 @@ let lmx = (import liminix {
|
|||||||
rogue = lmx.pkgs.rogue;
|
rogue = lmx.pkgs.rogue;
|
||||||
img = lmx.outputs.vmroot;
|
img = lmx.outputs.vmroot;
|
||||||
pkgs = import <nixpkgs> { overlays = [(import ../../overlay.nix)]; };
|
pkgs = import <nixpkgs> { overlays = [(import ../../overlay.nix)]; };
|
||||||
|
inherit (pkgs.pkgsBuildBuild) run-liminix-vm;
|
||||||
in pkgs.runCommand "check" {
|
in pkgs.runCommand "check" {
|
||||||
nativeBuildInputs = with pkgs; [
|
nativeBuildInputs = with pkgs; [
|
||||||
expect
|
expect
|
||||||
|
run-liminix-vm
|
||||||
socat
|
socat
|
||||||
min-copy-closure
|
min-copy-closure
|
||||||
rogue
|
rogue
|
||||||
@ -19,15 +21,11 @@ in pkgs.runCommand "check" {
|
|||||||
} ''
|
} ''
|
||||||
. ${../test-helpers.sh}
|
. ${../test-helpers.sh}
|
||||||
|
|
||||||
(
|
|
||||||
mkdir vm
|
mkdir vm
|
||||||
${img}/run.sh --lan user,hostfwd=tcp::2022-:22 --background ./vm
|
LAN=user,hostfwd=tcp::2022-:22 run-liminix-vm --background ./vm ${img}/vmlinux ${img}/rootfs
|
||||||
expect ${./wait-until-ready.expect}
|
expect ${./wait-until-ready.expect}
|
||||||
export SSH_COMMAND="ssh -o StrictHostKeyChecking=no -p 2022 -i ${./id}"
|
export SSH_COMMAND="ssh -o StrictHostKeyChecking=no -p 2022 -i ${./id}"
|
||||||
$SSH_COMMAND root@localhost echo ready
|
$SSH_COMMAND root@localhost echo ready
|
||||||
IN_NIX_BUILD=true min-copy-closure --quiet root@localhost ${rogue}
|
IN_NIX_BUILD=true min-copy-closure root@localhost ${rogue}
|
||||||
$SSH_COMMAND root@localhost ls -ld ${rogue}
|
$SSH_COMMAND root@localhost ls -l ${rogue} >$out
|
||||||
IN_NIX_BUILD=true min-copy-closure --root /run root@localhost ${rogue}
|
|
||||||
$SSH_COMMAND root@localhost ls -ld /run/${rogue}
|
|
||||||
) 2>&1 | tee $out
|
|
||||||
''
|
''
|
||||||
|
@ -1,18 +0,0 @@
|
|||||||
set timeout 60
|
|
||||||
|
|
||||||
spawn socat unix-connect:vm/console -
|
|
||||||
|
|
||||||
expect {
|
|
||||||
"s6-svscan exited" { }
|
|
||||||
timeout { exit 1 }
|
|
||||||
}
|
|
||||||
expect {
|
|
||||||
"s6-linux-init" { send "\r\n" };
|
|
||||||
"# " { send "\r\n" };
|
|
||||||
}
|
|
||||||
|
|
||||||
expect {
|
|
||||||
"# " { send "echo \$PATH; md5sum /persist/activate; figlet Yes\r\n" };
|
|
||||||
}
|
|
||||||
|
|
||||||
expect "#"
|
|
@ -2,7 +2,4 @@ set timeout 60
|
|||||||
|
|
||||||
spawn socat unix-connect:vm/console -
|
spawn socat unix-connect:vm/console -
|
||||||
send "\r\n"
|
send "\r\n"
|
||||||
expect {
|
expect "login:"
|
||||||
"# " { send "hostname\r\n" };
|
|
||||||
}
|
|
||||||
expect "(none)"
|
|
@ -1,7 +0,0 @@
|
|||||||
{ pkgs, ... } :
|
|
||||||
{
|
|
||||||
imports= [./config-ext4.nix];
|
|
||||||
defaultProfile.packages = with pkgs; [
|
|
||||||
figlet
|
|
||||||
];
|
|
||||||
}
|
|
@ -2,6 +2,7 @@ set timeout 60
|
|||||||
|
|
||||||
spawn socat unix-connect:vm/console -
|
spawn socat unix-connect:vm/console -
|
||||||
send "\r\n"
|
send "\r\n"
|
||||||
|
expect "login:" { send "root\r\n" }
|
||||||
expect "#"
|
expect "#"
|
||||||
set FINISHED 0
|
set FINISHED 0
|
||||||
set EXIT "1"
|
set EXIT "1"
|
||||||
@ -10,7 +11,7 @@ while { $FINISHED < 10 } {
|
|||||||
expect {
|
expect {
|
||||||
"192.168.100.1" { set FINISHED 20; set EXIT 0; }
|
"192.168.100.1" { set FINISHED 20; set EXIT 0; }
|
||||||
"can't find device" { send_user "waiting ..." ; send "\r\n"; sleep 3 }
|
"can't find device" { send_user "waiting ..." ; send "\r\n"; sleep 3 }
|
||||||
"DOWN" { send_user "waiting ..." ; send "\r\n"; sleep 3 }
|
"DOWN" { send_user "waiting ..." ; send "\r\n"; sleep 2 }
|
||||||
}
|
}
|
||||||
set FINISHED [ expr $FINISHED + 1 ]
|
set FINISHED [ expr $FINISHED + 1 ]
|
||||||
}
|
}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user