Installing NetBSD on woefully underpowered hardware
It’s no secret I have a knack for weird and generally useless computing devices. Today, I’ll dive into the wonderful world of NetBSD, and how I installed the most ported OS of all time on those woefully underpowered gizmos. Oh, right, happy 2024!
Raspberry Pi 1B
Story time: in my first year of high school (12 years ago!), I came across a magazine describing the Raspberry Pi and everything you could do with one. Not long after, I found an used Raspberry Pi 1B on eBay and promptly bought it. That, along with a Sun Fire V100 1U server I got from a fellow collector, was my first foray into Unix and Linux, which eventually led me to pursue a career in IT.
It’s been a long while since I last used this Pi, which is astonishingly slow by today’s standards! To circumvent the problem, i planned to run RISC OS on it, which is a simple cooperative multitasking OS that makes it feel fast. I like weird embedded OSes, but what I despise is the absurd business practices that revolve around it. The authors of RISC OS managed to open-source the OS code, but put the toolchain behind a paywall.
That ended my brief foray into RISC OS, sadly. I would’ve loved to learn more about it but it wasn’t meant to be. Maybe one day the toolkit will be released for free, and I’ll go back to it.
Since I needed another lightweight OS, I turned to NetBSD. Here’s how it went!
Preparing the Pi
Disabling overscan
If you have black bars around your screen on the Raspberry Pi, just add disable_overscan=1
to /boot/config.txt
.
echo "disable_overscan=1" >> /boot/config.txt
Writing NetBSD to an SD card
Unlike on x86 systems, OSes for the Raspberry Pi come preinstalled in SD card images. Get the appropriate image for your Pi and dd
it to an SD card. The system will resize the rootfs automatically based on the card’s size when you boot for the first time.
Configuring the System
The first time you boot the system from the SD card, nothing will work properly. We need to configure the system in order to use it.
Changing the hostname
To change the hostname, edit /etc/rc.conf
and :s/rpi/whatever
. If you want to change it without rebooting, you can use the hostname whatever
command. You can also change the /etc/motd
to your liking.
Changing the Timezone
# unlink /etc/localtime
# ln -s /usr/share/zoneinfo/Europe/Rome /etc/localtime
Adding an user
To add an user, you can use useradd
. Note that there won’t be any /home
directory initially, it will be created by useradd
when you add your first user.
useradd -g users -G wheel -m username
passwd username
Setting up pkgin
Set-up pkgsrc
to deliver binary packages via pkgin
. The CDN seems to be broken at the moment, so I used the closest EU mirror.
# PKG_PATH="http://ftp.fr.NetBSD.org/pub/pkgsrc/packages"
# PKG_PATH="$PKG_PATH/$(uname)/$(uname -p)/$(uname -r | cut -d _ -f 1)/All"
# export PKG_PATH
# pkg_add pkgin
pkg_add: Warning: package `pkgin-23.8.1' was built for a platform:
pkg_add: NetBSD/earmv6hf 9.0 (pkg) vs. NetBSD/earmv6hf 9.3_STABLE (this host)
pkg_add: Warning: package `pkg_install-20211115' was built for a platform:
pkg_add: NetBSD/earmv6hf 9.0 (pkg) vs. NetBSD/earmv6hf 9.3_STABLE (this host)
pkgin-23.8.1: copying /usr/pkg/share/examples/pkgin/repositories.conf.example to /usr/pkg/etc/pkgin/repositories.conf
# echo $PKG_PATH >> /usr/pkg/etc/pkgin/repositories.conf
Then comment the line above what you added.
Using pkgin
pkgin
is a convenient frontend for NetBSD’s package system. It does what APT does for Debian, essentially. pkgin
is very easy to use, but it won’t spoil you like DNF does.
You can use pkgin
to update the system as follows:
# pkgin update && pkgin upgrade
cleaning database from https://cdn.netbsd.org/pub/pkgsrc/packages/NetBSD/earmv6hf/9.0/All entries...
reading local summary...
processing local summary...
processing remote summary (http://ftp.fr.NetBSD.org/pub/pkgsrc/packages/NetBSD/earmv6hf/9.3/All)...
pkg_summary.bz2 100% 3169KB 19.1KB/s 02:46
calculating dependencies...done.
nothing to do.
You can also install new packages:
# pkgin in git-base doas vim
calculating dependencies...done.
11 packages to install:
curl-8.4.0 doas-6.3p2nb1 git-base-2.42.0 libidn2-2.3.4 libunistring-1.1
libxml2-2.10.4nb2 nghttp2-1.56.0 pcre2-10.42 vim-9.0.2122 vim-share-9.0.2122
xmlcatmgr-2.2nb1
0 to remove, 0 to refresh, 0 to upgrade, 11 to install
36M to download, 97M of additional disk space will be used
proceed ? [Y/n] Y
[1/11] curl-8.4.0.tgz 100% 1369KB 1.3MB/s 00:01
[2/11] doas-6.3p2nb1.tgz 100% 22KB 21.9KB/s 00:00
[3/11] git-base-2.42.0.tgz 100% 20MB 2.0MB/s 00:10
[4/11] libidn2-2.3.4.tgz 100% 313KB 313.3KB/s 00:00
[5/11] libunistring-1.1.tgz 100% 1630KB 815.0KB/s 00:02
[6/11] libxml2-2.10.4nb2.tgz 100% 1814KB 906.9KB/s 00:02
[7/11] nghttp2-1.56.0.tgz 100% 269KB 268.5KB/s 00:01
[8/11] pcre2-10.42.tgz 100% 1680KB 840.1KB/s 00:02
[9/11] vim-9.0.2122.tgz 100% 1714KB 571.5KB/s 00:03
[10/11] vim-share-9.0.2122.tgz 100% 8290KB 1.6MB/s 00:05
[11/11] xmlcatmgr-2.2nb1.tgz 100% 29KB 29.2KB/s 00:01
[1/11] installing xmlcatmgr-2.2nb1...
xmlcatmgr-2.2nb1: copying /usr/pkg/share/examples/xmlcatmgr/catalog.etc.sgml to /usr/pkg/etc/sgml/catalog
xmlcatmgr-2.2nb1: copying /usr/pkg/share/examples/xmlcatmgr/catalog.etc.xml to /usr/pkg/etc/xml/catalog
xmlcatmgr-2.2nb1: copying /usr/pkg/share/examples/xmlcatmgr/catalog.share.sgml to /usr/pkg/share/sgml/catalog
xmlcatmgr-2.2nb1: copying /usr/pkg/share/examples/xmlcatmgr/catalog.share.xml to /usr/pkg/share/xml/catalog
[2/11] installing libunistring-1.1...
[3/11] installing libxml2-2.10.4nb2...
[4/11] installing nghttp2-1.56.0...
[5/11] installing libidn2-2.3.4...
[6/11] installing pcre2-10.42...
[7/11] installing curl-8.4.0...
[8/11] installing vim-share-9.0.2122...
[9/11] installing git-base-2.42.0...
git-base-2.42.0: copying /usr/pkg/share/examples/git/templates/description to /usr/pkg/share/git-core/templates/description
git-base-2.42.0: copying /usr/pkg/share/examples/git/templates/hooks/applypatch-msg.sample to /usr/pkg/share/git-core/templates/hooks/applypatch-msg.sample
git-base-2.42.0: copying /usr/pkg/share/examples/git/templates/hooks/commit-msg.sample to /usr/pkg/share/git-core/templates/hooks/commit-msg.sample
git-base-2.42.0: copying /usr/pkg/share/examples/git/templates/hooks/post-update.sample to /usr/pkg/share/git-core/templates/hooks/post-update.sample
git-base-2.42.0: copying /usr/pkg/share/examples/git/templates/hooks/pre-applypatch.sample to /usr/pkg/share/git-core/templates/hooks/pre-applypatch.sample
git-base-2.42.0: copying /usr/pkg/share/examples/git/templates/hooks/pre-commit.sample to /usr/pkg/share/git-core/templates/hooks/pre-commit.sample
git-base-2.42.0: copying /usr/pkg/share/examples/git/templates/hooks/pre-rebase.sample to /usr/pkg/share/git-core/templates/hooks/pre-rebase.sample
git-base-2.42.0: copying /usr/pkg/share/examples/git/templates/hooks/prepare-commit-msg.sample to /usr/pkg/share/git-core/templates/hooks/prepare-commit-msg.sample
git-base-2.42.0: copying /usr/pkg/share/examples/git/templates/hooks/update.sample to /usr/pkg/share/git-core/templates/hooks/update.sample
git-base-2.42.0: copying /usr/pkg/share/examples/git/templates/info/exclude to /usr/pkg/share/git-core/templates/info/exclude
===========================================================================
$NetBSD: MESSAGE,v 1.3 2016/05/26 15:41:06 khorben Exp $
NOTE: Pristine templates are located in:
/usr/pkg/share/examples/git/templates.
To use the git-cvsimport repository conversion from CVS, install git-cvs.
To use the git-svn interface to Subversion, install git-svn.
===========================================================================
[10/11] installing doas-6.3p2nb1...
doas-6.3p2nb1: setting permissions on /usr/pkg/bin/doas (o=root, g=wheel, m=4511)
[11/11] installing vim-9.0.2122...
pkg_install warnings: 0, errors: 0
reading local summary...
processing local summary...
#
…and remove them along with their dependencies:
# pkgin rm neofetch vim
Password:
2 packages to delete:
neofetch-7.1.0 vim-9.0.2122
proceed ? [Y/n]
[1/2] removing neofetch-7.1.0...
[2/2] removing vim-9.0.2122...
pkg_install warnings: 0, errors: 0
reading local summary...
processing local summary...
# pkgin ar
Password:
2 packages to be autoremoved:
bash-5.2.15 vim-share-9.0.2122
proceed ? [Y/n] Y
[1/2] removing bash-5.2.15...
bash-5.2.15: removing /usr/pkg/bin/bash from /etc/shells
[2/2] removing vim-share-9.0.2122...
pkg_install warnings: 0, errors: 0
reading local summary...
processing local summary...
Configuring doas
doas
is a sudo
alternative that’s supposedly easier to use and more secure. BSD systems in particular seem to prefer doas
to sudo
, in the same way Solaris preferred pfexec
. You can use whatever you want, though.
Once you have installed doas
, edit /usr/pkg/etc/doas.conf
and make sure it contains the following:
# cat /usr/pkg/etc/doas.conf
permit :wheel
permit nopass :wheel cmd halt
permit nopass :wheel cmd reboot
This will let any user in the wheel
group to execute commands as superuser, plus it will let them issue halt
and reboot
without typing their password.
Using the system
The system feels quite responsive, but isn’t blazingly fast. I still can’t believe I used to run Deluge, a Samba server, and Apache2 off this thing!
Used space
The system fits nicely on a 4GB SD Card.
$ df -h
Filesystem Size Used Avail %Cap Mounted on
/dev/ld0a 3.5G 1.2G 2.2G 34% /
/dev/ld0e 80M 17M 63M 21% /boot
kernfs 1.0K 1.0K 0B 100% /kern
ptyfs 1.0K 1.0K 0B 100% /dev/pts
procfs 8.0K 8.0K 0B 100% /proc
tmpfs 112M 8.0K 112M 0% /var/shm
Swag
Because, why not?
`-/oshdmNMNdhyo+:-` quartz@icecube y/s+:-`` `.-:+oydNMMMMNhs/-`` -------------- -m+NMMMMMMMMMMMMMMMMMMMNdhmNMMMmdhs+/-` OS: NetBSD 9.3_STABLE evbarm -m+NMMMMMMMMMMMMMMMMMMMMmy+:` Uptime: 56 mins -N/dMMMMMMMMMMMMMMMds:` Packages: 18 (pkg_info) -N/hMMMMMMMMMmho:` Shell: ksh v5.2.14 99/07/13.2 -N/-:/++/:.` Terminal: /dev/pts/0 :M+ CPU: raspberrypi,model-b (1) :Mo Memory: 340MiB / 448MiB :Ms :Ms :Ms :Ms :Ms :Ms :Ms :Ms
IGEL D-210
If you combed through my blog, you might remember this little bugger from an old article I wrote detailing how I got Alpine running on this thing. It’s an interesting system, basically an embedded platform with an x86 CPU and a weird BIOS. I even got Windows 2000 running on it!
Set-up
I had to enable the Legacy USB Support option in the BIOS for it to see the USB drive. The system willl attempt to boot from Ventoy, but it will never find the rootfs. It might have worked if I dd-ed the appropriate image directly but I couldn’t be bothered; time to cheat! I attached the CF card from the IGEL to my laptop with an USB to CF adapter and did the following:
$ sudo qemu-system-i386 -m 1G -drive format=raw,file=/dev/sdb -cdrom NetBSD-9.3-i386.iso -boot d
This let me install the system to the CF card using QEMU. I reduced the swap size to 128MB and installed only the Base System. Since I’m running a generic kernel and the installer essentially only copies the system to the destination, the system will boot just fine (unlike Windows, which might crash since the drivers get baked in the filesystem during the install process).
I proceeded to set up everything except networking (and, thus, no fancy pkgin
setup) and shut down QEMU. I still enabled both sshd
and ntpdate
on boot so I couldn’t forget to do so later on.
I moved the CF card back to the IGEL and added the following to /etc/rc.conf
:
hostname=IGEL
dhcpcd=YES
This let me start the DHCP client with service dhcpcd start
, which gave me a valid IP address!
I then installed pkgin
using the procedure described earlier.
# export PKG_PATH="http://ftp.fr.NetBSD.org/pub/pkgsrc/packages/NetBSD/i386/9.3/All"
# pkg_add pkgin
pkg_add: Warning: package `pkgin-23.8.1' was built for a platform:
pkg_add: NetBSD/i386 9.0 (pkg) vs. NetBSD/i386 9.3 (this host)
pkg_add: Warning: package `pkg_install-20211115' was built for a platform:
pkg_add: NetBSD/i386 9.0 (pkg) vs. NetBSD/i386 9.3 (this host)
pkgin-23.8.1: copying /usr/pkg/share/examples/pkgin/repositories.conf.example to /usr/pkg/etc/pkgin/repositories.conf
# pkgin update && pkgin upgrade
processing remote summary (https://cdn.netbsd.org/pub/pkgsrc/packages/NetBSD/i386/9.0/All)...
pkg_summary.gz 100% 5259KB 14.5KB/s 06:03
calculating dependencies...done.
2 packages to upgrade:
pkg_install-20211115nb1 pkgin-23.8.1nb2
0 to remove, 0 to refresh, 2 to upgrade, 0 to install
363K to download, 8B of disk space will be freed up
proceed ? [Y/n]
[1/2] pkg_install-20211115nb1.tgz 100% 293KB 293.2KB/s 00:01
[2/2] pkgin-23.8.1nb2.tgz 100% 69KB 69.3KB/s 00:00
[1/2] upgrading pkg_install-20211115nb1...
[2/2] upgrading pkgin-23.8.1nb2...
===========================================================================
The following directories are no longer being used by pkgin-23.8.1,
and they can be removed if no other packages are using them:
/var/db/pkgin
===========================================================================
pkgin-23.8.1nb2: copying /usr/pkg/share/examples/pkgin/repositories.conf.example to /usr/pkg/etc/pkgin/repositories.conf
pkg_install warnings: 0, errors: 0
#
Using the system
The system is fine, although it feels a bit cramped. It would probably benefit from a larger CF card. This little bugger has a VIA Eden CPU running at 500MHz, and it feels faster than the RPi. I must compare them!
# neofetch
`-/oshdmNMNdhyo+:-` quartz@IGEL
y/s+:-`` `.-:+oydNMMMMNhs/-`` ------------------
-m+NMMMMMMMMMMMMMMMMMMMNdhmNMMMmdhs+/-` OS: NetBSD 9.3 i386
-m+NMMMMMMMMMMMMMMMMMMMMmy+:` Uptime: 28 mins
-N/dMMMMMMMMMMMMMMMds:` Packages: 5 (pkg_info)
-N/hMMMMMMMMMmho:` Shell: sh
-N/-:/++/:.` Terminal: /dev/pts/0
:M+ CPU: IDT/VIA 686-class (1)
:Mo Memory: 96MiB / 958MiB
:Ms
:Ms
:Ms
:Ms
:Ms
:Ms
:Ms
:Ms
# uname -a
NetBSD IGEL 9.3 NetBSD 9.3 (GENERIC) #0: Thu Aug 4 15:30:37 UTC 2022 mkrepro@mkrepro.NetBSD.org:/usr/src/sys/arch/i386/compile/GENERIC i386
# cat /proc/cpuinfo
processor : 0
vendor_id : CentaurHauls
cpu family : 6
model : 13
model name : VIA Eden Processor 500MHz
stepping : 0
cpu MHz : 500.07
apicid : 0
initial apicid : 0
fdiv_bug : no
fpu : yes
fpu_exception : yes
cpuid level : 1
wp : yes
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge cmov pat clflush acpi mmx fxsr sse sse2 tm pbe nx rng rng_en ace ace_en ace2 ace2_en phe phe_en pmm pmm_en
clflush size : 64
# df -h
Filesystem Size Used Avail %Cap Mounted on
/dev/wd0a 795M 225M 531M 29% /
tmpfs 240M 0B 240M 0% /tmp
kernfs 1.0K 1.0K 0B 100% /kern
ptyfs 1.0K 1.0K 0B 100% /dev/pts
procfs 4.0K 4.0K 0B 100% /proc
tmpfs 240M 0B 240M 0% /var/shm
#
Benchmarks
I couldn’t resist! NetBSD offers an implementation of LINPACK that can be used for benchmarking purposes. I also wanted to try 7-zip, but there are no prebuilt ARM binaries.
I performed the following tests:
- Single precision LINPACK.
- Double precision LINPACK.
- Memory-to-Memory transfer of 1 million 512-byte packages from
/dev/zero
to/dev/null
. - Disk transfer of 1 kilo 512-byte packages from
/dev/zero
to a file.
There is no scientific reason behind those benchmarks, so don’t bother asking me why I chose them. The file transfer is kinda pointless, I think, and I got it from here.
Raspberry Pi
LINPACK Single Precision
$ linpacks
Rolled Single Precision Linpack
Rolled Single Precision Linpack
norm. resid resid machep x[0]-1 x[n-1]-1
1.6 3.80277634e-05 1.19209290e-07 -1.38282776e-05 -7.51018524e-06
times are reported for matrices of order 100
dgefa dgesl total kflops unit ratio
times for array with leading dimension of 201
0.01 0.00 0.01 47032 0.04 0.26
0.01 0.00 0.01 45814 0.04 0.27
0.01 0.00 0.01 50111 0.04 0.24
0.01 0.00 0.01 46761 0.04 0.26
times for array with leading dimension of 200
0.01 0.00 0.01 49185 0.04 0.25
0.01 0.00 0.01 46795 0.04 0.26
0.01 0.00 0.01 49241 0.04 0.25
0.01 0.00 0.01 51403 0.04 0.24
Rolled Single Precision 46761 Kflops ; 10 Reps
LINPACK Double Precision
$ linpackd
Rolled Double Precision Linpack
Rolled Double Precision Linpack
norm. resid resid machep x[0]-1 x[n-1]-1
1.7 7.41628980e-14 2.22044605e-16 -1.49880108e-14 -1.89848137e-14
times are reported for matrices of order 100
dgefa dgesl total kflops unit ratio
times for array with leading dimension of 201
0.02 0.00 0.02 35147 0.06 0.35
0.02 0.00 0.02 35250 0.06 0.35
0.02 0.00 0.02 35357 0.06 0.35
0.02 0.00 0.02 35422 0.06 0.35
times for array with leading dimension of 200
0.02 0.00 0.02 35241 0.06 0.35
0.02 0.00 0.02 35226 0.06 0.35
0.02 0.00 0.02 35208 0.06 0.35
0.02 -0.00 0.02 36737 0.05 0.33
Rolled Double Precision 35422 Kflops ; 10 Reps
Memory-to-Memory I/O
$ dd if=/dev/zero of=/dev/null bs=512 count=1000000 oflag=dsync
1000000+0 records in
1000000+0 records out
512000000 bytes transferred in 28.282 secs (18103387 bytes/sec)
File I/O
$ touch test.file
$ dd if=/dev/zero of=test.file bs=512 count=1000 oflag=dsync
1000+0 records in
1000+0 records out
512000 bytes transferred in 13.918 secs (36786 bytes/sec)
IGEL D-210
LINPACK Single Precision
$ linpacks
Rolled Single Precision Linpack
Rolled Single Precision Linpack
norm. resid resid machep x[0]-1 x[n-1]-1
1.5 3.53703617e-05 1.19209290e-07 1.83582306e-05 1.33514404e-05
times are reported for matrices of order 100
dgefa dgesl total kflops unit ratio
times for array with leading dimension of 201
0.01 0.00 0.01 57834 0.03 0.21
0.01 0.00 0.01 57883 0.03 0.21
0.01 0.00 0.01 57761 0.03 0.21
0.01 0.00 0.01 57947 0.03 0.21
times for array with leading dimension of 200
0.01 0.00 0.01 57854 0.03 0.21
0.01 0.00 0.01 57893 0.03 0.21
0.01 0.00 0.01 57917 0.03 0.21
0.01 0.00 0.01 57922 0.03 0.21
Rolled Single Precision 57922 Kflops ; 10 Reps
LINPACK Double Precision
$ linpackd
Rolled Double Precision Linpack
Rolled Double Precision Linpack
norm. resid resid machep x[0]-1 x[n-1]-1
2.1 9.25510753e-14 2.22044605e-16 -8.68194405e-14 -7.20534743e-14
times are reported for matrices of order 100
dgefa dgesl total kflops unit ratio
times for array with leading dimension of 201
0.01 0.00 0.01 57237 0.03 0.21
0.01 0.00 0.01 57251 0.03 0.21
0.01 0.00 0.01 57289 0.03 0.21
0.01 0.00 0.01 57307 0.03 0.21
times for array with leading dimension of 200
0.01 0.00 0.01 57294 0.03 0.21
0.01 0.00 0.01 57313 0.03 0.21
0.01 0.00 0.01 57270 0.03 0.21
0.01 0.00 0.01 57333 0.03 0.21
Rolled Double Precision 57307 Kflops ; 10 Reps
Memory-to-Memory I/O
$ dd if=/dev/zero of=/dev/null bs=512 count=1000000 oflag=dsync
1000000+0 records in
1000000+0 records out
512000000 bytes transferred in 13.410 secs (38180462 bytes/sec)
File I/O
$ touch test.file
$ dd if=/dev/zero of=test.file bs=512 count=1000 oflag=dsync
1000+0 records in
1000+0 records out
512000 bytes transferred in 10.074 secs (50823 bytes/sec)
Summary
linpacks (Kflops) |
linpackd (Kflops) |
dd of=/dev/null 512x1M (bytes/sec) |
dd of=test.file 512x1K (bytes/sec) |
|
---|---|---|---|---|
Raspberry Pi | 46761 | 35422 | 18103387 | 36786 |
IGEL D-210 | 57922 (+19.3%) | 57307 (+38.2%) | 38180462 (+52.6%) | 50823 (+27.6%) |
The IGEL is quite a bit faster (34.4% on average) than the Raspberry Pi, but it is also beefier and it consumes more power. Overall, it feels snappier to use, but not by much.