Debian for MT7621 折腾记 (3) - 编译 Debian Kernel Package

转载请注明原帖链接和作者!


现在 Debian 已经能基本正常运行了,但是缺少一点最重要的东西,那就是内核模块。

虽然可以直接将 OpenWrt 编译出的 ko 复制到 Debian 中加载,但是这却有不少问题:
1. ko 被精简过,缺少必要信息,如 depmods
2. 编译的 ko 很少
3. 无法被自动加载/按需加载

此外,使用 OpenWrt 的 ko,而不自己编译,会导致系统缺少针对当前 Kernel 的头文件,无法实现在 Debian 中编译自己的 ko。

因此,我需要自己编译 Debian Kernel,也就是修改原始的 Debian Kernel 源代码,加入 OpenWrt 的部分 patch,修改 config,并编译,生成 kernel、header file、kernel modules。

1. 下载 Debian Kernel

根据自己使用的 Debian 发行版代号,选择其对应的 Kernel。

例如我选择的是 Buster,因此打开:

https://packages.debian.org/buster/kernel/linux-source

页面中显示

dep: linux-source-4.19

因此我们需要的 kernel 就是 linux-4.19。

然后选择一个国内源,例如清华源 https://mirrors.tuna.tsinghua.edu.cn/

转到 https://mirrors.tuna.tsinghua.edu.cn/debian-security/pool/updates/main/l/linux/

然后找找到 kernel 版本号最新的 linux_4.19.?? 文件,例如 4.19.67,然后下载相关的几个源码包:
linux_4.19.67-2+deb10u1.debian.tar.xz
linux_4.19.67.orig.tar.xz

2. 准备 Kernel 源代码

首先解压 linux_4.19.67.orig.tar.xz。
然后解压 linux_4.19.67-2+deb10u1.debian.tar.xz,并将其中的 debian 目录放入前面解压得到的源码根目录中 (包含 Makefile 的那一层)。

3. 给源码打上 OpenWrt 的 patch

OpenWrt 针对路由器平台的一些特殊的优化/功能更新也需要合进源码。对于 patch 的选择需要一定的经验。

我选择的文件如下 (其中依然有一些不是必需的,但是保留留作它用):

1. target/linux/generic/backport-4.19 下面的:
010-Kbuild-don-t-hardcode-path-to-awk-in-scripts-ld-vers.patch
011-kbuild-export-SUBARCH.patch
020-backport_netfilter_rtcache.patch
047-v4.21-mtd-keep-original-flags-for-every-struct-mtd_info.patch
048-v4.21-mtd-improve-calculating-partition-boundaries-when-ch.patch
095-Allow-class-e-address-assignment-via-ifconfig-ioctl.patch

2. target/linux/generic/pending-4.19 下面的:
102-MIPS-only-process-negative-stack-offsets-on-stack-tr.patch
120-Fix-alloc_node_mem_map-with-ARCH_PFN_OFFSET-calcu.patch
131-spi-use-gpio_set_value_cansleep-for-setting-chipsele.patch
140-jffs2-use-.rename2-and-add-RENAME_WHITEOUT-support.patch
141-jffs2-add-RENAME_EXCHANGE-support.patch
203-kallsyms_uncompressed.patch
205-backtrace_module_info.patch
220-optimize_inlining.patch
300-mips_expose_boot_raw.patch
302-mips_no_branch_likely.patch
306-mips_mem_functions_performance.patch
308-mips32r2_tune.patch
341-MIPS-mm-remove-no-op-dma_map_ops-where-possible.patch
440-block2mtd_init.patch
441-block2mtd_probe.patch
465-m25p80-mx-disable-software-protection.patch
466-Revert-mtd-spi-nor-fix-Spansion-regressions-aliased-.patch
470-mtd-spi-nor-support-limiting-4K-sectors-support-base.patch
475-mtd-spi-nor-Add-Winbond-w25q128jv-support.patch
476-mtd-spi-nor-add-eon-en25q128.patch
477-mtd-add-spi-nor-add-mx25u3235f.patch
495-mtd-core-add-get_mtd_device_by_node.patch
530-jffs2_make_lzma_available.patch
532-jffs2_eofdetect.patch
551-ubifs-fix-default-compression-selection.patch
553-ubifs-Add-option-to-create-UBI-FS-version-4-on-empty.patch
600-netfilter_conntrack_flush.patch
610-netfilter_match_bypass_default_checks.patch
611-netfilter_match_bypass_default_table.patch
612-netfilter_match_reduce_memory_access.patch
613-netfilter_optional_tcp_window_check.patch
616-net_optimize_xfrm_calls.patch
620-net_sched-codel-do-not-defer-queue-length-update.patch
630-packet_socket_type.patch
655-increase_skb_pad.patch
666-Add-support-for-MAP-E-FMRs-mesh-mode.patch
670-ipv6-allow-rejecting-with-source-address-failed-policy.patch
671-net-provide-defines-for-_POLICY_FAILED-until-all-cod.patch
680-NET-skip-GRO-for-foreign-MAC-addresses.patch
681-NET-add-of_get_mac_address_mtd.patch
701-phy_extension.patch
703-phy-add-detach-callback-to-struct-phy_driver.patch
810-pci_disable_common_quirks.patch
811-pci_disable_usb_common_quirks.patch
834-ledtrig-libata.patch
0931-w1-gpio-fix-problem-with-platfom-data-in-w1-gpio.patch

