aboutsummaryrefslogtreecommitdiff
path: root/images/raspberry-pi-2
diff options
context:
space:
mode:
authorJakob Odersky <jakob@odersky.com>2018-10-25 13:39:22 -0700
committerJakob Odersky <jakob@odersky.com>2018-10-25 13:39:22 -0700
commit802e1268022d8398c565601fd324994e5eab5ca8 (patch)
tree8613df8340e9f7b5a6e27c654797f18853948114 /images/raspberry-pi-2
parentcfeb980e870a799676f07bb393c4957cfdd9e3a0 (diff)
downloadinfra-802e1268022d8398c565601fd324994e5eab5ca8.tar.gz
infra-802e1268022d8398c565601fd324994e5eab5ca8.tar.bz2
infra-802e1268022d8398c565601fd324994e5eab5ca8.zip
Add base image scripts for single-board computers
Diffstat (limited to 'images/raspberry-pi-2')
-rw-r--r--images/raspberry-pi-2/Makefile99
-rw-r--r--images/raspberry-pi-2/README.md17
-rw-r--r--images/raspberry-pi-2/firstboot82
-rwxr-xr-ximages/raspberry-pi-2/scripts/mkrootimg107
4 files changed, 305 insertions, 0 deletions
diff --git a/images/raspberry-pi-2/Makefile b/images/raspberry-pi-2/Makefile
new file mode 100644
index 0000000..1c38efd
--- /dev/null
+++ b/images/raspberry-pi-2/Makefile
@@ -0,0 +1,99 @@
+SSH_KEY_FILE?=$(HOME)/.ssh/id_rsa.pub
+DISTRIBUTION=stretch
+ROOTFS=rootfs
+IMAGE=image
+
+all: $(IMAGE).bmap
+
+$(ROOTFS).debootstrapped:
+# apt-cacher-ng listens on port 3142
+ http_proxy="http://localhost:3142" \
+ qemu-debootstrap \
+ --include=linux-image-armmp-lpae,flash-kernel,u-boot-tools,u-boot-rpi,parted,dbus,apt,openssh-server \
+ --arch=armhf \
+ $(DISTRIBUTION) \
+ $(ROOTFS) \
+ http://httpredir.debian.org/debian
+ touch $(ROOTFS).debootstrapped
+
+# configure fstab
+$(ROOTFS).customized: $(ROOTFS).debootstrapped
+ echo "/dev/mmcblk0p1 /boot/firmware vfat noatime 0 2" > $(ROOTFS)/etc/fstab
+ echo "/dev/mmcblk0p2 / ext4 defaults 0 1" >> $(ROOTFS)/etc/fstab
+ echo "tmpfs /tmp tmpfs defaults 0 0" >> $(ROOTFS)/etc/fstab
+
+# install proprietary 2nd-stage bootloader firmware
+ mkdir -p "$(ROOTFS)/boot/firmware"
+ wget -O "$(ROOTFS)/boot/firmware/bootcode.bin" \
+ https://github.com/raspberrypi/firmware/raw/master/boot/bootcode.bin
+ wget -O "$(ROOTFS)/boot/firmware/start.elf" \
+ https://github.com/raspberrypi/firmware/raw/master/boot/start.elf
+ wget -O "$(ROOTFS)/boot/firmware/fixup.dat" \
+ https://github.com/raspberrypi/firmware/raw/master/boot/fixup.dat
+
+# configure u-boot 3rd-stage bootloader
+# https://blog.night-shade.org.uk/2015/05/booting-a-raspberry-pi2-with-u-boot-and-hyp-enabled/
+ cp "$(ROOTFS)/usr/lib/u-boot/rpi_2/u-boot.bin" "$(ROOTFS)/boot/firmware/u-boot.bin"
+ echo "gpu_mem=64" > "$(ROOTFS)/boot/firmware/config.txt"
+ echo "kernel=u-boot.bin" >> "$(ROOTFS)/boot/firmware/config.txt"
+
+# configure kernel flashing utility
+# http://sjoerd.luon.net/posts/2015/02/debian-jessie-on-rpi2/
+ echo "Raspberry Pi 2 Model B" > "$(ROOTFS)/etc/flash-kernel/machine"
+ echo "setenv distro_bootpart 2" > "$(ROOTFS)/etc/flash-kernel/ubootenv.d/10-partition"
+ echo "setenv prefix /boot/" >> "$(ROOTFS)/etc/flash-kernel/ubootenv.d/10-partition"
+ echo "Machine: Raspberry Pi 2 Model B" > "$(ROOTFS)/etc/flash-kernel/db"
+ echo "Boot-Script-Path: /boot/firmware/boot.scr" >> "$(ROOTFS)/etc/flash-kernel/db"
+
+# configure kernel boot args
+ echo 'LINUX_KERNEL_CMDLINE="quiet"' > "$(ROOTFS)/etc/default/flash-kernel"
+ echo 'LINUX_KERNEL_CMDLINE_DEFAULTS="console=ttyAMA0 root=/dev/mmcblk0p2"' >> "$(ROOTFS)/etc/default/flash-kernel"
+ chroot $(ROOTFS) flash-kernel
+
+# configure other system settings
+ echo "pi" > $(ROOTFS)/etc/hostname
+
+ echo "127.0.0.1 localhost" > $(ROOTFS)/etc/hosts
+ echo "::1 localhost" >> $(ROOTFS)/etc/hosts
+
+ echo "deb http://httpredir.debian.org/debian $(DISTRIBUTION) main contrib non-free" > $(ROOTFS)/etc/apt/sources.list
+ echo "deb http://httpredir.debian.org/debian $(DISTRIBUTION)-updates main contrib non-free" >> $(ROOTFS)/etc/apt/sources.list
+ echo "deb http://security.debian.org $(DISTRIBUTION)/updates main contrib non-free" >> $(ROOTFS)/etc/apt/sources.list
+
+ echo "auto lo" > "$(ROOTFS)/etc/network/interfaces.d/lo"
+ echo "iface lo inet loopback" >> "$(ROOTFS)/etc/network/interfaces.d/lo"
+
+ echo "allow-hotplug eth0" > "$(ROOTFS)/etc/network/interfaces.d/eth0"
+ echo "iface eth0 inet dhcp" >> "$(ROOTFS)/etc/network/interfaces.d/eth0"
+
+ mkdir -p -m 0600 $(ROOTFS)/root/.ssh
+ cat $(SSH_KEY_FILE) > $(ROOTFS)/root/.ssh/authorized_keys
+ sed -i 's/#PasswordAuthentication yes/PasswordAuthentication no/g' "$(ROOTFS)/etc/ssh/sshd_config"
+ chroot $(ROOTFS) sh -c "echo root:guest | chpasswd"
+
+ cp firstboot $(ROOTFS)/etc/firstboot
+ chmod +x $(ROOTFS)/etc/firstboot
+ echo "#!/bin/sh -e" > $(ROOTFS)/etc/rc.local
+ echo "/etc/firstboot" >> $(ROOTFS)/etc/rc.local
+ echo "exit 0" >> $(ROOTFS)/etc/rc.local
+ chmod +x $(ROOTFS)/etc/rc.local
+
+ touch $(ROOTFS).customized
+
+$(IMAGE).raw: $(ROOTFS).customized
+ scripts/mkrootimg $(ROOTFS) $(IMAGE).raw
+ touch $(IMAGE).raw
+
+$(IMAGE).bmap: $(IMAGE).raw
+ bmaptool create -o $(IMAGE).bmap $(IMAGE).raw
+
+clean:
+ rm -rf $(ROOTFS)
+ rm -f $(ROOTFS).debootstrapped
+ rm -f $(ROOTFS).customized
+
+mrproper: clean
+ rm -f $(IMAGE).raw
+ rm -f $(IMAGE).bmap
+
+.PHONY: all clean mrproper
diff --git a/images/raspberry-pi-2/README.md b/images/raspberry-pi-2/README.md
new file mode 100644
index 0000000..9d4ed0f
--- /dev/null
+++ b/images/raspberry-pi-2/README.md
@@ -0,0 +1,17 @@
+# Minimal Debian Image for the Raspberry Pi 2
+
+Makefile for building a bootable image that may be directly flashed to a memory card and used with a Raspberry Pi 2 Model B.
+
+The image contains a very basic Debian installation with an OpenSSH server. It is also self-expanding: on first boot, the partitions contained in the image will be expanded to fill the availale size of the memory card.
+
+## Build
+
+*Note: creating the image requires super user privileges because `chroot` is invoked as part of the build process.*
+
+Run the following to build a flashable image:
+
+ sudo make SSH_KEY_FILE=<path>
+
+where `SSH_KEY_FILE` is the absolute path of an SSH public key that will be used to login. SSH password login will be disabled, although the root account will nevertheless have its password set to "guest".
+
+This results in two image files `image.raw` and `image.bmap`. The former may be directly flashed to a memory card with a utility such as `dd`, whereas the latter is to be used with `bmaptool` (which promises perfomance increases of the flashing process).
diff --git a/images/raspberry-pi-2/firstboot b/images/raspberry-pi-2/firstboot
new file mode 100644
index 0000000..c384d50
--- /dev/null
+++ b/images/raspberry-pi-2/firstboot
@@ -0,0 +1,82 @@
+#!/bin/bash
+set -e
+echo "first boot: starting"
+
+led_blink() {
+ local led=/sys/class/leds/"$1"
+
+ local time_on="$2"
+ local time_off="$time_on"
+ local blinks="$3"
+
+ local trigger=$(cat "$led/trigger" | sed 's/.*\[\(.*\)\].*/\1/g' -)
+ local brightness=$(cat "$led/brightness")
+
+ echo "none" > "$led/trigger"
+ for i in $(seq 1 $blinks); do
+ echo 255 > "$led/brightness"
+ sleep "$time_on"
+ echo 0 > "$led/brightness"
+ sleep "$time_off"
+ done
+ echo "$brightness" > "$led/brightness"
+ echo "$trigger" > "$led/trigger"
+}
+
+led_trigger() {
+ local led=/sys/class/leds/"$1"
+
+ if [ "$2" == "heartbeat" ]; then
+ modprobe ledtrig_heartbeat || true
+ fi
+ echo "$2" > "$led/trigger"
+}
+
+echo "first boot: starting led trigger"
+led_blink ACT 0.1 20 &
+led_blink PWR 0.1 20
+led_trigger PWR heartbeat
+led_trigger ACT mmc0
+
+echo "first boot: generating ssh host keys"
+systemctl stop sshd
+rm -f /etc/ssh/ssh_host_*
+ssh-keygen -q -t rsa -N "" -f /etc/ssh/ssh_host_rsa_key
+ssh-keygen -q -t dsa -N "" -f /etc/ssh/ssh_host_dsa_key
+ssh-keygen -q -t ecdsa -N "" -f /etc/ssh/ssh_host_ecdsa_key
+ssh-keygen -q -t ed25519 -N "" -f /etc/ssh/ssh_host_ed25519_key
+systemctl start sshd
+
+echo "first boot: generating dbus machine-id"
+rm -f /var/lib/dbus/machine-id
+dbus-uuidgen --ensure
+
+echo "first boot: expanding root file system"
+fdisk /dev/mmcblk0 <<EOF || true
+p
+d
+2
+n
+p
+2
+
+
+n
+w
+EOF
+partprobe
+resize2fs /dev/mmcblk0p2
+
+echo "first boot: generating initramfs"
+update-initramfs -u
+
+echo "first boot: deleting script"
+rm -f /etc/firstboot
+sed -i '/.*firstboot/d' /etc/rc.local
+
+echo "first boot: stopping led trigger"
+led_trigger ACT heartbeat
+led_trigger PWR none
+
+echo "first boot: finished"
+reboot
diff --git a/images/raspberry-pi-2/scripts/mkrootimg b/images/raspberry-pi-2/scripts/mkrootimg
new file mode 100755
index 0000000..ff4f07c
--- /dev/null
+++ b/images/raspberry-pi-2/scripts/mkrootimg
@@ -0,0 +1,107 @@
+#!/bin/bash
+set -e
+
+print_usage() {
+ cat 1>&2 <<EOF
+Usage: $0 <rootfs_directory> <image_file>
+Package the contents of a debian root filesystem into a binary image file, ready to be burned onto an sd card.
+
+This script will create an image with two partitions, the first one for /boot/firmware and the second one for /.
+EOF
+}
+
+fail() {
+ echo "$1" >&2
+ exit 1
+}
+
+log() {
+ echo "mkrootimg: $1" >&2
+}
+
+# Directory to package
+rootfs="$1"
+
+# Binary image file
+image="$2"
+
+# Contains temporary build files
+builddir=$(mktemp -d)
+
+([ -n "$rootfs" ] && [ -n "$image" ]) || fail "$(print_usage)"
+[ -d "$rootfs" ] || fail "$rootfs does not exist or is not a directory"
+
+[ "$EUID" -eq 0 ] || fail "$0 must be run as root"
+
+cleanup() {
+ set +e
+ umount --lazy "$builddir/mount/boot/firmware" 2> /dev/null
+ umount --lazy "$builddir/mount" 2> /dev/null
+ sync
+ losetup --detach "$bootfs_loop" 2> /dev/null
+ losetup --detach "$rootfs_loop" 2> /dev/null
+ rm -rf "$builddir"
+ trap - 0 1 2 3 6
+}
+trap cleanup 0 1 2 3 6
+
+# Partition layout
+#
+# Content Size
+# ---------------------------------------------
+# reserved 1024k (1M, for e.g. a bootloader)
+# bootfs 100*1024k (100M)
+# rootfs as required
+
+# calculate minimum required space for root partition
+# (with 25% overhead for reserved blocks and journaling)
+rootfs_raw_size_min=$(du --block-size=1M -s "$rootfs" | awk '{ print $1 }')
+rootfs_size_min=$(( rootfs_raw_size_min + rootfs_raw_size_min * 25 / 100 ))
+
+# create and partition image file
+truncate --size $(( 1 + 100 + rootfs_size_min ))M "$image"
+parted "$image" --script mklabel msdos
+parted "$image" --script mkpart primary fat32 1M 100M
+parted "$image" --script mkpart primary ext4 100M 100%
+
+# get actual byte offsets of the partitions within the image
+bootfs_start=$(parted --machine --script "$image" unit B print | grep '^1:' | cut -d ':' -f 2 | sed 's/B//g')
+bootfs_size=$(parted --machine --script "$image" unit B print | grep '^1:' | cut -d ':' -f 4 | sed 's/B//g')
+rootfs_start=$(parted --machine --script "$image" unit B print | grep '^2:' | cut -d ':' -f 2 | sed 's/B//g')
+rootfs_size=$(parted --machine --script "$image" unit B print | grep '^2:' | cut -d ':' -f 4 | sed 's/B//g')
+
+# set up temporary loop devices
+log "setting up image loop devices"
+bootfs_loop=$(losetup \
+ --offset "$bootfs_start" \
+ --sizelimit "$bootfs_size" \
+ --find \
+ --show \
+ "$image")
+rootfs_loop=$(losetup \
+ --offset "$rootfs_start" \
+ --sizelimit "$rootfs_size" \
+ --find \
+ --show \
+ "$image")
+
+# format partitions
+log "formatting partitions"
+mkfs.vfat -F 32 "$bootfs_loop" &> /dev/null
+mkfs.ext4 -O^64bit "$rootfs_loop" &> /dev/null
+
+# mount partitions
+log "mounting partitions"
+mkdir -p "$builddir/mount"
+mount "$rootfs_loop" "$builddir/mount"
+mkdir -p "$builddir/mount/boot/firmware"
+mount "$bootfs_loop" "$builddir/mount/boot/firmware"
+
+# copy root filesystem to image
+log "copying root filesystem"
+rsync -a "$rootfs/" "$builddir/mount/"
+
+log "cleaning up"
+cleanup
+
+log "done"