Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save G-UK/ded781ea016e2c95addba2508c6bbfbe to your computer and use it in GitHub Desktop.
Save G-UK/ded781ea016e2c95addba2508c6bbfbe to your computer and use it in GitHub Desktop.
Build a 64bit Debian OS for the Raspberry Pi using Debootstrap

Introduction

The objective of these instructions is to create a complete Arm64 OS (Userland and Kernel) using Debian Debootstrap and RPI-Update for use on the Raspberry Pi 3 and 4.

Prerequisites:

  • An existing Debian/Raspbian system (any architecture will do)
  • An empty SD card formatted as per a standard Raspbian installation mounted to /mnt/sd on the build system
    • 1st Partition 0-256MB = FAT32 (Mount to /mnt/sd/boot)
    • 2nd Partition 256MB+ = EXT4 (Mount to /mnt/sd)

Set-up basic Debian system

The utility used by the Debian installer, and recognized as the official way to install a Debian base system, is debootstrap. We will also need QEMU if we are building an Arm64 system on another host architecture (x64 or ArmHF most likely)

So lets install them.

sudo apt install debootstrap qemu

Now lets tell debootstrap to set-up a base Debian Arm64 installation on our SD card. This may take a while and will download an entire basic Debian system.

sudo debootstrap --arch arm64 bullseye /mnt/sd http://ftp.uk.debian.org/debian

Before we can do anything with our new system we have to make it accessible from our hosts architecture, we do this using QEMU.

sudo cp /usr/bin/qemu-arm64-static /mnt/sd/usr/bin

Now we have a basic Debian system we can chroot into and start setting up.

sudo mount -t proc /proc /mnt/sd/proc/
sudo mount -t sysfs /sys /mnt/sd/sys/
sudo mount -o bind /dev /mnt/sd/dev/
sudo chroot /mnt/sd /bin/bash

Configure your new system

Set-up APT

Now we are chrooted into our new Debian system there are a few things we need to configure to make it useable. Lets deal with "apt" first so we can install new packages.

To set-up "apt" we need to tell it which sources to use, I'll use the UK Debian mirror in this example.

editor /etc/apt/sources.list
deb http://ftp.uk.debian.org/debian stable main contrib non-free
deb-src http://ftp.uk.debian.org/debian stable main contrib non-free

deb http://ftp.uk.debian.org/debian stable-updates main contrib non-free
deb-src http://ftp.uk.debian.org/debian stable-updates main contrib non-free

deb http://security.debian.org/ stable/updates main contrib non-free
deb-src http://security.debian.org/ stable/updates main contrib non-free

To minimise the number of packages that apt installs you can also disable the automatic installation of Recommended packages

editor /etc/apt/apt.conf.d/99_norecommends
APT::Install-Recommends "false";
APT::AutoRemove::RecommendsImportant "false";
APT::AutoRemove::SuggestsImportant "false";

Once that file is saved we can update the apt repositories and make sure everything is updated.

apt update
apt upgrade

Configure Basic System Settings

Now we can set-up some other basic system settings.

Timezone

Select your Timezone.

dpkg-reconfigure tzdata

Locales

Select your language and input settings.

apt install locales
dpkg-reconfigure locales

Networking

Basic Setup

I will use echo commands in these instructions for simplicity, alternatively you can use "editor" to edit these files.

Setup your network interfaces. (Example using a basic wired connection using DHCP, customise to suit)

echo \
'auto lo
iface lo inet loopback

auto eth0
iface eth0 inet dhcp

allow-hotplug wlan0
iface wlan0 inet dhcp
    wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf' \
> /etc/network/interfaces

Setup your DNS nameservers (Example using Cloudflare servers)

echo \
'nameserver 1.1.1.1
nameserver 1.0.0.1' \
> /etc/resolv.conf

Setup your hostname (Example using Pi-Example)

echo 'Pi-Example' > /etc/hostname

Set-up your hosts file (including IPV4 and IPV6)

