kernel:litoes_m
MCU:stm32f407zgt6
本文只讲解bootstrap组件的移植。bootstrap组件的原理介绍请移步官网文档.
简介
bootstrap服务启动组件实现了服务的自动初始化,即服务的初始化函数无需显式调用,而是将其使用宏定义的方式申明,就会在系统启动时自动被执行。实现原理是将服务启动的函数通过宏定义的方式申明之后,放在预定义好的zInit代码段中,系统启动的时候调用OHOS_SystemInit接口遍历该代码段并调用其中的函数。因此,需要在链接脚本中添加zInit段,并且在main函数里调用OHOS_SystemInit接口。
目录
base/startup/bootstrap_lite/ # 启动引导组件
└── services
└── source # 启动引导组件源文件目录
约束
目前支持轻量系统设备(参考内存≥128KB),如Hi3861V100。
使用说明
bootstrap组件无需单独配置,在SAMGR启动时会自动调用,用于启动系统服务。
移植过程
1. STM32F407ZGTx_FLASH.ld
在连接脚本中增加zInit代码段
.text :
{
. = ALIGN(4);
*(.text) /* .text sections (code) */
*(.text*) /* .text* sections (code) */
*(.glue_7) /* glue arm to thumb code */
*(.glue_7t) /* glue thumb to arm code */
*(.eh_frame)
/* bootstrap中增加的内容 - 开始 */
__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 = .;
__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 = .;
__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 = .;
__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 = .;
__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 = .;
__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 = .;
__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 = .;
__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 = .;
__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 = .;
__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 = .;
/* bootstrap中增加的内容 - 结束 */
KEEP (*(.init))
KEEP (*(.fini))
. = ALIGN(4);
_etext = .; /* define a global symbols at end of code */
} >FLASH
2. vendor/fx/TunnelControl/config.json下增加组件
//vendor/fx/TunnelControl/config.json
{
"subsystem": "startup",
"components": [
{
"component": "bootstrap_lite"
}
]
},
组件bootstrap的初始化接口函数base/startup/bootstrap_lite/services/source/system_init.c
中的OHOS_SystemInit()
中调用函数SAMGR_Bootstrap()
。
void OHOS_SystemInit(void)
{
MODULE_INIT(bsp);
MODULE_INIT(device);
MODULE_INIT(core);
SYS_INIT(service);
SYS_INIT(feature);
MODULE_INIT(run);
SAMGR_Bootstrap();
}
hb build
之后会继续,会报如下错误:
[OHOS ERROR] system_init.c:(.text.OHOS_SystemInit+0x6e): undefined reference to `SAMGR_Bootstrap'
[OHOS ERROR] collect2: error: ld returned 1 exit status
vendor/fx/tunnel/config.json下需要加入组件samgr_lite
。
{
"subsystem": "distributedschedule",
"components": [
{
"component": "samgr_lite",
"features": []
}
]
},
hb build
之后会继续,会报如下错误:
[OHOS ERROR] samgr_lite.c:(.text.AddTaskPool+0x62): undefined reference to `HiLogPrintf'
vendor/fx/TunnelControl/config.json下需要加入组件hilog_lite
。
{
"subsystem": "hiviewdfx",
"components": [
{
"component": "hilog_lite",
"features": []
}
]
},
hb build
之后会继续,会报如下错误:
[OHOS ERROR] In file included from ../../../base/hiviewdfx/hiview_lite/hiview_file.c:16:
[OHOS ERROR] ../../../base/hiviewdfx/hiview_lite/hiview_config.h:21:10: fatal error: ohos_types.h: No such file or directory
[OHOS ERROR] 21 | #include "ohos_types.h"
找到ohos_types.h
路径,将ohos_types.h
的路径加入device/board/fx/bajie/liteos_m/config.gni
中。如下所示:
//device/board/fx/bajie/liteos_m/config.gni
board_include_dirs = [
"//utils/native/lite/include"
]
hb build
之后会继续,会报如下错误:
[OHOS ERROR] hiview_util.c:(.text.HIVIEW_GetCurrentTime+0x1c): undefined reference to `clock_gettime'
[OHOS ERROR] collect2: error: ld returned 1 exit status
函数clock_gettime
在kernel/liteos_m/kal/posix/src/time.c
中。从posix可以看出,需要使能posix接口。make menuconfig
选择如下:
[*] Enable KAL CMSIS (NEW)
Choose libc implementation (newlibc) --->
[*] Enable POSIX API
[*] Enable POSIX Thread API (NEW)
[*] Enable POSIX Semaphore API (NEW)
[*] Enable POSIX Clock API (NEW)
[*] Enable POSIX Mqueue API (NEW)
[*] Enable POSIX Pipe API (NEW)
[*] Enable POSIX Signal API (NEW)
此时hb build
不报错。
[OHOS INFO] ---------------------------------------------
[OHOS INFO] c targets overlap rate statistics
[OHOS INFO] subsystem files NO. percentage builds NO. percentage overlap rate
[OHOS INFO] distributedschedule 15 6.1% 15 6.1% 1.00
[OHOS INFO] hiviewdfx 10 4.0% 10 4.0% 1.00
[OHOS INFO] kernel 51 20.6% 51 20.6% 1.00
[OHOS INFO] securec 39 15.8% 39 15.8% 1.00
[OHOS INFO] startup 2 0.8% 2 0.8% 1.00
[OHOS INFO] test 2 0.8% 2 0.8% 1.00
[OHOS INFO] third_party 127 51.4% 127 51.4% 1.00
[OHOS INFO] xts 2 0.8% 2 0.8% 1.00
[OHOS INFO]
[OHOS INFO] c overall build overlap rate: 1.00
[OHOS INFO]
[OHOS INFO]
[OHOS INFO] tunnel build success
[OHOS INFO] cost time: 0:00:08
可以看出,子系统startup
、hiviewdfx
和distributedschedule
都被编译成功。
3.编写测试代码
在main.c中编程测试代码,测试startup功能。
//增加一下两个头文件
#include "ohos_init.h"
#include "ohos_types.h"
……
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
HAL_Delay(3000);
usart_printf_init();
PRINT_INFO("SCB->VTOR = 0x%08lX\r\n", SCB->VTOR);
UINT32 ret;
ret = LOS_KernelInit();
OHOS_SystemInit(); // 这句式必须增加的,该接口遍历zInit代码段并调用其中的函数。
if (ret == LOS_OK)
{
LOS_Start();
}
while (1)
{
__asm volatile("wfi");
}
}
运行时报如下错误:
*************Exception Information**************
Type = 11
ThrdPid = 25
Phase = exc in task
FaultAddr = 0xabababab
Current task info:
Task name =
Task ID = 25
Task SP = 00000000
Task ST = 0x0
Task SS = 0x0
Exception reg dump:
PC = 0x80155e2
LR = 0x8015823
SP = 0x2001ffb8
R0 = 0x0
R1 = 0x8023a38
R2 = 0x0
R3 = 0x20011de0
R4 = 0x0
R5 = 0x8023a38
R6 = 0x0
R7 = 0x2001fff0
R8 = 0x0
R9 = 0x0
R10 = 0x0
R11 = 0x0
R12 = 0x0
PriMask = 0x0
xPSR = 0x41000000
----- backtrace start -----
backtrace 0 -- lr = 0x8015822
backtrace 1 -- lr = 0x8013314
backtrace 2 -- lr = 0x8011998
backtrace 3 -- lr = 0x80123b6
----- backtrace end -----
TID Priority Status StackSize WaterLine StackPoint TopOfStack EventMask SemID TaskEntry name
--- -------- -------- --------- --------- ---------- ---------- --------- ------ ---------- ----
0 0 Ready 0x2d0 0xcc 0x20004614 0x20004410 0 0xffff 0x800ea41 Swt_Task
1 31 Ready 0x500 0xcc 0x20004b24 0x200046f0 0 0xffff 0x800ef15 IdleCore000
从图中可以看出PC= 0x80155e2
。在.asm文件中查到搜索80155e2,定位到出现问题的代码位置。考虑到cortex-m采用的是三级流水线技术。实际当前运行位置应该是80155e8。
080155c8 <HiLogRegisterModule>:
80155c8: b570 push {r4, r5, r6, lr}
80155ca: b082 sub sp, #8
80155cc: 4604 mov r4, r0
80155ce: 460d mov r5, r1
80155d0: 4b2b ldr r3, [pc, #172] ; (8015680 <HiLogRegisterModule+0xb8>)
80155d2: 681b ldr r3, [r3, #0]
80155d4: 9301 str r3, [sp, #4]
80155d6: f04f 0300 mov.w r3, #0
80155da: eb00 0280 add.w r2, r0, r0, lsl #2
80155de: 4b29 ldr r3, [pc, #164] ; (8015684 <HiLogRegisterModule+0xbc>)
80155e0: 4413 add r3, r2
80155e2: f8d3 2001 ldr.w r2, [r3, #1]
80155e6: 4601 mov r1, r0
80155e8: 4827 ldr r0, [pc, #156] ; (8015688 <HiLogRegisterModule+0xc0>)
80155ea: f7fc f8d7 bl 801179c <__wrap_printf>
80155ee: 2c3f cmp r4, #63 ; 0x3f
80155f0: d840 bhi.n 8015674 <HiLogRegisterModule+0xac>
80155f2: 2d00 cmp r5, #0
80155f4: d040 beq.n 8015678 <HiLogRegisterModule+0xb0>
80155f6: eb04 0284 add.w r2, r4, r4, lsl #2
80155fa: 4b22 ldr r3, [pc, #136] ; (8015684 <HiLogRegisterModule+0xbc>)
80155fc: 4413 add r3, r2
80155fe: f8d3 3001 ldr.w r3, [r3, #1]
8015602: b14b cbz r3, 8015618 <HiLogRegisterModule+0x50>
8015604: 2000 movs r0, #0
8015606: 4b1e ldr r3, [pc, #120] ; (8015680 <HiLogRegisterModule+0xb8>)
8015608: 681a ldr r2, [r3, #0]
801560a: 9b01 ldr r3, [sp, #4]
异常发生在一个名为base/hiviewdfx/hilog_lite/frameworks/mini/hiview_log.c
中的函数HiLogRegisterModule
。分析问题的过程就不说了。问题出现在结构体HiLogModuleInfo上。代码中强制1字节对齐。cortex-m的地址是4字节的,必须4字节对齐。
base/hiviewdfx/hiview_lite/hiview_def.h
#pragma pack(1) 此处的pack(1)->pack(4)
typedef struct {
uint8 id;
const char *name; /* LOG_MODULE_NAME_LEN */
} HiLogModuleInfo;
#pragma pack()
hb build
之后,下载运行后,报如下错误:
*************Exception Information**************
Type = 11
ThrdPid = 25
Phase = exc in task
FaultAddr = 0xabababab
Current task info:
Task name =
Task ID = 25
Task SP = 00000000
Task ST = 0x0
Task SS = 0x0
Exception reg dump:
PC = 0x80156e0
LR = 0x80156dd
SP = 0x2001ff88
R0 = 0x1
R1 = 0x1
R2 = 0x20000534
R3 = 0x0
R4 = 0x1
R5 = 0x0
R6 = 0x1
R7 = 0x80239b8
R8 = 0x0
R9 = 0x0
R10 = 0x0
R11 = 0x0
R12 = 0x6
PriMask = 0x0
xPSR = 0x41000000
----- backtrace start -----
backtrace 0 -- lr = 0x80158a2
backtrace 1 -- lr = 0x8013314
backtrace 2 -- lr = 0x8011998
backtrace 3 -- lr = 0x80123b6
----- backtrace end -----
TID Priority Status StackSize WaterLine StackPoint TopOfStack EventMask SemID TaskEntry name
--- -------- -------- --------- --------- ---------- ---------- --------- ------ ---------- ----
0 0 Ready 0x2d0 0xcc 0x20004614 0x20004410 0 0xffff 0x800ea41 Swt_Task
1 31 Ready 0x500 0xcc 0x20004b24 0x200046f0 0 0xffff 0x800ef15 IdleCore000
根据PC=0x80156e0,在.asm文件中找到出问题的函数HiLogPrintf()
。找到其中的结构体,查看一下是否又pack(1)了。
base/hiviewdfx/hilog_lite/interfaces/native/kits/hilog_lite/hiview_log.h
#pragma pack(1) 改成 pack(4)
typedef struct {
uint8 head;
uint8 module;
uint8 level : 4;
uint8 valueNumber : 4;
uint8 task;
uint32 time; /* seconds */
uint16 milli; /* millisecond, 0-999 */
const char *fmt;
} HiLogCommon;
typedef struct {
HiLogCommon commonContent;
uint32 values[LOG_MULTI_PARA_MAX];
} HiLogContent;
#pragma pack()
之后遇到的几个问题都是用于pack(1)导致的。都改完之后,系统可以运行就起作用了。
然后可以调用utils/native/lite/include/ohos_init.h
提供的api了。
#define CORE_INIT(func) LAYER_INITCALL_DEF(func, core, "core")
#define CORE_INIT_PRI(func, priority) LAYER_INITCALL(func, core, "core", priority)
#define SYS_SERVICE_INIT(func) LAYER_INITCALL_DEF(func, sys_service, "sys.service")
#define SYS_SERVICE_INIT_PRI(func, priority) LAYER_INITCALL(func, sys_service, "sys.service", priority)
#define SYS_FEATURE_INIT(func) LAYER_INITCALL_DEF(func, sys_feature, "sys.feature")
#define SYS_FEATURE_INIT_PRI(func, priority) LAYER_INITCALL(func, sys_feature, "sys.feature", priority)
#define SYS_RUN(func) LAYER_INITCALL_DEF(func, run, "run")
#define SYS_RUN_PRI(func, priority) LAYER_INITCALL(func, run, "run", priority)
#define SYSEX_SERVICE_INIT(func) LAYER_INITCALL_DEF(func, app_service, "app.service")
#define SYSEX_SERVICE_INIT_PRI(func, priority) LAYER_INITCALL(func, app_service, "app.service", priority)
#define SYSEX_FEATURE_INIT(func) LAYER_INITCALL_DEF(func, app_feature, "app.feature")
#define SYSEX_FEATURE_INIT_PRI(func, priority) LAYER_INITCALL(func, app_feature, "app.feature", priority)
#define APP_SERVICE_INIT(func) LAYER_INITCALL_DEF(func, app_service, "app.service")
#define APP_SERVICE_INIT_PRI(func, priority) LAYER_INITCALL(func, app_service, "app.service", priority)
#define APP_FEATURE_INIT(func) LAYER_INITCALL_DEF(func, app_feature, "app.feature")
#define APP_FEATURE_INIT_PRI(func, priority) LAYER_INITCALL(func, app_feature, "app.feature", priority)
编写测试demo。
VOID TaskSampleEntry1(VOID) // 任务1的入口函数
{
while(1) {
LOS_TaskDelay(LOS_MS2Tick(2000));
HAL_GPIO_TogglePin(GPIOE, GPIO_PIN_2);
HILOG_INFO(HILOG_MODULE_MAIN, "This is an electric light program.");
// PRINTK("This is an electric light program.\r\n");
}
}
UINT32 TaskSample(VOID)
{
UINT32 uwRet;
UINT32 taskID1,taskID2;
TSK_INIT_PARAM_S stTask1={0};
stTask1.pfnTaskEntry = (TSK_ENTRY_FUNC)TaskSampleEntry1;
stTask1.uwStackSize = 0X1000;
stTask1.pcName = "taskSampleEntry1";
stTask1.usTaskPrio = 6; //stTask1的任务优先级设定,不同于stTask2
uwRet = LOS_TaskCreate(&taskID1, &stTask1);
if(uwRet != LOS_OK)
{
PRINT_ERR("start_task init error.\r\n");
}
return LOS_OK;
}
SYS_RUN(TaskSample);
hb build
之后,重新下载运行。电灯成功。说明SYS_RUN()
运行有效。
bootstrap加入acts兼容性测试
在device/board/fx/tunnel_box/liteos_m/boot/BUILD.gn
中
config("public") {
include_dirs = [
"include",
]
ldflags = [
"-Wl,-T" + rebase_path("STM32F407ZGTx_FLASH.ld"),
"-Wl,-u_printf_float",
]
if (build_xts) {
lib_dirs = [ "$root_out_dir/libs" ]
ldflags += [
"-Wl,--whole-archive",
"-lbootstrap",
"-lbroadcast",
"-lhctest",
#公共基础库
# "-lmodule_ActsUtilsFileTest",
# "-lmodule_ActsKvStoreTest",
#DFX
# "-lmodule_ActsDfxFuncTest",
# "-lmodule_ActsHieventLiteTest",
#启动恢复
"-lmodule_ActsBootstrapTest",
# "-lmodule_ActsParameterTest",
#分布式任务调度
# "-lmodule_ActsSamgrTest",
"-Wl,--no-whole-archive",
]
}
libs = [
"c",
"m",
"nosys",
]
}
```hb build``之后,下载到板子中运行现实如下信息:
Run test suite 1 times
[TestStartBootstrapSamgr001:0]../../../test/xts/acts/startup_lite/bootstrap_hal/src/samgr_api_test.c:342:TestStartBootstrapSamgr001:PASS
g_coreInit0: 01: 0default: 03: 04: 05: 0../../../test/xts/acts/startup_lite/bootstrap_hal/src/samgr_api_test.c:353:TestStartBootstrapSamgr002:PASS
g_sysServiceInit0: 01: 0default: 03: 04: 05: 0../../../test/xts/acts/startup_lite/bootstrap_hal/src/samgr_api_test.c:365:TestStartBootstrapSamgr003:PASS
g_sysFeatureInit0: 01: 0default: 03: 04: 05: 0../../../test/xts/acts/startup_lite/bootstrap_hal/src/samgr_api_test.c:377:TestStartBootstrapSamgr004:PASS
g_sysExServiceInit0: 01: 0default: 03: 04: 05: 0g_appServiceInit0: 01: 0default: 03: 04: 05: 0../../../test/xts/acts/startup_lite/bootstrap_hal/src/samgr_api_test.c:389:TestStartBootstrapSamgr005:PASS
g_sysExFeatureInit0: 01: 0default: 03: 04: 05: 0g_appFeatureInit0: 01: 0default: 03: 04: 05: 0../../../test/xts/acts/startup_lite/bootstrap_hal/src/samgr_api_test.c:403:TestStartBootstrapSamgr006:PASS
g_sysRun0: 01: 0default: 03: 04: 05: 0../../../test/xts/acts/startup_lite/bootstrap_hal/src/samgr_api_test.c:417:TestStartBootstrapSamgr007:PASS
+-------------------------------------------+
-----------------------
7 Tests 0 Failures 0 Ignored
OK
All the test suites finished!
bootstrap加入acts兼容性测试成功
补充非对齐访问的问题
根据STM32 Cortex®-M4 MCUs and MPUs programming manual - Programming manual的说法,cortex-m4支持非对齐访问。不对齐访问比对齐访问要慢,而且有些存储区域不支持非对齐访问。所以arm官方建议对齐访问。如下图所示:
为了使用非对齐访问,需要将寄存器NVIC_CCR中的UNALIGN_TRP位清零。当UNALIGN_TRP=0时,非对齐访问就不会触发usage fault。
liteos_m中make menuconfig可以关闭对齐访问操作。如下图所示:
这样的话就可以在不改源码的情况下,解决对齐访问的问题。