Introduction
NetBSD-10 can be installed on the Raspberry Pi 3 either as a 32-bit operating system (evbarmv7hf port) or as a 64-bit operating system (evbarm64 port). The 64-bit binaries deliver noticeably better performance, particularly for 64-bit integer operations. It is therefore recommended to download and install the 64-bit binaries.
The Raspberry Pi 3 boots an operating system using boot firmware, which is typically stored on a FAT32 partition. Two types of boot firmware are available:
- The original Pi 3 firmware: https://github.com/raspberrypi/firmware/releases/
- The UEFI Pi 3 firmware: https://github.com/pftf/RPi3/releases
NetBSD-10 does not seem to function correctly with UEFI firmware on the Raspberry Pi 3, as the kernel panics during boot. It is therefore recommended to use the original firmware instead.
The installation process outlined in this article requires access to an existing NetBSD system, either physical or virtual, to partition the disk, create file systems, extract the NetBSD sets, and configure the installed system. The interactive NetBSD installer is not used here, as it lacks the flexibility offered by the manual approach.
Disk Partitions: MBR and GPT
Two different disk partitioning schemes can be used: Master Boot Record (MBR) and GUID Partition Table (GPT). The Raspberry Pi 3 firmware supports booting only from MBR; however, GPT can still be used by employing a hybrid MBR/GPT. The hybrid MBR/GPT method enables the boot disk to be partitioned with GPT while tricking the firmware into recognising it as an MBR boot.
For straightforward disk partitioning requirements, MBR may be adequate; however, GPT offers several advantages, including support for disks larger than 2 TB and a more convenient overall structure.
NetBSD Installation Steps
Several steps are required to install NetBSD. The following sections explain each step in greater detail.
Step 1: Create GPT Partitions
The first step in installing NetBSD is to create required GPT partitions. In this example, a microSD card is used, which is detected as sd0 device:
gpt destroy sd0
gpt create -f sd0
gpt add -a 1m -l "EFI-system" -t efi -s 128m sd0
gpt add -a 1m -l "NetBSD-diag" -t ffs -s 1g sd0
gpt add -a 1m -l "NetBSD-root" -t ffs -s 8g sd0
gpt add -a 1m -l "NetBSD-swap" -t swap -s 1g sd0
gpt add -a 1m -l "NetBSD-var" -t ffs -s 4g sd0
gpt add -a 1m -l "NetBSD-opt" -t ffs sd0
The "gpt destroy" command clears disk of any previous GPT partitions and the "gpt create" command creates initial GPT table.
The "gpt add" commands create a number of partitions. The "-a 1m" flag aligns partitions on 1 MiB boundary. The "-l" flag label each parition with a specific name.
The following partitions are creates:
- EFI-system: FAT32 boot partition which will contain boot firmware and NetBSD kernel. This should be created first before any other partitions that may follow.
- NetBSD-diag: The secondary diagnostic runtime environment that can be used to repair the primary runtime environment if it fails to boot properly.
- NetBSD-root: The primary runtime environment that contains the root file system.
- NetBSD-swap, NetBSD-var, NetBSD-opt: The remaining partitions used for various file systems.
The "gpt create" command also automatically creates a Protective MBR (PMBR) partition. This partition prevents legacy MBR-based disk utilities that are unaware of GPT from altering the disk sectors reserved for GPT.
Created GPT partitions can be viewd with "gpt show" command:
gpt show sd0
start size index contents
0 1 PMBR
1 1 Pri GPT header
2 32 Pri GPT table
34 2014 Unused
2048 262144 1 GPT part - EFI System
264192 2097152 2 GPT part - NetBSD FFSv1/FFSv2
2361344 16777216 3 GPT part - NetBSD FFSv1/FFSv2
19138560 2097152 4 GPT part - NetBSD swap
21235712 8388608 5 GPT part - NetBSD FFSv1/FFSv2
29624320 95109120 6 GPT part - NetBSD FFSv1/FFSv2
124733440 2015 Unused
124735455 32 Sec GPT table
124735487 1 Sec GPT header
Sector 0 contains the MBR partition information, sector 1 contains the primary GPT header, and sectors 2–33 contain the primary GPT table. The first partition starts at sector 2048, followed by other NetBSD partitions.
Created MBR partitions can be viewd with "fdisk" command:
fdisk sd0
Partition table:
0: GPT Protective MBR (sysid 238)
start 1, size 124735487 (60906 MB, Cyls 0-7764/108/24)
PBR is not bootable: Bad magic number (0x0000)
1: <UNUSED>
2: <UNUSED>
3: <UNUSED>
No active partition.
Drive serial number: 0 (0x00000000)
The PMBR partition (sysid 238) is located at index 0 and spans the entire disk (sectors 1–124735487). This corresponds to the same disk area allocated for GPT.
Step 2: Create Hybrid MBR/GPT Layout
When the Raspberry Pi 3 is powered on, it locates the boot disk and attempts to boot from the first (index 0) MBR partition formatted with the FAT32 file system (sysid 12). To meet this requirement, a hybrid MBR/GPT layout must be created. The NetBSD "fdisk -gu" command can be used to modify the MBR at sector 0 without affecting any of the GPT partitions.
To create a hybrid MBR/GPT layout, the following modifications should be applied:
- MBR partition 0 should be assigned sysid 12 and correspond to the sectors containing GPT EFI partition. This is the MBR boot partition used by the Raspberry Pi 3 during power-on.
- MBR partition 1 should be assigned sysid 238 and correspond to the sectors containing GPT metadata. This is a placeholder PMBR partition. The exact sectors are not critical, provided they do not overlap with those of MBR partition 0. Mapping it to the sectors holding the GPT primary header and table is sufficient.
The actual MBR partition modifications are shown below:
fdisk -gu sd0
...
Which partition do you want to change?: [none] 0
The data for partition 0 is:
GPT Protective MBR (sysid 238)
start 1, size 124735487 (60906 MB, Cyls 0-7764/108/24)
PBR is not bootable: Bad magic number (0x0000)
sysid: [0..255 default: 238] 12
start: [0..7764cyl default: 1, 0cyl, 0MB] 2048
size: [0..7764cyl default: 124733440, 7764cyl, 60905MB] 262144
bootmenu: [] (space to clear)
The bootselect code is not installed, do you want to install it now? [n]
...
Which partition do you want to change?: [none] 1
The data for partition 1 is:
<UNUSED>
sysid: [0..255 default: 169] 238
start: [0..7764cyl default: 1, 0cyl, 0MB] 1
size: [0..0cyl default: 2047, 0cyl, 1MB] 2047
bootmenu: [] (space to clear)
The bootselect code is not installed, do you want to install it now? [n]
...
Which partition do you want to change?: [none]
...
Installed bootfile doesn't support required options.
Update the bootcode from /usr/mdec/mbr? [n]
...
Should we write new partition table? [n] y
The final hybrid MBR/GPT partition layout should look like this:
fdisk sd0
Partition table:
0: Primary DOS with 32 bit FAT - LBA (sysid 12)
start 2048, size 262144 (128 MB, Cyls 0/32/33-16/113/33)
PBR is not bootable: All bytes are identical (0x00)
1: GPT Protective MBR (sysid 238)
start 1, size 2047 (1 MB, Cyls 0-0/32/32)
PBR is not bootable: Bad magic number (0x0000)
2: <UNUSED>
3: <UNUSED>
No active partition.
Drive serial number: 0 (0x00000000)
Step 3: Create File Systems
Execute dkctl to display the wedges currently mapped to partitions. Note that wedge mappings are dynamic and may differ on your system:
dkctl sd0 listwedges
/dev/rsd0: 6 wedges:
dk1: EFI-system, 262144 blocks at 2048, type: msdos
dk2: NetBSD-diag, 2097152 blocks at 264192, type: ffs
dk3: NetBSD-root, 16777216 blocks at 2361344, type: ffs
dk4: NetBSD-swap, 2097152 blocks at 19138560, type: swap
dk5: NetBSD-var, 8388608 blocks at 21235712, type: ffs
dk6: NetBSD-opt, 95109120 blocks at 29624320, type: ffs
Use the wedge mappings shown above to create the necessary file systems. Note that raw special devices should be used; therefore, the wedges specified in the newfs commands should be /dev/rdkN, where N is the wedge ID:
newfs_msdos -F 32 /dev/rdk1
for i in rdk2 rdk3 rdk5 rdk6
do
newfs -B le -O 2ea /dev/${i} || break
done
Step 4: Mount File Systems and Extract Files
Mount all file systems associated with the primary and secondary runtime environments:
mkdir /mnt-netbsd-root && mount -o log NAME=NetBSD-root /mnt-netbsd-root &&
mkdir /mnt-netbsd-root/boot && mount -t msdos NAME=EFI-system /mnt-netbsd-root/boot &&
mkdir /mnt-netbsd-root/var && mount -o log NAME=NetBSD-var /mnt-netbsd-root/var &&
mkdir /mnt-netbsd-root/opt && mount -o log NAME=NetBSD-opt /mnt-netbsd-root/opt &&
mkdir /mnt-netbsd-diag && mount -o log NAME=NetBSD-diag /mnt-netbsd-diag
Download Raspberry Pi 3 boot firmware and NetBSD sets. Note that the X11 sets are not included, as the Raspberry Pi 3 will be used in headless/server mode in this setup:
ftp https://github.com/raspberrypi/firmware/releases/download/1.20240902/raspi-firmware_1.20240902.orig.tar.xz
mkdir netbsd_sets
for i in base comp etc games kern-GENERIC64 man misc modules rescue text
do
ftp -o netbsd_sets/${i}.tar.xz https://cdn.netbsd.org/pub/NetBSD/NetBSD-10.1/evbarm-aarch64/binary/sets/${i}.tar.xz || break
done
Extract boot firmware and NetBSD kernel into boot partition:
tar -C /mnt-netbsd-root/boot --strip-components=2 -xf raspi-firmware_1.20240902.orig.tar.xz '*/boot/*' &&
tar -C /mnt-netbsd-root/boot -xf netbsd_sets/kern-GENERIC64.tar.xz netbsd.img &&
sync
ls -l /mnt-netbsd-root/boot
total 76342
-rwxr-xr-x 1 root wheel 1594 Sep 2 2024 LICENCE.broadcom
-rwxr-xr-x 1 root wheel 52476 Sep 2 2024 bootcode.bin
-rwxr-xr-x 1 root wheel 7327 Sep 2 2024 fixup.dat
-rwxr-xr-x 1 root wheel 5456 Sep 2 2024 fixup4.dat
-rwxr-xr-x 1 root wheel 3232 Sep 2 2024 fixup4cd.dat
-rwxr-xr-x 1 root wheel 8450 Sep 2 2024 fixup4db.dat
-rwxr-xr-x 1 root wheel 8450 Sep 2 2024 fixup4x.dat
-rwxr-xr-x 1 root wheel 3232 Sep 2 2024 fixup_cd.dat
-rwxr-xr-x 1 root wheel 10295 Sep 2 2024 fixup_db.dat
-rwxr-xr-x 1 root wheel 10295 Sep 2 2024 fixup_x.dat
-rwxr-xr-x 1 root wheel 16775144 Dec 16 2024 netbsd.img
-rwxr-xr-x 1 root wheel 2983488 Sep 2 2024 start.elf
-rwxr-xr-x 1 root wheel 2259296 Sep 2 2024 start4.elf
-rwxr-xr-x 1 root wheel 811804 Sep 2 2024 start4cd.elf
-rwxr-xr-x 1 root wheel 3756808 Sep 2 2024 start4db.elf
-rwxr-xr-x 1 root wheel 3006920 Sep 2 2024 start4x.elf
-rwxr-xr-x 1 root wheel 811804 Sep 2 2024 start_cd.elf
-rwxr-xr-x 1 root wheel 4828616 Sep 2 2024 start_db.elf
-rwxr-xr-x 1 root wheel 3730536 Sep 2 2024 start_x.elf
Extract NetBSD sets into the primary and secondary runtime environments:
for i in base comp dtb etc games man misc modules rescue text
do
tar -C /mnt-netbsd-root -xpf netbsd_sets/${i}.tar.xz || break
done
for i in base dtb etc games man misc modules rescue text
do
tar -C /mnt-netbsd-diag -xpf netbsd_sets/${i}.tar.xz || break
done &&
rm -rf /mnt-netbsd-diag/boot/*
sync
We remove all files under /mnt-netbsd-diag/boot/ because they have already been extracted into the boot partition, which is shared by both runtime environments.
Step 5: Configure NetBSD Primary Runtime Environment
Create the cmdline.txt and config.txt files in the boot partition:
cat > /mnt-netbsd-root/boot/cmdline.txt << 'EOF'
root=NAME=NetBSD-root console=fb
#root=NAME=NetBSD-diag console=fb
EOF
cat > /mnt-netbsd-root/boot/config.txt << 'EOF'
# For more info see:
# https://www.raspberrypi.com/documentation/computers/config_txt.html
# https://www.raspberrypi.com/documentation/computers/legacy_config_txt.html
arm_64bit=1
upstream_kernel=1
os_prefix=dtb/broadcom/
cmdline=/cmdline.txt
kernel=/netbsd.img
kernel_address=0x200000
enable_uart=1
force_turbo=0
EOF
Create the /etc/fstab file:
cat > /mnt-netbsd-root/etc/fstab << 'EOF'
NAME=EFI-system /boot msdos rw 0 0
NAME=NetBSD-root / ffs rw,noatime,log 1 1
NAME=NetBSD-var /var ffs rw,noatime,log 1 1
NAME=NetBSD-opt /opt ffs rw,noatime,log 1 2
NAME=NetBSD-swap none swap sw,dp 0 0
kernfs /kern kernfs rw
procfs /proc procfs rw
ptyfs /dev/pts ptyfs rw
tmpfs /var/shm tmpfs rw,-m1777,-sram%25
EOF
Create the additional mount points and the time zone symlink:
mkdir /mnt-netbsd-root/kern /mnt-netbsd-root/proc /mnt-netbsd-root/home
ln -sf ../usr/share/zoneinfo/Europe/London /mnt-netbsd-root/etc/localtime
Create the /etc/rc.conf file:
cat >> /mnt-netbsd-root/etc/rc.conf << 'EOF'
rc_configured=YES
critical_filesystems_local="${critical_filesystems_local} /opt"
hostname="rp3"
domainname="home.lan"
# Static IP config
net_interfaces="mue0"
ifconfig_mue0="inet 192.168.1.1 netmask 255.255.255.0 tso4 tso6 ip4csum tcp4csum tcp6csum udp4csum udp6csum"
dns_search="home.lan"
dns_nameservers="192.168.1.1"
defaultroute="192.168.1.254"
# Dynamic IP config
#dhcpcd=YES
#dhcpcd_flags="-qM genet0"
ip6addrctl=YES
ip6addrctl_policy="ipv4_prefer"
ntpdate=YES
sshd=YES
devpubd=YES
EOF
Step 6: Configure NetBSD Secondary Diagnostic Runtime Environment
Create the /etc/fstab file:
cat > /mnt-netbsd-diag/etc/fstab << 'EOF'
NAME=EFI-system /boot msdos rw 0 0
NAME=NetBSD-diag / ffs rw,noatime,log 1 1
NAME=NetBSD-swap none swap sw,dp 0 0
kernfs /kern kernfs rw
procfs /proc procfs rw
ptyfs /dev/pts ptyfs rw
tmpfs /var/shm tmpfs rw,-m1777,-sram%25
EOF
Create the additional mount points and the time zone symlink:
mkdir /mnt-netbsd-diag/kern /mnt-netbsd-diag/proc /mnt-netbsd-diag/home
ln -sf ../usr/share/zoneinfo/Europe/London /mnt-netbsd-diag/etc/localtime
Create the /etc/rc.conf file:
cat >> /mnt-netbsd-diag/etc/rc.conf << 'EOF'
rc_configured=YES
hostname="rp3-diag"
domainname="home.lan"
# Static IP config
net_interfaces="mue0"
ifconfig_mue0="inet 192.168.1.1 netmask 255.255.255.0 tso4 tso6 ip4csum tcp4csum tcp6csum udp4csum udp6csum"
dns_search="home.lan"
dns_nameservers="192.168.1.1"
defaultroute="192.168.1.254"
# Dynamic IP config
#dhcpcd=YES
#dhcpcd_flags="-qM genet0"
ip6addrctl=YES
ip6addrctl_policy="ipv4_prefer"
ntpdate=YES
sshd=YES
devpubd=YES
EOF
Step 7: Clean Up
Finally unmount all file systems:
sync &&
umount /mnt-netbsd-root/boot &&
umount /mnt-netbsd-root/opt &&
umount /mnt-netbsd-root/var &&
umount /mnt-netbsd-root &&
umount /mnt-netbsd-diag
NetBSD can now be booted into either the primary or secondary runtime environment, selected by modifying the cmdline.txt file in the boot partition. Review afterboot(8), then carry out any additional configuration as required.