当前位置: 首页 > news >正文

ARM内存映射与启动地址重映射机制解析

目录

内存映射

1. 核心概念:内存映射 (Memory Map)

2. 启动过程与地址重映射 (Remapping)

关键:启动引脚 (Boot Pins)

这个过程可以类比:

3. 为什么设计成这样?

4. 一图流总结

图解说明:

核心要点:

总结

5. 关于上文的“重映射控制器”

核心区别:ARM Cortex-M 内核 vs. 芯片厂商的实现

“重映射”的具体实现方式

以STM32F1系列为例(来自ST的参考手册)

总结


内存映射

        在上一篇博客中,我们解析了arm内核架构中的icode、dcode、s-bus总线和总线矩阵。需要注意的是,不论是icode、dcode、s-bus 在访问物理内存时都经过了内存映射(或者叫寄存器映射)

内存重映射的机制是由芯片厂商设计的一部分硬件逻辑实现的,而这部分逻辑通常与总线矩阵紧密集成,或者说是总线矩阵功能的一部分。

上篇博客:https://blog.csdn.net/leilei050213/article/details/151442621?spm=1001.2014.3001.5501

1. 核心概念:内存映射 (Memory Map)

ARM Cortex-M内核设计了一个固定的内存映射架构。这意味着CPU内核“认为”4GB的地址空间(从0x0000_00000xFFFF_FFFF)的特定区域永远对应特定类型的内存或设备。

这种固定映射的好处是极大的可移植性。任何为Cortex-M编写的软件都知道:

  • 代码在 0x0000_00000x0800_0000

  • 数据RAM在 0x2000_0000

  • 外设在 0x4000_0000

  • 内核寄存器在 0xE000_0000

无需为不同的芯片重新配置基本内存布局。


2. 启动过程与地址重映射 (Remapping)

现在我们从一个疑问来探究地址重映射的过程:为什么代码物理上存储在0x08000000,但CPU却从0x00000000开始取指?

答案是通过一个叫做地址重映射的机制。这是由芯片厂商(如ST、NXP)在微控制器内部通过硬件实现的。

关键:启动引脚 (Boot Pins)

很多MCU都有启动引脚(如BOOT0, BOOT1)。这些引脚在上电复位时的电平,决定了芯片将什么物理内存映射到启动地址0x0000_0000。

以STM32为例,常见的启动选项有:

  1. 从主Flash启动 (通常模式):

    1. 将引脚配置为从主Flash启动。

    2. 此时,芯片内部的内存控制器会做一个简单的地址偏移映射:

      • 所有对地址 0x0000_0000 的访问,都会被重定向到 0x0800_0000

      • 访问 0x0000_0001 -> 变成访问 0x0800_0001

      • 访问 0x0000_FFFF -> 变成访问 0x0800_FFFF

    3. iCode总线去 0x0000_0000 取指令,内存控制器悄悄地将这个请求转给了 0x0800_0000 位置的Flash存储器。CPU内核完全不知道这个重映射过程,它以为指令就在 0x0000_0000

  2. 从系统存储器启动 (ISP模式):

    1. 芯片内部有一块特殊的BootROM,里面预烧了厂家的串口/USB下载程序。它的物理地址可能是在 0x1FFF_0000

    2. 当配置为从系统存储器启动时,对 0x0000_0000 的访问会被重定向到这片BootROM。

  3. 从内置SRAM启动:

    1. 用于调试。将SRAM(物理地址 0x2000_0000)映射到 0x0000_0000

这个过程可以类比:

  • 你的家(Flash) 实际地址是:幸福路808号(0x0800_0000)。

  • 但市政规定,所有寄到 市中心1号(0x0000_0000) 的包裹,都会自动被邮局转到 幸福路808号。

  • CPU(邮差) 只知道把包裹送到“市中心1号”,它不知道转交过程,但这个包裹最终总能正确送达你的家。


3. 为什么设计成这样?

