Linux RT 内核 (5) - 移植 PREEMPT_RT 内核补丁

1. 前言

限于作者能力水平,本文可能存在谬误,因此而给读者带来的损失,作者不做任何承诺。

2. 移植 PREEMPT_RT 内核补丁

2.1 下载源码

本文以 Linux 4.14.336 为例说明 PREEMPT_RT 补丁的移植过程。首先到地址 linux-4.14.336.tar.xz 下载 linux-4.14.336 内核源码,然后到地址 patch-4.14.336-rt159.patch.xz PREEMPT_RT 内核补丁源码。

2.2 应用 PREEMPT_RT 内核补丁

分别解压 linux-4.14.336.tar.xzpatch-4.14.336-rt159.patch.xz,假定 linux-4.14.336.tar.xz 解压到目录 linux-4.14.336 下,patch-4.14.336-rt159.patch.xz 解压后到目录 patches。通过如下脚本 apply-patches.shpatch-4.14.336-rt159.patch.xz 补丁应用到内核 linux-4.14.336.tar.xz

#!/bin/bash

# 脚本用法说明
usage() {
    echo "用法: $0 <补丁目录> <内核源码目录>"
    echo "  补丁目录: 包含 .patch 文件的目录"
    echo "  内核源码目录: 要应用补丁的 Linux 内核源码目录"
    exit 1
}

# 检查参数数量
if [ $# -ne 2 ]; then
    usage
fi

PATCH_DIR="$1"
KERNEL_DIR="$2"

# 检查目录是否存在
if [ ! -d "$PATCH_DIR" ]; then
    echo "错误: 补丁目录 '$PATCH_DIR' 不存在"
    exit 1
fi

if [ ! -d "$KERNEL_DIR" ]; then
    echo "错误: 内核源码目录 '$KERNEL_DIR' 不存在"
    exit 1
fi

# 将相对路径转换为绝对路径
get_abs_path() {
    local dir="$1"
    if [[ "$dir" != /* ]]; then
        echo "$(cd "$dir" && pwd)"
    else
        echo "$dir"
    fi
}

ABS_PATCH_DIR=$(get_abs_path "$PATCH_DIR")
ABS_KERNEL_DIR=$(get_abs_path "$KERNEL_DIR")

# 保存当前目录,以便脚本结束时返回
ORIGINAL_DIR="$(pwd)"

# 定义清理函数,确保退出时回到原目录
cleanup() {
    cd "$ORIGINAL_DIR" || exit
}

# 设置陷阱,确保脚本退出时执行清理
trap cleanup EXIT

# 切换到内核源码目录
cd "$ABS_KERNEL_DIR" || {
    echo "错误: 无法切换到内核源码目录 '$ABS_KERNEL_DIR'"
    exit 1
}

# 查找并排序 .patch 文件
PATCH_FILES=$(find "$ABS_PATCH_DIR" -name "*.patch" -type f | sort)

# 检查是否找到 .patch 文件
if [ -z "$PATCH_FILES" ]; then
    echo "警告: 在 '$ABS_PATCH_DIR' 中未找到 .patch 文件"
    exit 0
fi

echo "找到 $(echo "$PATCH_FILES" | wc -l) 个补丁文件"

# 应用补丁
for patch_file in $PATCH_FILES; do
    echo "正在应用补丁: $(basename "$patch_file")"
    
    # 使用 git apply 应用补丁
    if ! git apply --whitespace=nowarn "$patch_file"; then
        echo "错误: 应用补丁 '$(basename "$patch_file")' 失败"
        echo "已停止应用后续补丁"
        exit 1
    fi
done

echo "所有补丁已成功应用"
# 先建立 git 仓库才能应用补丁
$ cd linux-4.14.336
$ git init
$ git add -A
$ git commit -m "Initial commit."
$ cd ..

$ ./apply-patches.sh patches linux-4.14.336

也可以跳过补丁打入步骤,直接下载官方合并好的实时内核版本:

另外,现在的高版本内核更是在 upstream 内核直接集成了 RT 补丁,而不是独立维护了。

2.3 编译运行

笔者通过 QEMU 模拟 ARM 开发板,并辅以 ubuntu 的 rootfs 测试运行。先生成默认配置:

$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- O=output vexpress_defconfig

然后通过命令

$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- O=output menuconfig

选择内核抢占配置如下:

be26256c-847a-41a4-82c4-d0e6317eb815

也即选择 CONFIG_PREEMPT_RT_FULL=y,然后编译:

$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- O=output -j$(nproc)

最后用 QEMU 运行:

#!/bin/bash

sudo qemu-system-arm \
     -M vexpress-a9 -smp 4 -m 512M \
     -kernel linux-4.14.336/output/arch/arm/boot/zImage \
     -dtb linux-4.14.336/output/arch/arm/boot/dts/vexpress-v2p-ca9.dtb \
     -append "root=/dev/mmcblk0 rw rootfstype=ext4 console=ttyAMA0 page_owner=on" \
     -sd rootfs/image/arm-ubuntu-16.04.img \
     -serial stdio \
     -net nic -net tap,ifname=tap0,script=no,downscript=no
#    -nographic \
#     -S -s

运行起来后像这样:

Ubuntu 16.04 LTS qemu-ubuntu ttyAMA0

qemu-ubuntu login: root
Password: 
Welcome to Ubuntu 16.04 LTS (GNU/Linux 4.14.336-rt159+ armv7l)

 * Documentation:  https://help.ubuntu.com/
root@qemu-ubuntu:~# cat /proc/version 
Linux version 4.14.336-rt159+ (lxj@lxj-virtual-machine) (gcc version 5.4.0 20160609 (Ubuntu/Linaro 5.4.0-6ubuntu1~16.04.9)) #1 SMP PREEMPT RT Mon Mar 9 15:55:15 CST 2026
root@qemu-ubuntu:~#

cat /proc/version 可以看到 PREEMPT RT 输出,说明这是 RT 内核版本。

3. 番外

这两天又在开源硬件 NanoPi-NEO-Core 上移植了一把 PREEMPT_RT 补丁,主要分为两步:

  • 将内核从 4.14.111 升级到 4.14.336
  • 在内核 4.14.336 适配 PREEMPT_RT 补丁 patches-4.14.336-rt159.tar.gz

系统起来后,uname -a 的输出如下:

root@NanoPi-NEO-Core:~# uname -a
Linux NanoPi-NEO-Core 4.14.336-rt159 #3 SMP PREEMPT RT Tue Mar 17 13:25:16 CST 2026 armv7l armv7l armv7l GNU/Linux
posted @ 2026-03-09 17:17  JiMoKuangXiangQu  阅读(64)  评论(0)    收藏  举报