Finalise UEFI support for Raspberry Pi 4

This commit is contained in:
Andreas Zweili 2024-01-08 10:19:48 +01:00
parent 5e83a5049b
commit e9fd402dba
10 changed files with 130 additions and 66 deletions

View File

@ -4,25 +4,26 @@ This repository contains my configuration for my Nixos systems.
I don't provide any garantuees that it will work on other systems. I don't provide any garantuees that it will work on other systems.
In addition some of the scripts required for installation will destroy your data when used. In addition some of the scripts required for installation will destroy your data when used.
## Raspberry Pi installation ## Preparation
1. Add the new system to `flake.nix`. On a PC you don't have to do anything special.
2. Build the image with `scripts/build-raspi-image.sh SYSTEMNAME`
3. Flash the image to an SD card
`dd if=~/Downloads/SYSTEMNAME.img of=/dev/mmcblk0 bs=4M`.
4. After you've booted the Pi get the new SSH key with
`ssh-keyscan hostname.custom.domain` and add it to `scrts/secrets.nix`.
5. Then login into the new Pi and mount the `FIRMWARE` partition with
`sudo mkdir -p /mnt && sudo mount /dev/disk/by-label/FIRMWARE /mnt` and make
sure that your `config.txt` looks like [./systems/raspi4/config.txt](./systems/raspi4/config.txt)
6. Change the password
## x86 installation For a Raspberry Pi you need to prepare the SD card first with a UEFI partition. On a PC navigate into this project and run the following commands:
- `nix-shell`
- `sudo create-uefi-partition.sh`
This will format the SD card at `/dev/mmcblk0`, create a partition and download and copy all the required files for running UEFI on a Pi 4.
## Installation
1. Insert an USB stick with the latest NixOS ISO into your device.
1. `curl https://git.2li.ch/Nebucatnetzer/nixos/archive/master.tar.gz | tar xz` 1. `curl https://git.2li.ch/Nebucatnetzer/nixos/archive/master.tar.gz | tar xz`
2. `cd nixos && nix-shell` 1. `cd nixos && nix-shell setup-shell.nix`
3. `sudo ./scripts/format-disk.py` 1. For a normal PC run: `sudo ./scripts/format-disk.py` on a Raspberry Pi 4 run: `sudo ./scripts/format-sdcard.py`
4. `sudo nixos-install --no-root-passwd --root /mnt --impure --flake .#SYSTEMNAME` 1. `sudo nixos-install --no-root-passwd --root /mnt --impure --flake .#SYSTEMNAME`
When everything is finished you can reboot the system and remove the USB stick. You have now a fully encrypted NixOS system.
## Update remote systems ## Update remote systems

View File

@ -56,7 +56,7 @@
("Literate Haskell" brittany) ("Literate Haskell" brittany)
("Lua" lua-fmt) ("Lua" lua-fmt)
("Markdown" prettier) ("Markdown" prettier)
("Nix" nixpkgs-fmt) ("Nix" nixfmt)
("Objective-C" clang-format) ("Objective-C" clang-format)
("OCaml" ocp-indent) ("OCaml" ocp-indent)
("Perl" perltidy) ("Perl" perltidy)

View File

