Zephyr学习 第四章 -2:初始化 level、priority 与启动顺序
04-2初始化 level、priority 与启动顺序验证方式SYS_INIT()、device init、ELF/map、native_sim/native/64验证结论源码确认 编译确认 模拟确认1. 本节目标上一节确认 device init 会在main()前执行。本节进一步回答Zephyr 有哪些初始化 level同一个 level 内priority 如何决定顺序SYS_INIT()与 device init 是否使用同一套基础设施驱动为什么不能随便选择一个更早的 level本节最终验证的时间线EARLY - PRE_KERNEL_1 - PRE_KERNEL_2 - POST_KERNEL - APPLICATION - main2. Zephyr 的初始化基础设施本地源码zephyr/include/zephyr/init.hZephyr 使用同一套 init entry 基础设施支持SYS_INIT 注册的系统初始化函数 DEVICE_DT_DEFINE 注册的设备初始化函数init entry 的核心结构structinit_entry{unioninit_function init_fn;union{conststructdevice*dev;/* 可选 mutable device */};};其中union init_function能保存两种签名int(*sys)(void);int(*dev)(conststructdevice*dev);所以SYS_INIT callback 没有 device 参数 device init callback 接收对应 struct device *源码确认3. 初始化 level 总览本地init.h按顺序定义level执行阶段主要限制/用途EARLY刚进入 C 环境后的极早期架构、SoC 极早期设置系统服务不可假设可用PRE_KERNEL_1kernel 初始化上下文使用 interrupt stackkernel services 尚不可用PRE_KERNEL_2仍在 pre-kernel 上下文与 PRE_KERNEL_1 相同限制但阶段更晚POST_KERNELkernel 已可用可以使用 kernel primitives常用于普通 device driverAPPLICATIONmain()之前应用/子系统级初始化SMPSMP 专用阶段仅在CONFIG_SMP启用时可用本次native_sim没有验证 SMP 阶段因此实验只覆盖到APPLICATION。4. EARLY 阶段为什么要非常谨慎EARLY发生在系统启动的最前面。通常不应假设下面内容已经可用schedulersemaphore、mutexheaplogging backend普通 device object readyconsole driver 已完成初始化。本实验的 EARLY callback 只做boot_events[boot_event_count]EARLY:50;即只修改已经清零的静态 RAM不调用printk()从而避免依赖早期 console。5. PRE_KERNEL_1 与 PRE_KERNEL_2本地源码说明这两个阶段运行在 kernel initialization context 使用 interrupt stack kernel services 尚不可用因此 pre-kernel init 不适合阻塞等待 semaphore创建依赖 scheduler 的工作睡眠依赖普通 POST_KERNEL device使用尚未初始化的子系统。两个 level 的区别主要是全局顺序所有 PRE_KERNEL_1 都早于 所有 PRE_KERNEL_2即使PRE_KERNEL_1 priority 99 PRE_KERNEL_2 priority 0前者仍先执行因为 level 排序优先于 priority。6. POST_KERNEL本地定义Executed after Kernel is alive. From this point on, Kernel primitives can be used.普通传感器、总线和外设驱动经常使用POST_KERNEL因为初始化中可能需要semaphore、mutex 等内核对象已初始化的父总线 device日志或较完整的系统服务设备依赖检查。本节伪驱动使用DEVICE_DT_INST_DEFINE(...,POST_KERNEL,50,...)7. APPLICATIONAPPLICATIONinit 在应用main()前执行。适合应用级注册订阅系统事件在 main 前完成的子系统设置不属于具体 device object 的初始化逻辑。实验SYS_INIT(trace_application_20,APPLICATION,20);最终记录证明APPLICATION:20 早于 main8. priority 的规则priority 范围0 ... 99同一个 level 内数值越小 - 越早执行 数值越大 - 越晚执行例如POST_KERNEL priority 10 POST_KERNEL priority 50 POST_KERNEL priority 90顺序为10 - 50 - 90注意这与之后学习的 thread priority 不是同一套对象。这里只讨论启动 init entry 的链接排序。9. level 比 priority 更高一级错误理解priority 0 永远比 priority 99 早正确理解先按 level 排序 再在同一个 level 内按 priority 排序例如PRE_KERNEL_2:99 仍早于 POST_KERNEL:0可以把完整排序 key 简化理解为(level ordinal, priority, sub-priority)10. priority 必须是可用于 section 名的值SYS_INIT()文档要求 priority 是无前导零、无符号的十进制整数 literal或展开为这种整数的 symbolic name/Kconfig symbol。可以SYS_INIT(foo,POST_KERNEL,32);#defineMY_INIT_PRIORITY32SYS_INIT(foo,POST_KERNEL,MY_INIT_PRIORITY);不可以SYS_INIT(foo,POST_KERNEL,CONFIG_KERNEL_INIT_PRIORITY_DEFAULT5);原因是 priority 被拼进 linker section 名普通 C 算术表达式无法在这个位置使用。11. SYS_INIT 的基本形式系统初始化函数staticintmy_init(void){return0;}SYS_INIT(my_init,POST_KERNEL,50);SYS_INIT()创建一个静态struct init_entry并把它放入.z_init_LEVELPRIORITY_SUBPRIORITY_形式的 linker section。它不代表创建了struct deviceSYS_INIT 只有 system init entrydev 指针为 NULL DEVICE_DT_DEFINE 同时有 device object、device state 和 device init entry12. 本节 boot trace 设计实验注册EARLY:50 PRE_KERNEL_1:80 先写在源码中 PRE_KERNEL_1:20 后写在源码中 PRE_KERNEL_2:50 POST_KERNEL:90 先写在源码中 POST_KERNEL:10 后写在源码中 POST_KERNEL:device:50 APPLICATION:20 main故意逆序书写 priority 80/20 和 90/10是为了排除“按源码出现顺序执行”的错误理解。每个 callback 只调用boot_trace_record(LEVEL:priority);最后由 main 统一打印数组。13. 实际运行结果[init] devicelearning-device-0 initial42 current_before0 *** Booting Zephyr OS build v4.1.0-rc1 *** boot_trace_count9 boot_trace[0]EARLY:50 boot_trace[1]PRE_KERNEL_1:20 boot_trace[2]PRE_KERNEL_1:80 boot_trace[3]PRE_KERNEL_2:50 boot_trace[4]POST_KERNEL:10 boot_trace[5]POST_KERNEL:device:50 boot_trace[6]POST_KERNEL:90 boot_trace[7]APPLICATION:20 boot_trace[8]main [main] devicelearning-device-0 ready1 init_called1 initial42 current42验证结论level 顺序正确 同 level 内数值较小的 priority 先执行 device init 和 SYS_INIT entry 参与同一 POST_KERNEL 排序 APPLICATION 在 main 前执行模拟确认14. linker map 的直接证据查看rg-n-C2\.z_init_(EARLY|PRE_KERNEL_1|PRE_KERNEL_2|POST_KERNEL|APPLICATION)\/mnt/c/study/1-zephyr/work/ch04_init_order/zephyr/zephyr.map实际 section 顺序.z_init_EARLY50_0_ .z_init_PRE_KERNEL_120_0_ .z_init_PRE_KERNEL_180_0_ .z_init_PRE_KERNEL_199_0_ native console .z_init_PRE_KERNEL_20_0_ native timer .z_init_PRE_KERNEL_250_0_ .z_init_POST_KERNEL10_0_ .z_init_POST_KERNEL50_00012_ learning device .z_init_POST_KERNEL90_0_ .z_init_APPLICATION20_0_这说明 linker 不只排列实验代码也把 Zephyr 自带的 console、timer 和 device init 放进同一全局序列。编译确认15. 为什么源码逆序但执行仍有序init.h中#defineZ_INIT_ENTRY_SECTION(level,prio,sub_prio)\__attribute__((__section__(\.z_init_#levelSTRINGIFY(prio)\_STRINGIFY(sub_prio)_)))链接脚本再使用排序SORT_BY_NAME SORT_BY_ALIGNMENT因此真正决定顺序的是section 名 linker script不是C 文件中的函数位置CMake 中源码列出的顺序object 文件碰巧的顺序。16. sub-priority 是什么普通SYS_INIT()本次生成..._0_learning device 生成.z_init_POST_KERNEL50_00012_其中00012对应当前 node 的 dependency ordinal 相关排序信息。它帮助 Zephyr 在相同 level/priority 下处理设备依赖顺序。本节只观察到它存在设备依赖、required handles 和初始化失败传播将在 04-3 展开。不要在应用代码中手工依赖这个生成数字。17. nm 证据nm-n/mnt/c/study/1-zephyr/work/ch04_init_order/zephyr/zephyr.elf\|rgdevice_dts_ord_12|__init_trace实际地址顺序0x10 __init_trace_early_50 0x20 __init_trace_pre1_20 0x30 __init_trace_pre1_80 0x60 __init_trace_pre2_50 0x70 __init_trace_post_10 0x80 __init___device_dts_ord_12 0x90 __init_trace_post_90 0xa0 __init_trace_application_20与运行时记录一致。编译确认18. device init 可以选哪些 levelDEVICE_DEFINE()/DEVICE_DT_DEFINE()文档面向普通 device 时列出PRE_KERNEL_1 PRE_KERNEL_2 POST_KERNEL选择原则必须在 kernel 前准备的底层设备 - PRE_KERNEL level但必须遵守严格限制 需要 kernel primitives 或常规设备依赖 - POST_KERNEL 纯应用初始化 - 通常使用 SYS_INIT(..., APPLICATION, ...)不要为了“更早”而盲目选择 PRE_KERNEL。过早会让可用 API 更少、依赖关系更难满足。19. 初始化 priority 不是延时priority 10 priority 90不表示相差 80 ms每个 init 有固定时间片priority 10 一定执行得更快调度器 thread priority。它只表示同一 level 中 init entry 的相对排序键。如果 priority 10 的 init 阻塞很久priority 90 仍必须等待它返回。21. 常见错误21.1 认为所有 priority 在全局比较priority 只在相同 level 内比较。21.2 把 init priority 与 thread priority 混淆init priority 是链接排序thread priority 是 scheduler 概念。21.3 PRE_KERNEL 中使用 kernel primitive此时 kernel services 尚不可用。21.4 EARLY 阶段打印大量日志console/logging backend 可能尚未初始化。应使用最小、无依赖的状态记录。21.5 使用 priority 算术表达式section 名生成要求 literal 或可直接展开的 symbolic integer。21.6 用源码书写顺序推断执行顺序应检查 level、priority、生成 section 和最终 map。21.7 随意调整 driver priority 修复依赖如果 Devicetree 已表达设备依赖应优先理解依赖图和自动排序而不是靠不断试 priority 数字。下一节会专门学习。22. 可迁移到其他驱动的结论SYS_INIT 和 device init 使用同一 init entry/linker section 基础设施初始化先按 level、再按 priority、最后按 sub-priority 排序同 level 中数值较小的 priority 先执行PRE_KERNEL 阶段不能假设 kernel services 可用POST_KERNEL 是普通 device driver 的常见选择APPLICATION init 发生在 main 之前最终zephyr.map是确认真实 init 顺序的重要证据。23. 练习与自测请执行rg-n-C2\.z_init_(EARLY|PRE_KERNEL_1|PRE_KERNEL_2|POST_KERNEL|APPLICATION)\/mnt/c/study/1-zephyr/work/ch04_init_order/zephyr/zephyr.map然后回答PRE_KERNEL_2:99与POST_KERNEL:0哪个先执行为什么同为POST_KERNEL时priority 10、50、90 的顺序是什么为什么实验在 EARLY 阶段只记录内存而不直接打印为什么源码中 priority 80 写在 20 前面最终仍是 20 先执行SYS_INIT()与DEVICE_DT_DEFINE()的 init entry 有什么共同点和区别下一节04-3-初始化失败、设备依赖与device_is_ready。

相关新闻

第三篇:《在 Kubernetes 中部署 Istio:安装、配置与 Sidecar 注入》

第三篇:《在 Kubernetes 中部署 Istio:安装、配置与 Sidecar 注入》

理解了 Istio 的架构之后,是时候亲手搭建一个 Istio 环境了。在 Kubernetes 集群中安装 Istio 有多种方式,最常用的是 istioctl 命令行工具和 Helm。本文将详细介绍使用 istioctl 安装 Istio 的完整流程,涵盖环境准备、安装配置文件的选型、命…

2026/11/15 11:04:48 阅读更多 →
AI音乐生成实战:Spark项目本地部署与结构化音乐生成解析

AI音乐生成实战:Spark项目本地部署与结构化音乐生成解析

如果你是一位音乐爱好者、内容创作者,或者正在寻找一种高效、低成本的方式为自己的视频或项目制作高质量背景音乐,那么你很可能已经对“AI音乐生成”这个领域产生了兴趣。但面对市面上众多的AI音乐工具,一个核心的痛点始终存在:生…

2026/11/14 23:29:55 阅读更多 →
黄金价格软件国内外价格实时监控超方便

黄金价格软件国内外价格实时监控超方便

软件介绍 GOLDALL,一款黄金价格实时监控工具。最近黄金价格跌得厉害,今天的价格好像已经到866一克了,真的是跌跌不休。如果你也在关注黄金行情,这款软件值得了解一下。 国内外价格实时显示 软件可以同时显示黄金的国内价格和国…

