splitbrain.org

electronic brain surgery since 2001

FrameWork 13 (Intel Ultra) & ArchLinux

My trusty Thinkpad is now over a decade old and I was eyeing a Framework Laptop for a while now. So when the opportunity arose to get it as a work laptop I couldn't refuse ;-)

I picked the Intel Ultra Core 165H model with 96GB of RAM and a 4TB NVME disk. This beast should have plenty of power for the foreseeable future.

Of course Framework announced that they would release a new generation on February 25th just a couple of days after my order m(.

Below are my notes on how to set it up on Arch Linux. I might extend the post over the coming weeks…


Hardware

I got the DIY version which means some slight assembly is required. The installation guide is great and reminded me a lot of the Prusa assembly guides (including helpful user comments on each step). It took me and Kaddi about 20 minutes to assemble.

Start of Assembly First Boot

When buying the laptop, you can pick each individual component. Here's what I selected:

  • DIY Edition
  • Intel Core
  • System: Ultra 7 165H
  • Display: 2.8K Display (the “non-retina” display is not available for the Intel Core models)
  • Storage: WD_BLACK™ SN850X NVMe™- M.2 2280 - 4TB
  • Operating System: none
  • Bezel: black
  • Keyboard: German
  • Power Adapter: none
  • Expansion Cards: 2x USB-C, 1x USB-A, 1x HDMI

If this hadn't been a company laptop I probably would have bought RAM and storage somewhere else to save some money, but it was easier this way.

I did not get their power supply and instead bought a uGreen Nexode 65W Power Supply which is absolutely tiny.

I also ordered a laptop sleeve from CushCase but it hasn't arrived, yet. I'll add a picture when it does.

References

Bios Update

Before installing the OS I wanted to update the BIOS. To get the current version, press F2 during boot, then go to Setup Utility → Main → InsydeH2O Version. Mine said KFM30.03.01. Which the Framework people call just 03.01.

To update you can use an UEFI shellscript. You can find the zip file here: Linux/Other/UEFI Shell update.

TBH I found their BIOS upgrade guide a mess and no comparison to their assembly guide. Framework should really improve this.

To use the EFI Shell update, a FAT formatted USB stick with a GPT partition is needed:

$> sudo gdisk /dev/sde
p # to print current partitition table
d # delete existing partitition
n # for new partition
[enter] # for partition number 1
[enter] # for start sector default
[enter] # for end sector default
ef00 # for efi partition type
w # for writing table to disk
$> sudo mkfs.vfat /dev/sde1
$> sudo mount /dev/sde1 /mnt
$> cd /mnt
$> sudo unzip ~/temp/00-today/Framework_Laptop_13_Intel_Core_Ultra_Series1_capsule_signed_allsku_3.03_3.04_EFI.zip
$> cd
$> sudo umount /mnt

Now you can boot from that stick and the update should happen automatically. It should update first to 3.03, then to 3.04.

BIOS Update in progress

That seemed to work fine until the whole process somehow got stuck and did the same thing again and again. It would apply some update named “Port01: 270 → Port01: 270”, show “Update complete!!”, reboot and do the same thing again.

At some point I removed the USB stick and saw that the update to 3.03 had been applied, but 3.04 was nowhere to be seen.

I created a forum post asking for help and moved on to install the OS.

Boot Media

First step is preparing the bootable USB stick with the current ArchLinux ISO. I used Balena Etcher to “burn” the stick.

Once booted, I changed to a German keyboard layout with loadkeys de.

To connect to the internet, simply use iwctl:

#> iwctl
device list
station wlan0 scan
station wlan0 get-networks
station wlan0 connect YOURNETWORK

Encrypted File System

One thing mandated by my company is that all work related stuff has to be stored on an encrypted device. In the past I used ecryptFS to encrypt my home directory. But since I was starting from scratch here, I wanted to properly encrypt the whole root partition.

I decided for the following layout:

  • 1GB EXT4 mounted to /boot
  • 1GB FAT32 mounted to /efi
  • ~3.6TB LUKS2 encrypted
    • EXT4 mounted to /

The boot and EFI partitions are quite spacious, but better safe than sorry later.

Note that I decided against any LVM setup here. The only reason I can see to do so is if I wanted to have different partitions inside the LUKS container, but I prefer one huge root partition so I kept things simple here.

To create the partition table gdisk is used:

#> gdisk /dev/nvme01n1
n        # new partition
[enter]  # partition number
[enter]  # first available sector
+1g      # last sector (at 1GB after the first)
[enter]  # type Linux Filesystem

n        # new partition
[enter]  # partition number
[enter]  # first available sector
+1g      # last sector (at 1GB after the first)
ef00     # type EFI system partition

n        # new partition
[enter]  # partition number
[enter]  # first available sector
[enter]  # last available sector
[enter]  # type Linux Filesystem

p        # print current setup

Disk /dev/nvme0n1: 7814037168 sectors, 3.6 TiB
Model: WD_BLACK SN850X 4000GB
Sector size (logical/physical): 512/512 bytes
Disk identifier (GUID): F6D832C4-EE21-4995-A468-59BD03C351F7
Partition table holds up to 128 entries
Main partition table begins at sector 2 and ends at sector 33
First usable sector is 34, last usable sector is 7814037134
Partitions will be aligned on 2048-sector boundaries
Total free space is 3693 sectors (1.8 MiB)

Number  Start (sector)     End (sector)     Size        Code  Name
   1       2048            2099199          1024.0 MiB  8300  Linux filesystem
   2       2099200         4196351          1024.0 MiB  EF00  EFI system partition
   3       4196352         7814035455       3.6 TiB     8300  Linux filesystem

w        # write to disk
y        # confirm

Next the encryption for partition 3 is set up. I made sure to use the newer LUKS2 format, but kept everything else at its defaults:

cryptsetup luksFormat --type luks2 /dev/nvme0n1p3
cryptsetup open /dev/nvme0n1p3 luks

The opened encrypted block device is now available as /dev/mapper/luks. Time to create the file systems:

mkfs.ext4 /dev/nvme0n1p1        # boot partition
mkfs.fat -F32 /dev/nvme0n1p2    # efi partition
mkfs.ext4 /dev/mapper/luks # root partition

Finally the file systems can be mounted.

mount /dev/mapper/luks /mnt
mkdir /mnt/efi
mount /dev/nvme0n1p2 /mnt/efi
mkdir /mnt/boot
mount /dev/nvme0n1p1 /mnt/boot
@mortzu on Mastodon points out that the encrypted device should be opened with TRIM support to reduce wear on the SSD. The same ArchWiki page also recommends disabling work queues on SSDs.
Both changes can easily be enabled after the fact:
#> cryptsetup --allow-discards --perf-no_read_workqueue --perf-no_write_workqueue  --persistent refresh luks
#> cryptsetup luksDump /dev/nvme0n1p3 |grep Flags
Flags:       	allow-discards no-read-workqueue no-write-workqueue

Bootstrapping

Now the base ArchLinux system can be installed. Only the bare minimum here:

pacstrap /mnt base linux linux-firmware mkinitcpio vim dhcpcd wpa_supplicant intel-ucode iwd grub

A file system table can be auto generated. Disabling access times improves performance and reduces wear on the SSD:

genfstab -pU /mnt | sed 's/relatime/noatime/' >> /mnt/etc/fstab

Time to chroot into the new system:

arch-chroot /mnt

First set the timezone, hardware clock and hostname:

ln -s /usr/share/zoneinfo/Europe/Berlin /etc/localtime
hwclock --systohc --utc
echo ni > /etc/hostname

Uncomment en_US.UTF-8 UTF-8 in /etc/locale.gen and generate, then set up the locale

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

Don't forget to keep the German keyboard layout. The following sets /etc/vconsole.conf as well as the xorg default for later.

localectl set-x11-keymap de

Set up the hosts file:

/etc/hosts
127.0.0.1 localhost ni
::1 localhost

And create a root password:

passwd

Grub Setup

As the bootloader I used grub. To make it aware of the encrypted root disk some adjustments need to be made.

First we need to make sure the initramfs can decrypt our file system. This is done by adding the encrypt hook after the block hook in /etc/mkinitcpio.conf.

/etc/mkinitcpio.conf
HOOKS=(base udev autodetect keyboard modconf block encrypt filesystems fsck)

Be sure to recreate the initramfs after the change.

mkinitcpio -p linux

Next we need the UUID of the encrypted partition:

#> blkid -o value -s UUID /dev/nvme0n1p3
ce7318b0-4302-442c-aaff-6e9c26f7547e

Now the grub configuration can be adjusted. Find and edit the appropriate options in /etc/default/grub

/etc/default/grub
GRUB_CMDLINE_LINUX="cryptdevice=UUID=ce7318b0-4302-442c-aaff-6e9c26f7547e:luks"
GRUB_ENABLE_CRYPTODISK=y
GRUB_TERMINAL_OUTPUT=gfxterm
GRUB_GFXMODE=800x600

The first line tells the kernel to decrypt our root partition. The second tells grub about it. The last two lines simply reduce the graphics resolution so you don't have to squint at tiny pixels in your boot loader.

Next the bootloader can be installed:

mkdir /boot/grub
grub-mkconfig -o /boot/grub/grub.cfg
grub-install --target=x86_64-efi --efi-directory=/efi --removable

With all this done, it's time to reboot. Exit the chroot environment, unmount the disks and reboot (remove the USB stick).

exit
umount /mnt/efi /mnt/boot /mnt
reboot

XFCE & XOrg & UI Scaling

Once successfully booted and logged in, I needed network access again. It can be done the same way as in the install environment above. In theory you can simply enable both services at boot, but I will use the graphical network manager once X is up, so this is only temporary:

systemctl start iwd dhcpcd
iwctl

You should also create a local user now and add it to sudoers.

Time to install a bunch of packages. I am using XFCE for decades now and am perfectly happy with it. The same goes for Xorg. At some point in the future I might make the switch to Wayland, but for now I don't have any compelling reason.

One thing that threw me off, was that you should NOT install the xf86-video-intel package. It will not work with the modern hardware.

#> pacman -S xorg mesa mesa-utils xfce4 xfce4-goodies lightdm lightdm-gtk-greeter light-locker gnome-keyring ttf-dejavu ttf-liberation ttf-droid ttf-ubuntu-font-family ttf-roboto noto-fonts noto-fonts-emoji ttf-bitstream-vera pulseaudio pulseaudio-alsa alsa-utils pavucontrol networkmanager network-manager-applet nm-connection-editor networkmanager-openvpn openvpn gigolo gvfs gvfs-smb bind-tools colord xiccd
#> systemctl enable NetworkManager lightdm
#> systemctl start NetworkManager lightdm

You should now have a running XFCE desktop you can login to. Running at a ridiculous resolution of 2880×1920. Time to do some tweaking.

Proper “retina” style scaling is still a major PITA on Linux. The tweaks below are the best I could achieve so far. Individual tools might still trip over the settings.

First download the color profile for the screen:

$> wget --user-agent="Mozilla/5.0" https://www.notebookcheck.net/uploads/tx_nbc2/BOE0CB4.icm

Then open the Settings Manager and adjust some settings:

  • Appearance
    • Settings
      • Window Scaling: 2
  • Window Manager
    • Style
      • Theme: Default-xhdpi
  • Display
    • General
      • Scale: 0.75
  • Color Profiles
    • Select the Monitor
    • Click Add
      • Browse for the downloaded BOE0CB4.icm and add it
      • Select BOE0CB4 from the list
  • Mouse and Touchpad
    • Select the Touchpad Device
    • Buttons and Feedback
      • Pointer Speed
        • Acceleration: 8.0
    • Touchpad
      • Tap touchpad to click: enable
      • Click Method: Click 1,2 or 3 fingers…

The above will first set the scaling to 2x, then zoom out slightly again via xrandr. Feel free to play with the settings according to your preferences.

However some programs may still not pick up the correct scaling. In my case IntelliJ Idea failed to understand the settings. The solution was to set the GDK_SCALE env variable.

~/.xprofile
export GDK_SCALE=2

More issues can potentially pop up with every single program you run :-/. To make Gimp correctly scale the UI, I had to install gimp-devel from AUR. With Release Candidate 3 having been released just a week ago this will hopefully not be needed for much longer.

One issue I couldn't fix yet is that the mouse pointer size is quite tiny. And the size setting has absolutely no effect. I assume this is a bug that will be fixed in future updates.

External Displays

When you connect the laptop to an external non-retina display, you need to further downscale everything again. Luckily this is simple to do in the Settings Manager under DisplayGeneralScale where you can set a scale for each individual monitor. For non-retina monitors setting the scale to 0.5 will undo all the previous enlargements.

Under Advanced you can save different display settings as profiles and have them applied automatically when you connect a new display.

If the profile auto-selection fails sometimes, you can manually trigger it by running:

xrandr --auto
When connecting an external display via USB-C (opposed to using the HDMI expansion card) you need to make sure your cable is actually capable of doing video transfer. Chances are high that none of your existing cables are. When buying, either look for “Thunderbolt”, “USB Gen 4.0” or descriptors like “4K” or “8k”. Buying USB-Cables is a mess.

Auto Login

Since booting up already requires to unlock the encrypted root disk and this is a single user system, there is no reason to have lightdm ask me for a password for logging into my xsession. Instead I simply enable it's auto login feature:

/etc/lightdm/lightdm.conf
[Seat:*]
autologin-user=andi
autologin-user-timeout=0

To make that work, my user needs to be in a autologin group:

sudo groupadd -r autologin
sudo usermod -aG autologin andi

One issue I ran into is that gnome-keyring is usually unlocked by the user password. With auto-login that doesn't exist anymore. But again with the whole disk encrypted, additional encryption for gnome-keyring is superfluous.

To create a password-less keyring, I logged out and connected via SSH. Then deleted ~/.local/share/keyrings and rebooted. When I started Chrome (which uses the keyring) I was asked to create a new one and give it a password. I chose an empty one and confirmed that I am fine with unencrypted data.

Apparently the only way to change the password of an existing keyring is to use the graphical tool Seahorse. It's super weird to me that there is no (documented) way to do it from the command line. But I guess it's a Gnome tool, so they expect you to run their full suite of GUI tools…

Energy Management

I didn't do much for energy management yet except installing and enabling the recommended tools. Seems to work fine.

sudo pacman -S thermald tlp ethtool smartmontools
sudo systemctl enable thermald tlp
sudo systemctl start thermald tlp

Bluetooth

Getting Bluetooth to work was super easy. Just install the requirements and start the daemon.

sudo pacman -S bluez bluez-utils blueman pulseaudio-bluetooth
sudo systemctl enable bluetooth
sudo systemctl start bluetooth

This was enough to pair my Sony headphones but the actual audio connection wouldn't work until after a reboot 🤷‍♂️.

Fingerprint Sensor

The Framework 13 has a built-in fingerprint reader:

Bus 003 Device 003: ID 27c6:609c Shenzhen Goodix Technology Co.,Ltd. Goodix Fingerprint USB Device

It should work fine with the fprint daemon, but since I am logging into Xorg automatically and the LUKS passphrase is queried long before the system and fprint are initialized, there's not much sense in setting that up.

BIOS Update again

With the system running and no answer to my forum post, I decided to tackle the BIOS update again. This time not using the EFI shell but doing it from the installed system.

First install the needed packages and check the firmware version.

$> sudo pacman -S dmidecode fwupd
$> sudo dmidecode -s bios-version
03.03

Then basically

$ fwupdmgr get-devices
$ fwupdmgr refresh
$ fwupdmgr get-updates
$ sudo fwupdmgr update

Reboot and the familiar update screen will pop up again. However this time it worked. As confirmed after booting into Arch again:

$ sudo dmidecode -s bios-version
03.04

I think something in the update process did not like that there was only an UEFI partition on the USB stick but not on the main disk, yet.

Sensors

When using the sensors command from the lm_sensors package, a whole bunch of them are reported.

ucsi_source_psy_USBC000:004-isa-0000
Adapter: ISA adapter
in0:          20.00 V  (min =  +5.00 V, max = +38.80 V)
curr1:         2.25 A  (max =  +3.16 A)

ucsi_source_psy_USBC000:001-isa-0000
Adapter: ISA adapter
in0:           0.00 V  (min =  +0.00 V, max =  +0.00 V)
curr1:         0.00 A  (max =  +0.00 A)

iwlwifi_1-virtual-0
Adapter: Virtual device
temp1:        +55.0°C  

spd5118-i2c-14-50
Adapter: SMBus I801 adapter at efa0
temp1:        +50.5°C  (low  =  +0.0°C, high = +55.0°C)
                       (crit low =  +0.0°C, crit = +85.0°C)

coretemp-isa-0000
Adapter: ISA adapter
Package id 0:  +56.0°C  (high = +110.0°C, crit = +110.0°C)
Core 0:        +52.0°C  (high = +110.0°C, crit = +110.0°C)
Core 1:        +51.0°C  (high = +110.0°C, crit = +110.0°C)
Core 2:        +52.0°C  (high = +110.0°C, crit = +110.0°C)
Core 3:        +52.0°C  (high = +110.0°C, crit = +110.0°C)
Core 4:        +51.0°C  (high = +110.0°C, crit = +110.0°C)
Core 5:        +52.0°C  (high = +110.0°C, crit = +110.0°C)
Core 6:        +52.0°C  (high = +110.0°C, crit = +110.0°C)
Core 7:        +52.0°C  (high = +110.0°C, crit = +110.0°C)
Core 8:        +57.0°C  (high = +110.0°C, crit = +110.0°C)
Core 12:       +51.0°C  (high = +110.0°C, crit = +110.0°C)
Core 16:       +54.0°C  (high = +110.0°C, crit = +110.0°C)
Core 20:       +51.0°C  (high = +110.0°C, crit = +110.0°C)
Core 24:       +51.0°C  (high = +110.0°C, crit = +110.0°C)
Core 28:       +50.0°C  (high = +110.0°C, crit = +110.0°C)
Core 32:       +55.0°C  (high = +110.0°C, crit = +110.0°C)
Core 33:       +55.0°C  (high = +110.0°C, crit = +110.0°C)

BAT1-acpi-0
Adapter: ACPI interface
in0:          16.21 V  
curr1:         1.96 A  

acpi_fan-acpi-0
Adapter: ACPI interface
fan1:           0 RPM
power1:        0.00 W  

cros_ec-isa-0000
Adapter: ISA adapter
fan1:               0 RPM
local_f75397@4c:  +44.9°C  
cpu_f75303@4d:    +47.9°C  
battery_temp@b:   +39.9°C  
ddr_f75303@4d:    +42.9°C  
peci-temp:        +54.9°C  

ucsi_source_psy_USBC000:003-isa-0000
Adapter: ISA adapter
in0:           5.00 V  (min =  +5.00 V, max =  +5.00 V)
curr1:         0.00 A  (max =  +3.00 A)

spd5118-i2c-14-52
Adapter: SMBus I801 adapter at efa0
temp1:        +49.2°C  (low  =  +0.0°C, high = +55.0°C)
                       (crit low =  +0.0°C, crit = +85.0°C)

ucsi_source_psy_USBC000:002-isa-0000
Adapter: ISA adapter
in0:           0.00 V  (min =  +0.00 V, max =  +0.00 V)
curr1:       680.00 mA (max =  +0.00 A)

nvme-pci-a900
Adapter: PCI adapter
Composite:    +45.9°C  (low  =  -5.2°C, high = +89.8°C)
                       (crit = +93.8°C)

acpitz-acpi-0
Adapter: ACPI interface
temp1:        +54.8°C  
temp2:        +47.9°C  
temp3:        +42.9°C  
temp4:        +44.9°C  
temp5:        +40.0°C  

acpi_fan-acpi-0
Adapter: ACPI interface
fan1:             N/A
power1:           N/A

I asked in a forum thread about what the different values represent. It seems most important are the coretemp values (with Package id 0 being the overall processor temperature as reported by the CPU itself) and the values in cros_ec which are sensors near components on the motherboard, including the current fan speed.

You can easily add any of those sensors to an XFCE panel using the xfce4-sensors-plugin.

Tags:
framework, laptop, notebook, archlinux, howto
Similar posts: