RTOS之UCOS(五)---存储管理与虚拟内存

本文深入探讨嵌入式实时操作系统UCOS的存储管理,包括内存分类、存储器寻址、ARM内核的存储器映射、STM32的内存布局以及UCOS的物理内存管理。此外,还讨论了内存保护单元MPU的作用以及虚拟内存管理的概念,解释了Linux如何通过MMU和页表进行虚拟地址到物理地址的转换,以实现内存的高效管理和扩展。
摘要由CSDN通过智能技术生成

一、存储器寻址

我们使用C语言开发程序时经常涉及到存储空间的分配和释放,常用malloc/free两个函数完成相应的操作(C++语言则使用new/delete)。那么,我们分配和释放的到底是什么呢?有点计算机基础的应该知道,分配和释放的是运行内存(RAM:Random Access Memory)。计算机的主要作用是对输入数据进行处理和运算后输出,处理器主要完成数据的处理运算,但输入输出数据包括处理过程中的临时数据需要有一个空间去存放,这个临时存放数据供处理器和外设使用的地方就是内存,下面给出经典的冯诺依曼架构图:
冯诺依曼架构
现在的计算机多采用哈弗架构,只是在冯诺依曼架构基础上进行了些改进,为了提高效率把存放程序(也即控制指令)和数据(也即操作数)的空间分开,同时把访问指令与访问数据的总线分开,使取指令和执行指令能够重叠(处理器的流水线)。

1.1 存储器分类

存储器又根据应用需求不同,被分成了两大类:RAM(Random Access Memory)与ROM(Read-Only Memory,可通过电压驱动读写操作),前者的特点是访问速度快,但数据断电就丢失,适合保存中间临时数据,后者的特点是访问速度慢,但数据断电后能长期保存,适合保存永久型数据。实际存储器类别分的更细,下面给出存储器的层次结构图供参考:
存储器层次结构图
RAM又可分为两大类:一类是静态存储器SRAM,上面的寄存器和高速缓存SRAM都属于此类(主要位于处理器CPU或控制器MCU中),该类存储器主要由锁存器和触发器构成,基本单元是晶体管构成的门电路,访问速度快但成本较高;另一类是动态存储器DRAM,上面的主存DRAM属于此类(主要位于电脑或手机的内存中),该类存储器利用电容的电荷存储效应来存储数据,要定期刷新保证数据不丢失,速度慢但成本较低。

ROM最开始使用磁介质比如光盘/磁带等作为数据存储载体,但磁介质速度和存储密度满足不了特定使用场合的要求,所以身边以半导体电介质比如U盘/SSD固态硬盘等作为数据存储载体的设备越来越多。传统的电介质存储载体是EEPROM(Electrically Erasable Programmable Read-Only Memory),以字节为单位擦除数据,数据线与地址线分开,可以用地址线按字节随机寻址,但擦写速度慢且成本较高。

后来发展出了Flash EEPROM Memory,简称Flash,以块为单位(一般一个块为512字节)擦除数据,为了满足不同需求,又分出了两个类别:一类是NAND Flash(Not AND即与非),读写都是以块为单位,地址线与数据线复用,所以不支持地址线随机寻址,但擦写速度快、存储密度高且成本较低,我们常用的U盘/SSD固态硬盘等都属于此类;另一类是NOR Flash(Not OR即或非),读写都是以字节为单位,地址线与数据线分开,可以使用地址线按字节随机寻址,读取速度快但擦写速度较慢成本较高,跟EEPROM不同的是NOR按块擦除而EEPROM按字节擦除,因此NOR擦除速度比EEPROM更快,由于可以按字节随机寻址,保存在其中的程序可以直接执行,所以常用作程序存储器使用(大型系统因占用空间过大,所以一般只在程序存储器中保存引导启动代码,启动代码把系统代码载入内存后再执行)。

1.2 存储器寻址

一般像NAND Flash这种大容量的存储器由于不能通过地址线按字节进行随机寻址,所以并不直接与处理器通信,需要内存作为数据中转站间接与处理器进行数据交互,这类存储器由于距离处理器较远(不直接与处理器交互,由操作系统通过驱动程序间接管理),并不是操作系统内存管理的目标,所以本文主要介绍能通过地址线按字节进行随机寻址的存储器(比如程序存储器与数据存储器)。

处理器与内存之间有地址总线用于寻址,有数据总线用于传输数据,当然也有相应的控制线分辨读写操作,下面给出简单的关系图示如下:
CPU与主存关系
其中MDR(Memory Data Register)是主存数据寄存器,保存待处理的数据,MAR(Memory Address Register)是主存地址寄存器,用来保存源地址与目的地址,便于随机寻址。地址线用于从处理器经译码器到主存的寻址,信号是单向流动的;数据线用于处理器与主存间传输数据,数据需要双向流动,处理器与主存间还有读写控制线控制读写电路中的数据流向。

存储单元是以矩阵方式排列的,寻址时每个维度都有一个对应的地址译码器,就好比描述矩阵中的某一个元素,给定各个维度的编号就可以唯一确定该元素位置,所以一个存储单元的地址是由各个维度的编号组合而成的,下面给出一个二维存储单元的简单图示:
寻址译码器
从上面的介绍可知,处理器对内存的访问主要包含三部分:要访问的存储单元的地址(保存在MAR寄存器中,由计算机汇编指令的操作数中指定)、要对该存储单元执行的访问类型(由程序指令指定,比如汇编语言中的操作码)、要与该存储单元交互的具体数据(保存在MDR寄存器中)。程序或指令的执行过程,主要也是处理器通过寻址从内存获取数据,经过运算处理后,再把结果放入内存相应地址的过程,所以操作系统对内存的管理,主要是通过对内存中地址或地址区间的管理实现的。

