一. 绪 论

二. 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】

linux应用对物理内存映射,深入理解Linux内存映射机制 (1)相关推荐

  1. 《Linux Device Drivers》第十五章 内存映射和DMA——note

    简单介绍 很多类型的驱动程序编程都须要了解一些虚拟内存子系统怎样工作的知识 当遇到更为复杂.性能要求更为苛刻的子系统时,本章所讨论的内容迟早都要用到 本章的内容分成三个部分 讲述mmap系统调用的实现 ...

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

    这里记录一下Linux内核做二级内存映射的过程,以中断向量表的映射过程为例. 在S3C6410架构下,Linux采用的是粗粒度小页内存管理方式,即内存段(section)的大小为1M,而页(page) ...

  3. Linux学习之系统编程篇:mmap 内存映射区

    (1)作用:将磁盘文件的数据映射内存,用户通过修改内存就能修改磁盘文件. (2)函数原型: void *mmap(void *addr, size_t length, int prot, int fl ...

  4. 嵌入式Linux系统编程学习之二十二内存映射

    文章目录 前言 一.mmap函数 二.munmap函数 三.补充 前言   内存映射函数包括 mmap.munmap 和 msync,其原型为: #include <unistd.h>#i ...

  5. C语言 mmap ( 建立内存映射 ) 、munmap ( 解除内存映射 )

    ================================================ mmap ( 建立内存映射 ) 头文件 #include <unistd.h> #incl ...

  6. linux c 网络事件 通知,深入理解Linux网络技术内幕—通知链

    内核的很多子系统之间具有很强的相互依赖关系,其中一个子系统发现的或产生的事件,其他子系统可能都有兴趣.为了实现这种交互需求,Linux使用了通知链(Notification Chain)机制. 通知链 ...

  7. linux执行class文件_深入理解linux内核——可执行文件执行过程(2)

    接上篇.. 13.调用do_mmap()函数创建一个新线性区来对可执行文件正文段(即代码)进行映射.这个线性区的起始线性地址依赖于可执行文件的格式,因为程序的可执行代码通常是不可重定位的.因此,这个函 ...

  8. linux 文件可执行_深入理解linux内核——可执行文件执行过程(2)

    接上篇.. 13.调用do_mmap()函数创建一个新线性区来对可执行文件正文段(即代码)进行映射.这个线性区的起始线性地址依赖于可执行文件的格式,因为程序的可执行代码通常是不可重定位的.因此,这个函 ...

  9. 一步一图带你深入理解 Linux 虚拟内存管理

    从本文开始我们就正式开启了 Linux 内核内存管理子系统源码解析系列,笔者还是会秉承之前系列文章的风格,采用一步一图的方式先是详细介绍相关原理,在保证大家清晰理解原理的基础上,我们再来一步一步的解析 ...

最新文章

  1. 中职 学生学php学什么区别,职业高中和中专的区别是什么?哪个学历高
  2. 愿...统一沟通...易行天下!
  3. mysql backup_Mysqlbackup 备份详解(mysql官方备份工具)
  4. 计算机与程序设计语言教案,计算机程序设计(c语言)教案
  5. Homebrew软件包管理器中发现RCE漏洞,小心你的Mac和Linux
  6. step5 . day3 网络编程 基于TPC协议的网络编程Demo,类FTP功能
  7. 第35届MPD软件工作坊深圳站圆满落幕
  8. python学习笔记(五)
  9. PHP 数组排序函数sort,rsort,ksort,krsort,asort,arsort区别
  10. windows 安装jenkins
  11. Graduation Speech 毕业典礼致辞__转载
  12. python 百度文库_百度文库文档下载地址解析python版【摸索不易,还请支持】
  13. 百度竞价开户优化的细节到底是哪些
  14. python excel处理 pandas 统计重复数据
  15. lstm中look_back的大小选择_基于时空关联度加权的LSTM短时交通速度预测
  16. 外置存储权限在哪打开_安卓手机外置sd卡的权限怎么打开?
  17. 三十六计珍藏版(下)
  18. 常用运行命令win10
  19. Selenium自动化测试框架—简单了解
  20. 00012.01抽象类与抽象方法(abstract)

热门文章

  1. java实现次方的运算_【技术干货】Java 面试宝典:Java 基础部分(1)
  2. 网站“设为首页”代码,“加入收藏”代码
  3. CF938G Shortest Path Queries
  4. VBA 打开文件对话框
  5. 谷歌提出COMISR算法:针对视频压缩的压缩感知超分辨率
  6. 首次公开!华为最前沿的X Labs实验室都在研究什么?5G+CV
  7. 如何赋予自主系统具备持续学习的能力?
  8. ICCV 2019 Oral | 解读北大提出的期望最大化注意力网络EMANet
  9. mysql6位数货币大写,生成数字+英文字母大小写彩虹字符集(6位),共有62^6种可能_MySQL...
  10. CVPR2021 | 深度解读RepVGG!