windows sits on the 476g nvme - the disk with three partitions: a 16m
"microsoft reserved" msr with no filesystem, the 476g ntfs c: volume, and
a 832m winre. it has no efi system partition of its own, because it was
installed against the esp that nixos now owns (fs-uuid 5873-AD05). both
oses therefore boot from one shared esp; there is no separate windows
boot drive.
the nixos install reformatted that esp, which wiped
EFI/Microsoft/Boot/{bootmgfw.efi,BCD} and left windows unbootable. that
has since been repaired from winre, so the entry is live. the bcdboot
command is kept in the comment for the next time the esp is reformatted -
it has to run from windows media or winre because the bcd store cannot be
generated from linux, and copying bootmgfw.efi alone fails 0xc000000f.
chainloaded explicitly rather than via grub.useOSProber: deterministic,
pulls in no extra tooling, and avoids probing every disk on each
bootloader install. the -f guard makes the entry self-disabling, so a
future esp reformat degrades to a missing menu item rather than one that
boots into an error. because grub evaluates it at boot rather than at nix
eval time, repairing windows needed no rebuild.
searching by fs-uuid rather than (hdX,gptN) is deliberate: nvme
enumeration is not stable on this board, and /boot has been seen as both
nvme0n1p1 and nvme1n1p1. the -n "$esp" test is a separate nested if
rather than `[ -n "$esp" -a -f ... ]` because grub's test builtin
evaluates both operands of -a instead of short-circuiting, so the
combined form would still expand the path test against an unset device.
100 lines
4.8 KiB
Nix
100 lines
4.8 KiB
Nix
{
|
|
self,
|
|
inputs,
|
|
...
|
|
}: {
|
|
flake.nixosModules.shadowConfiguration = {...}: {
|
|
networking = {
|
|
hostName = "shadow";
|
|
};
|
|
|
|
# Windows lives on the 476G NVMe -- the one with three partitions: 16M
|
|
# "Microsoft reserved" MSR, 476G NTFS (fs-uuid 70E4E841E4E80AE4, the C:
|
|
# volume), 832M WinRE. Identified by layout rather than by nvmeXnY on
|
|
# purpose; see the enumeration note below.
|
|
#
|
|
# That disk has NO EFI System Partition of its own -- its 16M partition is a
|
|
# "Microsoft reserved" MSR with no filesystem. Windows was installed against
|
|
# the ESP that NixOS now owns: the 1G vfat partition fs-uuid 5873-AD05 on the
|
|
# 1.9T NVMe (that disk holds only two partitions, the ESP and the ext4 root
|
|
# deff63fc-1738-4cfc-a79c-06e58c78471a). So both OSes boot from one shared
|
|
# ESP; there is no separate Windows boot drive.
|
|
#
|
|
# The NixOS install reformatted that ESP, which wiped
|
|
# EFI/Microsoft/Boot/{bootmgfw.efi,BCD} and left Windows unbootable. That has
|
|
# since been repaired from WinRE and both files are back in place, so the
|
|
# menuentry below is live. Keep the recovery command to hand in case the ESP
|
|
# is ever reformatted again -- it has to be run from Windows install media or
|
|
# WinRE, because the BCD store cannot be generated from Linux:
|
|
#
|
|
# bcdboot C:\Windows /s S: /f UEFI (S: = the ESP, fs-uuid 5873-AD05)
|
|
#
|
|
# Copying bootmgfw.efi alone is not enough; without BCD it fails 0xc000000f.
|
|
# Note bcdboot also drops a copy of the Windows boot manager at
|
|
# EFI/BOOT/bootx64.efi -- see the fallback-path note in core/boot.nix.
|
|
#
|
|
# Chainloaded explicitly rather than via grub.useOSProber: deterministic,
|
|
# pulls in no extra tooling, and avoids probing every disk on each bootloader
|
|
# install. The `-f` guard makes the entry self-disabling: it renders only
|
|
# while bootmgfw.efi is actually present, so a future ESP reformat degrades
|
|
# to a missing menu item rather than one that boots into an error.
|
|
#
|
|
# fs-uuid is shadow's ESP, matching the "/boot" entry in disks.nix. Searching
|
|
# by UUID rather than (hdX,gptN) matters here: NVMe enumeration is not stable
|
|
# on this board -- /boot has been seen as both nvme0n1p1 and nvme1n1p1. For
|
|
# the same reason, re-derive device names before running anything
|
|
# destructive:
|
|
#
|
|
# lsblk -o NAME,SIZE,FSTYPE,PARTTYPENAME,UUID,MOUNTPOINT
|
|
#
|
|
# Windows' boot files now occupy ~30-60MiB of that shared 1G ESP and Windows
|
|
# Update rewrites them periodically, which is part of why
|
|
# grub.configurationLimit is held at 10 in core/boot.nix.
|
|
#
|
|
# Before dual-booting, turn off Windows Fast Startup. hiberfil.sys is present
|
|
# on the 476G NTFS volume, and Fast Startup plus this host's hibernation
|
|
# setup will corrupt any NTFS volume mounted read-write from both sides.
|
|
#
|
|
# On the GRUB script itself:
|
|
#
|
|
# The outer `search` + `-f` test run at *boot*, while GRUB parses grub.cfg —
|
|
# not at Nix eval time. That is why repairing Windows needed no rebuild: the
|
|
# entry started rendering as soon as bcdboot put bootmgfw.efi back, and it
|
|
# will stop again by itself if the file disappears.
|
|
#
|
|
# The `-n "$esp"` test is a *separate,
|
|
# nested* if rather than `[ -n "$esp" -a -f ... ]`: a failed search leaves
|
|
# $esp unset, and GRUB's `test` builtin evaluates both operands of `-a`
|
|
# rather than short-circuiting, so the combined form would still expand the
|
|
# `-f` to `()/...` and could complain about a bad device on every boot.
|
|
# Nesting guarantees the path test is not reached at all.
|
|
#
|
|
# No `insmod` is needed for the outer search: GRUB's EFI core image already
|
|
# embeds part_gpt/fat/search_fs_uuid, since it must find its own $prefix on
|
|
# the FAT ESP before reading this file. NixOS' own install-grub.pl relies on
|
|
# exactly that for the search it emits. The insmods inside the menuentry are
|
|
# kept only because `chain` genuinely is a separate module.
|
|
#
|
|
# The inner `search` deliberately repeats the outer one rather than reusing
|
|
# `set root=$esp`. It costs one extra disk scan, and only when the entry is
|
|
# actually selected, in exchange for a menuentry that is self-contained and
|
|
# cannot be broken by anything that clobbers $esp in between. This also
|
|
# matches the per-entry search install-grub.pl generates.
|
|
boot.loader.grub.extraEntries = ''
|
|
search --no-floppy --set=esp --fs-uuid 5873-AD05
|
|
if [ -n "$esp" ]; then
|
|
if [ -f ($esp)/EFI/Microsoft/Boot/bootmgfw.efi ]; then
|
|
menuentry "Windows Boot Manager" --class windows --class os {
|
|
insmod part_gpt
|
|
insmod fat
|
|
insmod chain
|
|
search --no-floppy --set=root --fs-uuid 5873-AD05
|
|
chainloader /EFI/Microsoft/Boot/bootmgfw.efi
|
|
}
|
|
fi
|
|
fi
|
|
'';
|
|
};
|
|
}
|
|
|