Files
reverse-skills-max/vendor-new/rev-skills/.claude/skills/re-rtos/references/ecos.md

8.1 KiB
Raw Blame History

eCos:ISR / DSR / thread、CDL 配置系统、HAL 与启动

eCos 有两条同样重要的东西,**只掌握其中一条都会误判**:
运行期:ISR → DSR → thread 三层(中断模型)
构建期:CDL 配置系统决定编进什么、向量在哪、谁先跑

同一份源码在不同配置下的产物差异极大——所以顺序是:

先确认配置(CDL),再谈代码

</CORE RULE>

一、ISR 与 DSR 的分工

  • ISR 返回时若带"需要调用 DSR"的位,系统会调用关联的 DSR(Deferred Service Routine)
  • 若调度器未被锁定,DSR 立即运行;若被中断的线程恰在内核调用里锁了调度器,DSR 会被推迟到解锁之后
  • 这个推迟正是 DSR 能安全做某些内核调用的原因——例如 post 一个信号量、signal 一个条件变量

二、同步级别是 API 的属性

级别 谁可以调用
Thread 仅线程代码
DSR DSR 或线程代码
ISR ISR、DSR 或线程代码

调用点落在哪一级,决定了哪些 API 是合法的。

三、三种同步机制

机制 作用 谁能用
与 ISR 同步(禁中断 + SMP 下自旋锁) 阻止临界区内 ISR 运行 必须短且少用
与 DSR 同步 阻止临界区内 DSR 运行(内核里等价于取调度器锁) DSR 与线程可用;ISR 不允许使用
与线程同步(互斥量、条件变量) 线程级阻塞与唤醒 只有线程可以 lock 互斥量与 wait 条件变量;DSR 可以 signal 条件变量

数据保护按"谁会碰它"分层:被 ISR 访问的数据在任何层级(包括 ISR 内部)都要用 ISR 锁/自旋锁保护;DSR 与线程共享的用 DSR 锁;只有线程访问的用互斥量。

四、三种典型驱动模型

  1. 全部处理放在 ISR(DSR 只 signal 条件变量唤醒线程)
  2. 处理推迟到 DSR(DSR 可选地 signal 条件变量并解屏蔽中断)
  3. 处理推迟到线程(DSR 只 signal,线程随后获得完整内核设施)

五、CDL:配置系统决定一切

配置由 CDL 定义驱动,选项决定"编进什么"。几个有逆向价值的类别:

  • 通信通道选择(通道数量、调试通道、控制台通道及其波特率、控制台默认通道)
  • 使用 ROM 监视器时这些通道选项通常失效——由监视器选择通道;应用可通过配置项声明自己接管通信
  • 调试/GDB 桩的包含与否直接影响镜像内容与异常处理去向
  • 构建目标(ROM / ROMRAM / RAM 等)决定镜像是否需要在启动时重定位

逆向含义:拿到一个 eCos 镜像,"里面有什么"是配置的产物,不是源码的自然结果。先把配置项与编入项对上,再解释代码。

六、HAL:向量表与 VSR

  • 向量表的位置完全由内存映射决定:由内存布局工具决定,并体现在布局描述文件里
  • 启动时初始化向量表
  • 同步异常的向量项大多指向一个默认异常向量:它保存 CPU 状态并调用异常处理器,后者按配置路由到调试桩或路由到 eCos
  • 由 ROM 监视器加载的应用,其向量项指向监视器自己的异常向量——所以异常会进监视器(例如调试器),除非应用显式替换该项
  • 异常向量的偏移由 HAL 头文件里的编号定义

七、虚拟向量:ROM 监视器给 RAM 应用提供的服务表

  • 在静态地址处有一张表(几十个向量),指向服务函数或数据,让 ROM 配置(如 RedBoot)为单独链接的 RAM 应用提供服务
  • 服务含:通信通道(控制台/调试)、微秒延时、复位、缓存刷新、调试/控制台通道切换、调试系统调用(线程信息)、flash 配置访问
  • 由 ROM 监视器或按策略由独立/RAM 配置初始化;无论用不用都保留固定的字节数
  • 代价是间接层(体积/性能开销,并多一个失败点);收益是应用可以不含调试桩也能被调试

