Installing Arch with Full-Disk Encryption on a Dell XPS 15 7590

Updated: November 21, 2020

This is a quick rundown of how I installed Arch with full-disk encryption on a Dell XPS 15 7590.

Specs

The XPS 15 7590 comes in many possible configurations. Here's the one I used:

Component Selected Option
Processor Intel i7-9750H
Memory 16GB DDR4-2666MHz
Graphics Nvidia GTX 1650 4GB
Storage 2TB M.2 PCIe NVMe SSD
WiFi Killer Wireless 1650X
Screen 4K UHD (3840 x 2160) Touch IPS

Everything works out of the box except for the fingerprint reader. To be fair, Dell doesn't even support its fingerprint readers on the "developer edition" XPS 13 that comes with Ubuntu factory-installed.

BIOS Settings

Arch---along with any other mainstream Linux distro I'm aware of---will not be able to recognize your hard drive using the factory BIOS settings. You need to go into the BIOS menu (by pressing F2 at the boot screen) and enable AHCI mode instead of RAID.

I also chose to disable Secure Boot. It's entirely possible to use Secure Boot with Arch but I'm not convinced that the security benefits outweigh the inconvenience. Your mileage may vary. The rest of this guide will assume that Secure Boot is disabled.

Having made those changes, you're now ready to boot from the Arch ISO. Press F12 at the boot screen to show the boot menu and choose the USB drive or CD that contains the Arch installation image.

Note: The name/label of your bootable USB's partition must match the name of the Arch release, e.g. "ARCH_202011". Some utilities like UNetbootin will not rename the partition for you, so you must do this yourself using your operating system's disk partitioner.

Connecting to the Internet

You can connect to WiFi using an interactive iwctl prompt. To start the prompt, do:

$ iwctl

Find your wireless device name:

[iwd]# device list

In my case the device name was wlan0.

Scan for networks and list their SSIDs:

[iwd]# station wlan0 scan
[iwd]# station wlan0 get-networks

Connect to an SSID, substituting <SSID> with the SSID you found in the previous step:

[iwd]# station wlan0 connect <SSID>

If the wireless network is secured, you will be prompted to enter a password.

Exit the interactive prompt:

[iwd]# exit

You can verify that your connection is active and working by pinging the Arch homepage:

$ ping -c2 archlinux.org

System Clock

Update the system clock by running:

$ timedatectl set-ntp true

Partitioning

We're going to create two partitions on the physical drive: one for /boot and one for the encrypted LVM. Then, we'll create a volume group for the encrypted root, home, and swap partitions.

First, you need to find your internal hard drive. To list all your hard drives:

$ fdisk -l

In my case, the internal hard drive was /dev/nvme0n1.

Start the disk partitioner for that hard drive:

$ cgdisk /dev/nvme0n1

Use the menu options and prompts in cgdisk to create the following partitioning scheme:

Size Hex Code Label
512MiB ef00 boot
(remainder) 8300 lvm

Write your changes to disk.

Get the UUIDs for your new partitions:

$ fdisk -l

In my case, the boot partition was /dev/nvme0n1p1 and the lvm partition was /dev/nvme0n1p2.

Next, format the boot partition:

$ mkfs.fat -F32 /dev/nvme0n1p1

And encrypt the LVM partition:

$ cryptsetup luksFormat /dev/nvme0n1p2
$ cryptsetup luksOpen /dev/nvme0n1p2 luks

The next step is to create the volume group and partitions on the encrypted LVM partition:

$ pvcreate /dev/mapper/luks
$ vgcreate vg0 /dev/mapper/luks
$ lvcreate -L 32G -n root vg0
$ lvcreate -L 20G -n swap vg0
$ lvcreate -l 100%FREE -n home vg0

Format the partitions:

$ mkfs.ext4 /dev/mapper/vg0-root
$ mkfs.ext4 /dev/mapper/vg0-home
$ mkswap /dev/mapper/vg0-swap

