ARM Linux (S3C6410架构/2.6.35内核)的内存映射(三)

发布者:悠然自在最新更新时间:2016-06-22 来源: eefocus关键字:ARM  Linux  S3C6410架构  2.6.35内核  内存映射 手机看文章 扫描二维码
随时随地手机看文章
这里记录一下Linux内核做二级内存映射的过程,以中断向量表的映射过程为例。

在S3C6410架构下,Linux采用的是粗粒度小页内存管理方式,即内存段(section)的大小为1M,而页(page)的大小为4K。在第一级内存映射中,每一个PGD项覆盖1M的内存区域;如果有二级内存映射的话,每一个PTE项覆盖4K的内存区域。

下面我们来看一下二级内存映射表的设计。如果段的大小是1M而页的大小是4K的话,那么每一张二级映射表即页表中就需要有1M/4K=256个表项。而不论是PGD还是PTE,每一个表项的大小是4字节,即一个长整形数的大小。一张页表的大小为256*4=1024/1K字节,所以,页表的大小与页的大小并不能对并,一张4K大小的内存页可以存得下4张这样的页表。Linux采用了这样一种设计来存放页表:(文件arch/arm/include/asm/pgalloc.h)

 

在一张4K大小的内存页中,存放了4张不同的页表,它们依次是:第一张页表的ARM版本(也被叫做硬件版本),第二张(与第一张表的虚拟空间是连续的)页表的ARM版本,第一张页表的内核版本(也被叫做Linux版本),第二张页表的内核版本。同一张表的内核版本与ARM版本不是连续存放,而是间隔开的。

页表为什么会有内核版本和硬件版本的区分呢?因为内核需要的一些信息(比如dirty、access等)在ARM需要的页表信息中没有,所以Linux需要另外一份满足自己需要的映射表。

可能正是因为页表大小(1K)与页大小(4K)的不匹配,也造成了内存映射计算方面的很多麻烦。直观地来理解,既然每一个一级页表项映射的内存空间是1M,那么在代码中一个一级页表项pgd_t的大小就应该定义为4字节,PGDIR_SIZE应该定义为1M,但事实不是这样:

   [c]
#define PGDIR_SHIFT 21
#define PGDIR_SIZE (1UL << PGDIR_SHIFT)
typedef unsigned long pgd_t[2];
[/c] 

PGDIR_AIZE被定义为2M,而pgd_t被定义为8个字节。其实这两个PGD仍然是互相独立的,并没有任何关联。
这给理解和计算都带来了麻烦,但唯一的一条好处就是更好地解决了页表大小与页大小不匹配的问题。因为每两个相邻的页表是放在一起处理的,所以干脆把两个相邻的PGD也定义在一起,这样当其中的一个被映射时也要保证另一个得到映射。
下面看一个映射中断向量表的实际过程,通过调用栈paging_init()->devicemaps_init()->create_mapping()->alloc_init_section()->alloc_init_pte(),最后到达了函数alloc_init_pte(),这段代码包含了我的注释和打印(以[Michael]开关):

   [c]
static void __init alloc_init_pte(pmd_t *pmd, unsigned long addr,
 unsigned long end, unsigned long pfn,
 const struct mem_type *type)
{
 pte_t *pte;
 printk(MICHAEL_DBG "alloc_init_pte()\n");

if (pmd_none(*pmd)) {
 
 pte = alloc_bootmem_low_pages(2 * PTRS_PER_PTE * sizeof(pte_t));
 printk(MICHAEL_DBG "pmd is still blank, pte = 0x%x\n", pte);
 printk(MICHAEL_DBG "will populate pmd\n");
 __pmd_populate(pmd, __pa(pte) | type->prot_l1);
 }
 

 pte = pte_offset_kernel(pmd, addr);
 do {
  void *linux_pte = (void *)pte;
  void *hw_pte = linux_pte - 2048;

  printk(MICHAEL_DBG "pmd has been populated, pte = 0x%x, pfn = 0x%x, pfn_pte = 0x%x\n", pte, pfn, pfn_pte(pfn, __pgprot(type->prot_pte)));
  printk(MICHAEL_DBG "before set_pte_ext(): hw_pte = 0x%x, *hw_pte = 0x%x, linux_pte = 0x%x, *linux_pte = 0x%x\n", hw_pte, *((unsigned int*)hw_pte), linux_pte, *((unsigned int *)linux_pte));

  set_pte_ext(pte, pfn_pte(pfn, __pgprot(type->prot_pte)), 0);

  printk(MICHAEL_DBG "after set_pte_ext(): hw_pte = 0x%x, *hw_pte = 0x%x, linux_pte = 0x%x, *linux_pte = 0x%x\n", hw_pte, *((unsigned int*)hw_pte), linux_pte, *((unsigned int *)linux_pte));

  pfn  ;
 } while (pte  , addr  = PAGE_SIZE, addr != end);
}
[/c] 

