OneXPlayer 2 Pro (8840) With Arch Linux
Installation with disk encryption
Partition with encryption
In case of after-sales service, I kept windows partitions. I deleted D:
partition and shrink C:
partition. I create two partitions: /boot
and /
. I will use btrfs on /
, so instead of using paritions, I will use subvolume for /home.
Encryption was applied exclusively to /
partition, and I enabled Secure Boot
to make EFI
partition and /boot
partition safe.
- Encrypt
/
partition.# Don't forget to back up the password. cryptsetup luksFormat /dev/nvme0n1p5 cryptsetup open /dev/nvme0n1p5 root
- Create a btrfs file system and mount it to
/mnt
.mkfs.btrfs /dev/mapper/root mount /dev/mapper/root /mnt
After that, follow Installation Guide.
Bootloader
As a old linux user, I have used GRUB
for a long time. In this installation, I still use GRUB
. OneXPlayer 2 Pro is bit heavy. I don't want to bring the keyboard cover everywhere. So, I need the partition to be automatically decrypted when booting from GRUB
by integrating the use of Secure Boot
and TPM
.
At first, I used GRUB
. But at the time I am writing this article, I found my plan is not secure enough. According to this article, an attacker can get the decryption key of the partition.
A rogue partition with metadata copied from the real root filesystem (such as partition UUID) can mimic the original partition. Then, initramfs will attempt to mount the rogue partition as the root filesystem (decryption failure will fall back to password entry), leaving pre-boot PCRs unchanged. The rogue root filesystem with files controlled by an attacker is still able to receive the decryption key for the real root partition.
To prevent this attack, we need to make sure: 1. PCRs are changed before leaving initramfs. 2. only trusted initramfs can be booted.
With a signed unified kernel image (UKI
), we can make sure that initramfs can't be modified. systemd
provides systemd-pcrphase-initrd.service
to modify the value of PCR 11 in the state of entering and leaving initramfs. The service works in a systemd based initramfs.
Why not GRUB
? UKI
is actually a EFI
bootloader. GRUB
can only load Secure Boot
keys signed EFI
bootloaders. But, we can't load our own Secure Boot
to a OneXPlayer 2 Pro. After researching, I found that rEFInd
supports Secure Boot
keys and MOK
keys signed EFI
bootloaders.
Enable Secure Boot
There are three methods to enable Secure Boot
for a linux system: CA Keys
and Shim
and Preloader
.
CA Keys
: Create a pair of private and public keys, then load the public key into the BIOS in setup mode. After that, only bootloaders signed by the private key can be booted.Shim
: A binary signed by Microsoft. Since the shim binary is signed by Microsoft, it is validated and accepted by the firmware when verifying against certificates already present in firmware. It usesMOKManager
to enroll a custom user public key, and then a user can use the corresponding private key to sign the bootloader and the kernel. It can also enroll the hash of a file.Preloader
: LikeShim
, but it verifies the bootloader and the kernel with a hash instead of a signature.
On a OneXPlayer 2 Pro, each time you change Secure Boot
into setup mode, it will load the default certificates after start. So, we can't use CA Keys
.
Enable Secure Boot
with Shim
-
Install shim-signed from AUR.
-
Mount
ESP
.mkdir /boot-efi # the default efi partition is /dev/nvme0n1p1 on a OneXPlayer 2 Pro mount /dev/nvme0n1p1 /boot-efi
-
Copy the efi files to
ESP
.cp /usr/share/shim-signed/shimx64.efi /boot-efi/EFI/BOOT/ cp /usr/share/shim-signed/mmx64.efi /boot-efi/EFI/BOOT/
-
Create a NVRAM entry for
Shim
.efibootmgr --unicode --disk /dev/nvme0n1 --part 1 --create --label "Shim" --loader /EFI/BOOT/shimx64.efi
-
Install
rEFInd
.pacman -S refind refind-install --shim /usr/share/shim-signed/shimx64.efi --localkeys
-
Use openssl to create the mok keypair.
cd /etc/refind.d/keys/ openssl req -newkey rsa:2048 -nodes -keyout refind_local.key -new -x509 -sha256 -days 3650 -subj "/CN=onexplayer2pro-fortime/" -out refind_local.crt openssl x509 -outform DER -in refind_local.crt -out refind_local.cer cp refind_local.cer /boot/
-
Create a custom config of mkinitcpio.
cat <<EOF > /etc/mkinitcpio.conf.d/lkus.conf # allow usb keyboard to input password for decryption in boot time. MODULES=(usbhid xhci_hcd) HOOKS=(base systemd autodetect microcode modconf kms keyboard sd-vconsole plymouth block sd-encrypt filesystems fsck) EOF
-
Create the config file of ukify.
cat <<EOF >/etc/kernel/ukify.conf [UKI] Microcode=/boot/amd-ucode.img OSRelease=@/etc/os-release SecureBootPrivateKey=/etc/refind.d/keys/refind_local.key SecureBootCertificate=/etc/refind.d/keys/refind_local.crt EOF
-
Create cmdline files for kernel parameters.
# rd.luks.name: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX=name, Specify the name of the mapped device after the LUKS partition is open, where XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX is the UUID of the LUKS partition. # rd.luks.options: Set options for the device specified by it UUID or, if not specified, for all UUIDs not specified elsewhere (e.g., crypttab). # resume: Specify the root device for hibernation. # resume_offset: Specify the offset of the swap file. The offset of swap file in a btrfs file system should be calculated by `btrfs inspect-internal map-swapfile`. Refer to [Hibernation](#Hibernation) # video: Set the video kernel parameter to rotate the builtin screen from portrait to landscape in the start of the system. # usbcore.autosuspend: USB Ports / Controller stops working after Device Disconnect. cat <<EOF >/etc/kernel/cmdline rd.luks.name=XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX=root rd.luks.options=XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX=tpm2-device=auto root=/dev/mapper/root rw resume=/dev/mapper/root resume_offset=yyyyyyy quiet splash video=eDP-1:panel_orientation=left_side_up usbcore.autosuspend=-1 EOF
-
Create a
mkinitcpio
post hook.cat <<EOF >/etc/initcpio/post/ukify #!/usr/bin/env bash kernel="\$1" initramfs="\$2" [ -n "\$kernel" ] || exit 0 [ -n "\$initramfs" ] || exit 0 initramfs_filename=\$(basename "\$initramfs") cmdline="" uki="" ukify_log="" case "\$initramfs_filename" in "initramfs-linux.img") cmdline=/etc/kernel/cmdline uki="/boot/arch-linux.efi" ukify_log="/etc/refind.d/keys/ukify.log" ;; "initramfs-linux-fallback.img") cmdline=/etc/kernel/cmdline-fallback uki="/boot/arch-linux-fallback.efi" ukify_log="/etc/refind.d/keys/ukify-fallback.log" ;; *) exit 0 ;; esac # it is hard to measure the value of PCR 11 with the uki file, we keep the log for getting the value of PCR 11. ukify build --config=/etc/kernel/ukify.conf --linux="\$kernel" --initrd="\$initramfs" --cmdline="@\$cmdline" --measure --output="\$uki" >"\$ukify_log" 2>&1 if [ "\$initramfs_filename" = "initramfs-linux.img" ] then pcr11=\$(grep "11:sha256" "\$ukify_log" | sed '1!d;s/.*=//') if [ \$? -eq 0 ] then # use PCR 7, PCR 11 and PCR 14 to protect the key in tpm2, and use a recovery key to decrypt the partition. systemd-cryptenroll /dev/nvme0n1p5 --wipe-slot=tpm2 --tpm2-device=auto --tpm2-pcrs="7+11:sha256=\$pcr11+14" --unlock-key-file=/etc/refind.d/keys/disk-encrypt.txt fi fi EOF chmod 700 /etc/initcpio/post/ukify EOF
-
Sign the grub bootloader and the kernel.
refind-install --shim /usr/share/shim-signed/shimx64.efi --localkeys
-
Enroll the
refind_local.cer
.
Reboot and enable Secure Boot. If shim does not find the certificate grubx64.efi is signed with in MokList it will launch MokManager (mmx64.efi).
In MokManager select Enroll key from disk, find refind-local.cer and add it to MokList. When done select Continue boot and your boot loader will launch and it will be capable launching any binary signed with your Machine Owner Key.
Secure path
Hibernation
To enable hibernation, we should create a swap partition or a swap file. Using swap file in btrfs is different with other file system. We should use utils provided by btrfs to create a swap file.
- Create a swap file.
btrfs filesystem mkswapfile /var/cache/swapfile -s 16g
- Calculate the offset of the swapfile.
btrfs inspect-internal map-swapfile /var/cache/swapfile
- Add a swap item in
/etc/fstab
.# swapfile for hiberation /var/cache/swapfile none swap defaults 0 0
- Add
resume
andresume_offset
to kernel cmdline.
TPM issue in hibernation
Measurement of PCR 11 in hibernation is different from normal boot. In hibernation, there is no measurement of leave-initrd
before leaving initrd. The leaving of initrd happens in systemd-hibernate-resume.service
.
I created a temporarily fix by stopping systemd-pcrphase-initrd.service
before systemd-hibernate-resume.service
.
- Create a initcpio install hook, create
/etc/initcpio/install/pcrphase-fix
.#!/bin/bash build() { printf '[Service]\nExecStartPre=/usr/bin/systemctl stop systemd-pcrphase-initrd.service' | add_systemd_drop_in systemd-hibernate-resume.service override } help() { cat << EOF Fix the issue of no stop of systemd-pcrphase-initrd.service in resume. EOF }
- Update the custom config of mkinitcpio.
cat <<EOF > /etc/mkinitcpio.conf.d/lkus.conf # allow usb keyboard to input password for decryption in boot time. MODULES=(usbhid xhci_hcd) HOOKS=(base systemd pcrphase-fix autodetect microcode modconf kms keyboard sd-vconsole plymouth block sd-encrypt filesystems fsck) EOF
Mapping buttons
There is no volume up/down button of this machine. As a handheld game console, this is unforgivable. So, I want to map the x1/x2 button to volume up/down button. After using evtest monitoring the key events, these two buttons trigger a key combo instead of a single keycode. I can't use hwdb to map keys. Here, i use keyd
to finish this work.
- Install and enable
keyd
.pacman -S keyd systemctl enable keyd
- Create a file /etc/keyd/oxp2p.conf.
[ids] 0001:0001 [main] leftmeta+d = volumedown leftcontrol+leftmeta+o = volumeup
- Restart
keyd
.systemctl start keyd
Foldable bluetooth keyboard
The key in the removable keyboard cover is too small. I buy a foldable bluetooth keyboard. Everything is ok, but Fn keys are function keys by default. I use Fn keys a lot in vim. It makes me very inconvenient. So, I add a hwdb file to switch Fn key and function key.
- Add a hwdb file /etc/udev/hwdb.d/90-custom-keyboard.hwdb.
evdev:input:b0005v0A5Cp8503e011B* KEYBOARD_KEY_700e2=leftmeta KEYBOARD_KEY_700e3=leftalt KEYBOARD_KEY_700e6=rightmeta KEYBOARD_KEY_700e7=rightalt KEYBOARD_KEY_c0223=esc KEYBOARD_KEY_70029=homepage KEYBOARD_KEY_c0221=f1 KEYBOARD_KEY_7003a=search KEYBOARD_KEY_7003b=back KEYBOARD_KEY_7003c=forward KEYBOARD_KEY_7003d=brightnessdown KEYBOARD_KEY_7003e=brightnessup KEYBOARD_KEY_c00b6=f6 KEYBOARD_KEY_7003f=previoussong KEYBOARD_KEY_c00cd=f7 KEYBOARD_KEY_70040=playpause KEYBOARD_KEY_c00b5=f8 KEYBOARD_KEY_70041=nextsong KEYBOARD_KEY_c00b5=f8 KEYBOARD_KEY_70041=nextsong KEYBOARD_KEY_c00e2=f9 KEYBOARD_KEY_70042=mute KEYBOARD_KEY_c00ea=f10 KEYBOARD_KEY_70043=volumedown KEYBOARD_KEY_c00e9=f11 KEYBOARD_KEY_70044=volumeup KEYBOARD_KEY_c0030=f12 KEYBOARD_KEY_70045=power
- But its f2, f3, f4 and f5 send a key combo instead of a single key. I use
keyd
again. Add akeyd
config file.[ids] 0a5c:8503 [main] leftalt+a = f2 leftalt+c = f3 leftalt+v = f4 leftalt+x = f5
Auto rotation
The accelerator sensor showed in Windows device manager is bmi160. But the bmi160 driver in Linux can't work. After some research, I found that the bmi260 driver also matches the acpi device id 10EC5280
. So, I try this driver, and it works.
Install bmi260-dkms
from AUR.
# iio-sensor-proxy: Proxies sensor devices (accelerometers, light sensors, compass) to applications through D-Bus.
paru -S bmi260-dkms iio-sensor-proxy
Wrong direction
After installing bmi260-dkms
, the auto-rotate works, but the screen is 90 degrees clockwise rotated. We can use udev rules to fix it.
- Create a file /etc/udev/hwdb.d/90-custom-oxp.hwdb with following content.
sensor:modalias:acpi:10EC5280*:dmi:*:rnONEXPLAYER2PROARP23P:rvrVersion1.0:* ACCEL_MOUNT_MATRIX=0, -1, 0; -1, 0, 0; 0, 0, 1
- Update hwdb and trigger udev to update the device.
sudo systemd-hwdb update && sudo udevadm trigger
KDE touch mode
Be default, kde disables touch mode if there is any pointer device. I use keyd to map buttons, and keyd creates a virtual pointer device which will make kde disables touch mode all the time. After reviewing the source code of kwin, I found we can add a tag kwin-ignore-tablet-mode
to the keyd pointer device to let kde ignore the device.
- Create a file /etc/udev/rules.d/90-tablet-mode.rules.
ACTION=="remove", GOTO="kwin_ignore_tablet_mode_end" SUBSYSTEM=="input", KERNEL=="event*", ATTRS{id/vendor}=="0fac", ATTRS{id/product}=="1ade", TAG+="kwin-ignore-tablet-mode" LABEL="kwin_ignore_tablet_mode_end"
Audio
Internal Speaker Of OneXPlayer 2 Pro (8840) In Linux
Multi-touch
TODO
Drop of signal with external monitor
I have two external monitors, a portable monitor and a Philips 279C9. Both of them have signal drop issue when I'm playing games.
The portable monitor
I occasionally turn off Free Sync
of the portable monitor, and the issue disappeared. In a later research, I found the cause. I'm using wayland and I often connect to other monitors, overriding edid is not a good enough solution, so I still keep Free Sync
off.
The Philips 279C9
At first, I think this is the same as the portable monitor. But there are no setting of Free Sync
in the menu the monitor. After some research, I found that there will be a dropdown option in KDE Display Configuration
if the monitor supports Free Sync
.
To check if the monitor supports Free Sync
, I install wxedid
to inspect the edid info the monitor.
sudo get-edid -b ${bus_id} > /tmp/philips-edid.bin
wxedid /tmp/philips-edid.bin
When I was checking the edid info, I noticed that only 4k@30 is used even if the monitor supports 4k@60. Why? So I enable the drm debug log.
# enable all kinds of drm debug log
echo 0x1BF > /sys/module/drm/parameters/debug
# disable all drm debug log
echo 0x0 > /sys/module/drm/parameters/debug
# what does 0x1BF mean, it is flags of debug category.
modinfo -p drm
In the debug log, it showed something like:
[drm:create_validate_stream_for_sink [amdgpu]] Mode 3840x2160 (clk 533250) failed DC validation with error 10 (No DP link bandwidth)
All modelines with pixel clock of 533250 are rejected. But when I switched to Windows
, 4k@60 is supported. It shouldn't be a quality issue of the cable. When I was trying to add more debug log, I occasionally found a comment of Philips 279C9
. It said that 4k@60 can only be used after switching usb3.2 to usb2.0 in the monitor menu when it is connected to a Mac OS. I tried this and the option of 4k@60 appeared. When I'm using 4k@60, the signal drop issue disappear too. I think it is because it will reduce the estimated bandwidth of a DP link if the type-c port is used as a usb3.2 hub.
I can’t believe I spent 10 hours troubleshooting during national day vacation! And it can be solved just by changing a setting like this. At last, I still don't know why this cause the signal drop issue, and why 4k@60 can be used in Windows
even if usb3.2 is using. ~~If the signal drop issue exists if I am using 4k@30 and usb2.0.~~The signal drop issue disappers after switching to usb2.0.
Reference
- https://wiki.archlinux.org/title/Dm-crypt/
- https://wiki.archlinux.org/title/Dm-crypt/System_configuration
- https://wiki.archlinux.org/title/Dm-crypt/Encrypting_an_entire_system#LUKS_on_a_partition_with_TPM2_and_Secure_Boot
- https://wiki.ubuntu.com/UEFI/SecureBoot
- https://wiki.archlinux.org/title/Unified_Extensible_Firmware_Interface/Secure_Boot
- https://git.launchpad.net/~ubuntu-core-dev/grub/+git/ubuntu/tree/debian/build-efi-images
- https://wiki.archlinux.org/title/Plymouth
- https://btrfs.readthedocs.io/en/latest/Swapfile.html
- https://github.com/ublue-os/bazzite/issues/440
- https://wiki.archlinux.org/title/Variable_refresh_rate#Monitor_occasionally_drops_signal_with_FreeSync_enabled