echo \
'127.0.0.1 localhost
127.0.1.1 Pi-Example

::1     ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
ff02::3 ip6-allhosts' \
> /etc/hosts
Wireless (Optional)

If you are going to be using a wireless network connection rather than wired you will need to setup wpasupplicant with your wifi connection details like this example.

apt install wpasupplicant
editor /etc/wpa_supplicant/wpa_supplicant.conf
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
country=GB

network={
     ssid="Your network name/SSID"
     psk="Your WPA/WPA2 security key"
     key_mgmt=WPA-PSK
}

Drive Mounts (Fstab)

Set-up your basic drive mounts for / , /boot & /proc

editor /etc/fstab

This example assumes a standard Raspberry Pi SD card set-up.

# <file system>   <dir>           <type>  <options>         <dump>  <pass>
proc              /proc           proc    defaults          0       0
/dev/mmcblk0p1    /boot           vfat    defaults          0       2
/dev/mmcblk0p2    /               ext4    defaults,noatime  0       1

Set-up Root user password

passwd

Install Additional Basic Packages

These are additional packages you may expect to find on a basic (Commandline) Debian system on the Raspberry Pi

apt install aptitude ca-certificates crda fake-hwclock firmware-brcm80211 gnupg man-db manpages net-tools ntp usb-modeswitch ssh sudo wget xz-utils

Install additional packages if you want to use a GUI and RDP (lxqt as an example)

apt install xorg xorgxrdp xrdp lxqt lightdm

Install mesa drivers to enable 3D acceleration (Note: I'm unsure of which specific packages are required but this should cover all bases)

apt install libegl-mesa0 libgbm1 libgl1-mesa-dev libgl1-mesa-dri libglapi-mesa libglx-mesa0 libosmesa6  mesa-opencl-icd mesa-va-drivers mesa-vdpau-drivers mesa-vulkan-drivers mesa-utils

Set-up user account

Creating a new user account

Standard Raspbian has the "pi" user so I'll use that as an example.

Create a user called "pi" that uses the "bash" shell, who has a home directory of "/home/pi" and is a member of the same groups as in a standard Raspbian install.

mkdir /home/pi
groupadd spi
groupadd i2c
groupadd gpio
useradd -s /bin/bash -d /home/pi -G sudo,video,adm,dialout,cdrom,audio,plugdev,games,users,input,netdev,spi,i2c,gpio pi
chown pi:pi /home/pi

Set the users password

passwd pi

Setting up user .profile

In order for your BASH settings (~/.bashrc) to load on log-in you require a .profile file in your user and root home directories.

editor /home/pi/.profile
# if running bash
if [ -n "$BASH_VERSION" ]; then
    # include .bashrc if it exists
    if [ -f "$HOME/.bashrc" ]; then
        . "$HOME/.bashrc"
    fi
fi

# set PATH so it includes user's private bin if it exists
if [ -d "$HOME/bin" ] ; then
    PATH="$HOME/bin:$PATH"
fi

# set PATH for RaspberryPi userland files in /opt/vc/bin if they exist
if [ -d "/opt/vc/bin" ] ; then
    PATH="$PATH:/opt/vc/bin"
fi
cp /home/pi/.profile /root/
chown pi:pi /home/pi/.profile

Install the Kernel and Userland Firmware

Install rpi-update script

cd /usr/local/bin
wget https://raw.githubusercontent.com/raspberrypi/rpi-update/master/rpi-update
chmod +x rpi-update

Install dependencies

apt install curl binutils cmake git build-essential

Install Kernel

WANT_32BIT=1 WANT_64BIT=1 WANT_PI4=1 rpi-update

Configure Kernel

Set-up config.txt and cmdline.txt

echo 'dwc_otg.lpm_enable=0 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait net.ifnames=0' > /boot/cmdline.txt
echo $'ngpu_mem=16\narm_64bit=1\ndtoverlay=vc4-fkms-v3d' > /boot/config.txt

Optional: Configure 64-bit Userland Firmware

(Incomplete and Unsupported. For full working Userland firmware I would recommend to multi-arch armhf as you can just use the rpi-update installed files in that case)

Build and install from Source

cd /tmp
git clone https://github.com/raspberrypi/userland
cd userland
./buildme --aarch64

Optional: Configure Multi-Arch to support Stock ArmHF & ArmEL Userland Firmware

dpkg --add-architecture armhf
dpkg --add-architecture armel
apt update
apt install libc6:armhf libc6:armel

Add /opt/vc/lib to linker config

echo '/opt/vc/lib' > /etc/ld.so.conf.d/00-vmcs.conf

Add /opt/vc/bin to sudo secure paths so that firmware commands work with sudo

echo 'Defaults        secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/vc/bin"' > /etc/sudoers.d/opt-path

Add udev rules to allow access to device tree via user groups

editor /etc/udev/rules.d/99-com.rules
SUBSYSTEM=="vchiq",GROUP="video",MODE="0660"
SUBSYSTEM=="vcio",GROUP="video",MODE="0660"
SUBSYSTEM=="vc-mem",GROUP="video",MODE="0660"
SUBSYSTEM=="input", GROUP="input", MODE="0660"
SUBSYSTEM=="i2c-dev", GROUP="i2c", MODE="0660"
SUBSYSTEM=="spidev", GROUP="spi", MODE="0660"
SUBSYSTEM=="bcm2835-gpiomem", GROUP="gpio", MODE="0660"
SUBSYSTEM=="rpivid-*", GROUP="video", MODE="0660"

KERNEL=="vcsm-cma", GROUP="video", MODE="0660"

SUBSYSTEM=="gpio", GROUP="gpio", MODE="0660"
SUBSYSTEM=="gpio*", PROGRAM="/bin/sh -c '\
	chown -R root:gpio /sys/class/gpio && chmod -R 770 /sys/class/gpio;\
	chown -R root:gpio /sys/devices/virtual/gpio && chmod -R 770 /sys/devices/virtual/gpio;\
	chown -R root:gpio /sys$devpath && chmod -R 770 /sys$devpath\
'"

SUBSYSTEM=="pwm*", PROGRAM="/bin/sh -c '\
	chown -R root:gpio /sys/class/pwm && chmod -R 770 /sys/class/pwm;\
	chown -R root:gpio /sys/devices/platform/soc/*.pwm/pwm/pwmchip* && chmod -R 770 /sys/devices/platform/soc/*.pwm/pwm/pwmchip*\
'"

KERNEL=="ttyAMA[01]", PROGRAM="/bin/sh -c '\
	ALIASES=/proc/device-tree/aliases; \
	if cmp -s $ALIASES/uart0 $ALIASES/serial0; then \
		echo 0;\
	elif cmp -s $ALIASES/uart0 $ALIASES/serial1; then \
		echo 1; \
	else \
		exit 1; \
	fi\
'", SYMLINK+="serial%c"

KERNEL=="ttyS0", PROGRAM="/bin/sh -c '\
	ALIASES=/proc/device-tree/aliases; \
	if cmp -s $ALIASES/uart1 $ALIASES/serial0; then \
		echo 0; \
	elif cmp -s $ALIASES/uart1 $ALIASES/serial1; then \
		echo 1; \
	else \
		exit 1; \
	fi \
'", SYMLINK+="serial%c"

Finally

If there is anything else you wish to configure such as SSH keys (Note SSH is enabled in this build but not configured), this can be done in the chroot environment you have been working.

Once complete you should be able to exit the chroot environment and unmount your new SD card.

exit
sudo umount /mnt/sd/*
sudo umount /mnt/sd

Your 64-bit Debian Bullseye is now ready for use, Just insert the card into your PI and power on.

@Algorithm0
Copy link

Thank you very much! This helped me a lot. Here is my fork for installing on Pi 5.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment