Dual Booting NixOS and Windows: Difference between revisions
imported>Makefu initial batch of nixos-users |
m Add category booting |
||
(31 intermediate revisions by 20 users not shown) | |||
Line 1: | Line 1: | ||
This section explains various methods to have the [[bootloader]] prompt whether to boot windows or NixOS. | |||
== Autodetection == | |||
< | === systemd-boot === | ||
When {{ic|systemd-boot}} is installed to the same EFI System Partition (ESP) that Windows uses, it will automatically detect the Windows installation ({{ic|/EFI/Microsoft/Boot/bootmgfw.efi}}) and present it as a boot option. | |||
You can verify detected boot loaders by running the {{ic|bootctl}} command. | |||
A system pre-installed with Windows might have a small ESP partition size that is not sufficient to store the kernel and initrd files for multiple NixOS generations. One solution is to create an additional [https://uapi-group.org/specifications/specs/boot_loader_specification/#the-partitions XBOOTLDR] partition and configure {{ic|systemd-boot}} to use it: | |||
{{File|/etc/nixos/configuration.nix|nix|<nowiki> | |||
{ | |||
fileSystems."/boot" = | |||
{ device = "/dev/disk/by-uuid/57D4-A2B2"; | |||
fsType = "vfat"; | |||
}; | |||
fileSystems."/efi" = | |||
{ device = "/dev/disk/by-uuid/3280-5418"; | |||
fsType = "vfat"; | |||
}; | |||
boot.loader.systemd-boot.enable = true; | |||
boot.loader.efi.canTouchEfiVariables = true; | |||
boot.loader.efi.efiSysMountPoint = "/efi"; | |||
boot.loader.systemd-boot.xbootldrMountPoint = "/boot"; | |||
} | |||
</nowiki>}} | |||
=== os-prober === | |||
<code>os-prober</code> is a tool to autodetect which other systems are present on the machine. Grub can be | |||
told to use os-prober to add a menu-entry for each of them. | |||
{{File|/etc/nixos/configuration.nix|nix|<nowiki> | |||
{ config, pkgs, ... }: { | |||
# ... | |||
boot.loader.grub.enable = true; | boot.loader.grub.enable = true; | ||
boot.loader.grub. | boot.loader.grub.device = "nodev"; | ||
boot.loader.grub.device = | boot.loader.grub.useOSProber = true; | ||
# ... | |||
}</nowiki>}} | |||
== Manual configuration == | |||
In case <code>os-prober</code> does not detect your windows partition you can configure your bootloader manually to find it. | |||
=== MBR === | |||
All MBR bootloaders will need at least some configuration to chainload Windows. | |||
==== Grub ==== | |||
Here is an example config: | |||
{{File|/etc/nixos/configuration.nix|nix|<nowiki> | |||
{ config, pkgs, ... }: { | |||
# ... | |||
boot.loader.grub.enable = true; | |||
boot.loader.grub.device = "/dev/sda"; | |||
boot.loader.grub.extraEntries = '' | boot.loader.grub.extraEntries = '' | ||
menuentry | menuentry "Windows 7" { | ||
chainloader (hd0,1)+1 | chainloader (hd0,1)+1 | ||
} | } | ||
''; | ''; | ||
}</ | }</nowiki>}} | ||
Source: https://www.reddit.com/r/NixOS/comments/31lx3i/windows_and_nixos_dual_boot/ | Source: https://www.reddit.com/r/NixOS/comments/31lx3i/windows_and_nixos_dual_boot/ | ||
= | === UEFI === | ||
After setting up a 256mb EFI Partition dualboot should work out of the box (at least for windows10) | After setting up a 256mb EFI Partition dualboot should work out of the box (at least for windows10) | ||
Source: https://zimbatm.com/journal/2016/09/09/nixos-window-dual-boot/ | Source: [https://web.archive.org/web/20170523065625/https://zimbatm.com/journal/2016/09/09/nixos-window-dual-boot/ zimbatm.com/journal/2016/09/09/nixos-window-dual-boot] | ||
Here is another article that documents dual booting NixOS and Windows on a Lenovo ThinkPad X1 Carbon (6th Gen): https://github.com/andywhite37/nixos/blob/master/DUAL_BOOT_WINDOWS_GUIDE.md | |||
==== Grub ==== | |||
Here we assume: | |||
* the EFI partition has been mounted on <nowiki>/boot/efi</nowiki> | |||
* <code>$FS_UUID</code> is the UUID of the EFI partition | |||
* the <code>boot.loader.systemd-boot.enable = true;</code> line added to configuration.nix by <code>nixos-generate-config</code> has been removed | |||
{{File|/etc/nixos/configuration.nix|nix|<nowiki> | |||
{ config, ... }: | |||
{ | |||
boot.loader = { | |||
efi = { | |||
canTouchEfiVariables = true; | |||
# assuming /boot is the mount point of the EFI partition in NixOS (as the installation section recommends). | |||
efiSysMountPoint = "/boot"; | |||
}; | |||
grub = { | |||
# despite what the configuration.nix manpage seems to indicate, | |||
# as of release 17.09, setting device to "nodev" will still call | |||
# `grub-install` if efiSupport is true | |||
# (the devices list is not used by the EFI grub install, | |||
# but must be set to some value in order to pass an assert in grub.nix) | |||
devices = [ "nodev" ]; | |||
efiSupport = true; | |||
enable = true; | |||
# set $FS_UUID to the UUID of the EFI partition | |||
extraEntries = '' | |||
menuentry "Windows" { | |||
insmod part_gpt | |||
insmod fat | |||
insmod search_fs_uuid | |||
insmod chain | |||
search --fs-uuid --set=root $FS_UUID | |||
chainloader /EFI/Microsoft/Boot/bootmgfw.efi | |||
} | |||
''; | |||
version = 2; | |||
}; | |||
}; | |||
}</nowiki>}} | |||
==== EFI with multiple disks ==== | |||
===== systemd-boot ===== | |||
As systemd-boot cannot directly load binaries from other ESPs<ref>https://github.com/systemd/systemd/issues/3252</ref>, let alone other disks, we have to employ [https://search.nixos.org/packages?channel=unstable&show=edk2-uefi-shell&from=0&size=50&sort=relevance&type=packages&query=edk2-uefi-shell edk2-uefi-shell] to implement a chainloading strategy<ref>https://wiki.archlinux.org/title/Systemd-boot#Boot_from_another_disk</ref>. The basic config looks like this:{{File|/etc/nixos/configuration.nix|nix|<nowiki> | |||
{ ... }: | |||
{ | |||
boot.loader = { | |||
efi.canTouchEfiVariables = true; | |||
systemd-boot = { | |||
enable = true; | |||
windows = { | |||
"windows" = | |||
let | |||
# To determine the name of the windows boot drive, boot into edk2 first, then run | |||
# `map -c` to get drive aliases, and try out running `FS1:`, then `ls EFI` to check | |||
# which alias corresponds to which EFI partition. | |||
boot-drive = "FS1"; | |||
in | |||
{ | |||
title = "Windows"; | |||
efiDeviceHandle = boot-drive; | |||
sortKey = "y_windows"; | |||
}; | |||
}; | |||
edk2-uefi-shell.enable = true; | |||
edk2-uefi-shell.sortKey = "z_edk2"; | |||
}; | |||
}; | |||
}</nowiki>}}You can try if this works without changes, but most likely you have to modify the value of <code>boot-drive</code> first to match your hardware configuration. | |||
First, make sure you <code>nixos-rebuild switch</code> or <code>nixos-rebuild boot</code> , then reboot your machine and select the entry "EDK2 UEFI Shell" from the systemd-boot menu. In this shell, run the command <code>map -c</code> to get a list of all "consistent" device mappings:<syntaxhighlight lang="text"> | |||
Press ESC in 1 seconds to skip startup.nsh or any other key to continue. | |||
Shell> map -c | |||
Mapping table | |||
HD0c3: Alias(s):FS0:;BLK7: | |||
PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)/HD(3,GPT,5CBAF773-8FFA-11EB-952D-FCAA14203853,0x1DAA6000,0x32000) | |||
HD0d1: Alias(s):FS1:;BLK10: | |||
PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)/HD(1,GPT,7F623BEA-5891-49EE-9980-6534716F0F50,0x800,0x1F4000) | |||
</syntaxhighlight>Then, change to each of these drives by entering the drive name (not one of the aliases!) and check whether the Windows bootloader is present:<syntaxhighlight lang="text"> | |||
Shell> HD0d1: | |||
HD0d1:\> ls EFI | |||
Directory of: HD0d1:\EFI\ | |||
09/21/2024 22:05 <DIR> 4,096 . | |||
09/21/2024 22:05 <DIR> 0 .. | |||
09/21/2024 23:08 <DIR> 4,096 BOOT | |||
09/21/2024 22:05 <DIR> 4,096 Linux | |||
09/24/2024 08:30 <DIR> 4,096 nixos | |||
01/01/1980 00:00 1,060,672 shell.efi | |||
09/21/2024 23:08 <DIR> 4,096 systemd | |||
1 File(s) 1,060,672 bytes | |||
6 Dir(s) | |||
HD0d1:\> HD0c3: | |||
HD0c3:\> ls EFI | |||
Directory of: HD0c3:\EFI\ | |||
03/28/2021 21:28 <DIR> 1,024 . | |||
03/28/2021 21:28 <DIR> 0 .. | |||
03/28/2021 21:28 <DIR> 1,024 Boot | |||
03/28/2021 21:28 <DIR> 1,024 Microsoft | |||
0 File(s) 0 bytes | |||
4 Dir(s) | |||
</syntaxhighlight>In this case, HD0d1 is the ESP of our NixOS installation, and HD0c3 is the ESP of Windows. | |||
After entering the Windows ESP, you can boot into it by running <code>EFI\Microsoft\Boot\Bootmgfw.efi</code>. This is also useful if you have multiple Windows installations and want to find out which ESP belongs to which installation. | |||
After this, you can change the value of <code>boot-drive</code> in the configuration snippet above, <code>nixos-rebuild switch</code> and reboot to boot into windows. Make sure that you use the actual device name, not one of the aliases, as these might not be available immediately on boot, making the shell invocation fail. | |||
===== Grub ===== | |||
In Grub, the following might work: | |||
{{File|/etc/nixos/configuration.nix|nix|<nowiki> | |||
{ config, ... }: | |||
{ | |||
boot.loader = { | |||
efi.canTouchEfiVariables = true; | |||
grub = { | |||
enable = true; | |||
devices = [ "nodev" ]; | |||
efiSupport = true; | |||
useOSProber = true; | |||
}; | |||
}; | |||
}</nowiki>}} | |||
== System time == | |||
System clock might be incorrect after booting Windows and going back to NixOS. | |||
It can be fixed by setting RTC time standard to UTC on Windows (''recommended'', see [https://wiki.archlinux.org/title/System_time#UTC_in_Microsoft_Windows how to do this]). | |||
Alternatively, you can set NixOS RTC time standard to localtime, compatible with Windows in its default configuration: | |||
{{file|/etc/nixos/configuration.nix|nix|<nowiki> | |||
{ | |||
time.hardwareClockInLocalTime = true; | |||
}</nowiki>}} | |||
See [https://wiki.archlinux.org/title/System_time#Time_standard Arch Linux wiki#System time] for discussion of both options. | |||
== See also == | |||
* [[GNU GRUB]] | |||
* [https://wiki.archlinux.org/index.php/GRUB#Windows_installed_in_UEFI-GPT_Mode_menu_entry Arch Linux wiki#GRUB] | |||
* [https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/system/boot/loader/grub/install-grub.pl NixOS GRUB installer] (check the code block beginning with <nowiki># install EFI GRUB</nowiki>) | |||
[[Category:Cookbook]] | |||
[[Category:NixOS]] | |||
[[Category:Booting]] |