FreeBSD on the ThinkPad X240

So, I bought a laptop to run FreeBSD.

I was going to get a C720 Chromebook, but I got a good deal for an X240. Yeah, yeah, a laptop from the preinstalled-insecure-adware company, whatever. Anyway, it’s a ThinkPad, so it feels very solid, has an excellent keyboard and good free software support.

So, let’s get FreeBSD running!

Installation

I’ve replaced the stock HDD with an SSD, compiled the drm-i915-update-38 branch of FreeBSD on a different machine, wrote the memstick image to an old USB flash drive, booted it and installed FreeBSD on the ThinkPad.

The first installation, with ZFS root + UFS /boot, did not work because the EFI loader couldn’t load zfs.ko. After reinstalling on UFS, the loader does load zfs.ko… Oh well.

GRUB 2 is also an option (and the option for using sysutils/beadm), but the recent “backspace 28 times to bypass boot passphrase” vulnerability really discouraged me from installing it. Of course, what are you even trying to protect with that passphrase, but ugh, GNU code “quality”.

Power management

The usual laptop settings for /etc/rc.conf:

powerd_enable="YES"
powerd_flags="-a hiadaptive -b adaptive -i 75 -r 85 -p 500"
performance_cx_lowest="Cmax"
economy_cx_lowest="Cmax"

And for /boot/loader.conf:

hw.pci.do_power_nodriver=3
drm.i915.enable_rc6=7
hw.snd.latency=7
hint.pcm.0.buffersize=65536
hint.pcm.1.buffersize=65536
hint.pcm.2.buffersize=65536
hw.snd.feeder_buffersize=65536

Battery life with the internal + big external battery: ~8 - 8.5 hours of mostly surfing the web with Firefox on Wi-Fi with 50% screen brightness. (Obviously, more hours without Firefox :D) I don’t know how some reviewers got 20 hours of Wi-Fi browsing on Windows. Linux users say it’s 6-7 hours or above 8 hours, so FreeBSD is not worse than Linux there. That’s good :-)

I couldn’t get suspend/resume to work. It does suspend but doesn’t resume (pressing the power button makes the fans spin, but the power button is still blinking).

But putting the X240 into sleep mode for short breaks is not really necessary. With the huge battery and the ultra-low-power processor, just leaving it running for 15-30 minutes won’t drain the battery much.

Oh, and the power consumption can be measured with Intel’s performance counters. Install sysutils/intel-pcm and run:

$ sudo kldload cpuctl
$ sudo pcm.x

Power consumption of the CPU (and GPU, and everything else on the chip) when idle and running Xorg is around 3 Watt.

Ethernet and Wi-Fi

Works. This laptop has Intel’s networking hardware, which is great news for free operating systems. Not that I like Intel (super evil Management Engine!!) but they do write open source drivers for Linux, and BSD developers port them to the BSDs.

The Intel PRO/1000 Ethernet card is supported by the em driver.

The Intel 7260 wireless card is supported by the iwm driver in 11-CURRENT (drm-i915-update-38 is based on 11-CURRENT).

Only 802.11g is supported in iwm for now (IIRC because the driver is imported from OpenBSD, and they’re still working on 802.11n support).

Bluetooth

Doesn’t work.

Apparently, it’s this one.

It’s not even connecting as a USB device:

usbd_req_re_enumerate: addr=1, set address failed! (USB_ERR_TIMEOUT, ignored)
usbd_setup_device_desc: getting device descriptor at addr 1 failed, USB_ERR_TIMEOUT
ugen0.2: <Unknown> at usbus0 (disconnected)
uhub_reattach_port: could not allocate new device

I never use Bluetooth on laptops, anyway.

Graphics (Intel HD Graphics on Haswell!)

Works. Well, there’s a reason I’m using the drm-i915-update-38 branch ;-) This is not in a release yet — it’s not even in -CURRENT! — so I’m not expecting perfect quality.

But it works fine with correct settings.

Do not load i915kms in the boot loader!! The system won’t boot. Instead, use the kld_list setting in /etc/rc.conf to load the module later in the boot process.

When you load i915kms, it will repeat this error for less than a second:

error: [drm:pid51453:intel_sbi_read] *ERROR* timeout waiting for SBI to complete read transaction
error: [drm:pid51453:intel_sbi_write] *ERROR* timeout waiting for SBI to complete write transaction

That’s okay, it works anyway. Looks like this is not even Haswell specific.

So, here’s the xorg.conf part:

Section "Device"
      Option      "AccelMethod"        	"sna"
      Option      "TripleBuffer"       	"true"
      Option      "HotPlug"            	"true"
      Option      "TearFree"           	"false"
      Identifier  "Card0"
      Driver      "intel"
      BusID       "PCI:0:2:0"
EndSection

Do not use uxa acceleration, it’s an old method and doesn’t work correctly on Haswell (text corruption on screen, application crashes). sna means Sandy Bridge New Acceleration, newer than uxa.

Do not use the TearFree option, it immediately crashes Xorg. Instead, use VSync in compton (or any X compositor I guess) to eliminate tearing. The following compton options work for me:

$ compton --backend xr_glx_hybrid --vsync opengl-swc # and then the shadows and fades and stuff

Do not use compton’s glx backend, it doesn’t work correctly (weird glitches, app crashes, etc).

Do not use compton’s drm VSync method, it seems to make the whole system hang/reboot more often.

UPDATE: disable the assertion that causes panics and rebuild the module. Recent changes also fix corruption bugs, probably glx in compton too.

Brightness adjustment works via both graphics/intel-backlight and acpi_video (sysctl hw.acpi.video.lcd0.brightness). The brightness keys on the keyboard don’t work properly though. The fn key on F5 (lower brightness) just sets the brightness to maximum, F6 (raise brightness) does nothing. Here’s the error that’s shown when pressing the lower brightness key with drm.debug=3 in /boot/loader.conf:

[drm:KMS:pid12:intel_panel_get_max_backlight] max backlight PWM = 852
[drm:KMS:pid12:intel_panel_actually_set_backlight] set backlight PWM = 841
[drm:pid12:intel_opregion_gse_intr] PWM freq is not supported

So I’ve configured F5 and F6 (the real function keys, FnLock mode) to call intel_backlight.

UPDATE: acpi_video is the one incorrectly changing the brightness to max! Don't load it. acpi_ibm changes the brightness correctly!

HDMI output works with a Mini DisplayPort adapter. 1080p video playback on an HDMI TV using mpv is smooth.

VAAPI video output and hardware accelerated decoding works. With mpv --vo=vaapi --hwdec=vaapi, CPU usage is around 20% for a 1080p H.264 video (vs. 60% with software decoding), the fans stay silent. You’ll need to install multimedia/libva-intel-driver and multimedia/mpv from pkg, and rebuild multimedia/ffmpeg with the VAAPI option.

OpenCL on the Haswell GPU (powered by Beignet) doesn’t work yet. clinfo shows:

Beignet: self-test failed: (3, 7, 5) + (5, 7, 3) returned (3, 7, 5)

Audio

Works. The built-in Realtek ALC292 sound card just works. FreeBSD’s audio support is good.

The internal microphone is recognized as a separate device:

$ cat /dev/sndstat
Installed devices:
pcm0: <Intel Haswell (HDMI/DP 8ch)> (play)
pcm1: <Realtek ALC292 (Analog 2.0+HP/2.0)> (play/rec) default
pcm2: <Realtek ALC292 (Internal Analog Mic)> (rec)

HDMI audio works too (sysctl hw.snd.default_unit to switch the sound card; applications that play sound have to be restarted.)

Webcam

Works. With webcamd, of course. But I don’t need it, so I’ve disabled it in the BIOS Setup.

SD card reader

Doesn’t work.

pciconf detects it as:

none2@pci0:2:0:0:       class=0xff0000 card=0x221417aa chip=0x522710ec rev=0x01 hdr=0x00
    vendor     = 'Realtek Semiconductor Co., Ltd.'
    device     = 'RTS5227 PCI Express Card Reader'

It’s supported in OpenBSD with rtsx(4). FreeBSD bugs for this: 161719, 204521.

It should be possible to use it with OpenBSD/NetBSD/Linux in a bhyve VM with PCI passthrough, like the Wi-Fi card before iwm was added. That would also be more secure (that’s what Qubes does for all the hardware.) But I don’t need to use SD cards on this laptop.

Trackpad and TrackPoint

Oh, this is the most interesting part. Well, it works, sure. But there are at least three ways of using them, none of which is perfect.

moused

FreeBSD includes moused, a little daemon that watches the mouse device you tell it to watch and forwards all events to a virtualized mouse, which is accessible to Xorg at /dev/sysmouse and also works on the text console. It has advanced support (like sensitivity settings) for Synaptics touchpads and ThinkPad TrackPoints (set hw.psm.synaptics_support=1 and hw.psm.trackpoint_support=1 in /boot/loader.conf to enable).

Sadly, it forwards all events to a virtualized mouse. Not a trackpad, just a mouse, so the experience is not as good.

xorg.conf:

Section "InputDevice"
      Identifier "SysMouse"
      Driver     "mouse"
      Option     "Device" "/dev/sysmouse"
EndSection

xf86-input-synaptics

This is the Synaptics driver that provides a great trackpad experience. Inertial scrolling, horizontal scrolling, natural scrolling, perfectly smooth cursor movement… Everything is as good as in OS X on a MacBook.

But the TrackPoint doesn’t work. On the X240, it’s attached to the trackpad as a guest mouse. The trackpad forwards the TrackPoint’s PS/2 events with a special mark (IIRC, it’s W = 3).

And the Synaptics driver stopped supporting guest devices in 2010.

UPDATE: added the guest mouse support back to xf86-input-synaptics! Also adds ClickPad support to the raw PS/2 protocol used by the driver on the BSDs (on Linux, it uses evdev, and they only added clickpad support there).

