最近在看arm linux 的mm部分,看的是2.6.8.1,芯片是INTEL PXA255,参考资料有arm linux演艺、《情景分析》等。一遍看下来只能说似懂非懂。这里有几个基础的问题,大家看看我的理解是否正确,另外还有一个小问题我没有理解。

arm 的mmu支持4K,16K,64K等几种页表和1M的段表(section),arm linux用的应该是4K(small page)页表和1M的section。

1M的段表地址比较简单,

[31:20] table index, 2048

[19:0] section index, 1M

4K页表的地址在ARM里是这样设置的:

[31:20] first-level table index,4096

[19:12] second-level table index,256

[11:0] page index

而在arm linux里PGD, PMD, PT的划分又如下:

[31:21] PGD, 2048

[20] PMD, 2

[19:12] PT, 512

但这里的PMD又形同虚设,因为PT一次总是操作相隔256的2的表项,高的为linux,低的为H/W

因此

PTRS_PER_PGD = 2048

PTRS_PER_PTE = 512

PERS_PE_PMD = 1

地址转换的时候,先找到PGD,这是存放在CP15 C2里面的,tssk->mm->pgd里存放每个任务的pgd。switch_mm的时候放入CP15 C2

cpu_switch_mm(next->pgd, next);

mcr p15, 0, r0, c2, c0, 0 @ load page table pointer, r0 = next->pgd

硬件根据CP15 C2的内容找到一个first-level descriptor table,也就是linux里的PGD,其高18位加上虚拟地址va的[31:20] (first-level table index),读取这个地址的内容(第一次读取内存),得到first-level descriptor。

如果first-level descriptor的最低2位是10,表示是section descriptor,则高12位加上va[19:0]就是物理地址。

如果first-level descriptor的最低2位是01,表示是Coarse page table descriptor,高22位(second-level table的地址)加上va[19:12](second-level table index),这个地址读到second-level descriptor(第二次读取内存),高20位加上va[11:0],就是最后的物理地址。

以上工作都是硬件自动完成的,arm linux 要做的,就是设置PGD表(first-level table)和页表(second-level table)。

比如内核的PGD,放在swapper_pg_dir数组的下标0项,同时保存在init_task->mm->pgd中。

但是看到分配页表的函数create_mapping,有个小问题。

static void __init create_mapping(struct map_desc *md)

{

...

while ((virt & 0xfffff || (virt + off) & 0xfffff) && length >= PAGE_SIZE) {

alloc_init_page(virt, virt + off, prot_l1, prot_pte);

virt += PAGE_SIZE;

length -= PAGE_SIZE;

}// 如果地址不是1M对齐的,则先给头上一部分分配页表,按页大小(4K)分配、填充页表

while (length >= (PGDIR_SIZE / 2)) {

alloc_init_section(virt, virt + off, prot_sect);

virt += (PGDIR_SIZE / 2);

length -= (PGDIR_SIZE / 2);

}// 这里的地址已经是1M对齐的了,设置PGD对应项,按1M分配、填充段表

while (length >= PAGE_SIZE) {

alloc_init_page(virt, virt + off, prot_l1, prot_pte);

virt += PAGE_SIZE;

length -= PAGE_SIZE;

}// 1M对齐剩下的尾巴,分配页表

...

}

这里都要设置descriptor的保护位,也就是没有被地址用到的那些位,表示一些状态属性。

alloc_init_section只需要段保护位prot_sect就可以了,这个没什么问题,比如我用的板子,

prot_sect = 0x42e

// 010000101110

// section descriptor

// cache and buffer

// domain = 1,kernel

// ap = 01, read/write

而alloc_init_page由于有first-level table 和 second-level table,需要两个保护位,分别是prot_l1, prot_pte

奇怪的是,代入的两个数值

prot_pte = 0x0

// 没有任何设置

prot_l1 = 0x20

// domain = 1,kernel

因为类型为MEMORY的存储设备,默认的prot_pte和prot_l1都是0。

虽然我用的PXA255开发板,地址是1M对齐的,且后面没有多余的地址,不需要前后两段分配页表(相信多数的处理器和开发板也是这样),但是既然有这样的代码,就应该赋给正确的值。

后面还有一段,映射中断向量表所在的区域

init_maps->physical = virt_to_phys(init_maps);

init_maps->virtual = vectors_base();

init_maps->length = PAGE_SIZE;

init_maps->type = MT_VECTORS;

create_mapping(init_maps);

这里面的保护位就没什么问题

prot_pte = 0xcb

// 11001011

// Extended small page base address

// cache not buffer

// read only?

// TEX = 11

prot_l1 = 0x1

// Coarse page table base address

// domain = 0, user

哪位研究过arm linux mm的朋友能解释一下?

下面是对上面用到的几个函数的展开分析。

static inline void

alloc_init_section(unsigned long virt, unsigned long phys, int prot)

{

pmd_t *pmdp;

pmdp = pmd_offset(pgd_offset_k(virt), virt);

// 展开为(pmd_t *)init_mm->pgd + (virt) >> 21, the high 11bit of va

// 得到虚拟地址virt 在 first-level table中的位置

if (virt & (1 << 20))

pmdp++; // linux 的 pmd

set_pmd(pmdp, __pmd(phys | prot));

// *pmdp = phys | prot

}

static inline void

alloc_init_page(unsigned long virt, unsigned long phys, unsigned int prot_l1, pgprot_t prot)

{

pmd_t *pmdp;

pte_t *ptep;

pmdp = pmd_offset(pgd_offset_k(virt), virt);

// 展开为(pmd_t *)init_mm->pgd + (virt) >> 21, the high 11bit of va

// 得到虚拟地址virt 在 first-level table中的位置

if (pmd_none(*pmdp)) { // 如果pmdp没设置过,分配一个second_level table

unsigned long pmdval;

ptep = alloc_bootmem_low_pages(2 * PTRS_PER_PTE *

sizeof(pte_t));

// alloc second_level table

pmdval = __pa(ptep) | prot_l1;

pmdp[0] = __pmd(pmdval);

pmdp[1] = __pmd(pmdval + 256 * sizeof(pte_t));

// 在这里填充first-level table对应项

flush_pmd_entry(pmdp);

}

ptep = pte_offset_kernel(pmdp, virt);

set_pte(ptep, pfn_pte(phys >> PAGE_SHIFT, prot));

// str r1, [r0]

// *ptep = pfn_pte(phys >> PAGE_SHIFT, prot),物理地址高20位加上保护位,放到一个second_level table 中的对应项

}

阅读(1089) | 评论(0) | 转发(0) |