二、ARM内核存储器映射

在嵌入式领域ARM应用挺广泛,选择主要流行32位与64位,我们以相对简单的32位为例来介绍。既然对存储空间的访问受限于地址总线的位宽,所以32位处理器的最大寻址范围是4GB(2的32次方字节),下面以Cortex-M3为例给出其预定义的存储器映射图:
CM3存储器映射图
由上图可知,CM3对支持的4GB寻址空间的每个字节都进行了编号,每个字节都有一个独一无二的32位编号,对某个字节的操作只需要知道其所在的地址编号即可,当然也可以通过某一个连续地址段的起始编号和长度管理这一段连续的地址区间。

2.1 STM32存储器映射

上面CM3的存储器映射只是ARM预定义支持的,将4GB存储空间粗略分为六大块(Code/SRAM/Peripheral/External RAM/External Device/System Level),但在不同厂家生产的芯片中,对每块地址区间的利用率并不相同,比如CM3内核支持512MB的SRAM地址区间,但STM32可能只提供了其中的64KB,根据应用场景不同,可以选择不同大小存储空间的芯片型号,尽可能降低成本。下面先给出STM32的系统模块结构图,可以清晰了解CM3内核与STM32芯片之间的关系:
STM32系统结构
由上图可以看出,CM3只是处理器内核,跟内存和外设通过总线进行通信,总线主要分为指令总线、数据总线与系统总线,指令总线与数据总线共同负责对代码存储区的访问,系统总线用于访问内存和外设,上图中的Flash指的是NOR Flash或EEPROM程序存储器,SRAM指的就是我们上面所说的内存,连接在AHB总线上的外设对应Peripheral区间。下面给出STM32的内存映射图如下:
STM32存储器映射
从上图可以看出,STM32上每个模块都映射到一段地址区间,方便处理器通过寻址访问该模块,比如对每个外设配置寄存器的访问,都是对其相应地址区间的读写访问。STM32除了片上支持的SRAM/Peripheral,还提供了可扩展性,主要通过FSMC(Flexible Static Memory Controller)对SRAM/Peripheral进行扩展,如果片上空间够用自然就不需要再扩展了。

下面给出STM32上主要的几个地址基点:

// Libraries\CMSIS\CM3\CoreSupport\core_cm3.h

/* Memory mapping of Cortex-M3 Hardware */
#define SCS_BASE            (0xE000E000)                              /*!< System Control Space Base Address */
#define ITM_BASE            (0xE0000000)                              /*!< ITM Base Address                  */
#define CoreDebug_BASE      (0xE000EDF0)                              /*!< Core Debug Base Address           */
#define SysTick_BASE        (SCS_BASE +  0x0010)                      /*!< SysTick Base Address              */
#define NVIC_BASE           (SCS_BASE +  0x0100)                      /*!< NVIC Base Address                 */
#define SCB_BASE            (SCS_BASE +  0x0D00)                      /*!< System Control Block Base Address */

/* Peripheral Memory mapping of STM32 Hardware */
#define FLASH_BASE            ((uint32_t)0x08000000) /*!< FLASH base address in the alias region */
#define SRAM_BASE             ((uint32_t)0x20000000) /*!< SRAM base address in the alias region */
#define PERIPH_BASE           ((uint32_t)0x40000000) /*!< Peripheral base address in the alias region */

#define SRAM_BB_BASE          ((uint32_t)0x22000000) /*!< SRAM base address in the bit-band region */
#define PERIPH_BB_BASE        ((uint32_t)0x42000000) /*!< Peripheral base address in the bit-band region */

#define FSMC_R_BASE           ((uint32_t)0xA0000000) /*!< FSMC registers base address */

/*!< Peripheral memory map */
#define APB1PERIPH_BASE       PERIPH_BASE
#define APB2PERIPH_BASE       (PERIPH_BASE + 0x10000)
#define AHBPERIPH_BASE        (PERIPH_BASE + 0x20000)

在前一篇文章介绍中断管理时谈到了NVIC、SCB、SYSTICK的相关寄存器配置,包括外设TIM、USART的配置,这些私有外设和片上外设寄存器对应的地址都是跟芯片相关的,想访问哪个寄存器就去访问其对应的地址编号,所以也不涉及内存的分配释放这类管理手段。除去私有外设与片上外设,比较重要的地址区间有两个:一个是Code区的Flash(程序存储器,存储程序代码,包括中断向量表)和System memory(存储系统引导启动BootLoader代码,一般单片机的代码量较少,Flash内能存放得下,所以不需要BootLoader代码,但对于占用空间较大的系统需要BootLoader),该区主要存储程序代码、初始化变量、中断向量表等跟系统启动运行相关的内容,处理器可以读取并执行,但运行期间不能写入或擦除,并不是操作系统存储管理的对象;另一个是SRAM区的SRAM地址区间(存储变量、堆栈等数据)是内存管理的主要对象,后面会针对SRAM地址区间详细讲解操作系统的内存管理。

2.2 STM32外设地址管理

前面谈中断管理时提到过私有外设与中断外设的配置,相关寄存器对应相应的地址,下面再以GPIO的配置为例,介绍下处理器是如何访问外设的,外设是如何在程序中被配置的。先看下GPIO对应的相关寄存器及其地址编号如下:

// Libraries\CMSIS\CM3\DeviceSupport\ST\STM32F10x\stm32f10x.h

#define PERIPH_BASE           ((uint32_t)0x40000000) /*!< Peripheral base address in the alias region */
#define
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

流云IoT

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值