ARM MMU页表框架

发布者:TranquilDreamer最新更新时间:2022-04-06 来源: eefocus关键字:ARM  MMU 手机看文章 扫描二维码
随时随地手机看文章

先上一张arm mmu的页表结构的通用框图(以下的论述都由该图来逐渐展开):

以上是arm的页表框图的典型结构:即是二级页表结构:


其中第一级页表(L1)是由虚拟地址的高12bit(bits[31:20])组成,所以第一级页表有4096个item,每个item占4个字节,所以一级页表的大小为16KB,而在第一级页表中的每个entry的最低2bit可以用来区分具体是什么种类的页表项,2bit可以区分4种页表项,具体每种页表项的结构如下:

简而言之L1页表的页表项主要有两大类:


第一大类是指向第二级页表(L2页表)的基地址;


第二类直接指向1MB的物理内存


在L1页表中每个表项可以覆盖1MB的内存,由于有4096K个选项(item),所以总计可以覆盖4096K*1MB=4GB的内存空间。


具体对应到linux,由于linux的软件架构是支持3级页表结构,而arm架构实际只有2级的页表结构,所以linux代码中的中间级页表的实现是空的。在linux代码中,第一级的页表的页目录表项用pgd表示,中间级的页表的页目录表项用pud表示(arm架构其实不需要),第三级的页表的页目录表项用pmd表示(由于中间pud是空的,所以pgd=pmd),另外目前arm体系的移动设备中RAM的page大小一般都是4KB/page,所以L1页表中的页表项都是指向fine page table的。


但在linux内核启动的初始化阶段,临时建立页表(initial page tables)以供linux内核初始化提供执行环境,这时L1的页表项使用的就是第二种页表项(section enty),他直接映射的是1M的内存空间。具体的可以参考arch/arm/kernel/head.S中的__create_page_tables函数,限于篇幅,这里就不展开说了。


针对这种section page translation,mmu硬件执行虚拟地址转物理地址的过程如下:


以上在初始化过程使用的临时页表(initial page tables),在内核启动的后期会被覆盖掉,即在paging_init--->map_lowmem函数中会重新建立页表,该函数为物理内存从0地址到低端内存(lowmem_limit)建立一个一一映射的映射表。所谓的一一映射就是物理地址和虚拟地址就差一个固定的偏移量,该偏移量一般就是0xc0000000(呵呵,为什么是0xc0000000?)


说到这里引入一个重要的概念,就是与低端内存相对的高端内存,什么是高端内存?为什么需要高端内存?为了解析这个问题,我们假设我们使用的物理内存有2GB大小,另外由于我们内核空间的地址范围是从3G-4G的空间,并且前面也说到了,linux内核的低端内存空间都是一一映射的,如果不引入高端内存这个概念,全部都使用一一映射的方式,那内核只能访问到1GB的物理内存,但实际上,我们是需要内核在内核空间能够访问所有的4GB的内存大小的,那怎么做到呢?


方法就是我们不让3G-4G的空间都使用一一映射,而是将物理地址的[0x00,fix_addr](fix_addr<1GB)映射到内核空间虚拟地址[0x00+3G,fix_addr+3G],然后将[fix_addr+3G,4G]这段空间保留下来用于动态映射,这样我们可以通过这段虚拟地址来访问从fix_addr到4GB的物理内存空间。怎么做到的呢?


譬如我们想要访问物理地址[fix_addr,4GB]这段区间中的任何一段,我就用宝贵的内核虚拟地址[fix_addr+3G,4G]的一段去映射他,建立好mmu硬件使用的页表,访问完后,将映射清除,将内核的这段虚拟地址释放,以供下次访问其他的物理内存使用。这样就可以达到访问所有4GB的物理内存的目的。


那么内核代码是如何建立映射表的呢?


我们着重从arch/arm/mm/mmu.c中的create_mapping函数来分析。在分析之前我们先看下arm mmu硬件是如何在二级页表结构中,实现虚拟地址转物理地址的。

先贴出原代码(arch/arm/mm/mmu.c):


