FreeBSD and custom firmware on the Google Pixelbook

Back in 2015, I jumped on the ThinkPad bandwagon by getting an X240 to run FreeBSD on. Unlike most people in the ThinkPad crowd, I actually liked the clickpad and didn’t use the trackpoint much. But this summer I’ve decided that it was time for something newer. I wanted something..

  • lighter and thinner (ha, turns out this is actually important, I got tired of carrying a T H I C C laptop - Apple was right all along);
  • with a 3:2 display (why is Lenovo making these Serious Work™ laptops 16:9 in the first place?? 16:9 is awful in below-13-inch sizes especially);
  • with a HiDPI display (and ideally with a good size for exact 2x scaling instead of fractional);
  • with USB-C ports;
  • without a dGPU, especially without an NVIDIA GPU;
  • assembled with screws and not glue (I don’t necessarily need expansion and stuff in a laptop all that much, but being able to replace the battery without dealing with a glued chassis is good);
  • supported by FreeBSD of course (“some development required” is okay but I’m not going to write big drivers);
  • how about something with open source firmware, that would be fun.

The Qualcomm aarch64 laptops were out because embedded GPU drivers like freedreno (and UFS storage drivers, and Qualcomm Wi-Fi..) are not ported to FreeBSD. And because Qualcomm firmware is very cursed.

Samsung’s RK3399 Chromebook or the new Pinebook Pro would’ve been awesome.. if I were a Linux user. No embedded GPU drivers on FreeBSD, again. No one has added the stuff needed for FDT/OFW attachment to LinuxKPI. It’s rather tedious work, so we only support PCIe right now. (Can someone please make an ARM laptop with a PCIe GPU, say with an MXM slot?)

So it’s still gonna be amd64 (x86) then.

I really liked the design of the Microsoft Surface Book, but the iFixit score of 1 (one) and especially the Marvell Wi-Fi chip that doesn’t have a driver in FreeBSD are dealbreakers.

I was considering a ThinkPad X1 Carbon from an old generation - the one from the same year as the X230 is corebootable, so that’s fun. But going back in processor generations just doesn’t feel great. I want something more efficient, not less!

And then I discovered the Pixelbook. Other than the big huge large bezels around the screen, I liked everything about it. Thin aluminum design, a 3:2 HiDPI screen, rubber palm rests (why isn’t every laptop ever doing that?!), the “convertibleness” (flip the screen around to turn it into.. something rather big for a tablet, but it is useful actually), a Wacom touchscreen that supports a pen, mostly reasonable hardware (Intel Wi-Fi), and that famous coreboot support (Chromebooks’ stock firmware is coreboot + depthcharge).

So here it is, my new laptop, a Google Pixelbook.

What is a Chromebook, even

The write protect screw is kind of a meme. All these years later, it’s That Thing everyone on various developer forums associates with Chromebooks. But times have moved on. As a reaction to glued devices and stuff, the Chrome firmware team has discovered a new innovative way of asserting physical presence: sitting around for a few minutes, pressing the power button when asked. Is actually pretty clever though, it is more secure than.. not doing that.

Wait, what was that about?

Let’s go back to the beginning and look at firmware security in Chromebooks and other laptops.

These devices are designed for the mass market first. Your average consumer trusts the vendor and (because they’ve read a lot of scary news) might be afraid of scary attackers out to install a stealthy rootkit right into their firmware. Businesses are even more afraid of that, and they push for boot security on company laptops even more. This is why Intel Boot Guard is a thing that the vast majority of laptops have these days. It’s a thing that makes sure only the vendor can update firmware. Evil rootkits are out. Unfortunately, the user is also out.

Google is not like most laptop vendors.

Yes, Google is kind of a surveillance capitalism / advertising monster, but that’s not what I’m talking about here. Large parts of Google are very much driven by FOSS enthusiasts. Or something. Anyway, the point is that Chromebooks are based on FOSS firmware and support user control as much as possible. (Without compromising regular-user security, but turns out these are not conflicting goals and we can all be happy.)

Instead of Boot Guard, Google has its own way of securing the boot process. The root of trust in modern (>=2017) devices is a special Google Security Chip, which in normal circumstances also ensures that only Google firmware runs on the machine, but:

  • if you sit through the aforementioned power-button-clicking procedure, you get into Developer Mode: OS verification is off, you have a warning screen at boot, and you can press Ctrl-D to boot into Chrome OS, or (if you enabled this via a command run as root) Ctrl-L to open SeaBIOS.
    • Here’s the fun part.. it doesn’t have to be SeaBIOS. You can flash any Coreboot payload into the RW_LEGACY slot right from Chrome OS, reboot, press a key and you’re booting that payload!
  • if you also buy or solder a special cable (“SuzyQable”) and do the procedure a couple times more, your laptop turns into the Ultimate Open Intel Firmware Development Machine. Seriously.
    • the security chip is a debug chip too! Case Closed Debugging gives you serial consoles for the security chip itself, the embedded controller (EC) and the application processor (AP, i.e. your main CPU), and it also gives you a flasher (via special flashrom for now, but I’m told there’s plans to upstream) that allows you to write AP and EC firmware;
    • some security is still preserved with all the debugging: you can (and should) set a CCD password, which lets you lock-unlock the debug capabilities and change write-protect whenever you want, so that only you can flash firmware (at least without opening the case and doing very invasive things, the flash chip is not even SOIC anymore I think);
    • and you can hack without fear: the security chip is not brickable! Yes, yes, that means the chip is only a “look but don’t touch” kind of open source, it will only boot Google-signed firmware. Some especially paranoid people think this is An NSA Backdoor™. I think this is an awesome way to allow FULL control of the main processor and the EC, over just a cable, with no way of bricking the device! And to solve the paranoia, reproducible builds would be great.

You mentioned something about FreeBSD in the title?

Okay, okay, let’s go. I didn’t even want to write an introduction to Chromebooks but here we are. Anyway, while waiting for the debug cable to arrive, I’ve done a lot of work on FreeBSD, using the first method above (RW_LEGACY).

SeaBIOS does not have display output working in OSes that don’t specifically support the Coreboot framebuffer (OpenBSD does, FreeBSD doesn’t), and I really just hate legacy BIOS, so I’ve had to install a UEFI implementation into RW_LEGACY since I didn’t have the cable yet. My own EDK2 build did not work (now I see that it’s probably because it was a debug build and that has failing assertions). So I’ve downloaded MrChromebox’s full ROM image, extracted the payload using cbfstool and flashed that. Boom. Here we go, press Ctrl-L for UEFI. Nice. Let’s install FreeBSD.

The live USB booted fine. With the EFI framebuffer, an NVMe SSD and a PS/2 keyboard it was a working basic system. I’ve resized the Chrome OS data partition (Chrome OS recovers from that fine, without touching custom partitions), found that there’s already an EFI system partition (with a GRUB2 setup to boot Chrome OS, which didn’t boot like that o_0), installed everything and went on with configuration and developing support for more hardware.

(note: I’m leaving out the desktop configuration part here, it’s mostly a development post; I use Wayfire as my display server if you’re curious.)

So how’s the hardware?

Wi-Fi and Bluetooth

Well, that was easy. The Pixelbook has an Intel 7265. The exact same wireless chip that was in my ThinkPad. So, Wi-Fi works great with iwm.

Bluetooth.. if this was the newer 8265, would’ve already just worked :D

These Intel devices present a “normal” ubt USB Bluetooth adapter, except it only becomes normal if you upload firmware into it, otherwise it’s kinda dead. (And in that dead state, it spews interrupts, raising the idle power consumption by preventing the system from going into package C7 state! So usbconfig -d 0.3 power_off that stuff.) FreeBSD now has a firmware uploader for the 8260/8265, but it does not support the older protocol used by the 7260/7265. It wouldn’t be that hard to add that, but no one has done it yet.

Input devices


Google kept the keyboard as good old PS/2, which is great for ensuring that you can get started with a custom OS with a for-sure working keyboard.

About the only interesting thing with the keyboard was the Google Assistant key, where the Win key usually is. It was not recognized as anything at all. I used DTrace to detect the scancode without adding prints into the kernel and rebooting:

dtrace -n 'fbt::*scancode2key:entry { printf("[st %x] %x?\n", *(int*)arg0, arg1); } \
  fbt::*scancode2key:return { printf("%x\n", arg1);  }'

And wrote a patch to interpret it as a useful key (right meta, couldn’t think of anything better).


The touchpad and touchscreen are HID-over-I²C, like on many other modern laptops. I don’t know why this cursed bus from the 80s is gaining popularity, but it is. At least FreeBSD has a driver for Intel (Synopsys DesignWare really) I²C controllers.

(Meanwhile Apple MacBooks now use SPI for even the keyboard. FreeBSD has an Intel SPI driver but right now it only supports ACPI attachment for Atoms and such, not PCIe yet.)

The even better news is that there is a nice HID-over-I²C driver in development as well. (note: the corresponding patch for configuring the devices via ACPI is pretty much a requirement, uncomment -DHAVE_ACPI_IICBUS in the iichid makefile too to get that to work. Also, upcoming Intel I²C improvement patch.)

The touchscreen started working with that driver instantly.

The touchpad was.. a lot more “fun”. The I²C bus it was on would just appear dead. After some debugging, it turned out that the in-progress iichid driver was sending a wrong extra out-of-spec command, which was causing Google’s touchpad firmware to throw up and lock up the whole bus.

But hey, nice bug discovery, if any other device turns out to be as strict in accepting input, no one else would have that problem.

Another touchpad thing: by default, you have to touch it with a lot of pressure. Easily fixed in libinput:

% cat /usr/local/etc/libinput/local-overrides.quirks
[Eve touchpad]

UPD 2019-10-24 Pixelbook Pen

The touchscreen in the Pixelbook is made by Wacom, and supports stylus input like the usual Wacom tablets. For USB ones, on FreeBSD you can just use webcamd to run the Linux driver in userspace. Can’t exactly do that with I²C.

But! Thankfully, it exposes generic HID stylus reports, zero Wacom specifics required. I’ve been able to write a driver for that quite easily. Now it works. With pressure, tilt, the button, all the things :)

Display backlight brightness

This was another “fun” debugging experience. The intel_backlight console utility (which was still the thing to use on FreeBSD) did nothing.

I knew that the i915 driver on Chrome OS could adjust the brightness, so I made it work here too, and all it took is:

  • adding more things to LinuxKPI to allow uncommenting the brightness controls in i915kms;
  • (and naturally, uncommenting them);
  • finding out that this panel uses native DisplayPort brightness configured via DPCD (DisplayPort Configuration Data), enabling compat.linuxkpi.i915_enable_dpcd_backlight="1" in /boot/loader.conf;
  • finding out that there’s a fun bug in the.. hardware, sort of:
    • the panel reports that it supports both DPCD backlight and a direct PWM line (which is true);
    • Google/Quanta/whoever did not connect the PWM line;
    • (the panel is not aware of that);
    • the i915 driver prefers the PWM line when it’s reported as available.

Turns out there was a patch sent to Linux to add a “prefer DPCD” toggle, but for some reason it was not merged. The patch does not apply cleanly so I just did a simpler hack version:

--- i/drivers/gpu/drm/i915/intel_dp_aux_backlight.c
+++ w/drivers/gpu/drm/i915/intel_dp_aux_backlight.c
@@ -252,8 +252,12 @@ intel_dp_aux_display_control_capable(struct intel_connector *connector)
         * the panel can support backlight control over the aux channel
        if (intel_dp->edp_dpcd[1] & DP_EDP_TCON_BACKLIGHT_ADJUSTMENT_CAP &&
-           (intel_dp->edp_dpcd[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_AUX_SET_CAP) &&
-           !(intel_dp->edp_dpcd[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_PWM_PIN_CAP)) {
+           (intel_dp->edp_dpcd[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_AUX_SET_CAP)
+/* for Pixelbook (eve), simpler version of https://patchwork.kernel.org/patch/9618065/ */
+#if 0
+            && !(intel_dp->edp_dpcd[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_PWM_PIN_CAP)
+                       ) {
                DRM_DEBUG_KMS("AUX Backlight Control Supported!\n");
                return true;

And with that, it works, with 65536 steps of brightness adjustment even.


The Pixelbook uses regular old ACPI S3 sleep, not the fancy new S0ix thing, so that’s good.

On every machine with a TPM though, you have to tell the TPM to save state before suspending, otherwise you get a reset on resume. I already knew this because I’ve experienced that on the ThinkPad.

The Google Security Chip runs an open-source TPM 2.0 implementation (fun fact, written by Microsoft) and it’s connected via… *drum roll* I²C. Big surprise (not).

FreeBSD already has TPM 2.0 support in the kernel, the userspace tool stack was recently added to Ports as well. But of course there was no support for connecting to the TPM over I²C, and especially not to the Cr50 (GSC) TPM specifically. (it has quirks!)

I wrote a driver (WIP) hooking up the I²C transport (relies on the aforementioned ACPI-discovery-of-I²C patch). It does not use the interrupt (I found it buggy: at first attachment, it fires continuously, and after a reattach it stops completely) and after attach (or after system resume) the first command errors out, but that can be fixed and other than that, it works. Resume is fixed, entropy can be harvested, it could be used for SSH keys too.

Another thing with resume: I’ve had to build the kernel with nodevice sdhci to prevent the Intel SD/MMC controller (which is not attached to anything here - I’ve heard that the 128GB model might be using eMMC instead of NVMe but that’s unclear) from hanging for a couple minutes on resume.

Dynamic CPU frequency

At least on the stock firmware, the old-school Intel SpeedStep did not work because the driver could not find some required ACPI nodes (perf or something).

Forget that, the new Intel Speed Shift (which lets the CPU adjust frequency on its own) works nicely with the linked patch.

Tablet mode switch

When the lid is flipped around, the keyboard is disabled (unless you turn the display brightness to zero, I’ve heard - which is fun because that means you can connect a montior and have a sort-of computer-in-a-keyboard look, like retro computers) and the system gets a notification (Chrome OS reacts to that by enabling tablet mode).

Looking at the DSDT table in ACPI, it was quite obvious how to support that notification:

Device (TBMC) {
    Name (_HID, "GOOG0006")  // _HID: Hardware ID
    Name (_UID, One)  // _UID: Unique ID
    Name (_DDN, "Tablet Motion Control")  // _DDN: DOS Device Name
    Method (TBMC, 0, NotSerialized) {
        If ((RCTM () == One)) { Return (One) }
        Else { Return (Zero) }

On Linux, this is exposed as an evdev device with switch events. I was able to replicate that quite easily. My display server does not support doing anything with that yet, but I’d like to do something like enabling an on-screen keyboard to pop up automatically when tablet mode is active.

Keyboard backlight brightness

I generally leave it off because I don’t look at the keyboard, but this was a fun and easy driver to write.

Also obvious how it works when looking at ACPI:

Device (KBLT) {
    Name (_HID, "GOOG0002")  // _HID: Hardware ID
    Name (_UID, One)  // _UID: Unique ID
    Method (KBQC, 0, NotSerialized) {
        Return (^^PCI0.LPCB.EC0.KBLV) /* \_SB_.PCI0.LPCB.EC0_.KBLV */
    Method (KBCM, 1, NotSerialized) {
        ^^PCI0.LPCB.EC0.KBLV = Arg0

Using the debug cable on FreeBSD

The debug cable presents serial consoles as bulk endpoints without any configuration capabilities. On Linux, they are supported by the “simple” USB serial driver.

Adding the device to the “simple” FreeBSD driver ugensa took some debugging. The driver was clearing USB stalls when the port is opened. That’s allowed by the USB spec and quite necessary on some devices. Unfortunately, the debug interface throws up when it sees that request. The responsible code in the device has a /* Something we need to add support for? */ comment :D


The only thing that’s unsupported is onboard audio. The usual HDA controller only exposes the DisplayPort audio-through-the-monitor thing. The speakers, mic and headphone jack are all connected to various codecs exposed via… yet again, I²C. I am not about to write the drivers for these codecs, since I’m not really interested in audio on laptops.

Firmware is Fun

After the debug cable arrived, I’ve spent some time debugging the console-on-FreeBSD thing mentioned above, and then started messing with coreboot and TianoCore EDK2.

My discoveries so far:

  • there’s nothing on the AP console on stock firmware because Google compiles release FW with serial output off, I think to save on power or something;
  • me_cleaner needs to be run with -S -w MFS. As mentioned in the --help, the MFS partition contains PCIe related stuff. Removing it causes the NVMe drive to detach soon after boot;
  • upstream Coreboot (including MrChromebox’s builds) fails to initialize the TPM, just gets zero in response to the vendor ID request. Funnily enough, that would’ve solved the resume problem without me having to write the I²C TPM driver for FreeBSD - but now that I’ve written it, I’d prefer to actually have the ability to use the TPM;
  • EDK2’s recent UefiPayloadPkg doesn’t support PS/2 keyboard and NVMe out of the box, but they’re very easy to add (hopefully someone would add them upstream after seeing my bug reports);
  • UefiPayloadPkg supports getting the framebuffer from coreboot very well;
  • coreboot can run Intel’s GOP driver before the payload (it’s funny that we’re running a UEFI module before running the UEFI implementation) and that works well;
  • but libgfxinit - the nice FOSS, written-in-Ada, verified-with-SPARK implementation of Intel GPU initialization and framebuffer configuration - supports Kaby Lake now!
    • however, we have a DPCD thing again with this display panel here - it reports max lane bandwidth as 0x00, libgfxinit interprets that as the slowest speed and we end up not having enough bandwidth for the high-res screen;
    • I’ve been told that this is because there’s a new way of conveying this information that’s unsupported. I’ll dig around in the Linux i915 code and try to implement it properly here but for now, I just did a quick hack, hardcoding the faster bandwidth. Ta-da! My display is initialized with formally verified open source code! Minus one blob running at boot!
  • persistent storage of EFI variables needs some SMM magic. There’s a quick patch that changes EDK2’s emulated variable store to use coreboot’s SMM store. EDK2 has a proper SMM store of its own, I’d like to look into making that coreboot-compatible or at least just writing a separate coreboot-compatible store module.
  • UPD 2019-10-24 for external displays, DisplayPort alt mode on USB-C can be used. Things to note:
    • DP++ (DP cables literally becoming HDMI cables) can’t work over USB Type C, which is why there are no HDMI-A-n connectors on the GPU, so a passive HDMI-mDP dongle plugged into a mDP-TypeC dongle won’t work;
    • the Chrome EC runs the alt mode negotiation, the OS doesn’t need any special support;
    • for DP dongles to work at all, the EC must run RW firmware and that doesn’t happen as-is with upstream coreboot. There is a jump command on the EC console. Also this patch should help?? (+ this)

An aside: why mess with firmware?

If you’re not the kind of person who’s made happy by just the fact that some more code during the boot process of their laptop is now open and verified, and you just want things to work, you might not be as excited about open source firmware development as I am.

But you can do cool things with firmware that give you practical benefit. The best example I’m seeing is better Hackintosh support. Instead of patching macOS to work on your machine, you could patch your machine to pretend to almost be a Mac:

Is this cool or what?


Pixelbook, FreeBSD, coreboot, EDK2 good.

Seriously, I have no big words to say, other than just recommending this laptop to FOSS enthusiasts :)

Moving VMs from VirtualBox to Client Hyper-V

I’ve decided to move the VMs on my desktop from VirtualBox to Microsoft Hyper-V. Because reasons.

Actually because I’ve upgraded my desktop to an AMD Ryzen CPU: first, AMD-V/SVM is not supported by the Intel HAXM thing from the Android SDK, so I wanted to try out Microsoft’s Hyper-V based Android “emulator” (VM configurator/runner thingy) instead. Second, giving 16 virtual CPUs on an SMT 8-core to a FreeBSD guest in VirtualBox results in a weird performance issue. (Though giving 4 vCPUs to multiple VMs on a 4-core CPU worked fine.) Third, it’s Oracle VM VirtualBox and no one likes Oracle.

So, here’s how you can do it as well.

How to get Hyper-V

You need Windows 10 Pro, Enterprise or Education. (Or Windows Server, obviously.) Just enable it as a feature and restart.

Alternatively, installing the MS Android “emulator” automatically enables it.

How to migrate a VM (FreeBSD, Linux or Windows with EFI)

(NOTE: older versions of FreeBSD apparently had some loader issue that prevented EFI boot in Hyper-V. Everything works for me on a recent build of 11-STABLE.)

In VirtualBox, go to the Virtual Media Manager (Ctrl+D) and copy your disk as VHD. In the Hyper-V Manager, use the Edit Disk dialog to convert the VHD to VHDX.

If you haven’t done that yet, go to the Virtual Switch Manager and make a virtual switch (“External” is like bridge mode in VBox).

Now make a virtual machine. Generation 2, no dynamic memory (FreeBSD doesn’t support that), select the virtual switch and the VHDX disk.

Click Connect and it should just work.

By the way, it’s nice that you can always close the console window without powering off the VM, unlike in VirtualBox where you need a special “Detachable start”.

Interestingly, if you create the VM without a disk and attach the disk later, you won’t see “boot from hard drive” in the firmware / boot order settings. And there’s no add button! (WTF?) The fix is to use PowerShell:

$vm = Get-VM "YOUR VM NAME"
Set-VMFirmware $vm -FirstBootDevice (Get-VMHardDiskDrive $vm)

Speaking of which, it’s nice to have a directly integrated PowerShell interface to all the things. My little xvmmgr script was initially written for VirtualBox, and that required COM.

How to migrate a VM (other OS)

Well, a similar process, but use Generation 1.

My experience so far

Client Hyper-V has pleasantly surprised me. It’s a very smooth experience: it looks like a Type 2 hypervisor even though it’s actually Type 1, it runs VMs without any performance issues… what else could you ask for?

Well, the downside is its lack of flexibility in terms of paravirtualized (MS calls them “synthetic” or something) vs emulated devices.

All you get is the choice between two generations. Generation 1 means legacy BIOS boot from an emulated IDE drive with emulated all the things plus optionally some paravirtualized devices like the NIC. Generation 2 means EFI boot from a SCSI drive with paravirtualized everything. Oh and the SCSI controller is also on the vmbus. So there’s no way to use EFI and SCSI with e.g. OpenBSD, you need full Hyper-V support for at least the disk and network to do that. Thankfully Microsoft contributed that support to FreeBSD! :)

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!


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.

UPDATE: that landed in head a long time ago, I think you can just pick up the latest release now.

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.

UPDATE: now ZFS root works out of the box.

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_flags="-a hiadaptive -b adaptive -i 75 -r 85 -p 500"

UPDATE: powerd++ is a better powerd!

And for /boot/loader.conf:


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.

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


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.

UPDATE: this was merged a long time ago. There’s a new drm-next in the graphics team’s fork though, and it brings Skylake support, Wayland…

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"

UPDATE: with drm-next, the modesetting driver with glamor acceleration works!

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)

UPDATE: OpenCL was fixed a long time ago.


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.)


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.

UPDATE: evdev synaptics landed in current!


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.


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


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.


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%"


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!


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.


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


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


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

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.

UPDATE: the new wmt(4) kernel driver supports the touchscreen perfectly, without that issue!! Also, libinput is better than evdev in Xorg.

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.

UPDATE: turns out the TPM was preventing the laptop from waking up from suspend! (And I did unload the tpm module before suspend.) Disabled it in firmware settings.


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.