And mount your new filesystem:

$ mount /dev/mapper/vg0-root /mnt
$ mkdir -p /mnt/{boot,home}
$ mount /dev/mapper/vg0-home /mnt/home
$ mount /dev/nvme0n1p1 /mnt/boot
$ swapon /dev/mapper/vg0-swap

Installing the Base System

Now that you've created the filesystem, you have a target you can install the base Arch system onto.

$ pacstrap -i /mnt base base-devel linux linux-firmware intel-ucode lvm2 vim git

Accept all the defaults at the installation prompt.

Generate an fstab config file, which controls how our filesystem is mounted on boot:

$ genfstab -pU /mnt >> /mnt/etc/fstab

Now log into your newly installed copy of Arch:

$ arch-chroot /mnt /bin/bash

Basic System Configuration

Set the timezone using the file in /usr/share/zoneinfo that matches your local timezone. For example, for Los Angeles time:

$ ln -s /usr/share/zoneinfo/America/Los_Angeles /etc/localtime

Now set the hardware clock mode to UTC:

$ hwclock --systohc --utc

Use vim to uncomment your locale's name:

$ vim /etc/locale.gen

In my case, my locale is en_US.UTF-8. Generate the locale and select it by doing the following, substituting in your own locale as needed:

$ locale-gen
$ echo LANG=en_US.UTF-8 > /etc/locale.conf
$ export LANG=en_US.UTF-8

Superuser Account

Create an admin user who will have access to the sudo command.

I'm creating a user named liv, but of course you can substitute your own name:

$ useradd -m -g users -G wheel -s /bin/bash liv
$ passwd liv

And grant users in the wheel group (like the one you just created) the ability to use the sudo command. You'll need to uncomment the line %wheel ALL=(ALL) ALL:

$ visudo

Networking

Install and enable Network Manager:

$ pacman -S networkmanager
$ systemctl enable NetworkManager

Set your hostname. In this example, I'm setting my hostname to xps15:

$ echo xps15 > /etc/hostname
$ echo "127.0.0.1    xps15" >> /etc/hosts
$ echo "::1          xps15" >> /etc/hosts
$ echo "127.0.1.1    xps15.localdomain xps15" >> /etc/hosts

Boot Loader

First, we need to edit our mkinitcpio hooks so that we can decrypt and mount the encrypted partition on boot. Edit the config file with:

$ vim /etc/mkinitcpio.conf

Edit the MODULES section so that it looks like this:

MODULES=(ext4)

And edit the HOOKS section so that it looks like this:

HOOKS=(base udev autodetect modconf block encrypt lvm2 resume filesystems keyboard keymap fsck)

Then build the linux image:

$ mkinitcpio -p linux

Now install the systemd-boot boot loader:

$ bootctl install --path=/boot

Create the bootloader configuration file:

$ vim /boot/loader/loader.conf

The file should have the following contents:

default arch.conf
timeout 0
console-mode max
editor no

Create the bootloader entry for Arch Linux:

$ vim /boot/loader/entries/arch.conf

The file should have the following contents:

title   Arch Linux
linux   /vmlinuz-linux
initrd  /intel-ucode.img
initrd  /initramfs-linux.img
options cryptdevice=/dev/nvme0n1p2:luks:allow-discards resume=/dev/mapper/vg0-swap root=/dev/mapper/vg0-root rw quiet

Now reboot and verify that you can log in:

$ exit
$ reboot --reboot

Graphical Desktop Environment

You should've gotten dumped back into a console environment. This might be all you need, but you probably want a graphical desktop environment. Arch gives you many choices here, but I personally like using Gnome with LightDM.

Connect to WiFi using NetworkManager, substituting <SSID> with your WiFi network's SSID and <PASSWORD> with its password. If the network is not secure, omit the password option entirely:

