liteos分散加载(十四)

1. 概述

1.1 基本概念

分散加载是一种实现特定代码快速启动的技术,通过优先加载特定代码到内存,达到缩短从系统开机到特定代码执行的时间。可被应用来实现关键业务的快速启动。

嵌入式系统通过uboot加载flash上的镜像文件到内存并执行,而镜像文件本身可能较大,由于flash读取速度的限制,将镜像全部加载完再执行可能无法满足时间敏感的业务对启动速度的要求。

分散加载的思想是先加载部分镜像并执行,这部分镜像包含了时间敏感的关键业务,从而达到快速启动关键业务的效果。

Huawei LiteOS的分散加载

Huawei LiteOS的分散加载分为两个阶段,第一阶段通过uboot将关键业务部分镜像加载到内存并执行,待这部分业务得到执行后,第二阶段在代码中加载剩余部分镜像到内存继续执分散加载的内部原理图如图2所示,图中的运作顺序可参照图1的流程说明。通过合理布局镜像,第一阶段加载部分镜像的速度会比加载完整镜像快,从而缩短系统启动到关键业务运行的时间。

在IPC Huawei LiteOS版本上,通过应用分散加载技术,实现了1s内从开机启动到录制,超越Linux版本的3s-4.5s。

1.2 运作机制

分散加载的主体思想是将部分时间敏感的业务提前加载执行,具体手段是将与这些业务相关的数据、代码段布局到镜像文件的前端,第一阶段只加载前端这段镜像,达到最短时间内即可运行时间敏感业务的开发指导目的。

在这些业务得到执行之后,第一阶段的代码中调用分散加载接口加载剩余部分镜像,接着运行镜像剩余部分的业务。

分散加载的内部原理图如图2所示,图中的运作顺序可参照图1的流程说明。

分散加载在关键业务第一时间被加载执行之后,再加载非关键业务。

2. 开发指导

2.1 使用场景

分散加载技术应用的典型场景是快速启动对时间敏感的业务。

嵌入式系统中可能存在某些业务对启动时间要求比较高,譬如Huawei LiteOS IPC项目上对从开机到录制预览的时间要求较高,可以利用分散加载技术实现录制预览业务的快速启动。

2.2 功能

Huawei LiteOS系统中的分散加载模块为用户提供如下接口。

功能分类 接口名 描述
分散加载接口 LOS_ScatterLoad 在分散加载阶段的最后调用此接口,从镜像加载剩余非紧急业务

2.3 开发流程

分散加载流程图如下所示。

步骤1 调用接口LOS_ScatterLoad,编写分散加载业务代码

业务代码入口为函数app_init,该函数位于os_adapt.c。在紧急业务代码后调用LOS_ScatterLoad函数进行分散加载,并用#ifndef MAKE_SCATTER_IMAGE、 #endif将该函数后的非紧急业务包围起来,用以编译紧急镜像和全部镜像时作区分,示例代码如下:

void app_init() {
    proc_fs_init();
    hi_uartdev_init();
    system_console_init("/dev/uartdev-0");
    LOS_CppSystemInit((unsigned long)&__init_array_start__, (unsigned long)&__init_array_end__,
    BEFORE_SCATTER);
    LOS_ScatterLoad(0x100000, flash_read, NAND_READ_ALIGN_SIZE);
#ifndef MAKE_SCATTER_IMAGE /* 以下为非紧急业务 */
    LOS_CppSystemInit((unsigned long)&__init_array_start__, (unsigned long)&__init_array_end__,
    AFTER_SCATTER);
    extern unsigned int osShellInit(void);
    osShellInit();
    rdk_fs_init();
    SDK_init();
    hi_product_driver_init();
    char *apszArgv[3]={"vs_server","./higv.bin","-i"};
    vs_server(3, apszArgv);
#endif /* MAKE_SCATTER_IMAGE */
}

os_adapt.c位于Huawei_LiteOS代码包的platform/bsp/hi3516a/os_adapt路径下。

步骤2 配置SCATTER_SRC变量

在根目录下Makefile中配置SCATTER_SRC,将变量定义为调用分散加载函数的业务源文件路径,如下所示,其中LITEOSTOPDIR指代Huawei_LiteOS代码根目录。

SCATTER_SRC := $(LITEOSTOPDIR)/platform/bsp/$(LITEOS_PLATFORM)/os_adapt/os_adapt.c

步骤3 执行make scatter,编译紧急部分镜像

在根目录下执行如下命令,则不会编译#ifndef MAKE_SCATTER_IMAGE以下的业务代码。编译系统将自动调用工具链抽取分散加载最小镜像的符号表并根据该符号表提取分散加载最小镜像的.a库列表。

Huawei_LiteOS$ make scatter

步骤4 执行make,编译全部镜像

  • 在根目录下执行如下命令,则编译全部业务代码。
Huawei_LiteOS$ make

