1

OpenHarmony南向设备应用程序启动流程分析

 2 years ago
source link: https://www.51cto.com/article/717392.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

OpenHarmony南向设备应用程序启动流程分析

作者:吃吃的等 2022-08-29 17:34:05
本文采用倒序的方式,初步梳理了从Hi3861芯片上电到OpenHarmony应用程序启动运行的流程。
41cd6ff42ed5bd317fd571c41807b6e3caf350.png

​想了解更多关于开源的内容,请访问:​

​51CTO 开源基础软件社区​

​https://ost.51cto.com​

一、用户程序示例

以qihang开发板gpio_led程序为例,为何单板上电后LedTask()会自动运行,SYS_RUN宏在背后是如何起作用的?

static void LedTask(void)
{
    while (1)
    {
        IoTGpioSetOutputVal(LED_TASK_GPIO2,1);
        usleep(500*1000);
        IoTGpioSetOutputVal(LED_TASK_GPIO2,0);
        usleep(500*1000);
    }
}
static void LedExampleEntry(void)
{
    osThreadAttr_t attr;
    IoTGpioInit(LED_TASK_GPIO2);
    IoTGpioSetDir(LED_TASK_GPIO2,IOT_GPIO_DIR_OUT);
    attr.name = "LedTask";
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = LED_TASK_STACK_SIZE;
    attr.priority = LED_TASK_PRIO;
    if (osThreadNew((osThreadFunc_t)LedTask1, NULL, &attr) == NULL) {
        printf("Falied to create LedTask!\n");
    }
}
SYS_RUN(LedExampleEntry);

二、第二阶段(应用)启动流程

在上一篇文章中"OpenHarmony南向设备开发建构编译分析",有提到qihang板产品配置文件中相关子系统及组件如下:

vendor/isoftstone/qihang/config.json。

......
    {
        "subsystem": "distributedschedule",  #分布式任务调度子系统
        "components": [
          { "component": "samgr_lite", "features":[] }
        ]
    },
    {
        "subsystem": "startup",
        "components": [
          { "component": "bootstrap_lite", "features":[] },  #bootstrap启动引导
          { "component": "syspara_lite", "features":  #提供系统属性读写接口
            [
              "enable_ohos_startup_syspara_lite_use_thirdparty_mbedtls = false"
            ]
          }
        ]
    },
......

可以看到,qihang板使用startup子系统中的bootstrap_lite组件和syspara_lite组件。重点看一下bootstrap_lite组件,位于SDK的base/startup/bootstrap_lite目录。引用该组件的readme文件说明如下:

bootstrap启动引导组件,提供了各服务和功能的启动入口标识。在SAMGR启动时,会调用boostrap标识的入口函数,并启动系统服务。

samgr_lite组件是针对Hi3861这类硬件资源有限的轻量化系统服务框架,代码位于foundation/distributedschedule/samgr_lite目录。该组件的功能引用如下:

系统服务框架基于面向服务的架构,提供了服务开发、服务的子功能开发、对外接口的开发、以及多服务共进程的开发框架。

device/soc/hisilicon/hi3861v100/sdk_liteos/app/wifiiot_app/src/app_main.c

hi_void app_main(hi_void)
{
    hi_flash_partition_table *ptable = HI_NULL;
    peripheral_init();
    peripheral_init_no_sleep();
    hi_u32 ret = hi_factory_nv_init(HI_FNV_DEFAULT_ADDR, HI_NV_DEFAULT_TOTAL_SIZE, HI_NV_DEFAULT_BLOCK_SIZE);
    hi_flash_partition_init();
    ptable = hi_get_partition_table();
    hi_nv_init(ptable->table[HI_FLASH_PARTITON_NORMAL_NV].addr, ptable->table[HI_FLASH_PARTITON_NORMAL_NV].size,
        HI_NV_DEFAULT_BLOCK_SIZE);
    hi_fs_init();
    (hi_void)hi_event_init(APP_INIT_EVENT_NUM, HI_NULL);
    hi_sal_init();
    hi_syserr_watchdog_debug(HI_FALSE);
    hi_syserr_record_crash_info(HI_TRUE);
    hi_lpc_init();
    hi_lpc_register_hw_handler(config_before_sleep, config_after_sleep);
    hi_at_init();
    tcpip_init(NULL, NULL);
    hi_wifi_init(APP_INIT_VAP_NUM, APP_INIT_USR_NUM);
    app_demo_task_release_mem(); /* 释放系统栈内存所使用任务 */
    hilink_main();
    OHOS_Main();
}

