Recently one of my customers brought to my attention Nerves. It aims to simplify use of Elixir (functional language leveraging Erlang VM) in embedded systems. This system has couple interesting features that are worth of research and blog post.

First is booting directly to application which is running in BEAM (Erlang VM). Nerves project replace systemd process with programming language virtual machine running application code. Concept is very interesting and I wonder if someone tried to use that with other VMs ie. JVM.

Second Nerves seems to utilize dual image update procedure. In my opinion any development of modern embedded system should start with update system. Any design that you can to your system update arsenal will be useful.

Third, Nerves use Buildroot as build system, which will I’m familiar with. Using popular build systems means simplified support for huge set of platforms (at point of writing this article Buildroot have 142 config files).

Let’s start with documentation

If you don’t want to go through all installation steps and you use Debian testing, you can run:

Erlang

Checking exact Erlang version for non Erlang developers is trivial:

Elixir

Checking Elixir version:

Unfortunately Nerves Project requires at least 1.4.0, what can be solved by:

fwup

fwup have to be installed from deb package:

I don’t understand why Nerves Projects used fwup, when software like swupdate from Denx is available. I don’t see difference in feature set and would say that swupdate is more flexible and covers more use cases. It looks like Nerves Project is main user of fwup.

Maybe it would be worth to consider comparison of fwup and swupdate ?

nerves_bootstrap

hello_nerves for BeagleBone Black

Flashing to SD card

booting

It look that things work out of the box and Elixir started and D2 LED blinks continuously.

Nerves booting

It looks like developers configured Linux kernel bootargs used by U-Boot to run elrinit as init process. erlinit is relatively simple application that can parse configuration file and do some basic system initialization. Depending on needs this may be considered quite weird approach. Of course adding systemd is not best approach for all solutions. For sure having custom init binary remove need for complex init system and makes updates much smaller. Also this solution targets dedicated embedded systems that whole purpose is running Elixir application.

Using custom init binary also limit attack vector to small amount of code. In typical build from Buildroot or Yocto final image contain quite a lot of process run by default. Nerves limit that to one that is needed for very specific use case that can be fully handled by Elixir application. Of course still some hardware setup is needed. In that case only Linux kernel or Elixir application can be attacked.

As one of my associate mention this is very similar approach to Busybox although here we replace shell with Elixir interpreter, but idea is similar to have one application that is entry point to the system.

From performance perspective this is also good solution since there a no daemons working in background that consuming resources. Lack of additional processes means that all server type of work have to be written in Elixir.

It would be very interesting to see how this approach can work for other VMs and if there are real world use cases for that.

erlinit & erlexec

erlinit is MIT licensed /sbin/init replacement. In general it:

  • setup pseudo-filesystems like /dev, /proc and /sys
  • setup serial console
  • register signal hendlers (SIGPWR, SIGUSR1, SIGTERM, SIGUSR2)
  • forks into cleanup process and new that start erlexec

elrexec is mix of C++ and Erlang that aim to control OS processes from Erlang application.

Source code can be found on Github: erlinit and erlexec.

Note about building natively

Recently I’m huge fan of containers and way this technology can be utilized by embedded software developers. Installing all dependencies in your environment is painful and can cause problems if you do not pay attention. Containers give you ability to separate tools for each project. In that way you create one Dockerfile for whole development environment and then share it with your peers. I believe Nerves Project shall share containers to build system images instead of maintaining documentation explaining how to setup development for lot of various environments.

For example steps for Debian required more of jumping between pages and googling then it was worth since correct set of packages solve issue.

Summary

Do you plan to use Nerves in your next embedded systems project ? Maybe you struggle with adapting similar approach for different VM ? Feel free to share your ideas and issues in comments. If you think content valuable please share this help us in providing more content to our blog.