NixOS and Windows 10 on the XPS 13 9370

I recently purchased the XPS 13 9370 (Notebookcheck felt the least biased) and have been spending the past couple of weeks tinkering and playing around with my dev environment to see what felt the best. It turned out that dual-booting NixOS (or any Linux distro for that matter) and Windows 10 side-by-side was non-trivial given the factory laptop configuration.

This will be a series of posts that aims to document my process so that those interested can get up-and-running with a bit less pain. Note that this first section goes into what went astray purely for contextual reasons, the helpful instructions follow-on after. I should also mention that as always, the Arch Wiki has greatly facilitated the learning process.

Out-of-the-box

If you chose to have Windows 10 installed by default, the XPS 13 should come with about five partitions. Running Windows 10 Disk Management should show something along the lines of ~512MB for the boot partition, ~220GB for Windows 10, and three other mystery partitions. I could not stand having, unexplained, occupied space on my drive, so with a bit of help from a colleague, diskpart, and the internet, we found out that said mystery partitions contained Dell’s factory install data for recovery purposes.

Going forward, I shrunk the Windows 10 partition down to ~90GB to create ~130GB of unallocated space to install NixOS in. I would only be using Windows sparsely for some light gaming (think Subset Game’s FTL), and perhaps a touch of Photoshop, etc. so I didn’t need too much space there.

Secure Boot, SATA mode, and Bitlocker troubles

Against the instruction of the NixOS manual, I used Rufus to create a bootable USB drive with the latest minimal (no-GUI) disk image of NixOS (18.03 at the time of writing). Rufus settings were pretty-much default - I tested both MBR and GPT partition schemes and either worked fine for booting the USB drive in UEFI mode, which was what I wanted.

In order to boot via the USB drive, some UEFI options were changed. Most importantly, Secure Boot was turned off. This is covered in more detail in the latter instructions. Once I was able to boot into NixOS on the USB drive I began to follow the instructions in the manual.

Right off-the-bat, lsblk showed the only drive available (under /dev/sda) was my USB drive (I’ve had to make up the output here as I am recalling from memory).

NAME        MAJ:MIN RM   SIZE RO TYPE MOUNTPOINT
sda         259:0    0    16G  0 disk
├─sda1      259:1    0    ??M  0 part /boot
├─sda2      259:2    0    16G  0 part /

Where was my internal drive? To my understanding, it turned out the default Linux drivers included in the kernel do not support NVMe SSDs unless the SATA mode for the drive is set to AHCI. This setting can be controlled via the UEFI options, however, changing the mode makes Windows 10 inaccessible unless it is started in Safe Mode. Further exacerbating the issue, turning off Secure Boot meant Bitlocker would kick-in whenever I tried to start my Windows 10 partition. This required me to log on to my Microsoft account on another device and copy a large number of digits to proceed with the boot process.

Unfortunately, this long string of obstacles ultimately led me to re-partition and format my SSD, before making a clean installation of Windows 10 alongside NixOS, with my SATA mode set to AHCI from the get-go. In hindsight, this was definitely the right choice as I decided to free up the space occupied by the recovery partitions and gain control over my installation options and drivers.

Installing everything, fresh

So, how do we go about having a clean dual-boot set-up on the XPS 13 9370? The process is pretty straightforward if you have ever done anything similar. If you haven’t, I would be wary about tinkering too much, on the off-chance you “brick” your laptop. I am not responsible for such scenarios.

The installation begins to become interesting when configuring NixOS (link to come). For this setup, I decided not to encrypt any of my partitions, though it is something I would like to explore in the future.

Windows 10

To begin with, prepare a bootable USB drive for installing Windows 10. I’ll assume there are enough resources out on the internet to learn how to do this. TLDR, run this tool. Remember to keep a copy of the Killer wireless drivers on the USB drive. I made the mistake of not doing so beforehand and had to USB-tether via my phone to download them once the install had completed.

Before beginning with the installation, you will need to change some UEFI options. To do this, hit F2 when you first see the Dell logo appear on start-up. It is recommended not to hold the button (it may be interpreted as being stuck), so I tap it rhythmically instead. The following options are necessary:

  • Secure Boot
    • Secure Boot Enable
      • Disabled
  • System Configuration
    • SATA Operation
      • AHCI

You may also have to set Fastboot (under POST Behavior) to Thorough. Only the right-hand side USB-C port can be used to boot into the USB drive. To enable the use of the ports on the left, Thunderbolt Boot Support (under System Configuration, USB/Thunderbolt Configuration) should additionally be enabled. To choose the boot drive, tap F12 when the Dell logo first appears.

Partitioning and formatting can be done during the Windows 10 installation. The only things to keep-in-mind are to preserve the boot partition (this was the first partition, in my case), and that Dell may-or-may-not be happy to provide support if the recovery partitions are wiped. This time around, I made my Windows partition ~100GB, and left the rest unallocated, leaving ~140GB for NixOS.

After the installation is complete, install the WiFi drivers, then the rest of the XPS 9370 drivers. A convenient list can be found here, and here. Everything seemed to work fine aside from:

  • Start-menu Personalization
    • Any settings/changes I made to the start-menu were not being saved. Rummaging on forums suggested it would fix itself after a couple of days, which it did.
  • Night Light
    • This option is greyed out for some reason.

NixOS

Once Windows 10 is on its feet, we can replace the Windows 10 image with the NixOS installer. As suggested earlier, using Rufus with default settings works fine. If given the option, use dd to perform the write. Booting into the installer is the same as Windows 10.

For the most part, I followed the NixOS manual to do the installation. Some pointers:

  • loadkeys uk for British keyboard layout.
  • ip link to get the list of network interfaces. I have:
     1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
         link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
     2: wlp2s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP mode DORMANT group default qlen 1000
         link/ether 9c:b6:d0:8e:7d:d3 brd ff:ff:ff:ff:ff:ff
    

    Where wlp2s0 is the name of wireless interface.

    In which case wpa_supplicant -B -i wlp2s0 -c <(wpa_passphrase "foo" "bar"), substituting foo for your the SSID (name) of your network, and bar for the password, will get you connected.

  • The internal SSD shows up under /dev/nvme0n1. I prefer gdisk for managing my partitions, it works well with GPT. The Arch Wiki has a lot of pragmatic example layouts. Here is my current table:
    Number  Start (sector)    End (sector)  Size       Code  Name
       1            2048         1333247   650.0 MiB   EF00  EFI system partition
       2         1333248         1595391   128.0 MiB   0C01  Microsoft reserved ...
       3         1595392       206395391   97.7 GiB    0700  Basic data partition
       4       206395392       495802367   138.0 GiB   8304  Linux x86-64 root (/)
       5       495802368       500118158   2.1 GiB     8200  Linux swap
    

    As I work with large amounts of in-memory data, potentially boasting > 8GB in size, I opt-in to a couple GB of swap (woes of CG/VFX software)!

  • As Nix installs all software, including user packages, under /nix/store, I would suggest making your /root larger if you are considering separating /home.
  • Remember to mount all your partitions before running nixos-generate-config --root /mnt. If you’ve forgotten any, you can mount them after and run the NixOS command again and it should update the file at /etc/nixos/hardware-configuration.nix. I recommend inspecting this file to see the options the installer detected and verify the disk UUIDs are correct.

Aside from the UEFI options to-or-already set in /etx/nixos/configuration.nix. The final thing to note before running nixos-install is the boot.loader.grub.useOSProber option. Setting this will allow GRUB to detect our Windows 10 partition and provide it as an option on start-up. We want this. Also, unless you’ve configured a display manager and/or desktop environment, you will only be able to log-in to the command line (no X)!

Of course, if you realize you’ve misconfigured something, the magic of Nix is the ability to re-build your configuration or rollback to the last working derivation, but more on this in the next post.

On a side note - I occasionally found that after starting the NixOS installation process, the USB drive would somehow become corrupt. Reading the drive in Linux or Windows seemed to fail. The most effective method of recovering the drive that I found, was to use ImageUSB to zero-out the drive, before using Rufus to re-write the NixOS image for me.


Hopefully, this post has been insightful/helpful in some way. For those of you that are interested, I aim to go over my own configuration and the decisions I made in the next post, which is available here.

Helpful links

Update

A friend mentioned swapfiles which I had completely forgotten about. This is helpful if you have limited disk space - which my laptop does - because the file can be dynamically re-sized on a needs basis. I’ve made a post on my process of updating the partition table and expanding the filesystem at /.