First shot at EFI booting.

Note: This feature is INCOMPLETE. Moreover, when runEfibootmgr is true it will
MODIFY NVRAM and, on Apple systems, possibly brick your firmware. PLEASE be
careful while further testing is performed

svn path=/nixos/trunk/; revision=33047
This commit is contained in:
Shea Levy 2012-03-13 19:27:59 +00:00
parent db0e7787ce
commit 001fcad421
4 changed files with 219 additions and 0 deletions

View file

@ -0,0 +1,118 @@
#! @bash@/bin/sh -e
shopt -s nullglob
export PATH=/empty
for i in @path@; do PATH=$PATH:$i/bin:$i/sbin; done
default=$1
if test -z "$1"; then
echo "Syntax: efi-boot-stub-builder.sh <DEFAULT-CONFIG>"
exit 1
fi
echo "updating the efi system partition..."
# Convert a path to a file in the Nix store such as
# /nix/store/<hash>-<name>/file to <hash>-<name>-<file>.
# Also, efi executables need the .efi extension
cleanName() {
local path="$1"
echo "$path" | sed 's|^/nix/store/||' | sed 's|/|-|g' | sed 's|@kernelFile@$|@kernelFile@.efi|'
}
# Copy a file from the Nix store to the EFI system partition
declare -A filesCopied
copyToKernelsDir() {
local src="$1"
local dst="@efiSysMountPoint@/efi/nixos/$(cleanName $src)"
# Don't copy the file if $dst already exists. This means that we
# have to create $dst atomically to prevent partially copied
# kernels or initrd if this script is ever interrupted.
if ! test -e $dst; then
local dstTmp=$dst.tmp.$$
cp $src $dstTmp
mv $dstTmp $dst
fi
filesCopied[$dst]=1
result=$dst
}
# Copy its kernel, initrd, and startup script to the efi system partition
# Add the efibootmgr entry if requested
addEntry() {
local path="$1"
local generation="$2"
if ! test -e $path/kernel -a -e $path/initrd; then
return
fi
local kernel=$(readlink -f $path/kernel)
local initrd=$(readlink -f $path/initrd)
copyToKernelsDir $kernel; kernel=$result
copyToKernelsDir $initrd; initrd=$result
local startup="@efiSysMountPoint@/efi/nixos/$(cleanName $(readlink -f $path))-startup.nsh"
if ! test -e $startup; then
local dstTmp=$startup.tmp.$$
echo "$(echo $kernel | sed 's|@efiSysMountPoint@||' | sed 's|/|\\|g') systemConfig=$(readlink -f $path) init=$(readlink -f $path/init) initrd=$(echo $initrd | sed 's|@efiSysMountPoint@||' | sed 's|/|\\|g') $(cat $path/kernel-params)" > $dstTmp
mv $dstTmp $startup
fi
filesCopied[$startup]=1
if test -n "@runEfibootmgr@"; then
set +e
efibootmgr -c -d "@efiDisk@" -g -l $(echo $kernel | sed 's|@efiSysMountPoint@||' | sed 's|/|\\|g') -L "NixOS $generation Generation" -p "@efiPartition@" \
-u systemConfig=$(readlink -f $path) init=$(readlink -f $path/init) initrd=$(echo $initrd | sed 's|@efiSysMountPoint@||' | sed 's|/|\\|g') $(cat $path/kernel-params)
set -e
fi
if test $(readlink -f "$path") = "$default"; then
if test -n "@runEfibootmgr@"; then
set +e
defaultbootnum=$(efibootmgr | grep "NixOS $generation Generation" | sed 's/Boot//' | sed 's/\*.*//')
set -e
fi
if test -n "@installStartupNsh@"; then
sed 's|.*@kernelFile@.efi|@kernelFile@.efi|' < $startup > "@efiSysMountPoint@/startup.nsh"
cp $kernel "@efiSysMountPoint@/@kernelFile@.efi"
fi
fi
}
mkdir -p "@efiSysMountPoint@/efi/nixos/"
# Remove all old boot manager entries
if test -n "@runEfibootmgr@"; then
set +e
modprobe efivars
for bootnum in $(efibootmgr | grep "NixOS" | grep "Generation" | sed 's/Boot//' | sed 's/\*.*//'); do
efibootmgr -B -b "$bootnum"
set -e
done
fi
# Add all generations of the system profile to the system partition, in reverse
# (most recent to least recent) order.
for generation in $(
(cd /nix/var/nix/profiles && ls -d system-*-link) \
| sed 's/system-\([0-9]\+\)-link/\1/' \
| sort -n -r); do
link=/nix/var/nix/profiles/system-$generation-link
addEntry $link $generation
done
if test -n "@runEfibootmgr@"; then
set +e
efibootmgr -o $defaultbootnum
set -e
fi
# Remove obsolete files from the EFI system partition
for fn in "@efiSysMountPoint@/efi/nixos/"*; do
if ! test "${filesCopied[$fn]}" = 1; then
rm -vf -- "$fn"
fi
done

