本来是不想写这篇文章的,但是一想到浪费的时间,于是就写出了这篇文章。

# 0x01

起因就是我在写 Reno3 Pro 的设备树 (虽然没写完) 的时候发现使用 prebuilt kernel 虽然方便,但是不能定制诸如 localversion 之类的信息。于是决定使用源码编译。

使用的源码为 OPPO 官方开源的内核源码,分支为 oppo/sm7250_s_12.1_reno4_5g .

当然光有写一个源码肯定是不够的。因为根据 OPPT 的尿性它把部分东西分开在另一个仓库里。

然而在调试内核的过程中遇到了几件极其操蛋的事情:

  • 必须把内核源码放在 kernel/ 目录下并重命名为 msm-4.19
  • 有些东西并没有软连接到内核源码仓库,例如 net/oplus_modules , 需要翻别的分支甚至真我一加的源码去找路径
  • 默认的配置大概率是不能用的,建议从本机复制一份过去

但是很抱歉,我手上并没有这台机子。所以就无法提取本机配置文件。

然后就秉承着多一事不如少一事的选择就把东西都放在一个仓库里了,虽然可以在 BoardConfig.mk 里这么写但是终究觉得不美观:

BoardConfig.mk
TARGET_KERNEL_SOURCE := kernel/oppo/kernel/msm-4.19
TARGET_KERNEL_CONFIG := vendor/lito-perf_defconfig
$ ls kernel/oppo
kernel vendor

# 0x02

然后就利用 find 命令找到软连接并一一移植过去,然后开始编译。

然而从来就没有顺利过:

h Logcat
AR      drivers/built-in.a
  GEN     .version
  CHK     include/generated/compile.h
  AR      built-in.a
  MODPOST vmlinux.o
WARNING: modpost: Found 1 section mismatch(es).
To see full details build your kernel with:
'make CONFIG_DEBUG_SECTION_MISMATCH=y'
FATAL: modpost: Section mismatches detected.
Set CONFIG_SECTION_MISMATCH_WARN_ONLY=y to allow them.
make[2]: *** [../scripts/Makefile.modpost:114: vmlinux.o] Error 1

然后把 CONFIG_DEBUG_SECTION_MISMATCH=y 打开发现:

h Logcat
AR      drivers/built-in.a
  GEN     .version
  CHK     include/generated/compile.h
  AR      built-in.a
  MODPOST vmlinux.o
WARNING: vmlinux.o(.text+0x61d27c): Section mismatch in reference from the function bootloader_log_probe() to the function .init.text:of_bootloader_log_platform_data()
The function bootloader_log_probe() references
the function __init of_bootloader_log_platform_data().
This is often because bootloader_log_probe lacks a __init 
annotation or the annotation of of_bootloader_log_platform_data is wrong.
FATAL: modpost: Section mismatches detected.
Set CONFIG_SECTION_MISMATCH_WARN_ONLY=y to allow them.
make[2]: *** [../scripts/Makefile.modpost:114: vmlinux.o] Error 1

然后通过 ChatGPT 给出的指令:

h
find android_kernel_oppo_sm7250 -type f -name '*.c' -print0 | xargs -0 grep -nw 'bootloader_log_probe'

找到了出错的文件 bootloader_log.c ,根据 ChatGPT 的回答修改了以下部分:

h diff
--- a/bootloader_log.c
+++ b/bootloader_log.c
@@ -146,7 +146,7 @@
 }
-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;

然后编译之后出现了报错:

h logcat
AR      drivers/built-in.a
  GEN     .version
  CHK     include/generated/compile.h
  AR      built-in.a
  MODPOST vmlinux.o
WARNING: vmlinux.o(.data+0xa7e10): Section mismatch in reference from the variable bootloader_log_driver to the function .init.text:bootloader_log_probe()
The variable bootloader_log_driver references
the function __init bootloader_log_probe()
If the reference is valid then annotate the
variable with __init* or __refdata (see linux/init.h) or name the variable:
*_template, *_timer, *_sht, *_ops, *_probe, *_probe_one, *_console
FATAL: modpost: Section mismatches detected.
Set CONFIG_SECTION_MISMATCH_WARN_ONLY=y to allow them.
make[2]: *** [../scripts/Makefile.modpost:114: vmlinux.o] Error 1

根据查看 Makefile 得知由 CONFIG_BOOTLOADER_LOG 控制,遂在配置里关闭了这个选项。

结果整个 vmlinux 就崩了:

h Logcat
AR      drivers/built-in.a
  GEN     .version
  CHK     include/generated/compile.h
  AR      built-in.a
  MODPOST vmlinux.o
kernel/fork.o: In function `copy_process':
/home/SekaiMoe/tmpdir/android_kernel_oppo_sm7250/msm-4.19/out/../kernel/fork.c:2306: undefined reference to `update_user_tasklist'
mm/vmscan.o: In function `shrink_page_list':
/home/SekaiMoe/tmpdir/android_kernel_oppo_sm7250/msm-4.19/out/../mm/vmscan.c:1186: undefined reference to `is_reclaim_should_cancel'
drivers/scsi/oufs/ufshcd.o: In function `ufshcd_comp_scsi_upiu':
/home/SekaiMoe/tmpdir/android_kernel_oppo_sm7250/msm-4.19/out/../drivers/scsi/oufs/ufshcd.c:3754: undefined reference to `ufsf_change_read10_debug_lun'
/home/SekaiMoe/tmpdir/android_kernel_oppo_sm7250/msm-4.19/out/../drivers/scsi/oufs/ufshcd.c:3755: undefined reference to `ufsf_prep_fn'
drivers/scsi/oufs/ufshcd.o: In function `ufshcd_suspend':
/home/SekaiMoe/tmpdir/android_kernel_oppo_sm7250/msm-4.19/out/../drivers/scsi/oufs/ufshcd.c:10876: undefined reference to `ufsf_hpb_suspend'
/home/SekaiMoe/tmpdir/android_kernel_oppo_sm7250/msm-4.19/out/../drivers/scsi/oufs/ufshcd.c:11018: undefined reference to `ufsf_resume'
drivers/scsi/oufs/ufshcd.o: In function `ufshcd_resume':
/home/SekaiMoe/tmpdir/android_kernel_oppo_sm7250/msm-4.19/out/../drivers/scsi/oufs/ufshcd.c:11146: undefined reference to `ufsf_resume'
/home/SekaiMoe/tmpdir/android_kernel_oppo_sm7250/msm-4.19/out/../drivers/scsi/oufs/ufshcd.c:11430: undefined reference to `ufsf_remove'
/home/SekaiMoe/tmpdir/android_kernel_oppo_sm7250/msm-4.19/out/../drivers/scsi/oufs/ufshcd.c:11431: undefined reference to `remove_ufsplus_ctrl_proc'
/home/SekaiMoe/tmpdir/android_kernel_oppo_sm7250/msm-4.19/out/../drivers/scsi/oufs/ufshcd.c:11435: undefined reference to `remove_signal_quality_proc'
drivers/scsi/oufs/ufshcd.o: In function `ufshcd_init':
/home/SekaiMoe/tmpdir/android_kernel_oppo_sm7250/msm-4.19/out/../drivers/scsi/oufs/ufshcd.c:11736: undefined reference to `ufsf_set_init_state'
/home/SekaiMoe/tmpdir/android_kernel_oppo_sm7250/msm-4.19/out/../drivers/scsi/oufs/ufshcd.c:11740: undefined reference to `create_signal_quality_proc'
drivers/scsi/oufs/ufshcd.o: In function `ufshcd_check_errors':
/home/SekaiMoe/tmpdir/android_kernel_oppo_sm7250/msm-4.19/out/../drivers/scsi/oufs/ufshcd.c:7984: undefined reference to `recordUniproErr'
/home/SekaiMoe/tmpdir/android_kernel_oppo_sm7250/msm-4.19/out/../drivers/scsi/oufs/ufshcd.c:7978: undefined reference to `recordUniproErr'
drivers/scsi/oufs/ufshcd.o: In function `ufshcd_update_uic_error':
/home/SekaiMoe/tmpdir/android_kernel_oppo_sm7250/msm-4.19/out/../drivers/scsi/oufs/ufshcd.c:7873: undefined reference to `recordUniproErr'
/home/SekaiMoe/tmpdir/android_kernel_oppo_sm7250/msm-4.19/out/../drivers/scsi/oufs/ufshcd.c:7903: undefined reference to `recordUniproErr'
/home/SekaiMoe/tmpdir/android_kernel_oppo_sm7250/msm-4.19/out/../drivers/scsi/oufs/ufshcd.c:7928: undefined reference to `recordUniproErr'
drivers/scsi/oufs/ufshcd.o:/home/SekaiMoe/tmpdir/android_kernel_oppo_sm7250/msm-4.19/out/../drivers/scsi/oufs/ufshcd.c:7939: more undefined references to `recordUniproErr' follow
drivers/scsi/oufs/ufshcd.o: In function `ufshcd_host_reset_and_restore':
/home/SekaiMoe/tmpdir/android_kernel_oppo_sm7250/msm-4.19/out/../drivers/scsi/oufs/ufshcd.c:8532: undefined reference to `ufsf_reset_host'
drivers/scsi/oufs/ufshcd.o: In function `ufshcd_probe_hba':
/home/SekaiMoe/tmpdir/android_kernel_oppo_sm7250/msm-4.19/out/../drivers/scsi/oufs/ufshcd.c:9664: undefined reference to `ufsf_reset'
/home/SekaiMoe/tmpdir/android_kernel_oppo_sm7250/msm-4.19/out/../drivers/scsi/oufs/ufshcd.c:9634: undefined reference to `ufsf_device_check'
/home/SekaiMoe/tmpdir/android_kernel_oppo_sm7250/msm-4.19/out/../drivers/scsi/oufs/ufshcd.c:9635: undefined reference to `ufsf_init'
drivers/scsi/oufs/ufshcd.o: In function `ufshcd_transfer_rsp_status':
/home/SekaiMoe/tmpdir/android_kernel_oppo_sm7250/msm-4.19/out/../drivers/scsi/oufs/ufshcd.c:6623: undefined reference to `ufsf_hpb_noti_rb'
drivers/scsi/oufs/ufshcd.o: In function `__ufshcd_transfer_req_compl':
/home/SekaiMoe/tmpdir/android_kernel_oppo_sm7250/msm-4.19/out/../drivers/scsi/oufs/ufshcd.c:6911: undefined reference to `ufsf_on_idle'
drivers/scsi/oufs/ufshcd.o: In function `ufshcd_devfreq_scale':
/home/SekaiMoe/tmpdir/android_kernel_oppo_sm7250/msm-4.19/out/../drivers/scsi/oufs/ufshcd.c:1879: undefined reference to `ufsf_tw_enable'
drivers/scsi/oufs/ufshcd.o: In function `ufshcd_query_ioctl':
/home/SekaiMoe/tmpdir/android_kernel_oppo_sm7250/msm-4.19/out/../drivers/scsi/oufs/ufshcd.c:9788: undefined reference to `ufsf_check_query'
/home/SekaiMoe/tmpdir/android_kernel_oppo_sm7250/msm-4.19/out/../drivers/scsi/oufs/ufshcd.c:9789: undefined reference to `ufsf_query_ioctl'
drivers/scsi/oufs/ufshcd.o: In function `ufshcd_eh_device_reset_handler':
/home/SekaiMoe/tmpdir/android_kernel_oppo_sm7250/msm-4.19/out/../drivers/scsi/oufs/ufshcd.c:8307: undefined reference to `ufsf_reset_lu'
drivers/scsi/oufs/ufshcd.o: In function `ufshcd_slave_configure':
/home/SekaiMoe/tmpdir/android_kernel_oppo_sm7250/msm-4.19/out/../drivers/scsi/oufs/ufshcd.c:6444: undefined reference to `ufsf_slave_configure'
drivers/scsi/oufs/ufs-sysfs.o: In function `latency_hist_show':
/home/SekaiMoe/tmpdir/android_kernel_oppo_sm7250/msm-4.19/out/../drivers/scsi/oufs/ufs-sysfs.c:255: undefined reference to `io_latency_hist_show'
/home/SekaiMoe/tmpdir/android_kernel_oppo_sm7250/msm-4.19/out/../drivers/scsi/oufs/ufs-sysfs.c:257: undefined reference to `io_latency_hist_show'
/home/SekaiMoe/tmpdir/android_kernel_oppo_sm7250/msm-4.19/out/../drivers/scsi/oufs/ufs-sysfs.c:259: undefined reference to `io_latency_hist_show'
net/ipv4/tcp_ipv4.o: In function `tcp_v4_rcv':
/home/SekaiMoe/tmpdir/android_kernel_oppo_sm7250/msm-4.19/out/../net/ipv4/tcp_ipv4.c:1748: undefined reference to `oplus_router_boost_handler'
/home/runner/aarch64-linux-android-4.9/bin/aarch64-linux-android-ld: net/ipv4/tcp_ipv4.o: relocation R_AARCH64_ADR_PREL_PG_HI21 against external symbol `oplus_router_boost_handler' can not be used when making a shared object; recompile with -fPIC
/home/SekaiMoe/tmpdir/android_kernel_oppo_sm7250/msm-4.19/out/../net/ipv4/tcp_ipv4.c:1748: undefined reference to `oplus_router_boost_handler'
net/ipv4/udp.o: In function `udp_queue_rcv_skb':
/home/SekaiMoe/tmpdir/android_kernel_oppo_sm7250/msm-4.19/out/../net/ipv4/udp.c:2067: undefined reference to `oplus_router_boost_handler'
/home/runner/aarch64-linux-android-4.9/bin/aarch64-linux-android-ld: net/ipv4/udp.o: relocation R_AARCH64_ADR_PREL_PG_HI21 against external symbol `oplus_router_boost_handler' can not be used when making a shared object; recompile with -fPIC
/home/SekaiMoe/tmpdir/android_kernel_oppo_sm7250/msm-4.19/out/../net/ipv4/udp.c:2067: undefined reference to `oplus_router_boost_handler'
make[1]: *** [/home/SekaiMoe/tmpdir/android_kernel_oppo_sm7250/msm-4.19/Makefile:1255: vmlinux] Error 1
make[1]: Leaving directory '/home/SekaiMoe/tmpdir/android_kernel_oppo_sm7250/msm-4.19/out'
make: *** [Makefile:146: sub-make] Error 2
make: Leaving directory '/home/SekaiMoe/tmpdir/android_kernel_oppo_sm7250/msm-4.19'

于是准备改源码来解决这个问题。

# 0x03

经过排查发现原来是这部分出现了问题:

h bootloader_log.c
static int bootloader_log_probe(struct platform_device *pdev)
{
        struct bootloader_log_platform_data *pdata = pdev->dev.platform_data;
        struct bootloader_log_platform_data of_pdata;
        phys_addr_t paddr;
        int err = -EINVAL;
        pr_err("bootloader_log_probe\n");
        if (pdev->dev.of_node) {
                if (of_bootloader_log_platform_data(pdev->dev.of_node,
                        &of_pdata)) {
                        pr_err("Invalid bootloader log device tree data\n");
                        goto fail_out;
                }
                pdata = &of_pdata;
        }
        if (!pdata->mem_size) {
                pr_err("memory size and record size must be non-zero\n");
                goto fail_out;
        }
        paddr = pdata->mem_address;
        err = persistent_ram_buffer_map(paddr, pdata->mem_size,
                &bootloader_log_ram_zone);
if (err)
                goto fail_out;
        proc_bootloader_log_init();
        pr_info("bootloader_log!\n");
        return 0;
fail_out:
        pr_err("bootloader_log, fail_out!\n");
        return err;
}

于是就把这部分扬了。然后发现整个 vmlinux 也崩了。

后来尝试改成这样:

h diff
--- a/bootloader_log.c
+++ b/bootloader_log.c
@@ -146,7 +146,7 @@
 }
 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;

改完之后编译发现直接编译报错了:

h Logcat
CC      net/sctp/stream_sched_prio.o
  CC      net/sctp/stream_sched_rr.o
../drivers/soc/oplus/system/misc/bootloader_log.c:190:9: warning: incompatible integer to pointer conversion returning 'int' from a function with result type 'int *'; take the address with & [-Wint-conversion]
        return err;
               ^~~
               &
../drivers/soc/oplus/system/misc/bootloader_log.c:205:12: error: incompatible pointer types initializing 'int (*)(struct platform_device *)' with an expression of type 'int *(struct platform_device *)' [-Werror,-Wincompatible-pointer-types]
        .probe          = bootloader_log_probe,
                          ^~~~~~~~~~~~~~~~~~~~
1 warning and 1 error generated.
make[5]: *** [../scripts/Makefile.build:339: drivers/soc/oplus/system/misc/bootloader_log.o] Error 1

我讨厌指针.jpg

然后把这部分去掉编译发现 vmlinux 还是崩,

于是还是接着使用 prebuilt kernel 算了。