编译后,命令行界面会返回紧急镜像大小信息,如下图所示。

  • 编译完成后,检查镜像段的排布,如果镜像中生成了分散加载相关的段则表明分散加载的镜像生成成功。进入系统镜像生成目录(hi3516a平台的镜像生成目录为out/hi3516a,其他类推),可以看到生成的系统镜像vs_server文件,执行命令readelf -S vs_server打开该文件,结果如下图所示。显示了与分散加载相关的段信息(包括段的名称、起始地址及偏移大小)。其中.fast_rodata为分散加载镜像的只读数据段, .fast_text为代码段, .fast_data为数据段

查看分散加载链接脚本.text段,新增了scatter.o(.text),如下图所示,实现了将分散加载的快速启动部分代码相关符号归拢到一个同一个段中。

分散加载链接脚本路径:Huawei_LiteOS/tools/scripts/ld/scatter.ld

步骤5 执行tftp 0x82000000 vs_server.bin;nand erase 0x100000 0x700000;nand write 0x82000000 0x100000 0x700000;,将全部镜像烧写到Flash

进入串口工具界面,输入如下命令,将全部镜像烧写到Flash的0x100000地址位。

tftp 0x82000000 vs_server.bin;nand erase 0x100000 0x700000;nand write 0x82000000 0x100000 0x700000;

其中, vs_server.bin为系统镜像文件名,先将其烧写到内存中一段高地址位0x82000000。然后烧写到Flash,起始地址为0x100000,烧写长度为0x700000,即烧写的镜像文件大小不能超过7M,跟据实际镜像大小调整数值。

步骤6 执行nand read 0x80008000 0x100000 0x4E0000; go 0x80008000;,加载紧急业务

执行如下命令,从Flash的0x100000地址处读取长度为0x4E0000的镜像,加载紧急业务到0x80008000。

nand read 0x80008000 0x100000 0x4E0000; go 0x80008000;

步骤7 系统自动重启

系统自动重启,在0x80008000地址处加载镜像。

3. 注意事项

  • 分散加载第一阶段拷贝过少或者拷贝偏移地址没有根据存储介质的差异进行对齐都会导致系统异常,因此使用时要按照编译最后给出的大小进行uboot加载镜像。
  • 用户需保证提取的库文件列表是支持关键业务运行的超集,否则会导致分散加载第一阶段中的代码访问到第二阶段中的代码或数据,从而导致系统异常。
  • 分散加载使用中可能存在这样一种场景:一个变量在第一阶段中运行后值被修改,但是在第二阶段加载运行之后,该变量值又成为一个未初始化的值。这种场景的原因是该变量在第一阶段中使用到,但是并没有被归拢到第一阶段中,所以在第一阶段修改之后,第二阶段加载进内存后该变量值又被覆盖成未初始化的值。解决的方法是将该变量归拢到第一阶段中,确保第一阶段使用到的数据都在快速启动段中

4. 常见问题汇总

本节介绍使用分散加载技术遇到的主要问题和解决方法。

  • 缺少.O文件
arm-hisiv300-linux-ld: cannot find libscatter.O
make: *** [vs_server] Error 1

这个问题出现的原因是修改了链接脚本后,没有对应生成.O文件,解决的方法是生成对应的.O文件并且放到目标目录下

  • 符号未定义
/usr1/xxxxx/gerrit_code/modify-debug/liteos_ipc/out/lib/libar6003.a(ar6000_drv.o): In
function `ar6000_avail_ev':
/usr1/xxxxx/gerrit_code/modify-debug/liteos_ipc/vendor/ar6k3_wifi/AR6003/host/qca/source/
ar6000_drv.c:1553: undefined reference to `wireless_init_event'
/usr1/xxxxx/gerrit_code/modify-debug/liteos_ipc/out/lib/libar6003.a(drv_config.o): In
function `ar6000_tkip_micerr_event':
/usr1/xxxxx/gerrit_code/modify-debug/liteos_ipc/vendor/ar6k3_wifi/AR6003/host/qca/source/
drv_config.c:1856: undefined reference to `wireless_send_event'
make: *** [vs_server] Error 1

这个问题的出现是比较常见的,可能是裁剪过程中在修改链接脚本的时候,将一些必要的.a文件也删除了,这时需要用grep指令在out/lib目录下搜索未定义的变量,找出都存在于哪些.a文件中,将未添加的.a文件添加到链接脚本中。

  • 分散加载进指令异常。
    通过查看系统异常时pc的位置是否超出分散加载第一阶段的范围,如果是则应该是第一阶段库文件列表涵盖不全,导致有符号未被归拢到第一阶段的代码、数据段中,需要结合系统镜像反汇编文件定位到异常pc所在函数名,找到该函数定义所在的库,将该库添加到库列表中。

原文地址:https://www.cnblogs.com/linhaostudy/p/11030928.html

时间: 2024-11-08 06:46:38

liteos分散加载(十四)的相关文章