View file

@ -0,0 +1,98 @@
{pkgs, config, ...}:
###### interface
let
inherit (pkgs.lib) mkOption mkIf;
options = {
boot = {
loader = {
efiBootStub = {
enable = mkOption {
default = false;
description = ''
Whether to use the linux kernel as an EFI bootloader.
When enabled, the kernel, initrd, and an EFI shell script
to boot the system are copied to the EFI system partition.
'';
};
efiDisk = mkOption {
default = "/dev/sda";
description = ''
The disk that contains the EFI system partition. Only used by
efibootmgr
'';
};
efiPartition = mkOption {
default = "1";
description = ''
The partition number of the EFI system partition. Only used by
efibootmgr
'';
};
efiSysMountPoint = mkOption {
default = "/boot";
description = ''
Where the EFI System Partition is mounted.
'';
};
runEfibootmgr = mkOption {
default = false;
description = ''
Whether to run efibootmgr to add the configuration to the boot options list.
WARNING! efibootmgr has been rumored to brick Apple firmware! Use 'bless' on
Apple efi systems.
'';
};
installStartupNsh = mkOption {
default = false;
description = ''
Whether to install a startup.nsh in the root of the EFI system partition.
For now, it will just boot the latest version when run, the eventual goal
is to have a basic menu-type interface.
'';
};
};
};
};
};
in
###### implementation
let
efiBootStubBuilder = pkgs.substituteAll {
src = ./efi-boot-stub-builder.sh;
isExecutable = true;
inherit (pkgs) bash;
path = [pkgs.coreutils pkgs.gnused pkgs.gnugrep] ++ (pkgs.stdenv.lib.optionals config.boot.loader.efiBootStub.runEfibootmgr [pkgs.efibootmgr pkgs.module_init_tools]);
inherit (config.boot.loader.efiBootStub) efiSysMountPoint runEfibootmgr installStartupNsh efiDisk efiPartition;
kernelFile = platform.kernelTarget;
};
# Temporary check, for nixos to cope both with nixpkgs stdenv-updates and trunk
platform = pkgs.stdenv.platform;
in
{
require = [
options
# config.system.build
# ../system/system-options.nix
];
system = mkIf config.boot.loader.efiBootStub.enable {
build = {
menuBuilder = efiBootStubBuilder;
};
boot.loader.id = "efiBootStub";
boot.loader.kernelFile = platform.kernelTarget;
};
}

View file

@ -22,6 +22,7 @@
./hardware/network/rtl8192c.nix
./hardware/pcmcia.nix
./hardware/all-firmware.nix
./installer/efi-boot-stub/efi-boot-stub.nix
./installer/generations-dir/generations-dir.nix
./installer/grub/grub.nix
./installer/init-script/init-script.nix

View file

@ -50,6 +50,8 @@ if [ "$action" = "switch" -o "$action" = "boot" ]; then
elif [ "@bootLoader@" = "generationsDir" ]; then
@menuBuilder@ @out@
elif [ "@bootLoader@" = "efiBootStub" ]; then
@menuBuilder@ @out@
else
echo "Warning: don't know how to make this configuration bootable; please enable a boot loader." 1>&2
fi