始创于2000年 股票代码:831685
咨询热线:0371-60135900 注册有礼 登录
  • 挂牌上市企业
  • 60秒人工响应
  • 99.99%连通率
  • 7*24h人工
  • 故障100倍补偿
您的位置: 网站首页 > 帮助中心>文章内容

深入理解Linux内存映射机制 (1)

发布时间:  2012/8/15 18:17:27

一. 绪 论
二. X86的硬件寻址方法
三. 内核对页表的设置
四. 实例分析映射机制

一. 绪 论
我们经常在程序的反汇编代码中看到一些类似0x32118965这样的地址,操作系统中称为线性地址,或虚拟地址。虚拟地址有什么用?虚拟地址又是如何转换为物理内存地址的呢?本章将对此作一个简要阐述。
1.1 Linux内存寻址概述
现代意义上的操作系统都处于32位保护模式下。每个进程一般都能寻址4G的物理空间。但是我们的物理内存一般都是几百M,进程怎么能获得4G的物理空间呢?这就是使用了虚拟地址的好处,通常我们使用一种叫做虚拟内存的技术来实现,因为可以使用硬盘中的一部分来当作内存使用。例外一点现在操作系统都划分为系统空间和用户空间,使用虚拟地址可以很好的保护内核空间被用户空间破坏。
对于虚拟地址如何转为物理地址,这个转换过程有操作系统和CPU共同完成. 操作系统为CPU设置好页表。CPU通过MMU单元进行地址转换。
1.2 浏览内核代码的工具
现在的内核都很大, 因此我们需要某种工具来阅读庞大的源代码体系,现在的内核开发工具都选用vim ctag cscope浏览内核代码,网上已有现成的makefile文件用来生成ctags/cscope/etags。
一、用法:
找一个空目录,把附件Makefile拷贝进去。然后在该目录中选择性地运行如下make命令:
$ make
将处理/usr/src/linux下的源文件,在当前目录生成ctags, cscope
注:SRCDIR用来指定内核源代码目录,如果没有指定,则缺省为/usr/src/linux/
1) 只创建ctags
$ make SRCDIR=/usr/src/linux-2.6.12/ tags
2) 只创建cscope
$ make SRCDIR=/usr/src/linux-2.6.12/ cscope
3) 创建ctags和cscope
$ make SRCDIR=/usr/src/linux-2.6.12/
4) 只创建etags
$ make SRCDIR=/usr/src/linux-2.6.12/ TAGS

二、处理时包括的内核源文件:
1) 不包括drivers,sound目录
2) 不包括无关的体系结构目录
3) fs目录只包括顶层目录和ext2,proc目录

三、最简单的ctags命令
1) 进入
进入vim后,用
:tag func_name
跳到函数func_name
2) 看函数(identifier)
想进入光标所在的函数,用
CTRL ]
3) 回退
回退用 CTRL T

1.3 内核版本的选取
本次论文分析, 我选取的是linux-2.6.10版本的内核。最新的内核代码为2.6.25。但是现在主流的服务器都使用的是RedHat AS4的机器,它使用2.6.9的内核。我选取2.6.10是因为它很接近2.6.9,现在红帽企业Linux 4以Linux2.6.9内核为基础,是最稳定、最强大的商业产品。在2004年期间,Fedora等开源项目为Linux 2.6内核技术的更加成熟提供了一个环境,这使得红帽企业 Linux v.4内核可以提供比以前版本更多更好的

功能和算法,具体包括:
• 通用的逻辑CPU调度程序:处理多内核和超线程CPU。
• 基于对象的逆向映射虚拟内存:提高了内存受限系统的性能。
• 读复制更新:针对操作系统数据结构的SMP算法优化。
• 多I/O调度程序:可根据应用环境进行选择。
• 增强的SMP和NUMA支持:提高了大型服务器的性能和可扩展性。
• 网络中断缓和(NAPI):提高了大流量网络的性能。
Linux 2.6 内核使用了许多技术来改进对大量内存的使用,使得 Linux 比以往任何时候都更适用于企业。包括反向映射(reverse mapping)、使用更大的内存页、页表条目存储在高端内存中,以及更稳定的管理器。因此,我选取linux-2.6.10内核版本作为分析对象。

 

二. X86的硬件寻址方法
请参考Intel x86手册^_^

 

三. 内核对页表的设置
CPU做出映射的前提是操作系统要为其准备好内核页表,而对于页表的设置,内核在系统启动的初期和系统初始化完成后都分别进行了设置。
3.1 与内存映射相关的几个宏
这几个宏把无符号整数转换成对应的类型
#define __pte(x) ((pte_t) { (x) } )
#define __pmd(x) ((pmd_t) { (x) } )
#define __pgd(x) ((pgd_t) { (x) } )
#define __pgprot(x) ((pgprot_t) { (x) } )

根据x把它转换成对应的无符号整数
#define pte_val(x) ((x).pte_low)
#define pmd_val(x) ((x).pmd)
#define pgd_val(x) ((x).pgd)
#define pgprot_val(x) ((x).pgprot)

把内核空间的线性地址转换为物理地址
#define __pa(x) ((unsigned long)(x)-PAGE_OFFSET)

把物理地址转化为线性地址
#define __va(x) ((void *)((unsigned long)(x) PAGE_OFFSET))

x是页表项值, 通过pte_pfn得到其对应的物理页框号, 最后通过pfn_to_page得到对应的物理页描述符
#define pte_page(x) pfn_to_page(pte_pfn(x))

如果对应的表项值为0, 返回1
#define pte_none(x) (!(x).pte_low)

x是页表项值, 右移12位后得到其对应的物理页框号
#define pte_pfn(x) ((unsigned long)(((x).pte_low >> PAGE_SHIFT)))
根据页框号和页表项的属性值合并成一个页表项值
#define pfn_pte(pfn, prot) __pte(((pfn) << PAGE_SHIFT) | pgprot_val(prot))

根据页框号和页表项的属性值合并成一个中间表项值
#define pfn_pmd(pfn, prot) __pmd(((pfn) << PAGE_SHIFT) | pgprot_val(prot))

向一个表项中写入指定的值
#define set_pte(pteptr, pteval) (*(pteptr) = pteval)
#define set_pte_atomic(pteptr, pteval) set_pte(pteptr,pteval)
#define set_pmd(pmdptr, pmdval) (*(pmdptr) = pmdval)
#define set_pgd(pgdptr, pgdval) (*(pgdptr) = pgdval)

根据线性地址得到高10位值, 也就是在目录表中的索引
#define pgd_index(address) (((address)>>PGDIR_SHIFT) & (PTRS_PER_PGD-1))

根据页描述符和属性得到一个页表项值
#define mk_pte(page, pgprot) pfn_pte(page_to_pfn(page), (pgprot))
3.2内核页表的初始化
内核在进入保护模式前, 还没有启用分页功能, 在这之前内核要先建立一个临时内核

亿恩科技地址(ADD):郑州市黄河路129号天一大厦608室 邮编(ZIP):450008 传真(FAX):0371-60123888
   联系:亿恩小凡
   QQ:89317007
   电话:0371-63322206


本文出自:亿恩科技【www.enkj.com】

服务器租用/服务器托管中国五强!虚拟主机域名注册顶级提供商!15年品质保障!--亿恩科技[ENKJ.COM]

  • 您可能在找
  • 亿恩北京公司:
  • 经营性ICP/ISP证:京B2-20150015
  • 亿恩郑州公司:
  • 经营性ICP/ISP/IDC证:豫B1.B2-20060070
  • 亿恩南昌公司:
  • 经营性ICP/ISP证:赣B2-20080012
  • 服务器/云主机 24小时售后服务电话:0371-60135900
  • 虚拟主机/智能建站 24小时售后服务电话:0371-60135900
  • 专注服务器托管17年
    扫扫关注-微信公众号
    0371-60135900
    Copyright© 1999-2019 ENKJ All Rights Reserved 亿恩科技 版权所有  地址:郑州市高新区翠竹街1号总部企业基地亿恩大厦  法律顾问:河南亚太人律师事务所郝建锋、杜慧月律师   京公网安备41019702002023号
      0
     
     
     
     

    0371-60135900
    7*24小时客服服务热线