先看前面一段(去掉了注释和打印):

   [c]
if (pmd_none(*pmd)) {
 pte = alloc_bootmem_low_pages(2 * PTRS_PER_PTE * sizeof(pte_t));
 __pmd_populate(pmd, __pa(pte) | type->prot_l1);
 }
[/c] 

先说明一下,因为在S3C6410上,最多只支持内存的二级映射即PGD->PTE->page,所以并不存在真正的PMD,即使当它出现时,它也与PGD相同。
这段代码检查一级映射项PGD是不是空,如果是空的话就说明一级映射还没有建立过,(二级)页表不存在,所以就先通过boomem来申请一张页面做为页表,有了页表就可以填充PGD了,填充PGD的代码__pmd_populate()在《Arm-Linux二级页表的问题》一篇中已经讲过,不再赘述。

这一段执行完之后,页表有了,但页表还是空的,下面要给指定的表项填充内容:

   [c]
 pte = pte_offset_kernel(pmd, addr);
 do {
 set_pte_ext(pte, pfn_pte(pfn, __pgprot(type->prot_pte)), 0);
 pfn  ;
 } while (pte  , addr  = PAGE_SIZE, addr != end);
}
[/c] 

addr是需要映射的页面的物理地址,pte_offset_kernel(pmd, addr)计算出这个物理地址在页表中对应的位置,不过需要注意的是,这里计算出的pte值指的是这个页面所对应的页表项在硬件页表中的位置。接下来调用set_pte_ext(),这是一个依硬件而不同的函数,比如在S3C6410上,它的实现是armv6_set_pte_ext(),是在arch/arm/mm/proc-macros.S文件中用汇编代码实现的。set_pte_ext()的作用是同时填充硬件页表和内核页表。

看一下在skyeye模拟器上运行这个内核的log:
vectors = 0xc02aa000
init_mm.pgd = 0xc0004000, addr = 0xffff0000, pgd_index() = 0x7ff, PGDIR_SHIFT = 21
alloc_init_pte()
pmd is still blank, pte = 0xc02ab000
will populate pmd
__pmd_populate():
&pmdp[0] = 0xc0007ff8, pmdp[0] = 0x502ab021
&pmdp[1] = 0xc0007ffc, pmdp[1] = 0x502ab421
pmd has been populated, pte = 0xc02abfc0, pfn = 0x502aa, pfn_pte = 0x502aa34b
before set_pte_ext(): hw_pte = 0xc02ab7c0, *hw_pte = 0x0, linux_pte = 0xc02abfc0, *linux_pte = 0x0
after set_pte_ext(): hw_pte = 0xc02ab7c0, *hw_pte = 0x502aa02a, linux_pte = 0xc02abfc0, *linux_pte = 0x502aa34b

我们通过bootmem申请到的中断向量表页的位置是0xc02aa000,这已经是一个虚拟地址,但我们需要把它重新映射到指定地址0xffff0000去。在alloc_init_pte()中,首先确认PGD为空,于是申请一页内存做为页表,得到的页面是0xc02ab000,紧挨着中断向量表那一样。

