kernel:litoes_m
MCU:stm32f407zgt6
本文只講解bootstrap組件的移植。bootstrap組件的原理介紹請移步官網(wǎng)文檔.
簡介
bootstrap服務(wù)啟動組件實現(xiàn)了服務(wù)的自動初始化,即服務(wù)的初始化函數(shù)無需顯式調(diào)用,而是將其使用宏定義的方式申明,就會在系統(tǒng)啟動時自動被執(zhí)行。實現(xiàn)原理是將服務(wù)啟動的函數(shù)通過宏定義的方式申明之后,放在預(yù)定義好的zInit代碼段中,系統(tǒng)啟動的時候調(diào)用OHOS_SystemInit接口遍歷該代碼段并調(diào)用其中的函數(shù)。因此,需要在鏈接腳本中添加zInit段,并且在main函數(shù)里調(diào)用OHOS_SystemInit接口。
目錄
base/startup/bootstrap_lite/ # 啟動引導(dǎo)組件
└── services
└── source # 啟動引導(dǎo)組件源文件目錄
約束
目前支持輕量系統(tǒng)設(shè)備(參考內(nèi)存≥128KB),如Hi3861V100。
使用說明
bootstrap組件無需單獨配置,在SAMGR啟動時會自動調(diào)用,用于啟動系統(tǒng)服務(wù)。
移植過程
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中增加的內(nèi)容 - 開始 */
__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中增加的內(nèi)容 - 結(jié)束 */
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的初始化接口函數(shù)base/startup/bootstrap_lite/services/source/system_init.c中的OHOS_SystemInit()中調(diào)用函數(shù)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之后會繼續(xù),會報如下錯誤:
[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之后會繼續(xù),會報如下錯誤:
[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之后會繼續(xù),會報如下錯誤:
[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 = [
"http://utils/native/lite/include"
]
hb build之后會繼續(xù),會報如下錯誤:
[OHOS ERROR] hiview_util.c:(.text.HIVIEW_GetCurrentTime+0x1c): undefined reference to `clock_gettime'
[OHOS ERROR] collect2: error: ld returned 1 exit status
函數(shù)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
可以看出,子系統(tǒng)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代碼段并調(diào)用其中的函數(shù)。
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,定位到出現(xiàn)問題的代碼位置??紤]到cortex-m采用的是三級流水線技術(shù)。實際當(dāng)前運行位置應(yīng)該是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]
異常發(fā)生在一個名為base/hiviewdfx/hilog_lite/frameworks/mini/hiview_log.c中的函數(shù)HiLogRegisterModule。分析問題的過程就不說了。問題出現(xiàn)在結(jié)構(gòu)體HiLogModuleInfo上。代碼中強制1字節(jié)對齊。cortex-m的地址是4字節(jié)的,必須4字節(jié)對齊。
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
根據(jù)PC=0x80156e0,在.asm文件中找到出問題的函數(shù)HiLogPrintf()。找到其中的結(jié)構(gòu)體,查看一下是否又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)導(dǎo)致的。都改完之后,系統(tǒng)可以運行就起作用了。
然后可以調(diào)用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) // 任務(wù)1的入口函數(shù)
{
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的任務(wù)優(yōu)先級設(shè)定,不同于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",
#公共基礎(chǔ)庫
# "-lmodule_ActsUtilsFileTest",
# "-lmodule_ActsKvStoreTest",
#DFX
# "-lmodule_ActsDfxFuncTest",
# "-lmodule_ActsHieventLiteTest",
#啟動恢復(fù)
"-lmodule_ActsBootstrapTest",
# "-lmodule_ActsParameterTest",
#分布式任務(wù)調(diào)度
# "-lmodule_ActsSamgrTest",
"-Wl,--no-whole-archive",
]
}
libs = [
"c",
"m",
"nosys",
]
}
```hb build``之后,下載到板子中運行現(xiàn)實如下信息:
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兼容性測試成功
補充非對齊訪問的問題
根據(jù)STM32 Cortex?-M4 MCUs and MPUs programming manual - Programming manual的說法,cortex-m4支持非對齊訪問。不對齊訪問比對齊訪問要慢,而且有些存儲區(qū)域不支持非對齊訪問。所以arm官方建議對齊訪問。如下圖所示:

為了使用非對齊訪問,需要將寄存器NVIC_CCR中的UNALIGN_TRP位清零。當(dāng)UNALIGN_TRP=0時,非對齊訪問就不會觸發(fā)usage fault。
liteos_m中make menuconfig可以關(guān)閉對齊訪問操作。如下圖所示:

這樣的話就可以在不改源碼的情況下,解決對齊訪問的問題。