linux页表,arm linux 页表(转)相关推荐

  1. 【Qt开发】【VS开发】【Linux开发】OpenCV、Qt-MinGw、Qt-msvc、VS2010、VS2015、Ubuntu Linux、ARM Linux中几个特别容易混淆的内容...

    [Qt开发][VS开发][Linux开发]OpenCV.Qt-MinGw.Qt-msvc.VS2010.VS2015.Ubuntu Linux.ARM Linux中几个特别容易混淆的内容 标签:[Qt ...

  2. linux pfn,ARM Linux下的page和pfn之间转换的宏。

    ARM Linux下的page和pfn之间转换的宏如下: 1)page_to_pfn 2)pfn_to_page 这两个宏依赖于内核编译时,选择的内存模型.在include/asm-generic/m ...

  3. linux usb网卡驱动 ko,qf9700 USB网卡在x86 linux和arm linux上的驱动安装以及配置

    最近要在一块老板子上面移植openwrt,需要扩展网口,于是选择了qf9700这款USB网卡,附赠的光盘里面有提供在linux下面安装的驱动源代码,所以我们要自己编译驱动源代码生成内核加载模块,加载模 ...

  4. ffmpeg arm linux编译,arm linux 移植 ffmpeg 库 + x264 + x265

    背景 Ffmpeg 中带有h264的解码,没有编码,需要添加x264.libx264是一个自由的H.264编码库,是x264项目的一部分,使用广泛,ffmpeg的H.264实现就是用的libx264. ...

  5. linux perf arm,linux kernel perf event(counter)

    最近接到一个客户bug,说是运行perf fuzzer的时候,手机会crash掉.当时我懵了.Perf fuzzer是什么鬼. 经过坚持不懈的google之后,终于找到了一些资料. perf coun ...

  6. arm linux tcp,ARM Linux多连接TCP服务器的应用程序设计

    嵌入式Linux工控主板EM9160的主要功能之一就是作为网络平台,工控领域中比较常见的网络应用是利用TCP/IP协议进行数据通讯.在网络应用中,通常都实现多连接的应用需求,本文主要介绍EM9160作 ...

  7. ARM Linux摄像头传感器数据处理全景视野:从板端编码视频到高级应用

    ARM Linux摄像头传感器数据处理全景视野:从板端编码视频到高级应用 1. 摄像头传感器与数据采集(Camera Sensor and Data Acquisition) 1.1 数字摄像头传感器 ...

  8. arm linux 进程页表,arm-linux内存页表创建

    linux的内存(正式)页表是在内核代码执行到start_kernel函数后执行paging _init函数建立的,这里要注意一个事情就是说,这里paging_init函数可以正常创建内存页表的条件有 ...

  9. arm的2级页表在Linux内核创建过程解析

    系统DDR的基地址为0x0,内存为1GB,所以TTB的基地址为0x4000.下面要创建虚拟地址0xfe700000到物理地址0xffff0000之间的映射,映射大小为64KB,即16页.由于物理地址不 ...

最新文章

  1. IBATIS + ORACLE(二)
  2. linux访问文档根目录之外的网页_开发文档加载不再卡顿,亿点点提升
  3. svn 与 vs2010
  4. Adobe illustrator 直接选择工具删除白板 - 连载 6
  5. easyui-super-theme后台模板
  6. 在HTML5 canvas里用卷积核进行图像处理
  7. vue router 跳转php,vue路由:路由跳转后怎么知道切换到那个router-view中
  8. python读取csv文件坐标地图描点_python3 通过百度地图API获取城市POI点并存于CSV格式...
  9. 如何实现一个符合规范的Promise
  10. Jquery的validate表单验证
  11. 月薪一万的北漂可以过上什么样的生活?
  12. 动手写简单的音乐推荐系统
  13. 二进制颜色查询对照表
  14. 埃航坠机事件调查结果公布时间!
  15. 用众城计算机弹学猫叫,19年真男神当众被逼学猫叫?谁能把我的童年还给我!...
  16. springboot整合jwt_springboot整合jwt实现身份验证
  17. Python 书籍 搜索
  18. iastora怎么改成ahci_Win10系统无需重装,硬盘IDE改为AHCI模式的方法
  19. OSChina 周四乱弹 ——世界欠你一个奥斯卡
  20. 2023计算机考研英语考一吗?考研英语一与英语二的区别

热门文章

  1. linux6 epel yum源,CentOS6下yum源与epel源配置
  2. eclipse html自动对齐,MyEclipse和Eclipse中jsp、html格式化自动排版问题
  3. python半年能达到什么程度_花半年的时间能把Python自学到什么程度?
  4. 子组件调用父组件方法_Vuejs组件(一)组件的注册使用方法
  5. 捷信达登录信息代码133_报名!广州40所热门民办初中学费均价38678,有学校涨幅133%...
  6. 调查了6万多名开发者后,我们发现了这些...
  7. 一位头发发白的神人教你怎么写程序,运维,买电脑,写文章,平面设计!
  8. composer mysql_php – 无法看到mysql数据库时,composer安装失败
  9. 《c语言从入门到精通》看书笔记——第2章 算法
  10. Linux下make使用gcc编译,Linux下GCC和Makefile实例(从GCC的编译到Makefile的引入)