【技术文章】小O带你走进OneOS,探索无限可能!

原创
2023/09/12 15:21
阅读数 7.8K
AI总结

1、OneOS概述

      OneOS是中国移动针对物联网领域推出的轻量级操作系统,具有可裁剪、跨平台、低功耗、高安全等特点,支持ARM Cortex-M/A、MIPS、RISC-V等主流芯片架构,兼容POSIX、CMSIS等标准接口,支持Javascript、Micropython语言开发,提供图形化开发工具,能够有效提高开发效率并降低开发成本,帮助客户开发稳定可靠、安全易用的物联网应用。OneOS遵循Apache许可证2.0版本,个人、企业客户可以在商业产品中使用,不需要公布源码,没有潜在商业风险。中移物联网有限公司将秉承开放合作的态度,为客户提供适用于各种物联网场景的稳定系统。

2、OneOS源码文件结构

目录或文件名称

描述

arch(architecture)

存放和 MCU(或 CPU )架构体系相关的代码。

common

存放一些通用的没有具体业务指向的程序代码,所有模块都可以使用,不通过编译选项控制是否编译,采用默认编译进工程的方式。

components

存放组件代码,可进行裁剪。

demos

存放内核或组件的对外接口如何使用的示例程序。

docs

存放一些文档,如编码规范、编程指南等。

drivers

存放驱动的抽象层代码和具体外设的驱动代码。

kernel

存放内核代码,如任务管理及调度、任务间同步以及通信、内存管理等代码。

libc

Libc 库部分硬件相关接口的底层适配。

osal

OneOS操作系统接口抽象层,支持Posix接口、CMSIS接口、RT-Thread接口等

projects

各种开发板的示例工程

scripts

存放OneOS-Cube工具在编译构造时所需要的脚本文件。

templates

存放为开发者搭建了OneOS当前所支持的MCU的标准工程模板

thirdparty

存放第三方开源社区或第三方厂家的程序,包括组件、工具、协议实现或对接平台的代码等。

user

存放供使用者阅读的文档

Kconfig

Menuconfig配置文件,代码工程(如projects目录下的示例工程)中的Kconfig文件会引用此文件

SConscript

OneOS操作系统使用Scons构建工具时的根编译脚本,该脚本会引用其它目录的SConscript脚本,若在OneOS操作系统根目录增加新的代码目录,需要修改此文件(参见“从零开始构建代码工程”章节)。

LICENSE

License 授权说明。

   

 

3、启动流程

STM32整个启动过程是指从上电系统启动开始,一直运行到用户main函数之间的这段过程,接下来以stm32l475-atk-pandora工程为例讲解启动的流程。

armcc(keil)启动流程为

①上电后硬件设置SP、PC

②设置系统时钟

③软件设置SP

④加载.data、.bss,并初始化栈区

⑤跳转到C文件的main函数

      从启动文件中的“SystemInit”函数开始,然后再执行“__main”函数,再执行$Sub$$main函数,在这个函数里边会执行“_k_startup()”函数,在“_k_startup()”函数中会执行一系列初始化的函数,其中就会执行到“_k_application_init()”函数,在该函数中会创建一个主程序进程“main”(非用户main),然后该进程开始执行后会进入“_k_main_task_entry()”函数,在该函数中先执行“_k_other_auto_init()”函数,然后才执行用户的main()函数。

stm32l475-atk-pandora工程

路径

文件

流程

startup_stm32l475xx_arm.s

SystemInit → __main

os_startup.c

$Sub$$main → _k_startup()

_k_startup() → _k_application_init()

_k_application_init() → _k_main_task_entry()

_k_main_task_entry() → $Super$$main()

$Super$$main() → main()

路径:

①templates\stm32l475-atk-pandora\board\startup\

②kernel\source

4、“.s”启动文件

STM32 MCU 的startup_xxx.s启动文件的主要功能

主要功能如下:

1. 初始化堆栈指针 SP

2. 初始化程序计数器指针 PC

3. 设置堆、栈的大小

4. 设置中断向量表的入口地址

5. 配置外部 SRAM 作为数据存储器

6. 调用 SystemInit() 函数配置 STM32 的系统时钟

7. 设置 C 库的分支入口 "__main” (最终用来调用 main 函数)

SystemInit() :配置 STM32 的系统时钟,配置向量表

__main :__main函数由编译器生成,并在最后跳转到用户自定义的main()函数。

​​​​​​​​​​​​​​5、“.map”文件

map文件是通过编译器编译之后,集程序、数据及IO空间的一种映射文件。

在遇到内存越界或溢出的情况,可以借助分析map文件。通过map文件可以知道函数大小、入口地址等一些重要信息。

里边有函数相互调用的关系、还有没有被调用的模块、变量储存的地址、函数的入口地址、代码占用的空间等等信息

打开:

配置

第一部分Section Cross References

指的是各个源文件生成的模块、段(定义的入口)之间相互引用的关系,配置中需勾选上:Cross Reference,例如:

main.o(i.main) refers to os_task.o(i.os_task_create) for os_task_create

表示 main.o文件中的 main 函数调用了 os_task.o 文件中的os_task_create 函数

main.o是main.c源文件生成的目标文件模块,i.mainmain函数的入口。

第二部分Removing Unused input sections from the image

移除未使用的模块,配置中需勾选上:Unused Sections Info,就是删除工程代码中,没有被调用的模块。最后面还有个统计信息。

 

第三部分Image Symbol Table

什么是局部标签与全局标签:

局部标签就是在函数内部用static声明的变量,还有用static声明的函数,基本上都是属于局部标签;全局标签就是不是用static声明的变量和函数,还有就是汇编文件里面的变量如果作用域是本文件的就是局部标签,作用域是全工程的就是全局标签。

第一列是函数名,前缀i.表示隶属于当前文件,出现无前缀的标签代表static标签。

i.前缀表示是在某个文件里面的某个函数,例如这里的drv_sai.o文件里面的HAL_SAI_RxCallback函数;这个 HAL_SAI_RxCallback要注意一下,为什么前面用i.前缀修饰过的函数,后面又出现一次呢?是因为这个函数是用static修饰的一个局部标签函数,用了130个字节的RAM大小,类型属于M3的Thumb指令代码。

映射符号表,配置中需勾选上:Symbols,从中可以看出符号名称,存储地址,存储大小,所在的目标文件

Symbols分为两大类 :Local Symbols局部 和 Global Symbols全局

1.Symbol Name:符号名称

2.Value:存储对应的地址;

大家会发现有0x0800xxxx、0x2000xxxx这样的地址。

0x0800xxxx指存储在FLASH里面的代码、变量等。

0x2000xxxx指存储在内存RAM中的变量Data等。

全局、静态变量等位于0x2000xxxx的内存RAM中。

3.Ov Type:符号对应的类型

符号类型大概有几种:Number、Section、Thumb Code、Data等;

4.Size:存储大小

这个容易理解,我们怀疑内存溢出,可以查看代码存储大小来分析。

5.Object(Section):段目标

这里一般指所在模块(所在源文件)

 

第四部分Memory Map of the image

内存映射分布,配置中需勾选上:Memory Map。映像文件可以分为加载域(Load Region)和运行域(Execution Region),加载域反映了ARM可执行映像文件的各个段存放在存储器中的位置关系,运行域反映了ARM可执行映像文件各个段真正执行时在存储器中的位置关系。另外,映像中的入口点就是程序开始执行的位置。

加载域就是程序在Flash中的实际存储,而运行域是芯片上电后的运行状态,因为MCU没上电时RAM中没有数据,所以此时所有的东西(包括代码、变量、初始值等)都是存放在flash中的,当上电后又要把变量等复制到RAM中才能正常运行。

Image Entry point : 0x08000401:指映射入口地址。

Load Region LR_IROM1 (Base: 0x08000000, Size: 0x00055334, Max: 0x00080000, ABSOLUTE, COMPRESSED[0x00054cbc]) 

指加载区域位于LR_IROM1开始地址0x08000000,大小有0x00055334,这块区域最大有0x00080000.

执行区域:

Execution Region ER_IROM1

Execution Region RW_IRAM0

Execution Region RW_IRAM1 

这个区域,其实就是对应我们目标配置中的区域,如下图:

第五部分Image component sizes

Code:指代码的大小;

RO-data:指除了内联数据(inline data)之外的常量数据;

RW-data:指可读写(RW)、已初始化的变量数据;

ZI-data:指未初始化或零初始化的数据(ZI)所占字节;

Debug :显示调试数据占用了多少字节;

Object Totals :显示链接到一起以生成映像的对象占用了多少字节。

(incl. Generated):链接器会生成的映像内容,例如,交互操作中间代码。 如果 Object Totals 行包含此类型的数据,则会显示在该行中。本例中共有 1016 字节的 RO 数据,其中32字节是链接器生成的 RO 数据。

(incl. Padding) :链接器根据需要插入填充,以强制字节对齐。

下面的Library Totals显示已提取并作为单个对象添加到映像中的库成员占用了多少字节。

Code、RO-data:位于FLASH中;

RW-data、ZI-data:位于RAM中;

提醒:RW-data已初始化的数据会存储在Flash中,上电会从FLASH搬移至RAM中。

关系如下:

RO Size = Code + RO Data

RW Size = RW Data + ZI Data  

ROM Size = Code + RO Data + RW Data

6、静态链接库文件“libxxx.a”

静态链接库文件名命名规则“libxxx.a”,库名前面加“lib”,后缀用“.a”,“xxx”为静态库名。

https://copyfuture.com/blogs-details/202208311102359537

静态链接库用来和所有的目标文件一起组织成可执行文件

展开阅读全文
加载中
点击加入讨论🔥(2) 发布并加入讨论🔥
2 评论
1 收藏
0
分享
AI总结
返回顶部
顶部