Also, clicking doesn’t work, but I don’t care. I’m used to tapping.

xorg.conf:

Section "InputDevice"
      Identifier  "Touchpad"
      Driver      "synaptics"
      Option      "Protocol" "psm"
      Option      "Device" "/dev/psm0"
      Option      "VertEdgeScroll" "off"
      Option      "VertTwoFingerScroll" "on"
      Option      "HorizEdgeScroll" "off"
      Option      "HorizTwoFingerScroll" "on"
      Option      "VertScrollDelta" "-111"
      Option      "HorizScrollDelta" "-111"
      Option      "ClickPad" "on"
      Option      "SoftButtonAreas" "4201 0 0 1950 2710 4200 0 1950"
      Option      "AreaTopEdge" "5%"
EndSection

evdevfbsd

I accidentally found evdevfbsd, a little program that exposes PS/2 devices as evdev devices via CUSE (Character Device in Userspace).

evdev is a protocol that comes from Linux. It allows kernel (or CUSE) drivers to provide a standardized interface for devices so that Xorg wouldn’t care about any particular vendor.

evdevfbsd correctly separates the trackpad and the TrackPoint. Cursor movement works. But only cursor movement. No touch scrolling, no tapping, no clicking. And it looks like it might be xf86-input-evdev’s fault, because evtest.py shows tap events when tapping!

Something else?

I’ve tried to write a CUSE program that works as a proxy between /dev/psm0 and the Synaptics driver, extracting guest (TrackPoint) events in the process.

It almost works… the only problem is that the Synaptics driver locks the whole X server while reading from my proxy, so only mouse movement works and nothing else, not even Ctrl+Alt+F1 to switch to a console. Well, the power button works. And SSHing into the laptop.

Seems like the problem with CUSE is that there’s no way to find out, in the poll method, that the process that polls your device wants to stop. So, when moused reads from the proxy, it works, but when you stop moused with Ctrl-C, it doesn’t stop until you touch the TrackPoint or the trackpad a little to send an event.

UPDATE: added the guest mouse support back to xf86-input-synaptics!

Touchscreen

Works. It’s recognized as a USB HID device at /dev/uhid0. There are two ways to use it in Xorg.

Mouse emulation

The simple way: you can use it with the mouse driver, as a regular mouse. Obviously, this does not provide multi-touch.

xorg.conf:

Section "InputDevice"
      Identifier "Touchscreen"
      Driver     "mouse"
      Option     "Protocol" "usb"
      Option     "Device" "/dev/uhid0"
EndSection

Multi-touch

The other way: you can use it with webcamd and the evdev driver. This will actually support multi-touch.

Recompile x11-drivers/xf86-input-evdev from ports with the MULTITOUCH option, start webcamd like this (note that CUSE is part of the base system on 11-CURRENT, so it’s not called cuse4bsd anymore):

$ sudo make -C /usr/ports/x11-drivers/xf86-input-evdev config deinstall install clean
$ sudo kldload cuse
$ sudo webcamd -d ugen1.3 -N Touchscreen-ELAN -M 0

xorg.conf:

Section "InputDevice"
      Identifier "Touchscreen"
      Driver     "evdev"
      Option     "Device" "/dev/input/event0"
EndSection

Start chrome --touch-events and visit the touch event test! Also, you can scroll in GTK+ 3 applications like Corebird.

Unfortunately, it’s really bad at detecting when a touch ends. This means that scrolling and tapping will get stuck. So I’m using the mouse driver for now.

TPM (Trusted Platform Module)

Works. (With the dedicated TPM 1.2 module. Haven’t tried Intel’s built-in TPM 2.0 support. The choice between them is in the BIOS/UEFI settings.)

OpenSSH works with a TPM key through simple-tpm-pk11.

Conclusion

It’s possible to use a Haswell ThinkPad with FreeBSD right now :-) Everything except Bluetooth, SD cards and waking up from sleep works.

OpenBSD would be better though. They have excellent ThinkPad support, because OpenBSD developers use OpenBSD on ThinkPads. But I’m working on software that uses FreeBSD jails, and I just prefer FreeBSD.

@myfreeweb @FiLiS sdcard reader not working is a no for me as I am depending on it :( (copying GB of data from my camera's sdcard)
@plantanran @myfreeweb does this work for you? lists.freebsd.org/pipermail/free… mentions mmc_load, mmcsd_load, sdhci_load in loader.conf
@FiLiS @plantanran no, this is a non standard card reader, i've linked to openbsd's driver in my post.

use an external reader
@myfreeweb if you have a UFS partition then the current loader will use that. Skip UFS, & you can boot direct to zfs. I have refind to help.
@myfreeweb thanks nice tips "usual laptop settings" good to know! I put all of /boot/ into UEFI partition to get boot to zfs working on MBP
@dch__ does the EFI loader search EFI (FAT) partitions too? I know it currently looks for the first UFS partition

I admit: I envy you for ZFS. I wish we could use it w/o third-party modules on Linux.