八、启动顺序(RedBoot / 典型 ROM 配置)

复位入口
  → 平台设置宏:禁中断与缓存、初始化内存控制器与时钟、建立并开启 MMU
    (ROMRAM 情形还要重定位镜像)
  → HAL 启动:在 0 号位置放置向量指令、复制 .data、设栈、清 .bss
    → 硬件初始化
    → (含调试桩则)初始化调试桩
    → 中断(ctrl-C 类)初始化
    → 【调用构造函数】
  → 进入 cyg_start

构造函数在硬件/桩/中断初始化之后、进入主启动之前运行。

九、构造函数与内存布局的一个真实坑

向量表所在区域如果与构造函数区域重叠,初始化会把构造函数冲掉——曾出现过"预期的构造函数在某个地址上,结果被初始化向量表时覆盖"的实例。

所以:向量表位置必须按目标内存映射决定,且如果需要被初始化,就不能放在 flash 里。

十、调试与 GDB 桩

  • 调试桩在 HAL 启动阶段被初始化;异常处理器在含桩时进 GDB
  • ROM 监视器通常包含 GDB 协议支持,可以关掉以节省代码与内存
  • 虚拟向量让"不含桩的应用"也能被调试;但某些较老的 ROM 监视器在异步调试中断上会失败,除非应用里也配了调试支持
  • 相关配置项控制"是否构建带 GDB 的监视器"以及"是否包含桩"

十一、平台差异与可配置性

  • eCos 覆盖多种架构的 HAL,不同架构的 HAL 在向量表、启动序列、缓存与 MMU 处理上不同
  • 调度器、定时器、同步原语都受配置影响;"这版 eCos 的线程模型是怎样的"要由配置回答
  • 内存池与堆的配置同样属于构建期选择

决策树

拿到 eCos 目标
├─ 先确认配置(CDL)
│    ├─ 构建目标(ROM/ROMRAM/RAM)→ 是否启动时重定位
│    ├─ 是否含调试桩 → 异常去向
│    └─ 通道/控制台/调度器等选项 → 编入了什么
├─ 看到一个很短的中断处理函数
│    └─ 真正工作可能在 DSR(或第三个线程)
├─ 看到一个没有线程入口却反复执行的函数
│    └─ 可能是 DSR
├─ 判断某个内核调用是否合法
│    └─ 查它的同步级别(Thread / DSR / ISR)
├─ 异常去向与预期不符
│    ├─ 是否含调试桩?
│    ├─ 向量项指向 eCos 还是 ROM 监视器?
│    └─ 应用是否替换了向量项
├─ 构造函数"没运行"
│    └─ 查向量表所在区域是否与构造函数区域重叠(会被初始化冲掉)
└─ 找不到某个功能
     └─ 可能是配置里就没编进去

工具与验证

  • 配置:CDL 选项与编入项、构建目标、调试桩是否包含
  • 分层:ISR 返回值(是否调度 DSR)、DSR 注册与调用点、各调用的同步级别
  • HAL:向量表位置(布局文件)、向量项指向、异常处理器路由
  • 启动:复位入口 → 平台设置 → HAL 启动 → 构造函数 → 主启动
  • 验证:能同时说清「这份镜像是哪套配置构建的 + 中断处理分布在哪几层 + 异常会去哪里」

该平台的坑(汇总)

  • 把 ISR 当完整的中断处理:工作可能在 DSR,甚至在第三个线程里
  • 把 DSR 当普通线程回调:它有同步级别与调度约束,且会被调度器锁推迟
  • 在 ISR 里套用 DSR 级同步的假设:ISR 不允许使用 DSR 锁
  • 以为 DSR 可以像线程一样等待:能 signal 条件变量,不能 wait
  • 按"中断发生时刻"推断时序:DSR 的运行时机受调度器锁影响
  • 不看配置就解释代码:CDL 决定编入项、通道、调试桩、构建目标
  • 把异常去向当固定:取决于是否含桩、向量项指向谁、应用是否替换
  • 忽略向量表与构造函数区域冲突:构造函数会被初始化覆盖
  • 以为 ROM 监视器加载的应用异常会进 eCos:默认进监视器
  • 把虚拟向量当纯开销:它让无桩应用也能被调试,是有意的权衡