3. target/linux/generic/hack-4.19 下面的:
160-leds-fix-regression-in-usbport-led-trigger.patch
211-host_tools_portability.patch
212-byteshift_portability.patch
220-gc_sections.patch
250-netfilter_depends.patch
300-MIPS-r4k_cache-use-more-efficient-cache-blast.patch
651-wireless_mesh_header.patch
661-use_fq_codel_by_default.patch
662-remove_pfifo_fast.patch
702-phy_add_aneg_done_function.patch
721-phy_packets.patch
910-kobject_uevent.patch
911-kobject_add_broadcast_uevent.patch

4. target/linux/ramips/patches-4.14 下面的:
0003-MIPS-Fix-memory-reservation-in-bootmem_init-for-cert.patch
0004-MIPS-ralink-add-MT7621-pcie-driver.patch
0007-MIPS-ralink-copy-the-commandline-from-the-devicetree.patch
0024-GPIO-add-named-gpio-exports.patch
0025-pinctrl-ralink-add-pinctrl-driver.patch
0028-GPIO-ralink-add-mt7621-gpio-controller.patch
0045-i2c-add-mt7621-driver.patch
0046-mmc-MIPS-ralink-add-sdhci-for-mt7620a-SoC.patch
0048-asoc-add-mt7620-support.patch
0052-pwm-add-mediatek-support.patch
0053-mtd-spi-nor-add-w25q256-3b-mode-switch.patch
0054-mtd-spi-nor-w25q256-respect-default-mode.patch
0070-weak_reordering.patch
0098-disable_cm.patch
100-mt7621-core-detect-hack.patch
101-mt7621-timer.patch
102-mt7621-fix-cpu-clk-add-clkdev.patch
110-mt7621-perfctr-fix.patch
302-spi-nor-add-gd25q512.patch
这下面的是折腾记 (2) 里面用到的 patch
400-net-mtk_soc_eth-add-support-for-mt7621.diff
402-net-next-mediatek-fix-DQL-support.patch
403-net-mediatek-disable-RX-VLan-offloading.patch
404-net-next-mediatek-honour-special-tag-bit-inside-RX-D.patch
405-net-next-mediatek-enable-special-tag-indication-for-.patch
406-net-mediatek-increase-tx_timeout.patch
407-atomic-sleep.patch
410-dsa-remove-mt7623-trgmii-code.patch
412-net-dsa-mediatek-add-support-for-GMAC2-wired-to-ext-.patch
414-net-next-dsa-mediatek-tell-GDMA-when-we-are-turning-.patch
415-net-dsa-mediatek-turn-into-platform-driver.patch

5. target/linux/ramips/files-4.14 里面的所有文件
注意这些文件也要做成 patch

将这些 patch 文件分类放入 debian/patches 里面,并按顺序将文件相对路径写入 debian/patches/series 里面。

4. 向 Debian package 增加一个新的 flavour

Debian 将系统平台分为3部分:arch/featureset/flavour,
其中 arch 即为 CPU 架构,这里 MT7621 对应的是 mipsel,
featureset 没用到,为 none,
flavour 对应 CPU 架构下的具体平台,因此需要创建一个 MT7621 对应的 flavour,就叫 mt7621。

修改全程以 4kc-malta 为参考。

4.1 修改 debian/config/mipsel/defines,增加如下内容:

--- a/debian/config/mipsel/defines
+++ b/debian/config/mipsel/defines
@@ -4,6 +4,7 @@ flavours:
  5kc-malta
  loongson-3
  octeon
+ mt7621
 kernel-arch: mips
 
 [build]
@@ -43,3 +44,11 @@ hardware-long: Cavium Networks Octeon
 
 [octeon_image]
 configs: kernelarch-mips/config.octeon
+
+[mt7621_description]
+hardware: MT7621
+hardware-long: MediaTek MT7621 boards
+
+[mt7621_image]
+configs:
+ kernelarch-mips/config.mt7621

4.2 创建 debian/config/kernelarch-mips/config.mt7621 文件

这个文件里面填入编译 MT7621 kernel 必需的各种 Kconfig 项目、不打算开启的项目以及需要编译为 ko 的项目。

这里完全按自己的需求来写。可以先 menuconfig 配置完成,再把 .config 改名为 config.mt7621。

必选:
CONFIG_MODVERSIONS=y (Enable loadable module support --->   Module versioning support)
CONFIG_MIPS_RAW_APPENDED_DTB=y (Kernel type   --->   Kernel appended dtb support   --->   vmlinux.bin or vmlinuz.bin)

4.3 创建 debian/installer/modules/mipsel-mt7621 目录

参考 mipsel-4kc-malta 将需要打包的 ko 文件列表写入目录文件中

4.4 创建 debian/abi/4.19.0-6/mipsel_none_mt7621

创建空文件即可

5. 准备编译环境

一定要使用 Debian 或其衍生版,如 Ubuntu 作为编译环境,这样才不会缺少工具。

5.1 安装必要的软件

fakeroot git kernel-wedge quilt ccache flex bison libssl-dev dh-exec gcc-8-mipsel-linux-gnu gcc-mipsel-linux-gnu

5.2 编译目标平台下的一些库,供 gcc-mipsel-linux-gnu 使用

到 https://mirrors.tuna.tsinghua.edu.cn/debian/pool/main/e/elfutils/ 下载最新的安装包:
libelf1_0.176-1.1_mipsel.deb
libelf-dev_0.176-1.1_mipsel.deb

到 https://mirrors.tuna.tsinghua.edu.cn/debian/pool/main/o/openssl/ 下载最新的安装包:
libssl1.1_1.1.1c-1_mipsel.deb
libssl-dev_1.1.1c-1_mipsel.deb

到 https://mirrors.tuna.tsinghua.edu.cn/debian/pool/main/z/zlib/ 下载最新的安装包:
zlib1g-dev_1.2.11.dfsg-1+b1_mipsel.deb
zlib1g_1.2.11.dfsg-1_mipsel.deb

将其中的 data.tar.xz 提取出来并解压,将头文件和库复制到 /usr/mipsel-linux-gnu 下面对应的目录

到 https://mirrors.tuna.tsinghua.edu.cn/debian/pool/main/g/glibc/ 下载最新的安装包:
libc6_2.28-10_mipsel.deb

先将 /usr/mipsel-linux-gnu/lib/libc.so.6 备份,然后将 libc6_2.28-10_mipsel.deb 里面的 libc.so.6 覆盖到 /usr/mipsel-linux-gnu/lib/。
等 6.3 节完成后,还原备份的 libc.so.6。

6. 编译 Kernel

6.1 设置环境变量

export ARCH=mipsel
export FEATURESET=none
export FLAVOUR=mt7621

export $(dpkg-architecture -a$ARCH)
export PATH=/usr/lib/ccache:$PATH
# 设定本次编译为交叉编译(Build profiles 具体内容请参考 debian/README.source)
export DEB_BUILD_PROFILES="cross nopython nodoc"
# 开启并行编译
export MAKEFLAGS="-j$(($(nproc)*2))"
# 禁止编译 -dbg 软件包
export DEBIAN_KERNEL_DISABLE_DEBUG=yes

6.2 编译 Kernel

# 清理上次编译的中间文件
fakeroot make -f debian/rules clean
# 这里执行后会提示错误,忽略即可

# 解包原始源代码,需将 linux_4.19.67.orig.tar.xz 放到上级目录 (与 linux_4.19.67 平级)
# 这一步不能省略,因为 Debian 要保证每次都是使用相同的干净的代码(即只打上了 debian/patches 里的 patch 文件)进行编译
fakeroot make -f debian/rules orig

# 准备源代码(打 patch,生成 control 文件,生成编译规则等)
fakeroot make -f debian/rules source

# 生成 .config 等配置文件
fakeroot make -f debian/rules.gen setup_${ARCH}_${FEATURESET}_${FLAVOUR}

# 编译
# 设置 LANGUAGE=C.UTF-8 是为了避免在非英文系统里编译出现错误
LANGUAGE=C.UTF-8 fakeroot make -f debian/rules.gen binary-arch_${ARCH}_${FEATURESET}_${FLAVOUR}

# 生成 linux-headers-common 等包
LANGUAGE=C.UTF-8 fakeroot make -f debian/rules.gen binary-indep

6.3 编译 linux-kbuild 包

这个包本来是不能交叉编译的,因为它会链接一些目标平台的库,这些库本来是不会存在于编译环境的。

但是在 5.2 节时,我已经将这些库交叉编译并放入了交叉编译工具链中,因此才能编译 linux-kbuild 包。

打开 debian/rules.real,找到 install-kbuild: 目标,将其后命令中的 dh_shlibdeps 注释掉,以屏蔽库依赖检查。

打开 debian/rules.gen,找到 build-arch_mipsel_none_mt7621_real:: 这个目标,将其后的具体命令,复制出来。

将其中的 build-arch-flavour 修改为 install-kbuild 以强制编译 install-kbuild。同时将 $(MAKE) 修改为 fakeroot make。

fakeroot make -f debian/rules.real install-kbuild ABINAME='4.19.0-6' ARCH='mipsel' COMPILER='gcc-8' DEBUG='True' FEATURESET='none' FLAVOUR='mt7621' IMAGE_FILE='vmlinux' IMAGE_INSTALL_STEM='vmlinux' IMAGE_PACKAGE_NAME='linux-image-4.19.0-6-mt7621' KCONFIG='debian/config/config debian/config/kernelarch-mips/config debian/config/mipsel/config debian/config/kernelarch-mips/config.mt7621' KCONFIG_OPTIONS=' -o DEBUG_INFO=y -o "BUILD_SALT=\"4.19.0-6-mt7621\""' KERNEL_ARCH='mips' LOCALVERSION='-mt7621' LOCALVERSION_HEADERS='' LOCALVERSION_IMAGE='-mt7621' SOURCEVERSION='4.19.67-2+deb10u1' SOURCE_BASENAME='linux' UPSTREAMVERSION='4.19' VERSION='4.19'

在当前编译目录下直接执行此命令即可。

6.4 制作可启动的 kernel uImage

编译出来的 kernel vmlinux 并不能直接拿给 u-boot/breed 等 Bootloader 使用,需要进行以下步骤的处理:

假设:
OPENWRT_ROOT 是 OpenWrt 源代码的根目录
KERNEL_ROOT 是要编译的 Kernel 源代码的根目录
BUILD_DIR 是实际编译并生成 vmlinux 文件的目录,一般是 ${KERNEL_ROOT}/debian/build/build_mipsel_none_mt7621
DTS_DIR 是未经预处理的原始 dts 所在的目录
SRC_DTS 是未经预处理的原始 dts,它依赖别的 dtsi (如 mt7621.dtsi)
FINAL_DTS 是经过预处理的完整的 dts
FINAL_DTB 是经过编译的 dts 二进制文件

首先将 dts/dtsi 合并为一个文件:

mipsel-linux-gnu-cpp -nostdinc -x assembler-with-cpp -I${DTS_DIR} -I${KERNEL_ROOT}/include  -undef -D__DTS__ -o ${FINAL_DTS} ${SRC_DTS}

然后编译 dts:

${BUILD_DIR}/scripts/dtc/dtc -Idts -Odtb -i${KERNEL_ROOT}/include -o ${FINAL_DTB} ${FINAL_DTS}

获取 vmlinux 的加载地址:
在 ${KERNEL_ROOT}/arch/mips/ralink/Platform 里面 load-$(CONFIG_SOC_MT7621) 记录的就是 vmlinux 的加载地址
如 load-$(CONFIG_SOC_MT7621) += 0xffffffff80001000,但是只需要低32位,记为 LOADADDR = 0x80001000

获取 vmlinux 的入口点地址:
mipsel-linux-gnu-objdump -f ${BUILD_DIR}/vmlinux
输出中以 "start address" 或者 "起始地址" 打头的那一行,后面记录的就是 vmlinux 的入口点地址
例如 起始地址 0x8067f8b0,记为 ENTRYADDR = 0x8067f8b0

提取 vmlinux.bin:
vmlinux 是一个 elf 文件,不仅体积大,还不能被一般的 Bootloader 加载,因此要先提取 RAW 格式的二进制文件

mipsel-linux-gnu-objcopy -Obinary --gap-fill=0xff ${BUILD_DIR}/vmlinux ${BUILD_DIR}/vmlinux.bin

拼接 vmlinux.bin 与 dtb:

cat ${BUILD_DIR}/vmlinux.bin ${FINAL_DTB} > ${BUILD_DIR}/vmlinux.dtb.bin

压缩 vmlinux.dtb.bin:
不能使用系统自带的 xz 版的 lzma,它不支持 EOS 标记,生成的压缩文件无法被 Bootloader 解压。
必须使用 OpenWrt 提供的 7z 版的 lzma。

${OPENWRT_ROOT}/staging_dir/host/bin/lzma e ${BUILD_DIR}/vmlinux.dtb.bin -lc1 -lp2 -pb2 -d21 ${BUILD_DIR}/vmlinux.dtb.bin.lzma

制作可被 Bootloader 加载的 vmlinux uImage:

mkimage -A mips -O linux -T kernel -C lzma -a ${LOADADDR} -e ${ENTRYADDR} -n "Linux mipsel 4.19.67 MT7621" -d ${BUILD_DIR}/vmlinux.dtb.bin.lzma ${BUILD_DIR}/vmlinux.img

最后将 vmlinux.img 以升级固件的方式更新到 MT7621 板子上即可

7. 测试

如果配置无误,那么应该能正常启动 Debian 系统。

在目标 Debian 环境中首先安装以下软件包:
libelf-dev zlib1g-dev libssl-dev linux-base initramfs-tools linux-initramfs-tool busybox initramfs-tools-core klibc-utils libklibc pigz

然后依次安装以下编译出来的 deb:
linux-config-4.19_4.19.67-2+deb10u1_mipsel.deb
linux-support-4.19.0-6_4.19.67-2+deb10u1_all.deb
linux-kbuild-4.19_4.19.67-2+deb10u1_mipsel.deb
linux-headers-4.19.0-6-common_4.19.67-2+deb10u1_all.deb
linux-headers-4.19.0-6-mt7621_4.19.67-2+deb10u1_mipsel.deb
linux-image-4.19.0-6-mt7621_4.19.67-2+deb10u1_mipsel.deb

现在就能使用全功能并支持 out-of-tree kernel module 编译的 Debian 系统了。

* linux-image-4.19.0-6-mt7621_4.19.67-2+deb10u1_mipsel.deb 里面也包含了 kernel vmlinux,但是这个是用不到的。

参考

[1] https://wiki.debian.org/HowToCrossBuildAnOfficialDebianKernelPackage

Debian for MT7621 折腾记 (3) - 编译 Debian Kernel Package》有5个想法

发表评论

电子邮件地址不会被公开。 必填项已用*标注