该函数的功能描述如下:


  Create the page directory entries and any necessary

  page tables for the mapping specified by `md'.  We

  are able to cope here with varying sizes and address

  offsets, and we take full advantage of sections and

  supersections.

line737-line742:参数合法性检查,该函数不为用户空间的虚拟地址建立映射表(记得多问自己一个为什么?)


line744-line750:如果是iomemory,则映射的虚拟地址范围应属于高端内存区间,由于我们这里是常规的memory,即type为MT_MEMORY,所以不会进入该分支


line775: 获得该虚拟地址addr属于第一级页表(L1)的哪个表项,详细跟踪pgd_offset_k函数(定义在:arch/arm/include/asm/pgtable.h),你会发现,我们内核的L1页目录表的基地址位于0xc0004000,而我们的内核代码则是放置在0xc0008000开始的位置。而从0xc0004000到0xc0008000区间大小是16KB,刚好就是L1页表的大小(见文章开头的描述)


在这里需要注意一个概念:内核的页目录表项和进程的页目录表项,内核的页目录表项是对系统所有进程都是公共的;而进程的页目录表项则是跟特定进程相关的,每个应用进程都有自己的页目录表项,但各个进程对应的内核空间的页目录表相都是一样的。正是由于每个进程都有自己的页目录表相,所以才能做到每个进程都可以独立拥有属于自己的[0,3GB]的内存空间。


line778 pgd_addr_end()确保[addr,next]地址不会跨越一个L1表项所能映射的最大内存空间2MB(为什么是2MB而不是1MB呢?这个是linux的一个处理技巧,以后再详细展开说)


line780 alloc_init_pud()函数为定位到的L1页目录表项pgd所指向的二级页表(L2)建立映射表


line784 pdg++下移L1页目录表项pgd,映射下一个2MB空间的虚拟地址到对应的2MB的物理空间。


在这里解析下,为什么L1页目录表项pgd能够映射2MB的虚地地址空间。


在本文的第一个图中,他是arm典型的mmu映射框架图,但并不是linux的,linux映射框架图在它的基础做了些调整和优化。


linux所做的调整描述如下(以下摘自linux内核:arch/arm/include/asm/pgtable-2level.h中提供的注释说明):


/*

 * Hardware-wise, we have a two level page table structure, where the first

 * level has 4096 entries, and the second level has 256 entries.  Each entry

 * is one 32-bit word.  Most of the bits in the second level entry are used

 * by hardware, and there aren't any "accessed" and "dirty" bits.

 *

 * Linux on the other hand has a three level page table structure, which can

 * be wrapped to fit a two level page table structure easily - using the PGD

 * and PTE only.  However, Linux also expects one "PTE" table per page, and

 * at least a "dirty" bit.

 *

 * Therefore, we tweak the implementation slightly - we tell Linux that we

 * have 2048 entries in the first level, each of which is 8 bytes (iow, two

 * hardware pointers to the second level.)  The second level contains two

 * hardware PTE tables arranged contiguously, preceded by Linux versions

 * which contain the state information Linux needs.  We, therefore, end up

 * with 512 entries in the "PTE" level.

 *

 * This leads to the page tables having the following layout:

 *


重要调整说明如下:


L1页表从4096个item变为2048个item,但每个item的大小从原来的4字节变为8个字节。


一个page中,放置2个L2页表,每个还是256项,每项是4个字节,所以总计是256*2*4=2KB,放置在page页的下半部,而上部分放置对应的linux内存管理系统使用的页表,mmu硬件是不会去使用它的。所以刚好 占满一个page页的大小(4KB),这样就不浪费空间了。

有了上面基础,下面再详细的分析以上的line780的函数alloc_init_pud,该函数会最终调用到alloc_init_pte函数:

line598 early_pte_alloc函数判断对应的pmd所指向的L2页表是否存在,如果不存在就分配L2页表,如果存在就返回L2页表所在page页的虚地址。

line572 判断pmd所指向的L2页表是否存在,不存在则通过early_alloc 函数分配PTE_HWTABLE_OFF(512*4=2KB)+PTE_HWTABLE_SIZE(512*4=2KB)总计4KB的一个物理页来存储2个linuxpet 页表+2个hwpte页表。


line574返回这个物理页所在虚拟地址


回到alloc_init_pte函数的line599:

line183 pte_index用来确定该虚拟地址在L2页表中的偏移量。即虚拟地址的bit[12~21]共计9个bit,刚好用于寻址两个L2页表(总计512项)


回到alloc_init_pte函数,其中line605行,是设置L2页表中addr所定位到的页表项(即pte),主要工作就是填充对应物理页的物理地址,以供mmu硬件来实现地址的翻译。


line604~line607循环填充完两个hwpte页表,完成一个2M物理内存的映射表的建立。


line608 将最终调用如下函数:static inline void __pmd_populate(pmd_t *pmdp, phys_addr_t pte, pmdval_t prot)

在执行这个函数之前,2个L2页表已经建立,该函数的作用就是设置L1页表的对应表项,使其指向刚建立的2个L2页表(hwpte0,hwpte1),正如前面所说,由于linux的L1页表项是8个字节大小,所以:


line133 将头4个字节指向hwpte0页表,


line135 将后4个字节指向hwpte1页表,至此L1---〉L2页表的关联已经建立。


line137 是刷新TLB缓冲,使系统的cpu都可以看见该映射的变化


至此已完成struct map_desc *md结构体所指定的虚拟地址到物理地址的映射关系的建立,以供硬件mmu来自动实现虚拟到物理地址的翻译。


以上过程,有选择的将某些细节给省略了,限于篇幅,另外如果明白了这个过程,很细节的可以自己去看相关的代码。譬如上面的set_pte_ext函数,会调用的汇编函数来实现pte表项的设置。

关键字:ARM  MMU 引用地址:ARM MMU页表框架

上一篇:2440烧写flash问题
下一篇:arm堆栈-(堆栈起始地址的选择)

推荐阅读最新更新时间:2024-11-13 13:45

ARM-Linux 内核移植--基于FL2440开发板(修改为Linux单系统)
硬件平台:FL2440开发板 内核版本:2.6.28 主机:ubuntu 11.04 内核版本:2.6.39 本来以为fl2440的nand flash大小为128M,问了客服才知道,现在FL2440使用的是现代的flash,现在都换成256M的了,只是飞凌的bootloader没有相应的修改,它使用的既不是u-boot,也不是vivi,而是自己的bootloader。现在修改bootloader源码中的nand.c 修改如下: //可更改删除分区,分区名字不可改 static struct Partition NandPart = { {0, 0x00020000, boot },
[单片机]
<font color='red'>ARM</font>-Linux 内核移植--基于FL2440开发板(修改为Linux单系统)
对于51单片机和arm9开发板串口通信问题的分析
距离毕设的时间还剩20天左右,这几天一直忙着做毕设,今天终于将51单片机和串口通信的问题解决了,抽出点时间,写一下遇到的问题。不然,过几天又忘了,记录下来也给后续学习的技术宅能提供一点帮助。 我的串口实验是:ARM9 控制板通过串口发送一个指令,51接受到这个指令后,根据这个指令控制小车的运行方式。(为什么不用arm9直接控制小车而采用51控制小车呢? 答:我的想法是电机驱动这一块直接交付给下一级控制器,程序简单,容易实现,况且通过串口,只需解析一个指令就可以实现)。 1、做此类串口通信一定要记得共地,我采用的方法是直接用5v直流输出引出了两个接口,分别为两个控制板供电,这样的话串口通讯的电压没有一点问题。 2、做串口通讯的
[单片机]
三星s5pv210启动过程(ARM Cortex-A8)
S5PV210内部有96Kb的IRAM和64Kb的IROM。 DRAM0的地址:0x2000_0000——0x3FFF_FFFF(512MB)(自带内存) DRAM1的地址:0x4000_0000——0x7FFF_FFFF(1024MB)(扩展内存) SROM的地址: 0x8000_0000——0xAFFF_FFFF(128MB*6)(扩展内存) IROM的地址: 0xD000_0000——0xD000_FFFF(64Kb) ISRAM的地址: 0xD002_0000——0xD003_7FFF(96Kb) SFR的地址: 0xE000_0000——0xFFFF_FFFF(512Mb) IROM结构: BL0:64Kb。 ISRA
[单片机]
ARM_Linux嵌入式开发环境配置
1.打开电脑超级终端进行配置串口(无串口可能还需要USB转串口); 2.安装USB驱动(独立安装,为上电时); 3.打开光盘中的dnw.exe 下载软件,可以看到USB 连接OK。 启动开发板时,把S2打到NOR一边,打开软件DNW,串口,上电,最后接上USB,不行,关电再开一次就OK了. 先按照开发板的内容,做一下,进行整体了解一下。 开发板采用的BIOS是基于三星原来的bootloader 之vivi 改进而来,名为Supervivi,它采用功能菜单的方式,并可以和原来的命令交互模式互相切换。 Supervivi 可以使用JTAG 板( 一般借助H-JTAG软件) 直接烧写入Nor Flash中使用,也可以直接烧
[单片机]
ARM 指令的寻址方式
1、立即寻址 操作数在指令中直接给出 ADD R0,R0,#1 ;R0 R0+1 ADD R0,R0,#0x3f ;R0 R0+0x3f 2、寄存器寻址 操作数在寄存器 ADD R0,R1,R2 ;R0 R1+R2 3、寄存器间接寻址 操作数的地址在寄存器 ADD R0,R1, ;R0 R1+ LDR R0, ;R0 STR R0, ; R0 4、基址变址寻址 操作数地址 = 基址寄存器 + 指令中给出的地址偏移 LDR R0, ;R0 LDR R0, ! ;R0 、R1 R1+4 LDR R0, ,#4 ;R0 、R1 R1+4 LDR R0, ;R0 5、多寄存器寻址 类似寄存器寻址
[单片机]
韦东山ARM裸机学习笔记——S3C2440的串口驱动编程原理
前言 讲解韦东山JZ2440开发板的串口驱动原理,对韦东山在维基教程串口使用内容的一些补充,串口使用点击这里进入。这里主要讲的是串口驱动的编程思路,如何根据s3c2440的芯片手册编写出最简单的串口驱动。 一、串口的初始化 串口初始化包括引脚初始化、串口时钟初始化和中断模式、波特率配置以及参数配置等。 1、引脚初始化 (1)看JZ2440开发板的原理图,可知UART0的引脚是GPH2(TXD0)和GPH3(RXD0)。 (2)到s3c2440芯片手册295页,看GPHCON(GPH控制寄存器),可以需要把GPH2也就是GPHCON 配置为10,GPH3也就是GPHCON 配置为10。 (3)配置引脚为内部上拉,
[单片机]
韦东山<font color='red'>ARM</font>裸机学习笔记——S3C2440的串口驱动编程原理
Keil(MDK-ARM-STM32)系列教程(八)在线调试(Ⅰ)
Ⅰ、写在前面 Keil在线调试的内容有很多,本文带来在线调试常用的内容:Debug Toolbar调试工具栏( 复位、全速运行、停止运行、单步调试、逐行调试、跳出调试、运行到光标行、跳转到暂停行、调试窗口)快捷按钮的详细内容。 Keil工具栏总共有三种:文件工具栏(File Toolbar)、编译工具栏(Build Toolbar)、调试工具栏(Debug Toolbar)。编译工具栏只在编辑模式有效,调试工具栏只在调试模式下有效。文件工具栏在两种模式下都有效。 文件工具栏可以参看文章: Keil(MDK-ARM-STM32)系列教程(二)工具栏详细说明 . Ⅱ、本文要点 调试工具栏是我们在线调试时常用的工具栏(
[单片机]
Keil(MDK-<font color='red'>ARM</font>-STM32)系列教程(八)在线调试(Ⅰ)
浅谈嵌入式指纹识别方案
应用背景 信息化时代,生物识别技术作为信息安全和个人身份识别技术越来越受到人们的重视。指纹作为人体中最明显的外表特征,具有唯一性、终身不变性、易获取、难以复制等优点。随着科学技术的发展,指纹识别已经成为目前最为实用、应用最为广泛的生物识别技术,尤其在民用生物识别技术中。 传统的指纹识别系统都是基于PC机的,这种系统具有识别速度快、样本存储量大、软件设计技术成熟等优点。但是,基于PC机的指纹识别系统由于价格昂贵、移动性能差、功耗高等缺点限制了其应用的进一步扩大。随着32位嵌入式微处理器的推广和应用,为人们设计廉价、便携的指纹识别系统提供了一个技术上的实现平台。 北京恒颐高科技术有限公司作为专业的嵌入式应用开发商和方案提供商,针
[单片机]
浅谈嵌入式指纹识别方案
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved