SylixOS BSP开发(八)

初始化FPU、MMU和Cache组件

        本来想在不初始化这些部件的情况下把SylixOS先启动起来感受下,结果测试发现如果MMU不使能的话,系统启动过程中线程无法进行调度emm。。。所以只好把这一章节提前来讲了。这三个组件的初始化都是在bspInit.c中进行的。

1. FPU初始化

        我们首先来看下FPU的初始化:

static VOID  halFpuInit (VOID)
{API_KernelFpuInit(ARM_MACHINE_A7, ARM_FPU_VFPv3);
}

        可以看出来FPU的初始化很简单,只需要调用API_KernelFpuInit 即可。第一个参数表示当前CPU的架构,第二个参数表示当前SOC中FPU使用的类型,这两个参数根据芯片数据手册的信息然后使用内核提供好的宏填入就行了。

2. Cache初始化

再来看看Cache的初始化:

static VOID  halCacheInit (VOID)
{API_CacheLibInit(CACHE_COPYBACK, CACHE_COPYBACK, ARM_MACHINE_A7);   /*  初始化 CACHE 系统           */API_CacheEnable(INSTRUCTION_CACHE);API_CacheEnable(DATA_CACHE);                                        /*  使能 CACHE                  */
}

首先使用API_CacheLibInit 接口初始化了内核Cache组件:

  • 第一个参数表示指令Cache的工作方式,一般有写回和写通两种模式,实际中一般使用写回模式。
  • 第二个参数表示数据Cache的工作方式,一般有写回和写通两种模式,实际中一般使用写回模式。
  • 第三个表示当前CPU的架构类型。

        初始化完了内核Cache组件,接着使用了API_CacheEnable 接口使能了指令Cache和数据Cache,可以看出Cache的初始化还是比较简单的,因为内核已经为大部分arm架构封装好了Cache等部件的操作,我们只需要调用接口即可。

        另外有些平台上的L2 Cache是可以单独控制的,比如zynq7000平台,针对这些L2 Cache可以控制的的平台我们还需要实现bspLib.c中的bspL2CBase bspL2CAux 这两个接口:

        全志R16平台并没有单独L2 Cache控制器,所以这两个接口我们直接使用默认实现即可。

3. MMU初始化

        MMU的初始化需要做三部分工作,一个是bspMap.h 中映射表的设置,另外一个是内核VMM组件初始化,最后是MMU页表池大小设置,下面我们分别来学习下这两部分的内容。

3.1 映射表设置

        映射表是定义在bspMap.h 中,_G_physicalDesc 描述物理地址空间的关系,_G_virtualDesc 描述虚拟地址空间关系,VMM通过这两个表中定义的关系来管理物理地址和虚拟地址。

3.1.1 物理地址空间映射表

        SylixOS中使用LW_MMU_PHYSICAL_DESC 这个数据结构来描述中断向量表、物理内存区、外设寄存器的物理地址和虚拟地址的映射关系:

/*********************************************************************************************************物理内存信息描述注意:TEXT, DATA, DMA 物理段 PHYD_ulPhyAddr 必须等于 PHYD_ulVirMap,TEXT, DATA, VECTOR, BOOTSFR, DMA 物理段 PHYD_ulVirMap 区间不能与虚拟内存空间冲突.
*********************************************************************************************************/typedef struct __lw_vmm_physical_desc {addr_t                   PHYD_ulPhyAddr;                            /*  物理地址 (页对齐地址)       */addr_t                   PHYD_ulVirMap;                             /*  需要初始化的映射关系        */size_t                   PHYD_stSize;                               /*  物理内存区长度 (页对齐长度) */#define LW_PHYSICAL_MEM_TEXT        0                                   /*  内核代码段                  */
#define LW_PHYSICAL_MEM_DATA        1                                   /*  内核数据段 (包括 HEAP)      */
#define LW_PHYSICAL_MEM_VECTOR      2                                   /*  硬件向量表                  */
#define LW_PHYSICAL_MEM_BOOTSFR     3                                   /*  启动时需要的特殊功能寄存器  */
#define LW_PHYSICAL_MEM_BUSPOOL     4                                   /*  总线地址池, 不进行提前映射  */
#define LW_PHYSICAL_MEM_DMA         5                                   /*  DMA 物理内存, 不进行提前映射*/
#define LW_PHYSICAL_MEM_APP         6                                   /*  装载程序内存, 不进行提前映射*/UINT32                   PHYD_uiType;                               /*  物理内存区间类型            */UINT32                   PHYD_uiReserve[8];
} LW_MMU_PHYSICAL_DESC;
typedef LW_MMU_PHYSICAL_DESC *PLW_MMU_PHYSICAL_DESC;
  • PHYD_ulPhyAddr:表示物理地址空间起始地址。
  • PHYD_ulVirMap:表示起始虚拟地址。
  • PHYD_stSize:表示物理地址空间大小。
  • PHYD_uiType:物理空间的类型。

注意:这里的地址和大小值必须是当前平台页对齐的值,系统启动过程中会检测是否对齐,如果不对齐则会启动失败。

让我们来看看R16平台上这个表的具体设置:

LW_MMU_PHYSICAL_DESC    _G_physicalDesc[] = {{                                                                   /*  中断向量表                  */BSP_CFG_RAM_BASE,0,LW_CFG_VMM_PAGE_SIZE,LW_PHYSICAL_MEM_VECTOR},{                                                                   /*  内核代码段                  */BSP_CFG_RAM_BASE,BSP_CFG_RAM_BASE,BSP_CFG_TEXT_SIZE,LW_PHYSICAL_MEM_TEXT},{                                                                   /*  内核数据段                  */BSP_CFG_RAM_BASE + BSP_CFG_TEXT_SIZE,BSP_CFG_RAM_BASE + BSP_CFG_TEXT_SIZE,BSP_CFG_DATA_SIZE,LW_PHYSICAL_MEM_DATA},{                                                                   /*  DMA 缓冲区                  */BSP_CFG_RAM_BASE + BSP_CFG_TEXT_SIZE + BSP_CFG_DATA_SIZE,BSP_CFG_RAM_BASE + BSP_CFG_TEXT_SIZE + BSP_CFG_DATA_SIZE,BSP_CFG_DMA_SIZE,LW_PHYSICAL_MEM_DMA},{                                                                   /*  APP 通用内存                */BSP_CFG_RAM_BASE + BSP_CFG_TEXT_SIZE + BSP_CFG_DATA_SIZE + BSP_CFG_DMA_SIZE,BSP_CFG_RAM_BASE + BSP_CFG_TEXT_SIZE + BSP_CFG_DATA_SIZE + BSP_CFG_DMA_SIZE,BSP_CFG_APP_SIZE,LW_PHYSICAL_MEM_APP},/** TODO: 加入启动设备的寄存器映射, 参考代码如下:*/{                                                                   /*  UART0 ~ 4                   */0x01C28000,0x01C28000,2 * LW_CFG_VMM_PAGE_SIZE,LW_PHYSICAL_MEM_BOOTSFR},{                                                                   /*  结束                        */0,0,0,0}
};
  • 在以前比较老的arm平台,中断向量表的地址必须是放在0地址处的,当使能MMU之后,需要将中断向量表所在的实际物理地址映射为虚拟地址0,这样中断向量表才能被正常使用。
  • 内核代码段和内核数据段会在VMM初始化时将表中记录的物理地址和虚拟地址建立对等映射关系。
  • DMA内存段中记录的映射关系不会再VMM初始化的时候使用,但是会在申请DMA内存的时候使用,一般都是对等映射。
  • 这个表中APP内存段中的虚拟地址不会被VMM使用,VMM主要使用的是这里记录的物理基址和大小,其对应的虚拟地址是再另一个表中配置的。这里为了表内容统一,直接将物理地址填在虚拟地址的位置。
  • SylixOS支持启动的时候静态映射寄存器和通过调用接口动态映射寄存器地址。如果需要静态映射,就将映射关系填入上表中,一般也都是对等映射,动态映射在下一小节说明。由于使能MMU之后,我们还需要串口进行输出信息,所以这里需要将串口寄存器地址进行静态映射。
3.1.2虚拟地址空间表

        SylixOS中使用LW_MMU_VIRTUAL_DESC 数据结构来描述虚拟地址空间信息: 

typedef struct __lw_mmu_virtual_desc {addr_t                   VIRD_ulVirAddr;                            /*  虚拟空间地址 (页对齐地址)   */size_t                   VIRD_stSize;                               /*  虚拟空间长度 (页对齐长度)   */#define LW_VIRTUAL_MEM_APP      0                                       /*  装载程序虚拟内存区间        */
#define LW_VIRTUAL_MEM_DEV      1                                       /*  设备映射虚拟内存空间        */UINT32                   VIRD_uiType;                               /*  虚拟内存区间类型            */UINT32                   VIRD_uiReserve[8];
} LW_MMU_VIRTUAL_DESC;
typedef LW_MMU_VIRTUAL_DESC *PLW_MMU_VIRTUAL_DESC;
  • VIRD_ulVirAddr:虚拟地址空间起始地址。
  • VIRD_stSize:虚拟地址空间大小。
  • VIRD_uiType:虚拟空间类型。

        同样的,起始地址和大小值也必须是页对齐的值。VMM管理的虚拟地址空间只有两种:LW_VIRTUAL_MEM_APP 表示系统动态加载的程序、动态库和内核模块所使用的虚拟地址空间;LW_VIRTUAL_MEM_DEV 表示系统调用API_VmmIoRemap 这类接口动态映射寄存器地址时所使用的虚拟地址空间。

        我们来看看R16平台上的实际配置:

LW_MMU_VIRTUAL_DESC    _G_virtualDesc[] = {/** TODO: 加入虚拟地址空间的定义, 参考代码如下:*/
#if 1{                                                                   /*  应用程序虚拟空间            */0x80000000,((size_t)1 * LW_CFG_GB_SIZE),LW_VIRTUAL_MEM_APP},{0xC0000000,                                                     /*  ioremap 空间                */(64 * LW_CFG_MB_SIZE),LW_VIRTUAL_MEM_DEV},
#endif{                                                                   /*  结束                        */0,0,0}
};

 注意:这里的虚拟地址和物理空间描述表中各个区域的虚拟地址不要有重复,在满足这个前提下,地址值可以任意配置。另外还需要注意的是起始地址加上大小之后不要超过4GB,因为我们现在用的是32位的地址空间。

3.2 VMM组件初始化

        在配置好上述的两个映射表后,就可以使用API_VmmLibInit 这个接口来初始化VMM组件:

static VOID  halVmmInit (VOID)
{API_VmmLibInit(_G_physicalDesc, _G_virtualDesc, ARM_MACHINE_A7);API_VmmMmuEnable();
}

上述代码应该很好理解,就不再赘述。初始化好VMM组件之后,最后调用API_VmmMmuEnable 接口来使能MMU。

3.3 MMU页表池设置

        MMU正常工作需要使用页表,全志R16属于armv7架构,在armv7架构下,SylixOS内核使用的是二级页表机制。第一级页表叫全局页目录(Page Global Directory),也可以叫做一级页表,页目录中单个条目就叫做页目录项,一个页目录项可以映射1MB的物理页,32位地址空间有4GB大小,所以整个页目录共有4096个页目录项。第二级页表叫做二级页表,二级页表中单个条目就叫做页表项(Page Table Entry),一般arm32位都是用4KB页大小,也就是一个页表项可以映射4KB的物理页,一个二级页表可以映射1MB大小,所以一个二级页表中共有256个页表项:

在SylixOS中,一级页表和二级页表所占的内存是在内核堆上的,也就是内核数据区空间,所以在配置config.h时,最好将内核数据区配置大点,否则有可能因为MMU页表申请不到内存空间而导致系统启动失败。

