Devuan on N900
What follows is an account about how I managed to get Devuan running on a Nokia N900 (console only, no desktop environment for now).
Contents |
Linux kernel
I first cloned mainline (or rather stable) kernel:
git clone https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git
This creates a folder named linux-stable
in the present working directory, and populates it by git (hidden) files and kernel sources (obtained by checking out the master branch). I decided to work on the stable branch (linux-4.10.y at present) on a separate directory:
mkdir linux-4.10.8 (or whatever) cd linux-stable git --work-tree=../linux-4.10.8 checkout linux-4.10.y -- . cd ../linux-4.10.8
I used Pali’s rx51_defconfig
[1] as a configuration file:
curl -o arch/arm/configs https://raw.githubusercontent.com/pali/linux-n900/v4.6-rc1-n900/arch/arm/configs/rx51_defconfig
Now we need a cross-toolchain to compile the kernel. Let’s assume we are on an x86 machine running Devuan Jessie. Also, I assume we are root. There are two options: either the arm-none-eabi toolchain, or the arm-linux-gnueabihf one. The former is easier to install since it is available from
deb http://auto.mirror.devuan.org/merged/ jessie main
by
apt-get install gcc-arm-none-eabi
The latter is more complicated, but may be useful later on. It may be downloaded from emdebian.org. By following Debian’s wiki [2], we first create /etc/apt/sources.list.d/crosstools.list
containing:
deb http://emdebian.org/tools/debian/ jessie main
Then we install the archive key:
curl http://emdebian.org/tools/debian/emdebian-toolchain-archive.key | apt-key add -
At this point the installation goes like:
dpkg --add-architecture armhf apt-get update apt-get install crossbuild-essential-armhf
Now we may compile the kernel [3]. Let’s first cd back to the linux-4.10.8
directory. Then select the desired target architecture and cross-toolchain:
export ARCH=arm export CROSS_COMPILE=arm-none-eabi- (or arm-linux-gnueabihf-)
Prepare the kernel configuration:
make rx51_defconfig
At this point it is wise to hack a bit the kernel configuration by setting the two watchdogs (OMAP and TWL4030) to be included into the kernel itself and not separated as loadable modules [4]. This is done by calling
make menuconfig
and following the path Device Drivers -> Watchdog Timer Support, then setting the two watchdogs not as <M> but as <*>. Save and exit.
Next step is the actual build, which is triggered by:
make (add -j followed by a number N to enable N parallel build processes) zImage
At the end, the compressed kernel image should be available in the linux-4.10.8
directory at:
/arch/arm/boot/zImage
This is not usable yet - needs an appended Device Tree Blob. So, again from the linux-4.10.8
directory, issue:
make omap3-n900.dtb
and
cat arch/arm/boot/zImage arch/arm/boot/dts/omap3-n900.dtb > zImage
The resulting zImage should be bootable and stable. For further useful functions, such as battery charging and network connection, we also need the modules:
make (-jN) modules
These will be installed later, after having cross-debootstrapped the Devuan file system.
Devuan file system
For the following steps it is essential to be root on a Devuan system [5]. Let’s install some packages:
apt-get install binfmt-support qemu qemu-user-static debootstrap
From outside of the kernel directory, we create a novel directory for the N900 file system:
mkdir n900
Time to run debootstrap:
debootstrap --foreign --arch armhf jessie n900 http://packages.devuan.org
At the end, copy ‘qemu-arm-static’ to the n900 directory, chroot there (after setting the locale as C, in order to avoid lots of warnings) and conclude the debootstrap process:
cp /usr/bin/qemu-arm-static n900/usr/bin export LANG=C export LANGUAGE=C export LC_ALL=C chroot n900 cd debootstrap debootstrap --second-stage dpkg --configure -a exit
Time to install the kernel modules to the newly created file system:
cd linux-4.10.8 export INSTALL_MOD_PATH=/full/path/to/n900/dir make modules_install
At this point, we have a minimal system, with a few problems and many missing features. The first problem is related to the fact that we won’t use any initrd, but boot directly into the rootfs; this seems simpler, but when the system V init process starts, no runtime file system is mounted yet (we only have the root fs; /proc, /sys, /dev
and so on are missing). As a consequence, the loopback lo device may not be mounted, and udev (more precisely the net.agent) waits for it up to timeout, causing a 30 seconds delay at boot (which, by the way, precludes a complete boot if the watchdogs are in the modules).
Good news are that we don’t need udev: there won’t be hotplugged devices, and the udev’s functions may be easily performed in a different way. So let’s take rid of udev. cd
to the n900
directory. First, let’s setup etc/apt/sources.list
as:
# jessie deb http://auto.mirror.devuan.org/merged/ jessie main contrib non-free # jessie-security, previously known as 'volatile' deb http://auto.mirror.devuan.org/merged/ jessie-security main contrib non-free # jessie-updates, previously known as 'volatile' deb http://auto.mirror.devuan.org/merged/ jessie-updates main contrib non-free
Then, change etc/apt/preferences.d/avoid-systemd
to:
Package: systemd-sysv Pin: release o=Debian Pin-Priority: -1 Package: udev Pin: release o=Devuan Pin-Priority: -1
Now, in order to perform our customisation, we have to chroot again. To this aim, we first mount the /proc
file system of the host to the n900
directory, and tell the system to install packages without starting their associated services. So let’s create usr/sbin/policy-rc.d
with [6]:
#!/bin/sh exit 101
Then,
chmod +x usr/sbin/policy-rc.d mount -t proc /proc proc chroot .
Remove udev:
apt-get purge udev
(if suggested by the system, also apt-get autoremove
).
To supply for the missing udev at boot and mount the /dev
nodes anyway, we need to modify the /etc/init.d/mountkernfs.h
script (remember we are in the chroot jail, so the leading / is correct). Add the following lines:
# # Mount devtmpfs on /dev # domount "$MNTMODE" devtmpfs "" /dev devtmpfs "-omode=0755,nosuid"
at the end of the mount_filesystems
function (right before the closing curly bracket).
We conclude this digression on udev by updating and upgrading:
apt-get update apt-get upgrade
The second problem of our system is SELinux. It is probably not needed (and if I am not wrong it is disabled in the kernel); in any case, at boot the /sys/fs/selinux
node is not mounted, and the init process, calling a function from libselinux to check whether SELinux is enabled, tries anyway to mount the selinux
filesystem: being unable to do that, it complains “loudly.” I found two solutions to this “issue:” an easy workaround, and a modification of the init code.
The workaround consists in simply creating a /selinux
(empty) folder. In this way, the functions from libselinux, when they don’t find /sys/fs/selinux
, mount the selinux
fs at /selinux
(and don’t complain anymore). Besides this, I disabled SELinux in /etc/selinux/config
by changing the declaration of the SELINUX
variable to:
SELINUX=disabled
If one does not like the /selinux
workaround, it is possible to modify the init code (and disable SELinux in its config file as above). I think there is a bug here, since the code should not try to mount selinux in any case; however, the simplest thing to do is to get the source code for sysvinit and re-build it without declaring the WITH_SELINUX
variable: this cancels out the pieces of code which take care of SELinux. Here however we need the arm-linux-gnueabihf toolchain, due to a missing crypt library in the arm-none-eabi one.
So let’s exit the chroot jail and the n900
directory, and do:
apt-get source sysvinit cd sysvinit* (the actual name of the directory has the version appended) export CC=arm-linux-gnueabihf-gcc make
This should build the init code; I got a few warnings, but no errors. The new init binary is at src/init
, and should replace the sbin/init
in the n900
directory.
Third problem: adding a few packages. Again chroot n900
(with proc
mounted). I did what follows.
passwd (to set root password) adduser <user> (to create a std user) apt-get install locales apt-get install keyboard-configuration apt-get install console-setup
To set up the correct locale, just do:
dpkg-reconfigure locales
and follow the instructions.
To set up correctly the keyboard, modify /etc/default/keyboard
as follows:
… XKBMODEL=“nokiarx51” XKBLAYOUT=“<two letter country code>” …
and do:
dpkg-reconfigure console-setup
following the instructions. This, besides other things, runs ckbcomp to compile the XKB keyboard description to a keymap suitable for the console.
WARNING: ckbcomp reads /etc/default/keyboard
, and then files in /usr/share/X11/xkb/
. The first file to be read is rules/xorg
, which specifies other files to be read for the keyboard model and layout specified in /etc/default/keyboard
. Based on the rules, files are read in geometry/, keycodes/
and symbols/
. At present (and probably also in the future) ckbcomp does not read files in types/
: the types for modifier keys are hardcoded in ckbcomp itself. As a consequence, there is a particular issue: the version of ckbcomp included in Jessie does not know about PC_FN_LEVEL2
, a type which allows on some keyboard layouts (e.g. Italian and German) to switch from left/right to up/down arrows by pressing (and holding) the function (blue) key. This results in a warning, and the arrow switch is instead obtained by means of shift. To correct the behaviour, I installed console-setup version 1.164 (from Debian sid), or rather installed it on Debian and copied /usr/bin/ckbcomp
to the Devuan file system.
If one wants to customise the keyboard, the layout is defined in symbols/nokia_vndr/rx-51
; edit the file [7] and run again dpkg-reconfigure console-setup
.
In order to have a working power button for shutdown, we need:
apt-get install acpi-support-base
The way I will use to boot the system provides (sometimes…) a dark screen (no backlight). It is a good idea to prepare at this time a script to turn on the light: create /root/light
with
echo 200 > /sys/class/backlight/acx565akm/brightness
then chmod +x /root/light
and create /root/.bash_profile
with
PATH+=:/root
To enable battery charging, edit /etc/modules
adding:
bq27xxx_battery bq2415x_charger isp1704_charger
This tells the kernel to load the three needed modules.
Last thing: wireless networking. First we need the firmware (which is non-free):
apt-get install firmware-ti-connectivity
Then we need the kernel module: add
wl1251_spi
to /etc/modules
. At this point the wifi interface should be ready. In order to connect to my wlan, I also set up the wpa-psk protocol [8]. This requires:
apt-get install wpasupplicant
and create /etc/network/interfaces.d/wlan0
containing
auto wlan0 iface wlan0 inet dhcp wpa-ssid <myssid> wpa-psk <mypsk>
I got <mypsk>
from the Devuan host, by running (from outside the chroot):
wpa_passphrase <myssid>
and giving, at prompt, the corresponding passphrase. (Actually, I did wpa_passhprase <myssid> <mypassphrase> > /path/to/n900/etc/network/interfaces.d/wlan0
, and edited this file.)
I also added ssh support [9]:
apt-get install openssh-server
The file system should be quite ready for booting into console. Exit the chroot jail, unmount proc
and remove usr/sbin/policy-rc.d
.
Boot
Instead of flashing u-boot, I decided to test the system by:
- copying the n900 Devuan file system to sd card;
- uploading the kernel to memory and booting from there by using Nokia’s proprietary flasher and NOLO.
I created an ext3 partition on the sd card (ext3 is readable from Maemo, so one may change things on the new filesystem by booting into Maemo and mounting the sd card partition). I did it this way: connected the N900 to my host Devuan system by usb, turned it on and selected “Mass storage mode.” Novel nodes appear at /dev
(on the host), one for the /home
partition in the internal eMMC and one for the external sd card (with subnodes for the partitions). Let’s call sdb
the node related to the sd card. I did (from /dev
):
parted -a optimal sdb
Then used parted commands to resize the original FAT primary partition, created an extended partition, and a logical partition inside the extended one. Lastly,
partprobe sdb
to re-read the partition table. At this point, inside /dev
there should be sdb1
(primary), sdb2
(extended) and sdb5
(logical) nodes. Format sdb5
:
mkfs.ext3 sdb5
Now I created a directory /media/devuan
, and mounted sdb5
there. Then cd /path/to/n900
(the new Devuan file system) and:
rsync -avh * /media/devuan
This copies the new Devuan file system to the new ext3 partition on the sd card.
My main computer is a Mac, so I downloaded Nokia’s proprietary flasher [10] (I have also a binary for 0xFFFF, built from the sources with a few modifications, but it is prone to hanging the whole system) and installed it (actually, since newer macs have some restrictions due to the System Integrity Protection, I had to unpack the files and copy them manually to proper positions. But this is another story). Then transferred the kernel zImage from the Devuan host to the Mac.
This is the way I boot Devuan on the N900: turn off the device, hold “u”, connect to Mac by usb cable, wait for the usb symbol to appear on the top right corner (usually with backlight off) and on the Mac, from the directory containing the kernel zImage, issue:
flasher-3.5 -k zImage -l flasher-3.5 -b”rootwait root=/dev/mmcblk0p5 rw”
or, in a single line,
flasher-3.5 -k zImage -l -b”rootwait root=/dev/mmcblk0p5 rw”
Explanation: the first command uploads the kernel to ram. The second tells NOLO to boot it and pass to the kernel the specified command line. There, rootwait
tells the kernel to wait for the root file system to be mounted before passing it the control, the root
parameter tells the location of the root fs ( mmcblk0
is the sd card, in contrast to Maemo, where it is mmcblk1
; p5
is the partition where the Devuan fs is located) and the rw
flag tells to mount the root fs as read and write.
This is what happens: the usb symbol on the N900 screen disappears, after about one second the Nokia logo fades out, and after a while messages appear on the screen reporting a regular kernel boot, ending in a login prompt. One should be able to login as root with the password previously specified, and then issue “light” to run the script which turns on the screen backlight. Also, the device should appear on the wlan with a dynamically assigned IP address; I can issue (on the Mac, as standard user - with the same name as the standard user previously defined for the N900 Devuan file system):
ssh <N900 IP>
enter the standard user’s password, get a remote shell, issue “su”, enter the root password, and enjoy the new system from my Mac.
There are indeed a few things to tune, and I still miss a desktop environment.
Footnotes
- ↑ https://github.com/pali/linux-n900/blob/v4.6-rc1-n900/arch/arm/configs/rx51_defconfig
- ↑ https://wiki.debian.org/CrossToolchains
- ↑ http://elinux.org/N900
- ↑ Actually the system may boot also with the watchdogs in the modules, but in this case it is very unstable: to avoid reboot, the watchdogs need to be loaded in a few seconds, which may not be possible in some cases (namely, I had a problem due to udev waiting for the loopback lo device to be mounted, which did not happen due to the lack of an initrd).
- ↑ https://wiki.debian.org/EmDebian/CrossDebootstrap
- ↑ https://serverfault.com/questions/567474/how-can-i-install-packages-without-starting-their-associated-services
- ↑ https://wiki.maemo.org/Remapping_keyboard
- ↑ https://wiki.debian.org/WiFi/HowToUse
- ↑ https://wiki.debian.org/SSH
- ↑ It may be found at http://web.archive.org/web/20131117073524/http://skeiron.org/tablets-dev/maemo_dev_env_downloads/.