X806在鸿蒙OS下的启动过程
-
大家好,全志的老师好,
我最近在持续关注XR806这颗IC,也确实打算用这颗IC做产品,奈何自身才疏学浅,对XR806 鸿蒙OS下的启动过程不甚了解,也理不清头绪,有没有对着代码详细解读XR806在鸿蒙LiteOS下的启动过程的资料或文章呢,,还请各位大师指点迷津!!!!!!
-
@zhugx
相关文章还没找到,但大致流程如下:
1、首先是芯片启动,芯片启动后内部会有一段引导程序,最终引导到main函数,也就是device/xradio/xr806/xr_skylark/project/common/startup/gcc/retarget.c这个文件下的
int __wrap_main(void)->void main_task_start(void)->static void main_task(void *arg)。2、liteOS的启动代码在kernel/liteos_m/kernel/arch/arm/cortex-m33/gcc/los_dispatch.S,是使用汇编写的,大致流程和其他RTOS差不多,先是吧堆栈指针从MSP切换到PSP,然后把空闲任务的地址给到PC,然后跳转PC,就启动了liteos。
3、接下来是Harmony的启动。Harmony的启动是调用void OHOS_SystemInit(void)这个函数,位置是在base/startup/bootstrap_lite/services/source/system_init.c。要详细理解Harmony的启动需要花点时间看看源码。如果熟悉LD脚本的话会比较好理解。篇幅较长,在下个回复中说明。
-
@zhugx
OHOS_SystemInit()的第一行代码是MODULE_INIT(bsp);,bsp在806中没有用到,806_OpenHarmony主要用了MODULE_INIT(run)。
MODULE_INIT(name)是个宏,本体是MODULE_CALL(name, 0);
MODULE_CALL(name, 0)也是一个宏,本体是
#define MODULE_CALL(name, step)
do {
InitCall *initcall = (InitCall *)(MODULE_BEGIN(name, step)); //这是个宏
InitCall *initend = (InitCall *)(MODULE_END(name, step)); //这也是个宏
for (; initcall < initend; initcall++) {
(*initcall)();
}
} while (0)
上面的for循环很好理解,就是从 initcall运行到initend,也就是从MODULE_BEGIN运行到MODULE_END。他们的宏展开后如下:
#define MODULE_BEGIN(name, step)
({ extern InitCall _zinitcall##name##_start;
InitCall *initCall = &_zinitcall##name##_start;
(initCall);
})#define MODULE_END(name, step)
({ extern InitCall _zinitcall##name##_end;
InitCall *initCall = &_zinitcall##name##_end;
(initCall);
})
前面说了这是用run替换掉name,就变成了
InitCall *initCall = &__zinitcall_run_start;
InitCall *initCall = &__zinitcall_run_end;
这两个符号都在ld链接脚本(device/xradio/xr806/xr_skylark/project/linker_script/gcc/appos.ld)中定义好的。 -
@zhugx
接下来的疑问是怎么把代码放在__ zinitcall_run_start和__zinitcall_run_end这两个地址的中间,用到的函数其实就是SYS_RUN(),其实这个也不是函数,只是一个宏。一层层展开如下:
#define SYS_RUN(func) LAYER_INITCALL_DEF(func, run, "run")#define LAYER_INITCALL_DEF(func, layer, clayer)
LAYER_INITCALL(func, layer, clayer, 2)#define LAYER_INITCALL(func, layer, clayer, priority)
static const InitCall USED_ATTR _zinitcall##layer##_##func
attribute((section(".zinitcall." clayer #priority ".init"))) = func其实SYS_RUN()就是把括号内的字符拼接成一个地址,然后存放在zinitcall.run2.init这个位置。
例如SYS_RUN(LEDMain),意思就是设定一个函数地址为__ zinitcall _ run _ LEDMain,然后位段位于zinitcall.run2.init。ld文件里面有一段的代码:
__zinitcall_run_start = .;
KEEP ((.zinitcall.run0.init))
KEEP ((.zinitcall.run1.init))
KEEP ((.zinitcall.run2.init))
KEEP ((.zinitcall.run3.init))
KEEP (*(.zinitcall.run4.init))
__zinitcall_run_end = .;
可以看到Harmony把任务启动的优先级分为5个等级,SYS_RUN默认是等级2,如果任务有启动优先级,那么久可以用SYS_RUN_PRI(func, priority)调整初始化顺序。对于做产品时如果有外设需要初始化的,就可以使用SYS_BSP。通过这种机制,Harmony实现了裁剪功能。
-
@i_a_student 您的答复太专业了,十分感谢您这么专业的答复,向大师致敬!
Copyright © 2024 深圳全志在线有限公司 粤ICP备2021084185号 粤公网安备44030502007680号