Building OnePlus Kernels
Dependencies
First, figure out the system info for your build.
adb shell
cat /proc/version
getprop ro.build.version.release
Set up your working directory and get required dependencies. The NDK version can be found by googling around with the clang version retrieved above. In our case, we have an OnePlus 10 Pro with Android 13.0. The NDK version is r23.
mkdir oneplus && cd oneplus
wget https://dl.google.com/android/repository/android-ndk-r23-linux.zip
unzip android-ndk-*
rm android-ndk-*.zip
mkdir prebuilts && cd prebuilts
git clone https://android.googlesource.com/platform/prebuilts/build-tools -b android-13.0.0_r1 --depth 1
cd ..
git clone https://android.googlesource.com/kernel/build -b android-13.0.0_r0.130 --depth 1
mkdir external && cd external
git clone https://android.googlesource.com/platform/external/dtc --depth 1
cd dtc
ln -s dtc-parser.tab.h dtc-parser.h
cd ../..
Now we need to grab the kernel sources. The code structure is pretty picky, so we need to match what it expects. Find the corresponding android_kernel_msm
and android_kernel_modules
repositories for your device on GitHub, and make sure to checkout the correct branch.
git clone https://github.com/OnePlusOSS/android_kernel_modules_and_devicetree_oneplus_sm8450 -b oneplus/sm8450_t_13.0_10pro --depth 1
ln -s android_kernel_modules_and_devicetree_oneplus_sm8450/vendor vendor
ln -s android_kernel_modules_and_devicetree_oneplus_sm8450/kernel_platform kernel_platform
mkdir kernel && cd kernel
git clone https://github.com/OnePlusOSS/android_kernel_msm-5.10_oneplus_sm8450 -b oneplus/sm8450_t_13.0_10pro --depth 1
cd ..
ln -s kernel/android_kernel_msm-5.10_oneplus_sm8450 common
Now that we have the files, our directory structure looks like this:
.
├── android_kernel_modules_and_devicetree_oneplus_sm8450
├── android-ndk-r23
├── build
├── common -> kernel/android_kernel_msm-5.10_oneplus_sm8450/
├── external
│ └── dtc
├── kernel
│ └── android_kernel_msm-5.10_oneplus_sm8450
├── kernel_platform -> android_kernel_modules_and_devicetree_oneplus_sm8450/kernel_platform
├── prebuilts
│ └── build-tools
└── vendor -> android_kernel_modules_and_devicetree_oneplus_sm8450/vendor
And we get to go and link a bunch of files, along with our final dependency…
cd kernel/android*
cd arch/arm64/boot/dts
mv qcom qcom_original
ln -s ../../../../../../kernel_platform/qcom/proprietary/devicetree/qcom qcom
ln -s ../../../../../../kernel_platform/qcom/proprietary/devicetree/oplus oplus
rm vendor
ln -s ../../../../../../kernel_platform/qcom/proprietary/devicetree vendor
cd ../../../../include/soc/oplus
ln -s ../../../../../vendor/oplus/kernel/boot/include/ boot
ln -s ../../../../../vendor/oplus/kernel/dft/include/ dft
cd ../../../drivers/soc/oplus
ln -s ../../../../../vendor/oplus/kernel/boot/ boot
ln -s ../../../../../vendor/oplus/kernel/dfr/ dfr
ln -s ../../../../../vendor/oplus/kernel/dft/ dft
ln -s ../../../../../vendor/oplus/kernel/power/ power
ln -s ../../../../../vendor/oplus/kernel/system/ system
cd ../../input/
ln -s ../../../../vendor/oplus/secure/common/bsp/drivers/ oplus_secure_drivers
cd ../../../..
Then, let's set up a script for our environment variables.
We'll set BUILD_CONFIG to the right config for our system, which is named after the SoC. In our device, it's build.config.msm.waipio
.
export ARCH=arm64
export TARGET=arm64
export CROSS_COMPILE=aarch64-linux-android31-
export LLVM=1
export PATH=/path/to/oneplus/android-ndk-r23/toolchains/llvm/prebuilt/linux-x86_64/bin/:${PATH}
export CC=clang-12
export HOSTCC=/usr/bin/clang-17
export AR=llvm-ar
export OBJCOPY=llvm-objcopy
export OUT_DIR=out
export KERNEL_DIR=kernel/android_kernel_msm-5.10_oneplus_sm8450
export BUILD_CONFIG=${KERNEL_DIR}/build.config.msm.waipio
Then we have to patch the kernel a bit… apply the following to the kernel, which seems to have some code pulled from a future kernel version somehow.
@@ -214,11 +214,11 @@ static int binder_update_page_range(struct binder_alloc *alloc, int allocate,
if (mm) {
mmap_read_lock(mm);
- if (!mmget_still_valid(mm)) {
+ //if (!mmget_still_valid(mm)) {
if (allocate == 0)
goto free_range;
goto err_no_vma;
- }
+ //}
vma = alloc->vma;
}
@@ -906,7 +906,7 @@ static void cooling_device_stats_setup(struct thermal_cooling_device *cdev)
var += sizeof(*stats->time_in_state) * states;
var += sizeof(*stats->trans_table) * states * states;
- stats = kvzalloc(var, GFP_KERNEL);
+ stats = kzalloc(var, GFP_KERNEL);
if (!stats)
return;
@@ -925,7 +925,7 @@ static void cooling_device_stats_setup(struct thermal_cooling_device *cdev)
static void cooling_device_stats_destroy(struct thermal_cooling_device *cdev)
{
- kvfree(cdev->stats);
+ kfree(cdev->stats);
cdev->stats = NULL;
}
If you want to disable LTO (see later), apply this patch to the modules and devicetree repository to add some missing annotations that aren't caught when LTO is enabled.
@@ -146,7 +146,7 @@ static int persistent_ram_buffer_map(phys_addr_t start, size_t size,
}
-static int bootloader_log_probe(struct platform_device *pdev)
+static int __init bootloader_log_probe(struct platform_device *pdev)
{
struct bootloader_log_platform_data *pdata = pdev->dev.platform_data;
struct bootloader_log_platform_data of_pdata;
@@ -201,7 +201,7 @@ static const struct of_device_id bootloader_log_of_match[] = {
};
MODULE_DEVICE_TABLE(of, bootloader_log_of_match);
-static struct platform_driver bootloader_log_driver = {
+static struct platform_driver bootloader_log_driver __refdata = {
.probe = bootloader_log_probe,
.remove = __exit_p(bootloader_log_remove),
.driver = {
@@ -286,7 +286,7 @@ static const struct of_device_id dump_device_info_of_match[] = {
};
MODULE_DEVICE_TABLE(of, dump_device_info_of_match);
-static struct platform_driver dump_device_info_driver = {
+static struct platform_driver dump_device_info_driver __refdata = {
.probe = dump_device_info_probe,
.remove = __exit_p(dump_device_info_remove),
.driver = {
~/o/android_kernel_modules_and_devicetree_oneplus_sm8450 oneplus/sm8450_t_13.0_10pro *… less temp.patch
~/o/android_kernel_modules_and_devicetree_oneplus_sm8450 oneplus/sm8450_t_13.0_10pro *… cat temp.patch
@@ -146,7 +146,7 @@ static int persistent_ram_buffer_map(phys_addr_t start, size_t size,
}
-static int bootloader_log_probe(struct platform_device *pdev)
+static int __init bootloader_log_probe(struct platform_device *pdev)
{
struct bootloader_log_platform_data *pdata = pdev->dev.platform_data;
struct bootloader_log_platform_data of_pdata;
@@ -201,7 +201,7 @@ static const struct of_device_id bootloader_log_of_match[] = {
};
MODULE_DEVICE_TABLE(of, bootloader_log_of_match);
-static struct platform_driver bootloader_log_driver = {
+static struct platform_driver bootloader_log_driver __refdata = {
.probe = bootloader_log_probe,
.remove = __exit_p(bootloader_log_remove),
.driver = {
@@ -286,7 +286,7 @@ static const struct of_device_id dump_device_info_of_match[] = {
};
MODULE_DEVICE_TABLE(of, dump_device_info_of_match);
-static struct platform_driver dump_device_info_driver = {
+static struct platform_driver dump_device_info_driver __refdata = {
.probe = dump_device_info_probe,
.remove = __exit_p(dump_device_info_remove),
.driver = {
Apply this patch to to the build repo.
@@ -693,7 +693,7 @@ if [ ! -z "${BUILD_BOOT_IMG}" ] ; then
fi
set -x
- python "$MKBOOTIMG_PATH" --kernel "${DIST_DIR}/${KERNEL_BINARY}" \
+ python3 "$MKBOOTIMG_PATH" --kernel "${DIST_DIR}/${KERNEL_BINARY}" \
--header_version "${BOOT_IMAGE_HEADER_VERSION}" \
"${MKBOOTIMG_ARGS[@]}" -o "${DIST_DIR}/boot.img"
set +x
Build
Now we can try to compile.
. env.sh
build/build.sh -j8
We'll fail at the very end trying to build the vendor release, but that's fine. If you want to build just changes, make sure to tell the build script to not clean:
SKIP_MRPROPER=1 SKIP_DEFCONFIG=1 ./build/build.sh -j8
Fair warning that the LTO step on the full kernel vmlinux takes a lot of RAM. On my laptop which has 16G, I needed to allocate 8G of swap. If you want to disable it, edit arch/arm64/configs/gki_defconfig
and delete the lines defining CONFIG_LTO_CLANG_FULL
and CONFIG_CFI_CLANG
(CFI requires LTO).
Building a boot image
WARNING: Built image has not been tested on actual device. Flash at your own risk.
First we get new dependencies and build a base boot image.
cat /dev/block/platform/soc/1d84000.ufshc/by-name/boot_a > boot.img
cat /dev/block/platform/soc/1d84000.ufshc/by-name/vendor_boot_a > vendor_boot.img
git clone https://android.googlesource.com/platform/system/libufdt -b android-13.0.0_r1 --depth 1
cd libufdt/sydeps
$HOSTCC -shared libufdt_sysdeps_posix.c -Iinclude -fPIC -o libufdt_sysdeps.so
cd ..
$HOSTCC -I./include -I./sysdeps/include tests/src/ufdt_overlay_test_app.c tests/src/util.c *.c -L./sysdeps -lfdt -lufdt_sysdeps -o ufdt_apply_overlay
cd ..
cd build
cp -r ../kernel_platform/oplus/build/ oplus
cd ..
git clone https://android.googlesource.com/platform/system/tools/mkbootimg -b android-13.0.0_r1 --depth 1 tools/mkbootimg
export PATH=${PWD}/libufdt/utils/src:${PWD}/libufdt:${PATH}
Apply this diff to fix the build script.
14c14
< ANDROID_KERNEL_OUT=${ANDROID_BUILD_TOP}/device/qcom/${TARGET_PRODUCT}-kernel
> ANDROID_KERNEL_OUT=${OUT_DIR}
67c67
< gunzip vendor_ramdisk.gz
> unlz4 vendor_ramdisk.gz vendor_ramdisk
108c108
< MKBOOTIMG_ARGS+=("--dtb" "${ANDROID_KERNEL_OUT}/dtbs/dtb.img")
> MKBOOTIMG_ARGS+=("--dtb" "${DIST_DIR}/dtb.img")
Now we can build.
# Build boot image
SKIP_MRPROPER=1 SKIP_DEFCONFIG=1 BUILD_BOOT_IMG=1 ./build/build.sh -j8
# Build vendor boot
SKIP_MRPROPER=1 SKIP_DEFCONFIG=1 BUILD_BOOT_IMG=1 ./build/oplus/oplus_build_boot.sh
Built images will be located at /out/dist/boot.img
and /out/dist/vendor_boot.img
.
Building OnePlus Kernels
Dependencies
First, figure out the system info for your build.
adb shell cat /proc/version # Identify gcc version getprop ro.build.version.release # Get release version
Set up your working directory and get required dependencies. The NDK version can be found by googling around with the clang version retrieved above. In our case, we have an OnePlus 10 Pro with Android 13.0. The NDK version is r23.
mkdir oneplus && cd oneplus wget https://dl.google.com/android/repository/android-ndk-r23-linux.zip # Get NDK unzip android-ndk-* # Decompress rm android-ndk-*.zip mkdir prebuilts && cd prebuilts git clone https://android.googlesource.com/platform/prebuilts/build-tools -b android-13.0.0_r1 --depth 1 # Pick a branch matching your android version cd .. git clone https://android.googlesource.com/kernel/build -b android-13.0.0_r0.130 --depth 1 mkdir external && cd external git clone https://android.googlesource.com/platform/external/dtc --depth 1 cd dtc ln -s dtc-parser.tab.h dtc-parser.h cd ../..
Now we need to grab the kernel sources. The code structure is pretty picky, so we need to match what it expects. Find the corresponding
android_kernel_msm
andandroid_kernel_modules
repositories for your device on GitHub, and make sure to checkout the correct branch.git clone https://github.com/OnePlusOSS/android_kernel_modules_and_devicetree_oneplus_sm8450 -b oneplus/sm8450_t_13.0_10pro --depth 1 ln -s android_kernel_modules_and_devicetree_oneplus_sm8450/vendor vendor ln -s android_kernel_modules_and_devicetree_oneplus_sm8450/kernel_platform kernel_platform mkdir kernel && cd kernel git clone https://github.com/OnePlusOSS/android_kernel_msm-5.10_oneplus_sm8450 -b oneplus/sm8450_t_13.0_10pro --depth 1 cd .. ln -s kernel/android_kernel_msm-5.10_oneplus_sm8450 common
Now that we have the files, our directory structure looks like this:
. ├── android_kernel_modules_and_devicetree_oneplus_sm8450 ├── android-ndk-r23 ├── build ├── common -> kernel/android_kernel_msm-5.10_oneplus_sm8450/ ├── external │ └── dtc ├── kernel │ └── android_kernel_msm-5.10_oneplus_sm8450 ├── kernel_platform -> android_kernel_modules_and_devicetree_oneplus_sm8450/kernel_platform ├── prebuilts │ └── build-tools └── vendor -> android_kernel_modules_and_devicetree_oneplus_sm8450/vendor
And we get to go and link a bunch of files, along with our final dependency…
cd kernel/android* cd arch/arm64/boot/dts mv qcom qcom_original ln -s ../../../../../../kernel_platform/qcom/proprietary/devicetree/qcom qcom ln -s ../../../../../../kernel_platform/qcom/proprietary/devicetree/oplus oplus rm vendor ln -s ../../../../../../kernel_platform/qcom/proprietary/devicetree vendor cd ../../../../include/soc/oplus ln -s ../../../../../vendor/oplus/kernel/boot/include/ boot ln -s ../../../../../vendor/oplus/kernel/dft/include/ dft cd ../../../drivers/soc/oplus ln -s ../../../../../vendor/oplus/kernel/boot/ boot ln -s ../../../../../vendor/oplus/kernel/dfr/ dfr ln -s ../../../../../vendor/oplus/kernel/dft/ dft ln -s ../../../../../vendor/oplus/kernel/power/ power ln -s ../../../../../vendor/oplus/kernel/system/ system cd ../../input/ ln -s ../../../../vendor/oplus/secure/common/bsp/drivers/ oplus_secure_drivers cd ../../../..
Then, let's set up a script for our environment variables.
We'll set BUILD_CONFIG to the right config for our system, which is named after the SoC. In our device, it's
build.config.msm.waipio
.# env.sh export ARCH=arm64 export TARGET=arm64 export CROSS_COMPILE=aarch64-linux-android31- # set to correct version export LLVM=1 export PATH=/path/to/oneplus/android-ndk-r23/toolchains/llvm/prebuilt/linux-x86_64/bin/:${PATH} export CC=clang-12 export HOSTCC=/usr/bin/clang-17 # may be ignored export AR=llvm-ar export OBJCOPY=llvm-objcopy export OUT_DIR=out export KERNEL_DIR=kernel/android_kernel_msm-5.10_oneplus_sm8450 export BUILD_CONFIG=${KERNEL_DIR}/build.config.msm.waipio
Then we have to patch the kernel a bit… apply the following to the kernel, which seems to have some code pulled from a future kernel version somehow.
diff --git a/drivers/android/binder_alloc.c b/drivers/android/binder_alloc.c index fc35eb5af..e9b532a61 100644 --- a/drivers/android/binder_alloc.c +++ b/drivers/android/binder_alloc.c @@ -214,11 +214,11 @@ static int binder_update_page_range(struct binder_alloc *alloc, int allocate, if (mm) { mmap_read_lock(mm); - if (!mmget_still_valid(mm)) { + //if (!mmget_still_valid(mm)) { if (allocate == 0) goto free_range; goto err_no_vma; - } + //} vma = alloc->vma; } diff --git a/drivers/thermal/thermal_sysfs.c b/drivers/thermal/thermal_sysfs.c index 982ecccec..f52708f31 100644 --- a/drivers/thermal/thermal_sysfs.c +++ b/drivers/thermal/thermal_sysfs.c @@ -906,7 +906,7 @@ static void cooling_device_stats_setup(struct thermal_cooling_device *cdev) var += sizeof(*stats->time_in_state) * states; var += sizeof(*stats->trans_table) * states * states; - stats = kvzalloc(var, GFP_KERNEL); + stats = kzalloc(var, GFP_KERNEL); if (!stats) return; @@ -925,7 +925,7 @@ static void cooling_device_stats_setup(struct thermal_cooling_device *cdev) static void cooling_device_stats_destroy(struct thermal_cooling_device *cdev) { - kvfree(cdev->stats); + kfree(cdev->stats); cdev->stats = NULL; }
If you want to disable LTO (see later), apply this patch to the modules and devicetree repository to add some missing annotations that aren't caught when LTO is enabled.
diff --git a/vendor/oplus/kernel/boot/misc/bootloader_log.c b/vendor/oplus/kernel/boot/misc/bootloader_log.c index cb41ae7..0c2dc66 100755 --- a/vendor/oplus/kernel/boot/misc/bootloader_log.c +++ b/vendor/oplus/kernel/boot/misc/bootloader_log.c @@ -146,7 +146,7 @@ static int persistent_ram_buffer_map(phys_addr_t start, size_t size, } -static int bootloader_log_probe(struct platform_device *pdev) +static int __init bootloader_log_probe(struct platform_device *pdev) { struct bootloader_log_platform_data *pdata = pdev->dev.platform_data; struct bootloader_log_platform_data of_pdata; @@ -201,7 +201,7 @@ static const struct of_device_id bootloader_log_of_match[] = { }; MODULE_DEVICE_TABLE(of, bootloader_log_of_match); -static struct platform_driver bootloader_log_driver = { +static struct platform_driver bootloader_log_driver __refdata = { .probe = bootloader_log_probe, .remove = __exit_p(bootloader_log_remove), .driver = { diff --git a/vendor/oplus/kernel/dfr/qcom/dump_device_info/dump_device_info.c b/vendor/oplus/kernel/dfr/qcom/dump_device_info/dump_device_info.c index 8ffbc9d..258a154 100755 --- a/vendor/oplus/kernel/dfr/qcom/dump_device_info/dump_device_info.c +++ b/vendor/oplus/kernel/dfr/qcom/dump_device_info/dump_device_info.c @@ -286,7 +286,7 @@ static const struct of_device_id dump_device_info_of_match[] = { }; MODULE_DEVICE_TABLE(of, dump_device_info_of_match); -static struct platform_driver dump_device_info_driver = { +static struct platform_driver dump_device_info_driver __refdata = { .probe = dump_device_info_probe, .remove = __exit_p(dump_device_info_remove), .driver = { ~/o/android_kernel_modules_and_devicetree_oneplus_sm8450 oneplus/sm8450_t_13.0_10pro *… less temp.patch ~/o/android_kernel_modules_and_devicetree_oneplus_sm8450 oneplus/sm8450_t_13.0_10pro *… cat temp.patch diff --git a/vendor/oplus/kernel/boot/misc/bootloader_log.c b/vendor/oplus/kernel/boot/misc/bootloader_log.c index cb41ae7..0c2dc66 100755 --- a/vendor/oplus/kernel/boot/misc/bootloader_log.c +++ b/vendor/oplus/kernel/boot/misc/bootloader_log.c @@ -146,7 +146,7 @@ static int persistent_ram_buffer_map(phys_addr_t start, size_t size, } -static int bootloader_log_probe(struct platform_device *pdev) +static int __init bootloader_log_probe(struct platform_device *pdev) { struct bootloader_log_platform_data *pdata = pdev->dev.platform_data; struct bootloader_log_platform_data of_pdata; @@ -201,7 +201,7 @@ static const struct of_device_id bootloader_log_of_match[] = { }; MODULE_DEVICE_TABLE(of, bootloader_log_of_match); -static struct platform_driver bootloader_log_driver = { +static struct platform_driver bootloader_log_driver __refdata = { .probe = bootloader_log_probe, .remove = __exit_p(bootloader_log_remove), .driver = { diff --git a/vendor/oplus/kernel/dfr/qcom/dump_device_info/dump_device_info.c b/vendor/oplus/kernel/dfr/qcom/dump_device_info/dump_device_info.c index 8ffbc9d..258a154 100755 --- a/vendor/oplus/kernel/dfr/qcom/dump_device_info/dump_device_info.c +++ b/vendor/oplus/kernel/dfr/qcom/dump_device_info/dump_device_info.c @@ -286,7 +286,7 @@ static const struct of_device_id dump_device_info_of_match[] = { }; MODULE_DEVICE_TABLE(of, dump_device_info_of_match); -static struct platform_driver dump_device_info_driver = { +static struct platform_driver dump_device_info_driver __refdata = { .probe = dump_device_info_probe, .remove = __exit_p(dump_device_info_remove), .driver = {
Apply this patch to to the build repo.
diff --git a/build.sh b/build.sh index f4ac890..8394141 100755 --- a/build.sh +++ b/build.sh @@ -693,7 +693,7 @@ if [ ! -z "${BUILD_BOOT_IMG}" ] ; then fi set -x - python "$MKBOOTIMG_PATH" --kernel "${DIST_DIR}/${KERNEL_BINARY}" \ + python3 "$MKBOOTIMG_PATH" --kernel "${DIST_DIR}/${KERNEL_BINARY}" \ --header_version "${BOOT_IMAGE_HEADER_VERSION}" \ "${MKBOOTIMG_ARGS[@]}" -o "${DIST_DIR}/boot.img" set +x
Build
Now we can try to compile.
. env.sh build/build.sh -j8 # If you don't specify any flags here the script will blow up :)
We'll fail at the very end trying to build the vendor release, but that's fine. If you want to build just changes, make sure to tell the build script to not clean:
Fair warning that the LTO step on the full kernel vmlinux takes a lot of RAM. On my laptop which has 16G, I needed to allocate 8G of swap. If you want to disable it, edit
arch/arm64/configs/gki_defconfig
and delete the lines definingCONFIG_LTO_CLANG_FULL
andCONFIG_CFI_CLANG
(CFI requires LTO).Building a boot image
WARNING: Built image has not been tested on actual device. Flash at your own risk.
First we get new dependencies and build a base boot image.
# On device cat /dev/block/platform/soc/1d84000.ufshc/by-name/boot_a > boot.img cat /dev/block/platform/soc/1d84000.ufshc/by-name/vendor_boot_a > vendor_boot.img # Pull images to oplus/prebuild/img # On host git clone https://android.googlesource.com/platform/system/libufdt -b android-13.0.0_r1 --depth 1 # Compile libufdt cd libufdt/sydeps $HOSTCC -shared libufdt_sysdeps_posix.c -Iinclude -fPIC -o libufdt_sysdeps.so cd .. $HOSTCC -I./include -I./sysdeps/include tests/src/ufdt_overlay_test_app.c tests/src/util.c *.c -L./sysdeps -lfdt -lufdt_sysdeps -o ufdt_apply_overlay cd .. cd build cp -r ../kernel_platform/oplus/build/ oplus # Need to copy because it uses readlink to find its base; but expects the android build tools in another place cd .. git clone https://android.googlesource.com/platform/system/tools/mkbootimg -b android-13.0.0_r1 --depth 1 tools/mkbootimg export PATH=${PWD}/libufdt/utils/src:${PWD}/libufdt:${PATH}
Apply this diff to fix the build script.
14c14 < ANDROID_KERNEL_OUT=${ANDROID_BUILD_TOP}/device/qcom/${TARGET_PRODUCT}-kernel --- > ANDROID_KERNEL_OUT=${OUT_DIR} 67c67 < gunzip vendor_ramdisk.gz --- > unlz4 vendor_ramdisk.gz vendor_ramdisk 108c108 < MKBOOTIMG_ARGS+=("--dtb" "${ANDROID_KERNEL_OUT}/dtbs/dtb.img") --- > MKBOOTIMG_ARGS+=("--dtb" "${DIST_DIR}/dtb.img")
Now we can build.
Built images will be located at
/out/dist/boot.img
and/out/dist/vendor_boot.img
.