在一个实际的嵌入式项目中,并不会完全使用4GB的空间,那么我们就可以将二级页表的个数减少点来节省下内存给其他的内核模块或者应用使用,这是通过bspLib.c中的bspMmuPgdMaxNum bspMmuPteMaxNum 这两个接口实现的。

bspMmuPgdMaxNum 接口主要用来获取一级页表的个数,一个一级页表已经能映射4GB的空间了,所以这个函数一般都是返回1:

        bspMmuPteMaxNum 接口主要用来获取二级页表的个数,注意是二级页表的个数而不是页表项的个数。如果是4096则表示映射完整的4GB空间,这里实际返回的是2048,也就是表示只映射2GB的空间:

        因为本次使用的开发板内存是1GB,再加上其他的寄存器空间大小,2GB空间已经足够使用了。如果开发板内存是2GB的话,那么这个函数的返回值就需要改大一点了,总之这个值根据实际情况进行设置。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/118130.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Unity游戏开发中打造游戏攻击技能架构与设计

一、技能系统的设计 在 MOBA 游戏中,每个英雄角色都会有多个技能,这些技能可以分为普通攻击和技能攻击两种。普通攻击是英雄角色的基本攻击方式,而技能攻击则需要消耗一定的资源(如蓝量)才能使用。在设计技能系统时&a…

【面试经典150 | 链表】循环链表

文章目录 Tag题目来源题目解读解题思路方法一:哈希集合方法二:快慢指针方法三:计数 拓展其他语言python3 写在最后 Tag 【快慢指针】【哈希集合】【计数】【链表】 题目来源 141. 环形链表 题目解读 判断一个链表中是否存在环。 解题思路 …

(Java)中的数据类型和变量

文章目录 一、字面常量二、数据类型三、变量1.变量的概念2.语法的格式3.整型变量4.长整型变量5.短整型变量6.字节型变量 四、浮点型变量1.双精度浮点数2.单精度浮点数 五、字符型常量六、布尔型变量七、类型转换1.自动类型转换(隐式)2.强制类型转换(显式…

react的setState做了什么

1、为什么需要setState setState的作用是帮助我们更改数据的同时并且通知视图进行渲染。因为React并不会绑定视图和state,需要我们手动去更新视图。 2、setState什么时候是同步的,什么时候是异步的 setState这个方法在调用的时候是同步的,…

【人工智能Ⅰ】实验1:谓词表示法与产生式知识表示

实验1 谓词表示法与产生式知识表示 一、实验目的 1、熟悉谓词逻辑表示法; 2、理解和掌握产生式知识表示方法,实现产生式系统的规则库。 二、实验内容 要求通过C/C/python语言编程实现: 1、猴子摘香蕉问题 2、动物识别系统 &#xff08…

Spring无法加载静态属性和SpringBoot单元测试指定加载配置文件

一、Spring无法加载静态属性,怎么解决? Spring主要用于管理和注入Bean(对象)的实例属性,而不是静态属性。静态属性属于类本身,而不是类的实例,因此Spring的依赖注入机制不会处理它们。 看图&a…

项目部署Linux步骤

1、最小化安装centos7-环境准备 安装epel-release 安装epel-release,因为有些rpm包在官方库中找不到。前提是保证可以联网 yum install -y epel-release 修改IP net-tools net-tool:工具包集合,包含ifconfig等命令 yum install -y net-…

【MySQL-->数据操作】

文章目录 前言一、insert1.单行插入2.多行插入3.插入更新/替换 二、select1.全列查询2.指定列插入3.列别名4. 表达式计算5.去重6.where条件查询7.排序8.limit分页显示 三、update四、delete五、插入查询结果六、聚合函数六、聚合分组1.格式2.where和having的区别 前言 一、inse…

个人创业新机遇,零成本开启真人手办定制项目

桌上的日历变薄,2023年已经接近尾声,浅观这一年,您是否发现大家日常关注的重点有明显的变化,诸多社会事件和宏观数字的背后,潜藏着对经济的“不托底”,而当我们真正开始关注起用个人经济积累去对冲未来的不…

大数据Flink(一百零一):SQL 表值函数(Table Function)

文章目录 SQL 表值函数(Table Function) SQL 表值函数(Table Function) Python UDTF,即 Python TableFunction,针对每一条输入数据,Python UDTF 可以产生 0 条、1 条或者多条输出数据,此外,一条输出数据可以包含多个列。比如以下示例,定义了一个名字为 split 的Pyt…

【会员管理系统】篇二之项目搭建、初始化、安装第三方库

一、项目搭建 1.全局安装vue-cli npm install -g vue/cli查看版本信息 vue -V 2.创建项目 vue create 项目名称 回车 回车 剩余选择如下 之后等待项目创建 最后npm run serve 二、初始化配置 1.更改标题 打开public下的index,将title标签里的改成想要设置的…

汽车电子专有名词与相应技术

1.EEA (Electronic & Electrical Architecture 电子电气架构) EEA在宏观上概括为物理架构与逻辑架构的结合,微观上通过众多电子元器件的协同配合,或集成式或分布式的系统级电子电气架构,具体详见专栏 新能源汽车电…

contenteditable实现文本内容确认提示

功能需求: 列表进行批量查询,需要对输入的值做提交校验,分三种情况: 若部分字符串有误,部分字符串需要变更字体颜色做提示,再次点击确认则对部分正确数据执行批量查询 若全部数据有误则变更字体颜色做提示&…

redis场用命令及其Java操作

目录 1. Redis入门 1.1 Redis简介 1.2 Redis下载与安装 1.2.1 Redis下载 1.2.2 Redis安装 1.3 Redis服务启动与停止 1.3.1 服务启动命令 1.3.2 客户端连接命令 1.3.3 修改Redis配置文件 1.3.4 Redis客户端图形工具 2. Redis数据类型 2.1 五种常用数据类型介绍 2.2 …

docker(1) dockfile制作docker java镜像 并启动

Dockerfile就是利用固定的指令来描述镜像的结构和构建过程,这样Docker才可以依次来构建镜像; 将springboot项目打包上传到指定目录,并且编写一个dockefile文件放在jar包的同级目录 输入命令 打包镜像 成功打包显示 运行镜像

中国区域2013-2021年森林地上生物量产品

该数据集包括中国陆地区域2013-2021年30m分辨率森林地上生物量产品。每年的产品存放在以年份数字命名的文件夹中,有2013-2021共9个文件夹。 每个文件夹内包括分块的产品和vrt文件。 产品命名方式为分区名年份数字.tif。 不同的分区名称如下: cold te…

简单聊下Redis的主从复制和哨兵机制以及集群(面试题)

ChatGPT的简答: Redis的主从复制(Master-Slave Replication)是指将一个Redis服务器的数据复制到其他Redis服务器的过程,其中一个服务器作为主节点(Master),而其他服务器作为从节点(S…

加上boot程序,FreeRTOS就跑不起来了

一、问题描述 bootloader跳转到APP时,app执行完初始化程序后死机 二、分析问题 第一步,执行app时死机死到哪里?通过DEBUG调试发现死到hardfault_handler()函数中,硬件错误,导致硬件错误的原因一般都是中断异常引起的。…

李宇航

该篇文章仅用作能直接在百度搜索到我的csdn,进入我的主页,没有实际意义. 进入李宇航博客方法 通过百度搜索"李宇航" 链接: https://blog.csdn.net/llllyh812 1.电脑端进入方法 输入网址链接: https://blog.csdn.net/llllyh812 或者 进入csdn主页,搜索"李宇…

口袋参谋:实时监测竞争对手的流量来源!

​ 在竞争激烈的淘宝天猫上运营店铺,如果想快速了解竞争对手的销售情况。 则可以通过口袋参谋同类目竞店透视工具,来剖析对方的数据信息,全面了解竞争对手的营销策略。 口袋参谋【同类目竞店透视】功能: 支持一键透视任意竞品…