@ -11,7 +11,10 @@ in {
StrictHostKeyChecking no StrictHostKeyChecking no
UserKnownHostsFile /dev/null UserKnownHostsFile /dev/null
User nixos User nixos
LogLevel QUIET
Host mobile.2li.local
StrictHostKeyChecking no
UserKnownHostsFile /dev/null
Host *.2li.local Host *.2li.local
User andreas User andreas

View File

@ -64,16 +64,20 @@ in {
supportedFilesystems = supportedFilesystems =
lib.mkForce [ "f2fs" "ntfs" "cifs" "ext4" "vfat" "nfs" "nfs4" ]; lib.mkForce [ "f2fs" "ntfs" "cifs" "ext4" "vfat" "nfs" "nfs4" ];
}; };
fileSystems = { fileSystems."/" = {
"/" = { device = "/dev/disk/by-label/NixosSd";
device = "/dev/disk/by-label/NIXOS_SD"; fsType = "ext4";
fsType = "ext4"; options = [ "noatime" ];
options = [ "noatime" ]; };
}; fileSystems."/boot" = {
device = "/dev/disk/by-label/SdBoot";
fsType = "vfat";
}; };
boot = { boot = {
initrd.availableKernelModules = [ initrd.availableKernelModules = [
"cryptd"
"genet" # required for the ethernet to work at initrd
"usbhid" "usbhid"
"usb_storage" "usb_storage"
"vc4" "vc4"
@ -81,13 +85,24 @@ in {
"reset-raspberrypi" # required for vl805 firmware to load "reset-raspberrypi" # required for vl805 firmware to load
]; ];
loader = { initrd.luks.devices."cryptlvmsd".device = "/dev/mmcblk1p2";
grub.enable = false; initrd.network = {
generic-extlinux-compatible.enable = true; enable = true;
ssh = {
enable = true;
port = 22;
shell = "/bin/cryptsetup-askpass";
authorizedKeys =
config.users.users.${config.az-username}.openssh.authorizedKeys.keys;
hostKeys = [
"/etc/secrets/initrd/ssh_host_rsa_key"
"/etc/secrets/initrd/ssh_host_ed25519_key"
];
};
}; };
loader = { systemd-boot.enable = true; };
}; };
boot.extraModulePackages = [ ]; boot.extraModulePackages = [ ];
boot.kernelParams = [ ];
hardware.enableRedistributableFirmware = true; hardware.enableRedistributableFirmware = true;
hardware.pulseaudio.enable = true; hardware.pulseaudio.enable = true;

View File

@ -16,6 +16,8 @@ in {
}; };
config = lib.mkIf cfg.enable { config = lib.mkIf cfg.enable {
boot.kernelParams =
[ "ip=${cfg.ip}::10.7.89.1:255.255.255.0:${cfg.hostname}:eth0" ];
hardware.az-raspi4-base.enable = true; hardware.az-raspi4-base.enable = true;
networking = { networking = {
useDHCP = false; useDHCP = false;

View File

@ -18,6 +18,8 @@ in {
config = lib.mkIf cfg.enable { config = lib.mkIf cfg.enable {
hardware.az-raspi4-base.enable = true; hardware.az-raspi4-base.enable = true;
boot.kernelParams =
[ "ip=10.7.89.159::10.7.89.1:255.255.255.0:mobile:enabcm6e4ei0" ];
boot = { boot = {
kernelModules = [ "libcomposite" ]; kernelModules = [ "libcomposite" ];
loader.raspberryPi.firmwareConfig = "dtoverlay=dwc2"; loader.raspberryPi.firmwareConfig = "dtoverlay=dwc2";

19
scripts/create-uefi.sh Executable file
View File

@ -0,0 +1,19 @@
#! /usr/bin/env nix-shell
#! nix-shell -i bash -p parted unzip curl
# Create the boot partition
parted --script /dev/mmcblk0 mklabel gpt
parted --script /dev/mmcblk0 mkpart ESP fat32 0% 1GiB
parted --script /dev/mmcblk0 set 1 esp on
mkfs.fat -F32 -n SdBoot /dev/mmcblk0p1
# Download and install the UEFI firmware
mkdir -p /tmp/sdcard/boot
mount /dev/mmcblk0p1 /tmp/sdcard/boot
curl -o /tmp/pi4-uefi.zip -L https://github.com/pftf/RPi4/releases/download/v1.35/RPi4_UEFI_Firmware_v1.35.zip
unzip /tmp/pi4-uefi.zip -d /tmp/sdcard/boot
sync
# Cleanup
umount /tmp/sdcard/boot
rm /tmp/pi4-uefi.zip

View File

@ -9,22 +9,17 @@ import sys
def _run_command(command, user_input=""): def _run_command(command, user_input=""):
if user_input: if user_input:
result = subprocess.run(command, result = subprocess.run(
capture_output=True, command, capture_output=True, text=True, check=True, input=user_input
text=True, )
check=True,
input=user_input)
else: else:
result = subprocess.run(command, result = subprocess.run(command, capture_output=True, text=True, check=True)
capture_output=True,
text=True,
check=True)
return result return result
def _get_system_memory(): def _get_system_memory():
mem_bytes = os.sysconf('SC_PAGE_SIZE') * os.sysconf('SC_PHYS_PAGES') mem_bytes = os.sysconf("SC_PAGE_SIZE") * os.sysconf("SC_PHYS_PAGES")
mem_gib = mem_bytes / (1024.**3) mem_gib = mem_bytes / (1024.0**3)
return round(mem_gib) return round(mem_gib)
@ -72,16 +67,16 @@ def _partition_suffix(disk):
def create_boot_partition(disk): def create_boot_partition(disk):
boot_partition = "{}{}1".format(disk, _partition_suffix(disk)) boot_partition = "{}{}1".format(disk, _partition_suffix(disk))
print("Create boot partition {}.".format(boot_partition)) print("Create boot partition {}.".format(boot_partition))
_run_command(["parted", "--script", disk, "mkpart", _run_command(
"ESP", "fat32", "1MiB", "512MiB"]) ["parted", "--script", disk, "mkpart", "ESP", "fat32", "1MiB", "512MiB"]
)
_run_command(["parted", "--script", disk, "set", "1", "esp", "on"]) _run_command(["parted", "--script", disk, "set", "1", "esp", "on"])
_run_command(["mkfs.fat", "-F", "32", "-n", "BOOT", boot_partition]) _run_command(["mkfs.fat", "-F", "32", "-n", "BOOT", boot_partition])
def create_main_partition(disk): def create_main_partition(disk):
print("Create main partition.") print("Create main partition.")
_run_command(["parted", "--script", disk, "mkpart", _run_command(["parted", "--script", disk, "mkpart", "primary", "512MiB", "100%"])
"primary", "512MiB", "100%"])
return "{}{}2".format(disk, _partition_suffix(disk)) return "{}{}2".format(disk, _partition_suffix(disk))
@ -93,21 +88,20 @@ def _create_main_filesystem():
def _create_swap(): def _create_swap():
memory = _get_system_memory() memory = _get_system_memory()
print("Create swap partition of {} GiB in size".format(memory)) print("Create swap partition of {} GiB in size".format(memory))
_run_command(["lvcreate", _run_command(["lvcreate", "-L", "{}G".format(memory), "MainGroup", "-n", "swap"])
"-L",
"{}G".format(memory),
"MainGroup",
"-n",
"swap"])
_run_command(["mkswap", "-L", "swap", "/dev/MainGroup/swap"]) _run_command(["mkswap", "-L", "swap", "/dev/MainGroup/swap"])
def _encrypt_disk(partition_path): def _encrypt_disk(partition_path):
password = getpass.getpass() password = getpass.getpass()
print("Encrypting disk.") print("Encrypting disk.")
_run_command(["cryptsetup", "luksFormat", "-q", _run_command(
"--type", "luks1", partition_path], user_input=password) ["cryptsetup", "luksFormat", "-q", "--type", "luks1", partition_path],
_run_command(["cryptsetup", "open", partition_path, "cryptlvm"], user_input=password) user_input=password,
)
_run_command(
["cryptsetup", "open", partition_path, "cryptlvm"], user_input=password
)
def _setup_lvm(lvm_target): def _setup_lvm(lvm_target):

View File

@ -2,6 +2,7 @@
#! nix-shell -i python3 -p python3 parted #! nix-shell -i python3 -p python3 parted
import getpass import getpass
import os
import subprocess import subprocess
@ -15,24 +16,29 @@ def _run_command(command, user_input=""):
return result return result
def create_partition_table(disk): def read_disks():
print("Create partition table.") output = _run_command(["lsblk", "-dpno", "name"])
_run_command(["parted", "--script", disk, "mklabel", "gpt"]) disks = []
for disk in output.stdout.splitlines():
if "loop" in disk:
continue
disks.append(disk)
return disks
def create_boot_partition(disk): def create_menu(disks):
boot_partition = f"{disk}p1" for position, disk in enumerate(disks):
print(f"Create boot partition {boot_partition}.") print("{}: {}".format(position, disk))
_run_command(
["parted", "--script", disk, "mkpart", "ESP", "fat32", "1MiB", "1024MiB"]
) def get_disk_to_format():
_run_command(["parted", "--script", disk, "set", "1", "esp", "on"]) disk_to_format = input("Which disk dou you want to format?: ")
_run_command(["mkfs.fat", "-F", "32", "-n", "SdBoot", boot_partition]) return int(disk_to_format)
def create_main_partition(disk): def create_main_partition(disk):
print("Create main partition.") print("Create main partition.")
_run_command(["parted", "--script", disk, "mkpart", "primary", "1024MiB", "100%"]) _run_command(["parted", "--script", disk, "mkpart", "primary", "1GiB", "100%"])
return f"{disk}p2" return f"{disk}p2"
@ -67,12 +73,20 @@ def create_file_systems(partition):
_create_main_filesystem() _create_main_filesystem()
def mount_partitions():
print("Mounting partitions.")
_run_command(["mount", "/dev/MainGroupSd/sdroot", "/mnt"])
os.mkdir("/mnt/boot")
_run_command(["mount", "/dev/disk/by-label/SdBoot", "/mnt/boot"])
def main(): def main():
disk_to_format = "/dev/mmcblk0" disks = read_disks()
create_partition_table(disk_to_format) create_menu(disks)
create_boot_partition(disk_to_format) disk_to_format = disks[get_disk_to_format()]
main_partition = create_main_partition(disk_to_format) main_partition = create_main_partition(disk_to_format)
create_file_systems(main_partition) create_file_systems(main_partition)
mount_partitions()
if __name__ == "__main__": if __name__ == "__main__":

14
setup-shell.nix Normal file
View File

@ -0,0 +1,14 @@
{ pkgs ? import <nixpkgs> { } }:
pkgs.mkShell {
name = "nixosbuildshell";
nativeBuildInputs = with pkgs; [ nixFlakes ];
shellHook = ''
PATH=${
pkgs.writeShellScriptBin "nix" ''
${pkgs.nixFlakes}/bin/nix --experimental-features "nix-command flakes" "$@"
''
}/bin:$PATH
'';
}