SylixOS BSP开发(八)

news2024/9/21 2:47:31
初始化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.coloradmin.cn/o/1132682.html

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

相关文章

从零开始做一个SDWAN

VPN和SD-WAN的区别 VPN(Virtual Private Network)和SD-WAN(Software-Defined Wide Area Network)是两种不同的网络技术,它们在目的、功能和实施方式上有一些重要的区别。 目的和应用场景: VPN:VPN主要用于…

做图标设计一些常用的设计规范分享

应用程序图标设计是将某个概念转换为清晰易读的图形,从而降低用户的理解成本,提高界面的美感。在我们的企业级应用设计范围内,应用图标在界面设计的许多元素中往往只占很小的比例,调用时会缩小到比设计稿小很多倍的尺寸。此外&…

kafka3.X集群安装(不使用zookeeper)

参考: 【kafka专栏】不用zookeeper怎么安装kafka集群-最新kafka3.0版本 一、kafka集群实例角色规划 在本专栏的之前的一篇文章《kafka3种zk的替代方案》已经为大家介绍过在kafka3.0种已经可以将zookeeper去掉。 上图中黑色代表broker(消息代理服务)&…

DLT645转modbus协议网关采集电表的数据方法

DLT645有两个版本分别是DLT645-97和DLT645-07,该协议主要用于电表抄表,采用为主-从结构的半双工通讯模式,硬件接口使用RS-485今天我们来看下,用远创智控YC-645-TCP网关如何采集电表的数据 1,首先,我们需要…

淘宝京东抖音1688苏宁等关键词搜索商品API接口(关键词搜索商品API接口,关键词搜索商品列表接口)

淘宝京东抖音1688苏宁等关键词搜索商品API接口(关键词搜索商品API接口,关键词搜索商品列表接口)代码对接如下: item_search-按关键字搜索淘宝商品 taobao.item_search 1.公共参数 名称类型必须描述keyString是调用key&#xf…

UG\NX二次开发 获取面的面面积、周长

文章作者:里海 来源网站:王牌飞行员_里海_里海NX二次开发3000例,里海BlockUI专栏,C\C++-CSDN博客 感谢粉丝订阅 感谢 weixin_38891498 订阅本专栏,非常感谢。 简介 UG\NX二次开发 获取面的面面积、周长 效果 代码 #include "me.hpp" #include <NXOpen/Session…

docker部署prometheus+grafana服务器监控(二) - 安装数据收集器 node-exporter

在目标服务器安装数据收集器 node-exporter 1. 安装数据收集器 node-exporter wget https://github.com/prometheus/node_exporter/releases/download/v1.6.1/node_exporter-1.6.1.linux-amd64.tar.gztar xvf node_exporter-1.6.1.linux-amd64.tar.gzmv node_exporter-1.6.1…

【蓝桥】铺地板

1、题目 问题描述 小蓝家要装修了&#xff0c;小蓝爸爸买了很多块&#xff08;可理解为数量无限&#xff09; 2 3 2 \times 3 23 规格的地砖&#xff0c;小蓝家的地板是 n m n \times m nm 规格的&#xff0c;小蓝想问你&#xff0c;能否用这些 2 3 2 \times 3 23 的地砖…

【QT开发(14)】QT P2P chat 聊天

在【P2P学习&#xff08;2&#xff09;】P2P 通信&#xff0c;主要存在四种不同的网络模型的第一阶段&#xff1a;集中式P2P 模式 最简单的路由方式就是集中式&#xff0c;即存在一个中心节点保存了其他所有节点的索引信息&#xff0c;索引信息一般包括节点 IP 地址、端口、节…

YOLOv8训练自己的数据集+改进方法复现

yolov8已经出来好几个月了&#xff0c;并且yolov8从刚开始出来之后的小版本也升级好几次&#xff0c;总体变化不大&#xff0c;个别文件存放位置发生了变化&#xff0c;以下以最新版本的YOLOv8来详细学习和使用YOLOv8完成一次目标检测。 一、环境按照 深度学习环境搭建就不再…

