- 1、有哪些信誉好的足球投注网站(book118)网站文档一经付费(服务费),不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。。
- 2、本站所有内容均由合作方或网友上传,本站不对文档的完整性、权威性及其观点立场正确性做任何保证或承诺!文档内容仅供研究参考,付费前请自行鉴别。如您付费,意味着您自己接受本站规则且自行承担风险,本站不退款、不进行额外附加服务;查看《如何避免下载的几个坑》。如果您已付费下载过本站文档,您可以点击 这里二次下载。
- 3、如文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“版权申诉”(推荐),也可以打举报电话:400-050-0827(电话支持时间:9:00-18:30)。
- 4、该文档为VIP文档,如果想要下载,成为VIP会员后,下载免费。
- 5、成为VIP后,下载本文档将扣除1次下载权益。下载后,不支持退款、换文档。如有疑问请联系我们。
- 6、成为VIP后,您将拥有八大权益,权益包括:VIP文档下载权益、阅读免打扰、文档格式转换、高级专利检索、专属身份标志、高级客服、多端互通、版权登记。
- 7、VIP文档为合作方或网友上传,每下载1次, 网站将根据用户上传文档的质量评分、类型等,对文档贡献者给予高额补贴、流量扶持。如果你也想贡献VIP文档。上传文档
查看更多
MMAP和DMA 这一章介绍Linux内存管理和内存映射的奥秘。同时讲述设备驱动程序是如何使用“直接内存访问”(DMA)的。尽管你可能反对,认为DMA更属于硬件处理而不是软件接口,但我觉得与硬件控制比起来,它与内存管理更相关。 这一章比较高级;大多数驱动程序的作者并不需要太深入到系统内部。不过理解内存如何工作可以帮助你在设计驱动程序时有效地利用系统的能力。 Linux中的内存管理 这一节不是描述操作系统中内存管理的理论,而是关注于这个理论在Linux实现中的主要特征。本节主要提供一些信息,跳过它不会影响您理解后面一些更面向实现的主题。 页表 当一个程序查一个虚地址时,处理器将地址分成一些位域(bit field)。每个位域被用来索引一个称做页表的数组,以获得要么下一个表的地址,要么是存有这个虚地址的物理页的地址。 为了进行虚地址到物理地址的映射,Linux核心管理三级页表。开始这也许会显得有些奇怪。正如大多数PC程序员所知道的,x86硬件只实现了两级页表。事实上,大多数Linux支持的32位处理器实现两级,但不管怎样核心实现了三级。 在处理器无关的实现中使用三级,使得Linux可以同时支持两级和三级(如Alpha)的处理器,而不必用大量的#ifdef语句把代码搅得一团糟。这种“保守编码”方式并不会给核心在两级处理器上运行时带来额外的开销,因为实际上,编译器已经把没用的一级优化掉了。 但是让我们看一会儿实现换页的数据结构。为了跟上讨论,你应该记住大多数用作内存管理的数据都采用unsigned long的内部表示,因为它们所表示的地址不会再被复引用。 下述几条总结了Linux的三级实现,由图13-1示意: 一个“页目录(Page Directory,PGD)”是顶级页表。PGD是由pgd_t项所组成的数组,每一项指向一个二级页表。每个进程都有它自己的页目录,你可以认为页目录是个页对齐的pgd_t数组。 二级表被称做“中级页目录(Page Mid_level Directory)”或PMD。 PMD是一个页对齐的pmd_t数组。每个pmd_t是个指向三级页表的指针。两级的处理器,如x86和sparc_4c,没有物理PMD;它们将PMD声明为只有一个元素的数组,这个元素的值就是PMD本身——马上我们将会看到C语言是如何处理这种情况以及编译器是如何把这一级优化掉的。 再下一级被简单地称为“页表(Page Table)”。同样地,它也是一个页对齐的数组,每一项被称为“页表项(Page Table Entry)”。核心使用pte_t类型表示每一项。pte_t包含数据页的物理地址。 上面提到的类型都在asm/page.h中定义,每个与换页相关的源文件都必须包含它。 核心在一般程序执行时并不需要为页表查寻操心,因为这是有硬件完成的。不过,核心必须将事情组织好,硬件才能正常工作。它必须构造页表,并在处理器报告一个页面错时(即当处理器需要的虚地址不在内存中时)查找页表,。 下面的符号被用来访问页表。asm/page.h和asm/pgtable.h必须被包含以使它们可以被访问。 (Figure 13.1 Linux的三级页表) PTRS_PER_PGD PTRS_PER_PMD PTRS_PER_PTE 每个页表的大小。两级处理器置PTRS_PER_PMD为1,以避免处理中级。 unsigned long pgd_bal(pgd_t pgd) unsigned long pmd_val(pmd_t pmd) unsigned long pte_val(pte_t pte) 这三个宏被用来从有类型数据项中获取无符号长整数值。这些宏通过在源码中使用严格的数据类型有助于减小计算开销。 pgd_t *pgd_offset(struct mm_struct *mm,unsigned long address) pmd_t *pmd_offset(pgd_t *dir,unsigned long address) pte_t *pte_offset(pmd_t *dir,unsigned long address) 这些线入函数是用于获取与address相关联的pgd,pmd和pte项。页表查询从一个指向结构mm_struct的指针开始。与当前进程内存映射相关联的指针是current-mm。指向核心空间的指针由init_mm描述,它没有被引出到模块,因为它们不需要它。两级处理器定义pmd_offset(dir,add)为(pmd_t( )dir,这样就把pmd折合在pgd上。扫描页表的函数总是被声明为inline,而且编译器优化掉所有pmd查找。 unsigned long pte_page(pte_t pte) 这个函数从页表项中抽取物理页的地址。使用pte
文档评论(0)