How to get hibernation working on 12th gen Framework with Pop!_OS 22.04

After a lot of trial and error, lots of guides and documentation, I finally managed to get hibernation working on Framework with i7-1280p (12th gen) running Pop!_OS 22.04 LTS.

Main guide was made by Dylan Awalt-Conley and can be found here.

I felt a more detailed explanation of the steps was needed, as well as modifications I did in order to get it working.

This setup was made on a Pop!_OS 22.04 LTS installation without an encrypted disk.

I selected my own partition layout and defined a swap partition as big as my RAM. Various guides mention that hibernation either always writes 100% of RAM (so every time you hibernate, you write 16 GB or how much you have to SSD) or it compresses the RAM so only the actual RAM used is sent to storage (so if you get 25% usage from 16 GB of RAM when you hibernate you will write ~4 GB to SSD).

After you get the hang of the steps, I’m pretty sure you can adapt the guide to work on a fully encrypted disk.

Step 1 - Set some environment variables:

SWAP_DEVICE=$(sudo cryptsetup status cryptswap | grep 'device:' | awk '{print $2}')
This represents the partition that currently holds the swap.

This is the default on Pop!_OS. The current mapping used by crypttab.

This is the location of your swap encryption key. This will be used to decrypt the swap partition instead of a random key assigned each boot (which is the main culprit that breaks hibernation on Pop!_OS). I used /.swap-key instead of /root/.swap-key as the latter didn’t make crypttab unlock my LUKS partition and swap was not working on boot.

Step 2 - Turn off swap

sudo swapoff $SWAP_DEVICE

Step 3 - Lock the LUKS partition that holds the swap

sudo cryptsetup luksClose $CRYPT_DEVICE

Step 4 - Comment out the old swap mapping from crypttab

Basically crypttab holds mapping information for encrypted partitions and how to handle them. By default, Pop!_OS makes the swap partition encrypted with a key that is randomly generated at every boot. This breaks hibernation. We want to re-create this swap partition with a key that doesn’t change.
sudo sed -i 's!^cryptswap!# &!' /etc/crypttab

Step 5 - Create encryption key file

sudo dd if=/dev/urandom of=$SWAP_KEY bs=1024 count=4

Step 6 - Format the old swap partition and map it to the encryption key

sudo cryptsetup luksFormat -d $SWAP_KEY $SWAP_DEVICE

Step 7 - Open the new partition and mount it

sudo cryptsetup open -d $SWAP_KEY $SWAP_DEVICE cryptswap

Step 8 - Format the partition for swap

sudo mkswap $CRYPT_DEVICE

By this point, if you open Disks you should have a LUKS partition available and a swap partition underneath:

Now comes the complex stuff. Take note of the files we edit and remember them in case the system won’t boot anymore. You can make backups of them or comment out the old entries.

Step 9 - Set some new environment variables

Here I find the names confusing, but to keep it the same as the source Gist, I will leave them as is.

SWAP_UUID=$(sudo blkid -s UUID -o value $SWAP_DEVICE)
This holds the UUID of the LUKS partition that contains the swap.

CRYPT_UUID=$(sudo blkid -s UUID -o value $CRYPT_DEVICE)
This holds the UUID of the swap partition inside the luks partition.

ROOT_UUID=$(sudo findmnt -no UUID -T $SWAP_KEY)
This holds the UUID of the partition that holds the encryption key (mounted at / in our case, mounted at /root in the original guide)

Step 10 - Add our new cryptswap entry to crypttab

echo "cryptswap UUID=$SWAP_UUID /dev/disk/by-uuid/$ROOT_UUID:$SWAP_KEY luks,discard,keyscript=/lib/cryptsetup/scripts/passdev,noauto" | sudo tee -a /etc/crypttab

Step 11 - Checkpoint - Reboot and test

By this point, what you did was to make a new swap partition that uses a fixed encryption key instead of a random key.

run sudo update-initramfs -u and check for any errors.
You shouldn’t get any.

Reboot your system and test to see if swap is used or not.

sudo swapon -s should show output if swap is working.
You can also check Disks to see if the LUKS partition is automatically unlocked and if the swap partition is used by the system.

Step 12 - add RESUME flags to initramfs

echo "resume=UUID=$CRYPT_UUID" | sudo tee -a /etc/initramfs-tools/conf.d/resume
This will tell your system that for every kernel update from now on, also apply the changes in our resume file. So we don’t have to manually update each systemd entry whenever a change happens.

Step 13 - add RESUME flags to kernelstub

This step is (as far as I know) Pop!_OS specific.
They use a tool called kernelstub to update the systemd kernel parameters. Makes it easier to maintain extras (like nvme.noacpi=1 for example)

sudo kernelstub -a "resume=UUID=$CRYPT_UUID"

Step 14 - update initramfs again

sudo update-initramfs -u

Reboot, then open some programs and try hibernating with
sudo systemctl hibernate.

After a few seconds, your laptop should shutdown and when you turn it back on, you should get a grey screen with a message resuming from /dev/disk/by-uuid/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx and everything should be just the way you left it.