How to build your own Ubuntu Concept X Elite kernel

How to build your own Ubuntu Concept X Elite kernel packages

This is intended as a reference for people who want to test their own kernel package builds based on the qcom-x1e Ubuntu kernel we use in the concept image. There are multiple and possibly faster ways to build kernel binaries from our source tree. The one documented here is how the packages we ship in our images are built on launchpad.

Getting the source

The kernel source code is available via git on launchpad under the ~ubuntu-concept team.
To clone the source you can run:

$ git clone https://git.launchpad.net/~ubuntu-concept/ubuntu/+source/linux/+git/oracular \
  -b qcom-x1e linux-qcom-x1e
$ cd linux-qcom-x1e

Dependencies

Kernel build dependencies can be installed via the apt-get(8) build-dep command.
In the source code directory, run:

$ apt build-dep .

Configuration

The kernel configuration in Ubuntu kernel packages is managed using a custom mechanism called annotations. In our case it is stored in debian.qcom-x1e/config/annotations.

The easiest way to modify it is exporting it to .config with:

$ ./debian/scripts/misc/annotations \
    --arch arm64 --flavour qcom-x1e --export > .config

and then editing it locally using the usual commands like make nconfig.

The modified config can be imported back into the annotations file with:

$ ./debian/scripts/misc/annotations \
    --arch arm64 --flavour qcom-x1e --import .config
$ fakeroot debian/rules clean updateconfigs

For more information, see the kernel teams post on Ubuntu kernel configs.

Update the changelog

It is recommended to bump the package version for new builds to make apt happy when
trying to install the new packages.
The easiest way to do this is using dch(1):

$ dch -i -Doracular --upstream --changelog debian.qcom-x1e/changelog

Building

Before starting a build the annotations need to be cleaned up and the actual packaging
metadata files in debian/ need to be generated from our flavour specific templates in
debian.qcom-x1e/:

$ fakeroot ./debian/rules clean
$ ./debian/rules updateconfigs

After this the qcom-x1e kernel can be built locally using:

$ fakeroot ./debian/rules binary-qcom-x1e

Since this kernel supports arm64 only it needs to be build in an arm64 environment.

Installation

If everything goes well the binary packages end up in the parent directory.
They can be installed with apt or dpkg:

$ apt install \
    ../linux-image-unsigned-6.11.0-51-qcom-x1e_6.11.0-51.51_arm64.deb \
    ../linux-modules-6.11.0-51-qcom-x1e_6.11.0-51.51_arm64.deb \
    ../linux-modules-extra-6.11.0-51-qcom-x1e_6.11.0-51.51_arm64.deb
2 Likes

Thanks for this write-up, helped quite a bit. Building a custom kernel is not well documented for newer Ubuntu versions. Did you build this on a Thinkpad t14s gen6? If I run the build on my t14s it always shuts down after some minutes under load. I guess it has something to do with power management or fan control.
Do you know, if I can also cross-compile the kernel? I tried setting ARCH=arm64 and CROSS_COMPILE=aarch64-linux-gnu-, but I can’t get it running.

@mlasch For cross compiling I would probably use something like sbuild(1). It manages temporary build chroots independent from your host system and can even create cross-arch chroots. There is a relatively simple guide to set that up in the Ubuntu wiki.

For cross building you would essentially mk-sbuild --target arm64 orcular and then follow the guide above and replace the build step with:

$ fakeroot ./debian/rules clean
$ sbuild --host=arm64
1 Like

Hi @tobhe,

Looks like there are some issues with the latest x1e kernel:

arch/arm64/boot/dts/qcom/x1e80100.dtsi:3244.28-3257.5: ERROR (duplicate_node_names): /soc@0/phy@1d87000: Duplicate node name
ERROR: Input tree has errors, aborting (use -f to force output)
arch/arm64/boot/dts/qcom/x1e80100.dtsi:3244.28-3257.5: ERROR (duplicate_node_names): /soc@0/phy@1d87000: Duplicate node name
ERROR: Input tree has errors, aborting (use -f to force output)
make[3]: *** [scripts/Makefile.dtbs:131: arch/arm64/boot/dts/qcom/x1e001de-devkit.dtb] Error 2
arch/arm64/boot/dts/qcom/x1e80100.dtsi:3244.28-3257.5: ERROR (duplicate_node_names): /soc@0/phy@1d87000: Duplicate node name
arch/arm64/boot/dts/qcom/x1e80100.dtsi:3244.28-3257.5: ERROR (duplicate_node_names): /soc@0/phy@1d87000: Duplicate node name
ERROR: Input tree has errors, aborting (use -f to force output)
ERROR: Input tree has errors, aborting (use -f to force output)
make[3]: *** [scripts/Makefile.dtbs:131: arch/arm64/boot/dts/qcom/x1e80100-crd.dtb] Error 2
make[3]: *** [scripts/Makefile.dtbs:131: arch/arm64/boot/dts/qcom/x1e78100-lenovo-thinkpad-t14s.dtb] Error 2
make[3]: *** [scripts/Makefile.dtbs:131: arch/arm64/boot/dts/qcom/x1e80100-asus-vivobook-s15.dtb] Error 2
arch/arm64/boot/dts/qcom/x1e80100.dtsi:3244.28-3257.5: ERROR (duplicate_node_names): /soc@0/phy@1d87000: Duplicate node name
ERROR: Input tree has errors, aborting (use -f to force output)
make[3]: *** [scripts/Makefile.dtbs:131: arch/arm64/boot/dts/qcom/x1e80100-dell-xps13-9345.dtb] Error 2
make[2]: *** [scripts/Makefile.build:478: arch/arm64/boot/dts/qcom] Error 2
make[1]: *** [/home/tudorl/oss/linux-qcom-x1e/Makefile:1411: dtbs] Error 2

Thanks! I wonder if you forgot to push my latest one, shouldn’t have changed since my last upload. I’ll check.

Cool, thanks!
FYI, I’m on this SHA:

commit d1ebdfd8c47f27aa181a5876e8e62d6e390ec82a (HEAD -> qcom-x1e, tag: Ubuntu-qcom-x1e-6.12.0-23.23, origin/qcom-x1e)
Author: Tobias Heider <me@tobhe.de>
Date:   Thu Jan 23 17:33:20 2025 +0100

    UBUNTU: Changelog for 6.12.0-23.23

Yeah that seems to be outdated, I pushed a new one tagged Ubuntu-qcom-x1e-6.12.0-28.28

Awesome, thanks! Giving it a try now.

@tobhe Thank you so much for the instructions! I struggled through them a bit but almost everything ended up being operator error on my end. I built this on both an RPi5 (overnight build time) and a Lenovo Yoga 7x.

1 Like

Maybe I’m the only one, but after importing a config for updated annotations, I always have to do this dance:

  • also save the defconfig (for non-ubuntu bisect builds and dev/test stuff) with make savedefconfig and copy it over to the name you use (mine is arch/arm64/configs/ubuntu_x1e_defconfig)
  • add / stash these changes
  • do a make mrproper
  • do a git reset --hard
  • pop the changes from stash
  • then do the fakeroot debian/rules clean updateconfigs

Otherwise I will always run into the error “Build environment is in an unclean state, please do make mrproper”.

Bit late, but you could build with -j4 to limit the amount of jobs to prevent cpu overheat which causes the shutdown.

2 Likes

With good air flow I can use -j8.

With which scheduler? And how do you provide good airflow?

I’m using schedutil and have mine eventually shutdown most of the time with -j6 during normal use placed on a desk.

With powersave I can utilize all 12 cores.

I’ll try -j8, placing the laptop on it’s right side for good airflow.

I don’t have it that long yet, but:

with some hard prop (small block or box, ~1cm) at the upper end of the body, I can:

  • utilize -j12 when booted on EL1 with normal adsp firmware - getting hot but no emergency cutoff
  • utilize -j8 when booted on EL2 with the adsp-lite firmware - same. -j12 would burn it into emergency shutoff.

EL2 because its the 64GB model (and because we all want that, thats why), could only use ~30GB with cutmem otherwise. Which is also stable, fortunately.

Oh and default scheduler, I changed nothing. All 12 cores say [none] mq-deadline

Hello. A question from a confused user: is there a way to boot “with EL2”?
I have the T14s with 64GB and would like to have it available (using cutmem fix now).
Any specific kernel needed etc?

Hello. A question from a confused user: is there a way to boot “with EL2”?
I have the T14s with 64GB and would like to have it available (using cutmem fix now).
Any specific kernel needed etc?

We haven’t packaged any of the required software but you can take a look at GitHub - TravMurav/slbounce: Secure-Launch implementation for Qualcomm devices. It should be compatible with our qcom-x1e kernel but you will need to set up the el2 device tree somehow. I am not sure if slbounce does that automatically or whether you need dtbloader too.