首页 > 系统相关 >Cortex-M7 内存模型

Cortex-M7 内存模型

时间:2024-04-06 20:58:52浏览次数:25  
标签:区域 访问 M7 指令 Cortex memory CPU 内存

1 前言 

       如图1所示, Cortex-M7最大支持4GB的内存寻址,并对内存映射(memory map)做了初步的规定,将整个内存空间划分为了多个内存区域(region)。每个内存区域有着既定的内存类型(memory type)和内存属性(memory attribute),这两者决定了访存的具体行为。

图1  Cortex-M7 memory map 

2 内存区域的类型和属性

        Memory ordering(内存排序) 描述了CPU访问内存的前后顺序,既可以指编译器编译时生成的内存访问序列,也可以指在运行时(runtime)由CPU生成的内存访问序列。CPU 并不是完全按照我们写的程序的逻辑顺序来访问内存的,在保证原始语义的情况下,编译器会对代码指令进行重新排序, CPU也会对指令进行重新排序、延缓执行、各种缓存等等,即通过乱序执行(out-of-order execution)来提升程序执行效率。

        所以,内存排序描述了CPU在内存顺序重排方面的能力,这也直接决定了CPU是否支持乱序执行。乱序执行使得CPU可以在最大程度上利用各类型的内存的总线带宽(bus-bradwidth)以提高程序运行效率。例如,cache比普通的memory banks的访问带宽要大很多。在单线程模式下,编译器和CPU偷偷地做了优化,乱序执行的细节无须由应用层代码操心,彷佛程序确实在严格按照代码的逻辑顺序执行;但在多线程模式下,或者通过内存总线和其他硬件进行数据交互时,乱序执行很容易出问题,这时候就需要内存屏障(memory barriers)指令出场了。     

2.1  内存类型memory types

         Cortex-M7的内存区域的类型主要有以下几种:

        ① 正常(Normal)

        Cortex-M7采用了流水线机制,通过执行前预取指令和分支预测来优化程序执行效率。对于normal类型内存区域,CPU可以重新排序处理(指令)以提高效率,或者可以做一些乐观的猜测性读操作(ldr);

       设备内存和强排序内存区域Device and Strongly-Ordered)

        对于设备内存(device memory)或强排序内存区域(Strongly-ordered memory)来说,CPU会老老实实的严格按照程序定义的顺序进行指令执行。

        此外,设备内存强排序内存区域也有所不同,外部内存系统(external memory system)可以用带缓冲地写设备内存(device memory)进行写操作,但不可带缓冲地写强排序内存区域。

2.2 内存属性memory attributes

         内存属性主要包括以下两种:

        ① 可共享(Shareable)

        对于可共享内存区域,如果系统中存在多个总线master(bus master,例如CPU配有DMA控制器),内存系统需要在总线master之间提供数据同步机制。所以,可共享即意味着拿来即可用,其内存区域内的数据由内存系统来保证同步性。

        此外,强排序内存区域总是可共享的,强排序的目的其实是为了防范语义风险;如果多个总线master可以访问一个不可共享的内存区域,则必须由软件来保证个总线master之间的数据一致性(data coherency)。

        ② 不可执行(Execute Never,XN)

        意为不可执行,即不可从该内存区域取值。谁胆敢从XN内存区域进行取值操作,立马错误异常(fault exception)伺候。

3 内存系统的内存访问顺序

        Memory system ordering of memory accesses,描述了内存系统对于内存访问顺序相关的规范。

        在不影响指令序列的行为的前提下,对于由显式内存访问指令引起的内存访问,内存系统不保证访问的实际顺序与指令的程序级顺序完全相同,即支持乱序执行。如果程序的正确执行依赖于两个内存访问指令的执行顺序,则软件必须在这两条指令之间加入内存屏障指令来保证其时序。

        但是,对于设备内存(device memory)或强排序内存区域(Strongly-ordered memory)来说,内存系统确实在一定程度上保证了访存的时序。例如,假设有由同一主接口(master interface)发起的A1和A2两条访存指令,如果A1在程序中执行的顺序在A2之前,则这两条访存指令的最终内存访问顺序如表1所示:

表1 内存访问顺序示例

        从中可见,若两者都为可共享的设备内存或强排序内存,亦或者两者都为不可共享的设备内存,则内存访问都是严格序列化的。

4 各内存区域的访存行为(Behavior of memory accesses)

        Cortex-M7对于不同内存区域的访存行为具有不同的规范。其中,Code,SRAM和 external RAM区域可用于加载程序代码,具体如表2所示。

表2 各内存区域的内存访问行为明细

        以上只是默认的内存访问行为,如果使能MPU,则可以对其进行重新定义。

        当系统拥有cache和可共享内存(shared memory)时,某些内存区域的约束有所增加,某些内存区域被划分成更小颗粒度的区域,具体如表3所示:

 表3 各内存区域的共享性和cache策略

        其中,WT表示的是write through,no allocate;WBWA表示write back,write allocate,具体含义如图2所示。        

图2 Cache读写策略示意图

5 软件程序定义的内存访问顺序

        软件程序直观地定义了一个程序执行流(program flow),其规则时基于一定的逻辑顺序。而当软件程序经编译器翻译成可执行的机器码并在CPU上执行时,内存系统通常不会严格按照软件程序定义的时序来进行内存访问,这也就是前文描述的乱序执行。

        CPU采用乱序执行的原因主要有以下几点:

        ① 在不改变软件程序定义的指令序列的预期行为的前提下,CPU可能会对一些访存操作重新排序;

        ② CPU拥有多个总线接口(bus interface);

        ③ 不同的内存区域或设备具有不同的等待状态;

        ④ 一些内存访问是带缓冲的,或者是带分支预测的;        

        举例来说,如果可以在运行时更改存储器的映射关系或者内存保护区的设置, (通过写MPU 的寄存器),就必须在更改之后立即补上一条 DSB 指令(数据同步指令)。因为对 MPU 的写操作很可能会被放到一个写缓冲中。

        写缓冲是为了提高存储器的总体访问效率而设的,但它也有副作用,其中之一,就是会导致写内存的指令被延迟几个周期执行,因此对存储器的设置不能即刻生效,这会导致紧临着的下一条指令仍然使用旧的存储器设置——但程序员的本意显然是使用新的存储器设置。这种紊乱危象是后患无穷的,常会破坏未知地址的数据,有时也会产生非法地址访问 fault。

       章节3中描述的一些由内存系统保驾护航的,严格按程序定义的顺序来访问内存的情况。除此之外,需要软件程序通过内存屏障指令(memory barrier instructions)来强制保证CPU的内存访问顺序,即严格按照软件程序定义的指令序列执行。

        这些相关的内存屏障指令指令有如下几种:

        ① DMB(Data Memory Barrier)             

        DMB指令可以保证其身前的内存指令全部处理完成后,其身后的指令才可以开始处理;DMB对于非访存指令的执行顺序没有影响;

        ② DSB(Data Synchronization Barrier)

       DSB架起了一道屏障,保证其身前所有的内存指令都执行完毕后,才会打开屏障,使得其身后的内存指令得以开始执行。在屏障打开之前,后续的所有内存指令都只能乖乖等待。此外,DSB指令不会更新xPSR的标志位。

        ③ ISB(Instruction Synchronization Barrier)

        ISB指令是指令级别的同步指令,在其身前的内存指令全部处理完毕后,对于其后的已预取指令通通抛掉,直接清洗流水线,重新从cache或内存中取指。这也就,处理结果对于后续的指令来说,ISB之前的所有指令都已执行完毕,且结果也已经落到实处;

        DMB 在双口 RAM 以及多核架构的操作中很有用。如果 RAM 的访问是带缓冲的,并且写完之后马上读,就必须让它“喘口气” ——用 DMB 指令来隔离,以保证缓冲中的数据已经落实到 RAM 中。
        DSB 比 DMB 更保险(当然也是有执行代价的),它是宁可错杀也不漏网——清空了写缓冲,使得任何它后面的指令,不管要不要使用先前的存储器访问结果,通通等待访问完成。
        同 DMB/DSB 相比, ISB 指令看起来似乎最强悍,对于高级底层技巧:“自我更新” (self-mofifying)代码,非常有用。举例来说,如果某个程序从下一条要执行的指令处更新了自己,但是先前的旧指令已经被预取到流水线中去了,此时就必须清洗流水线,把旧版本的指令洗出去,再预取新版本的指令。因此,必须在被更新代码段的前面使用 ISB,以保证旧的代码从流水线中被清洗出去,不再有机会执行。

