1
0
forked from dan/liminix

Compare commits

...

12 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
dan 12b9feb8ee using openwrt mtd command, advide erase before writing 2023-09-18 10:59:55 +01:00
dan b3a7a2246d tutorial: move the warning nearer to the decision point 2023-09-17 21:53:15 +01:00
dan 6674344021 don't end chapter with ellipsis 2023-09-17 21:47:09 +01:00
dan c81ee62374 doc: proofread admin section, add link to TFTP 2023-09-17 21:44:32 +01:00
dan dd0b1734c1 how to write a module 2023-09-17 21:32:22 +01:00
dan 0a2588013a include generated module options 2023-09-17 17:47:04 +01:00
15 changed files with 258 additions and 46 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
+1 -1
View File
@@ -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 = ''
+75
View File
@@ -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
View File
@@ -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
View File
@@ -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.
+2
View File
@@ -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
+1
View File
@@ -10,6 +10,7 @@ Liminix
configuration
admin
development
modules
Indices and tables
+4
View File
@@ -0,0 +1,4 @@
Module options
##############
.. include:: modules-generated.rst
+14 -16
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
'';
+2 -2
View File
@@ -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
+6 -3
View File
@@ -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 \
+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;
});