Compiling kernel module for XA2 Plus

I’m running SFOS 4.1 on an XA2 Plus, and I am trying to compile a kernel module. Specifically, I’d like to compile wireguard. I’ve got a userspace implementation working, but tihs is of course much slower and more power-hungry than using a kernel implementation.

So, I’ve downloaded the kernel source from 50.1.A.11.40.tar.bz2 from sony and am trying to compile it. So far, it’s going badly. The source yielded quite some warnings, which then failed the compilation. I’ve turned them off - it’s probably compiled in the past so it’ll work, and there seems to be some issue with include paths so I’m editing files to get them to compile.

Jolla probably made changes to the kernel source. Isn’t there a working source somewhere I can download? Did somebody already get something working?

2 Likes

I managed to make some headway here. Since I don’t want to actually replace the kernel, but rather get the correct configuration for compiling kernel modules, I don’t have to patch the actual buggy kernel source. I need to do the following:

  • download a working cross compiler. We cannot use gcc on the device, as the kernel must be compiled with gcc 4.9 due to newer versions coming with better warnings, tripping up the Makefile and aborting. Isn’t old code great? I’ve downloaded the linaro aarch64 cross compiler for this.
  • I take the kernel config from /proc/config.gz and extract it to a build (which I’ve unoriginally called /build)
  • I then select the default values for those options not in the config. How that’s possible, I have no idea, maybe Jolla did something funky to their kernel? make ARCH=arm64 CROSS_COMPILE=/toolchain/gcc-linaro-4.9-2016.02-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu- O=/build olddefconfig
  • I then install the header and scripts necessary for module compilation with this: make ARCH=arm64 CROSS_COMPILE=/data/gcc-linaro-4.9-2016.02-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu- O=/build prepare headers_install scripts

At this point I’m almost ready to compile my kernel module. Apparantly CONFIG_MODVERSIONS is turned on for the kernel (see: zcat /proc/config.gz | grep CONFIG_MODVERSIONS), so I need a valid Module.symvers. This is where I’m stuck now.

I did find a very old python script that should be able to do this given a binary blob: extract-symvers. The script initially borked on a syntax error, until I figured out that since it’s so old, it needs python2. Now it doesn’t work, I think because I’m not giving it the right address for the kernel .init. According to the accompanying blog post you should check by inspecting the output of dmesg for .init, but apparantly that’s no longer a thing (other people mention this too).

Somebody else mentioned using readelf and objdump for this, but I couldn’t get this to work. I’ve copied the hybris-boot.img to my workstation and unpacked it using abootimg -x, giving me the zImage. I’ve unzipped it and have tried various things to find the init section in it, but nothing I try will give me useful information. All I get is that the ‘format isn’t recognized’. If I run file on it, it recognizes it correctly and tells me Image: Linux kernel ARM64 boot executable Image, little-endian, 4K pages

So, unless extract-symvers.py no longer works due to changes in the linux kernel, all that’s stopping me now is finding the correct offset to feed it.

Does anybody have any idea how to get the right offset to feed it to give me the Module.symvers information?

1 Like

Looking into the kernel specs for aarch64 I figured out how to get at the kernel base address. The kernel image starts with a mandatory header:

  u32 code0;			/* Executable code */
  u32 code1;			/* Executable code */
  u64 text_offset;		/* Image load offset, little endian */
  u64 image_size;		/* Effective Image size, little endian */
  u64 flags;			/* kernel flags, little endian */
  u64 res2	= 0;		/* reserved */
  u64 res3	= 0;		/* reserved */
  u64 res4	= 0;		/* reserved */
  u32 magic	= 0x644d5241;	/* Magic number, little endian, "ARM\x64" */
  u32 res5;			/* reserved (used for PE COFF offset) */

The image load offset is in the third field, so there’s two uint32_t fields preceding it. With a hex editor at offset 0x8 it gives me a text_offset of 0x80000. I’m now fairly certain this should be the base address. Unfortunately, it still doesn’t work. Looks like I’ll need to spend more time reading the specs.

I’ve asked Jolla support, but they’re unwilling to release the kernel sources since they “unfortunately do not provide support in development matters”. Way to go there, Jolla!

1 Like

I am almost sure you have seen my similar question over here. But in case not maybe one of those links help you to find what I could not?

1 Like

I’ve seen it, but thanks for linking anyway. All information is welcome!

Unfortunately it doesn’t really help me. The issue isn’t exactly having the correct headers. It’s more the fact I don’t have the symbol versions. When you build a kernel with module support, you get this Module.symvers file (assuming the CONFIG_MODVERSIONS option is turned on, which it is).

If you want to build modules for this kernel, you need to have this file, otherwise the kernel rejects the module. The exact symbols in this file depend on many things, not just the kernel source and config, also other things like the compiler used. It’s very fiddly to get exactly right.

1 Like