高效地加载图片(四) 管理缓存

除了缓存图片意外,还有一些其他的方式来促进GC的效率和图片的复用.不同的Android系统版本有不同的处理策略.BitmapFun中就包含了这个类,能够使我们高效地构建我们的项目. 为了开始以下教程,我们需要先介绍一下Android系统对Bitmap管理的进化史. 在Android2.2(API level 8)以及更低的版本中,当垃圾被回收时,应用的线程会被停止,这会造成一定程度的延时.在Android 2.3中,加入了并发回收机制,这意味着当Bitmap不再被使用的时候,内存会被很快地回收.

ARM分散加载

在ARM开发当中,希望某些代码或者数据,在编译时放置在指定位置. 关键词:scf(scatter file分散加载文件) _attribute_属性  makefile编译 map文件 bin文件 1. 分散加载文件: bin文件的加载方式: code区+RO(read only data)+RW&ZI(已初始化的变量和未初始化的变量) 执行方式: code区+RO区:如果flash片上可执行,则可直接在该nor flash则可直接在该nor flash上直接执行.否则则要拷贝至RAM当中执行.

Keil sct分散加载文件

首先介绍几个概念: 1.ARM映像文件 ARM映像文件是一个层次性结构的文件,其中包含了域(region).输出段(output section)和输入段(input section).各部分关系如下: 一个映像文件由一个或多个域组成 每个域包含一个或多个输出段 每个输出段包含一个或多个输入段 各输入段包含了目标文件中的代码和数据 输入段中包含了4类内容:代码.已经初始化的数据.未经初始化的存储区域.内容初始化成0的存储区域.每个输入段有相应的属性,可以为只读的(RO).可读写的(RW)以及初始

liteos动态加载(十三)

1. 概述 1.1 基本概念 动态加载是一种程序加载技术. 静态链接是在链接阶段将程序各模块文件链接成一个完整的可执行文件,运行时作为整体一次性加载进内存.动态加载允许用户将程序各模块编译成独立的文件而不将它们链接起来,在需要使用到模块时再动态地将其加载到内存中. 静态链接将程序各模块文件链接成一个整体,运行时一次性加载入内存,具有代码装载速度快等优点.但当程序的规模较大,模块的变更升级较为频繁时,会存在内存和磁盘空间浪费.模块更新困难等问题. 动态加载技术可以较好地解决上述静态链接中存在的问题

Storyboard中ViewController加载的四种方式

这个总结来自于<Programming iOS 10>一书: 1.storyboard的初始化ViewController,通过方法instantiateInitialViewController. 2.通过StoryboardID加载,通过方法:instantiateViewController(withIdentifier:). 3.通过关系:比如TabBarVC.NavigationVC这类的导航关系 3.通过segue的触发.

自研模块加载器(四) 模块资源定位-异步加载

资源定位-动态加载 通过resolve方法进行异步解析,完整解析如下图所示: 根据上篇文章startUp.js代码,我们继续完善本章动态加载资源的代码. (function(global) { var startUp = global.startUp = { version: '1.0.1' } var data = {}; // 获取当前模块加载器配置信息 var cache = {}; // 缓存 //模块的生命周期 var status = { FETCHED: 1, SAVED: 2,

关于 ARM Cortex-M3 的启动文件分析及分散加载

原文 https://blog.strongwong.top/posts/%E5%85%B3%E4%BA%8E-ARM-Cortex-M3-%E7%9A%84%E5%90%AF%E5%8A%A8%E6%96%87%E4%BB%B6%E5%88%86%E6%9E%90%E5%8F%8A%E5%88%86%E6%95%A3%E5%8A%A0%E8%BD%BD.html 原文地址:https://www.cnblogs.com/dreamblog/p/11404104.html

如何加快页面加载速度

一.使用良好的结构 二.不要使布局超载 三.不要使用图像来表示文本 四.检查cookie使用情况 五.不要包含不必要的 JavaScript 代码,尽可能将其外部化 六.尽可能避免使用表格 七.删除任何不必要的元素 八.一些优化网页的技巧 九.压缩和缩小 JavaScript 文件 十.使用 HTTP 压缩,并始终使用小写的 div 和类名 十一.设置图像大小 十三.尽可能延迟脚本加载 十四.按需加载 JavaScript 文件 十六.优化 CSS 文件

浅谈android中的异步加载一

1.为什么需要异步加载. 因为我们都知道在Android中的是单线程模型,不允许其他的子线程来更新UI,只允许UI线程(主线程更新UI),否则会多个线程都去更新UI会造成UI的一个混乱有些耗时的操纵(例如网络请求等),如果直接放到主线程中去请求的话则会造成主线程阻塞,而我们系统有规定的响应时间,当响应的时间超过了了阻塞的时间就会造成"Application No Response",也就是我们熟知的ANR错误解决上述问题的时候:我们一般使用的是线程或者线程池+Handler机制如果线程