Cesium 展示——实现鼠标移动到实体上动态高亮显示

文章目录 需求分析需求 在开发中,遇到这样一个需求:在绘制完实体后,要求鼠标移动到上边后有高亮的效果,看的清除一点,因此,经过尝试,做出了如下解决方案 在这里,我们以线为例,实现其动态高亮显示 分析 在这里我们首先需要有一个鼠标监听事件,在合适的位置注册鼠标监听…

uni.showModal的用法

uni.showModal({title: 提示,//标题content: "内容",//提示内容可以加入\r\n进行换行showCancel: true,//是否显示取消按钮&#xff0c;默认为truecancelText: 取消,//取消按钮的文字confirmText: 确定,//确认按钮的文字confirmColor: #ff0000,//确认按钮文字颜色can…

chrony时间服务

目录 1.1.重要性 1.2. Linux的两个时钟 1.3. NTP 1.4. Chrony介绍 2.安装与配置 2.1.安装: 2.2. Chrony配置文件分析 3.实验 3.1实验1 3.2实验2 3.常见时区 1.1.重要性 ●由于IT系统中&#xff0c;准确的计时非常重要&#xff0c;有很多种原因需要准确计时: 。在网络…

Netty核心源码剖析

Netty 线程模型 Netty高并发高性能架构设计精髓 主从Reactor线程模型NIO多路复用非阻塞无锁串行化设计思想支持高性能序列化协议零拷贝(直接内存的使用)ByteBuf内存池设计灵活的TCP参数配置能力并发优化 无锁串行化设计思想 在大多数场景下&#xff0c;并行多线程处理可以提…

网络原理之TCP协议(超详细 干货满满)

文章目录 前言TCP 协议的段格式TCP 协议的相关特性什么叫做可靠传输TCP 采用了哪些主要机制保证了可靠传输和优化传输效率1. 确认应答2. 超时重传3. 连接管理&#xff08;三次握手、四次挥手&#xff09;三次握手&#xff08;建立连接&#xff09;四次挥手&#xff08;断开连接…

【方法】如何给PDF文件添加“打开密码”?

PDF文件可以在线浏览&#xff0c;但如果想要给文件添加“打开密码”&#xff0c;就需要用到软件工具&#xff0c;下面小编分享两种常用的工具&#xff0c;小伙伴们可以根据需要选择。 工具一&#xff1a;PDF编辑器 PDF阅读器一般是没有设置密码的功能模块&#xff0c;PDF编辑器…

全志A523(显示篇一)

全志使用de架构&#xff0c;兼容drm架构 返回目录

全面的‘由于找不到mfc110u.dll,无法继续执行代码’的解决方法分享,3分钟教你快速修复

在我们使用电脑的过程中&#xff0c;有时候可能会遇到某个应用程序启动失败&#xff0c;提示“由于找不到mfc110u.dll,无法继续执行代码”的问题。本文将详细介绍如何针对这类问题进行处理&#xff0c;以及mfc110u.dll文件的相关知识。 一.mfc110u.dll文件盘点 首先&#xff0…

用豆瓣电影和掌桥科研练习网页解析的三种方式——正则、Xpath和bs4

网页解析 豆瓣电影解析方式正则表达式Xpathbs4 翻页 掌桥科研正则表达式Xpathbs4 豆瓣电影 解析方式 先爬取数据&#xff1a; # -- coding: utf-8 --** import requests import json import time import pandas as pdurlhttps://movie.douban.com/top250?start0&filter…

【带头学C++】----- 1.基础知识 ---- 1.21.23.9 位运算符的综合应用

最近做任务&#xff0c;公司项目比较重&#xff0c;赶上1024的活动流量券任务&#xff0c;内容治疗略微有一些杂乱&#xff0c;后期会把专栏目录重新搞一下&#xff0c;内容我是融合了很多课程和书籍包含ai的一些理解&#xff0c;我整理和增加了自己的见解和代码贴图&#xff0…