2026/11/12 6:48:33 阅读更多 →

最新新闻

Electron桌面应用开发实战:从环境搭建到打包发布全流程

Electron桌面应用开发实战:从环境搭建到打包发布全流程

做前端这些年,我大部分时间都在跟浏览器标签页打交道,直到第一次把桌面应用跑起来,才发现原来自己一直被限制在地址栏和刷新按钮围起来的框框里。Electron这个词,最开始是在某段时间频繁出现在同事的讨论里,一个用HTML…

2026/11/15 5:13:35 阅读更多 →
滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

简介:亚太天能T109滑盖智能锁产品说明书是一份PDF格式的官方技术文档,主要面向智能锁安装人员、终端用户及售后维护者,帮助快速掌握产品安装、配置与常见故障处理。全包仅1个PDF文件,大小4.37MB,内容结构清晰&#xff…

2026/11/15 5:13:35 阅读更多 →
PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

上个月我在调试一台高速AGV的驱动系统,整车要求空载跑到8m/s,电机转速已经拉到额定点,驱动器的输出电压也顶到了母线电压极限附近。再往上踩速度指令,转速纹丝不动,三相电流反而开始震荡。那会儿我的第一反应就是&…

2026/11/15 5:13:35 阅读更多 →
C++核心知识点:从内存管理到STL的实战指南

