OpenBSD on the Microsoft Surface Go

For some reason I like small laptops and the constraints they place on me (as long as they're still usable). I used a Dell Mini 9 for a long time back in the netbook days and was recently using an 11" MacBook Air as my primary development machine for many years. Recently Microsoft announced a smaller, cheaper version of its Surface tablets called Surface Go which piqued my interest.

surface go with keyboard on desk

Hardware

The Surface Go is available in two hardware configurations: one with 4 GB of RAM and a 64 GB eMMC, and another with 8 GB of RAM with a 128 GB NVMe SSD. (I went with the latter.) Both ship with an Intel Pentium Gold 4415Y processor which is not very fast, but it's certainly usable.

The tablet measures 9.65" across, 6.9" tall, and 0.3" thick. Its 10" diagonal 3:2 touchscreen is covered with Gorilla Glass and has a resolution of 1800x1200. The bezel is quite large, especially for such a small screen, but it makes sense on a device that is meant to be held, to avoid accidental screen touches.

The keyboard and touchpad are located on a separate, removable slab called the Surface Go Signature Type Cover which is sold separately. I opted for the "cobalt blue" cover which has a soft, cloth-like alcantara material. The cover attaches magnetically along the bottom edge of the device and presents USB-attached keyboard and touchpad devices. When the cover is folded up against the screen, it sends an ACPI sleep signal and is held to the screen magnetically. During normal use, the cover can be positioned flat on a surface or slightly raised up about 3/4" near the screen for better ergonomics. When using the device as a tablet, the cover can be rotated behind the screen which causes it to automatically stop sending keyboard and touchpad events until it is rotated back around.

The keyboard has a decent amount of key travel and a good layout, with Home/End/Page Up/Page Down being accessible via Fn+Left/Right/Up/Down but also dedicated Home/End/Page Up/Page Down keys on the F9-F12 keys which I find quite useful since the keyboard layout is somewhat small. By default, the F1-F12 keys do not send F1-F12 key codes and Fn must be used, either held down temporarily or Fn pressed by itself to enable Fn-lock which annoyingly keeps the bright Fn LED illuminated. The keys are backlit with three levels of adjustment, handled by the keyboard itself with the F7 key.

The touchpad on the Type Cover is a Windows Precision Touchpad connected via USB HID. It has a decent click feel but when the cover is angled up instead of flat on a surface, it sounds a bit hollow and cheap.

surface go running openbsd with gimp image editor, showing 'hello from openbsd' written in an image on screen

The touchscreen is powered by an Elantech chip connected via HID-over-I2C, which also supports pen input. A Surface Pen digitizer is available separately from Microsoft and comes in the same colors as the Type Covers. The pen works without any pairing necessary, though the top button on it works over Bluetooth so it requires pairing to use. Either way, the pen requires an AAAA battery inside it to operate. The Surface Pen can attach magnetically to the left side of the screen when not in use.

A kickstand can swing out behind the display to use the tablet in a laptop form factor, which can adjust to any angle up to about 170 degrees. The kickstand stays firmly in place wherever it is positioned, which also means it requires a bit of force to pull it out when initially placing the Surface Go on a desk.

Along the top of the display are a power button and physical volume rocker buttons. Along the right side are the 3.5mm headphone jack, USB-C port, power port, and microSD card slot located behind the kickstand.

Charging can be done via USB-C or the dedicated charge port, which accommodates a magnetically-attached, thin barrel similar to Apple's first generation MagSafe adapter. The charging cable has a white LED that glows when connected, which is kind of annoying since it's near the mid-line of the screen rather than down by the keyboard. Unlike Apple's MagSafe, the indicator light does not indicate whether the battery is charged or not. The barrel charger plug can be placed up or down, but in either direction I find it puts an awkward strain on the power cable coming out of it due to the vertical position of the port.

Wireless connectivity is provided by a Qualcomm Atheros QCA6174 802.11ac chip which also provides Bluetooth connectivity.

Most of the sensors on the device such as the gyroscope and ambient light sensor are connected behind an Intel Sensor Hub PCI device, which provides some power savings as the host CPU doesn't have to poll the sensors all the time.

Firmware

The Surface Go's BIOS/firmware menu can be entered by holding down the Volume Up button, then pressing and releasing the Power button, and releasing Volume Up when the menu appears. Secure Boot as well as various hardware components can be disabled in this menu. Boot order can also be adjusted. A temporary boot menu can be brought up the same way but using Volume Down instead.

Installing OpenBSD

Installation was very easy, with the Type Cover keyboard working out of the box and most of the hardware being standard PC components.

To boot the OpenBSD installer, dd the install64.fs image to a USB disk, enter the BIOS as noted above and disable Secure Boot, then set the USB device as the highest boot priority.

When partitioning the 128 GB SSD, one can safely delete the Windows Recovery partition which takes up 1 GB, as it can't repair a totally deleted Windows partition anyway and a full recovery image can be downloaded from Microsoft's website and copied to a USB disk.

After installing OpenBSD but before rebooting, mount the EFI partition (sd0i) and delete the /EFI/Microsoft directory. Without that, it may try to boot the Windows Recovery loader. OpenBSD's EFI bootloader at /EFI/Boot/BOOTX64.EFI will otherwise load by default.

One annoyance to note: if the touchpad is touched or F1-F6 keys are pressed during installation, the Type Cover will detach all of its USB devices and then reattach them. This happens because the ramdisk does not contain touchpad drivers or anything to support the USB HID consumer controls for F1-F6, so the USB pipes for those devices are not open, so nothing responds to the Type Cover when it has data to send on them. Presumably the Type Cover is restarting itself in this situation as a failsafe to force it to reattach, rather than requiring the user to detach the cover and reattach it.

This won't happen for the touchpad once the normal kernel is booted since it contains the umt driver. See my notes below for using usbhidcontrol to respond to the F1-F6 keys which will keep the proper USB pipe open to prevent the detach/reattach when using these keys.

OpenBSD Support Log

2018-08-23: I received the Surface Go and booted an OpenBSD-current USB disk after disabling Secure Boot. I was able to install OpenBSD in place of the Windows partition, keeping the Windows Recovery partition. After rebooting, the Surface kept trying to boot to Windows Recovery which just failed over and over. I booted to a Windows USB installation and was able to use EasyUEFI to add a new UEFI boot option to explicitly boot OpenBSD's BOOTX64.EFI. OpenBSD now boots by default.

I noticed that the screen had a dead pixel in the lower left corner, so I decided to take it to the nearby Microsoft Store for an exchange. But first I needed to re-install Windows, which ended up taking many hours because the Windows Recovery partition can't actually recover anything if the Windows partition has been erased. I downloaded a Surface recovery image from Microsoft's website and was able to make a USB disk to reinstall Windows. Eventually I made my way to the Microsoft Store and they quickly gave me a new one in exchange.

When installing OpenBSD on the new device, I decided to wipe out the Windows Recovery partition since it's useless anyway and would save me an extra gigabyte of space. Before rebooting, I had a hunch that the UEFI boot variables were pointing at the Windows Recovery EFI files in \EFI\Microsoft first, so I just deleted all of that directory leaving \EFI\Boot\BOOTX64.EFI which is OpenBSD's bootloader. It worked as expected and OpenBSD now boots by default.

2018-08-24: The touchpad on the Type Cover is attaching to ums but it's a Windows Precision Touchpad so it should work like my imt driver, but over USB. ums only supports one finger of input and annoyingly the hardware has tap-to-click enabled by default and it can't be disabled. I wrote a new umt driver to hook up hidmt to USB, but then wasted a bunch of time debugging why the device was failing to enter PTP mode properly. I tracked it down to some confusion in ihidev and hidmt that needed to be fixed first, so I sent a diff to tech@.

2018-08-25: I committed the ihidev and hidmt changes and sent a diff to import umt to tech@ for review. It was quickly imported.

2018-08-28: I spent some time over the past couple days looking into what is required to get the Elan touchscreen working. It attaches to ihidev as a HID-over-I2C device, but it doesn't attach to imt. Eventually I discovered that it's not a PTP-compliant device, but it conforms to the older Windows 8 style multitouch. I started adding support for these Windows 8 style devices to hidmt and moved some code duplicated in umt and imt into hidmt.

I also looked into the hardware volume buttons on the top of the screen. Sadly they don't work with our existing acpisurface driver, so I booted a Linux USB disk and traced how they operated. Apparently it's an "Intel 5-button Array" device which works through ACPI. I wrote a new acpihid driver for this and the volume buttons now control the audio volume. There's some overlap in acpihid handling the power button and the standard ACPI GPE interrupt way of receiving the power button press, so I had to make that and acpibtn heed to acpihid if it attaches. It'd be nice if there were a sysctl variable like machdep.lidaction that specified whether the power button shut down, suspended, or did nothing.

2018-08-29: I wanted to get the keyboard F1-F6 functions working (brightness, play/pause, mute, volume down/up) on the Type Cover. Currently whenever they're pressed, the Type Cover basically restarts, as in the backlight turns off and all of its USB devices detach and then reattach. While tracing how it works in Linux, I saw that it's basically just using their generic hid-input driver, so it shouldn't need anything custom. I started work on a generic USB HID input driver (unlike ukbd/hidkbd which requires keyboard-specific usages) but then stumbled across usbhidaction which we already have in base and should work fine for this task.

Unfortunately usbhidaction requires one to know the specific uhid device path of the HID device being controlled, and it exits as soon as the device goes away. For the Surface Type Cover, this device could change depending on what was plugged in when it was booted, and it will detach every time the machine suspends so usbhidaction will just quit.

After spending a bunch of time modifying usbhidaction to poll on the /dev/usbN device to wait for device additions and removals, I realized that the man page is out of date and all of these events were ripped out of the kernel many years ago. I ripped out this line in the man page.

2018-08-30: To be able to get usbhidaction to automatically find a USB device by its vendor and product ID, as well as be able to wait for the device to show up automatically, I hooked it up to /dev/hotplug. Unfortunately hotplug only supports one concurrent reader, so I implemented device cloning in the hotplug driver so that multiple processes can read from /dev/hotplug and each get their own queue of events. I emailed this to the OpenBSD developer list and got some initial feedback on it.

I made a lot of progress on my usbhidaction change, and committed it in my tree.

I also committed a change upstream to create 8 /dev/uhidN devices, since there were only 4 before.

2018-08-31: I decided to give up on my Windows 8 multitouch support for now, since the touchscreen should be usable with just basic ims support (acting as a one-button mouse). Using imt meant it had to claim all (25!) HID reports on the device, which broke support for using a stylus and my Surface Pen arrived so I wanted to use it. This way ims can just attach to the one touchscreen report and another ims can attach to the pen input report.

While making ims match on touchscreen reports, I ran across what looks like a bug in our HID parser (or it just isn't supported) where it was matching usage pages that it shouldn't. The result of this was that when hidms was looking for the usage page indicating the logical minimum and maximum X/Y of the screen (to be able to map input coordinates from the touchscreen onto the screen's display), it was getting usages for something else unrelated and it was making the driver think the screen was way bigger than it was. When I'd touch the screen and scroll all the way across it, it would only move the cursor about 1/4 of the way.

I sent a diff to tech@ to work around this and attach ims to touchscreens.

2018-09-01: The hidms diff and ims diff were committed. OpenBSD 6.4 will support the touchscreen, Surface Pen, keyboard, and multitouch touchpad out of the box.

I'm still waiting for feedback on my hotplug change, which will then allow me to further develop my usbhidaction changes.

I also need to start working on a driver for the PCI Intel Sensor Hub device which would then allow me to support the ambient light sensor and gyroscope for rotation detection. Looking at the Linux driver for it, though, it seems like a ton of code and of course there is no open documentation for it that I can find.

2018-12-26: I sold the Surface Go a few weeks ago as it's been sitting on my desk unused for at least a couple months. I would have liked to use it as my daily workstation but I just kept going back to my Matebook X due to the more comfortable keyboard and working WiFi. There is a lot of driver work required to support the Atheros WiFi on the Surface Go and I won't have the time (nor the skill) to do it any time soon.

Current OpenBSD Support Summary

Status is relative to OpenBSD-current as of 2018-09-03. I sold this laptop in December of 2018 so this page will no longer be updated.

Component Works? Notes
AC adapter Yes Supported via acpiac and status available via apm and hw.sensors, also supports charging via USB-C.
Ambient light sensor No Connected behind a PCI Intel Sensor Hub device which requires a new driver.
Audio Yes HDA audio with a Realtek 298 codec supported by azalia.
Battery status Yes Supported via acpibat and status available via apm and hw.sensors.
Bluetooth No Atheros device, shows up as a ugen device but OpenBSD does not support Bluetooth. Can be disabled in the BIOS.
Cameras No There are apparently front, rear, and IR cameras, none of which are supported (nor desired). Can be disabled in the BIOS.
Gyroscope No Connected behind a PCI Intel Sensor Hub device which requires a new driver which could feed our sensor framework and then tell xrandr to rotate the screen.
Hibernation Yes Works fine from ZZZ.
MicroSD slot Yes Realtek RTS522A, supported by rtsx.
SSD Yes Toshiba NVMe device accessible via nvme.
Surface Pen Yes Works on the touchscreen via ims. The button on the top of the pen requires Bluetooth support so it is not supported. Due to dwiic still requiring polling for these chipsets, drawing with the pen is not as smooth as it could be with proper interrupts.
Suspend/resume Yes Works fine from zzz and by closing the Type Cover against the screen. It does not wake up automatically when the Type Cover is removed, but pressing the power button will wake it up.
Touchscreen Yes HID-over-I2C, supported by ims.
Type Cover Keyboard Yes USB, supported by ukbd. 3 levels of backlight control are adjustable by the keyboard itself with F7. F1-F6 key actions come through on report 3 and can be responded to with usbhidaction -u 045e:096f -r 3.
Type Cover Touchpad Yes USB, supported by my new umt driver for 5-finger multitouch, two-finger scrolling, hysteresis, and to be able to disable tap-to-click which is otherwise enabled by default in normal mouse mode.
USB Yes The USB-C port works fine for data and charging.
Video Yes inteldrm has Kaby Lake support adding accelerated video, DPMS, gamma control, integrated backlight control, and proper S3 resume.
Volume buttons Yes Intel 5-button array, supported by my new acpihid driver not yet imported upstream.
Wireless No Qualcomm Atheros QCA6174 802.11ac wireless chip, not supported. FreeBSD has a work-in-progress port of ath10k from Linux (ISC licensed) which may be possible to port. I'm currently using a tiny USB-A wireless adapter which is made less-tiny by a USB-A to USB-C adapter.
Questions or comments?
Please feel free to contact me.