接下来填充PGD。我们要映射的的目标虚拟地址是0xffff0000,它在PGD表中的序号是0xffff0000/1M=0xfff,每个PGD占4字节,而PGD表的开始位置是0xc0004000,所以0xffff0000所对应的PGD的位置是0xc0004000 ((0xffff0000/1M) * 4) = 0xc0007ffc。它是相邻两个PGD中的第二个,前一个PGD在0xc0007ff8。真给PGD的内容呢,先看前一项0xc0007ff8,向这里填的内容是(页表基地址 属性),新得到的页表地址为0xc02ab000,物理地址为0x502ab000,加上属性值0x21,所以向0xc0007ff8填充的PGD内容为0x502ab021。那么相应地,相邻的下一张页表的基地址要加上256*4=1024/1K,即0x400,所以向一个PGD(0xc0007ffc)填充的内容为0x502ab021  0x400 = 0x502ab421。

现在页表有了,下面要做的就是填充指定的页表项。目标虚拟地址0xffff0000在Linux页表中表项的地址是0xc02abfc0,这是由pte_offset_kernel(pmd, addr)计算出来的,然后调用set_pte_ext()写入页表项,汇编代码的细节这里先不深究,只看写入的内容。最后两行打印分别是调用set_pte_ext()前后硬件页表和内核页表的内容,可以看到两张表里的内容都已经填好:

before set_pte_ext(): hw_pte = 0xc02ab7c0, *hw_pte = 0x0, linux_pte = 0xc02abfc0, *linux_pte = 0x0
after set_pte_ext(): hw_pte = 0xc02ab7c0, *hw_pte = 0x502aa02a, linux_pte = 0xc02abfc0, *linux_pte = 0x502aa34b

关键字:ARM  Linux  S3C6410架构  2.6.35内核  内存映射 引用地址:ARM Linux (S3C6410架构/2.6.35内核)的内存映射(三)

上一篇:ARM Linux系统中的用户栈与内核栈
下一篇:ARM Linux (S3C6410架构/2.6.35内核)的内存映射(二)

推荐阅读最新更新时间:2024-03-16 14:58

