4. INTEGRITY分区与调度机制

INTEGRITY 作为面向高安全等级系统的实时操作系统,其核心思想可以用一句话概括:把多个应用“关进”彼此隔离的分区里,再按一张预先设计好的时间表轮流放它们上 CPU 运行。前者是空间分区,后者是时间分区。二者结合,使一个分区即使崩溃、跑飞或超时,也不会破坏其他分区的内存与执行时间,从而让整个系统在混合关键度场景下仍可预测、可验证。

一、空间分区:让每个分区只看见自己的内存

空间分区的本质是内存隔离。INTEGRITY 在系统初始化时,由配置工具为每个分区分配一段独立的物理内存区域,包括代码段、数据段、堆栈和堆区,并把这些区域登记到 MMU(内存管理单元)的页表中。分区运行时,MMU 只允许它访问属于自己的页;一旦越界访问,立即触发异常,由内核接管处理,而不是让错误扩散到其他分区。

空间分区通常包含三层含义:

  • 地址空间隔离:每个分区有独立的虚拟地址空间,分区 A 的指针无法直接指向分区 B 的数据。
  • 访问权限隔离:页表项区分只读、读写、可执行等属性,防止代码段被改写、数据段被执行。
  • 共享内存受控:分区之间若确需通信,必须通过内核提供的受控通道(如消息队列、共享内存区),并显式声明大小与访问方向,不能随意互访。

在工程配置中,空间分区一般以“分区名 + 内存段 + 大小 + 权限”的形式描述。例如某飞控场景中,导航分区分配 2 MB 只读代码 + 1 MB 读写数据,显示分区分配 4 MB 读写数据,二者互不重叠。配置完成后,链接脚本与页表由工具链自动生成,开发者不需要手工填写物理地址。

二、时间分区:用调度表切分 CPU 时间

时间分区解决的是“谁在什么时候用 CPU”的问题。INTEGRITY 采用基于时间触发(Time-Triggered)的周期调度:系统维护一张分区调度表(Partition Schedule Table),把一个大周期(Major Frame)划分为若干时间窗口(Time Window),每个窗口固定分配给某个分区。窗口一到,内核切换上下文,让对应分区运行;窗口结束,无论该分区是否执行完,都强制切走。

调度表的关键参数包括:

  • 主周期(Major Frame):调度表循环一次的总时长,例如 20 ms。
  • 窗口偏移(Offset):该分区窗口在主周期内的起始时刻。
  • 窗口时长(Duration):该分区本次可连续占用的 CPU 时间,例如 2 ms。
  • 周期(Period):窗口重复出现的间隔,通常等于主周期。

下面这张图展示了一个主周期为 20 ms 的调度表:导航分区在 0~4 ms 运行,控制分区在 4~10 ms 运行,通信分区在 10~14 ms 运行,健康监控分区在 14~16 ms 运行,剩余 16~20 ms 作为空闲/余量窗口。每个分区只在自己的窗口内获得 CPU,窗口之外即使有任务就绪也必须等待。

INTEGRITY 分区调度表(主周期 20 ms) 0 4 10 14 16 20 导航分区 0–4 ms 控制分区 4–10 ms 通信分区 10–14 ms 监控 14–16 ms 空闲/余量 16–20 ms 调度规则: ① 窗口内分区独占 CPU,窗口结束强制切换;② 分区超时未完成则被挂起,等待下一主周期; ③ 空闲窗口可运行低优先级后台任务,但不影响关键分区的时间预算。

三、周期调度与实时性保障

时间分区调度的最大优势是可预测性。由于每个分区的执行窗口在编译期就已确定,最坏情况响应时间(WCRT)可以静态计算:一个分区从被唤醒到获得 CPU 的最长等待时间,等于调度表中排在它前面的所有窗口时长之和。只要这个值小于任务的截止期,实时性就有保证。

以图中调度表为例,控制分区在 4 ms 时刻获得 CPU。若某控制任务在 0 ms 被外部中断唤醒,它最坏要等到 4 ms 才能运行,即最坏调度延迟为 4 ms。如果该任务截止期为 8 ms,则满足要求;若截止期为 3 ms,则必须调整调度表,把控制分区窗口前移或缩短导航分区窗口。

实时性保障还需要注意以下几点:

  • 窗口预算要留余量:分区实际执行时间应小于窗口时长,建议不超过 70%~80%,为中断处理、上下文切换和抖动留出空间。
  • 中断处理要短:中断服务程序应尽量精简,把耗时工作交给分区任务,避免中断抢占过多时间。
  • 避免优先级反转:分区内部任务调度与分区间调度相互独立,分区内可使用优先级抢占,但分区边界由时间窗口强制隔离。
  • 健康监控配合:每个分区可配置执行时间监控,超时即触发故障处理,防止某个分区拖垮整个主周期。

四、配置示例与验证方法

下面是一段简化的分区调度表配置片段(示例参数,非实测值),用于说明工程中如何描述时间分区:

partition Navigation {
    memory  { code 2M ro, data 1M rw }
    schedule { offset 0ms, duration 4ms, period 20ms }
}
partition Control {
    memory  { code 3M ro, data 2M rw }
    schedule { offset 4ms, duration 6ms, period 20ms }
}
partition Comm {
    memory  { code 1M ro, data 1M rw }
    schedule { offset 10ms, duration 4ms, period 20ms }
}
partition Health {
    memory  { code 512K ro, data 256K rw }
    schedule { offset 14ms, duration 2ms, period 20ms }
}

配置完成后,验证通常分三步:静态检查——确认所有窗口之和不超过主周期,且各分区内存区域无重叠;时序测量——在目标板上用示波器或跟踪工具测量各分区实际进入/退出时刻,与调度表对比,偏差应在允许抖动范围内;故障注入——人为让某分区死循环或越界访问,观察它是否被限制在自己的窗口和内存内,其他分区是否仍按表运行。

判断调度表是否合格的核心依据:所有分区窗口之和 ≤ 主周期;每个分区的最坏调度延迟 ≤ 其任务截止期;故障注入后其他分区的时间与空间边界不被突破。

总结来说,INTEGRITY 的分区与调度机制把“隔离”和“时间确定性”同时做进了内核:空间分区用 MMU 划清内存边界,时间分区用调度表划清 CPU 边界,二者共同构成混合关键度系统可预测运行的基础。工程上真正要做的,是把每个分区的内存预算、窗口偏移、窗口时长和周期设计准确,再用静态检查、时序测量和故障注入三类手段验证它确实按预期工作。