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所在函数名,找到该函数定义所在的库,将该库添加到库列表中。
liteos分散加载(十四)的更多相关文章
- liteos动态加载(十三)
1. 概述 1.1 基本概念 动态加载是一种程序加载技术. 静态链接是在链接阶段将程序各模块文件链接成一个完整的可执行文件,运行时作为整体一次性加载进内存.动态加载允许用户将程序各模块编译成独立的文件 ...
- XAML加载的四种方式
XAML加载与编译可以分为四种: 仅使用代码进行WPF程序的生成 使用代码和未编译的标记 使用代码和编译过的BAML 1.只是用代码进行窗体的生成:优点是可以随意定制应用程序,缺点是没有可视化编辑窗口 ...
- ExtJs基础知识总结:自定义弹窗和ComboBox自动联想加载(四)
概述 Extjs弹窗可以分为消息弹窗.对话框,这些弹窗的方式ExtJs自带的Ext.Msg.alert就已经可以满足简单消息提示,但是相对复杂的提示,比如如何将Ext.grid.Panel的控件显示嵌 ...
- 深入java虚拟机学习 -- 类的加载机制(四)
类加载的命名空间 每个类加载器都有自己的命名空间,命名空间由所有以此加载器为初始类加载器的类组成,不同命名空间的两个类是不可见的,但只要得到类所对应的Class对象的refrence(反射),还是可以 ...
- Storyboard中ViewController加载的四种方式
这个总结来自于<Programming iOS 10>一书: 1.storyboard的初始化ViewController,通过方法instantiateInitialViewContro ...
- mybatis源码解析之Configuration加载(四)
概述 上一篇文章,我们主要讲了datasource的相关内容,那么<environments>标签下的内容就看的差不多了,今天就来看一下在拿到transationManager和datas ...
- 基于FBX SDK的FBX模型解析与加载 -(四)
8. 骨骼蒙皮动画 骨骼蒙皮动画是当前游戏引擎中最常用的一种动画方式,关于其基本原理网络上的资料较多,关于到涉及的其它较复杂操作,如插值.融合等在这里也就先不再讨论了,而且其实现方式也与具体引擎的动作 ...
- ERP存储过程的调用和树形菜单的加载(四)
引用:DAL:System.Data.SqlClient;System.Data; namespace CommTool { public class SqlComm { /// <summar ...
- Keil sct分散加载文件
官方说明:http://www.keil.com/support/man/docs/armlink/armlink_pge1401393372646.htm
随机推荐
- vue非父子关系之间通信传值
第一种方法: 通过给vue实例添加自定义属性 <!DOCTYPE html> <html> <head> <meta charset="utf-8& ...
- R语言入门1:安装R和RStudio
R语言入门1:安装R和RStudio 曹务强 中科院遗传学博士研究生 9 人赞同了该文章 1. Windows安装R 在Windows系统上,安装R语言比较简单,直接从R的官方网站下载,按照正常的软件 ...
- [20191115]oracle实例占用内存计算.txt
[20191115]oracle实例占用内存计算.txt --//以前学习oracle数据库时,总想了解实例占用内存多少,我曾经在一些会议底下问过一位高手,对方说计算这个相对很难,许多东西是共享的.- ...
- CodeForces - 1238D(思维)
题意 https://vjudge.net/problem/CodeForces-1238D 如果一个字符串的每个字母,属于至少一个(长度大于1)的回文串,则称这个字符串为good. 一个长度为n的字 ...
- TensorFlow从1到2(十二)生成对抗网络GAN和图片自动生成
生成对抗网络的概念 上一篇中介绍的VAE自动编码器具备了一定程度的创造特征,能够"无中生有"的由一组随机数向量生成手写字符的图片. 这个"创造能力"我们在模型中 ...
- C++ 数据类型判断 typeid
#include <iostream> // typeid testing //////////////////////////////////////////////////////// ...
- 将静态页面部署到github.io
背景: 我的腾讯云服务器是之前利用学生身份(有优惠)买的,现在快到期了,而且服务器上面只有一个引导页(静态页面)还有用,别的项目都没有用了.所以就想找一种不花钱买服务器就可以访问到我的引导页的方法 ...
- 【51nod1253】Kundu and Tree(容斥+并查集)
点此看题面 大致题意: 给你一棵树,每条边为黑色或红色, 求有多少个三元组\((x,y,z)\),使得路径\((x,y),(x,z),(y,z)\)上都存在至少一条红色边. 容斥 我们可以借助容斥思想 ...
- ubuntu 16.04 + eigen3 安装(解决 fatal error: Eigen/Core: No such file or directory)
1.安装 sudo apt-get install libeigen3-dev 2. 解决 fatal error: Eigen/Core: No such file or directory 当调用 ...
- LeetCode 1:两数之和 Two Sum
题目: 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标. 你可以假设每种输入只会对应一个答案.但是,你不能重复利用这个数组中 ...