$ nmcli device wifi connect <SSID> password <PASSWORD>

Install Gnome:

$ sudo pacman -S gnome gnome-extra lightdm xorg gnome-screensaver

Accept all the default installation options.

Install the slick LightDM greeter from the AUR:

$ cd /tmp
$ git clone https://aur.archlinux.org/lightdm-slick-greeter.git
$ cd lightdm-slick-greeter
$ makepkg -si

Edit the LightDM config file to use the slick greeter:

$ vim /etc/lightdm/lightdm.conf

Edit the greeter-session line like this:

greeter-session=lightdm-slick-greeter

Disable GDM (which was installed with Gnome) and enable LightDM instead:

$ systemctl disable gdm
$ systemctl enable lightdm

Set a background for the LightDM greeter, since without one it looks pretty odd:

$ echo "[Greeter]" >> /etc/lightdm/slick-greeter.conf
$ echo "background=/usr/share/backgrounds/gnome/adwaita-night.jpg" >> /etc/lightdm/slick-greeter.conf

Reboot and you should be greeted with a graphical environment instead of a command-line prompt:

$ reboot --reboot

Nvidia Optimus

Optionally, you can install Nvidia with Optimus for switching between dedicated and integrated graphics. You can also enable Nvidia's power management:

$ sudo pacman -S nvidia nvidia-settings
$ git clone https://aur.archlinux.org/optimus-manager.git
$ cd optimus-manager
$ makepkg -si
$ systemctl enable optimus-manager

Create the file /lib/udev/rules.d/80-nvidia-pm.rules with these settings:

# Remove NVIDIA USB xHCI Host Controller devices, if present
ACTION=="add", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x0c0330", ATTR{remove}="1"

# Remove NVIDIA USB Type-C UCSI devices, if present
ACTION=="add", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x0c8000", ATTR{remove}="1"

# Remove NVIDIA Audio devices, if present
ACTION=="add", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x040300", ATTR{remove}="1"

# Enable runtime PM for NVIDIA VGA/3D controller devices on driver bind
ACTION=="bind", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x030000", TEST=="power/control", ATTR{power/control}="auto"
ACTION=="bind", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x030200", TEST=="power/control", ATTR{power/control}="auto"

# Disable runtime PM for NVIDIA VGA/3D controller devices on driver unbind
ACTION=="unbind", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x030000", TEST=="power/control", ATTR{power/control}="on"
ACTION=="unbind", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x030200", TEST=="power/control", ATTR{power/control}="on"

Create the file /etc/modprobe.d/nvidia.conf with these contents:

options nvidia "NVreg_DynamicPowerManagement=0x02"

Reboot:

$  reboot --reboot

Set the graphics to hybrid mode on boot; there's no point in using the integrated graphics since Nvidia's power management should theoretically be handling that for us.

Create a config file:

$ sudo cp /usr/share/optimus-manager.conf /etc/optimus-manager/optimus-manager.conf

Edit the config file at /etc/optimus-manager/optimus-manager.conf. In my case, I set the power mode to nouveau and all of the startup modes to hybrid.

Reboot:

$  reboot --reboot

Power Management

Install powertop, a utility from Intel that will improve power consumption:

$ pacman -S powertop

Create a service that will enable powertop's auto-tuning suggestions:

$ vim /etc/systemd/system/powertop.service

The file should have these contents:

[Unit]
Description=Powertop tunings

[Service]
Type=oneshot
ExecStart=/usr/bin/powertop --auto-tune

[Install]
WantedBy=multi-user.target

Closing Thoughts

Given the state of hardware support for this laptop, using a bleeding-edge distribution like Arch actually meant fewer problems instead of more. The installation process was pretty painless and everything works out of the box.

Battery life is a little worse than in Windows 10, but I still get between 6 and 7 hours of real-world usage (web browsing, writing code, etc.). Some of the issues I was having with thermal performance a year ago seem to have been resolved.