这种设计非常巧妙,主要有两个优点:

  1. 统一的入口点:

    1. 无论芯片内部Flash的物理地址在哪里,无论你有多少种启动方式,ARM内核CPU硬件永远、且只需要从同一个地址 0x0000_0000 开始取指令。

    2. 这简化了CPU内核的设计,使其不需要关心外部世界的复杂变化。

  2. 极大的灵活性:

    1. 芯片厂商可以通过启动引脚和重映射逻辑,提供多种启动模式,而无需修改CPU核心。

    2. 开发者可以灵活选择从程序Flash启动、从BootLoader启动、或者从RAM启动进行调试,硬件帮你搞定地址转换问题。

4. 一图流总结


图解说明:

  1. 起点 (CPU请求):

    1. CPU 内核的 iCode 总线严格按照 ARM 架构设计,永远从逻辑地址 0x0000 0000 开始取指。这是它的固定行为。

  2. 路由 (总线矩阵):

    1. 这个取指请求首先到达总线矩阵,这是芯片内部的“交通枢纽”。

  3. 决策 (启动配置):

    1. 总线矩阵会根据启动引脚(BOOT0, BOOT1) 的电平状态,决定将这个请求路由到哪里。最常见的情况(用户Flash启动)就是路由到重映射控制器。

  4. 转换 (地址重映射):

    1. 所谓的“重映射控制器”是这个过程的核心。它接收到一个针对 0x0000 0000 的访问请求,然后根据厂家预设的规则,悄悄地将这个请求转换为对物理地址 0x0800 0000 的访问。

  5. 目的地 (物理Flash):

    1. 转换后的请求最终抵达实际的物理硬件:主Flash存储器。指令数据从这里被取出。

  6. 返回数据:

    1. 数据沿着原路返回:Flash -> 重映射控制器 -> 总线矩阵 -> CPU。

    2. CPU 始终认为自己是从 0x0000 0000 读到了数据,它对背后发生的重映射过程一无所知。

核心要点:

  • 逻辑地址 vs. 物理地址: 0x0000 0000 是CPU视角的逻辑地址(它认为的世界)。0x0800 0000 是Flash芯片的物理地址(真实的世界)。

  • 重映射是桥梁: 芯片内部的“重映射”负责将CPU的“逻辑世界”和存储器的“物理世界”连接起来。

  • 对程序员透明: 整个重映射过程由硬件完成,软件工程师无需干预。你只需要知道你的程序被烧录到了 0x0800 0000,并且CPU会正确地从那里开始执行。

总结

  • CPU从 0x0000_0000 开始执行:这是ARM Cortex-M架构规定的、不可改变的硬件行为。

  • Flash物理地址在 0x0800_0000:这是芯片厂商根据ARM的内存映射建议分配的物理地址。

  • 连接二者的桥梁:是芯片内部的重映射机制。它根据启动引脚的配置,将CPU对“启动地址”的访问透明地重定向到不同的物理存储器上(Flash、SRAM或BootROM)。

  • iCode总线:它负责执行取指操作,它发出的是“逻辑地址”(0x0000_0000),但经过重映射后,这个请求被传递到了“物理地址”(0x0800_0000)上的Flash存储器。

所以,0x0000 0000 和 0x0800 0000 这两个地址都是存在的,它们描述的是不同层面的概念:一个是CPU视角的逻辑地址,一个是存储器的物理地址。重映射技术则将这两个视角巧妙地统一了起来。

5. 关于上文的“重映射控制器”

在 ARM Cortex-M3 Technical Reference Manual (cortex-m3技术参考手册) 中,我们不会找到一个名为 “Remapping Controller” (重映射控制器) 的独立模块。

“重映射控制器”是一个为了易于理解而使用的一个功能性的统称,它实际上指向了芯片厂商实现的一系列机制。

核心区别:ARM Cortex-M 内核 vs. 芯片厂商的实现

