为 Linux 内核移植 PREEMPT_RT:架构级支持要求完整指南
为 Linux 内核移植 PREEMPT_RT架构级支持要求完整指南【免费下载链接】linuxLinux kernel source tree项目地址: https://gitcode.com/GitHub_Trending/li/linux本指南基于 Linux 内核文档 Documentation/core-api/real-time/architecture-porting.rst系统梳理让一个 CPU 架构获得 PREEMPT_RT 完全抢占实时支持所必须具备的架构级条件。文档作者为 Sebastian Andrzej SiewiorLinux 实时内核维护者之一。读完本文你将掌握 PREEMPT_RT 对中断线程化、抢占、POSIX CPU 定时器、软中断栈、FPU/SIMD 上下文、异常处理等环节的架构要求以及可选增强特性高精度时钟源、lazy preemption、NBCON 串口控制台的落地方式并能在 Kconfig 中正确开启ARCH_SUPPORTS_RT。概述从架构要求到 ARCH_SUPPORTS_RTPREEMPT_RTFULLY PREEMPTIBLE是内核提供的实时抢占配置。要让一个架构可以启用它不是在架构的 Kconfig 里直接打开某个选项而是必须先实现文档列出的若干架构级功能然后在架构 Kconfig 中选择ARCH_SUPPORTS_RT使 kernel/Kconfig.preempt 中的PREEMPT_RT变为可选config PREEMPT_RT ... depends on EXPERT ARCH_SUPPORTS_RT !COMPILE_TEST也就是说ARCH_SUPPORTS_RT是 PREEMPT_RT 的使能闸门。以 ARM64 为例arch/arm64/Kconfig 中已有select ARCH_SUPPORTS_RT。文档同时强调许多前置条件例如 genirq 通用中断框架支持已由公共代码强制保证因此本清单只关注架构自身必须实现的部分可选特性虽非强制但强烈建议评估。强制要求Requirements1. 强制中断线程化Forced threaded interrupts文档要求架构必须选择CONFIG_IRQ_FORCED_THREADING即内核将绝大多数中断处理程序放到专用内核线程中执行从而把中断优先级冲突对实时任务的影响降到最低。该选项在 kernel/irq/Kconfig 中定义# Support forced irq threading config IRQ_FORCED_THREADING bool必须保持硬中断上下文的例外任何必须留在硬 IRQ 上下文的中断都要用IRQF_NO_THREAD标志注册。文档明确列出三类典型例子时钟源事件中断clocksource event interrupts负责驱动clockevents的周期性/单次触发中断必须保持硬中断语义perf 中断性能计数采样中断要求低延迟与确定性不能线程化级联中断控制器处理程序cascading interrupt-controller handlers父控制器转发子控制器中断时其处理逻辑必须在硬中断上下文完成。关于IRQF_NO_THREAD的处理可参见 kernel/irq/manage.c 与 kernel/irq/handle.c 中强制线程化路径的实现。2. 抢占支持PREEMPTION support内核抢占必须可用即CONFIG_ARCH_NO_PREEMPT必须保持未选择。同时从中断或其他异常处理程序中发出的调度请求如schedule()请求必须被立即处理不能延迟到返回用户态。这是 PREEMPT_RT 低延迟保证的基础任何抢占点都必须能够即时响应调度请求而不是等待当前执行流自然结束。3. POSIX CPU 定时器与 KVMPOSIX CPU timers and KVMPREEMPT_RT 要求POSIX CPU 定时器在线程上下文中到期而不是直接在定时器中断里执行。这通过设置CONFIG_HAVE_POSIX_CPU_TIMERS_TASK_WORK启用其定义与默认规则位于 kernel/time/Kconfigconfig HAVE_POSIX_CPU_TIMERS_TASK_WORK bool ... default y if POSIX_TIMERS HAVE_POSIX_CPU_TIMERS_TASK_WORK即将定时器到期动作包装为 task work在返回用户态或切换上下文时以线程上下文处理避免在硬中断中执行可能睡眠的操作。虚拟化场景当启用 KVM 等虚拟化支持时还必须设置CONFIG_VIRT_XFER_TO_GUEST_WORK确保在进入 guest 模式之前处理完所有挂起工作例如 POSIX 定时器到期。否则 guest 可能带着未处理的定时器工作进入破坏实时语义。该选项在虚拟化代码路径中衔接迁移到 guest的入口。4. 硬中断栈与软中断栈Hard-IRQ and Soft-IRQ stacksPREEMPT_RT 改变了软中断的执行模型软中断在触发它的线程上下文中处理若软中断由硬中断上下文触发其执行会被推迟到 ksoftirqd 线程软中断处理期间从不关闭抢占因此软中断是可抢占的。这一模型对栈的需求影响很大如果架构提供了自定义的__do_softirq()实现且使用独立栈则必须选择CONFIG_HAVE_SOFTIRQ_ON_OWN_STACK。该选项在 arch/Kconfig 中定义且只有在CONFIG_SOFTIRQ_ON_OWN_STACK设置时才应启用config HAVE_SOFTIRQ_ON_OWN_STACK bool help Architecture provides a function to run __do_softirq() on a separate stack. config SOFTIRQ_ON_OWN_STACK def_bool HAVE_SOFTIRQ_ON_OWN_STACK !PREEMPT_RT注意SOFTIRQ_ON_OWN_STACK的默认规则显式带上了 !PREEMPT_RT因为 PREEMPT_RT 下软中断运行在线程上下文由内核栈处理独立软中断栈便不再必要。这是功能只在非 RT 且具备独立栈实现时生效的典型联动。5. 内核态的 FPU/SIMD 访问FPU and SIMD access in kernel mode内核态通常不使用 FPU/SIMD 寄存器因此内核抢占时不会保存这些寄存器。任何在内核态使用这些寄存器的代码必须被包在kernel_fpu_begin()与kernel_fpu_end()之间。在普通内核上kernel_fpu_begin()通常会调用local_bh_disable()既屏蔽软中断打扰也关闭普通抢占从而保证受保护代码在线程上下文和软中断上下文都能安全运行在 PREEMPT_RT 内核上kernel_fpu_begin()不得调用local_bh_disable()而应改用preempt_disable()。原因正如第 4 点所述PREEMPT_RT 下软中断始终在线程上下文处理仅关闭抢占便已足够无需也不应关闭下半部。与 crypto 子系统的配合crypto 子系统基于内存页工作在处理请求时需要遍历并映射这些页walk and map。该操作必须在kernel_fpu_begin()/kernel_fpu_end()区段之外进行因为页映射需要开启抢占。这些抢占点通常足以避免产生过度的调度延迟。6. 异常处理程序Exception handlers异常处理程序如缺页异常处理通常在早期就使能中断然后才调用通用代码处理异常——因为处理缺页可能涉及可睡眠操作。这一点在 PREEMPT_RT 上尤其重要RT 内核中spinlock_t等锁会变成可睡眠的sleepable中断若迟迟不打开可能长时间阻塞实时任务。文档给出两个具体例子处理非法操作码invalid opcode异常可能导致向用户任务发送SIGILL信号调试异常debug exception会发送SIGTRAP信号。两种情况下若异常发生在用户空间尽早使能中断是安全的因为发送信号既要求中断使能也要求内核抢占使能。架构移植时应确保异常入口路径在适当时机通常是在判断异常来源后尽快打开中断。可选特性Optional features1. 定时器与时钟源Timer and clocksource建议提供高分辨率时钟源high-resolution clocksource支持CLOCK_EVT_FEAT_ONESHOT单次触发模式的 clockevents 设备以获得最优定时行为。大多数场景下微秒级精度已足够。单次触发模式配合高精度定时框架可以避免周期性 tick 带来的无谓唤醒是实时系统降低抖动的基础设施。2. Lazy preemption惰性抢占该机制允许针对非实时任务的内核内调度请求延迟到任务即将返回用户空间时再执行。它的意义在于避免在一个持有可睡眠锁sleeping lock的任务正要被调度时将其抢占从而减少锁持有期间的上下文切换与优先级反转窗口。当启用了CONFIG_GENERIC_IRQ_ENTRY时支持该特性需要在架构的线程信息标志中定义一个TIF_NEED_RESCHED_LAZY位最好紧挨着TIF_NEED_RESCHED公共头文件 include/linux/thread_info.h 提供了默认回退#ifndef TIF_NEED_RESCHED_LAZY #define TIF_NEED_RESCHED_LAZY TIF_NEED_RESCHED #define _TIF_NEED_RESCHED_LAZY _TIF_NEED_RESCHED #endif已实现该特性的架构如 x86会在 arch/x86/include/asm/thread_info.h 中定义HAVE_TIF_NEED_RESCHED_LAZY。移植时建议参考 x86 的线程信息标志布局。3. 支持 NBCON 的串口控制台Serial console with NBCONPREEMPT_RT 启用后所有控制台输出由专用线程处理而不是在调用printk()的原始上下文中直接输出。这一设计使printk()可以在原子上下文原子上下文指关闭抢占/中断或中断处理等场景安全使用。代价如果内核崩溃且无法切换到打印线程将看不到任何输出——系统无法打印最终信息。不过存在例外例如panic()处理期间的立即输出。为了支持这种例外的即时输出控制台驱动必须实现新式锁处理new-style lock handling具体包括在console::flags中设置CON_NBCON标志提供以下四个回调的实现write_atomic用于原子上下文如 panic 时的即时输出write_thread由打印线程调用的常规输出device_lock/device_unlock设备级锁的获取与释放。这些回调的原型与语义定义在 include/linux/console.h 与 include/linux/console.h 中CON_NBCON标志位于 flags 的BIT(8)。NBCONnon-blocking console框架专门服务于原子上下文可打印 线程化常规打印双模式是 PREEMPT_RT 串口控制台的正解。移植检查清单综合文档与仓库实现架构移植者可按以下清单逐项核对编号检查项配置/标志位置参考1强制中断线程化CONFIG_IRQ_FORCED_THREADING必须选择硬中断例外用IRQF_NO_THREADkernel/irq/Kconfig2内核抢占CONFIG_ARCH_NO_PREEMPT不得选择调度请求立即处理—3POSIX CPU 定时器线程化CONFIG_HAVE_POSIX_CPU_TIMERS_TASK_WORKkernel/time/Kconfig3b虚拟化迁移前处理挂起工作CONFIG_VIRT_XFER_TO_GUEST_WORK启用 KVM 时—4独立软中断栈自定义__do_softirq()时选CONFIG_HAVE_SOFTIRQ_ON_OWN_STACK仅在CONFIG_SOFTIRQ_ON_OWN_STACK置位时启用arch/Kconfig5FPU/SIMD 内核访问kernel_fpu_begin()在 RT 下用preempt_disable()而非local_bh_disable()页映射在区段外—6异常处理早期开中断用户态异常尽快使能中断与抢占如 SIGILL/SIGTRAP 路径—7可选高精度时钟高分辨率 clocksource CLOCK_EVT_FEAT_ONESHOT—8可选Lazy preemption定义TIF_NEED_RESCHED_LAZY靠近TIF_NEED_RESCHED参考HAVE_TIF_NEED_RESCHED_LAZYinclude/linux/thread_info.h9可选NBCON 控制台CON_NBCON标志 write_atomic/write_thread/device_lock/device_unlock回调include/linux/console.h收尾步骤全部强制项实现并验证后在架构 Kconfig 中添加select ARCH_SUPPORTS_RT可参考 arch/arm64/Kconfig 的现成做法PREEMPT_RT即会在make menuconfig的Kernel Features → Preemption Model中出现可选。结语PREEMPT_RT 的架构移植并非打开一个开关那么简单而是对中断、抢占、软中断、FPU 上下文、异常路径与定时器语义的一整套架构级适配。本文以官方文档 Documentation/core-api/real-time/architecture-porting.rst 为骨架结合仓库中 arch/arm64/Kconfig、arch/Kconfig、kernel/Kconfig.preempt、kernel/time/Kconfig、include/linux/thread_info.h 与 include/linux/console.h 等源码给出了可验证的实现依据。若需了解调度模型本身的差异可进一步阅读 Documentation/scheduler 相关章节本指南聚焦于架构如何接入 RT是开始移植工作的第一步。【免费下载链接】linuxLinux kernel source tree项目地址: https://gitcode.com/GitHub_Trending/li/linux创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考