网站开发如何dw中小手,深圳全网营销平台排名,龙岩装修公司,怎样做辅导班的网站目录
一、 ARM架构内存映射模型
1.1 页表项
1.2 一级页表映射过程
1.3 二级页表映射过程
1.4 cache 和 buffer
二、 鸿蒙内存映射代码学习
三、 为板子编写内存映射代码
3.1 内存地址范围
3.2 设备地址范围 一、 ARM架构内存映射模型
#xff08;以前我以为页表机制… 目录
一、 ARM架构内存映射模型
1.1 页表项
1.2 一级页表映射过程
1.3 二级页表映射过程
1.4 cache 和 buffer
二、 鸿蒙内存映射代码学习
三、 为板子编写内存映射代码
3.1 内存地址范围
3.2 设备地址范围 一、 ARM架构内存映射模型
以前我以为页表机制是linux这种操作系统规定的今天看了韦东山老师的视频才知道原来这个机制是由架构来规定的。 有一个这样的文档来指导开发A架构的程序。
1.1 页表项 ARM架构支持一级页表映射也就是说MMU根据CPU发来的虚拟地址可以找到第1个页表从第1个页表里就可以知道这个虚拟地址对应的物理地址。一级页表里地址映射的最小单位是1M。 ARM架构还支持二级页表映射也就是说MMU根据CPU发来的虚拟地址先找到第1个页表从第1个页表里就可以知道第2级页表在哪里再取出第2级页表从第2个页表里才能确定这个虚拟地址对应的物理地址。二级页表地址映射的最小单位有4K、1KLinux使用4K。 一级页表项里的内容决定了它是指向一块物理内存还是指问二级页表如下图 页表项就是一个32位的数据里面保存有物理地址还有一些控制信息。 页表项的bit1、bit0表示它是一级页表项还是二级页表项。 对于一级页表项里面含有1M空间的物理基地址这也成为段映射该物理地址也被称为**段基址**。 上图中的TEX、C、B可以用来控制这块空间的访问方法是否使用Cache、Buffer等待。 下图过于复杂我们只需要知道
* 访问外设时不能使用Cache、Buffer * 访问内存时使用Cache、Buffer可以提高速度 * 如果内存用作DMA传输不要使用Cache、Buffer
如下图所示 1.2 一级页表映射过程
使用一级页表时先在内存里设置好各个页表项然后把页表基地址告诉MMU就可以启动MMU了。
以下图为例介绍地址映射过程
* ① CPU发出虚拟地址vaddr假设为0x12345678 * ② MMU根据vaddr[31:20]找到一级页表项 * 虚拟地址0x12345678是虚拟地址空间里第0x123个1M * 所以找到页表里第0x123项根据此项内容知道它是一个段页表项 * 段内偏移是0x45678。
* ③ 从这个表项里取出物理基地址Section Base Address假设是0x81000000 * ④ 物理基地址加上段内偏移得到0x81045678
所以CPU要访问虚拟地址0x12345678时实际上访问的是0x81045678的物理地址。 1.3 二级页表映射过程
先设置好一级页表、二级页表并且把一级页表的首地址告诉MMU。
以下图为例介绍地址映射过程 ① CPU发出虚拟地址vaddr假设为0x12345678 ② MMU根据vaddr[31:20]找到一级页表项 虚拟地址0x12345678是虚拟地址空间里第0x123个1M所以找到页表里第0x123项。 根据此项内容知道它是一个二级页表项。 ③ 从这个表项里取出地址假设是address这表示的是二级页表项的物理地址 ④ vaddr[19:12]表示的是二级页表项中的索引index即0x45在二级页表项中找到第0x45项 ⑤ 二级页表项格式如下 * 里面含有这4K或1K物理空间的基地址page base addr假设是0x81889000 * 它跟vaddr[11:0]组合得到物理地址0x81889000 0x678 0x81889678 * 所以CPU要访问虚拟地址0x12345678时实际上访问的是0x81889678的物理地址
linux二级页表使用的是4K大小
其实还有一个机制就是为什么我们的内存只有16个G时linux能为每个进程分配4个G或者更多的虚拟空间 虚拟内存Linux使用虚拟内存技术它为每个进程提供了一个独立的、连续的虚拟地址空间。这个虚拟地址空间与实际的物理内存是分开的。进程在运行时会在这个虚拟地址空间中请求内存。Linux内核会负责将这些虚拟地址映射到实际的物理内存地址或者当物理内存不足时使用交换空间swap space来存储部分数据。内存管理单元MMU现代计算机硬件中的内存管理单元MMU支持虚拟内存技术。当进程访问内存时MMU负责将虚拟地址转换为物理地址。这意味着尽管物理内存有限但每个进程都可以有自己的虚拟地址空间。页表Linux内核为每个进程维护一个页表该页表记录了虚拟地址到物理地址的映射关系。当进程访问某个虚拟地址时内核会查找相应的页表项将虚拟地址转换为物理地址。如果所请求的数据不在物理内存中即发生了页面错误内核会负责从交换空间或其他地方加载数据。进程隔离虚拟内存还提供了进程隔离的功能。每个进程都有自己的虚拟地址空间因此一个进程无法直接访问另一个进程的内存。这增强了系统的安全性和稳定性。 这个交换空间其实是我们的外存空间比如硬盘将进程一部分不需要立刻执行的资源放到外存里不断的交换到内存去执行这样效率会大大降低但是却可以拥有更多的内存空间。
1.4 cache 和 buffer
ARM的cache和写缓冲器write buffer_arm coretex a7 write buffer-CSDN博客
使用MMU时需要有cache、buffer的知识。 下图是CPU和内存之间的关系有cache、buffer(写缓冲器)。 Cache是一块高速内存写缓冲器相当于一个FIFO可以把多个写操作集合起来一次写入内存。 程序运行时有“局部性原理”这又分为时间局部性、空间局部性。
* 时间局部性 在某个时间点访问了存储器的特定位置很可能在一小段时间里会反复地访问这个位置。
* 空间局部性 访问了存储器的特定位置很可能在不久的将来访问它附近的位置。
而CPU的速度非常快内存的速度相对来说很慢。 CPU要读写比较慢的内存时怎样可以加快速度 根据“局部性原理”可以引入cache
* 读取内存addr处的数据时 * 先看看cache中有没有addr的数据如果有就直接从cache里返回数据这被称为cache命中。 * 如果cache中没有addr的数据则从内存里把数据读入 注意它不是仅仅读入一个数据而是读入一行数据(cache line)。 * 而CPU很可能会再次用到这个addr的数据或是会用到它附近的数据这时就可以快速地从cache中获得数据。
* 写数据 * CPU要写数据时可以直接写内存这很慢也可以先把数据写入cache这很快。 * 但是cache中的数据终究是要写入内存的啊这有2种写策略 * a. 写通(write through) 数据要同时写入cache和内存所以cache和内存中的数据保持一致但是它的效率很低。 能改进吗可以 使用“写缓冲器”cache大哥你把数据给我就可以了我来慢慢写保证帮你写完。 有些写缓冲器有“写合并”的功能比如CPU执行了4条写指令写第0、1、2、3个字节每次写1字节写缓冲器会把这4个写操作合并成一个写操作写word。 对于内存来说这没什么差别但是对于硬件寄存器这就有可能导致问题。 所以对于寄存器操作不会启动buffer功能对于内存操作比如LCD的显存可以启用buffer功能。 * b. 写回(write back) 新数据只是写入cache不会立刻写入内存cache和内存中的数据并不一致。 新数据写入cache时这一行cache被标为“脏”(dirty)当cache不够用时才需要把脏的数据写入内存。 使用写回功能可以大幅提高效率。但是要注意cache和内存中的数据很可能不一致。这在很多时间要小心处理比如CPU产生了新数据DMA把数据从内存搬到网卡这时候就要CPU执行命令先把新数据从cache刷到内存。反过来也是一样的DMA从网卡得过了新数据存在内存里CPU读数据之前先把cache中的数据丢弃。 是否使用cache、是否使用buffer就有4种组合(Linux内核文件arch\arm\include\asm\pgtable-2level.h) 已经不止4种了哦这是3.14版本的 韦东山老师这个是哪个版本不太清楚这四种对应下面的表。 第1种是不使用cache也不使用buffer读写时都直达硬件这适合寄存器的读写。
第2种是不使用cache但是使用buffer写数据时会用buffer进行优化可能会有“写合并”这适合显存的操作。因为对显存很少有读操作基本都是写操作而写操作即使被“合并”也没有关系。
第3种是使用cache不使用buffer就是“write through”适用于只读设备在读数据时用cache加速基本不需要写。
第4种是既使用cache又使用buffer适合一般的内存读写。 二、 鸿蒙内存映射代码学习
分析启动文件kernel\liteos_a\arch\arm\arm\src\startup\reset_vector_up.Sup和mp的区别和我昨天猜测的一样up是单核mp是多核multi-processoruni-processor环境 可以得到下图所示的地址映射关系
* 内存地址 * KERNEL_VMM_BASE开始的这块虚拟地址使用Cache速度快 * UNCACHED_VMM_BASE开始的这块虚拟地址不使用Cache适合DAM传输、LCD Framebuffer等 * 设备空间就是各种外设比如UART、LCD控制器、I2C控制器、中断控制器 * PERIPH_DEVICE_BASE开始的这块虚拟地址不使用Cache不使用Buffer * PERIPH_CACHED_BASE开始的这块虚拟地址使用Cache使用Buffer * PERIPH_UNCACHE_BASE开始的这块虚拟地址不使用Cache但是使用Buffer Liteos-a的地址空间是怎么分配的 KERNEL_VMM_BASE等于0x40000000并且在kernel\liteos_a\kernel\base\include\los_vm_zone.h看到如下语句 #if (PERIPH_UNCACHED_BASE (0xFFFFFFFFU - PERIPH_UNCACHED_SIZE))
#error Kernel virtual memory space has overflowed!
#endif 所以可以粗略地认为
* 内核空间0x40000000 ~ 0xFFFFFFFF * 用户空间0 ~ 0x3FFFFFFF 三、 为板子编写内存映射代码
3.1 内存地址范围
这里我还是以exynos4412为例 找到了一张这个图挺有意思的
下面这个是6ull的内存映射图 下面这个是exynos4412的内存映射图 这里我们要按手册修改这点两个芯片有所不同6uLL是固定的2个G
但是4412是可选的从0x40000000开始可以安3个G的内存条这里我们安了一个G所以就是 从0x40000000~0x80000000
3.2 设备地址范围
IMX6ULL芯片上设备地址分部太零散从0到0x6FFFFFFF都有涉及中间有很多保留的地址不用入下图 如果把0到0x6FFFFFFF全部映射完地址空间不够 正确的做法应该是忽略那些保留的地址空间为各个模块单独映射地址。 但是Liteos-a尚未实现这样的代码(要自己实现也是可以的但是我们先把最小系统移植成功)。 我们至少要映射2个设备的地址UART1(100ASK_IMX6ULL开发板使用UART1)、GIC如下图 所以
// source\vendor\democom\demochip\board\include\board.h
#define PERIPH_PMM_BASE 0x00a00000 // GIC的基地址
#define PERIPH_PMM_SIZE 0x02300000 // 尽可能大一点,以后使用其他外设时就不用映射了
PERIPH_PMM_SIZE也不能太大限制条件是
#if (PERIPH_UNCACHED_BASE (0xFFFFFFFFU - PERIPH_UNCACHED_SIZE))
#error Kernel virtual memory space has overflowed!
#endif
但是我们不用考虑这个问题我们有一个G的内存可以把整个SFR寄存器都进行映射 ... 注意MMU以1MB为单位映射大小要是1MB的倍数。