首先要理解一个关键区别:

  1. ARM Cortex-M 内核: 它定义了CPU核心本身的行为(如寄存器、指令集、NVIC)和它期望看到的固定内存映射(即CPU发出的地址0x0000_0000应该对应什么)。

  2. 芯片厂商 (如ST, NXP, TI): 他们购买ARM的IP授权,然后围绕Cortex-M内核设计自己的芯片(MCU)。他们负责实现内存控制器、Flash、SRAM、外设,并决定如何将物理存储器映射到CPU所期望的地址空间。

我们找不到“重映射控制器”的原因在于:这个“重映射”功能是芯片厂商在它们自己的芯片设计中加入的,不属于ARM Cortex-M核心的标准部分。因此,它不会出现在内核的技术参考手册中,而是描述在芯片厂商的数据手册 (Datasheet) 和参考手册 (Reference Manual) 里。


“重映射”的具体实现方式

芯片厂商通常通过以下两种主要方式来实现地址 0x0000_0000 的“重映射”:

  1. 地址别名 (Address Aliasing) - 最常见的方式

这是最简单、最低成本的方式。它不是一个复杂的“控制器”,而更像是一个固定的地址连线偏移。

  • 工作原理: 在芯片的内部总线结构中,将CPU对地址块 0x0000_0000 - 0x0007_FFFF (例如) 的访问请求,其地址线最高位直接忽略或重新编码,从而定向到物理地址块 0x0800_0000 - 0x0807_FFFF

  • 类比: 这就像是一栋大楼。CPU总是说“我要去101房间”,而大楼的管理系统(芯片设计)硬性规定“所有101房间的请求都自动引导到201房间”。没有复杂的计算,只是一个简单的、固定的规则。

  • 特点: 这种方式是静态的、固定的。一旦芯片制造好,0x0000_0000 就永远别名到 0x0800_0000。启动模式的选择可能是通过改变别名到的目标地址来实现的(见下一条)。

  1. 内存地址重映射开关 (Memory Remap Switch)

一些更复杂的芯片(或Cortex-A系列)会有一个真正的可编程重映射控制器,通常称为 “Remap” 或 “Memory Controller” 功能。

  • 工作原理: 芯片内部存在一个可配置的开关电路。CPU可以通过配置一个特定的控制寄存器来改变这个开关的状态。

  • 这个寄存器: 允许软件动态地改变地址 0x0000_0000 映射到哪一块物理存储器(Flash, SRAM, BootROM)。

  • 在哪里描述: 这个寄存器是芯片厂商自定义的,它的地址、位定义都会写在芯片的参考手册中,通常是在系统配置(System Configuration)或内存控制器(Memory Controller)的章节里。例如,在STM32的参考手册中,你会找到类似“Boot configuration”的寄存器。


以STM32F1系列为例(来自ST的参考手册)

在STM32中,实现“重映射”的机制是上述两种方式的结合:

  1. 固定别名区域: CPU地址 0x0000_0000 - 0x1FFF_FFFF 这块512MB的区域被设计为可重映射的区域。它本身不固定对应任何物理内存。

  2. Boot引脚配置开关: 芯片上电复位时,会采样BOOT0和BOOT1引脚的电平。

  3. 硬件自动配置: 根据引脚电平,芯片内部的硬件逻辑会自动设置一个隐藏的开关,将这个“可重映射区域”连接到三块物理存储器中的一块:

    1. BOOT1=0, BOOT0=0 -> 映射到 Main Flash (物理地址 0x0800_0000)

    2. BOOT1=0, BOOT0=1 -> 映射到 System Memory (BootROM, 物理地址 0x1FFF_0000 等)

    3. BOOT1=1, BOOT0=1 -> 映射到 Embedded SRAM (物理地址 0x2000_0000)

这个过程在复位后由硬件瞬间完成,无需软件初始化。之后,这个映射关系就固定了,直到下一次复位。

