liminix

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

user.rst (11468B)


      1 User Manual
      2 ###########
      3 
      4 This manual is an early work in progress, not least because Liminix is
      5 not yet really ready for users who are not also developers. Your
      6 feedback to improve it is very welcome.
      7 
      8 Installation
      9 ************
     10 
     11 The Liminix installation process is not quite like installing NixOS on
     12 a real computer, but some NixOS experience will nevertheless be
     13 helpful in understanding it.  The steps are as follows:
     14 
     15 * Decide whether you want the device to be updatable in-place (there
     16   are advantages and disadvantages), or if you are happy to generate
     17   and flash a new image whenever changes are required.
     18 
     19 * Create a :file:`configuration.nix` describing the system you want
     20 
     21 * Build an image
     22 
     23 * Flash it to the device
     24 
     25 Supported devices
     26 =================
     27 
     28 For a list of devices that Liminix (present or previous versions)
     29 has run on, refer to `devices/ in the source repo <https://gti.telent.net/dan/liminix/src/branch/main/devices>`_. For devices that _currently_ build,
     30 cross-reference it with `the CI status <https://build.liminix.org/jobset/liminix/build#tabs-jobs>`_. Everything that builds is (usually) expected
     31 to run, so if you end up with an image that builds but doesn't
     32 boot, please report it as a bug.
     33 
     34 As of June 2023 the device list is a little thin. Adding devices based
     35 on the Atheros or Mediatek (Ralink) platform should be quite
     36 straightforward if you have some C/Linux kernel experience and are
     37 prepared to open it up and attach serial wires: please refer to the
     38 Developer Manual.
     39 
     40 
     41 Choosing a flavour (read-only or updatable)
     42 ===========================================
     43 
     44 Liminix installations come in two "flavours"- read-only or in-place
     45 updatable:
     46 
     47 * a read-only installation can't be updated once it is flashed to your
     48   device, and so must be reinstalled in its entirety every time you
     49   want to change it.  It uses the ``squashfs`` filesystem which has
     50   very good compression ratios and so you can pack quite a lot of
     51   useful stuff onto your device.  This is good if you don't expect
     52   to change it often.
     53 
     54 * an updatable installation has a writable filesystem so that you can
     55   update configuration, upgrade packages and install new packages over
     56   the network after installation. This uses the `jffs2
     57   <http://www.linux-mtd.infradead.org/doc/jffs2.html>`_ filesystem:
     58   although it does compress the data, the need to support writes means
     59   that it can't pack quite as small as squashfs, so you will not have
     60   as much space to play with.
     61 
     62 Updatability caveats
     63 ~~~~~~~~~~~~~~~~~~~~
     64 
     65 At the time of writing this manual the read-only squashfs support is
     66 much more mature. Consider also that it may not be possible to perform
     67 "larger" updates in-place even if you do opt for updatability.  If you
     68 have (for example) an 11MB system on a 16MB device, you won't be able
     69 to do an in-place update of something fundamental like the C library
     70 (libc), as this will temporarily require 22MB to install all the
     71 packages needing the new library before the packages using the old
     72 library can be removed. A writable system will be more useful for
     73 smaller updates such as installing a new package (perhaps you
     74 temporarily need tcpdump to diagnose a network problem) or for
     75 changing configuration files.
     76 
     77 Note also that the kernel is not part of the filesystem so cannot be
     78 updated this way. Kernel changes require a full reflash.
     79 
     80 
     81 
     82 Creating configuration.nix
     83 ==========================
     84 
     85 
     86 You need to create a :file:`configuration.nix` that describes your device
     87 and the services that you want to run on it. Start by copying
     88 :file:`vanilla-configuration.nix` and adjusting it, or look in the `examples`
     89 directory for some pre-written configurations.
     90 
     91 :file:`configuration.nix` conventionally describes the packages, services,
     92 user accounts etc of the device. It does not describe the hardware
     93 itself, which is specified separately in the build command (as you
     94 will see below).
     95 
     96 Your configuration may include modules: it probably *should*
     97 include the ``standard`` module unless you understand what it
     98 does and what happens if you leave it out.
     99 
    100 .. code-block:: nix
    101 
    102     imports = [
    103       ./modules/standard.nix
    104     ]
    105     configuration.rootfsType = "jffs2"; # or "squashfs"
    106 
    107 
    108 
    109 Building
    110 ========
    111 
    112 Build Liminix using the :file:`default.nix` in the project toplevel
    113 directory, passing it arguments for configuration and hardware. For
    114 example:
    115 
    116 .. code-block:: console
    117 
    118     nix-build -I liminix-config=./tests/smoke/configuration.nix \
    119      --arg device "import ./devices/qemu" -A outputs.default
    120 
    121 In this command ``<liminix-config>`` points to your
    122 :file:`configuration.nix`, ``device`` is the file for your hardware device
    123 definition, and ``outputs.default`` will generate some kind of
    124 Liminix image output appropriate to that device.
    125 
    126 For the qemu device in this example, ``outputs.default`` is an alias
    127 for ``outputs.vmbuild``, which creates a directory containing a
    128 squashfs root image and a kernel. You can use the :command:`mips-vm` command to
    129 run this.
    130 
    131 For the currently supported hardware devices, ``outputs.default``
    132 creates a directory containing a file called ``firmware.bin``.  This
    133 is a raw image file that can be written directly to the firmware flash
    134 partition.
    135 
    136 
    137 Flashing
    138 ========
    139 
    140 
    141 Flashing from the boot monitor
    142 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    143 
    144 If you are prepared to open the device and have a TTL serial adaptor
    145 of some kind to connect it to, you can probably flash it using U-Boot.
    146 This is quite hardware-specific, and sometimes involves soldering:
    147 please refer to the Developer Manual.
    148 
    149 
    150 Flashing from an existing Liminix system with :command:`flashcp`
    151 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    152 
    153 The flash procedure from an existing Liminix-system is two-step.
    154 First we reboot the device (using "kexec") into an "ephemeral"
    155 RAM-based version of the new configuration, then when we're happy it
    156 works we can flash the image - and if it doesn't work we can reboot
    157 the device again and it will boot from the old image.
    158 
    159 
    160 
    161 Building the RAM-based image
    162 ............................
    163 
    164 To create the ephemeral image, build ``outputs.kexecboot`` instead of
    165 ``outputs.default``.  This generates a directory containing the root
    166 filesystem image and kernel, along with an executable called `kexec`
    167 and a `boot.sh` script that runs it with appropriate arguments.
    168 
    169 For example
    170 
    171 .. code-block:: console
    172 
    173    nix-build --show-trace -I liminix-config=./examples/arhcive.nix \
    174      --arg device "import ./devices/gl-ar750"
    175      -A outputs.kexecboot && \
    176      (tar chf - result | ssh root@the-device tar -C /run -xvf -)
    177 
    178 and then login to the device and run
    179 
    180 .. code-block:: console
    181 
    182    cd /run/result
    183    sh ./boot.sh .
    184 
    185 
    186 This will load the new kernel and map the root filesystem into a RAM
    187 disk, then start executing the new kernel. *This is effectively a
    188 reboot - be sure to close all open files and finish anything else
    189 you were doing first.*
    190 
    191 If the new system crashes or is rebooted, then the device will revert
    192 to the old configuration it finds in flash.
    193 
    194 
    195 Building the second (permanent) image
    196 .....................................
    197 
    198 While running in the kexecboot system, you can copy the permanent
    199 image to the device with :command:`ssh`
    200 
    201 .. code-block:: console
    202 
    203    build-machine$ tar chf - result/firmware.bin | \
    204     ssh root@the-device tar -C /run -xvf -
    205 
    206 Next you need to connect to the device and locate the "firmware"
    207 partition, which you can do with a combination of :command:`dmesg`
    208 output and the contents of :file:`/proc/mtd`
    209 
    210 .. code-block:: console
    211 
    212    <5>[    0.469841] Creating 4 MTD partitions on "spi0.0":
    213    <5>[    0.474837] 0x000000000000-0x000000040000 : "u-boot"
    214    <5>[    0.480796] 0x000000040000-0x000000050000 : "u-boot-env"
    215    <5>[    0.487056] 0x000000050000-0x000000060000 : "art"
    216    <5>[    0.492753] 0x000000060000-0x000001000000 : "firmware"
    217 
    218    # cat /proc/mtd
    219    dev:    size   erasesize  name
    220    mtd0: 00040000 00001000 "u-boot"
    221    mtd1: 00010000 00001000 "u-boot-env"
    222    mtd2: 00010000 00001000 "art"
    223    mtd3: 00fa0000 00001000 "firmware"
    224    mtd4: 002a0000 00001000 "kernel"
    225    mtd5: 00d00000 00001000 "rootfs"
    226 
    227 Now run (in this example)
    228 
    229 .. code-block:: console
    230 
    231    flashcp -v firmware.bin /dev/mtd3
    232 
    233 
    234 "I know my new image is good, can I skip the intemediate step?"
    235 ```````````````````````````````````````````````````````````````
    236 
    237 In addition to giving you a chance to see if the new image works, this
    238 two-step process ensures that you're not copying the new image over
    239 the top of the active root filesystem. It might work, or it might
    240 crash in surprising ways.
    241 
    242 
    243 
    244 Flashing from OpenWrt (not currently advised!)
    245 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    246 
    247 .. CAUTION:: At your own risk! This will (at least in some
    248              circumstances) lead to bricking the device: we think this
    249              flash method is currently incompatible with use of a
    250              writeable (jffs2) filesystem.
    251 
    252 If your device is running OpenWrt then it probably has the
    253 :command:`mtd` command installed. After transferring the image onto the
    254 device using e.g. :command:`ssh`,  you can run it as follows:
    255 
    256 .. code-block:: console
    257 
    258    mtd -r write /tmp/firmware.bin firmware
    259 
    260 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.
    261 
    262 
    263 Updating an installed system (JFFS2)
    264 ************************************
    265 
    266 Adding packages
    267 ===============
    268 
    269 
    270 If your device is running a JFFS2 root filesystem, you can build
    271 extra packages for it on your build system and copy them to the
    272 device: any package in Nixpkgs or in the Liminix overlay is available
    273 with the ``pkgs`` prefix:
    274 
    275 .. code-block:: console
    276 
    277     nix-build -I liminix-config=./my-configuration.nix \
    278      --arg device "import ./devices/mydevice" -A pkgs.tcpdump
    279 
    280     nix-shell -p min-copy-closure root@the-device result/
    281 
    282 Note that this only copies the package to the device: it doesn't update
    283 any profile to add it to ``$PATH``
    284 
    285 
    286 Rebuilding the system
    287 =====================
    288 
    289 :command:`liminix-rebuild` is the Liminix analogue of :command:`nixos-rebuild`, although its operation is a bit different because it expects to run on a build machine and then copy to the host device. Run it with the same ``liminix-config`` and ``device`` parameters as you would run :command:`nix-build`, and it will build any new/changed packages and then copy them to the device using SSH. For example:
    290 
    291 .. code-block:: console
    292 
    293      liminix-rebuild root@the-device  -I liminix-config=./examples/rotuer.nix --arg device "import ./devices/gl-ar750"
    294 
    295 This will
    296 
    297 * build anything that needs building
    298 * copy new or changed packages to the device
    299 * reboot the device
    300 
    301 It doesn't delete old packages automatically: to do that run
    302 :command:`min-collect-garbage`, which will delete any packages not in
    303 the current system closure. Note that Liminix does not have the NixOS
    304 concept of environments or generations, and there is no way back from
    305 this except for building the previous configuration again.
    306 
    307 
    308 
    309 Caveats
    310 ~~~~~~~
    311 
    312 * it needs there to be enough free space on the device for all the new
    313   packages in addition to all the packages already on it - which may be
    314   a problem if a lot of things have changed (e.g. a new version of
    315   nixpkgs).
    316 
    317 * it cannot upgrade the kernel, only userland
    318 
    319 Configuration options
    320 *********************
    321 
    322 .. include:: modules.rst