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,
|
||||
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
|
||||
a high-level overview of breaking changes.
|
||||
_In general:_ development mostly happens on the `main` branch, which is
|
||||
therefore not guaranteed to build or to work on every commit. For the
|
||||
latest functioning version, see [the CI system](https://build.liminix.org/jobset/liminix/build) and pick a revision with all jobs green.
|
||||
|
||||
Development mostly happens on the `main` branch, which is therefore
|
||||
not guaranteed to build or to work on every commit. For the latest
|
||||
functioning version, see [the CI system](https://build.liminix.org/jobset/liminix/build) and pick a revision with all jobs green.
|
||||
_In particular:_ as of July 2023, a significant re-arrangement of
|
||||
modules and services is ongoing:
|
||||
|
||||
* if you are using out-of-tree configurations created before commit
|
||||
2e50368, especially if they reference things under pkgs.liminix,
|
||||
they will need updating. Look at changes to examples/rotuer.nix
|
||||
for guidance
|
||||
|
||||
* the same is intermittently true for examples/{extensino,arhcive}.nix
|
||||
where I've updated rotuer and not updated them to match.
|
||||
|
||||
|
||||
## Documentation
|
||||
|
1317
THOUGHTS.txt
1317
THOUGHTS.txt
File diff suppressed because it is too large
Load Diff
@ -99,16 +99,14 @@ in {
|
||||
};
|
||||
};
|
||||
};
|
||||
environment.systemPackages =
|
||||
let wireshark-nogui = pkgs.wireshark.override { withQt = false ; };
|
||||
in with pkgs; [
|
||||
tcpdump
|
||||
wireshark-nogui
|
||||
socat
|
||||
tufted
|
||||
iptables
|
||||
usbutils
|
||||
];
|
||||
environment.systemPackages = with pkgs; [
|
||||
tcpdump
|
||||
wireshark
|
||||
socat
|
||||
tufted
|
||||
iptables
|
||||
usbutils
|
||||
];
|
||||
security.sudo.wheelNeedsPassword = false;
|
||||
networking = {
|
||||
hostName = "border";
|
||||
|
73
ci.nix
73
ci.nix
@ -8,63 +8,48 @@ let
|
||||
pkgs = (import nixpkgs {});
|
||||
borderVmConf = ./bordervm.conf-example.nix;
|
||||
inherit (pkgs.lib.attrsets) genAttrs;
|
||||
devices = [
|
||||
"gl-ar750" "gl-mt300n-v2" "gl-mt300a"
|
||||
"qemu" "qemu-aarch64" "qemu-armv7l"
|
||||
];
|
||||
devices = {
|
||||
virt = [ "qemu" "qemu-aarch64" ];
|
||||
hw = [ "gl-ar750" "gl-mt300n-v2" "gl-mt300a" ];
|
||||
};
|
||||
vanilla = ./vanilla-configuration.nix;
|
||||
for-device = name:
|
||||
for-device = cfg: name:
|
||||
(import liminix {
|
||||
inherit nixpkgs borderVmConf;
|
||||
device = import (liminix + "/devices/${name}");
|
||||
liminix-config = vanilla;
|
||||
liminix-config = cfg;
|
||||
}).outputs.default;
|
||||
tests = import ./tests/ci.nix;
|
||||
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 //
|
||||
{
|
||||
buildEnv = (import liminix {
|
||||
inherit nixpkgs borderVmConf;
|
||||
inherit nixpkgs borderVmConf;
|
||||
device = import (liminix + "/devices/qemu");
|
||||
liminix-config = vanilla;
|
||||
}).buildEnv;
|
||||
doc =
|
||||
let json =
|
||||
(import liminix {
|
||||
inherit nixpkgs borderVmConf;
|
||||
device = import (liminix + "/devices/qemu");
|
||||
liminix-config = {...} : {
|
||||
imports = [ ./modules/all-modules.nix ];
|
||||
};
|
||||
}).outputs.optionsJson;
|
||||
installers = map (f: "system.outputs.${f}") [
|
||||
"vmroot"
|
||||
"mtdimage"
|
||||
"ubimage"
|
||||
];
|
||||
inherit (pkgs.lib) concatStringsSep;
|
||||
in pkgs.stdenv.mkDerivation {
|
||||
name = "liminix-doc";
|
||||
nativeBuildInputs = with pkgs; [
|
||||
gnumake sphinx fennel luaPackages.lyaml
|
||||
];
|
||||
src = ./.;
|
||||
buildPhase = ''
|
||||
cat ${json} | fennel --correlate doc/parse-options.fnl > doc/modules-generated.rst
|
||||
cat ${json} | fennel --correlate doc/parse-options-outputs.fnl > doc/outputs-generated.rst
|
||||
cp ${(import ./doc/hardware.nix)} doc/hardware.rst
|
||||
make -C doc html
|
||||
'';
|
||||
installPhase = ''
|
||||
mkdir -p $out/nix-support $out/share/doc/
|
||||
cd doc
|
||||
cp *-generated.rst $out
|
||||
ln -s ${json} $out/options.json
|
||||
cp -a _build/html $out/share/doc/liminix
|
||||
echo "file source-dist \"$out/share/doc/liminix\"" \
|
||||
> $out/nix-support/hydra-build-products
|
||||
'';
|
||||
doc = pkgs.stdenv.mkDerivation {
|
||||
name = "liminix-doc";
|
||||
nativeBuildInputs = with pkgs; [
|
||||
gnumake sphinx
|
||||
fennel luaPackages.lyaml
|
||||
];
|
||||
src = ./doc;
|
||||
buildPhase = ''
|
||||
cat ${(import ./doc/extract-options.nix).doc} > options.json
|
||||
cat options.json | fennel --correlate parse-options.fnl > modules-generated.rst
|
||||
cp ${(import ./doc/hardware.nix)} hardware.rst
|
||||
make html
|
||||
'';
|
||||
installPhase = ''
|
||||
mkdir -p $out/nix-support $out/share/doc/
|
||||
cp modules.rst options.json $out
|
||||
cp -a _build/html $out/share/doc/liminix
|
||||
echo "file source-dist \"$out/share/doc/liminix\"" \
|
||||
> $out/nix-support/hydra-build-products
|
||||
'';
|
||||
};
|
||||
with-unstable = (import liminix {
|
||||
nixpkgs = unstable;
|
||||
|
14
default.nix
14
default.nix
@ -13,14 +13,13 @@ let
|
||||
allowUnsupportedSystem = true; # mipsel
|
||||
permittedInsecurePackages = [
|
||||
"python-2.7.18.6" # kernel backports needs python <3
|
||||
"python-2.7.18.7"
|
||||
];
|
||||
};
|
||||
});
|
||||
|
||||
eval = pkgs.lib.evalModules {
|
||||
config = (pkgs.lib.evalModules {
|
||||
modules = [
|
||||
{ _module.args = { inherit pkgs; inherit (pkgs) lim; }; }
|
||||
{ _module.args = { inherit pkgs; lib = pkgs.lib; }; }
|
||||
./modules/hardware.nix
|
||||
./modules/base.nix
|
||||
./modules/busybox.nix
|
||||
@ -31,8 +30,7 @@ let
|
||||
./modules/users.nix
|
||||
./modules/outputs.nix
|
||||
];
|
||||
};
|
||||
config = eval.config;
|
||||
}).config;
|
||||
|
||||
borderVm = ((import <nixpkgs/nixos/lib/eval-config.nix>) {
|
||||
system = builtins.currentSystem;
|
||||
@ -45,12 +43,6 @@ let
|
||||
in {
|
||||
outputs = config.system.outputs // {
|
||||
default = config.system.outputs.${config.hardware.defaultOutput};
|
||||
optionsJson =
|
||||
let o = import ./doc/extract-options.nix {
|
||||
inherit pkgs eval;
|
||||
lib = pkgs.lib;
|
||||
};
|
||||
in pkgs.writeText "options.json" (builtins.toJSON o);
|
||||
};
|
||||
|
||||
# this is just here as a convenience, so that we can get a
|
||||
|
@ -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 = {
|
||||
crossSystem = {
|
||||
config = "aarch64-unknown-linux-musl";
|
||||
};
|
||||
};
|
||||
|
||||
module = {pkgs, config, lib, lim, ... }:
|
||||
module = {pkgs, config, lib, ... }:
|
||||
let firmware = pkgs.stdenv.mkDerivation {
|
||||
name = "wlan-firmware";
|
||||
phases = ["installPhase"];
|
||||
@ -48,12 +19,7 @@
|
||||
'';
|
||||
};
|
||||
in {
|
||||
imports = [
|
||||
../../modules/arch/aarch64.nix
|
||||
../../modules/outputs/tftpboot.nix
|
||||
../../modules/outputs/ubifs.nix
|
||||
];
|
||||
config = {
|
||||
imports = [ ../../modules/arch/aarch64.nix ];
|
||||
kernel = {
|
||||
src = pkgs.pkgsBuildBuild.fetchurl {
|
||||
name = "linux.tar.gz";
|
||||
@ -100,6 +66,7 @@
|
||||
PCIE_MEDIATEK = "y";
|
||||
|
||||
BLOCK = "y"; # move this to base option
|
||||
NETDEVICES = "y"; # and this probably also
|
||||
|
||||
SPI_MASTER = "y";
|
||||
SPI = "y";
|
||||
@ -120,7 +87,10 @@
|
||||
MTD_SPI_NOR= "y";
|
||||
MTD_SPLIT_FIRMWARE= "y";
|
||||
MTD_SPLIT_FIT_FW= "y";
|
||||
|
||||
MTD_UBI="y";
|
||||
MTD_UBI_BEB_LIMIT="20";
|
||||
MTD_UBI_BLOCK="y";
|
||||
MTD_UBI_WL_THRESHOLD="4096";
|
||||
|
||||
MMC = "y";
|
||||
MMC_BLOCK = "y";
|
||||
@ -146,11 +116,9 @@
|
||||
SERIAL_OF_PLATFORM="y";
|
||||
};
|
||||
};
|
||||
boot = {
|
||||
commandLine = [ "console=ttyS0,115200" ];
|
||||
tftp.loadAddress = lim.parseInt "0x4007ff28";
|
||||
imageFormat = "fit";
|
||||
};
|
||||
boot.commandLine = [
|
||||
"console=ttyS0,115200"
|
||||
];
|
||||
filesystem =
|
||||
let inherit (pkgs.pseudofile) dir symlink;
|
||||
in
|
||||
@ -173,36 +141,19 @@
|
||||
klibBuild = config.system.outputs.kernel.modulesupport;
|
||||
};
|
||||
in {
|
||||
ubi = {
|
||||
minIOSize = "2048";
|
||||
eraseBlockSize = "126976";
|
||||
maxLEBcount = "1024"; # guessing
|
||||
};
|
||||
|
||||
defaultOutput = "ubimage";
|
||||
# the kernel expects this to be on a 2MB boundary. U-Boot
|
||||
# (I don't know why) has a default of 0x41080000, which isn't.
|
||||
# We put it at the 32MB mark so that tftpboot can put its rootfs
|
||||
# image and DTB underneath, but maybe this is a terrible waste of
|
||||
# RAM unless the kernel is able to reuse it later. Oh well
|
||||
loadAddress = lim.parseInt "0x42000000";
|
||||
entryPoint = lim.parseInt "0x42000000";
|
||||
rootDevice = "ubi0:liminix";
|
||||
defaultOutput = "flashimage";
|
||||
loadAddress = "0x41080000";
|
||||
entryPoint = "0x41080000";
|
||||
rootDevice = "/dev/mtdblock0";
|
||||
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 = [
|
||||
"${openwrt.src}/target/linux/mediatek/dts"
|
||||
"${config.system.outputs.kernel.modulesupport}/arch/arm64/boot/dts/mediatek/"
|
||||
];
|
||||
};
|
||||
|
||||
# - 0x000000000000-0x000008000000 : "spi-nand0"
|
||||
# - 0x000000000000-0x000000080000 : "bl2"
|
||||
# - 0x000000080000-0x0000001c0000 : "fip"
|
||||
# - 0x0000001c0000-0x0000002c0000 : "factory"
|
||||
# - 0x0000002c0000-0x000000300000 : "reserved"
|
||||
# - 0x000000300000-0x000008000000 : "ubi"
|
||||
|
||||
flash.eraseBlockSize = "65536"; # c.f. pkgs/mips-vm/mips-vm.sh
|
||||
networkInterfaces =
|
||||
let
|
||||
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 = {
|
||||
crossSystem = {
|
||||
@ -13,9 +21,6 @@
|
||||
GL.iNet GL-AR750
|
||||
****************
|
||||
|
||||
Hardware summary
|
||||
================
|
||||
|
||||
The GL-AR750 "Creta" travel router features:
|
||||
|
||||
- QCA9531 @650Mhz SoC
|
||||
@ -25,34 +30,29 @@
|
||||
- 16MB NOR Flash
|
||||
- supported in OpenWrt by the "ath79" SoC family
|
||||
|
||||
As with many GL.iNet devices, the stock vendor firmware
|
||||
is a fork of OpenWrt, meaning that the plain binary
|
||||
``firmware.bin`` that Liminix builds can be flashed using the
|
||||
vendor web UI and the U-Boot emergency "unbrick" routine
|
||||
|
||||
The GL-AR750 has two distinct sets of wifi hardware. The 2.4GHz
|
||||
radio is part of the QCA9531 SoC, i.e. it's on the same silicon as
|
||||
the CPU, the Ethernet, the USB etc. The device is connected to the
|
||||
host via `AHB <https://en.wikipedia.org/wiki/Advanced_Microcontroller_Bus_Architecture>`_ and it is
|
||||
supported in Linux using the ath9k driver. 5GHz wifi
|
||||
is provided by a QCA9887 PCIe (PCI embedded) WLAN chip,
|
||||
host via AHB, the "Advanced High-Performance Bus" and it is
|
||||
supported in Linux using the ath9k driver. The 5GHz support, on the
|
||||
other hand, is provided by a QCA9887 PCIe (PCI embedded) WLAN chip:
|
||||
I haven't looked closely at the router innards to see if this is
|
||||
actually physically a separate board that could be unplugged, but
|
||||
as far as Linux is concerned it behaves as one. This is
|
||||
supported by the ath10k driver.
|
||||
|
||||
Installation
|
||||
============
|
||||
|
||||
As with many GL.iNet devices, the stock vendor firmware
|
||||
is a fork of OpenWrt, meaning that the binary created by
|
||||
:ref:`system-outputs-mtdimage` can be flashed using the
|
||||
vendor web UI or the U-Boot emergency "unbrick" routine.
|
||||
|
||||
For flashing from an existing Liminix system (we believe that) it
|
||||
is necessary to first boot into a :ref:`system-outputs-kexecboot`
|
||||
system, otherwise you'll be overwriting flash partitions while
|
||||
they're in use - and that might not end well.
|
||||
|
||||
Vendor web page: https://www.gl-inet.com/products/gl-ar750/
|
||||
|
||||
OpenWrt web page: https://openwrt.org/toh/gl.inet/gl-ar750
|
||||
|
||||
'';
|
||||
|
||||
module = {pkgs, config, lim, ... }:
|
||||
module = {pkgs, config, ... }:
|
||||
let
|
||||
openwrt = pkgs.openwrt;
|
||||
firmwareBlobs = pkgs.pkgsBuildBuild.fetchFromGitHub {
|
||||
@ -77,8 +77,8 @@
|
||||
};
|
||||
ath10k_cal_data =
|
||||
let
|
||||
offset = lim.parseInt "0x5000";
|
||||
size = lim.parseInt "0x844";
|
||||
offset = 1024 * 20; # 0x5000
|
||||
size = 2048 + 68; # 0x844
|
||||
in pkgs.liminix.services.oneshot rec {
|
||||
name = "ath10k_cal_data";
|
||||
up = ''
|
||||
@ -96,22 +96,19 @@
|
||||
imports = [
|
||||
../../modules/network
|
||||
../../modules/arch/mipseb.nix
|
||||
../../modules/outputs/tftpboot.nix
|
||||
../../modules/outputs/mtdimage.nix
|
||||
../../modules/outputs/jffs2.nix
|
||||
];
|
||||
|
||||
programs.busybox.options = {
|
||||
FEATURE_DD_IBS_OBS = "y"; # ath10k_cal_data needs skip_bytes,fullblock
|
||||
};
|
||||
hardware = {
|
||||
defaultOutput = "mtdimage";
|
||||
loadAddress = lim.parseInt "0x80060000";
|
||||
entryPoint = lim.parseInt "0x80060000";
|
||||
defaultOutput = "flashimage";
|
||||
loadAddress = "0x80060000";
|
||||
entryPoint = "0x80060000";
|
||||
flash = {
|
||||
address = lim.parseInt "0x9F060000";
|
||||
size = lim.parseInt "0xfa0000";
|
||||
eraseBlockSize = 65536;
|
||||
address = "0x9F060000";
|
||||
size ="0xfa0000";
|
||||
eraseBlockSize = "65536";
|
||||
};
|
||||
rootDevice = "/dev/mtdblock5";
|
||||
dts = {
|
||||
@ -147,7 +144,7 @@
|
||||
};
|
||||
};
|
||||
boot.tftp = {
|
||||
loadAddress = lim.parseInt "0x00A00000";
|
||||
loadAddress = "0x00A00000";
|
||||
};
|
||||
kernel = {
|
||||
src = pkgs.pkgsBuildBuild.fetchurl {
|
||||
@ -155,14 +152,9 @@
|
||||
url = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.71.tar.gz";
|
||||
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 = ''
|
||||
${openwrt.applyPatches.ath79}
|
||||
'';
|
||||
|
||||
config = {
|
||||
ATH79 = "y";
|
||||
PCI = "y";
|
||||
@ -183,6 +175,7 @@
|
||||
CONSOLE_LOGLEVEL_QUIET = "4";
|
||||
|
||||
NET = "y";
|
||||
NETDEVICES = "y";
|
||||
ETHERNET = "y";
|
||||
NET_VENDOR_ATHEROS = "y";
|
||||
AG71XX = "y"; # ethernet (qca,qca9530-eth)
|
||||
|
@ -13,11 +13,34 @@
|
||||
|
||||
description = ''
|
||||
GL.iNet GL-MT300A
|
||||
*****************
|
||||
********************
|
||||
|
||||
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.
|
||||
|
||||
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
|
||||
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/
|
||||
|
||||
@ -43,7 +55,7 @@
|
||||
|
||||
'';
|
||||
|
||||
module = { pkgs, config, lib, lim, ...}:
|
||||
module = { pkgs, config, lib, ...}:
|
||||
let
|
||||
inherit (pkgs.liminix.networking) interface;
|
||||
inherit (pkgs) openwrt;
|
||||
@ -52,16 +64,11 @@
|
||||
klibBuild = config.system.outputs.kernel.modulesupport;
|
||||
};
|
||||
in {
|
||||
imports = [
|
||||
../../modules/arch/mipsel.nix
|
||||
../../modules/outputs/tftpboot.nix
|
||||
../../modules/outputs/mtdimage.nix
|
||||
../../modules/outputs/jffs2.nix
|
||||
];
|
||||
imports = [ ../../modules/arch/mipsel.nix ];
|
||||
hardware = {
|
||||
defaultOutput = "mtdimage";
|
||||
loadAddress = lim.parseInt "0x80000000";
|
||||
entryPoint = lim.parseInt "0x80000000";
|
||||
defaultOutput = "flashimage";
|
||||
loadAddress = "0x80000000";
|
||||
entryPoint = "0x80000000";
|
||||
|
||||
# Creating 5 MTD partitions on "spi0.0":
|
||||
# 0x000000000000-0x000000030000 : "u-boot"
|
||||
@ -74,9 +81,9 @@
|
||||
# 0x000000260000-0x000000f80000 : "rootfs"
|
||||
|
||||
flash = {
|
||||
address = lim.parseInt "0xbc050000";
|
||||
size = lim.parseInt "0xf80000";
|
||||
eraseBlockSize = 65536;
|
||||
address = "0xbc050000";
|
||||
size ="0xf80000";
|
||||
eraseBlockSize = "65536";
|
||||
};
|
||||
rootDevice = "/dev/mtdblock5";
|
||||
|
||||
@ -125,7 +132,7 @@
|
||||
};
|
||||
};
|
||||
boot.tftp = {
|
||||
loadAddress = lim.parseInt "0x00A00000";
|
||||
loadAddress = "0x00A00000";
|
||||
};
|
||||
|
||||
kernel = {
|
||||
@ -152,6 +159,7 @@
|
||||
CONSOLE_LOGLEVEL_QUIET = "4";
|
||||
|
||||
NET = "y";
|
||||
NETDEVICES = "y";
|
||||
ETHERNET = "y";
|
||||
NET_VENDOR_RALINK = "y";
|
||||
NET_RALINK_MDIO = "y";
|
||||
|
@ -13,22 +13,10 @@
|
||||
GL.iNet GL-MT300N-v2
|
||||
********************
|
||||
|
||||
The GL-MT300N-v2 "Mango" is is very similar to the :ref:`MT300A <GL.iNet GL-MT300A>, but is
|
||||
based on the MT7628 chipset instead of MT7620. It's also marginally cheaper
|
||||
and comes in a yellow case not a blue one. Be sure your device is
|
||||
v2 not v1, which is a different animal and has only half as much RAM.
|
||||
|
||||
Installation
|
||||
============
|
||||
|
||||
The stock vendor firmware is a fork of OpenWrt, meaning that the
|
||||
binary created by :ref:`system-outputs-mtdimage` can be flashed
|
||||
using the vendor web UI or the U-Boot emergency "unbrick" routine.
|
||||
|
||||
For flashing from an existing Liminix system (we think) it
|
||||
is necessary to first boot into a :ref:`system-outputs-kexecboot`
|
||||
system, otherwise you'll be overwriting flash partitions while
|
||||
they're in use - and that might not end well.
|
||||
The GL-MT300N-v2 "Mango" is is very similar to the MT300A, but is
|
||||
based on MT7628 instead of MT7620. It's also marginally cheaper
|
||||
and comes in a yellow case not a blue one. It's different again
|
||||
to the v1, which has only half the RAM.
|
||||
|
||||
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
|
||||
inherit (pkgs.liminix.networking) interface;
|
||||
inherit (pkgs.liminix.services) oneshot;
|
||||
@ -52,12 +40,7 @@
|
||||
hash = "sha256:1dkhfznmdz6s50kwc841x3wj0h6zg6icg5g2bim9pvg66as2vmh9";
|
||||
};
|
||||
in {
|
||||
imports = [
|
||||
../../modules/arch/mipsel.nix
|
||||
../../modules/outputs/tftpboot.nix
|
||||
../../modules/outputs/mtdimage.nix
|
||||
../../modules/outputs/jffs2.nix
|
||||
];
|
||||
imports = [ ../../modules/arch/mipsel.nix ];
|
||||
filesystem = dir {
|
||||
lib = dir {
|
||||
firmware = dir {
|
||||
@ -66,14 +49,14 @@
|
||||
};
|
||||
};
|
||||
hardware = {
|
||||
defaultOutput = "mtdimage";
|
||||
loadAddress = lim.parseInt "0x80000000";
|
||||
entryPoint = lim.parseInt "0x80000000";
|
||||
defaultOutput = "flashimage";
|
||||
loadAddress = "0x80000000";
|
||||
entryPoint = "0x80000000";
|
||||
|
||||
flash = {
|
||||
address = lim.parseInt "0xbc050000";
|
||||
size = lim.parseInt "0xfb0000";
|
||||
eraseBlockSize = 65536;
|
||||
address = "0xbc050000";
|
||||
size = "0xfb0000";
|
||||
eraseBlockSize = "65536";
|
||||
};
|
||||
rootDevice = "/dev/mtdblock5";
|
||||
|
||||
@ -121,7 +104,7 @@
|
||||
boot.tftp = {
|
||||
# 20MB seems to give enough room to uncompress the kernel
|
||||
# without anything getting trodden on. 10MB was too small
|
||||
loadAddress = lim.parseInt "0x1400000";
|
||||
loadAddress = "0x1400000";
|
||||
};
|
||||
|
||||
kernel = {
|
||||
@ -160,6 +143,7 @@
|
||||
REGULATOR_FIXED_VOLTAGE = "y";
|
||||
|
||||
NET = "y";
|
||||
NETDEVICES = "y";
|
||||
ETHERNET = "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
|
||||
installer = "vmroot";
|
||||
description = "";
|
||||
|
||||
module = {pkgs, config, lim, ... }: {
|
||||
imports = [
|
||||
../../modules/arch/aarch64.nix
|
||||
../families/qemu.nix
|
||||
];
|
||||
|
||||
module = {pkgs, config, ... }: {
|
||||
imports = [ ../../modules/arch/aarch64.nix ];
|
||||
kernel = {
|
||||
src = pkgs.pkgsBuildBuild.fetchurl {
|
||||
name = "linux.tar.gz";
|
||||
url = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.71.tar.gz";
|
||||
hash = "sha256-yhO2cXIeIgUxkSZf/4aAsF11uxyh+UUZu6D1h92vCD8=";
|
||||
};
|
||||
config = {
|
||||
VIRTUALIZATION = "y";
|
||||
PCI_HOST_GENERIC="y";
|
||||
|
||||
MTD = "y";
|
||||
MTD_BLOCK2MTD = "y";
|
||||
MTD_BLOCK = "y";
|
||||
|
||||
VIRTIO_MENU = "y";
|
||||
PCI = "y";
|
||||
VIRTIO_PCI = "y";
|
||||
BLOCK = "y";
|
||||
VIRTIO_BLK = "y";
|
||||
NETDEVICES = "y";
|
||||
VIRTIO_NET = "y";
|
||||
|
||||
SERIAL_EARLYCON_ARM_SEMIHOST = "y"; # earlycon=smh
|
||||
SERIAL_AMBA_PL011 = "y";
|
||||
SERIAL_AMBA_PL011_CONSOLE = "y";
|
||||
};
|
||||
@ -43,9 +45,31 @@
|
||||
boot.commandLine = [
|
||||
"console=ttyAMA0,38400"
|
||||
];
|
||||
hardware = let addr = lim.parseInt "0x40010000"; in {
|
||||
loadAddress = addr;
|
||||
entryPoint = addr;
|
||||
};
|
||||
hardware =
|
||||
let
|
||||
mac80211 = pkgs.mac80211.override {
|
||||
drivers = ["mac80211_hwsim"];
|
||||
klibBuild = config.system.outputs.kernel.modulesupport;
|
||||
};
|
||||
in {
|
||||
defaultOutput = "vmroot";
|
||||
loadAddress = "0x0";
|
||||
entryPoint = "0x0";
|
||||
rootDevice = "/dev/mtdblock0";
|
||||
|
||||
flash.eraseBlockSize = "65536"; # c.f. pkgs/mips-vm/mips-vm.sh
|
||||
networkInterfaces =
|
||||
let inherit (config.system.service.network) link;
|
||||
in {
|
||||
wan = link.build { ifname = "eth0"; };
|
||||
lan = link.build { ifname = "eth1"; };
|
||||
|
||||
wlan_24 = link.build {
|
||||
ifname = "wlan0";
|
||||
dependencies = [ mac80211 ];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
};
|
||||
}
|
||||
|
@ -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 = ''
|
||||
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
|
||||
virtualizer".
|
||||
|
||||
Liminix can build QEMU for both MIPS (:code:`qemu` device) and Aarch64 (:code:`qemu-aarch64` device)
|
||||
|
||||
MIPS QEMU emulates a "Malta" board, which was an ATX form factor
|
||||
evaluation board made by MIPS Technologies, but mostly in Liminix
|
||||
we use paravirtualized devices (Virtio) instead of emulating
|
||||
hardware.
|
||||
hardware. For Aarch64 we use the QEMU "virt" board.
|
||||
|
||||
Building an image for QEMU results in a :file:`result/` directory
|
||||
containing ``run.sh`` ``vmlinux``, and ``rootfs`` files. To invoke
|
||||
the emulator, run ``run.sh``.
|
||||
containing ``run.sh`` ``vmlinux``, ``rootfs`` and possibly
|
||||
(architecture-dependent) ``Image``. To invoke the emulator,
|
||||
run ``run.sh``.
|
||||
|
||||
The configuration includes two emulated "hardware" ethernet
|
||||
devices and the kernel :code:`mac80211_hwsim` module to
|
||||
@ -36,41 +39,56 @@
|
||||
in the Development manual.
|
||||
|
||||
'';
|
||||
module = {pkgs, config, lib, lim, ... }: {
|
||||
imports = [
|
||||
../../modules/arch/mipseb.nix
|
||||
../families/qemu.nix
|
||||
];
|
||||
module = {pkgs, config, ... }: {
|
||||
imports = [ ../../modules/arch/mipseb.nix ];
|
||||
kernel = {
|
||||
src = pkgs.pkgsBuildBuild.fetchurl {
|
||||
name = "linux.tar.gz";
|
||||
url = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.71.tar.gz";
|
||||
hash = "sha256-yhO2cXIeIgUxkSZf/4aAsF11uxyh+UUZu6D1h92vCD8=";
|
||||
};
|
||||
config = {
|
||||
MIPS_MALTA= "y";
|
||||
CPU_MIPS32_R2= "y";
|
||||
|
||||
POWER_RESET = "y";
|
||||
POWER_RESET_SYSCON = "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_8250= "y";
|
||||
SERIAL_8250_CONSOLE= "y";
|
||||
};
|
||||
};
|
||||
hardware =
|
||||
# from arch/mips/mti-malta/Platform:load-$(CONFIG_MIPS_MALTA) += 0xffffffff80100000
|
||||
let addr = lim.parseInt "0x80100000";
|
||||
in {
|
||||
loadAddress = addr;
|
||||
entryPoint = addr;
|
||||
|
||||
# Unlike the arm qemu targets, we need a static dts when
|
||||
# running u-boot-using tests, qemu dumpdtb command doesn't
|
||||
# work for this board. I am not at all sure this dts is
|
||||
# *correct* but it does at least boot
|
||||
dts = lib.mkForce {
|
||||
src = "${config.system.outputs.kernel.modulesupport}/arch/mips/boot/dts/mti/malta.dts";
|
||||
includes = [
|
||||
"${config.system.outputs.kernel.modulesupport}/arch/mips/boot/dts/"
|
||||
];
|
||||
let
|
||||
mac80211 = pkgs.mac80211.override {
|
||||
drivers = ["mac80211_hwsim"];
|
||||
klibBuild = config.system.outputs.kernel.modulesupport;
|
||||
};
|
||||
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
|
||||
server to download and flash the image. This is quite
|
||||
hardware-specific, and sometimes involves soldering: please refer
|
||||
to :ref:`serial`.
|
||||
to the :ref:`development manual <tftp server>`.
|
||||
|
||||
|
||||
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
|
||||
|
||||
This creates a :file:`result/` directory containing a :file:`vmlinux`
|
||||
and a :file:`rootfs`, and also a shell script :file:`run.sh` which
|
||||
invokes QEMU to run that kernel with that filesystem. It connects the Liminix
|
||||
In a ``buildEnv`` nix-shell, you can use the :command:`run-liminix-vm` command
|
||||
to run Qemu with appropriate options. It connects the Liminix
|
||||
serial console and the `QEMU monitor <https://www.qemu.org/docs/master/system/monitor.html>`_ to stdin/stdout. Use ^P (not ^A) to switch to the monitor.
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
nix-shell --run "run-liminix-vm result/vmlinux result/squashfs"
|
||||
|
||||
If you run with ``--background /path/to/some/directory`` as the first
|
||||
parameter, it will fork into the background and open Unix sockets in
|
||||
that directory for console and monitor. Use :command:`nix-shell --run
|
||||
connect-vm` to connect to either of these sockets, and ^O to
|
||||
disconnect.
|
||||
that directory for console and monitor. Use :command:`connect-vm`
|
||||
(also in the ``buildEnv`` environment) to connect to either of these
|
||||
sockets, and ^O to disconnect.
|
||||
|
||||
.. _qemu-networking:
|
||||
|
||||
@ -52,11 +55,9 @@ the right way:
|
||||
* multicast 230.0.0.1:1235 : lan
|
||||
* multicast 230.0.0.1:1236 : world (the internet)
|
||||
|
||||
Any VM started by a :command:`run.sh` script is connected to "lan" and
|
||||
"access", and the emulated border network gateway (see below) runs
|
||||
PPPoE and is connected to "access" and "world".
|
||||
|
||||
.. _border-network-gateway:
|
||||
A VM started with :command:`run-liminix-vm` is connected to "lan" and "access", and
|
||||
the emulated border network gateway (see below) runs PPPoE and is
|
||||
connected to "access" and "world".
|
||||
|
||||
Border Network Gateway
|
||||
----------------------
|
||||
@ -88,68 +89,6 @@ time with configurations for RP-PPPoE and/or Accel PPP.`
|
||||
Hardware devices
|
||||
****************
|
||||
|
||||
.. _serial:
|
||||
|
||||
U-Boot and serial shenanigans
|
||||
=============================
|
||||
|
||||
Every device that we have so far encountered in Liminix uses `U-Boot,
|
||||
the "Universal Boot Loader" <https://docs.u-boot.org/en/latest/>`_ so
|
||||
it's worth knowing a bit about it. "Universal" is in this context a
|
||||
bit of a misnomer, though: encountering *mainline* U-Boot is very rare
|
||||
and often you'll find it is a fork from some version last updated
|
||||
in 2008. Upgrading U-Boot is more or less complicated depending on the
|
||||
device and is outside scope for Liminix.
|
||||
|
||||
To speak to U-Boot on your device you'll usually need a serial
|
||||
connection to it. This is device-specific. Usually it involves
|
||||
opening the box, locating the serial header pins (TX, RX and GND) and
|
||||
connecting a USB TTL converter to them.
|
||||
|
||||
The Rolls Royce of USB/UART cables is the `FTDI cable
|
||||
<https://cpc.farnell.com/ftdi/ttl-232r-rpi/cable-debug-ttl-232-usb-rpi/dp/SC12825?st=usb%20to%20uart%20cable>`_,
|
||||
but there are cheaper alternatives based on the PL2303 and CP2102 chipsets. Or
|
||||
get creative and use the `UART GPIO pins <https://pinout.xyz/>`_ on a Raspberry Pi. Whatever you do, make sure
|
||||
that the voltages are compatible: if your device is 3.3V (this is
|
||||
typical but not universal), you don't want to be sending it 5v or
|
||||
(even worse) 12v.
|
||||
|
||||
Run a terminal emulator such as Minicom on the computer at other end
|
||||
of the link. 115200 8N1 is the typical speed.
|
||||
|
||||
.. NOTE::
|
||||
|
||||
TTL serial connections typically have no form of flow control and
|
||||
so don't always like having massive chunks of text pasted into
|
||||
them - and U-Boot may drop characters while it's busy. So don't
|
||||
necessarily expect to copy-paste large chunks of text into the
|
||||
terminal emulator and have it work just like that.
|
||||
|
||||
If using Minicom, you may find it helps to bring up the "Termimal
|
||||
settings" dialog (C^A T), then configure "Newline tx delay" to
|
||||
some small but non-zero value.
|
||||
|
||||
When you turn the router on you should be greeted with some messages
|
||||
from U-Boot, followed by the instruction to hit some key to stop
|
||||
autoboot. Do this and you will get to the prompt. If you didn't see
|
||||
anything, the strong likelihood is that TX and RX are the wrong way
|
||||
around. If you see garbage, try a different speed.
|
||||
|
||||
Interesting commands to try first in U-Boot are :command:`help` and
|
||||
:command:`printenv`.
|
||||
|
||||
To do anything useful with U-Boot you will probably need a way to get
|
||||
large binary files onto the device, and the usual way to do this is by
|
||||
adding a network connection and using TFTP to download them. It's
|
||||
quite common that the device's U-Boot doesn't speak DHCP so it will
|
||||
need a static LAN address. You might also want to keep it away from
|
||||
your "real" LAN: see :ref:`bng` for some potentially useful tooling
|
||||
to use it on an isolated network.
|
||||
|
||||
|
||||
TFTP
|
||||
====
|
||||
|
||||
.. _tftp server:
|
||||
|
||||
How you get your image onto hardware will vary according to the
|
||||
@ -180,7 +119,7 @@ Now add the device and server IP addresses to your configuration:
|
||||
};
|
||||
|
||||
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
|
||||
|
||||
* :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.
|
||||
|
||||
|
||||
.. _bng:
|
||||
|
||||
Networking
|
||||
==========
|
||||
|
||||
|
@ -1,10 +1,31 @@
|
||||
{ eval, lib, pkgs }:
|
||||
let
|
||||
overlay = import ../overlay.nix;
|
||||
pkgs = import <nixpkgs> ( {
|
||||
overlays = [overlay];
|
||||
config = {
|
||||
allowUnsupportedSystem = true; # mipsel
|
||||
permittedInsecurePackages = [
|
||||
"python-2.7.18.6" # kernel backports needs python <3
|
||||
];
|
||||
};
|
||||
});
|
||||
inherit (pkgs) lib;
|
||||
inherit (lib) types;
|
||||
modulenames =
|
||||
builtins.attrNames
|
||||
(lib.filterAttrsRecursive
|
||||
(n: t:
|
||||
(n != "arch") &&
|
||||
((t=="directory") ||
|
||||
((t=="regular") && ((builtins.match ".*\\.nix$" n) != null))))
|
||||
(builtins.readDir ../modules));
|
||||
modulefiles = builtins.map (n: builtins.toPath "${../modules}/${n}") modulenames;
|
||||
eval = (lib.evalModules {
|
||||
modules = [
|
||||
{ _module.args = { inherit pkgs; lib = pkgs.lib; }; }
|
||||
] ++ modulefiles;
|
||||
});
|
||||
conf = eval.config;
|
||||
rootDir = builtins.toPath ./..;
|
||||
stripAnyPrefixes = lib.flip (lib.fold lib.removePrefix)
|
||||
["${rootDir}/"];
|
||||
optToDoc = name: opt : {
|
||||
inherit name;
|
||||
description = opt.description or null;
|
||||
@ -21,12 +42,16 @@ let
|
||||
then
|
||||
let sd = lib.attrByPath item.loc ["not found"] conf;
|
||||
in item // {
|
||||
declarations = map stripAnyPrefixes item.declarations;
|
||||
parameters =
|
||||
let x = lib.mapAttrsToList optToDoc sd.parameters; in x;
|
||||
}
|
||||
else
|
||||
item // { declarations = map stripAnyPrefixes item.declarations; };
|
||||
in
|
||||
builtins.map spliceServiceDefn
|
||||
(pkgs.lib.optionAttrSetToDocList eval.options)
|
||||
item;
|
||||
o = builtins.map spliceServiceDefn
|
||||
(pkgs.lib.optionAttrSetToDocList eval.options);
|
||||
in {
|
||||
doc = pkgs.writeText "options.yaml" ''
|
||||
# ${./..}
|
||||
${builtins.toJSON o}
|
||||
'';
|
||||
}
|
||||
|
@ -1,23 +1,12 @@
|
||||
with import <nixpkgs> {} ;
|
||||
|
||||
let
|
||||
inherit (builtins) stringLength readDir filter;
|
||||
devices = filter (n: n != "families")
|
||||
(lib.mapAttrsToList (n: t: n) (readDir ../devices));
|
||||
texts = map (n:
|
||||
devices =
|
||||
builtins.readDir ../devices;
|
||||
texts = lib.mapAttrsToList (n: t:
|
||||
let d = import ../devices/${n}/default.nix;
|
||||
d' = {
|
||||
description = "${n}\n${substring 0 (stringLength n) "********************************"}\n";
|
||||
} // d;
|
||||
installer =
|
||||
if d ? description && d ? installer
|
||||
then ''
|
||||
|
||||
The default installation route for this device is
|
||||
:ref:`system-outputs-${d.installer}`
|
||||
''
|
||||
else "";
|
||||
in d'.description)
|
||||
d' = { description = "no description for ${n}"; } // d;
|
||||
in d'.description )
|
||||
devices;
|
||||
in
|
||||
writeText "hwdoc" ''
|
||||
|
@ -12,7 +12,6 @@ Liminix
|
||||
development
|
||||
modules
|
||||
hardware
|
||||
outputs
|
||||
|
||||
|
||||
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))
|
||||
|
||||
(fn basename [str ext]
|
||||
(-> str
|
||||
(string.gsub "(.*/)(.*)" "%2")
|
||||
(string.gsub (.. ext "$") "")))
|
||||
|
||||
(fn headline [name]
|
||||
(let [title (assert (basename name ".nix"))
|
||||
len (title:len)]
|
||||
(.. title "\n" (string.rep "=" len))))
|
||||
(let [(_ _ basename) (string.find name ".*/([^/].*).nix")
|
||||
len (basename:len)]
|
||||
(.. basename "\n" (string.rep "=" len))))
|
||||
|
||||
(fn read-preamble [pathname]
|
||||
(let [pathname (if (string.match pathname ".nix$")
|
||||
pathname
|
||||
(.. pathname "/default.nix"))]
|
||||
(with-open [f (assert (io.open pathname :r))]
|
||||
(accumulate [lines nil
|
||||
l (f:lines)
|
||||
:until (not (= (string.sub l 1 2) "##"))]
|
||||
(.. (or lines "") (string.gsub l "^## *" "") "\n")))))
|
||||
(if (= (pathname:sub 1 1) "/")
|
||||
(let [pathname (if (string.match pathname ".nix$")
|
||||
pathname
|
||||
(.. pathname "/default.nix"))]
|
||||
(with-open [f (assert (io.open pathname :r))]
|
||||
(accumulate [lines nil
|
||||
l (f:lines)
|
||||
:until (not (= (string.sub l 1 2) "##"))]
|
||||
(.. (or lines "") (string.gsub l "^## *" "") "\n"))))))
|
||||
|
||||
(fn relative-pathname [pathname]
|
||||
(let [pathname
|
||||
|
@ -69,11 +69,10 @@ device's serial console and the `QEMU monitor
|
||||
stdin/stdout.
|
||||
|
||||
You should now see Linux boot messages and after a few seconds be
|
||||
presented with a root shell prompt. You can run commands to look at
|
||||
the filesystem, see what processes are running, view log messages (in
|
||||
:file:/run/uncaught-logs.current), etc. To kill the emulator, press ^P
|
||||
(Control P) then c to enter the "QEMU Monitor", then type ``quit`` at
|
||||
the ``(qemu)`` prompt.
|
||||
presented with a login prompt. You can login on the console as
|
||||
``root`` (password is "secret") and poke around to see what processes are
|
||||
running. To kill the emulator, press ^P (Control P) then c to enter the
|
||||
"QEMU Monitor", then type ``quit`` at the ``(qemu)`` prompt.
|
||||
|
||||
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
|
||||
@ -138,12 +137,20 @@ unbrick if necessary.
|
||||
work here, but you accept the slightly greater bricking
|
||||
risk if it doesn't.
|
||||
|
||||
You may want to read and inwardly digest the Develoment Manual section
|
||||
:ref:`serial` when you start working with Liminix on real hardware. You
|
||||
won't *need* serial access for this example, assuming it works, but it
|
||||
You may want to acquire a `USB TTL serial cable
|
||||
<https://cpc.farnell.com/ftdi/ttl-232r-rpi/cable-debug-ttl-232-usb-rpi/dp/SC12825?st=usb%20to%20uart%20cable>`_
|
||||
when you start working with Liminix on real hardware. You
|
||||
won't *need* it for this example, assuming it works, but it
|
||||
allows you
|
||||
to see the boot monitor and kernel messages, and to login directly to
|
||||
the device if for some reason it doesn't bring its network up.
|
||||
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
|
||||
configuration as we did for Qemu, you might not want to plug a DHCP
|
||||
|
@ -24,6 +24,7 @@ in rec {
|
||||
};
|
||||
|
||||
imports = [
|
||||
../modules/standard.nix
|
||||
../modules/wlan.nix
|
||||
../modules/network
|
||||
../modules/vlan
|
||||
@ -31,6 +32,7 @@ in rec {
|
||||
../modules/watchdog
|
||||
../modules/mount
|
||||
];
|
||||
|
||||
hostname = "arhcive";
|
||||
|
||||
kernel = {
|
||||
|
@ -33,6 +33,7 @@ in rec {
|
||||
../modules/ntp
|
||||
../modules/ppp
|
||||
../modules/ssh
|
||||
../modules/standard.nix
|
||||
../modules/vlan
|
||||
../modules/wlan.nix
|
||||
];
|
||||
|
@ -30,6 +30,7 @@ in rec {
|
||||
../modules/hostapd
|
||||
../modules/bridge
|
||||
../modules/ssh
|
||||
../modules/standard.nix
|
||||
];
|
||||
|
||||
hostname = "extneder";
|
||||
|
@ -8,6 +8,7 @@ in rec {
|
||||
../modules/network
|
||||
../modules/ssh
|
||||
../modules/vlan
|
||||
../modules/flashimage.nix
|
||||
];
|
||||
|
||||
boot.tftp = {
|
||||
|
@ -34,6 +34,7 @@ in rec {
|
||||
|
||||
imports = [
|
||||
../modules/wlan.nix
|
||||
../modules/standard.nix
|
||||
../modules/network
|
||||
../modules/ppp
|
||||
../modules/dnsmasq
|
||||
@ -44,6 +45,7 @@ in rec {
|
||||
../modules/ntp
|
||||
../modules/ssh
|
||||
];
|
||||
rootfsType = "jffs2";
|
||||
hostname = "rotuer";
|
||||
|
||||
services.hostap = svc.hostapd.build {
|
||||
@ -181,8 +183,4 @@ in rec {
|
||||
defaultProfile.packages = with pkgs; [
|
||||
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 = {
|
||||
kernel.config = {
|
||||
@ -12,7 +12,5 @@
|
||||
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 = {
|
||||
kernel.config = {
|
||||
@ -10,7 +10,6 @@
|
||||
OF = "y";
|
||||
USE_OF = "y";
|
||||
};
|
||||
hardware.ram.startAddress = lim.parseInt "0x80000000";
|
||||
boot.commandLine = [
|
||||
"console=ttyS0,115200" # true of all mips we've yet encountered
|
||||
];
|
||||
|
@ -5,6 +5,5 @@
|
||||
kernel.config = {
|
||||
CPU_BIG_ENDIAN = "y";
|
||||
};
|
||||
system.outputs.u-boot = pkgs.ubootQemuMips;
|
||||
};
|
||||
}
|
||||
|
@ -39,12 +39,7 @@ in {
|
||||
};
|
||||
rootfsType = mkOption {
|
||||
default = "squashfs";
|
||||
type = types.enum [
|
||||
"ext4"
|
||||
"jffs2"
|
||||
"squashfs"
|
||||
"ubifs"
|
||||
];
|
||||
type = types.enum ["squashfs" "jffs2"];
|
||||
};
|
||||
boot = {
|
||||
commandLine = mkOption {
|
||||
@ -52,13 +47,9 @@ in {
|
||||
default = [];
|
||||
description = "Kernel command line";
|
||||
};
|
||||
imageFormat = mkOption {
|
||||
type = types.enum ["fit" "uimage"];
|
||||
default = "uimage";
|
||||
};
|
||||
tftp = {
|
||||
loadAddress = mkOption {
|
||||
type = types.ints.unsigned;
|
||||
type = types.str;
|
||||
description = ''
|
||||
RAM address at which to load data when transferring via
|
||||
TFTP. This is not the address of the flash storage,
|
||||
|
@ -11,7 +11,7 @@ in {
|
||||
options.system.outputs = {
|
||||
firmware = mkOption {
|
||||
type = types.package;
|
||||
internal = true; # component of mtdimage
|
||||
internal = true; # component of flashimage
|
||||
description = ''
|
||||
Binary image (combining kernel, FDT, rootfs, initramfs
|
||||
if needed, etc) for the target device.
|
||||
@ -19,40 +19,17 @@ in {
|
||||
};
|
||||
flash-scr = mkOption {
|
||||
type = types.package;
|
||||
internal = true; # component of mtdimage
|
||||
internal = true; # component of flashimage
|
||||
description = ''
|
||||
Copy-pastable U-Boot commands to TFTP download the
|
||||
image and write it to flash
|
||||
'';
|
||||
};
|
||||
mtdimage = mkOption {
|
||||
flashimage = mkOption {
|
||||
type = types.package;
|
||||
description = ''
|
||||
mtdimage
|
||||
**********
|
||||
|
||||
This creates an image called :file:`firmware.bin` suitable for
|
||||
squashfs or jffs2 systems. It can be flashed from U-Boot (if
|
||||
you have a serial console connection), or on some devices from
|
||||
the vendor firmware, or from a Liminix kexecboot system.
|
||||
|
||||
If you are flashing from U-Boot, the file
|
||||
:file:`flash.scr` is a sequence of commands
|
||||
which you can paste at the U-Boot prompt to
|
||||
to transfer the firmware file from a TFTP server and
|
||||
write it to flash. **Please read the script before
|
||||
running it: flash operations carry the potential to
|
||||
brick your device**
|
||||
|
||||
.. NOTE::
|
||||
|
||||
TTL serial connections typically have no form of flow
|
||||
control and so don't always like having massive chunks of
|
||||
text pasted into them - and U-Boot may drop characters
|
||||
while it's busy. So don't necessarily expect to copy-paste
|
||||
the whole of :file:`flash.scr` into a terminal emulator and
|
||||
have it work just like that. You may need to paste each
|
||||
line one at a time, or even retype it.
|
||||
Flashable image for the target device, and the script to
|
||||
install it
|
||||
'';
|
||||
};
|
||||
};
|
||||
@ -75,15 +52,15 @@ in {
|
||||
firmware =
|
||||
let
|
||||
o = config.system.outputs;
|
||||
bs = toString config.hardware.flash.eraseBlockSize;
|
||||
bs = config.hardware.flash.eraseBlockSize;
|
||||
in pkgs.runCommand "firmware" {} ''
|
||||
dd if=${o.uimage} of=$out bs=${bs} conv=sync
|
||||
dd if=${o.rootfs} of=$out bs=${bs} conv=sync,nocreat,notrunc oflag=append
|
||||
'';
|
||||
mtdimage =
|
||||
flashimage =
|
||||
let o = config.system.outputs; in
|
||||
# could use trivial-builders.linkFarmFromDrvs here?
|
||||
pkgs.runCommand "mtdimage" {} ''
|
||||
pkgs.runCommand "flashimage" {} ''
|
||||
mkdir $out
|
||||
cd $out
|
||||
ln -s ${o.firmware} firmware.bin
|
||||
@ -106,9 +83,9 @@ in {
|
||||
cat > $out << EOF
|
||||
setenv serverip ${tftp.serverip}
|
||||
setenv ipaddr ${tftp.ipaddr}
|
||||
tftp 0x${toHexString tftp.loadAddress} result/firmware.bin
|
||||
erase 0x${toHexString flash.address} +0x${toHexString flash.size}
|
||||
cp.b 0x${toHexString tftp.loadAddress} 0x${toHexString flash.address} \''${filesize}
|
||||
tftp 0x$(printf %x ${tftp.loadAddress}) result/firmware.bin
|
||||
erase 0x$(printf %x ${flash.address}) +${flash.size}
|
||||
cp.b 0x$(printf %x ${tftp.loadAddress}) 0x$(printf %x ${flash.address}) \''${filesize}
|
||||
echo command line was ${builtins.toJSON (concatStringsSep " " config.boot.commandLine)}
|
||||
EOF
|
||||
'';
|
@ -16,14 +16,8 @@ in {
|
||||
hardware = {
|
||||
dts = {
|
||||
src = mkOption {
|
||||
type = types.nullOr types.path;
|
||||
description = ''
|
||||
If the device requires an external device tree to be loaded
|
||||
alongside the kernel, this is the path to the device tree source
|
||||
(we usually get these from OpenWrt). This value may be null if the
|
||||
platform creates the device tree - currently this is the case
|
||||
only for QEMU.
|
||||
'';
|
||||
type = types.path;
|
||||
description = "Path to the device tree source (usually from OpenWrt)";
|
||||
};
|
||||
includes = mkOption {
|
||||
default = [];
|
||||
@ -32,15 +26,9 @@ in {
|
||||
};
|
||||
};
|
||||
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;
|
||||
};
|
||||
ram = {
|
||||
startAddress = mkOption {
|
||||
type = types.int;
|
||||
};
|
||||
};
|
||||
|
||||
flash = {
|
||||
# start address and size of whichever partition (often
|
||||
# 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
|
||||
we don't want to clobber the bootloader, calibration data etc
|
||||
'';
|
||||
type = types.ints.unsigned;
|
||||
type = types.str;
|
||||
};
|
||||
size = mkOption {
|
||||
type = types.ints.unsigned;
|
||||
type = types.str;
|
||||
description = "Size in bytes of the firmware partition";
|
||||
};
|
||||
eraseBlockSize = mkOption {
|
||||
description = "Flash erase block size in bytes";
|
||||
type = types.ints.unsigned;
|
||||
type = types.str;
|
||||
};
|
||||
};
|
||||
loadAddress = mkOption { type = types.ints.unsigned; default = null; };
|
||||
entryPoint = mkOption { type = types.ints.unsigned; };
|
||||
loadAddress = mkOption { default = null; };
|
||||
entryPoint = mkOption { };
|
||||
radios = mkOption {
|
||||
description = ''
|
||||
Kernel modules (from mac80211 package) required for the
|
||||
|
@ -13,23 +13,13 @@ in
|
||||
boot.initramfs = {
|
||||
enable = mkEnableOption "initramfs";
|
||||
};
|
||||
system.outputs = {
|
||||
initramfs = mkOption {
|
||||
type = types.package;
|
||||
internal = true;
|
||||
description = ''
|
||||
Initramfs image capable of mounting the real root
|
||||
filesystem
|
||||
'';
|
||||
};
|
||||
systemConfiguration = mkOption {
|
||||
type = types.package;
|
||||
description = ''
|
||||
pkgs.systemconfig for the configured filesystem,
|
||||
contains 'activate' and 'init' commands
|
||||
'';
|
||||
internal = true;
|
||||
};
|
||||
system.outputs.initramfs = mkOption {
|
||||
type = types.package;
|
||||
internal = true;
|
||||
description = ''
|
||||
Initramfs image capable of mounting the jffs2 root
|
||||
filesystem
|
||||
'';
|
||||
};
|
||||
};
|
||||
config = mkIf config.boot.initramfs.enable {
|
||||
@ -47,14 +37,18 @@ in
|
||||
dir /proc 0755 0 0
|
||||
dir /dev 0755 0 0
|
||||
nod /dev/console 0600 0 0 c 5 1
|
||||
nod /dev/mtdblock0 0600 0 0 b 31 0
|
||||
nod /dev/mtdblock1 0600 0 0 b 31 1
|
||||
nod /dev/mtdblock2 0600 0 0 b 31 2
|
||||
nod /dev/mtdblock3 0600 0 0 b 31 3
|
||||
nod /dev/mtdblock4 0600 0 0 b 31 4
|
||||
nod /dev/mtdblock5 0600 0 0 b 31 5
|
||||
dir /target 0755 0 0
|
||||
dir /target/persist 0755 0 0
|
||||
dir /target/nix 0755 0 0
|
||||
file /init ${pkgs.preinit}/bin/preinit 0755 0 0
|
||||
SPECIALS
|
||||
'';
|
||||
systemConfiguration =
|
||||
pkgs.systemconfig config.filesystem.contents;
|
||||
};
|
||||
};
|
||||
}
|
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.liminix.networking) address interface;
|
||||
inherit (pkgs.liminix.services) bundle;
|
||||
inherit (pkgs) liminix;
|
||||
|
||||
type_service = pkgs.liminix.lib.types.service;
|
||||
|
||||
in {
|
||||
options = {
|
||||
kernel = {
|
||||
src = mkOption { type = types.path; } ;
|
||||
src = mkOption { type = types.package; } ;
|
||||
modular = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
@ -42,25 +41,11 @@ in {
|
||||
};
|
||||
'';
|
||||
};
|
||||
makeTargets = mkOption {
|
||||
type = types.listOf types.str;
|
||||
};
|
||||
};
|
||||
};
|
||||
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 {
|
||||
modular = true; # disabling this is not yet supported
|
||||
makeTargets = ["vmlinux"];
|
||||
config = {
|
||||
IKCONFIG = "y";
|
||||
IKCONFIG_PROC = "y";
|
||||
@ -79,8 +64,6 @@ in {
|
||||
PACKET = "y"; # for ppp, tcpdump ...
|
||||
SYSVIPC= "y";
|
||||
|
||||
NETDEVICES = "y"; # even PPP needs this
|
||||
|
||||
# disabling this option causes the kernel to use an "empty"
|
||||
# initramfs instead: it has a /dev/console node and not much
|
||||
# else. Note that pid 1 is started *before* the root
|
||||
|
@ -7,7 +7,7 @@
|
||||
let
|
||||
inherit (lib) mkOption mkForce types concatStringsSep;
|
||||
in {
|
||||
imports = [ ../ramdisk.nix ];
|
||||
imports = [ ./ramdisk.nix ];
|
||||
options.system.outputs = {
|
||||
kexecboot = mkOption {
|
||||
type = types.package;
|
@ -68,21 +68,7 @@ in {
|
||||
ifname = mkOption {
|
||||
type = types.str;
|
||||
example = "eth0";
|
||||
description = ''
|
||||
Device name as used by the kernel (as seen in "ip link"
|
||||
or "ifconfig" output). If devpath is also specified, the
|
||||
device will be renamed to the name provided.
|
||||
'';
|
||||
};
|
||||
devpath = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
example = "/devices/platform/soc/soc:internal-regs/f1070000.ethernet";
|
||||
description = ''
|
||||
Path to the sysfs node of the device. If you provide this
|
||||
and the ifname option, the device will be renamed to the
|
||||
name given by ifname.
|
||||
''; };
|
||||
# other "ip link add" options could go here as well
|
||||
mtu = mkOption {
|
||||
type = types.nullOr types.int;
|
||||
|
@ -4,27 +4,13 @@
|
||||
, serviceFns
|
||||
, lib
|
||||
}:
|
||||
{
|
||||
ifname
|
||||
, devpath ? null
|
||||
, mtu} :
|
||||
# if devpath is supplied, we rename the interface at that
|
||||
# path to have the specified name.
|
||||
{ifname, mtu} :
|
||||
let
|
||||
inherit (liminix.services) longrun oneshot;
|
||||
inherit (lib) concatStringsSep;
|
||||
name = "${ifname}.link";
|
||||
rename = if devpath != null
|
||||
then ''
|
||||
oldname=$(cd /sys${devpath} && cd net/ && echo *)
|
||||
ip link set ''${oldname} name ${ifname}
|
||||
''
|
||||
else "";
|
||||
up = liminix.networking.ifup name ifname;
|
||||
in oneshot {
|
||||
inherit name;
|
||||
up = ''
|
||||
${rename}
|
||||
${liminix.networking.ifup name ifname}
|
||||
'';
|
||||
inherit name up;
|
||||
down = "ip link set down dev ${ifname}";
|
||||
}
|
||||
|
@ -7,132 +7,103 @@
|
||||
let
|
||||
inherit (lib) mkOption types concatStringsSep;
|
||||
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
|
||||
{
|
||||
imports = [
|
||||
./squashfs.nix
|
||||
./outputs/vmroot.nix
|
||||
./outputs/extlinux.nix
|
||||
];
|
||||
options = {
|
||||
system.outputs = {
|
||||
# the convention here is to mark an output as "internal" if
|
||||
# it's not a complete system (kernel plus userland, or installer)
|
||||
# but only part of one.
|
||||
kernel = mkOption {
|
||||
type = types.package;
|
||||
internal = true;
|
||||
description = ''
|
||||
kernel
|
||||
******
|
||||
|
||||
Kernel vmlinux file (usually ELF)
|
||||
'';
|
||||
};
|
||||
zimage = mkOption {
|
||||
type = types.package;
|
||||
internal = true;
|
||||
description = ''
|
||||
zimage
|
||||
******
|
||||
|
||||
Kernel in compressed self-extracting package
|
||||
'';
|
||||
};
|
||||
dtb = mkOption {
|
||||
type = types.package;
|
||||
internal = true;
|
||||
description = ''
|
||||
dtb
|
||||
***
|
||||
|
||||
Compiled device tree (FDT) for the target device
|
||||
'';
|
||||
};
|
||||
uimage = mkOption {
|
||||
type = types.package;
|
||||
internal = true;
|
||||
description = ''
|
||||
uimage
|
||||
******
|
||||
|
||||
Combined kernel and FDT in uImage (U-Boot compatible) format
|
||||
'';
|
||||
};
|
||||
u-boot = mkOption {
|
||||
vmroot = mkOption {
|
||||
type = types.package;
|
||||
description = ''
|
||||
Directory containing separate kernel and rootfs image for
|
||||
use with qemu (see run-liminix-vm)
|
||||
'';
|
||||
};
|
||||
manifest = mkOption {
|
||||
type = types.package;
|
||||
internal = true;
|
||||
description = ''
|
||||
Debugging aid. JSON rendition of config.filesystem, on
|
||||
which can run "nix-store -q --tree" on it and find
|
||||
out what's in the image, which is nice if it's unexpectedly huge
|
||||
'';
|
||||
};
|
||||
rootdir = mkOption {
|
||||
type = types.package;
|
||||
internal = true;
|
||||
description = ''
|
||||
directory of files to package into root filesystem
|
||||
'';
|
||||
};
|
||||
bootablerootdir = mkOption {
|
||||
type = types.package;
|
||||
internal = true;
|
||||
description = ''
|
||||
directory of files to package into root filesystem, including
|
||||
a kernel and appropriate associated gubbins for the
|
||||
selected bootloader
|
||||
'';
|
||||
};
|
||||
rootfs = mkOption {
|
||||
type = types.package;
|
||||
internal = true;
|
||||
description = ''
|
||||
root filesystem (squashfs or jffs2) image
|
||||
'';
|
||||
internal = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
config = {
|
||||
system.outputs = rec {
|
||||
# tftpd = pkgs.buildPackages.tufted;
|
||||
kernel = liminix.builders.kernel.override {
|
||||
inherit (config.kernel) config src extraPatchPhase;
|
||||
};
|
||||
dtb = liminix.builders.dtb {
|
||||
inherit (config.boot) commandLine;
|
||||
dts = config.hardware.dts.src;
|
||||
includes = config.hardware.dts.includes ++ [
|
||||
"${o.kernel.headers}/include"
|
||||
"${kernel.headers}/include"
|
||||
];
|
||||
};
|
||||
uimage = liminix.builders.uimage {
|
||||
commandLine = concatStringsSep " " config.boot.commandLine;
|
||||
inherit (config.hardware) loadAddress entryPoint;
|
||||
inherit (config.boot) imageFormat;
|
||||
inherit (o) kernel dtb;
|
||||
inherit kernel;
|
||||
inherit dtb;
|
||||
};
|
||||
rootdir =
|
||||
# could use trivial-builders.linkFarmFromDrvs here?
|
||||
vmroot =
|
||||
let
|
||||
inherit (pkgs.pkgsBuildBuild) runCommand;
|
||||
in runCommand "mktree" { } ''
|
||||
mkdir -p $out/nix/store/ $out/secrets $out/boot
|
||||
cp ${o.systemConfiguration}/bin/activate $out/activate
|
||||
ln -s ${pkgs.s6-init-bin}/bin/init $out/init
|
||||
mkdir -p $out/nix/store
|
||||
for path in $(cat ${o.systemConfiguration}/etc/nix-store-paths) ; do
|
||||
(cd $out && cp -a $path .$path)
|
||||
done
|
||||
'';
|
||||
bootablerootdir =
|
||||
let inherit (pkgs.pkgsBuildBuild) runCommand;
|
||||
in runCommand "add-slash-boot" { } ''
|
||||
cp -a ${o.rootdir} $out
|
||||
${if config.boot.loader.extlinux.enable
|
||||
then "(cd $out && chmod -R +w . && rmdir boot && cp -a ${o.extlinux} boot)"
|
||||
else ""
|
||||
}
|
||||
'';
|
||||
cmdline = builtins.toJSON (concatStringsSep " " config.boot.commandLine);
|
||||
makeBootableImage = pkgs.runCommandCC "objcopy" {}
|
||||
(if pkgs.stdenv.isAarch64
|
||||
then "${pkgs.stdenv.cc.targetPrefix}objcopy -O binary -S ${kernel} $out"
|
||||
else "cp ${kernel} $out");
|
||||
in pkgs.runCommandCC "vmroot" {} ''
|
||||
mkdir $out
|
||||
cd $out
|
||||
ln -s ${config.system.outputs.rootfs} rootfs
|
||||
ln -s ${kernel} vmlinux
|
||||
ln -s ${manifest} manifest
|
||||
ln -s ${kernel.headers} build
|
||||
echo ${cmdline} > commandline
|
||||
cat > run.sh << EOF
|
||||
#!${pkgs.runtimeShell}
|
||||
CMDLINE=${cmdline} ${pkgs.pkgsBuildBuild.run-liminix-vm}/bin/run-liminix-vm --arch ${arch} \$* ${makeBootableImage} ${config.system.outputs.rootfs}
|
||||
EOF
|
||||
chmod +x run.sh
|
||||
'';
|
||||
|
||||
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 = {
|
||||
file = ''
|
||||
#!${execline}/bin/execlineb -P
|
||||
importas PATH PATH
|
||||
export PATH ${s6}/bin:''${PATH}
|
||||
foreground { echo path is ''${PATH} }
|
||||
${s6-linux-init}/bin/s6-linux-init-shutdownd -c "/etc/s6-linux-init/current" -g 3000
|
||||
'';
|
||||
mode = "0755";
|
||||
@ -81,44 +78,26 @@ let
|
||||
};
|
||||
getty = dir {
|
||||
run = {
|
||||
# We can't run a useful shell on /dev/console because
|
||||
# /dev/console is not allowed to be the controlling
|
||||
# tty of any process, which means ^C ^Z etc don't work.
|
||||
# So we work out what the *actual* console device is
|
||||
# using sysfs and open our shell there instead.
|
||||
file = ''
|
||||
#!${execline}/bin/execlineb -P
|
||||
${execline}/bin/cd /
|
||||
redirfd -r 0 /sys/devices/virtual/tty/console/active
|
||||
withstdinas CONSOLETTY
|
||||
importas CONSOLETTY CONSOLETTY
|
||||
redirfd -w 2 /dev/''${CONSOLETTY}
|
||||
fdmove -c 1 2
|
||||
redirfd -r 0 /dev/''${CONSOLETTY}
|
||||
/bin/ash -l
|
||||
'';
|
||||
#!${execline}/bin/execlineb -P
|
||||
/bin/getty -l /bin/login 115200 /dev/console
|
||||
'';
|
||||
mode = "0755";
|
||||
};
|
||||
down-signal = {
|
||||
file = "HUP\n";
|
||||
};
|
||||
};
|
||||
".s6-svscan" =
|
||||
let
|
||||
openConsole = ''
|
||||
#!${execline}/bin/execlineb -P
|
||||
${execline}/bin/redirfd -w 2 /dev/console
|
||||
${execline}/bin/fdmove -c 1 2
|
||||
'';
|
||||
quit = message: ''
|
||||
${openConsole}
|
||||
${execline}/bin/foreground { ${s6-linux-init}/bin/s6-linux-init-echo -- ${message} }
|
||||
${s6-linux-init}/bin/s6-linux-init-hpr -fr
|
||||
'';
|
||||
#!${execline}/bin/execlineb -P
|
||||
${execline}/bin/redirfd -w 2 /dev/console
|
||||
${execline}/bin/fdmove -c 1 2
|
||||
${execline}/bin/foreground { ${s6-linux-init}/bin/s6-linux-init-echo -- ${message} }
|
||||
${s6-linux-init}/bin/s6-linux-init-hpr -fr
|
||||
'';
|
||||
shutdown = action: ''
|
||||
#!${execline}/bin/execlineb -P
|
||||
${s6-linux-init}/bin/s6-linux-init-shutdown -a #{action} -- now
|
||||
'';
|
||||
#!${execline}/bin/execlineb -P
|
||||
${s6-linux-init}/bin/s6-linux-init-hpr -a #{action} -- now
|
||||
'';
|
||||
empty = "#!${execline}/bin/execlineb -P\n";
|
||||
in dir {
|
||||
crash = {
|
||||
@ -126,13 +105,7 @@ let
|
||||
mode = "0755";
|
||||
};
|
||||
finish = {
|
||||
file = ''
|
||||
${openConsole}
|
||||
ifelse { test -x /run/maintenance/exec } { /run/maintenance/exec }
|
||||
foreground { echo "s6-svscan exited. Rebooting." }
|
||||
wait { }
|
||||
${s6-linux-init}/bin/s6-linux-init-hpr -fr
|
||||
'';
|
||||
file = quit "s6-svscan exited. Rebooting.";
|
||||
mode = "0755";
|
||||
};
|
||||
SIGINT = {
|
||||
@ -168,6 +141,7 @@ let
|
||||
};
|
||||
in {
|
||||
config = {
|
||||
programs.busybox.applets = [ "login" "getty" ];
|
||||
filesystem = dir {
|
||||
etc = dir {
|
||||
s6-rc = dir {
|
||||
|
@ -1,22 +1,18 @@
|
||||
#!/bin/sh -e
|
||||
|
||||
## s6-linux-init-shutdownd never tells s6-svscan to exit, so if
|
||||
## you're running s6-linux-init, it's normal that your
|
||||
## .s6-svscan/finish script is not executed.
|
||||
### Things to do *right before* the machine gets rebooted or
|
||||
### powered off, at the very end of the shutdown sequence,
|
||||
### when all the filesystems are unmounted.
|
||||
|
||||
## The place where you want to hack things is /etc/rc.shutdown.final,
|
||||
## which is run by the stage 4 script right before the hard reboot.
|
||||
## So you can do dirty stuff [...] which should clean up the
|
||||
## s6-supervise and the foreground, and give control to
|
||||
## .s6-svscan/finish.
|
||||
### This is a last resort hook; normally nothing should be
|
||||
### done here (your rc.shutdown script should have taken care
|
||||
### of everything) and you should leave this script empty.
|
||||
|
||||
## -- Laurent Bercot on skaware mailing list,
|
||||
## https://skarnet.org/lists/skaware/1913.html
|
||||
### Some distributions, however, may need to perform some
|
||||
### actions after unmounting the filesystems: typically if
|
||||
### an additional teardown action is required on a filesystem
|
||||
### after unmounting it, or if the system needs to be
|
||||
### pivot_rooted before it can be shut down, etc.
|
||||
|
||||
exec >/dev/console 2>&1
|
||||
|
||||
# down, exit supervisor, wait, stay down
|
||||
s6-svc -dxwD /run/service/s6-linux-init-shutdownd
|
||||
# HUP, exit supervisor, wait, down
|
||||
s6-svc -hxwd /run/service/s6-svscan-log
|
||||
s6-svscanctl -b /run/service # abort
|
||||
### Those are all exceptional cases. If you don't know for
|
||||
### certain that you need to do something here, you don't.
|
||||
|
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;
|
||||
in
|
||||
extraPkgs // {
|
||||
# liminix library functions
|
||||
lim = {
|
||||
parseInt = s : (builtins.fromTOML "r=${s}").r;
|
||||
};
|
||||
mtdutils = prev.mtdutils.overrideAttrs(o: {
|
||||
patches = (if o ? patches then o.patches else []) ++ [
|
||||
./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 =
|
||||
let chrony' = prev.chrony.overrideAttrs(o: {
|
||||
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 =
|
||||
let d = prev.dnsmasq.overrideAttrs(o: {
|
||||
@ -83,15 +134,6 @@ extraPkgs // {
|
||||
nettle = null;
|
||||
};
|
||||
|
||||
dropbear = prev.dropbear.overrideAttrs (o: {
|
||||
postPatch = ''
|
||||
(echo '#define DSS_PRIV_FILENAME "/run/dropbear/dropbear_dss_host_key"'
|
||||
echo '#define RSA_PRIV_FILENAME "/run/dropbear/dropbear_rsa_host_key"'
|
||||
echo '#define ECDSA_PRIV_FILENAME "/run/dropbear/dropbear_ecdsa_host_key"'
|
||||
echo '#define ED25519_PRIV_FILENAME "/run/dropbear/dropbear_ed25519_host_key"') > localoptions.h
|
||||
'';
|
||||
});
|
||||
|
||||
hostapd =
|
||||
let
|
||||
config = [
|
||||
@ -119,40 +161,13 @@ extraPkgs // {
|
||||
});
|
||||
in h.override { openssl = null; sqlite = null; };
|
||||
|
||||
kexec-tools-static = prev.kexec-tools.overrideAttrs(o: {
|
||||
# For kexecboot we copy kexec into a ramdisk on the system being
|
||||
# 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;
|
||||
|
||||
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"
|
||||
];
|
||||
dropbear = prev.dropbear.overrideAttrs (o: {
|
||||
postPatch = ''
|
||||
(echo '#define DSS_PRIV_FILENAME "/run/dropbear/dropbear_dss_host_key"'
|
||||
echo '#define RSA_PRIV_FILENAME "/run/dropbear/dropbear_rsa_host_key"'
|
||||
echo '#define ECDSA_PRIV_FILENAME "/run/dropbear/dropbear_ecdsa_host_key"'
|
||||
echo '#define ED25519_PRIV_FILENAME "/run/dropbear/dropbear_ed25519_host_key"') > localoptions.h
|
||||
'';
|
||||
});
|
||||
|
||||
openssl = prev.openssl.overrideAttrs (o: {
|
||||
@ -169,92 +184,4 @@ extraPkgs // {
|
||||
});
|
||||
|
||||
pppBuild = prev.ppp;
|
||||
|
||||
qemuLim = let q = prev.qemu.overrideAttrs (o: {
|
||||
patches = o.patches ++ [
|
||||
./pkgs/qemu/arm-image-friendly-load-addr.patch
|
||||
];
|
||||
}); in q.override { nixosTestRunner = true; sdlSupport = false; };
|
||||
|
||||
rsyncSmall =
|
||||
let r = prev.rsync.overrideAttrs(o: {
|
||||
configureFlags = o.configureFlags ++ [
|
||||
"--disable-openssl"
|
||||
];
|
||||
});
|
||||
in r.override { openssl = null; };
|
||||
|
||||
|
||||
inherit s6;
|
||||
s6-linux-init = prev.s6-linux-init.override {
|
||||
skawarePackages = prev.skawarePackages // {
|
||||
inherit s6;
|
||||
};
|
||||
};
|
||||
s6-rc = prev.s6-rc.override {
|
||||
skawarePackages = prev.skawarePackages // {
|
||||
inherit s6;
|
||||
};
|
||||
};
|
||||
|
||||
strace = prev.strace.override { libunwind = null; };
|
||||
|
||||
ubootQemuAarch64 = final.buildUBoot {
|
||||
defconfig = "qemu_arm64_defconfig";
|
||||
extraMeta.platforms = ["aarch64-linux"];
|
||||
filesToInstall = ["u-boot.bin"];
|
||||
};
|
||||
|
||||
ubootQemuArm = final.buildUBoot {
|
||||
defconfig = "qemu_arm_defconfig";
|
||||
extraMeta.platforms = ["armv7l-linux"];
|
||||
filesToInstall = ["u-boot.bin"];
|
||||
extraConfig = ''
|
||||
CONFIG_CMD_UBI=y
|
||||
CONFIG_CMD_UBIFS=y
|
||||
CONFIG_BOOTSTD=y
|
||||
CONFIG_BOOTMETH_DISTRO=y
|
||||
CONFIG_LZMA=y
|
||||
CONFIG_CMD_LZMADEC=y
|
||||
CONFIG_SYS_BOOTM_LEN=0x1000000
|
||||
'';
|
||||
};
|
||||
|
||||
ubootQemuMips = final.buildUBoot {
|
||||
defconfig = "malta_defconfig";
|
||||
extraMeta.platforms = ["mips-linux"];
|
||||
filesToInstall = ["u-boot.bin"];
|
||||
# define the prompt to be the same as arm{32,64} so
|
||||
# we can use the same expect script for both
|
||||
extraPatches = [ ./pkgs/u-boot/0002-virtio-init-for-malta.patch ];
|
||||
extraConfig = ''
|
||||
CONFIG_SYS_PROMPT="=> "
|
||||
CONFIG_VIRTIO=y
|
||||
CONFIG_AUTOBOOT=y
|
||||
CONFIG_DM_PCI=y
|
||||
CONFIG_VIRTIO_PCI=y
|
||||
CONFIG_VIRTIO_NET=y
|
||||
CONFIG_VIRTIO_BLK=y
|
||||
CONFIG_VIRTIO_MMIO=y
|
||||
CONFIG_QFW_MMIO=y
|
||||
CONFIG_FIT=y
|
||||
CONFIG_LZMA=y
|
||||
CONFIG_CMD_LZMADEC=y
|
||||
CONFIG_SYS_BOOTM_LEN=0x1000000
|
||||
CONFIG_SYS_MALLOC_LEN=0x400000
|
||||
CONFIG_MIPS_BOOT_FDT=y
|
||||
CONFIG_OF_LIBFDT=y
|
||||
CONFIG_OF_STDOUT_VIA_ALIAS=y
|
||||
'';
|
||||
};
|
||||
|
||||
util-linux-small = prev.util-linux.override {
|
||||
ncursesSupport = false;
|
||||
pamSupport = false;
|
||||
systemdSupport = false;
|
||||
nlsSupport = false;
|
||||
translateManpages = false;
|
||||
capabilitiesSupport = false;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -102,8 +102,4 @@ in {
|
||||
fennel = callPackage ./fennel {};
|
||||
fennelrepl = callPackage ./fennelrepl {};
|
||||
anoia = callPackage ./anoia {};
|
||||
|
||||
levitate = callPackage ./levitate {};
|
||||
|
||||
libubootenv = callPackage ./libubootenv {};
|
||||
}
|
||||
|
@ -7,13 +7,16 @@
|
||||
, config
|
||||
, src
|
||||
, extraPatchPhase ? "echo"
|
||||
, targets ? ["vmlinux"]
|
||||
} :
|
||||
let
|
||||
writeConfig = import ./write-kconfig.nix { inherit lib writeText; };
|
||||
kconfigFile = writeConfig "kconfig" config;
|
||||
arch = stdenv.hostPlatform.linuxArch;
|
||||
targetNames = map baseNameOf targets;
|
||||
arch = if stdenv.isMips
|
||||
then "mips"
|
||||
else if stdenv.isAarch64
|
||||
then "arm64"
|
||||
else throw "unknown arch";
|
||||
|
||||
inherit lib; in
|
||||
stdenv.mkDerivation rec {
|
||||
name = "kernel";
|
||||
@ -36,7 +39,7 @@ stdenv.mkDerivation rec {
|
||||
|
||||
dontStrip = true;
|
||||
dontPatchELF = true;
|
||||
outputs = ["out" "headers" "modulesupport"] ++ targetNames;
|
||||
outputs = ["out" "headers" "modulesupport"];
|
||||
phases = [
|
||||
"unpackPhase"
|
||||
"butcherPkgconfig"
|
||||
@ -52,7 +55,6 @@ stdenv.mkDerivation rec {
|
||||
patches = [
|
||||
./cmdline-cookie.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
|
||||
@ -93,12 +95,11 @@ stdenv.mkDerivation rec {
|
||||
'';
|
||||
|
||||
buildPhase = ''
|
||||
make ${lib.concatStringsSep " " targetNames} modules_prepare -j$NIX_BUILD_CORES
|
||||
make vmlinux modules_prepare
|
||||
'';
|
||||
|
||||
installPhase = ''
|
||||
${CROSS_COMPILE}strip -d vmlinux
|
||||
${lib.concatStringsSep "\n" (map (f: "cp ${f} \$${baseNameOf f}") targets)}
|
||||
cp vmlinux $out
|
||||
mkdir -p $headers
|
||||
cp -a include .config $headers/
|
||||
@ -107,4 +108,5 @@ stdenv.mkDerivation rec {
|
||||
make clean modules_prepare
|
||||
cp -a . $modulesupport
|
||||
'';
|
||||
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
/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
|
||||
|
||||
/ {
|
||||
@ -12,7 +12,7 @@
|
||||
description = "Vanilla Linux kernel";
|
||||
// data = /incbin/("./vmlinux.bin.gz");
|
||||
type = "kernel";
|
||||
// arch = "arm64";
|
||||
arch = "arm64";
|
||||
os = "linux";
|
||||
// compression = "gzip";
|
||||
// load = <00000000>;
|
||||
@ -28,7 +28,7 @@
|
||||
description = "Flattened Device Tree blob";
|
||||
// data = /incbin/("./target.dtb");
|
||||
type = "flat_dt";
|
||||
// arch = "arm64";
|
||||
arch = "arm64";
|
||||
compression = "none";
|
||||
hash-1 {
|
||||
algo = "crc32";
|
||||
|
@ -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
|
||||
objcopy = "${stdenv.cc.bintools.targetPrefix}objcopy";
|
||||
arch = stdenv.hostPlatform.linuxArch;
|
||||
stripAndZip = ''
|
||||
${objcopy} -O binary -R .reginfo -R .notes -R .note -R .comment -R .mdebug -R .note.gnu.build-id -S vmlinux.elf vmlinux.bin
|
||||
rm -f vmlinux.bin.lzma ; lzma -k -z vmlinux.bin
|
||||
'';
|
||||
in {
|
||||
kernel
|
||||
, commandLine
|
||||
, entryPoint
|
||||
, extraName ? "" # e.g. socFamily
|
||||
, loadAddress
|
||||
, imageFormat
|
||||
, dtb ? null
|
||||
} : stdenv.mkDerivation {
|
||||
} :
|
||||
stdenv.mkDerivation {
|
||||
name = "kernel.image";
|
||||
phases = [
|
||||
"preparePhase"
|
||||
(if commandLine != null then assert dtb != null; "mungeDtbPhase" else ":")
|
||||
(if imageFormat == "fit" then "buildPhaseFIT" else "buildPhaseUImage")
|
||||
"installPhase"
|
||||
];
|
||||
(if dtb != null then "dtbPhase" else ":")
|
||||
"buildPhase"
|
||||
"installPhase" ];
|
||||
nativeBuildInputs = [
|
||||
lzma
|
||||
dtc
|
||||
@ -37,43 +31,35 @@ in {
|
||||
preparePhase = ''
|
||||
cp ${kernel} vmlinux.elf; chmod +w vmlinux.elf
|
||||
'';
|
||||
mungeDtbPhase = ''
|
||||
dtbPhase = ''
|
||||
dtc -I dtb -O dts -o tmp.dts ${dtb}
|
||||
echo '/{ chosen { bootargs = ${builtins.toJSON commandLine}; }; };' >> tmp.dts
|
||||
dtc -I dts -O dtb -o tmp.dtb tmp.dts
|
||||
'';
|
||||
|
||||
buildPhaseUImage = ''
|
||||
test -f tmp.dtb && ${objcopy} --update-section .appended_dtb=tmp.dtb vmlinux.elf || ${objcopy} --add-section .appended_dtb=tmp.dtb vmlinux.elf
|
||||
${stripAndZip}
|
||||
mkimage -A ${arch} -O linux -T kernel -C lzma -a 0x${lib.toHexString loadAddress} -e 0x${lib.toHexString entryPoint} -n '${lib.toUpper arch} Liminix Linux ${extraName}' -d vmlinux.bin.lzma kernel.uimage
|
||||
'';
|
||||
|
||||
buildPhaseFIT = ''
|
||||
${stripAndZip}
|
||||
cat ${./kernel_fdt.its} > mkimage.its
|
||||
cat << _VARS >> mkimage.its
|
||||
/ {
|
||||
images {
|
||||
kernel {
|
||||
data = /incbin/("./vmlinux.bin.lzma");
|
||||
load = <0x${lib.toHexString loadAddress}>;
|
||||
entry = <0x${lib.toHexString entryPoint}>;
|
||||
arch = "${arch}";
|
||||
compression = "lzma";
|
||||
};
|
||||
fdt-1 {
|
||||
data = /incbin/("./tmp.dtb");
|
||||
arch = "${arch}";
|
||||
};
|
||||
};
|
||||
};
|
||||
_VARS
|
||||
mkimage -f mkimage.its kernel.uimage
|
||||
mkimage -l kernel.uimage
|
||||
'';
|
||||
|
||||
buildPhase =
|
||||
let arch =
|
||||
# per output of "mkimage -A list". I *think* these
|
||||
# are the same as the kernel arch convention, but
|
||||
# maybe that's coincidence
|
||||
if stdenv.isMips
|
||||
then "mips"
|
||||
else if stdenv.isAarch64
|
||||
then "arm64"
|
||||
else throw "unknown arch";
|
||||
in ''
|
||||
${objcopy} -O binary -R .reginfo -R .notes -R .note -R .comment -R .mdebug -R .note.gnu.build-id -S vmlinux.elf vmlinux.bin
|
||||
rm -f vmlinux.bin.lzma ; lzma -k -z vmlinux.bin
|
||||
cat ${./kernel_fdt.its} > mkimage.its
|
||||
echo '/ { images { kernel { data = /incbin/("./vmlinux.bin.lzma"); }; }; };' >> mkimage.its
|
||||
echo '/ { images { kernel { load = <${loadAddress}>; }; }; };' >> mkimage.its
|
||||
echo '/ { images { kernel { entry = <${entryPoint}>; }; }; };' >> mkimage.its
|
||||
echo '/ { images { kernel { compression = "lzma"; }; }; };' >> mkimage.its
|
||||
echo '/ { images { fdt-1 { data = /incbin/("./tmp.dtb"); }; }; }; ' >> mkimage.its
|
||||
mkimage -f mkimage.its mkimage.itb
|
||||
mkimage -l mkimage.itb
|
||||
'';
|
||||
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}
|
||||
'';
|
||||
cleanupScript = name : ''
|
||||
if test -d ${prefix}/${name} ; then rm -rf ${prefix}/${name} ; fi
|
||||
#!/bin/sh
|
||||
test -d ${prefix}/${name} && rm -rf ${prefix}/${name}
|
||||
'';
|
||||
service = {
|
||||
name
|
||||
|
@ -14,7 +14,11 @@
|
||||
, lib
|
||||
}:
|
||||
let
|
||||
arch = stdenv.hostPlatform.linuxArch;
|
||||
arch = if stdenv.isMips
|
||||
then "mips"
|
||||
else if stdenv.isAarch64
|
||||
then "arm64"
|
||||
else throw "unknown arch";
|
||||
openwrtSrc = fetchFromGitHub {
|
||||
name = "openwrt-source";
|
||||
repo = "openwrt";
|
||||
@ -25,52 +29,47 @@ let
|
||||
inherit (liminix.services) oneshot longrun;
|
||||
inherit (lib.lists) foldl;
|
||||
configs = {
|
||||
ath9k.kconfig = {
|
||||
ath9k = {
|
||||
WLAN_VENDOR_ATH = "y";
|
||||
ATH_COMMON = "m";
|
||||
ATH9K = "m";
|
||||
ATH9K_AHB = "y";
|
||||
# ATH9K_DEBUGFS = "y";
|
||||
# ATH_DEBUG = "y";
|
||||
BACKPORTED_ATH9K_AHB = "y";
|
||||
};
|
||||
ath9k_pci = {
|
||||
module = "ath9k";
|
||||
kconfig = {
|
||||
WLAN_VENDOR_ATH = "y";
|
||||
ATH_COMMON = "m";
|
||||
ATH9K = "m";
|
||||
ATH9K_PCI = "y";
|
||||
};
|
||||
};
|
||||
ath10k_pci.kconfig = {
|
||||
ath10k_pci = {
|
||||
WLAN_VENDOR_ATH = "y";
|
||||
ATH_COMMON = "m";
|
||||
ATH10K = "m";
|
||||
# BACKPORTED_ATH10K_AHB = "y";
|
||||
# ATH10K_AHB = "y";
|
||||
ATH10K_PCI = "y";
|
||||
ATH10K_DEBUG = "y";
|
||||
};
|
||||
rt2800soc.kconfig = {
|
||||
rt2800soc = {
|
||||
WLAN_VENDOR_RALINK = "y";
|
||||
RT2800SOC = "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_MEDIATEK = "y";
|
||||
MT7603E = "y";
|
||||
};
|
||||
|
||||
mt7915e.kconfig = {
|
||||
mt7915e = {
|
||||
MT7915E = "m";
|
||||
};
|
||||
mt7615e.kconfig = {
|
||||
mt7615e = {
|
||||
MT7615E = "m";
|
||||
MT7622_WMAC = "y";
|
||||
};
|
||||
mac80211_hwsim.kconfig = {
|
||||
mac80211_hwsim = {
|
||||
MAC80211_HWSIM = "y";
|
||||
};
|
||||
};
|
||||
kconfig = (foldl (config: d: (config // configs.${d}.kconfig)) {
|
||||
kconfig = (foldl (config: d: (config // configs.${d})) {
|
||||
WLAN = "y";
|
||||
CFG80211 = "m";
|
||||
MAC80211 = "m";
|
||||
@ -87,6 +86,7 @@ let
|
||||
CFG80211_CRDA_SUPPORT = "n";
|
||||
|
||||
MAC80211_MESH = "y";
|
||||
|
||||
} drivers) // extraConfig;
|
||||
|
||||
writeConfig = name : config: writeText name
|
||||
@ -166,11 +166,7 @@ let
|
||||
find . -name \*.ko | cpio --make-directories -p $out/lib/modules/0.0
|
||||
depmod -b $out -v 0.0
|
||||
touch $out/load.sh
|
||||
for i in ${lib.concatStringsSep " "
|
||||
(map
|
||||
(d: let c = { module = d; } // configs.${d} ;
|
||||
in c.module)
|
||||
drivers)}; do
|
||||
for i in ${lib.concatStringsSep " " drivers}; do
|
||||
modprobe -S 0.0 -d $out --show-depends $i >> $out/load.sh
|
||||
done
|
||||
tac < $out/load.sh | sed 's/^insmod/rmmod/g' > $out/unload.sh
|
||||
|
@ -1,25 +1,18 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
ssh_command=${SSH_COMMAND-ssh}
|
||||
if [ "$1" = "--no-reboot" ] ; then
|
||||
reboot="true"
|
||||
shift
|
||||
else
|
||||
reboot="reboot"
|
||||
fi
|
||||
|
||||
target_host=$1
|
||||
shift
|
||||
|
||||
if [ -z "$target_host" ] ; then
|
||||
echo Usage: liminix-rebuild [--no-reboot] target-host params
|
||||
echo Usage: liminix-rebuild target-host params
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if toplevel=$(nix-build "$@" -A outputs.systemConfiguration --no-out-link); then
|
||||
echo systemConfiguration $toplevel
|
||||
min-copy-closure $target_host $toplevel
|
||||
$ssh_command $target_host $toplevel/bin/install
|
||||
$ssh_command $target_host cp -v -fP $toplevel/bin/* $toplevel/etc/* /persist
|
||||
$ssh_command $target_host "sync; source /etc/profile; reboot"
|
||||
else
|
||||
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
|
||||
|
||||
ssh_command=${SSH_COMMAND-ssh}
|
||||
|
||||
root_prefix=/
|
||||
verbose=true
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
-r|--root)
|
||||
root_prefix="$2"
|
||||
shift
|
||||
shift
|
||||
;;
|
||||
-q|--quiet)
|
||||
verbose=""
|
||||
shift
|
||||
;;
|
||||
-*|--*)
|
||||
echo "Unknown option $1"
|
||||
exit 1
|
||||
;;
|
||||
*)
|
||||
if test -z "$target_host"; then
|
||||
target_host="$1"
|
||||
else
|
||||
paths+=("$1") # save positional arg
|
||||
fi
|
||||
shift # past argument
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
progress() {
|
||||
test -n "$verbose" && echo $*
|
||||
}
|
||||
target_host=$1
|
||||
shift
|
||||
|
||||
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
|
||||
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
|
||||
# skip the requisites when running tests in hydra
|
||||
paths=$(nix-store -q --requisites "$paths")
|
||||
paths=$@
|
||||
else
|
||||
paths=$(nix-store -q --requisites "$@")
|
||||
fi
|
||||
needed=""
|
||||
|
||||
@ -54,16 +25,16 @@ coproc remote {
|
||||
exec 10>&${remote[1]}
|
||||
|
||||
for p in $paths; do
|
||||
progress -n Checking $(basename $p) ...
|
||||
echo "test -e ${root_prefix}$p && echo skip || echo $p" >&10
|
||||
echo -n Checking $(basename $p) ...
|
||||
echo "test -e $p && echo skip || echo $p" >&10
|
||||
read n <&${remote[0]}
|
||||
case $n in
|
||||
skip)
|
||||
progress skip
|
||||
echo skip
|
||||
;;
|
||||
*)
|
||||
needed="${needed} $n"
|
||||
progress will copy
|
||||
echo will copy
|
||||
;;
|
||||
esac
|
||||
done
|
||||
@ -73,11 +44,10 @@ if test -z "$needed" ; then
|
||||
exit 1
|
||||
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 "echo finished" >&10
|
||||
echo "date" >&10
|
||||
read n <&${remote[0]}
|
||||
echo $n
|
||||
|
@ -34,5 +34,4 @@ in {
|
||||
applyPatches.ath79 = doPatch "ath79";
|
||||
applyPatches.ramips = doPatch "ramips";
|
||||
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;
|
||||
hardeningDisable = [ "all" ];
|
||||
CFLAGS = "-Os -static -DPREINIT_USE_LIBC -fno-stack-protector -fpic -fPIC -I ./ -I ${kernel}/tools/include/nolibc";
|
||||
|
||||
postBuild = ''
|
||||
$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 <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/wait.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <asm/setup.h> /* for COMMAND_LINE_SIZE */
|
||||
|
||||
void parseopts(char * cmdline, char **root, char **rootfstype);
|
||||
#else
|
||||
#include <nolibc.h>
|
||||
#endif
|
||||
#include <asm/setup.h>
|
||||
|
||||
#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 void die() {
|
||||
/* if init exits, it causes a kernel panic. On the Turris
|
||||
* Omnia (and maybe other hardware, I don't know), the kernel
|
||||
* panics _before_ any of the messages from AVER are printed,
|
||||
* which makes it really hard to tell what went wrong. So
|
||||
* let's wait a little here to give the console a chance to
|
||||
* catch up.
|
||||
*
|
||||
* 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 begins_with(char * str, char * prefix)
|
||||
{
|
||||
while(*prefix) {
|
||||
if(*str == '\0') return 0;
|
||||
if(*str != *prefix) return 0;
|
||||
str++;
|
||||
prefix++;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int fork_exec(char * command, char *args[])
|
||||
static void fork_exec(char * command, char *args[])
|
||||
{
|
||||
int fork_pid = fork();
|
||||
AVER(fork_pid);
|
||||
if(fork_pid > 0)
|
||||
return wait(NULL);
|
||||
else
|
||||
return execve(command, args, NULL);
|
||||
int fork_pid = fork();
|
||||
AVER(fork_pid);
|
||||
if(fork_pid > 0)
|
||||
wait(NULL);
|
||||
else
|
||||
AVER(execve(command, args, NULL));
|
||||
}
|
||||
|
||||
char banner[] = "Running pre-init...\n";
|
||||
@ -49,53 +39,52 @@ char buf[COMMAND_LINE_SIZE];
|
||||
|
||||
int main(int argc, char *argv[], char *envp[])
|
||||
{
|
||||
char *rootdevice = 0;
|
||||
char *rootfstype = 0;
|
||||
#ifndef PREINIT_USE_LIBC
|
||||
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));
|
||||
AVER(mount("none", "/dev", "devtmpfs", 0, NULL));
|
||||
int cmdline = open("/proc/cmdline", O_RDONLY, 0);
|
||||
|
||||
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) {
|
||||
int len = read(cmdline, buf, sizeof buf - 1);
|
||||
buf[len]='\0';
|
||||
while(buf[len-1]=='\n') {
|
||||
buf[len-1]='\0';
|
||||
len--;
|
||||
while(*p) {
|
||||
if(begins_with(p, "root=")) {
|
||||
rootdevice = p + 5;
|
||||
while(*p && (*p != ' ')) p++;
|
||||
*p= '\0';
|
||||
}
|
||||
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(!rootfstype) rootfstype = "jffs2"; /* backward compatibility */
|
||||
write(1, "rootdevice ", 11);
|
||||
write(1, rootdevice, strlen(rootdevice));
|
||||
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));
|
||||
if(rootdevice) {
|
||||
write(1, "rootdevice ", 11);
|
||||
write(1, rootdevice, strlen(rootdevice));
|
||||
write(1, "\n", 1);
|
||||
|
||||
char *exec_args[] = { "activate", "/target", NULL };
|
||||
AVER(fork_exec("/target/persist/activate", exec_args));
|
||||
AVER(chdir("/target"));
|
||||
AVER(mount(rootdevice, "/target/persist", "jffs2", 0, NULL));
|
||||
AVER(mount("/target/persist/nix", "/target/nix",
|
||||
"bind", MS_BIND, NULL));
|
||||
|
||||
AVER(mount("/target", "/", "bind", MS_BIND | MS_REC, NULL));
|
||||
AVER(chroot("."));
|
||||
char *exec_args[] = { "activate", "/target", NULL };
|
||||
fork_exec("/target/persist/activate", exec_args);
|
||||
AVER(chdir("/target"));
|
||||
|
||||
argv[0] = "init";
|
||||
argv[1] = NULL;
|
||||
AVER(execve("/persist/init", argv, envp));
|
||||
}
|
||||
die();
|
||||
AVER(mount("/target", "/", "bind", MS_BIND | MS_REC, NULL));
|
||||
AVER(chroot("."));
|
||||
argv[0] = "init";
|
||||
argv[1] = NULL;
|
||||
|
||||
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
|
||||
, writeShellScript
|
||||
, writeFennel
|
||||
, runCommand
|
||||
, writeShellScriptBin
|
||||
, symlinkJoin
|
||||
, lib
|
||||
, lua
|
||||
, pkgsBuildBuild
|
||||
}: let
|
||||
run-liminix-vm = pkgsBuildBuild.writeFennel "run-liminix-vm" {
|
||||
packages = [ qemuLim lua.pkgs.luaposix lua.pkgs.fennel ];
|
||||
} ./run-liminix-vm.fnl;
|
||||
connect = writeShellScript "connect-vm" ''
|
||||
run-liminix-vm = writeShellScriptBin "run-liminix-vm" ''
|
||||
export PATH="${lib.makeBinPath [qemu]}:$PATH"
|
||||
${builtins.readFile ./run-liminix-vm.sh}
|
||||
'';
|
||||
connect = writeShellScriptBin "connect-vm" ''
|
||||
export PATH="${lib.makeBinPath [socat]}:$PATH"
|
||||
socat -,raw,echo=0,icanon=0,isig=0,icrnl=0,escape=0x0f unix-connect:$1
|
||||
'';
|
||||
in runCommand "vm" {} ''
|
||||
mkdir -p $out/bin
|
||||
cd $out/bin
|
||||
ln -s ${connect} ./connect-vm
|
||||
ln -s ${run-liminix-vm} ./run-liminix-vm
|
||||
''
|
||||
in symlinkJoin {
|
||||
name = "run-liminix-vm";
|
||||
paths = [ run-liminix-vm connect ];
|
||||
}
|
||||
|
@ -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 = ./.;
|
||||
|
||||
CFLAGS = "-Os";
|
||||
LDFLAGS = "-static -Xlinker -static";
|
||||
LDFLAGS = "-static";
|
||||
|
||||
postConfigure = ''
|
||||
cp ${makedevs} makedevs.c
|
||||
@ -80,10 +80,5 @@ in attrset:
|
||||
cp $closure/store-paths $out/etc/nix-store-paths
|
||||
$STRIP --remove-section=.note --remove-section=.comment --strip-all makedevs -o $out/bin/activate
|
||||
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)
|
||||
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 retried = 0
|
||||
local timeout = time() + timeout_secs
|
||||
local timedout = false
|
||||
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
|
||||
local ack, ackhost, ackport = socket:recvfrom(ACKSIZE)
|
||||
local ack_sequence = self.parse_ACK(ack)
|
||||
|
||||
if ackhost ~= host or ackport ~= port then
|
||||
if ackhost ~= host or ackport ~= port or self.parse_ACK(ack) ~= tid then
|
||||
--[[https://tools.ietf.org/html/rfc1350#page-5
|
||||
"If a source TID does not match, the packet should be
|
||||
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)
|
||||
yield(true, false)
|
||||
elseif ack_sequence ~= tid then
|
||||
-- this looks confusing, but the local variable
|
||||
-- "tid" here is actually block number (aka
|
||||
-- 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
|
||||
else
|
||||
acked = true
|
||||
end
|
||||
retried = retried + 1
|
||||
timedout = time() > timeout
|
||||
until acked or retried > ACK_RETRIES
|
||||
if retried > ACK_RETRIES then
|
||||
until acked or retried > ACK_RETRIES or timedout
|
||||
if timedout or retried > ACK_RETRIES then
|
||||
--There doesn't seem to be a standard error for timeout.
|
||||
socket:sendto(err("Ack timeout"), host, port)
|
||||
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 "package.path = ${lib.strings.escapeShellArg (builtins.concatStringsSep "" luapath)} .. package.path"
|
||||
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}
|
||||
) > ${name}.lua
|
||||
'';
|
||||
|
@ -3,9 +3,7 @@
|
||||
pseudofiles = import ./pseudofiles/test.nix;
|
||||
wlan = import ./wlan/test.nix;
|
||||
pppoe = import ./pppoe/test.nix;
|
||||
jffs2 = import ./jffs2/test.nix;
|
||||
ext4 = import ./ext4/test.nix;
|
||||
jffs2 = import ./jffs2/test.nix;
|
||||
min-copy-closure = import ./min-copy-closure/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 = [
|
||||
../../vanilla-configuration.nix
|
||||
../../modules/squashfs.nix
|
||||
../../modules/outputs/jffs2.nix
|
||||
../../modules/jffs2.nix
|
||||
];
|
||||
config.rootfsType = "jffs2";
|
||||
config.filesystem = dir {
|
||||
|
@ -2,6 +2,7 @@ set timeout 10
|
||||
|
||||
spawn socat unix-connect:vm/console -
|
||||
send "\r\n"
|
||||
expect "login:" { send "root\r\n" }
|
||||
expect "#"
|
||||
send "echo HELLO WORLD > /hello\r\n"
|
||||
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 {
|
||||
imports = [
|
||||
../../vanilla-configuration.nix
|
||||
../../modules/outputs/jffs2.nix
|
||||
../../modules/jffs2.nix
|
||||
];
|
||||
config = {
|
||||
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;
|
||||
img = lmx.outputs.vmroot;
|
||||
pkgs = import <nixpkgs> { overlays = [(import ../../overlay.nix)]; };
|
||||
inherit (pkgs.pkgsBuildBuild) run-liminix-vm;
|
||||
in pkgs.runCommand "check" {
|
||||
nativeBuildInputs = with pkgs; [
|
||||
expect
|
||||
run-liminix-vm
|
||||
socat
|
||||
min-copy-closure
|
||||
rogue
|
||||
@ -19,15 +21,11 @@ in pkgs.runCommand "check" {
|
||||
} ''
|
||||
. ${../test-helpers.sh}
|
||||
|
||||
(
|
||||
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}
|
||||
export SSH_COMMAND="ssh -o StrictHostKeyChecking=no -p 2022 -i ${./id}"
|
||||
$SSH_COMMAND root@localhost echo ready
|
||||
IN_NIX_BUILD=true min-copy-closure --quiet root@localhost ${rogue}
|
||||
$SSH_COMMAND root@localhost ls -ld ${rogue}
|
||||
IN_NIX_BUILD=true min-copy-closure --root /run root@localhost ${rogue}
|
||||
$SSH_COMMAND root@localhost ls -ld /run/${rogue}
|
||||
) 2>&1 | tee $out
|
||||
IN_NIX_BUILD=true min-copy-closure root@localhost ${rogue}
|
||||
$SSH_COMMAND root@localhost ls -l ${rogue} >$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 -
|
||||
send "\r\n"
|
||||
expect {
|
||||
"# " { send "hostname\r\n" };
|
||||
}
|
||||
expect "(none)"
|
||||
expect "login:"
|
@ -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 -
|
||||
send "\r\n"
|
||||
expect "login:" { send "root\r\n" }
|
||||
expect "#"
|
||||
set FINISHED 0
|
||||
set EXIT "1"
|
||||
@ -10,7 +11,7 @@ while { $FINISHED < 10 } {
|
||||
expect {
|
||||
"192.168.100.1" { set FINISHED 20; set EXIT 0; }
|
||||
"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 ]
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user