总结

  1. 关于“内存重映射”该查阅哪里:

    1. 要理解CPU视角的内存布局,看 《Cortex-M3 Technical Reference Manual》。

    2. 要理解物理芯片的内存布局和重映射实现细节,看 芯片的数据手册 (Datasheet) 和 参考手册 (Reference Manual)。查找 “Boot configuration”、 “Memory organization” 或 “Controller registers” 等章节。

  2. 对程序员的意义:

    1. 对于绝大多数应用程序开发者来说,这个重映射过程是完全透明的。你只需要知道程序计数器从 0x0000_0000 开始,而你的代码链接在 0x0800_0000,硬件会帮你处理好一切。

    2. 只有当你在编写Bootloader或进行非常底层的系统调试时,才需要深入了解BOOT引脚的配置和芯片具体的重映射机制。


文章转载自:

http://MTcrPF55.gywfp.cn
http://qgpoblFU.gywfp.cn
http://PEnPNPmg.gywfp.cn
http://1aTUcJul.gywfp.cn
http://R3Algkqb.gywfp.cn
http://ryAzNpIG.gywfp.cn
http://e6RkL3OQ.gywfp.cn
http://RIWrCzMl.gywfp.cn
http://IJxSQQey.gywfp.cn
http://pVySNTqo.gywfp.cn
http://0HKIqEaB.gywfp.cn
http://FbzNxsGz.gywfp.cn
http://C8fGoqKk.gywfp.cn
http://S1MJ4dUI.gywfp.cn
http://URPvVQSZ.gywfp.cn
http://NoSkAD4j.gywfp.cn
http://NNV3IJiB.gywfp.cn
http://sjT1h9bQ.gywfp.cn
http://JNw0Ft7E.gywfp.cn
http://RekbSOhO.gywfp.cn
http://YMh7iOe8.gywfp.cn
http://RzrqZ7W4.gywfp.cn
http://abx8qauC.gywfp.cn
http://8XKM2JKb.gywfp.cn
http://NP0gaGc0.gywfp.cn
http://RgCzUznQ.gywfp.cn
http://0rzNatG2.gywfp.cn
http://L4unb6wX.gywfp.cn
http://xK6beO8h.gywfp.cn
http://Cm2N8NE3.gywfp.cn
http://www.dtcms.com/a/377346.html

相关文章:

  • 如何使用 QuickAPI 快速连接 MySQL 数据库并发布 RESTful API
  • PAT 1104 Sum of Number Segments
  • LeetCode 热题 3.无重复字符的最长子串
  • 抓虫:unshared后执行命令dump
  • 自定义类型:结构体、枚举、联合
  • SnowPro Core Certification
  • Java 大视界 -- Java 大数据机器学习模型在金融市场情绪分析与投资决策辅助中的应用
  • C++ 学习与 CLion 使用:(十三)分别提供了 CLion 中使用 cout 和 cin 中文乱码的问题
  • 容器编排工具Docker Copmose
  • 黑马点评高级篇第7节课 输入INFO replication 显示0个从节点,但是在7002节点又显示它已经是7001节点的从节点了
  • 单例模式(C++)详解(1)
  • 回声消除AEC初探
  • 9 如何评估 AI 产品的效果
  • C6.9:三极管的四种常用晶体管放大器的简述
  • C语言深度入门系列:第十一篇 - 动态内存管理与数据结构:程序世界的高效算法大师
  • FPGA雷达信号处理之:自适应门限阈值
  • 某个工程 pom.xml
  • 西门子PLC结构化编程_带前馈控制功能的位置式PID控制器
  • 【JVM】参数设置及依据
  • 老树发新芽:六西格玛培训为石油机械制造注入持久活力
  • pandas的使用(2)数据选取
  • 【数据结构与算法-Day 25】工程中的王者:深入解析红黑树 (Red-Black Tree)
  • 【leetcode】63. 不同路径 II
  • 低压电工作业操作证的考试难度如何?
  • 【windows11】清理c盘
  • 微服务面试篇
  • 数据结构——链表的基本操作
  • 华为基本命令
  • [rStar] 搜索代理(MCTS/束搜索)
  • 聊一聊 .NET 某跨境物流系统 内存暴涨分析