ARM·存储器配置
关于配置SDRAM的这个程序,因为研究了2天,所以这里最后再复习一下 首先补充一下基本的知识: 运行地址- 链接地址 在SRAM或者SDRAM中执行程序时,PC指向这个地址,那么命令就应该在这个地址里面 ; 加载地址- 存储地址 程序保存在NAND FLSAH中的地址 位置无关码:B,BL,MOV 位置有关码:LDR PC,=Label 【关于Makefile】 sdram.bin : head.S leds.c arm-linux-gcc -c -o head.o head.S arm-linux-gcc -c -o leds.o leds.c arm-linux-l
[单片机]
ARM嵌入式平台的VGA接口设计
大多数嵌入式产品的显示终端都选择LCD,但在某些需要大屏幕显示的应用中,工业级LCD的价格比较昂贵,且现有的大屏幕显示器(包括CRT显示器和LCD显示器)一般都采用统一的15针VGA显示接口。三星公司ARM9芯片S3C2410以其强大的功能和高性价比在目前嵌入式产品中得到广泛的应用。笔者在开发基于ARM嵌入式平台的血液流变测试仪的过程中,成功地利用高性能视频D/A转换芯片ADV7120,将S3C2410自带的LCD扫描式接口转换为VGA接口,使之能够驱动VGA接口的显示器。 1 VGA接口介绍 近年来,业界制定出了众多数字化的显示接口协议,较为典型的是DVI(Digital Visual Interface)。由于数字接口的标
[工业控制]
[Linux 底层]U-boot编译移植
系统版本:Ubuntu18.04-64 编译器版本:gcc version 7.4.0 (Ubuntu/Linaro 7.4.0-1ubuntu1~18.04.1) uboot版本:2018.07 -linux4sam_6.0 板子型号:at91sama5d3x-xplained MCU型号:sama5d36 1、uboot目录如下: 2、在configs/ 文件夹下面有官方的默认配置 # To put environment variables in nandflash (default): sama5d3_xplained_nandflash_defconfig # To put envi
[单片机]
[<font color='red'>Linux</font> 底层]U-boot编译移植
Linux下vim编辑器的使用小技巧
Vim是Linux操作系统中最常用一个编辑器。如配置文件的更改、环境变量的设置等等基本上都是在这个vim编辑器上完成。所以这是Linux系统管理员最常用的一个工具。不过这个工具虽然小,但是其有很多的实用小技巧。有些系统管理员可能并不知道。在此笔者就把这些技巧共享出来,大家若觉得有用,不妨在工作中用用看。 一、备份个性化配置文件。 Vim文本编辑器有很多默认的设置。但是当系统管理员熟悉了这个工具之后,可能这个默认的设置就不符合他们的需求了。为此系统管理员希望能够像Word等文本处理器一样对其进行一些个性化的设置,以方便他们编写配置文件、设置环境变量等等。如系统管理员可能会重新定义某些键的功能、创建一些缩写符号、或者设置特定的
[嵌入式]
基于ARM的在线更新机制的设计实现
0 引言 分散型控制系统中的现场终端一般由控制器和各检测模块构成,它们之间通过一定的通信网络建立数据的交换链路。这种系统具有高可靠、开放性、灵活性、协调性、易维护等优点。然而,该分散型系统也具有终端数量多、分布范围广的特点。一旦终端系统软件存在缺陷或用户提出新的功能和指标要求时,其升级、维护的工作量和成本都非常大。本文针对上述情况,设计了一种方便、灵活、快速及稳定地对MCU节点进行在线更新的机制。基于LPC11C24微控制器组成的CAN网络,采用IAP编程技术(In Application Programming),实现了对目标节点MCU的软件更新功能。 1 LPC11C24单片机和CAN总线 恩智浦半导体(NXP)推出业界首款内嵌
[单片机]
基于<font color='red'>ARM</font>的在线更新机制的设计实现
ARM、DSP、FPGA的技术特点和区别有哪些
ARM、DSP、FPGA与什么区别?各自有什么特点?这是一个很基础的问题,本文对ARM、DSP、FPGA的各自特点和技术进行了分析。 ARM(Advanced RISC Machines)是微处理器行业的一家知名企业,设计了大量高性能、廉价、耗能低的RISC处理器、相关技术及软 件。ARM架构是面向低预算市场设计的第一款RISC微处理器,基本是32位单片机的行业标准,它提供一系列内核、体系扩展、微处理器和系统芯片方案,四 个功能模块可供生产厂商根据不同用户的要求来配置生产。由于所有产品均采用一个通用的软件体系,所以相同的软件可在所有产品中运行。目前ARM在手持设备 市场占有90以上的份额,可以有效地缩短应用程序开发与测试
[单片机]
Arm联合创始人:Arm收购将使美形成新的技术垄断
据thisismoney报道,Arm联合创始人Hermann Hauser警告称,若将Arm出售给英伟达,美国将形成技术垄断。 Hauser称,基于Arm架构设计的芯片无处不在。收购Arm将意味着Arm不再是“半导体行业的瑞士”,它的知识产权可能会让英伟达成为谷歌、Facebook和亚马逊那样的主导力量。 在一封给议会外交事务委员会的信中,Hauser说:“世界上任何一家重要的半导体公司都能获得Arm许可证。” 英伟达有机会成为全球微处理器的准垄断供应商。这将使英伟达在所有处理器领域占据主导地位,并形成另一家美国技术垄断企业。英伟达虽一再强调,它将保持Arm对竞争对手的中立立场,但有人呼吁对该交易进行调查。
[手机便携]
ARM入门笔记
ISP实验 一.背景 由于前面的实验都是用仿真器将代码下载到AT91SAM7S64的SRAM里调试的,还不能在实际的Flash ROM里跑。所以在这个实验中,我们将通过ATMEL提供的SAM-BA 软件和AT91SAM7S64自带的ROMBoot功能,完成AT91SAM7S64的Flash ROOM的在线烧写。 二.实验目的 用前面 I/O口输入实验 的源程序生成二进制文件,下载到AT91SAM7S64的Flash ROM中,且能脱机正确运行。 三.操作方法 1 安装。双击Install SAM-BA.exe文件运行,按提示一步步安装即可。 2 连接好硬件,且使AT91SAM7S64处于RomBoot状态。 3 运行。双
[单片机]
<font color='red'>ARM</font>入门笔记
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

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

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

换一换 更多 相关热搜器件
随便看看
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved