This effort is also a continuation of my ongoing personal interest in these platforms, especially in mobile form factors such as widely-available tablets. Although I am no longer involved with contributing on the technical side of Replicant, I still care for the project and would like to see it move forward. Finding new developers for Replicant is hard and it's fair to say that a large part of the project is kept alive by its community of users and contributors. The project inherits from its upstream (currently LineageOS, that counts more developers by far), but a significant number of adaptations have to be introduced to workaround the use of proprietary blobs for hardware support, for each and every new version and device we want to support.
In the free software community, most of the effort related to liberating hardware support in a sustainable and future-proof direction happens (sometimes inadvertently so) in upstream projects such as Linux, coreboot and U-Boot. These projects usually drag more than enough contributions to keep their maintainers busy. Since features are added through a code review process (that requires submitting clean and maintainable code in the first place), the set of features supported by mainline is slow to pick-up with downstream modified versions provided by manufacturers, that are used instead in Replicant. For the mobile use cases that we aim to cover, the constraints are high in terms of required features and power management. This is why it did not seem like a good idea to ship mainline Linux in Replicant at first. However, using downstream software components has a cost in terms of maintenance (no kernel updates), security (no kernel updates) or long-term sustainability and compatibility with newer technologies (still no kernel updates). The amount of required time spent dealing with code where only the very minimum amount of structure and conventionality is in place is also very significant.
After a while working on Replicant, I became more and more reluctant to dedicate time to new contributions, mainly for the fact that I had to deal with downstream code that was just very unpleasant. It also felt like all the time and effort put-in could only ever have a very short term impact. That the level of contributed software support was only useful as long as the Android and Linux versions stayed relevant (and well, we can't say that they stay relevant for a very long time for these use cases).
This is why I was dragged more and more towards mainline software.
A Plea for Upstream Software
The effort to liberate hardware support is much more significant with mainline, but these contributions do tag along and stay, as long as there are people to care for them. The decisions regarding the code in future versions are also taken by the community instead of a single entity, although the community may also take decisions detrimental to freedom in digital technology. With mainline support landed in Linux, the userspace interfaces for systems are standardized and much less work has to be put-in on the userspace side (or more precisely, it only has to be done once and incrementally updated with new features). This means less involvement required on the Replicant side, with the ultimate goal of making Replicant a sheer rebranding of Lineage OS without proprietary blobs and using only generic Hardware Abstraction Layers (HALs) shared across Android systems. The Android-x86 project already has such HALs for various aspects of userspace software support (some of which where developed by companies like Intel that stick close to mainline), but there is still work left to do to adapt these HALs for mobile uses cases. Since these could benefit any Android system, it would be interesting to bring a coordinated effort for supporting mainline kernel interfaces through generic Android HALs (something an entity like Linaro could care for). This would allow redirecting the development effort for hardware support away from the downstream userspace side of Android systems and focused on mainline instead. Of course, mainline support also benefits other GNU/Linux systems and opens up the possibility of properly supporting mobile use cases in these systems, while also enabling new use cases.Purism is currently working in that direction, with projects to integrate KDE and GNOME-based interfaces to a mobile telephony-enabled device. Running GNU/Linux on mobile devices is not exactly new though, as a first wave of interest rose around 2008 from the Openmoko community, revolving around the Neo FreeRunner phone running with GNU/Linux. One of the systems supporting that phone was SHR (for Stable Hybrid Release) that was based on the Freesmartphone.org (FSO) framework for mobile devices and went on to support other devices such as the N900 or the Nexus S. But just like with the original systems for the FreeRunner, using regular GNU/Linux applications on SHR was hard and required using a stylus. The interface was obviously not designed nor adapted for the mobile use case, just like plenty of other system components. On the kernel side, the amount of changes required for the FreeRunner made the upstreaming process slow (and it was still not fully completed to this day).
The GTA01 development device, the Neo FreeRunner (GTA02) and the GTA04
Nowadays mobile devices revolve around the ARM instruction set (and the very commonly found ARM Cortex core implementations from the company) and ARM support in the mainline Linux kernel has come a long way since 2008. Most notably, the introduction of the OpenFirmwaredevice-tree (initially designed for supporting PowerPC devices) allowed a clean distinction between the hardware description and the drivers, which were previously glued together in (plenty of) platform data initialization laid out directly in the source code. Back then, adding support for a new device was tedious and each kernel had to be compiled for a precise device. Device-tree changed the game here, as it became much easier to introduce new device-specific support and possible at all to run the same kernel binary on different devices with the same ARM instruction set. This also made platform bringup a more streamlined task (by easily reusing similar blocks from previous generations and applying appropriate quirks at run-time). The number of supported ARM platforms, features and use cases kept on increasing, with the commitment of big companies like TI, Samsung, Google, ARM, Freescale/NXP or Rockchip, entities like Linaro or the linux-sunxi community but also smaller players (often providing upstreaming services to companies) like Bootlin (formerly Free Electrons), Collabora or Pengutronix. While most of the supported platforms are not ready for conventional mobile use cases yet, some come close and already offer support for a reduced number of use cases.
Signature Verifications Gone Wrong
Despite free software support in Linux, some platforms are fatally flawed when it comes to the boot software they are running. This is the case with enforced boot software signature verifications with missing keys, where the circuitry of the platform validates the digital signature of the first software running at boot with a public key stored in read-only memory. If the signature was not created using the (missing) private key associated with the public key, the platform will simply refuse to boot. A significant number of ARM platforms, such as the ones made by Qualcomm (Snapdragon and others), Amlogic or Samsung (Exynos) are plagued by enforced boot software signature verifications with missing keys. While signature verifications are a really good thing to have, it only makes sense if the user of the device has access to the associated keys. When the keys are kept secret by the manufacturer of the device or the platform, the whole security model of the device is delegated to this third party. The user cannot decide of their own security model and consider potential threats based on their own situation, that may not set this third party as a fully trusted peer. Instead, the implemented security model only covers this third party's threat model, that is designed to consider the user as a threat. While it might sound very odd, this is the result of enforcing technical limitations such as DRM, that are designed to forbid the user from accessing the unlocked raw multimedia contents.
LG Security Error
This modus operandi looks very similar to what a parent would do to prevent their newborn child from wandering around during night time: applying a technical restriction such as bars on the infant's bed. This is perfectly fine when the individual subjected to the restriction is not able to decide what is good for themselves. But when it comes to individuals with that capacity, imposing such intentional restrictions designed to serve this third party's interests first and foremost feels very inappropriate. But that's not the end of it: this limitation removes the practical possibility for the user to replace the software signed by these missing keys, making it proprietary software de-facto. It sometimes occurs that free copylefted software is used in devices that enforce such signature verifications, as it first occurred with the Tivo (and coined the name Tivoization for the process). Even with source code and the appropriate compilers available, only intermediate forms of software can be obtained. The product form of software (that is the form adapted for practical use) is intrinsically tied to the processing unit that executes the associated software instructions. This is why the practical ability to install the generated intermediate form into the code storage from where the code is executed (effectively making it the product form of the software) is an absolute requirement. When signature verifications are enforced, the part of the installation process related to signing the binaries (so that they can be executed) is missing. The software thus never reaches its product form, leaving the user with freedom over the source and intermediate forms of the software but not over its product form. As a result, the software cannot be considered to be free as a whole, although its license says so.
Current Status of Free Upstream Support
Thankfully, a number of ARM platforms are not flawed in this manner and allow running free boot software. Examples of such platforms include Allwinner, Rockchip, i.MX, OMAP GP and Tegra (without keys burned). U-Boot is widely used on devices with these platforms and manufacturers often use modified downstream versions based off ancient upstream releases. The associated source code for both U-Boot and Linux is not always available, although these projects are covered by a copyleft license. And when it does, it often takes the form of a board support package tarball with no version control information. Some parts of the code required for hardware support can also come missing or be voluntarily moved out of copylefted projects (something that Android seems to vastly encourage). This is often the case with DRAM initialization and features related to multimedia. Nevertheless, these source releases are useful and often allow adding mainline support for these devices.
The Google OP1 (Rockchip RK3399) as found on the Samsung Chromebook Plus
At this point in time, the platforms mentioned and many of the devices that use them are supported, to a more or less advanced degree, by upstream free software. Many significant tasks are still ahead of us, but there is work in progress going at a good rate. Support for Vivante GPUs (found in i.MX platforms) was merged and is being improved with time. There is also work in progress for both Mali Utgard, with the revival of the Lima project and Mali Midgard/Bifrost, with the Panfrost project that concerns a number of platforms such as Allwinner and Rockchip. Multimedia features in Linux are also work in progress, with the introduction of the media request API that will allow supporting stateless VPUs (that don't have a dedicated processor, nor require any firmware) in the V4L2 framework, coupled with the MEM2MEM framework that already allows supporting stateful VPUs such as the one found on Exynos and the i.MX6 platform (that require a proprietary loaded firmware). Support for stateless VPUs has been working in progress on the Rockchip side, with a reference driver available on the Chromium OS kernel tree, using an early proposal of the media request API, as well as an early driver from developer Ayaka, in addition to the reference Rockchip kernel driver. On the Tegra side of things, developer digetix from the Grate project has been working on VPU support for early generations of Tegra, that should apply to newer generations with limited effort. On Allwinner, VPU support is work in progress and a number of versions of the Sunxi-Cedrus VPU driver have been submitted already.
Innards of an i.MX6 CuBox-i
In addition to VPUs support, a number of image processing units are made available (especially so on Rockchip) with features ranging from colorspace conversion, and scaling to 2D operations like bit blit and porter-duff alpha blending. Some of this processing is useful for general-purpose image processing, like colorspace conversion and scaling and seems relevant to the V4L2 subsystem, while 2D operations seem more relevant for the DRM subsystem. There seems not to be much support for 2D operations acceleration through generic DRM interfaces in regular userspace implementations from freedesktop.org. Support for such acceleration in compositors would allow significantly speeding up these operations without resorting to the GPU. Since GPUs in graphics cards are often required for video features in x86 systems, it has become a common assumption that GPU support is available for all types of graphical operations. Needless to say that GPU support on ARM is still work in progress and that it is currently generally not available without proprietary software (especially on the many platforms that embed Mali or PowerVR GPUs). Moreover, using the GPU is not power-efficient compared to dedicated hardware components and sometimes does not even perform as fast.
However, the DRM subsystem already leverages plane overlays, that each have their own framebuffer and position on the CRTC and are blended by the hardware before hitting the encoder, as a single frame. But planes support in Xorg is currently not as easy thing to implement, especially when it comes to showing YUV 420 video frames in a dedicated plane. The historical approach for supporting this use case consists in setting a color key on the display hardware, that sets a particular color to alpha, and blend the result with the video frame, that integrates with the rest of the display contents. One downside is that the coloured box bounding the video plane has to follow the movements of the window displaying it, so some coordination is required. This coordination as well as color-keying was historically provided by the Xv extension to the X server. Alas, this extension relies on buffer copies, introducing a significant bottleneck in performance and sharing buffers directly is a much preferred approach nowadays (that wade possible with DMABUF handles). Thankfully, DRI3 and Wayland bring solutions to the issues found on Xorg.
Other features related to multimedia are slowly picking up support in Linux, with support for media pipelines and camera sensor input controllers. Other specific features also require significant effort, such as proper power management (a crucial feature on mobile devices). With all these developments happening, the idea of running mobile devices on upstream free software with a significant set of features allowing usual daily use cases slowly becomes a reality. These days, embedded mobile devices only seem to get more and more diversified: from laptops to phones and tablets, they are nowadays found in all sorts of form factors such as convertible laptops, single-board computers, mini PCs, dongles, home automation equipment or even connected surveillance, car and action cameras. All these new use cases are running with wild downstream software that causes a great deal of issues in terms of freedom and privacy/security. The proposed solution to allowing a somewhat sane use of this technology clearly has to start with upstream software support. Some of these products and use cases are not necessarily a good thing to have on a society-wide scale, but provided that they do exist, we might as well try and sanitize the technology that supports these new use cases.
Covering a New Interesting Use Case
When going through some of the latest released devices on Chinese marketplaces like Aliexpress or GearBest, I noticed a number of 4K action cameras featuring Wi-Fi and HDMI. With an ever-renewed interest for finding out about the guts of unusual devices (well, come to think of it, of usual devices too), I ran through the specs and found that the SoC is an Allwinner V3. One that probably has the VPU that I am writing support for. One that also has an 8M pixel sensor and a wide-angle lense attached, screaming to be piped to the VPU's encoder. But unfortunately, one that is not yet supported in upstream U-Boot and Linux. Thankfully, the community was quick to pick-up support for the V3s SoC from Allwinner. It was contributed to mainline U-Boot and Linux by linux-sunxi community member Icenowy, who has also designed a board using the V3s. The V3s is an integrated LQFP package grouping 64 MiB of DDR2 DRAM and the same processor and controllers as Allwinner's V3 SoC.
Allwinner V3 SoC
In the past, Allwinner has already released chips with minor variations under different names, such as the A10s matching the A13 or the R16 matching the A33. These chips share nearly the exact same set of registers as the platforms they are based on (if not the very same), so when it came to adding support for them in U-Boot and Linux, only a minimal amount of work was required. With V3s support in good shape in free upstream hardware support projects, adding bringing up the V3 based on the existing V3 support with a device in hands looks like a rather reasonable task.
And so I clicked and typed and clicked and typed until I received a little package with my name on it and a F60 Action Camera inside. Next up in the process: discovering and documenting the components used in the camera, starting with a hardware teardown!
During the past few months, I've been working on bringing Replicant 4.2 support to the Goldelico GTA04, a montherboard replacement for the Openmoko FreeRunner (GTA02) that is manufactured by Golden Delicious with the intent of being free software friendly. The board design is also released under a free licence. There is an active community of developers and users dedicated to the GTA04 and other similar projects, brougt together under the hood of OpenPhoenux. Other similar projects include the upcoming Neo900, a motherboard replacement for the Nokia N900 using similar hardware as the GTA04 and also aiming to be free software friendly, with a particular emphasis on security and privacy features.
Currently, Android devices ship with Linux 3.4, after a long time of using version 3.0, which started with Android 4.0 Ice Cream Sandwich. To this day, the reference common Android kernel repos have branches with Linux 3.10 and experimental work is done on Linux 3.14. That's pretty close to the Linux 3.12 version we're using on the GTA04!
The first challenge to overcome was dealing with suspend and resume. Android uses a particular mechanism to implement opportunistic suspend, using wakelocks: both the kernel and userspace can register these locks to prevent the device from going to suspend. In Android kernels, there is another mechanism that allows some non-critical chips to reach suspend state before the rest of the system: this is earlysuspend. As the whole Android system is built around the concept of wakelocks to handle power management, something similar needed to be implemented in the mainline Linux kernel. After efforts from the Android kernel maintainers, wakelocks were implemented in a clean fashion some time ago. In order to implement opportunistic suspend, a separate interface was implemented on mainline Linux, known as autosleep, which uses different nodes than /sys/power/state (that the Android kernels use directly for opportunistic suspend). Starting in Android 4.1, a library was added to Android in order to detect and handle these different modes.
So thankfully, everything was already in place to use autosleep properly on Android 4.2. Except that it didn't work. This turned out to be because of a dedicated capability that was missing from the Android userspace: CAP_BLOCK_SUSPEND. It turned out to be easier to just revert the patch restricting access to wakelocks to users with that capability in the kernel.
Android USB Gadget and Android Debug Bridge
Android also went their own way in implementing USB device drivers for the various things that are used by Android: mass storage, rndis for USB networking, MTP for file access and a couple others, including ADB. The Android Debug Bridge (ADB) is a great way of debugging what's going on with an Android device, providing easy access to the logs, to a shell and file transfer (these are the features of ADB I use the most). All of that is not integrated at all in the mainline Linux kernel, so there was some substantial work to do here. The first thing to do was importing the related commits from the android-3.10 branch of the common Android Linux kernel. All of that built nicely with only minor code corrections, to follow some API changes in 3.12 and some features like rndis or MTP worked right away, but the most interesting part was left not working: that's the Android Debug Bridge. A few kernel versions back, there used to be a dedicated composite function driver for ADB, but a commit by one of Android's kernel maintainers totally gets rid of it, calling it obsolete with no further information. While attempts to restore it failed, I tried to find out in details why it is obsolete and if that meant the final death of ADB, that I found rather convenient.
Thankfully, someone found out what happened and wrote about it: the dedicated ADB driver was being replaced by another one using FunctionFS, a more flexible and generic way of implementing such drivers, directly from userspace. It turns out that FunctionFS support for the userspace ADB server was merged nearly entirely in Android 4.2. I had to backport a missing fix to have it fully working properly and also had to import adaptation a patch in recovery to have sideload working with FunctionFS too. A few bits were also needed in the initialization procedure to have things set up right. Once all of that was done, it could finally run flawlessly!
Headset/headphones detection with SoC Jack
So Jack's a good guy. Everyone knows about that. Whether he's saving the homeland from yet another threat or just letting us know something of interest just got plugged in one hole or another, it always feels great to hear from Jack. However, the Android kernel guys didn't seem to appreciate his participation in the show as much as we all do, or at least until recently.
The traditional way of reporting a headset or headphones plug/unplug in Android kernels was using a switch called h2w, reporting these events to userspace. The mainline kernel prefers another approach, using our beloved Jack SoC architecture. It also provides a convenient way of reporting button pushes, which is quite nice. So instead of rewriting it all using the h2w switch, it struck me that there is a frameworks config option to politely ask Android to give Jack some consideration. And when it does that, everything works great, including button press reports!
Firmwares are programs that do not run on the main processor of a computer: instead, they runs inside separate chips that have a dedicated functionality. Most of the time, firmwares are proprietary programs, which do not respect the user's freedom. When they are not already installed in the chip they run in, the main processor has to load them into the chip, which requires the firmware to be distributed as a file. Since they are proprietary software, I think firmwares shouldn't be shipped with any operating system, not should any operating system ever advise the user to install them.
However, people sometimes need a functionality that depends on proprietary firmwares so bad that they would rather use a system that ships and encourages the use of proprietary software, including the needed firmware, over a free system. In that case, it is better for their freedom that they use a free system with only the proprietary firmware installed, over another system that contains dozens of other proprietary pieces, including ones that also run on the main processor and are able to compromise the whole system (from a security point of view), on top of not respecting the user's freedom.
On Android devices, people are often facing this choice and look around for instructions on how to install only the missing firmwares so that they can avoid installing a system that contains even more proprietary bits. While these instructions cannot be released on free system's official documentation pages, for the sake of not encouraging the use of proprietary software, it makes sense for me to publish such instructions on my personal pages. I have written scripts that extract the firmwares from CyanogenMod installation zips for a few Android devices and push them to the device: cm-firmwares.git
The procedure to install the firmwares is the following:
I recently acquired an Allwinner A13 unbranded tablet in order to port Replicant to it: this platform is well supported by free software (the Linux kenrel and the u-boot bootloader) and there is an active community of developers working on free software for the Allwinner A1x platforms: linux-sunxi.
The tablet I ended up with contains an Elan EKTF2000 touchscreen, but I couldn't find any touchscreen driver for it in the linux-sunxi kernel tree: the source code was just not released, even though it's marked as being GPL-licensed. Moreover, since the tablet is unbranded, there was no one I could contact to request source code. So I asked around, and it turned out that nobody knew about source code that would have been released for that touchscreen. However, the tablet came with Android preinstalled and there was an ektf2k.ko module.
After some research, I finally found a driver for elan ktf2000 touchscreens written by HTC. It seemed to match mine (both use I2C) and preliminary tests revealed that the same protocol (on top of I2C) was used by my touchscreen. However, it was not quite enough to write an usable implementation for my device: as a matter of fact, the returned coordinates from my touchscreen did not match the screen size: it reported values up to 896x576 while the screen size is 800x640. So the whole issue was about figuring out these values (896 and 576) at run time in order to scale down to the actual screen size.
The preinstalled Android system came with a kernel module called ektf2k.so which is the actual driver. When loaded, I saw this message on the kernel logs:
[elan] __fw_packet_handler: x resolution: 576, y resolution: 896
Which meant that this driver had the code to get the values from the touchscreen chip.
I quickly understood how the touchscreen protocol works by reading the HTC driver, and it turned out that requests were arrays of 4 bytes, with the first one set to 0x53 (indicating a request) and the second one set to a particular command (indicating what we request). Now considering that requests are usually static tables that are defined in code (that's the way it's done in the HTC driver), declared at the beginning of the function, I knew that the static array of 4 bytes corresponding to the request for the size I needed to find out was held somewhere in the ektf2k.ko module.
Thanks to objdump, I decompiled the module (it is legal to perform such reverse engineering in Europe) and looked at the assembly code for the function __fw_packet_handler. I clearly saw the different calls to elan_ktf2k_ts_get_data and printk, but no sign of the data packets. I then looked at the .rodata section, that contains, as its name suggests, the read-only data, where the packets would likely be stored. The string “__fw_packet_handler” is stored at offset 0170 In this section. Right before, I found the following data:
Looks very much like static arrays of data with the first byte set to 0x53! So I tried issuing requests with the commands 0x00, 0x60, 0x63 and 0xf0 and received the height with 0x60 and the width with 0x63! It was not in the most obvious format but 576 is 0x240 and 896 is 0x380, so it was easy to see that the responses were containing these values.
While reversing the Galaxy Tab 2 sensors, I have been looking for a way to calculate the orientation vector from acceleration and magnetic field vectors: I've looked at any sensors implementation I could find and each time, this was being held into some proprietary component, to the point that the Galaxy Tab 2 has an user-space blob dedicated to this task (orientationd). Since I am not an expert at physics, I soon gave up on writing a free orientationd implementation, which was really a shame given the time I spent making the geomagnetic sensor work properly. I just realized that there was one last implementation I didn't look at, that is the free software user-space program for AKM8975. So many thanks to Asahi Kasei: I was able to reuse that code directly and it worked perfectly at first try. That's pretty amazing!