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.
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`.
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
On a PC you don't have to do anything special.
## 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`
2. `cd nixos && nix-shell`
3. `sudo ./scripts/format-disk.py`
4. `sudo nixos-install --no-root-passwd --root /mnt --impure --flake .#SYSTEMNAME`
1. `cd nixos && nix-shell setup-shell.nix`
1. For a normal PC run: `sudo ./scripts/format-disk.py` on a Raspberry Pi 4 run: `sudo ./scripts/format-sdcard.py`
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

View File

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

View File

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

View File

@ -64,16 +64,20 @@ in {
supportedFilesystems =
lib.mkForce [ "f2fs" "ntfs" "cifs" "ext4" "vfat" "nfs" "nfs4" ];
};
fileSystems = {
"/" = {
device = "/dev/disk/by-label/NIXOS_SD";
fsType = "ext4";
options = [ "noatime" ];
};
fileSystems."/" = {
device = "/dev/disk/by-label/NixosSd";
fsType = "ext4";
options = [ "noatime" ];
};
fileSystems."/boot" = {
device = "/dev/disk/by-label/SdBoot";
fsType = "vfat";
};
boot = {
initrd.availableKernelModules = [
"cryptd"
"genet" # required for the ethernet to work at initrd
"usbhid"
"usb_storage"
"vc4"
@ -81,13 +85,24 @@ in {
"reset-raspberrypi" # required for vl805 firmware to load
];
loader = {
grub.enable = false;
generic-extlinux-compatible.enable = true;
initrd.luks.devices."cryptlvmsd".device = "/dev/mmcblk1p2";
initrd.network = {
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.kernelParams = [ ];
hardware.enableRedistributableFirmware = true;
hardware.pulseaudio.enable = true;

View File

@ -16,6 +16,8 @@ in {
};
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;
networking = {
useDHCP = false;

View File

@ -18,6 +18,8 @@ in {
config = lib.mkIf cfg.enable {
hardware.az-raspi4-base.enable = true;
boot.kernelParams =
[ "ip=10.7.89.159::10.7.89.1:255.255.255.0:mobile:enabcm6e4ei0" ];
boot = {
kernelModules = [ "libcomposite" ];
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=""):
if user_input:
result = subprocess.run(command,
capture_output=True,
text=True,
check=True,
input=user_input)
result = subprocess.run(
command, capture_output=True, text=True, check=True, input=user_input
)
else:
result = subprocess.run(command,
capture_output=True,
text=True,
check=True)
result = subprocess.run(command, capture_output=True, text=True, check=True)
return result
def _get_system_memory():
mem_bytes = os.sysconf('SC_PAGE_SIZE') * os.sysconf('SC_PHYS_PAGES')
mem_gib = mem_bytes / (1024.**3)
mem_bytes = os.sysconf("SC_PAGE_SIZE") * os.sysconf("SC_PHYS_PAGES")
mem_gib = mem_bytes / (1024.0**3)
return round(mem_gib)
@ -72,16 +67,16 @@ def _partition_suffix(disk):
def create_boot_partition(disk):
boot_partition = "{}{}1".format(disk, _partition_suffix(disk))
print("Create boot partition {}.".format(boot_partition))
_run_command(["parted", "--script", disk, "mkpart",
"ESP", "fat32", "1MiB", "512MiB"])
_run_command(
["parted", "--script", disk, "mkpart", "ESP", "fat32", "1MiB", "512MiB"]
)
_run_command(["parted", "--script", disk, "set", "1", "esp", "on"])
_run_command(["mkfs.fat", "-F", "32", "-n", "BOOT", boot_partition])
def create_main_partition(disk):
print("Create main partition.")
_run_command(["parted", "--script", disk, "mkpart",
"primary", "512MiB", "100%"])
_run_command(["parted", "--script", disk, "mkpart", "primary", "512MiB", "100%"])
return "{}{}2".format(disk, _partition_suffix(disk))
@ -93,21 +88,20 @@ def _create_main_filesystem():
def _create_swap():
memory = _get_system_memory()
print("Create swap partition of {} GiB in size".format(memory))
_run_command(["lvcreate",
"-L",
"{}G".format(memory),
"MainGroup",
"-n",
"swap"])
_run_command(["lvcreate", "-L", "{}G".format(memory), "MainGroup", "-n", "swap"])
_run_command(["mkswap", "-L", "swap", "/dev/MainGroup/swap"])
def _encrypt_disk(partition_path):
password = getpass.getpass()
print("Encrypting disk.")
_run_command(["cryptsetup", "luksFormat", "-q",
"--type", "luks1", partition_path], user_input=password)
_run_command(["cryptsetup", "open", partition_path, "cryptlvm"], user_input=password)
_run_command(
["cryptsetup", "luksFormat", "-q", "--type", "luks1", partition_path],
user_input=password,
)
_run_command(
["cryptsetup", "open", partition_path, "cryptlvm"], user_input=password
)
def _setup_lvm(lvm_target):

View File

@ -2,6 +2,7 @@
#! nix-shell -i python3 -p python3 parted
import getpass
import os
import subprocess
@ -15,24 +16,29 @@ def _run_command(command, user_input=""):
return result
def create_partition_table(disk):
print("Create partition table.")
_run_command(["parted", "--script", disk, "mklabel", "gpt"])
def read_disks():
output = _run_command(["lsblk", "-dpno", "name"])
disks = []
for disk in output.stdout.splitlines():
if "loop" in disk:
continue
disks.append(disk)
return disks
def create_boot_partition(disk):
boot_partition = f"{disk}p1"
print(f"Create boot partition {boot_partition}.")
_run_command(
["parted", "--script", disk, "mkpart", "ESP", "fat32", "1MiB", "1024MiB"]
)
_run_command(["parted", "--script", disk, "set", "1", "esp", "on"])
_run_command(["mkfs.fat", "-F", "32", "-n", "SdBoot", boot_partition])
def create_menu(disks):
for position, disk in enumerate(disks):
print("{}: {}".format(position, disk))
def get_disk_to_format():
disk_to_format = input("Which disk dou you want to format?: ")
return int(disk_to_format)
def create_main_partition(disk):
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"
@ -67,12 +73,20 @@ def create_file_systems(partition):
_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():
disk_to_format = "/dev/mmcblk0"
create_partition_table(disk_to_format)
create_boot_partition(disk_to_format)
disks = read_disks()
create_menu(disks)
disk_to_format = disks[get_disk_to_format()]
main_partition = create_main_partition(disk_to_format)
create_file_systems(main_partition)
mount_partitions()
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
'';
}