Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b306031b7c | |||
| c948a9b49a | |||
| 56d679416f | |||
| f38270a365 | |||
| 8f4d5e51f4 | |||
| 2841952245 | |||
| 12b9feb8ee | |||
| b3a7a2246d | |||
| 6674344021 | |||
| c81ee62374 | |||
| dd0b1734c1 | |||
| 0a2588013a |
@@ -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
|
||||
|
||||
@@ -35,7 +35,7 @@ let
|
||||
src = ./doc;
|
||||
buildPhase = ''
|
||||
cat ${(import ./doc/extract-options.nix).doc} > options.json
|
||||
cat options.json | fennel --correlate parse-options.fnl > modules.rst
|
||||
cat options.json | fennel --correlate parse-options.fnl > modules-generated.rst
|
||||
make html
|
||||
'';
|
||||
installPhase = ''
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
# 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, ... }: {
|
||||
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 = {
|
||||
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";
|
||||
PCI = "y";
|
||||
VIRTIO_PCI = "y";
|
||||
BLOCK = "y";
|
||||
VIRTIO_BLK = "y";
|
||||
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";
|
||||
};
|
||||
};
|
||||
hardware =
|
||||
let
|
||||
mac80211 = pkgs.mac80211.override {
|
||||
drivers = ["mac80211_hwsim"];
|
||||
klibBuild = config.system.outputs.kernel.modulesupport;
|
||||
};
|
||||
in {
|
||||
defaultOutput = "vmroot";
|
||||
loadAddress = "0x0";
|
||||
entryPoint = "0x0";
|
||||
rootDevice = "/dev/mtd1";
|
||||
|
||||
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 ];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
};
|
||||
}
|
||||
+25
-15
@@ -12,8 +12,8 @@ Flashing and updating
|
||||
|
||||
|
||||
|
||||
Flashing from an existing Liminix system with :command:`flashcp`
|
||||
================================================================
|
||||
Flashing from Liminix
|
||||
=====================
|
||||
|
||||
The flash procedure from an existing Liminix-system has two steps.
|
||||
First we reboot the device (using "kexec") into an "ephemeral"
|
||||
@@ -34,7 +34,7 @@ For example
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
nix-build --show-trace -I liminix-config=./examples/arhcive.nix \
|
||||
nix-build -I liminix-config=./examples/arhcive.nix \
|
||||
--arg device "import ./devices/gl-ar750"
|
||||
-A outputs.kexecboot && \
|
||||
(tar chf - result | ssh root@the-device tar -C /run -xvf -)
|
||||
@@ -59,11 +59,16 @@ to the old configuration it finds in flash.
|
||||
Building the second (permanent) image
|
||||
-------------------------------------
|
||||
|
||||
While running in the kexecboot system, you can copy the permanent
|
||||
image to the device with :command:`ssh`
|
||||
While running in the kexecboot system, you can build the permanent
|
||||
image and copy it to the device with :command:`ssh`
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
build-machine$ nix-build -I liminix-config=./examples/arhcive.nix \
|
||||
--arg device "import ./devices/gl-ar750"
|
||||
-A outputs.default && \
|
||||
(tar chf - result | ssh root@the-device tar -C /run -xvf -)
|
||||
|
||||
build-machine$ tar chf - result/firmware.bin | \
|
||||
ssh root@the-device tar -C /run -xvf -
|
||||
|
||||
@@ -109,18 +114,20 @@ Flashing from the boot monitor
|
||||
==============================
|
||||
|
||||
If you are prepared to open the device and have a TTL serial adaptor
|
||||
of some kind to connect it to, you can probably flash it using U-Boot.
|
||||
This is quite hardware-specific, and sometimes involves soldering:
|
||||
please refer to the Developer Manual.
|
||||
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 the :ref:`development manual <tftp server>`.
|
||||
|
||||
|
||||
Flashing from OpenWrt (not currently advised!)
|
||||
==============================================
|
||||
Flashing from OpenWrt
|
||||
=====================
|
||||
|
||||
.. CAUTION:: At your own risk! This will (at least in some
|
||||
circumstances) lead to bricking the device: we think this
|
||||
flash method is currently incompatible with use of a
|
||||
writeable (jffs2) filesystem.
|
||||
.. CAUTION:: Untested! A previous version of these instructions
|
||||
(without the -e flag) led to bricking the device
|
||||
when flashing a jffs2 image. If you are reading
|
||||
this message, nobody has yet reported on whether the
|
||||
new instructions are any better.
|
||||
|
||||
If your device is running OpenWrt then it probably has the
|
||||
:command:`mtd` command installed. After transferring the image onto the
|
||||
@@ -128,8 +135,11 @@ device using e.g. :command:`ssh`, you can run it as follows:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
mtd -r write /tmp/firmware.bin firmware
|
||||
mtd -e -r write /tmp/firmware.bin firmware
|
||||
|
||||
The options to this command are for "erase before writing" and "reboot
|
||||
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)
|
||||
|
||||
+106
-3
@@ -150,7 +150,110 @@ meaning that it won't be started until that other service is up.
|
||||
Module implementation
|
||||
*********************
|
||||
|
||||
TODO: make your own modules
|
||||
Modules in Liminix conventionally live in
|
||||
:file:`modules/somename/default.nix`. If you want or need to
|
||||
write your own, you may wish to refer to the
|
||||
examples there in conjunction with reading this section.
|
||||
|
||||
* how a module exposes services
|
||||
* defining types
|
||||
A module is a function that accepts ``{lib, pkgs, config, ... }`` and
|
||||
returns an attrset with keys ``imports, options config``.
|
||||
|
||||
* ``imports`` is a list of paths to the other modules required by this one
|
||||
|
||||
* ``options`` is a nested set of option declarations
|
||||
|
||||
* ``config`` is a nested set of option definitions
|
||||
|
||||
The NixOS manual section `Writing NixOS Modules
|
||||
<https://nixos.org/manual/nixos/stable/#sec-writing-modules>`_ is a
|
||||
quite comprehensive reference to writing NixOS modules, which is also
|
||||
mostly applicable to Liminix except that it doesn't cover
|
||||
service templates.
|
||||
|
||||
Service templates
|
||||
=================
|
||||
|
||||
To expose a service template in a module, it needs the following:
|
||||
|
||||
* an option declaration for ``system.service.myservicename`` with the
|
||||
type of ``liminix.lib.types.serviceDefn``
|
||||
|
||||
.. code-block:: nix
|
||||
|
||||
options = {
|
||||
system.service.cowsay = mkOption {
|
||||
type = liminix.lib.types.serviceDefn;
|
||||
};
|
||||
};
|
||||
|
||||
* an option definition for the same key, which specifies where to
|
||||
import the service template from (often :file:`./service.nix`)
|
||||
and the types of its parameters.
|
||||
|
||||
.. code-block:: nix
|
||||
|
||||
config.system.service.cowsay = liminix.callService ./service.nix {
|
||||
address = mkOption {
|
||||
type = types.str;
|
||||
default = "0.0.0.0";
|
||||
description = "Listen on specified address";
|
||||
example = "127.0.0.1";
|
||||
};
|
||||
port = mkOption {
|
||||
type = types.port;
|
||||
default = 22;
|
||||
description = "Listen on specified TCP port";
|
||||
};
|
||||
breed = mkOption {
|
||||
type = types.str;
|
||||
default = "British Friesian"
|
||||
description = "Breed of the cow";
|
||||
};
|
||||
};
|
||||
|
||||
Then you need to provide the service template itself, probably in
|
||||
:file:`./service.nix`:
|
||||
|
||||
.. code-block:: nix
|
||||
|
||||
{
|
||||
# any nixpkgs package can be named here
|
||||
liminix
|
||||
, cowsayd
|
||||
, serviceFns
|
||||
, lib
|
||||
}:
|
||||
# these are the parameters declared in the callService invocation
|
||||
{ address, port, breed} :
|
||||
let
|
||||
inherit (liminix.services) longrun;
|
||||
inherit (lib.strings) escapeShellArg;
|
||||
in longrun {
|
||||
name = "cowsayd";
|
||||
run = "${cowsayd}/bin/cowsayd --address ${address} --port ${builtins.toString port} --breed ${escapeShellArg breed}";
|
||||
}
|
||||
|
||||
.. tip::
|
||||
|
||||
Not relevant to module-based services specifically, but a common
|
||||
gotcha when specifiying services is forgetting to transform "rich"
|
||||
parameter values into text when composing a command for the shell
|
||||
to execute. Note here that the port number, an integer, is
|
||||
stringified with ``toString``, and the name of the breed,
|
||||
which may contain spaces, is
|
||||
escaped with ``escapeShellArg``
|
||||
|
||||
Types
|
||||
=====
|
||||
|
||||
All of the NixOS module types are available in Liminix. These
|
||||
Liminix-specific types also exist in ``pkgs.liminix.lib.types``:
|
||||
|
||||
* ``service``: an s6-rc service
|
||||
* ``interface``: an s6-rc service which specifies a network
|
||||
interface
|
||||
* ``serviceDefn``: a service "template" definition
|
||||
|
||||
In the future it is likely that we will extend this to include other
|
||||
useful types in the networking domain: for example; IP address,
|
||||
network prefix or netmask, protocol family and others as we find them.
|
||||
|
||||
@@ -87,6 +87,8 @@ time with configurations for RP-PPPoE and/or Accel PPP.`
|
||||
Hardware devices
|
||||
****************
|
||||
|
||||
.. _tftp server:
|
||||
|
||||
How you get your image onto hardware will vary according to the
|
||||
device, but is likely to involve taking it apart to add wires to
|
||||
serial console pads/headers, then using U-Boot to fetch images over
|
||||
|
||||
@@ -10,6 +10,7 @@ Liminix
|
||||
configuration
|
||||
admin
|
||||
development
|
||||
modules
|
||||
|
||||
|
||||
Indices and tables
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
Module options
|
||||
##############
|
||||
|
||||
.. include:: modules-generated.rst
|
||||
+14
-16
@@ -1,8 +1,8 @@
|
||||
Getting Started
|
||||
###############
|
||||
Tutorial
|
||||
########
|
||||
|
||||
Liminix is very configurable, which can make it initially quite
|
||||
daunting, especially if you're learning Nix or Linux or networking
|
||||
daunting - especially if you're learning Nix or Linux or networking
|
||||
concepts at the same time. In this section we build some "worked
|
||||
example" Liminix images to introduce the concepts. If you follow the
|
||||
examples exactly, they should work. If you change things as you go
|
||||
@@ -10,16 +10,6 @@ along, they may work differently or not at all, but the experience
|
||||
should be educational either way.
|
||||
|
||||
|
||||
.. warning:: The first example we will look at runs under emulation,
|
||||
so there is no danger of bricking your hardware
|
||||
device. For the second example you may (if you have
|
||||
appropriate hardware and choose to do so) flash the
|
||||
configuration onto an actual router. There is always a
|
||||
risk of rendering the device unbootable when you do this,
|
||||
and various ways to recover depending on what went wrong.
|
||||
We'll write more about that at the appropriate point
|
||||
|
||||
|
||||
Requirements
|
||||
************
|
||||
|
||||
@@ -135,9 +125,17 @@ 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
|
||||
has been chosen for the purpose because it's cheap and easy to
|
||||
unbrick. Using some other Liminix-supported MIPS hardware device also
|
||||
*ought* to work here, but you accept the slightly greater bricking
|
||||
risk if it doesn't.
|
||||
unbrick if necessary
|
||||
|
||||
.. warning:: There is always a risk of rendering your device
|
||||
unbootable by flashing it with an image that doesn't
|
||||
work. The GL-MT300A has a builtin "debrick" procedure in
|
||||
the boot monitor and is also comparatively simple to
|
||||
attach serial cables to (soldering not required), so it
|
||||
is lower-risk than some devices. Using some other
|
||||
Liminix-supported MIPS hardware device also *ought* to
|
||||
work here, but you accept the slightly greater bricking
|
||||
risk if it doesn't.
|
||||
|
||||
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>`_
|
||||
|
||||
+2
-1
@@ -6,6 +6,7 @@
|
||||
} :
|
||||
let
|
||||
objcopy = "${stdenv.cc.bintools.targetPrefix}objcopy";
|
||||
arch = "arm64";
|
||||
in {
|
||||
kernel
|
||||
, commandLine
|
||||
@@ -40,7 +41,7 @@ stdenv.mkDerivation {
|
||||
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 mips -O linux -T kernel -C lzma -a ${loadAddress} -e ${entryPoint} -n 'MIPS Liminix Linux ${extraName}' -d vmlinux.bin.lzma kernel.uimage
|
||||
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
|
||||
|
||||
+3
-3
@@ -56,9 +56,9 @@ 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";
|
||||
# MIPS_BOOTLOADER_CMDLINE_REQUIRE_COOKIE = "y";
|
||||
# MIPS_BOOTLOADER_CMDLINE_COOKIE = "\"liminix\"";
|
||||
# MIPS_CMDLINE_DTB_EXTEND = "y";
|
||||
|
||||
# basic networking protocols
|
||||
NET = "y";
|
||||
|
||||
+2
-1
@@ -76,11 +76,12 @@ in
|
||||
inherit dtb;
|
||||
};
|
||||
# could use trivial-builders.linkFarmFromDrvs here?
|
||||
vmroot = pkgs.runCommand "qemu" {} ''
|
||||
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
|
||||
'';
|
||||
|
||||
@@ -28,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 = "mips"; # kernel uses "mips" here for both mips and mipsel
|
||||
ARCH = "arm64";
|
||||
KBUILD_BUILD_HOST = "liminix.builder";
|
||||
|
||||
dontStrip = true;
|
||||
@@ -47,7 +47,7 @@ stdenv.mkDerivation rec {
|
||||
];
|
||||
|
||||
patches = [
|
||||
./cmdline-cookie.patch
|
||||
# ./cmdline-cookie.patch
|
||||
];
|
||||
|
||||
# this is here to work around what I think is a bug in nixpkgs
|
||||
|
||||
@@ -42,10 +42,13 @@ fi
|
||||
|
||||
INIT=${INIT-/bin/init}
|
||||
echo $QEMU_OPTIONS
|
||||
qemu-system-mips \
|
||||
-M malta -m 256 \
|
||||
|
||||
qemu-system-aarch64 \
|
||||
-M virt -m 512 \
|
||||
-echr 16 \
|
||||
-append "liminix default console=ttyS0,38400n8 panic=10 oops=panic init=$INIT loglevel=8 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 \
|
||||
|
||||
Reference in New Issue
Block a user