1
0
forked from dan/liminix

6 Commits

Author SHA1 Message Date
dan b306031b7c don't need fake dts either now we've removed u-boot 2023-09-19 21:14:04 +01:00
dan c948a9b49a didn't need u-boot 2023-09-19 21:09:01 +01:00
dan 56d679416f derubbishify 2023-09-19 20:53:46 +01:00
dan f38270a365 reove more unneeded kconfig 2023-09-19 20:40:07 +01:00
dan 8f4d5e51f4 remove unneeded kconfig 2023-09-19 19:08:08 +01:00
dan 2841952245 hacky wip aarch64 boots in qemu 2023-09-19 18:44:09 +01:00
58 changed files with 236 additions and 1149 deletions
+14
View File
@@ -2436,3 +2436,17 @@ Sun Sep 17 16:44:31 BST 2023
Can we figure out which bits of the old doc are missing from the new
one and just transplant those? Then we can merge it sooner
instead of blocking on writig all the new stuff
We need to find a nice place for an introduction to choosing
rootfsType
Mon Sep 18 17:07:56 BST 2023
Let's see if we can hack up an aarch64 qemu port
From https://gist.github.com/oznu/ac9efae7c24fd1f37f1d933254587aa4 :
curl -L https://releases.linaro.org/components/kernel/uefi-linaro/latest/release/qemu64/QEMU_EFI.fd -O
dd if=/dev/zero of=flash1.img bs=1M count=64
dd if=/dev/zero of=flash0.img bs=1M count=64
dd if=QEMU_EFI.fd of=flash0.img conv=notrunc
+4 -9
View File
@@ -8,21 +8,17 @@ let
pkgs = (import nixpkgs {});
borderVmConf = ./bordervm.conf-example.nix;
inherit (pkgs.lib.attrsets) genAttrs;
devices = {
virt = [ "qemu" "qemu-aarch64" ];
hw = [ "gl-ar750" "gl-mt300n-v2" "gl-mt300a" ];
};
devices = [ "qemu" "gl-ar750" "gl-mt300n-v2" "gl-mt300a" ];
vanilla = ./vanilla-configuration.nix;
for-device = cfg: name:
for-device = name:
(import liminix {
inherit nixpkgs borderVmConf;
device = import (liminix + "/devices/${name}");
liminix-config = cfg;
liminix-config = vanilla;
}).outputs.default;
tests = import ./tests/ci.nix;
jobs =
(genAttrs devices.hw (name: for-device ./vanilla-configuration-hw.nix name)) //
(genAttrs devices.virt (name: for-device vanilla name)) //
(genAttrs devices (name: for-device name)) //
tests //
{
buildEnv = (import liminix {
@@ -40,7 +36,6 @@ let
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 = ''
+1 -1
View File
@@ -54,7 +54,7 @@ in {
tufted
routeros.routeros
routeros.ros-exec-script
run-liminix-vm
mips-vm
borderVm.build.vm
go-l2tp
min-copy-closure
-181
View File
@@ -1,181 +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 = "aarch64-unknown-linux-musl";
};
};
module = {pkgs, config, lib, ... }:
let firmware = pkgs.stdenv.mkDerivation {
name = "wlan-firmware";
phases = ["installPhase"];
installPhase = ''
mkdir $out
cp ${pkgs.linux-firmware}/lib/firmware/mediatek/{mt7915,mt7615,mt7622}* $out
'';
};
in {
imports = [ ../../modules/arch/aarch64.nix ];
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.mediatek}
'';
config = {
PCI = "y";
ARCH_MEDIATEK = "y";
# ARM_MEDIATEK_CPUFREQ = "y";
# needed for "Cannot find regmap for /infracfg@10000000"
MFD_SYSCON = "y";
MTK_INFRACFG = "y";
MTK_PMIC_WRAP = "y";
MTK_EFUSE="y";
# MTK_HSDMA="y";
MTK_SCPSYS="y";
MTK_SCPSYS_PM_DOMAINS="y";
# MTK_THERMAL="y";
MTK_TIMER="y";
COMMON_CLK_MT7622 = "y";
COMMON_CLK_MT7622_ETHSYS = "y";
COMMON_CLK_MT7622_HIFSYS = "y";
COMMON_CLK_MT7622_AUDSYS = "y";
PM_CLK="y";
REGMAP_MMIO = "y";
CLKSRC_MMIO = "y";
REGMAP = "y";
MEDIATEK_GE_PHY = "y";
# MEDIATEK_MT6577_AUXADC = "y";
# MEDIATEK_WATCHDOG = "y";
NET_MEDIATEK_SOC = "y";
NET_MEDIATEK_SOC_WED = "y";
NET_MEDIATEK_STAR_EMAC = "y"; # this enables REGMAP_MMIO
NET_VENDOR_MEDIATEK = "y";
PCIE_MEDIATEK = "y";
BLOCK = "y"; # move this to base option
NETDEVICES = "y"; # and this probably also
SPI_MASTER = "y";
SPI = "y";
SPI_MEM="y";
SPI_MTK_NOR="y";
SPI_MTK_SNFI = "y";
MTD = "y";
MTD_BLOCK = "y";
MTD_RAW_NAND = "y";
MTD_NAND_MTK = "y";
MTD_NAND_MTK_BMT = "y"; # Bad-block Management Table
MTD_NAND_ECC_MEDIATEK= "y";
MTD_NAND_ECC_SW_HAMMING= "y";
MTD_SPI_NAND= "y";
MTD_OF_PARTS = "y";
MTD_NAND_CORE= "y";
MTD_SPI_NOR= "y";
MTD_SPLIT_FIRMWARE= "y";
MTD_SPLIT_FIT_FW= "y";
MTD_UBI="y";
MTD_UBI_BEB_LIMIT="20";
MTD_UBI_BLOCK="y";
MTD_UBI_WL_THRESHOLD="4096";
MMC = "y";
MMC_BLOCK = "y";
MMC_CQHCI = "y";
MMC_MTK = "y";
# Distributed Switch Architecture is needed
# to make the ethernet ports visible
NET_DSA="y";
NET_DSA_MT7530="y";
NET_DSA_TAG_MTK="y";
PSTORE = "y";
PSTORE_RAM = "y";
PSTORE_CONSOLE = "y";
PSTORE_DEFLATE_COMPRESS = "n";
SERIAL_8250 = "y";
SERIAL_8250_CONSOLE = "y";
SERIAL_8250_MT6577="y";
# SERIAL_8250_NR_UARTS="3";
# SERIAL_8250_RUNTIME_UARTS="3";
SERIAL_OF_PLATFORM="y";
};
};
boot.commandLine = [
"console=ttyS0,115200"
];
filesystem =
let inherit (pkgs.pseudofile) dir symlink;
in
dir {
lib = dir {
firmware = dir {
mediatek = symlink firmware;
};
};
};
hardware =
let
openwrt = pkgs.openwrt;
mac80211 = pkgs.mac80211.override {
drivers = [
"mt7615e"
"mt7915e"
];
klibBuild = config.system.outputs.kernel.modulesupport;
};
in {
defaultOutput = "flashimage";
loadAddress = "0x41080000";
entryPoint = "0x41080000";
rootDevice = "/dev/mtdblock0";
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/"
];
};
flash.eraseBlockSize = "65536"; # c.f. pkgs/mips-vm/mips-vm.sh
networkInterfaces =
let
inherit (config.system.service.network) link;
inherit (config.system.service) bridge;
in rec {
wan = link.build { ifname = "wan"; };
lan1 = link.build { ifname = "lan1"; };
lan2 = link.build { ifname = "lan2"; };
lan3 = link.build { ifname = "lan3"; };
lan4 = link.build { ifname = "lan4"; };
lan = lan3;
wlan = link.build {
ifname = "wlan0";
dependencies = [ mac80211 ];
};
wlan5 = link.build {
ifname = "wlan1";
dependencies = [ mac80211 ];
};
};
};
};
}
+17 -25
View File
@@ -18,22 +18,13 @@
};
description = ''
GL.iNet GL-AR750
****************
The GL-AR750 "Creta" travel router features:
GL.INet GL-AR750 "Creta" travel router
- QCA9531 @650Mhz SoC
- dual band wireless: IEEE 802.11a/b/g/n/ac
- two 10/100Mbps LAN ports and one WAN
- 128MB DDR2 RAM
- 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
- 128MB DDR2 RAM / 16MB NOR Flash
- "ath79" soc family
https://www.gl-inet.com/products/gl-ar750/
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
@@ -43,13 +34,8 @@
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
as far as the Linux is concerned it behaves as one. This is
supported by the ath10k driver.
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, ... }:
@@ -93,10 +79,7 @@
inherit (pkgs.pseudofile) dir symlink;
inherit (pkgs.liminix.networking) interface;
in {
imports = [
../../modules/network
../../modules/arch/mipseb.nix
];
imports = [ ../../modules/network];
programs.busybox.options = {
FEATURE_DD_IBS_OBS = "y"; # ath10k_cal_data needs skip_bytes,fullblock
@@ -123,11 +106,11 @@
in {
lan = link.build { ifname = "eth0"; };
wan = link.build { ifname = "eth1"; };
wlan = link.build {
wlan_24 = link.build {
ifname = "wlan0";
dependencies = [ mac80211 ];
};
wlan5 = link.build {
wlan_5 = link.build {
ifname = "wlan1";
dependencies = [ mac80211 ath10k_cal_data ];
};
@@ -156,6 +139,9 @@
${openwrt.applyPatches.ath79}
'';
config = {
MIPS_ELF_APPENDED_DTB = "y";
OF = "y";
USE_OF = "y";
ATH79 = "y";
PCI = "y";
PCI_AR724X = "y";
@@ -183,6 +169,7 @@
AR8216_PHY = "y"; # eth1 is behind a switch
MTD_SPI_NOR = "y";
MTD_SPI_NOR_USE_4K_SECTORS = "n"; # jffs2 needs min 8k erase block
SPI_ATH79 = "y"; # these are copied from OpenWrt.
SPI_MASTER= "y"; # At least one of them is necessary
@@ -199,17 +186,22 @@
SYSFS = "y";
SPI = "y";
MTD = "y";
MTD_CMDLINE_PARTS = "y";
MTD_BLOCK = "y"; # fix undefined ref to register_mtd_blktrans_devs
WATCHDOG = "y";
ATH79_WDT = "y"; # watchdog timer
CPU_BIG_ENDIAN= "y";
# this is all copied from nixwrt ath79 config. Clearly not all
# of it is device config, some of it is wifi config or
# installation method config or ...
CMDLINE_PARTITION = "y";
EARLY_PRINTK = "y";
PARTITION_ADVANCED = "y";
PRINTK_TIME = "y";
};
};
+11 -41
View File
@@ -1,4 +1,4 @@
# GL.iNet GL-MT300A
# GL.INet GL-MT300A
{
system = {
@@ -12,47 +12,10 @@
};
description = ''
GL.iNet GL-MT300A
********************
The GL-MT300A is based on a MT7620 chipset.
The GL.iNet pocket router range makes nice cheap hardware for
playing with Liminix or similar projects. The manufacturers seem
open to the DIY market, and the devices have a reasonable amount
of RAM and are much easier to get serial connections than many
COTS routers.
Wire up the serial connection: this probably involves opening
the box, locating the serial header pins (TX, RX and GND) and
connecting a USB TTL converter - e.g. a PL2303 based device - to
it. The defunct OpenWRT wiki has a guide with some pictures. (If
you don't have a USB TTL converter to hand, other options are
available. For example, use the GPIO pins on a Raspberry Pi.)
Run a terminal emulator such as Minicom on whatever is on the
other end of the link. I use 115200 8N1 and find it also helps
to set "Line tx delay" to 1ms, "backspace sends DEL" and
"lineWrap on".
When you turn the router on you should be greeted with some
messages from U-Boot and a little bit of ASCII art, followed by
the instruction to hit SPACE to stop autoboot. Do this and you
will get a gl-mt300a> prompt.
For flashing from uboot, the firmware partition is from
0xbc050000 to 0xbcfd0000.
WiFi on this device is provided by the rt2800soc module. It
expects firmware to be present in the "factory" MTD partition, so
- assuming we want to use the wireless - we need to build MTD
support into the kernel even if we're using TFTP root.
Vendor web page: https://www.gl-inet.com/products/gl-mt300a/
OpenWrt web page: https://openwrt.org/toh/gl.inet/gl-mt300a
support into the kernel even if we're using TFTP root
'';
module = { pkgs, config, lib, ...}:
@@ -63,8 +26,7 @@
drivers = ["rt2800soc"];
klibBuild = config.system.outputs.kernel.modulesupport;
};
in {
imports = [ ../../modules/arch/mipsel.nix ];
in {
hardware = {
defaultOutput = "flashimage";
loadAddress = "0x80000000";
@@ -145,6 +107,9 @@
${openwrt.applyPatches.ramips}
'';
config = {
MIPS_ELF_APPENDED_DTB = "y";
OF = "y";
USE_OF = "y";
RALINK = "y";
PCI = "y";
@@ -175,13 +140,18 @@
SPI_MEM= "y";
MTD = "y";
MTD_CMDLINE_PARTS = "y";
MTD_BLOCK = "y"; # fix undefined ref to register_mtd_blktrans_devs
CPU_LITTLE_ENDIAN = "y";
CMDLINE_PARTITION = "y";
EARLY_PRINTK = "y";
NEW_LEDS = "y";
LEDS_CLASS = "y"; # required by rt2x00lib
PARTITION_ADVANCED = "y";
PRINTK_TIME = "y";
} // lib.optionalAttrs (config.system.service ? vlan) {
SWCONFIG = "y";
+9 -16
View File
@@ -1,3 +1,5 @@
# GL.INet GL-MT300N v2
{
system = {
crossSystem = {
@@ -9,21 +11,6 @@
};
};
description = ''
GL.iNet GL-MT300N-v2
********************
The GL-MT300N-v2 "Mango" is is very similar to the MT300A, but is
based on MT7628 instead of MT7620. It's also marginally cheaper
and comes in a yellow case not a blue one. It's different again
to the v1, which has only half the RAM.
Vendor web page: https://www.gl-inet.com/products/gl-mt300n-v2/
OpenWrt web page: https://openwrt.org/toh/gl.inet/gl-mt300n_v2
'';
module = { pkgs, config, lib, ...}:
let
inherit (pkgs.liminix.networking) interface;
@@ -40,7 +27,6 @@
hash = "sha256:1dkhfznmdz6s50kwc841x3wj0h6zg6icg5g2bim9pvg66as2vmh9";
};
in {
imports = [ ../../modules/arch/mipsel.nix ];
filesystem = dir {
lib = dir {
firmware = dir {
@@ -117,10 +103,14 @@
${openwrt.applyPatches.ramips}
'';
config = {
MIPS_ELF_APPENDED_DTB = "y";
OF = "y";
USE_OF = "y";
RALINK = "y";
PCI = "y";
SOC_MT7620 = "y";
CPU_LITTLE_ENDIAN= "y";
SERIAL_8250_CONSOLE = "y";
SERIAL_8250 = "y";
@@ -131,6 +121,7 @@
CONSOLE_LOGLEVEL_QUIET = "4";
MTD = "y";
MTD_CMDLINE_PARTS = "y";
MTD_BLOCK = "y"; # fix undefined ref to register_mtd_blktrans_dev
SPI = "y";
@@ -160,8 +151,10 @@
PHY_RALINK_USB = "y";
CMDLINE_PARTITION = "y";
EARLY_PRINTK = "y";
PARTITION_ADVANCED = "y";
PRINTK_TIME = "y";
} // lib.optionalAttrs (config.system.service ? vlan) {
SWCONFIG = "y";
+9 -9
View File
@@ -9,12 +9,7 @@
};
};
# this device is described by the "qemu" device
description = "";
module = {pkgs, config, ... }: {
imports = [ ../../modules/arch/aarch64.nix ];
kernel = {
src = pkgs.pkgsBuildBuild.fetchurl {
name = "linux.tar.gz";
@@ -22,11 +17,15 @@
hash = "sha256-yhO2cXIeIgUxkSZf/4aAsF11uxyh+UUZu6D1h92vCD8=";
};
config = {
CPU_LITTLE_ENDIAN= "y";
CPU_BIG_ENDIAN= "n";
VIRTUALIZATION = "y";
PCI_HOST_GENERIC="y";
MTD = "y";
MTD_BLOCK2MTD = "y";
MTD_BLKDEVS = "y";
MTD_BLOCK = "y";
VIRTIO_MENU = "y";
@@ -37,14 +36,15 @@
NETDEVICES = "y";
VIRTIO_NET = "y";
# https://stackoverflow.com/a/68340492
CMDLINE="\"earlycon=smh console=ttyAMA0\"";
CMDLINE_FROM_BOOTLOADER = "y";
SERIAL_EARLYCON_ARM_SEMIHOST = "y"; # earlycon=smh
SERIAL_AMBA_PL011 = "y";
SERIAL_AMBA_PL011_CONSOLE = "y";
};
};
boot.commandLine = [
"console=ttyAMA0,38400"
];
hardware =
let
mac80211 = pkgs.mac80211.override {
@@ -55,7 +55,7 @@
defaultOutput = "vmroot";
loadAddress = "0x0";
entryPoint = "0x0";
rootDevice = "/dev/mtdblock0";
rootDevice = "/dev/mtd1";
flash.eraseBlockSize = "65536"; # c.f. pkgs/mips-vm/mips-vm.sh
networkInterfaces =
+4 -30
View File
@@ -12,35 +12,7 @@
};
};
description = ''
QEMU
****
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. For Aarch64 we use the QEMU "virt" board.
Building an image for QEMU results in a :file:`result/` directory
containing ``run.sh`` ``vmlinux``, ``rootfs`` and possibly
(architecture-dependent) ``Image``. To invoke the emulator,
run ``run.sh``.
The configuration includes two emulated "hardware" ethernet
devices and the kernel :code:`mac80211_hwsim` module to
provide an emulated wlan device. To read more about how
to connect to this network, refer to :ref:`qemu-networking`
in the Development manual.
'';
module = {pkgs, config, ... }: {
imports = [ ../../modules/arch/mipseb.nix ];
kernel = {
src = pkgs.pkgsBuildBuild.fetchurl {
name = "linux.tar.gz";
@@ -49,10 +21,13 @@
};
config = {
MIPS_MALTA= "y";
CPU_LITTLE_ENDIAN= "n";
CPU_BIG_ENDIAN= "y";
CPU_MIPS32_R2= "y";
MTD = "y";
MTD_BLOCK2MTD = "y";
MTD_BLKDEVS = "y";
MTD_BLOCK = "y";
VIRTIO_MENU = "y";
@@ -75,8 +50,7 @@
};
in {
defaultOutput = "vmroot";
rootDevice = "/dev/mtdblock0";
flash.eraseBlockSize = "65536"; # c.f. pkgs/run-liminix-vm/run-liminix-vm.sh
flash.eraseBlockSize = "65536"; # c.f. pkgs/mips-vm/mips-vm.sh
networkInterfaces =
let inherit (config.system.service.network) link;
in {
+3 -3
View File
@@ -138,8 +138,8 @@ device using e.g. :command:`ssh`, you can run it as follows:
mtd -e -r write /tmp/firmware.bin firmware
The options to this command are for "erase before writing" and "reboot
after writing".
after writing".
For more information, please see the `OpenWrt manual <https://openwrt.org/docs/guide-user/installation/sysupgrade.cli>`_ which may also contain (hardware-dependent) instructions on how to flash an image using the vendor firmware - perhaps even from a web interface.
Updating an installed system (JFFS2)
@@ -188,7 +188,7 @@ this except for building the previous configuration again.
Caveats
-------
~~~~~~~
* it needs there to be enough free space on the device for all the new
packages in addition to all the packages already on it - which may be
+1 -12
View File
@@ -13,10 +13,7 @@ author = 'Daniel Barlow'
# -- General configuration ---------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
extensions = [
'sphinx.ext.autosectionlabel'
]
autosectionlabel_prefix_document = True
extensions = []
templates_path = ['_templates']
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
@@ -28,11 +25,3 @@ exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
html_theme = 'alabaster'
html_static_path = ['_static']
html_theme_options = {
'logo': '/logo.svg',
'globaltoc_collapse': 'false',
'page_width': '90%',
'body_max_width': '90%',
'description': 'A Nix-based OpenWrt-style embedded Linux system for consumer wifi routers'
}
+3 -5
View File
@@ -27,13 +27,13 @@ To build it,
nix-build -I liminix-config=path/to/your/configuration.nix --arg device "import ./devices/qemu" -A outputs.default
In a ``buildEnv`` nix-shell, you can use the :command:`run-liminix-vm` command
In a ``buildEnv`` nix-shell, you can use the :command:`mips-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"
nix-shell --run "mips-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
@@ -41,8 +41,6 @@ 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:
Networking
==========
@@ -55,7 +53,7 @@ the right way:
* multicast 230.0.0.1:1235 : lan
* multicast 230.0.0.1:1236 : world (the internet)
A VM started with :command:`run-liminix-vm` is connected to "lan" and "access", and
A VM started with :command:`mips-vm` is connected to "lan" and "access", and
the emulated border network gateway (see below) runs PPPoE and is
connected to "access" and "world".
+2 -3
View File
@@ -15,9 +15,8 @@ let
builtins.attrNames
(lib.filterAttrsRecursive
(n: t:
(n != "arch") &&
((t=="directory") ||
((t=="regular") && ((builtins.match ".*\\.nix$" n) != null))))
(t=="directory") ||
((t=="regular") && ((builtins.match ".*\\.nix$" n) != null)))
(builtins.readDir ../modules));
modulefiles = builtins.map (n: builtins.toPath "${../modules}/${n}") modulenames;
eval = (lib.evalModules {
-18
View File
@@ -1,18 +0,0 @@
with import <nixpkgs> {} ;
let
devices =
builtins.readDir ../devices;
texts = lib.mapAttrsToList (n: t:
let d = import ../devices/${n}/default.nix;
d' = { description = "no description for ${n}"; } // d;
in d'.description )
devices;
in
writeText "hwdoc" ''
Supported hardware
##################
${lib.concatStringsSep "\n\n" texts}
''
-1
View File
@@ -11,7 +11,6 @@ Liminix
admin
development
modules
hardware
Indices and tables
+10 -84
View File
@@ -60,7 +60,7 @@ Now you can try it:
.. code-block:: console
./result/run.sh
nix-shell --run "mips-vm ./result/vmlinux ./result/rootfs"
This starts the Qemu emulator with a bunch of useful options, to run
the Liminix configuration you just built. It connects the emulated
@@ -123,9 +123,9 @@ Installing on hardware
**********************
For the next example, we're going to install onto an actual hardware
device. These steps have been tested using a GL.iNet GL-MT300A, which
device. These steps have been tested using a GL-iNet GL-MT300A, which
has been chosen for the purpose because it's cheap and easy to
unbrick if necessary.
unbrick if necessary
.. warning:: There is always a risk of rendering your device
unbootable by flashing it with an image that doesn't
@@ -227,86 +227,13 @@ example, but this time for real.
with some imagination could probably still do something
awful using it.
Congratulations Part II! You have installed your first Liminix system on actual hardware - albeit that it *still* has no practical use.
Congratulations Part II! You have installed your first Liminix system on
actual hardware - albeit that it *still* has no practical use.
Exercise for the reader: change the default password by editing
:file:`examples/hello-from-mt300.nix`, and then create and upload a
new image that has it set to something less hopeless.
Routing
*******
The third example :file:`examples/demo.nix` is a fully-functional home
"WiFi router" - although you will have to edit it a bit before it will
actually work for you. Copy :file:`examples/demo.nix` to
:file:`my-router.nix` (or other name of your choice) and open it in
your favourite text editor. Everywhere that the text :code:`EDIT`
appears is either a place you probably want to change or a place you
almost certainly need to change.
There's a lot going on in this configuration:
* it provides a wireless access point using the :code:`hostapd`
service: in this stanza you can change the ssid, the channel,
the passphrase etc.
* the wireless lan and wired lan are bridged together with the
:code:`bridge` service, so that your wired and wireless clients appear
to be on the same network.
.. tip:: If you were using a hardware device that provides both 2.4GHz
and 5GHz wifi, you'd probably find that it has two wireless
devices (often called wlan0 and wlan1). In Liminix we handle
this by running two :code:`hostapd` services, and adding
both of them to the network bridge along with the wired lan.
(You can see an example in :file:`examples/rotuer.nix`)
* we use the combination DNS and DHCP daemon provided by the
:code:`dnsmasq` service, which you can configure
* the upstream network is "PPP over Ethernet", provided by the
:code:`pppoe` service. Assuming that your ISP uses this standard,
they will have provided you with a PPP username and password
(sometimes this will be listed as "PAP" or "CHAP") which you can edit
into the configuration
* this example supports the new [#ipv6]_ Internet Protocol v6
as well as traditional IPv4. Configuring IPv6 seems to
vary from one ISP to the next: this example expects them
to be providing IP address allocation and "prefix delegation"
using DHCP6.
Build it using the same method as the previous example
.. code-block:: console
nix-build -I liminix-config=./my-router.nix \
--arg device "import ./devices/gl-mt300a" -A outputs.default
and then you can flash it to the device.
Bonus: in-place updates
=======================
This configuration uses a writable filesystem (see the line
:code:`rootfsType = "jffs2"`), which means that once you've flashed it
for the first time, you can make further updates over SSH onto the
running router. To try this, make a small change (I'd suggest changing
the hostname) and then run
.. code-block:: console
nix-shell --run "liminix-rebuild root@address-of-the-device -I liminix-config=./my-router.nix --arg device "import ./devices/gl-ar750""
(This requires the device to be network-accessible from your build
machine, which for a test/demo system might involve a second network
device in your build system - USB ethernet adapters are cheap - or
a bit of messing around unplugging cables.)
For more information about :code:`liminix-rebuild`, see the manual section :ref:`admin:Rebuilding the system`.
Final thoughts
**************
@@ -316,14 +243,13 @@ Final thoughts
:file:`examples/rotuer,arhcive,extneder.nix` are based on some
actual real hosts in my home network.
* These example images are not writable. Later we will explain how to
generate an image that can be changed after installation, and
even use :command:`liminix-rebuild` (analogous to :command:`nixos-rebuild`)
to keep it up to date.
* The technique used here for flashing was chosen mostly because it
doesn't need much infrastructure/tooling, but it is a bit of a faff
(requires physical access, vendor specific). There are slicker ways
to do it that need a bit more setup - we'll talk about that later as
well.
.. rubric:: Footnotes
.. [#ipv6] `RFC1883 Internet Protocol, Version 6 <https://datatracker.ietf.org/doc/html/rfc1883>`_ was published in 1995, so only "new" when Bill Clinton was US President
+1
View File
@@ -51,6 +51,7 @@ in rec {
SCSI = "y";
BLK_DEV_SD = "y";
USB_PRINTER = "y";
PARTITION_ADVANCED = "y";
MSDOS_PARTITION = "y";
EFI_PARTITION = "y";
EXT4_FS = "y";
-203
View File
@@ -1,203 +0,0 @@
# This is an example configuration for a "typical" small office/home
# router and wifi access point.
# You need to copy it to another filename and change the configuration
# wherever the text "EDIT" appears - please consult the tutorial
# documentation for details.
{ config, pkgs, lib, ... } :
let
inherit (pkgs.liminix.services) bundle oneshot longrun;
inherit (pkgs) serviceFns;
# EDIT: you can pick your preferred RFC1918 address space
# for NATted connections, if you don't like this one.
ipv4LocalNet = "10.8.0";
svc = config.system.service;
in rec {
boot = {
tftp = {
freeSpaceBytes = 3 * 1024 * 1024;
serverip = "10.0.0.1";
ipaddr = "10.0.0.8";
};
};
imports = [
../modules/bridge
../modules/dhcp6c
../modules/dnsmasq
../modules/firewall
../modules/hostapd
../modules/network
../modules/ntp
../modules/ppp
../modules/ssh
../modules/standard.nix
../modules/vlan
../modules/wlan.nix
];
rootfsType = "jffs2";
hostname = "the-internet"; # EDIT
services.hostap = svc.hostapd.build {
interface = config.hardware.networkInterfaces.wlan;
# EDIT: you will want to change the obvious things
# here to values of your choice
params = {
ssid = "the-internet";
channel = "1";
country_code = "GB";
wpa_passphrase = "not a real wifi password";
hw_mode="g";
ieee80211n = 1;
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
wmm_enabled = 1;
};
};
services.int = svc.network.address.build {
interface = svc.bridge.primary.build { ifname = "int"; };
family = "inet"; address = "${ipv4LocalNet}.1"; prefixLength = 16;
};
services.bridge = svc.bridge.members.build {
primary = services.int;
members = with config.hardware.networkInterfaces;
[ wlan lan ];
};
services.ntp = svc.ntp.build {
pools = { "pool.ntp.org" = ["iburst"]; };
makestep = { threshold = 1.0; limit = 3; };
};
services.sshd = svc.ssh.build { };
users.root = {
# EDIT: choose a root password and then use
# "mkpasswd -m sha512crypt" to determine the hash.
# It should start wirh $6$.
passwd = "$6$6HG7WALLQQY1LQDE$428cnouMJ7wVmyK9.dF1uWs7t0z9ztgp3MHvN5bbeo0M4Kqg/u2ThjoSHIjCEJQlnVpDOaEKcOjXAlIClHWN21";
openssh.authorizedKeys.keys = [
# EDIT: you can add your ssh pubkey here
# "ssh-rsa AAAAB3NzaC1....H6hKd user@example.com";
];
};
services.dns =
let interface = services.int;
in svc.dnsmasq.build {
resolvconf = services.resolvconf;
inherit interface;
ranges = [
"${ipv4LocalNet}.10,${ipv4LocalNet}.249"
# EDIT: ... maybe. In this example we use "ra-stateless",
# meaning dnsmasq sends router advertisements with the O and A
# bits set, and provides a stateless DHCP service. The client
# will use a SLAAC address, and use DHCP for other
# configuration information.
# If you didn't understand the preceding sentence then
# the default is _probably_ fine, but if you need
# a DHCP-only IPv6 network or some other different
# configuration, this is the place to change it.
"::,constructor:$(output ${interface} ifname),ra-stateless"
];
# EDIT: choose a domain name for the DNS names issued for your
# DHCP-issued hosts
domain = "lan.example.com";
};
services.wan = svc.pppoe.build {
interface = config.hardware.networkInterfaces.wan;
ppp-options = [
"debug" "+ipv6" "noauth"
# EDIT: change the strings "chap-username"
# and "chap-secret" to match the username/password
# provided by your ISP for PPP logins
"name" "chap-username"
"password" "chap-secret"
];
};
services.resolvconf = oneshot rec {
dependencies = [ services.wan ];
name = "resolvconf";
up = ''
. ${serviceFns}
( in_outputs ${name}
echo "nameserver $(output ${services.wan} ns1)" > resolv.conf
echo "nameserver $(output ${services.wan} ns2)" >> resolv.conf
chmod 0444 resolv.conf
)
'';
};
filesystem =
let inherit (pkgs.pseudofile) dir symlink;
in dir {
etc = dir {
"resolv.conf" = symlink "${services.resolvconf}/.outputs/resolv.conf";
};
};
services.defaultroute4 = svc.network.route.build {
via = "$(output ${services.wan} address)";
target = "default";
dependencies = [ services.wan ];
};
services.defaultroute6 = svc.network.route.build {
via = "$(output ${services.wan} ipv6-peer-address)";
target = "default";
interface = services.wan;
};
services.firewall = svc.firewall.build {
ruleset = import ./demo-firewall.nix;
};
services.packet_forwarding = svc.network.forward.build { };
# We expect the ISP uses DHCP6 to issue IPv6 addresses. There is a
# service to request address information in the form of a DHCP
# lease, and two dependent services that listen for updates to the
# DHCP address information and update the addresses of the WAN and
# LAN interfaces respectively.
services.dhcp6c =
let client = svc.dhcp6c.client.build {
interface = services.wan;
};
in bundle {
name = "dhcp6c";
contents = [
(svc.dhcp6c.prefix.build {
# if your ISP provides you a real IPv6 prefix for your local
# network (usually a /64 or /48 or something in between the
# two), this service subscribes to that "prefix delegation"
# information, and uses it to assign an address to the LAN
# device. dnsmasq will notice this address and use it to
# form the addresses it hands out to devices on the lan
inherit client;
interface = services.int;
})
(svc.dhcp6c.address.build {
# if your ISP provides you a regular global IPv6 address,
# this service subscribes to that information and assigns
# the address to the WAN device.
inherit client;
interface = services.wan;
})
];
};
defaultProfile.packages = with pkgs; [
min-collect-garbage
];
}
+33 -24
View File
@@ -9,7 +9,7 @@
{ config, pkgs, lib, ... } :
let
secrets = import ./rotuer-secrets.nix;
inherit (pkgs.liminix.services) oneshot longrun bundle;
inherit (pkgs.liminix.services) oneshot longrun;
inherit (pkgs) serviceFns;
svc = config.system.service;
wirelessConfig = {
@@ -38,7 +38,6 @@ in rec {
../modules/network
../modules/ppp
../modules/dnsmasq
../modules/dhcp6c
../modules/firewall
../modules/hostapd
../modules/bridge
@@ -49,7 +48,7 @@ in rec {
hostname = "rotuer";
services.hostap = svc.hostapd.build {
interface = config.hardware.networkInterfaces.wlan;
interface = config.hardware.networkInterfaces.wlan_24;
params = {
ssid = "liminix";
hw_mode="g";
@@ -59,7 +58,7 @@ in rec {
};
services.hostap5 = svc.hostapd.build {
interface = config.hardware.networkInterfaces.wlan5;
interface = config.hardware.networkInterfaces.wlan_5;
params = rec {
ssid = "liminix_5";
hw_mode="a";
@@ -79,9 +78,7 @@ in rec {
services.bridge = svc.bridge.members.build {
primary = services.int;
members = with config.hardware.networkInterfaces;
[ wlan
wlan5
lan ];
[ wlan_24 wlan_5 lan ];
};
services.ntp = svc.ntp.build {
@@ -157,27 +154,39 @@ in rec {
};
services.firewall = svc.firewall.build {
ruleset = import ./demo-firewall.nix;
ruleset = import ./rotuer-firewall.nix;
};
services.packet_forwarding = svc.network.forward.build { };
services.dhcp6c =
let client = svc.dhcp6c.client.build {
interface = services.wan;
};
in bundle {
name = "dhcp6c";
contents = [
(svc.dhcp6c.prefix.build {
inherit client;
interface = services.int;
})
(svc.dhcp6c.address.build {
inherit client;
interface = services.wan;
})
];
services.dhcp6 =
let
name = "dhcp6c.wan";
in longrun {
inherit name;
notification-fd = 10;
run = ''
export SERVICE_STATE=/run/service-state/${name}
${pkgs.odhcp6c}/bin/odhcp6c -s ${pkgs.odhcp-script} -e -v -p /run/${name}.pid -P 48 $(output ${services.wan} ifname)
)
'';
dependencies = [ services.wan ];
};
services.acquire-lan-prefix =
let script = pkgs.callPackage ./acquire-delegated-prefix.nix { };
in longrun {
name = "acquire-lan-prefix";
run = "${script} /run/service-state/dhcp6c.wan $(output ${services.int} ifname)";
dependencies = [ services.dhcp6 ];
};
services.acquire-wan-address =
let script = pkgs.callPackage ./acquire-wan-address.nix { };
in longrun {
name = "acquire-wan-address";
run = "${script} /run/service-state/dhcp6c.wan $(output ${services.wan} ifname)";
dependencies = [ services.dhcp6 ];
};
defaultProfile.packages = with pkgs; [
+49
View File
@@ -0,0 +1,49 @@
{
lzma
, stdenv
, ubootTools
, dtc
} :
let
objcopy = "${stdenv.cc.bintools.targetPrefix}objcopy";
arch = "arm64";
in {
kernel
, commandLine
, entryPoint
, extraName ? "" # e.g. socFamily
, loadAddress
, dtb ? null
} :
stdenv.mkDerivation {
name = "kernel.image";
phases = [
"preparePhase"
(if dtb != null then "dtbPhase" else ":")
"buildPhase"
"installPhase" ];
nativeBuildInputs = [
lzma
dtc
stdenv.cc
ubootTools
];
preparePhase = ''
cp ${kernel} vmlinux.elf; chmod +w vmlinux.elf
'';
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
${objcopy} --update-section .appended_dtb=tmp.dtb vmlinux.elf || ${objcopy} --add-section .appended_dtb=${dtb} vmlinux.elf
'';
buildPhase = ''
${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
mkimage -A ${arch} -O linux -T kernel -C lzma -a ${loadAddress} -e ${entryPoint} -n '${arch} Liminix Linux ${extraName}' -d vmlinux.bin.lzma kernel.uimage
'';
installPhase = ''
cp kernel.uimage $out
'';
}
-16
View File
@@ -1,16 +0,0 @@
{ lib, pkgs, config, ...}:
{
config = {
kernel.config = {
CPU_LITTLE_ENDIAN= "y";
CPU_BIG_ENDIAN= "n";
# CMDLINE_FROM_BOOTLOADER availability is conditional
# on CMDLINE being set to something non-empty
CMDLINE="\"empty=false\"";
CMDLINE_FROM_BOOTLOADER = "y";
OF = "y";
# USE_OF = "y";
};
};
}
-17
View File
@@ -1,17 +0,0 @@
{ lib, pkgs, config, ...}:
{
config = {
kernel.config = {
MIPS_ELF_APPENDED_DTB = "y";
MIPS_BOOTLOADER_CMDLINE_REQUIRE_COOKIE = "y";
MIPS_BOOTLOADER_CMDLINE_COOKIE = "\"liminix\"";
MIPS_CMDLINE_DTB_EXTEND = "y";
OF = "y";
USE_OF = "y";
};
boot.commandLine = [
"console=ttyS0,115200" # true of all mips we've yet encountered
];
};
}
-9
View File
@@ -1,9 +0,0 @@
{ lib, pkgs, config, ...}:
{
imports = [ ./mips.nix ];
config = {
kernel.config = {
CPU_BIG_ENDIAN = "y";
};
};
}
-9
View File
@@ -1,9 +0,0 @@
{ lib, pkgs, config, ...}:
{
imports = [ ./mips.nix ];
config = {
kernel.config = {
CPU_LITTLE_ENDIAN = "y";
};
};
}
+1 -1
View File
@@ -81,7 +81,7 @@ in {
[ s6 s6-init-bin execline s6-linux-init s6-rc ];
boot.commandLine = [
"panic=10 oops=panic init=/bin/init loglevel=8"
"console=ttyS0,115200 panic=10 oops=panic init=/bin/init loglevel=8"
"root=${config.hardware.rootDevice}"
"rootfstype=${config.rootfsType}"
"fw_devlink=off"
-16
View File
@@ -1,16 +0,0 @@
{
liminix
, lib
, callPackage
}:
{ client, interface } :
let
inherit (liminix.services) longrun;
inherit (lib) mkOption types;
name = "dhcp6c.addr.${client.name}.${interface.name}";
script = callPackage ./acquire-wan-address.nix { };
in longrun {
inherit name;
run = "${script} /run/service-state/${client.name} $(output ${interface} ifname)";
dependencies = [ client interface ];
}
-21
View File
@@ -1,21 +0,0 @@
{
liminix
, lib
, odhcp6c
, odhcp-script
}:
{ interface } :
let
inherit (liminix.services) longrun;
inherit (lib) mkOption types;
name = "dhcp6c.${interface.name}";
in longrun {
inherit name;
notification-fd = 10;
run = ''
export SERVICE_STATE=/run/service-state/${name}
${odhcp6c}/bin/odhcp6c -s ${odhcp-script} -e -v -p /run/${name}.pid -P0 $(output ${interface} ifname)
)
'';
dependencies = [ interface ];
}
-52
View File
@@ -1,52 +0,0 @@
## DHCP6 client module
## ===================
##
## This is for use if you have an IPv6-capable upstream that provides
## address information and/or prefix delegation using DHCP6. It
## provides a service to request address information in the form of a
## DHCP lease, and two dependent services that listen for updates
## to the DHCP address information and can be used to update
## addresses of network interfaces that you want to assign those
## prefixes to
{ lib, pkgs, config, ...}:
let
inherit (lib) mkOption types;
inherit (pkgs.liminix.services) oneshot;
inherit (pkgs) liminix;
in
{
options = {
system.service.dhcp6c = {
client = mkOption { type = liminix.lib.types.serviceDefn; };
prefix = mkOption { type = liminix.lib.types.serviceDefn; };
address = mkOption { type = liminix.lib.types.serviceDefn; };
};
};
config.system.service.dhcp6c = {
client = liminix.callService ./client.nix {
interface = mkOption {
type = liminix.lib.types.interface;
description = "interface (usually WAN) to query for DHCP6";
};
};
address = liminix.callService ./address.nix {
client = mkOption {
type = types.anything; # liminix.lib.types.service;
};
interface = mkOption {
type = liminix.lib.types.interface;
description = "interface to assign the address to";
};
};
prefix = liminix.callService ./prefix.nix {
client = mkOption {
type = types.anything; # liminix.lib.types.service;
};
interface = mkOption {
type = liminix.lib.types.interface;
description = "interface to assign <prefix>::1 to";
};
};
};
}
-16
View File
@@ -1,16 +0,0 @@
{
liminix
, lib
, callPackage
}:
{ client, interface } :
let
inherit (liminix.services) longrun;
inherit (lib) mkOption types;
name = "dhcp6c.prefix.${client.name}.${interface.name}";
script = callPackage ./acquire-delegated-prefix.nix { };
in longrun {
inherit name;
run = "${script} /run/service-state/${client.name} $(output ${interface} ifname)";
dependencies = [ client interface ];
}
+4 -9
View File
@@ -38,9 +38,6 @@ in {
kernel = {
config = {
MTD_SPLIT_UIMAGE_FW = "y";
} // lib.optionalAttrs (pkgs.stdenv.isMips) {
# https://stackoverflow.com/questions/26466470/can-the-logical-erase-block-size-of-an-mtd-device-be-increased
MTD_SPI_NOR_USE_4K_SECTORS = "n";
};
};
@@ -50,12 +47,10 @@ in {
system.outputs = {
firmware =
let
o = config.system.outputs;
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
let o = config.system.outputs; in
pkgs.runCommand "firmware" {} ''
dd if=${o.uimage} of=$out bs=128k conv=sync
dd if=${o.rootfs} of=$out bs=128k conv=sync,nocreat,notrunc oflag=append
'';
flashimage =
let o = config.system.outputs; in
+5 -1
View File
@@ -24,7 +24,7 @@ in {
extraPatchPhase = mkOption {
default = "true";
type = types.lines;
};
} ;
config = mkOption {
description = ''
Kernel config options, as listed in Kconfig* files in the
@@ -56,6 +56,10 @@ in {
MODULE_SIG = if modular then "y" else "n";
DEBUG_FS = "y";
# MIPS_BOOTLOADER_CMDLINE_REQUIRE_COOKIE = "y";
# MIPS_BOOTLOADER_CMDLINE_COOKIE = "\"liminix\"";
# MIPS_CMDLINE_DTB_EXTEND = "y";
# basic networking protocols
NET = "y";
UNIX = "y";
+12 -30
View File
@@ -7,12 +7,6 @@
let
inherit (lib) mkOption types concatStringsSep;
inherit (pkgs) liminix callPackage writeText;
arch = let s = pkgs.stdenv; in
if s.isAarch64
then "aarch64"
else if s.isMips
then "mips"
else throw "can't determine arch";
in
{
imports = [
@@ -42,7 +36,7 @@ in
type = types.package;
description = ''
Directory containing separate kernel and rootfs image for
use with qemu (see run-liminix-vm)
use with qemu (see mips-vm)
'';
};
manifest = mkOption {
@@ -68,41 +62,29 @@ in
kernel = liminix.builders.kernel.override {
inherit (config.kernel) config src extraPatchPhase;
};
dtb = liminix.builders.dtb {
dtb = (callPackage ../kernel/dtb.nix {}) {
inherit (config.boot) commandLine;
dts = config.hardware.dts.src;
includes = config.hardware.dts.includes ++ [
"${kernel.headers}/include"
];
};
uimage = liminix.builders.uimage {
uimage = (callPackage ../kernel/uimage.nix {}) {
commandLine = concatStringsSep " " config.boot.commandLine;
inherit (config.hardware) loadAddress entryPoint;
inherit kernel;
inherit dtb;
};
# could use trivial-builders.linkFarmFromDrvs here?
vmroot =
let
cmdline = builtins.toJSON (concatStringsSep " " config.boot.commandLine);
makeBootableImage = pkgs.runCommandCC "objcopy" {}
(if pkgs.stdenv.isAarch64
then "${pkgs.stdenv.cc.targetPrefix}objcopy -O binary -S ${kernel} $out"
else "cp ${kernel} $out");
in pkgs.runCommandCC "vmroot" {} ''
mkdir $out
cd $out
ln -s ${config.system.outputs.rootfs} rootfs
ln -s ${kernel} vmlinux
ln -s ${manifest} manifest
ln -s ${kernel.headers} build
echo ${cmdline} > commandline
cat > run.sh << EOF
#!${pkgs.runtimeShell}
CMDLINE=${cmdline} ${pkgs.pkgsBuildBuild.run-liminix-vm}/bin/run-liminix-vm --arch ${arch} \$* ${makeBootableImage} ${config.system.outputs.rootfs}
EOF
chmod +x run.sh
'';
vmroot = pkgs.runCommandCC "vmroot" {} ''
mkdir $out
cd $out
ln -s ${config.system.outputs.rootfs} rootfs
ln -s ${kernel} vmlinux
${pkgs.stdenv.cc.targetPrefix}objcopy -O binary -S ${kernel} Image
ln -s ${manifest} manifest
ln -s ${kernel.headers} build
'';
manifest = writeText "manifest.json" (builtins.toJSON config.filesystem.contents);
};
+8 -22
View File
@@ -42,41 +42,27 @@ in {
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
ln -s ${o.boot-scr} 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 ]; } ''
pkgs.buildPackages.runCommand "boot-scr" {} ''
uimageSize=$(($(stat -L -c %s ${o.uimage}) + 0x1000 &(~0xfff)))
rootfsStart=0x$(printf %x $((${cfg.loadAddress} + 0x100000 + $uimageSize &(~0xfffff) )))
rootfsStart=0x$(printf %x $((${cfg.loadAddress} + 0x100000 + $uimageSize)))
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";
cmd="mtdparts=phram0:''${rootfsMb}M(rootfs) phram.phram=phram0,''${rootfsStart},''${rootfsBytes},${config.hardware.flash.eraseBlockSize} memmap=''${rootfsBytes}\$''${rootfsStart} 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
cat > $out << 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
#
setenv bootargs 'liminix $cmd'
tftp 0x$(printf %x ${cfg.loadAddress}) result/uimage ; tftp 0x$(printf %x $rootfsStart) result/rootfs
bootm 0x$(printf %x ${cfg.loadAddress})
EOF
'';
};
+1 -3
View File
@@ -16,8 +16,6 @@ in {
networking = callPackage ./liminix-tools/networking {};
builders = {
squashfs = callPackage ./liminix-tools/builders/squashfs.nix {};
dtb = callPackage ./kernel/dtb.nix {};
uimage = callPackage ./kernel/uimage.nix {};
kernel = callPackage ./kernel {};
};
callService = path : parameters :
@@ -59,7 +57,7 @@ in {
systemconfig = callPackage ./systemconfig {};
s6-init-bin = callPackage ./s6-init-bin {};
s6-rc-database = callPackage ./s6-rc-database {};
run-liminix-vm = callPackage ./run-liminix-vm {};
mips-vm = callPackage ./mips-vm {};
ppp = callPackage ./ppp {};
pppoe = callPackage ./pppoe {};
+1 -6
View File
@@ -11,11 +11,6 @@
}:
let
writeConfig = import ../kernel/write-kconfig.nix { inherit lib writeText; };
arch = if stdenv.isMips
then "mips"
else if stdenv.isAarch64
then "arm64"
else throw "unknown arch";
in stdenv.mkDerivation {
name = "kernel-modules";
@@ -30,7 +25,7 @@ in stdenv.mkDerivation {
HOST_EXTRACFLAGS = with buildPackages.pkgs;
"-I${buildPackages.openssl.dev}/include -L${buildPackages.openssl.out}/lib";
CROSS_COMPILE = stdenv.cc.bintools.targetPrefix;
ARCH = arch;
ARCH = "mips"; # kernel uses "mips" here for both mips and mipsel
KBUILD_BUILD_HOST = "liminix.builder";
buildPhase = ''
+3 -10
View File
@@ -11,12 +11,6 @@
let
writeConfig = import ./write-kconfig.nix { inherit lib writeText; };
kconfigFile = writeConfig "kconfig" config;
arch = if stdenv.isMips
then "mips"
else if stdenv.isAarch64
then "arm64"
else throw "unknown arch";
inherit lib; in
stdenv.mkDerivation rec {
name = "kernel";
@@ -24,7 +18,7 @@ stdenv.mkDerivation rec {
hardeningDisable = ["all"];
nativeBuildInputs = [buildPackages.stdenv.cc] ++
(with buildPackages.pkgs; [
rsync bc bison flex pkg-config
rsync bc bison flex pkgconfig
openssl ncurses.all perl
]);
CC = "${stdenv.cc.bintools.targetPrefix}gcc";
@@ -34,7 +28,7 @@ stdenv.mkDerivation rec {
"-I${openssl.dev}/include -L${openssl.out}/lib -L${ncurses.out}/lib";
PKG_CONFIG_PATH = "./pkgconfig";
CROSS_COMPILE = stdenv.cc.bintools.targetPrefix;
ARCH = arch;
ARCH = "arm64";
KBUILD_BUILD_HOST = "liminix.builder";
dontStrip = true;
@@ -53,8 +47,7 @@ stdenv.mkDerivation rec {
];
patches = [
./cmdline-cookie.patch
./phram-allow-cached-mappings.patch
# ./cmdline-cookie.patch
];
# this is here to work around what I think is a bug in nixpkgs
-50
View File
@@ -1,50 +0,0 @@
/dts-v1/;
// used on aarch64 to provide a U-bootable image that combines
// kernel and fdt
/ {
description = "Simple image with single Linux kernel and FDT blob";
#address-cells = <1>;
images {
kernel {
description = "Vanilla Linux kernel";
// data = /incbin/("./vmlinux.bin.gz");
type = "kernel";
arch = "arm64";
os = "linux";
// compression = "gzip";
// load = <00000000>;
// entry = <00000000>;
hash-1 {
algo = "crc32";
};
hash-2 {
algo = "sha1";
};
};
fdt-1 {
description = "Flattened Device Tree blob";
// data = /incbin/("./target.dtb");
type = "flat_dt";
arch = "arm64";
compression = "none";
hash-1 {
algo = "crc32";
};
hash-2 {
algo = "sha1";
};
};
};
configurations {
default = "conf-1";
conf-1 {
description = "Boot Linux kernel with FDT blob";
kernel = "kernel";
fdt = "fdt-1";
};
};
};
@@ -1,47 +0,0 @@
From bb7e7aeb3d832059e33b1e76eb85d4680f77abf2 Mon Sep 17 00:00:00 2001
From: Ben Hutchings <ben@decadent.org.uk>
Date: Fri, 3 Jun 2016 01:08:36 +0100
Subject: [PATCH] phram: Use memremap() to allow mapping of system RAM
Using memremap() instead of ioremap() allows mapping a disk image in
system RAM that has somehow been reserved. It should fall back
to ioremap() where necessary.
Entirely untested, and I'm not convinced this is a good idea at all.
---
drivers/mtd/devices/phram.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/drivers/mtd/devices/phram.c b/drivers/mtd/devices/phram.c
index 8b66e52ca3cc..0ea254e2ba51 100644
--- a/drivers/mtd/devices/phram.c
+++ b/drivers/mtd/devices/phram.c
@@ -88,7 +88,7 @@ static void unregister_devices(void)
list_for_each_entry_safe(this, safe, &phram_list, list) {
mtd_device_unregister(&this->mtd);
- iounmap(this->mtd.priv);
+ memunmap(this->mtd.priv);
kfree(this->mtd.name);
kfree(this);
}
@@ -104,7 +104,8 @@ static int register_device(char *name, phys_addr_t start, size_t len)
goto out0;
ret = -EIO;
- new->mtd.priv = ioremap(start, len);
+ new->mtd.priv = memremap(start, len,
+ MEMREMAP_WB | MEMREMAP_WT | MEMREMAP_WC);
if (!new->mtd.priv) {
pr_err("ioremap failed\n");
goto out1;
@@ -134,7 +135,7 @@ static int register_device(char *name, phys_addr_t start, size_t len)
return 0;
out2:
- iounmap(new->mtd.priv);
+ memunmap(new->mtd.priv);
out1:
kfree(new);
out0:
-65
View File
@@ -1,65 +0,0 @@
{
lzma
, stdenv
, ubootTools
, dtc
, lib
} :
let
objcopy = "${stdenv.cc.bintools.targetPrefix}objcopy";
in {
kernel
, commandLine
, entryPoint
, extraName ? "" # e.g. socFamily
, loadAddress
, dtb ? null
} :
stdenv.mkDerivation {
name = "kernel.image";
phases = [
"preparePhase"
(if dtb != null then "dtbPhase" else ":")
"buildPhase"
"installPhase" ];
nativeBuildInputs = [
lzma
dtc
stdenv.cc
ubootTools
];
preparePhase = ''
cp ${kernel} vmlinux.elf; chmod +w vmlinux.elf
'';
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
'';
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 mkimage.itb $out
'';
}
+2 -15
View File
@@ -14,11 +14,6 @@
, lib
}:
let
arch = if stdenv.isMips
then "mips"
else if stdenv.isAarch64
then "arm64"
else throw "unknown arch";
openwrtSrc = fetchFromGitHub {
name = "openwrt-source";
repo = "openwrt";
@@ -57,14 +52,6 @@ let
WLAN_VENDOR_MEDIATEK = "y";
MT7603E = "y";
};
mt7915e = {
MT7915E = "m";
};
mt7615e = {
MT7615E = "m";
MT7622_WMAC = "y";
};
mac80211_hwsim = {
MAC80211_HWSIM = "y";
};
@@ -107,11 +94,11 @@ let
hardeningDisable = ["all"];
nativeBuildInputs = [buildPackages.stdenv.cc] ++
(with buildPackages.pkgs;
[bc bison flex pkg-config openssl
[bc bison flex pkgconfig openssl
which kmod cpio
]);
inherit CC CROSS_COMPILE;
ARCH = arch;
ARCH = "mips"; # kernel uses "mips" here for both mips and mipsel
dontStrip = true;
dontPatchELF = true;
phases = [
@@ -5,15 +5,15 @@
, symlinkJoin
, lib
}: let
run-liminix-vm = writeShellScriptBin "run-liminix-vm" ''
mips-vm = writeShellScriptBin "mips-vm" ''
export PATH="${lib.makeBinPath [qemu]}:$PATH"
${builtins.readFile ./run-liminix-vm.sh}
${builtins.readFile ./mips-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 symlinkJoin {
name = "run-liminix-vm";
paths = [ run-liminix-vm connect ];
name = "mips-vm";
paths = [ mips-vm connect ];
}
@@ -12,12 +12,6 @@ usage(){
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
@@ -37,7 +31,7 @@ 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)
rootfs=$(mktemp mips-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
@@ -45,21 +39,16 @@ 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 \
echo $QEMU_OPTIONS
qemu-system-aarch64 \
-M virt -m 512 \
-echr 16 \
-append "$CMDLINE liminix root=/dev/mtdblock0 block2mtd.block2mtd=/dev/vda,65536" \
-append "liminix default earlycon=smh console=ttyAMA0,38400n8 panic=10 oops=panic init=$INIT loglevel=8 root=/dev/mtdblock0 block2mtd.block2mtd=/dev/vda,65536" \
-semihosting \
-cpu cortex-a72 \
-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 \
-3
View File
@@ -14,7 +14,6 @@ let
cp -av ${src}/target/linux/generic/files/* .
chmod -R u+w .
cp -av ${src}/target/linux/${family}/files/* .
test -d ${src}/target/linux/${family}/files-5.15/ && cp -av ${src}/target/linux/${family}/files-5.15/* .
chmod -R u+w .
patches() {
for i in $* ; do patch --batch --forward -p1 < $i ;done
@@ -27,11 +26,9 @@ let
patch --batch -p1 --reverse < ${src}/target/linux/generic/pending-5.15/330-MIPS-kexec-Accept-command-line-parameters-from-users.patch
patches ${src}/target/linux/generic/hack-5.15/*.patch
patches ${src}/target/linux/${family}/patches-5.15/*.patch
patches ${./make-mtdsplit-jffs2-endian-agnostic.patch}
'';
in {
inherit src;
applyPatches.ath79 = doPatch "ath79";
applyPatches.ramips = doPatch "ramips";
applyPatches.mediatek = doPatch "mediatek"; # aarch64
}
@@ -1,25 +0,0 @@
From 12345790 Tue Sep 26 18:30:44 2023
From: Daniel Barlow <dan@telent.net>
Date: Tue Sep 26 18:29:47 BST 2023
Subject: mtdsplit: find magic of little-endian JFFS2
On a little-endian CPU, the little-endian JFFS2 magic
appears to be word-swapped.
There is probably a better way to implement this; if you are reading
this patch you are probably well-qualified to do that and upstream it
to OpenWrt
diff --git a/drivers/mtd/mtdsplit/mtdsplit.c b/drivers/mtd/mtdsplit/mtdsplit.c
index b2e51dcfc6..533af0298e 100644
--- a/drivers/mtd/mtdsplit/mtdsplit.c
+++ b/drivers/mtd/mtdsplit/mtdsplit.c
@@ -92,6 +93,6 @@
*type = MTDSPLIT_PART_TYPE_SQUASHFS;
return 0;
- } else if (magic == 0x19852003) {
+ } else if ((magic == 0x19852003) || (magic == 0x20031985)) {
if (type)
*type = MTDSPLIT_PART_TYPE_JFFS2;
return 0;
+1 -1
View File
@@ -12,7 +12,7 @@ in stdenv.mkDerivation {
sha256 = "0hi2rj1a1fbvr5n1090q1zzigjyxmn643jzrwngw4ij0g82za3al";
};
name = "swconfig";
buildInputs = [ buildPackages.pkg-config ];
buildInputs = [ buildPackages.pkgconfig ];
nativeBuildInputs = [ libnl ];
CFLAGS="-O2 -Ifrom_kernel -I${libnl.dev}/include/libnl3";
LDFLAGS="-L${libnl.out}/lib";
+1 -1
View File
@@ -1,7 +1,7 @@
let
nixpkgs = <nixpkgs>;
liminix = (import ./default.nix {
device = (import ./devices/qemu);
device = (import ./devices/qemu-aarch64);
liminix-config = ./vanilla-configuration.nix;
inherit nixpkgs;
});
+3 -1
View File
@@ -7,13 +7,15 @@ let img = (import liminix {
liminix-config = ./configuration.nix;
}).outputs.vmroot;
pkgs = import <nixpkgs> { overlays = [(import ../../overlay.nix)]; };
inherit (pkgs.pkgsBuildBuild) routeros mips-vm;
in pkgs.runCommand "check" {
nativeBuildInputs = with pkgs; [
mips-vm
expect
socat
] ;
} ''
mkdir vm
${img}/run.sh --background ./vm
mips-vm --background ./vm ${img}/vmlinux ${img}/rootfs
expect ${./script.expect} >$out
''
+3 -3
View File
@@ -9,11 +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;
inherit (pkgs.pkgsBuildBuild) mips-vm;
in pkgs.runCommand "check" {
nativeBuildInputs = with pkgs; [
expect
run-liminix-vm
mips-vm
socat
min-copy-closure
rogue
@@ -22,7 +22,7 @@ in pkgs.runCommand "check" {
. ${../test-helpers.sh}
mkdir vm
LAN=user,hostfwd=tcp::2022-:22 run-liminix-vm --background ./vm ${img}/vmlinux ${img}/rootfs
LAN=user,hostfwd=tcp::2022-:22 mips-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
+3 -2
View File
@@ -7,7 +7,7 @@ let img = (import liminix {
liminix-config = ./configuration.nix;
}).outputs.default;
pkgs = import <nixpkgs> { overlays = [(import ../../overlay.nix)]; };
inherit (pkgs.pkgsBuildBuild) routeros run-liminix-vm;
inherit (pkgs.pkgsBuildBuild) routeros mips-vm;
in pkgs.runCommand "check" {
nativeBuildInputs = with pkgs; [
python3Packages.scapy
@@ -15,6 +15,7 @@ in pkgs.runCommand "check" {
jq
socat
routeros.routeros
mips-vm
] ;
} ''
serverstatedir=$(mktemp -d -t routeros-XXXXXX)
@@ -26,7 +27,7 @@ export MPLCONFIGDIR=$(mktemp -d -t routeros-XXXXXX)
routeros $serverstatedir
mkdir vm
${img}/run.sh --background ./vm
mips-vm --background ./vm ${img}/vmlinux ${img}/rootfs
expect ${./getaddress.expect}
set -o pipefail
+5 -3
View File
@@ -7,15 +7,17 @@ let img = (import liminix {
liminix-config = ./configuration.nix;
}).outputs.default;
pkgs = import <nixpkgs> { overlays = [(import ../../overlay.nix)]; };
inherit (pkgs.pkgsBuildBuild) run-liminix-vm;
inherit (pkgs.pkgsBuildBuild) mips-vm;
in pkgs.runCommand "check" {
nativeBuildInputs = with pkgs; [
expect socat
expect
mips-vm
socat
] ;
} ''
. ${../test-helpers.sh}
mkdir vm
${img}/run.sh --background ./vm
mips-vm --background ./vm ${img}/vmlinux ${img}/rootfs
expect ${./wait-for-wlan.expect} |tee output && mv output $out
''
-7
View File
@@ -1,7 +0,0 @@
{ ... }:
{
imports = [
./vanilla-configuration.nix
./modules/standard.nix
];
}