device/soc/hisilicon/hi3861v100/sdk_liteos/app/wifiiot_app/src/ohos_main.c。

void OHOS_Main()
{
    OHOS_SystemInit();
}

base/startup/bootstrap_lite/services/source/system_init.c。

void OHOS_SystemInit(void)
{
    MODULE_INIT(bsp);
    MODULE_INIT(device);
    MODULE_INIT(core);
    SYS_INIT(service);
    SYS_INIT(feature);
    MODULE_INIT(run);
    SAMGR_Bootstrap();
}
#define SYS_INIT(name)     \
    do {                   \
        SYS_CALL(name, 0); \
    } while (0)
#define SYS_CALL(name, step)                                      \
    do {                                                          \
        InitCall *initcall = (InitCall *)(SYS_BEGIN(name, step)); \
        InitCall *initend = (InitCall *)(SYS_END(name, step));    \
        for (; initcall < initend; initcall++) {                  \
            (*initcall)();                                        \
        }                                                         \
    } while (0)
#define SYS_BEGIN(name, step)                                 \
    ({        extern InitCall __zinitcall_sys_##name##_start;       \
        InitCall *initCall = &__zinitcall_sys_##name##_start; \
        (initCall);                                           \
    })
#define SYS_END(name, step)                                 \
    ({        extern InitCall __zinitcall_sys_##name##_end;       \
        InitCall *initCall = &__zinitcall_sys_##name##_end; \
        (initCall);                                         \
    })
#define MODULE_INIT(name)     \
    do {                      \
        MODULE_CALL(name, 0); \
    } while (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)
#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);                                     \
    })

foundation/distributedschedule/samgr_lite/samgr/source/samgr_lite.c。

void SAMGR_Bootstrap(void)
{
    SamgrLiteImpl *samgr = GetImplement();
    WDT_Reset(WDG_SVC_BOOT_TIME);
    Vector initServices = VECTOR_Make(NULL, NULL);
    MUTEX_Lock(samgr->mutex);
    samgr->status = TO_NEXT_STATUS(samgr->status);
    int16 size = VECTOR_Size(&(samgr->services));
    int16 i;
    for (i = 0; i < size; ++i) {
        ServiceImpl *serviceImpl = (ServiceImpl *)VECTOR_At(&(samgr->services), i);
        VECTOR_Add(&initServices, serviceImpl);
    }
    MUTEX_Unlock(samgr->mutex);
    InitializeAllServices(&initServices);
    VECTOR_Clear(&initServices);
    InitCompleted();
}

在用户应用程序组件的代码中,会包含下述声明:

APP_FEATURE_INIT(MQTTDemo);
SYS_RUN(LedExampleEntry);

上述宏的说明引用如下:

/**
@brief Identifies the entry for initializing and starting an application-layer service by the
priority 2.
This macro is used to identify the entry called at the priority 2 of the application-layer
service phase of the startup process. \n
@param func Indicates the entry function for initializing and starting an application-layer
service. The type is void (*)(void).
*/
#define APP_SERVICE_INIT(func) LAYER_INITCALL_DEF(func, app_service, “app.service”)
/**
@brief Identifies the entry for initializing and starting a system running phase by the
priority 2.
This macro is used to identify the entry called at the priority 2 in the system startup
phase of the startup process. \n
@param func Indicates the entry function for initializing and starting a system running phase.
The type is void (*)(void).
#define SYS_RUN(func) LAYER_INITCALL_DEF(func, run, “run”)
*/

总结以上分析,程序第二阶段启动流程如下图图所示:

OpenHarmony南向设备应用程序启动流程分析-开源基础软件社区

三、第一阶段(上电)启动流程

请参考本文最后延申阅读第二篇文章的具体介绍,程序加载由3个boot程序前后配合完成:

romboot:

  • 芯片内部自带的上电引导程序,引导loaderboot。

loaderboot (device/soc/hisilicon/hi3861v100/sdk_liteos/boot/loaderboot):

  • 与HiBurn通讯,下载镜像到flash。
  • 烧写EFUSE(芯片配置信息)。
  • 校验并引导flashboot。

flashboot (device/soc/hisilicon/hi3861v100/sdk_liteos/boot/flashboot):

  • 升级固件。
  • 校验并引导固件(主程序)。

loaderboot/common/cmd_loop.c 定义了从hiburn接收并处理的操作:

const loader_cmd g_loader_cmdtable[LOADER_CMD_MAX] = {
    { CMD_DL_IMAGE,         loader_download_image },
    { CMD_BURN_EFUSE,       loader_burn_efuse },
    { CMD_UL_DATA,          loader_upload_data },
    { CMD_READ_EFUSE,       loader_read_efuse },
    { CMD_FLASH_PROTECT,    loader_flash_protect },
    { CMD_RESET,            loader_reset },
    { CMD_FACTORY_IMAGE,    loader_download_image },
    { CMD_VERSION,          loader_burn_version},
};

loader_download_image就是接收hiburn传来的升级文件,并烧录到flash中。

flashboot/startup目录下有两个重要文件:

  • riscv_init_flshboot.S 汇编语言格式,RISC-V启动代码。
  • main.c。
#define KERNEL_START_ADDR   0x40D3C0
boot_kernel(KERNEL_START_ADDR);
global_reset();
hi_void boot_kernel(uintptr_t kaddr)
{
    __asm__ __volatile__("ecall");  /* switch U-MODE -> M-MODE */
    hi_void (*entry)(hi_void) = (hi_void*)(kaddr);
    entry();
}

在最后build应用生成的map文件,可看到内存布局如下:

Name             Origin             Length             Attributes
BIN              0x000000000040d3c0 0x0000000000200000 xr
ROM_TEXT         0x00000000003b8000 0x00000000000457e0 xr
ROM_DATA0        0x000000000011d7c0 0x0000000000000020 xrw
ROM_DATA1        0x000000000011d7e0 0x00000000000006e8 xrw
ROM_BSS          0x000000000011a9c0 0x0000000000002e00 xrw
STACK            0x00000000001185c0 0x0000000000002400 rw
CHECK_INFO       0x000000000011dfc0 0x0000000000000040 rw
FLASH            0x000000000040d3c0 0x00000000001f2c40 xrw
PATCH_BSS        0x00000000000d8000 0x0000000000000400 xrw
RAM              0x00000000000d8400 0x00000000000401c0 xrw
EXTERN_ROM_DATA1_BSS 0x000000000011dec8 0x00000000000000f8 xrw
*default*        0x0000000000000000 0xffffffffffffffff

 .entry.text    0x000000000040d3c0        0x4 build/libs/hi3861/release/no_mesh/liblitekernel_flash.a(los_startup.o)
                0x000000000040d3c0                _start
                0x000000000040d3e0                . = ALIGN (0x20)

对比可以看到,KERNEL_START_ADDR与应用程序的起始地址一致,基本可推断flashboot最后操作为调用应用程序。通过ecall指令,实现RISC-V处理器( Hi3861使用 )从User Mode( 禁止不可信代码执行特权指令 )切换为Machine Mode( 最高特权模式 )。

本文采用倒序的方式,初步梳理了从Hi3861芯片上电到OpenHarmony应用程序启动运行的流程。还有很多内容都没有涉及,包括芯片安全启动,Flash的存储分布等,boot部分说明也比较粗浅。

​想了解更多关于开源的内容,请访问:​

​51CTO 开源基础软件社区​

​https://ost.51cto.com​​。

责任编辑:jianghua 来源: 鸿蒙社区

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK