A few weekends ago I left my Samsung S7 running Gnome on software-rendered X11. This kind of works as a demo but it’s slow and clunky so I followed that by attempting to get Phosh running. Phosh is a gnome-shell replacement for Purism’s Librem5. It uses phoc as a Wayland compositor instead of Mutter, which in turn is based on wlroots, the compositor-as-a-library component of Sway.

It should be much easier to add a hwcomposer backend to wlroots than Mutter, and in fact someone already started: NotKit/wlroots. I took this and rebased on the latest upstream wlroots tag, hacked the code around until it compiled with the new interface, ran the example app and… the screen flashed green for a second and then kernel panicked and rebooted. Ouch.

<0>[ 7300.959344] I[0:      swapper/0:    0] Kernel panic - not syncing: Unrecoverable System MMU Fault!!
<0>[ 7300.959382] I[0:      swapper/0:    0] Kernel loaded at: 0x8013c000, offset from compile-time address bc000
<3>[ 7300.959438] I[0:      swapper/0:    0] exynos_check_hardlockup_reason: smc_lockup virt: 0xffffffc879980000 phys: 0x00000008f9980000 size: 4096.
<0>[ 7300.959489] I[0:      swapper/0:    0] exynos_check_hardlockup_reason: SMC_CMD_GET_LOCKUP_REASON returns 0x1. fail to get the information.
<0>[ 7300.959534] I[0:      swapper/0:    0] exynos_ss_prepare_panic: no core got stucks in EL3 monitor.

The panic log is not very helpful, there’s no user stack trace.

After a painful few hours debugging by adding prints and sleeps and comparing against the working test_hwcomposer from libhybris I managed to fix it. I’ve pushed a hwcomposer-0.10.1 branch here.

Then I built phoc and phosh, linking against the modified wlroots and libhybris. To my surprise it Just Worked, with the exception of touch input. Input requires enabling the libinput backend of wlroots, and that in turn requires an active “session”. Session in the systemd world means being associated with a “seat” in systemd-logind. We can do that by starting phoc inside a systemd service and associating it with a TTY. I copied phosh.service from the Librem5 package and edited it for my system.

Unfortunately phoc then hangs at startup inside the wlroots libinput backend polling for sd_seat_can_graphical(..) to return true. Logind seems to make some people very angry, but debugging it with the source code and loginctl wasn’t too bad.

$ loginctl 
SESSION  UID USER SEAT  TTY  
    132 1000 nick            
    162 1000 nick seat0 tty7     <---------------
      4 1000 nick            
      6 1000 nick            
      7 1000 nick            
     c2    0 root       pts/4
 
6 sessions listed.

Here phoc is running on seat0 which is attached to /dev/tty7.

$ loginctl show-seat seat0 
Id=seat0
ActiveSession=162
CanMultiSession=yes
CanTTY=yes
CanGraphical=no    <-----------
Sessions=162
IdleHint=yes
IdleSinceHint=1587287027759986
IdleSinceHintMonotonic=18371557550

From reading the logind source, CanGraphical is true if there is a device attached to the seat that has the udev TAG attribute with value "master-of-seat". Normally this attribute is added to graphics devices by the udev rules systemd ships in /lib/udev/rules.d/71-seat.rules. The S7 has a special “decon” graphics driver so none of the standard rules match. But it’s easy to add a custom rule:

SUBSYSTEM=="graphics", KERNEL=="fb0", DRIVERS=="decon", TAG+="master-of-seat"

After reloading and retriggering the udev rules, the framebuffer device now has this tag:

$ udevadm info /dev/fb0
P: /devices/13960000.decon_f/graphics/fb0
N: fb0
L: 0
S: graphics/fb0
E: DEVPATH=/devices/13960000.decon_f/graphics/fb0
E: DEVNAME=/dev/fb0
E: MAJOR=29
E: MINOR=0
E: SUBSYSTEM=graphics
E: USEC_INITIALIZED=42601393
E: ID_PATH=platform-13960000.decon_f
E: ID_PATH_TAG=platform-13960000_decon_f
E: ID_FOR_SEAT=graphics-platform-13960000_decon_f
E: ID_SEAT=seat0
E: DEVLINKS=/dev/graphics/fb0
E: TAGS=:seat0:seat:master-of-seat:      <-----------

And after restarting phoc/phosh touch is working! 😀

From left: Gnome calculator, app drawer, Gnome terminal and squeekboard onscreen keyboard