OpenHarmony移植案例与原理 - startup子系统之bootstrap_lite服务启动引导部件(1)

网友投稿 741 2022-05-30

bootstrap_lite服务启动引导组件提供了各服务和功能的启动入口标识。在SAMGR(System ability manager,系统服务管理)启动时,会调用bootstrap_lite标识的入口函数,并启动系统服务。本文介绍下移植开发板时如何适配服务启动引导部件bootstrap_lite,并介绍下相关的运行机制原理。bootstrap_lite启动引导部件定义在build\lite\components\startup.json。bootstrap_lite启动引导部件源代码目录如下:

base/startup/bootstrap_lite/ # 启动引导组件 └── services └── source # 启动引导组件源文件目录

1、bootstrap_lite服务启动引导部件适配示例

1.1 产品解决方案配置启用部件

移植开发板适配startup子系统之bootstrap_lite服务启动引导部件时,需要在产品解决方案的config.json增加下述配置项,可以参考vendor\bestechnic\display_demo\config.json中的配置示例:

{ "subsystem": "startup", "components": [ { "component": "bootstrap_lite" }, ...... ] },

1.2 使用bootstrap服务启动部件提供的初始化宏函数

OpenHarmony移植案例与原理 - startup子系统之bootstrap_lite服务启动引导部件(1)

然后就可以使用bootstrap服务启动部件提供的初始化宏函数SYS_SERVICE_INIT、APP_SERVICE_INIT等来自动初始化服务,示例代码可以参考device\board\fnlink\v200zr\liteos_m\at\at_wifi.c中的用法,片段如下,可以看到调用了宏函数来初始化RegisterCustomATCmd函数实现的服务。device\board\bearpi\bearpi_hm_nano\app\目录下有更多的使用示例。下文分析实现机制原理。

static void RegisterCustomATCmd() { cmd_tbl_t cmd_list[] = { {"AT+IFCFG", 8, at_lwip_ifconfig, "AT+IFCFG - ifconfig\n"}, {"AT+STARTAP", 7, at_start_softap, "AT+STARTAP - start wifi softap\n"}, {"AT+STOPAP", 1, at_stop_softap, "AT+STOPAP - stop wifi softap\n"}, {"AT+STARTSTA", 1, at_start_wifista, "AT+STARTSTA - start wifi sta\n"}, {"AT+STOPSTA", 1, at_stop_wifista, "AT+STOPSTA - stop wifi sta\n"}, {"AT+DHCP", 3, at_setup_dhcp, "AT+DHCP - dhcp\n"}, {"AT+DHCPS", 3, at_setup_dhcps, "AT+DHCPS - dhcps\n"}, }; for (int i = 0; i < sizeof(cmd_list) / sizeof(cmd_tbl_t); i++) { console_cmd_add(&cmd_list[i]); } } SYS_SERVICE_INIT(RegisterCustomATCmd);

1.3 链接脚本中增加zInit代码段

适配bootstrap_lite部件时,还需要在链接脚本文件中手动新增如下段,链接脚本示例可以参考//device/soc/bestechnic/bes2600/liteos_m/sdk/bsp/out/best2600w_liteos/_best2001.lds,还可以参考device\soc\hisilicon\hi3861v100\sdk_liteos\build\link\link.ld.S。从链接脚本片段中可以看出,有.zinitcall.bsp、.zinitcall.device、.zinitcall.core、.zinitcall.sys.service、.zinitcall.sys.feature、.zinitcall.run、.zinitcall.app.service、.zinitcall.app.feature、.zinitcall.test和.zinitcall.exit等几种类型的段。

/* zInit code and data - will be freed after init */ .zInit (.) : { __zinitcall_bsp_start = .; KEEP (*(.zinitcall.bsp0.init)) KEEP (*(.zinitcall.bsp1.init)) KEEP (*(.zinitcall.bsp2.init)) KEEP (*(.zinitcall.bsp3.init)) KEEP (*(.zinitcall.bsp4.init)) __zinitcall_bsp_end = .; . = ALIGN(4); __zinitcall_device_start = .; KEEP (*(.zinitcall.device0.init)) KEEP (*(.zinitcall.device1.init)) KEEP (*(.zinitcall.device2.init)) KEEP (*(.zinitcall.device3.init)) KEEP (*(.zinitcall.device4.init)) __zinitcall_device_end = .; . = ALIGN(4); __zinitcall_core_start = .; KEEP (*(.zinitcall.core0.init)) KEEP (*(.zinitcall.core1.init)) KEEP (*(.zinitcall.core2.init)) KEEP (*(.zinitcall.core3.init)) KEEP (*(.zinitcall.core4.init)) __zinitcall_core_end = .; . = ALIGN(4); __zinitcall_sys_service_start = .; KEEP (*(.zinitcall.sys.service0.init)) KEEP (*(.zinitcall.sys.service1.init)) KEEP (*(.zinitcall.sys.service2.init)) KEEP (*(.zinitcall.sys.service3.init)) KEEP (*(.zinitcall.sys.service4.init)) __zinitcall_sys_service_end = .; . = ALIGN(4); __zinitcall_sys_feature_start = .; KEEP (*(.zinitcall.sys.feature0.init)) KEEP (*(.zinitcall.sys.feature1.init)) KEEP (*(.zinitcall.sys.feature2.init)) KEEP (*(.zinitcall.sys.feature3.init)) KEEP (*(.zinitcall.sys.feature4.init)) __zinitcall_sys_feature_end = .; . = ALIGN(4); __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 = .; . = ALIGN(4); __zinitcall_app_service_start = .; KEEP (*(.zinitcall.app.service0.init)) KEEP (*(.zinitcall.app.service1.init)) KEEP (*(.zinitcall.app.service2.init)) KEEP (*(.zinitcall.app.service3.init)) KEEP (*(.zinitcall.app.service4.init)) __zinitcall_app_service_end = .; . = ALIGN(4); __zinitcall_app_feature_start = .; KEEP (*(.zinitcall.app.feature0.init)) KEEP (*(.zinitcall.app.feature1.init)) KEEP (*(.zinitcall.app.feature2.init)) KEEP (*(.zinitcall.app.feature3.init)) KEEP (*(.zinitcall.app.feature4.init)) __zinitcall_app_feature_end = .; . = ALIGN(4); __zinitcall_test_start = .; KEEP (*(.zinitcall.test0.init)) KEEP (*(.zinitcall.test1.init)) KEEP (*(.zinitcall.test2.init)) KEEP (*(.zinitcall.test3.init)) KEEP (*(.zinitcall.test4.init)) __zinitcall_test_end = .; . = ALIGN(4); __zinitcall_exit_start = .; KEEP (*(.zinitcall.exit0.init)) KEEP (*(.zinitcall.exit1.init)) KEEP (*(.zinitcall.exit2.init)) KEEP (*(.zinitcall.exit3.init)) KEEP (*(.zinitcall.exit4.init)) __zinitcall_exit_end = .; . = ALIGN(4); } > FLASH

1.4 配置编译时链接bootstrap库

另外,bootstrap_lite部件会编译//base/startup/bootstrap_lite/services/source/bootstrap_service.c,该文件中,通过SYS_SERVICE_INIT将Init函数符号指定到__zinitcall_sys_service_start和__zinitcall_sys_service_end段中,由于没有显式调用Init函数,所以需要将它强制链接到最终的镜像。可以参考device\board\goodix\gr5515_sk\liteos_m\config.gni文件中的链接选项。恒玄的开发板适配时,是配置到vendor\bestechnic\display_demo\config.json文件中的自己定义的配置项force_link_libs里,该配置项在device\soc\bestechnic\bes2600\BUILD.gn中被解析、链接。

board_ld_flags = [ .... "-lbootstrap",

1.5 调用OHOS_SystemInit接口

函数void OHOS_SystemInit(void)定义在文件base\startup\bootstrap_lite\services\source\system_init.c中,在移植适配时,需要调用该接口。可以参考文件device\soc\bestechnic\bes2600\liteos_m\sdk\bsp\rtos\liteos\liteos_m\board.c中的使用示例。

int main(void); extern void OHOS_SystemInit(void); ...... OHOS_SystemInit(); ...... while (1) { osDelay(1000); TRACE(0, "main idle"); } }

2、bootstrap_lite服务启动引导部件实现原理之system_init

bootstrap_lite服务启动部件实现了服务的自动初始化,即服务的初始化函数无需显式调用,它是使用宏定义的方式申明,在系统启动时自动被执行。实现原理是将服务启动的函数通过宏申明之后,放在预定义好的zInit代码段中,系统启动的时候调用OHOS_SystemInit接口,遍历该代码段并调用其中的函数。因此在适配移植时,需要在device/soc/下面具体的芯片的链接脚本中添加zInit段,并且在main函数里调用OHOS_SystemInit接口。

2.1 bootstrap_lite服务启动引导部件的初始化宏

bootstrap_lite服务启动引导部件的初始化宏定义在文件utils\native\lite\include\ohos_init.h,片段如下。初始化函数宏SYS_SERVICE_INIT(func)用于标识核心系统服务的初始化入口,该宏识别的函数在启动过程中核心系统服务优先级2阶段被调用;初始化宏SYS_SERVICE_INIT_PRI(func, priority)可以指定优先级数值,优先级的取值范围为[0,5),调用顺序为0, 1, 2, 3, 4。

/** * @brief Identifies the entry for initializing and starting a core system service by the * priority 2. * * This macro is used to identify the entry called at the priority 2 in the core system * service phase of the startup process. \n * * @param func Indicates the entry function for initializing and starting a core system service. * The type is void (*)(void). */ #define SYS_SERVICE_INIT(func) LAYER_INITCALL_DEF(func, sys_service, "sys.service") /** * @brief Identifies the entry for initializing and starting a core system service by the * specified priority. * * This macro is used to identify the entry called at the specified priority in the core system * service phase of the startup process. \n * * @param func Indicates the entry function for initializing and starting a core system service. * The type is void (*)(void). * @param priority Indicates the calling priority when starting the core system service in the * startup phase. The value range is [0,5), and the calling sequence is 0, 1, 2, 3, and 4. */ #define SYS_SERVICE_INIT_PRI(func, priority) LAYER_INITCALL(func, sys_service, "sys.service", priority)

更多的初始化宏见下文的列表,处理这些初始化宏,还有可以指定优先级的版本XXX_PRI。

2.2 LAYER_INITCALL宏定义

从上文已知,bootstrap_lite服务启动引导部件的初始化宏会调用LAYER_INITCALL_DEF和LAYER_INITCALL宏。这些宏的定义在文件utils\native\lite\include\ohos_init.h,代码片段如下。⑴处声明函数类型,无参无返回值。⑵处处理定义分层初始化共享库宏LAYER_INIT_SHARED_LIB的情况,如果没有定义该宏,则执行⑹。在文件foundation/distributedschedule/samgr_lite/samgr/BUILD.gn中定义了该宏,在移植适配芯片开发板时,没有定义这个宏。⑶处定义5个分层初始化级别,⑷处定义7个构建值(constructor value,简称CTOR Value)。⑸处是宏LAYER_INITCALL的定义,该宏需要4个参数,分别是初始化服务或功能函数func;layer是分层名称,支持的取值为device、core、sys_service、sys_feature、app_service、app_feature和run,拼装为CTOR_VALUE_XXX;clayer参数在定义宏LAYER_INIT_SHARED_LIB时未使用;priority是优先级参数。attribute((constructor))表示这段代码将在main函数前调用。当传入参数为(myFunc, sys_feature, “sys.feature”, 2)时,函数宏替换为:static __attribute__((constructor(130 + 2))) void BOOT_sys_featurer2myFunc {myFunc();}。等于定义个一个新的启动引导函数BOOT_sys_featurer2myFunc()。

当没有定义LAYER_INIT_SHARED_LIB宏时,执行⑹,当传入参数为(myFunc, sys_feature, “sys.feature”, 2)时,函数宏替换为:static const InitCall __attribute__((used)) __zinitcall_sys_feature_myFunc __attribute__((section(".zinitcall.sys.feature2.init"))) = myFunc,除了__attribute__部分,等于声明一个函数类型InitCall的变量__zinitcall_sys_feature_myFunc。该函数变量放入section段".zinitcall.sys.feature2.init"内,所以移植适配时,需要在芯片开发板的链接脚本里添加zInit代码段。

⑴ typedef void (*InitCall)(void); #define USED_ATTR __attribute__((used)) ⑵ #ifdef LAYER_INIT_SHARED_LIB ⑶ #define LAYER_INIT_LEVEL_0 0 #define LAYER_INIT_LEVEL_1 1 #define LAYER_INIT_LEVEL_2 2 #define LAYER_INIT_LEVEL_3 3 #define LAYER_INIT_LEVEL_4 4 ⑷ #define CTOR_VALUE_device 100 #define CTOR_VALUE_core 110 #define CTOR_VALUE_sys_service 120 #define CTOR_VALUE_sys_feature 130 #define CTOR_VALUE_app_service 140 #define CTOR_VALUE_app_feature 150 #define CTOR_VALUE_run 700 ⑸ #define LAYER_INITCALL(func, layer, clayer, priority) \ static __attribute__((constructor(CTOR_VALUE_##layer + LAYER_INIT_LEVEL_##priority))) \ void BOOT_##layer##priority##func() {func();} #else ⑹ #define LAYER_INITCALL(func, layer, clayer, priority) \ static const InitCall USED_ATTR __zinitcall_##layer##_##func \ __attribute__((section(".zinitcall." clayer #priority ".init"))) = func #endif // Default priority is 2, priority range is [0, 4] #define LAYER_INITCALL_DEF(func, layer, clayer) \ LAYER_INITCALL(func, layer, clayer, 2)

Bootstrap IoT 轻量级操作系统 LiteOS

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:【转载】基于MindSpore的Deeplabv3—语义分割体验分享
下一篇:excel表格设置数字0不显示的方法
相关文章