5 总结        

        以上讨论的都是Cortex-M7默认的内存框架和内存访问行为,在功能安全的加注下,MPU的地位愈发重要,很多内容都还要和MPU结合起来一起考虑。不过,这都是后话了。

标签:区域,访问,M7,指令,Cortex,memory,CPU,内存
From: https://blog.csdn.net/m0_47462420/article/details/137413444

相关文章

  • Redis过期删除策略和内存淘汰机制
    过期删除策略1、惰性删除就是过期之后下一次取数据时,发现过期了,就删除它。2、定期删除定期删除一些过期的key。redis采用的时惰性删除+过期删除。问题:可能会漏掉一些key,从而导致OOM。内存淘汰机制3*2+2volatile-lru:从过期数据集中选择最近最少使用的数据淘汰。allKe......
  • 43.数据在内存中的存储
    1.整数在内存中的存储整数的2进制表⽰⽅法有三种,即原码、反码和补码三种表⽰⽅法均有符号位和数值位两部分,符号位都是⽤0表⽰“正”,⽤1表⽰“负”,⽽数值位最⾼位的⼀位是被当做符号位,剩余的都是数值位。正整数的原、反、补码都相同。负整数的三种表⽰⽅法各不相同。原......
  • Tomcat内存马回显
    回顾JSP马详情见:https://www.cnblogs.com/F12-blog/p/18111253之前说的都是利用jsp注入内存马,但Web服务器中的jsp编译器还是会编译生成对应的java文件然后进行编译加载并进行实例化,所以还是会落地。但如果直接注入,比如利用反序列化漏洞进行注入,由于request和respons......
  • 在Linux中,虚拟内存和交换空间作用是什么?
    在Linux系统中,虚拟内存和交换空间是用于扩展物理内存(RAM)容量的两种机制。它们允许系统在物理内存不足时继续运行程序和处理数据,从而提高了系统的可用性和稳定性。1.虚拟内存(VirtualMemory)概念:虚拟内存是一种内存管理技术,它使得系统可以访问比物理内存更多的内存空间。虚拟......
  • 虚拟内存知识详解
    虚拟内存单片机的CPU是直接操作内存的「物理地址」在这种情况下,要想在内存中同时运行两个程序是不可能的操作系统是如何解决这个问题呢?关键的问题是这两个程序都引用了绝对物理地址,而这正是我们最需要避免的。可以把进程所使用的地址「隔离」开来,即让操作系统为每......
  • Spark面试整理-解释Spark中的内存管理和持久化机制
    在Apache Spark中,内存管理和持久化机制是核心特性,它们对于提高大规模数据处理的效率和性能至关重要。内存管理统一的内存管理:Spark使用统一的内存管理模型,将执行内存(用于计算如shuffle、join等)和存储内存(用于缓存数据如RDDs)合并在一起。这种模型提供了更高的灵活性和效......
  • 内存分块!
    这是我在学习这方面知识的笔记,主要是网课上老师讲的内容和一些自己的想法,整理了一下,希望对学习这方面知识的小伙伴有帮助:)1.内存条全局区:    全局变量    静态变量  (static关键字)    常量:      字符串常量      con......
  • 《架构风清扬-Java面试系列第13讲》说一说Java对象在内存中的生命周期
    大家好,加个餐!像线程的生命周期,Servlet的生命周期,相信这类问题大家都非常熟悉了Java对象在内存中的生命周期,这个题目倒是有些新鲜来,思考片刻,说出你的答案(PS:上图缓冲)Java对象在其内存中的生命周期可以被划分为多个阶段,下面钊哥逐个给大家说一说1,创建阶段(Creation......
  • 数据在内存中的存储
    ......
  • [转帖]Linux内存–零拷贝
    https://plantegg.github.io/2020/11/15/Linux%E5%86%85%E5%AD%98--%E9%9B%B6%E6%8B%B7%E8%B4%9D/ 本系列有如下几篇Linux内存问题汇总Linux内存–PageCacheLinux内存–管理和碎片Linux内存–HugePageLinux内存–零拷贝零拷贝“Zero-copy“describescomputeroper......