摘要:项目最后选定了 LK 作为内核,直接上手后发现它把很多关键点都处理好了,启动快,功能比典型的轻量 RTOS 强,代码量又远小于 Linux。把它放到工程里,启动时间以毫秒计,移植也不费劲,这就是最直观的结果。把它放到工程里,启动时间以毫秒计,移植也不费劲,这就
项目最后选定了 LK 作为内核,直接上手后发现它把很多关键点都处理好了,启动快,功能比典型的轻量 RTOS 强,代码量又远小于 Linux。把它放到工程里,启动时间以毫秒计,移植也不费劲,这就是最直观的结果。把它放到工程里,启动时间以毫秒计,移植也不费劲,这就是最直观的结果。
说回来,这事儿能这么顺利,和 LK 的设计有关。它并不是传统的那种轻量 RTOS,也不是完整的 Linux 内核,而处在两者之间。对一个需要比 FreeRTOS 更丰富功能但又不能承受 Linux 复杂度的项目来说,LK 刚好填了这个空白。它有虚拟内存支持和多核调度,能做一些更复杂的任务;同时保持了非常小的体量,内核代码只有几万行,启动非常快,所以适合引导阶段或者资源受限的嵌入式场景。
再往前说点背景。LK 的作者是 Travis Geiselbrecht,最早是为 Android 设备做 bootloader 的。很多设备把它当作引导程序用了,百万级别的应用案例证明了它不是纸上谈兵。现在它已经演进成一个完整的嵌入式内核,被开源社区和商业项目都拿来用了。想看源码的人可以去 GitHub 上查 littlekernel 仓库。
它的工程和架构设计值得细看。整体采用分层、模块化的思路,常见的 Arch、Platform、Target 这种三层抽象在里面表现得很干净。更进一步,它把关注点分得清楚,从底层到上层大概分成五层,每一层各自负责自己的事情。这样的好处很明显:高内聚、低耦合。要新增某个平台支持,通常只要在对应目录下添加几份代码就行,其他部分几乎不受影响。
构建系统也很讲究。模块间的依赖通过 rules.mk 声明,构建工具会自动解析这些依赖,保证编译和链接的顺序正确。你不用手动去维护那些复杂的 Makefile 依赖链,工程化得比较好。还有一个小技巧是初始化函数的注册机制。代码里用宏把初始化项放到一个单独的段里,编译器会把这些结构体集合到 .lk_init 段,启动时系统按预定顺序遍历并执行它们。这样就能确保子系统按合适的优先级依次初始化,不会出现某个模块还没准备好就被使用的窘境。
调度是内核里最敏感的部分之一。LK 用的是优先级抢占式调度,支持 32 级优先级。这套设计里有就绪队列和一个优先级位图,位图用来快速找出最高优先级的就绪线程。调度流程并不复杂:先看位图找最优先级,然后从对应的就绪队列取出线程,切换执行。为了处理公平性和响应性,它还实现了基于定时器的时间片轮转,这样低优先级的线程也能获得运行机会,同时高优先级的实时任务能迅速抢占。
初始化顺序被划分为多个级别。每个级别都可以注册多个初始化函数,系统会按照级别顺序执行,级别内部按注册顺序或优先级处理。许多平台相关的驱动、内存子系统、调度器这些关键模块都会被放到不同的初始化级别里,保证彼此之间的依赖关系被满足。这个机制虽然简单,但在实际移植或扩展功能时非常实用。
关于模块化和依赖注入,LK 并不是那种把所有东西绑在一起的单体内核。每个模块在自己的 rules.mk 里声明依赖,构建系统据此决定编译链接顺序。举个使用层面的例子,一个应用可能有文件结构像 app/myapp/myapp.c 和 app/myapp/rules.mk,整个工程通过 project/myproject.mk 把这些模块组合起来。开发者只需要在各自目录放好代码和规则,就能把模块编译进最终镜像。实际操作体验就是省了不少手工配置的麻烦。
从工程实践角度看,代码风格比较统一,注释也够用,采用 MIT 许可证对外友好。模块之间的边界分明,增加功能或者移植新平台时,不用重构大块代码。构建系统支持跨平台编译,模块依赖自动化管理,使得团队协作和持续集成都更容易上手。如果你想学一套既能体现 RTOS 特性又不被 Linux 重度复杂性压垮的内核实现,LK 是个不错的样本。
实际案例值得说一下。把 LK 当 bootloader 用在某型号设备上时,工程组最先遇到的问题是启动顺序和驱动依赖。通过把驱动初始化分配到不同的 init 级别,问题很快解决。另一个常见场景是需要支持多核,LK 的多核调度和虚拟内存支持让移植变得可行,虽然要做的事情不少,但整体复杂度在可控范围。把这些细节处理好后,系统既能快速启动,又能在运行时保证实时性和稳定性。
代码里的一些关键片段比如调度器的就绪队列和优先级位图,初次读可能有点晦涩,但逻辑其实不难理解。位图用来快速定位非空的最高优先级队列,找到队列后按顺序取出线程结构体,然后做上下文切换。时间片和定时器结合用来避免某个线程独占 CPU。这样既保证了响应速度,也兼顾了系统公平性。
最后一点是可扩展性。LK 的模块化设计让添加新功能或者移植新硬件都比较直接。你可以把新的驱动放到 platform 目录或者 target 目录,写好 rules.mk,按照现有的初始化级别注册初始化函数,编译系统会把它们打包进镜像。工作流清晰,排查问题也方便。说实话,对于想深入嵌入式系统但又不想被 Linux 全家桶压得喘不过气的人,LK 是个挺合适的入门和进阶选择。
来源:最亮的星ab