C++核心知识点:从内存管理到STL的实战指南

C 这门语言我前前后后折腾了十几年,用它写过嵌入式驱动、做过游戏服务端,也搭过基础组件库。每次看到新人一头扎进"C 核心知识点"这个搜索词,我其实挺感慨的——这门语言的难点从来不是语法多,而是知识点之间的耦合太深…

2026/11/15 3:37:41 阅读更多 →
T109滑盖智能锁怎么装?安装调试与故障排查全攻略

T109滑盖智能锁怎么装?安装调试与故障排查全攻略

简介:亚太天能T109滑盖智能锁产品说明书以PDF格式发布,适合智能锁用户、安装人员与售后维修人员阅读。内容围绕T109系列指纹密码刷卡锁展开,先介绍前面板、后面板、锁体、机械钥匙、电池盒盖等部件名称与功能,再给出完整安装步骤&…

2026/11/15 4:18:38 阅读更多 →
LLM知识降熵:从信息垄断到理解权下放

LLM知识降熵:从信息垄断到理解权下放

你有没有过这种经历:翻开源码注释、论文摘要或者一份专业报告,每个字都认识,连在一起却像天书。想找人聊聊,身边要么没人懂,要么懂的懒得跟你解释。后来我试着把同一段内容丢给一个大语言模型,几秒钟之后&a…

2026/11/15 5:13:35 阅读更多 →

日新闻

周新闻

月新闻