[置顶] Linux 虚拟地址与物理地址的映射关系分析【转】

转自:http://blog.csdn.net/ordeder/article/details/41630945

版权声明:本文为博主(http://blog.csdn.net/ordeder)原创文章,未经博主允许不得转载。

目录(?)[-]

  1. 虚拟空间
  2. 进程虚拟地址的组织
    1. 1 虚拟空间用户空间
    2. 2 内存区间
  3. 系统物理地址的组织
    1. 1 用户空间页面目录映射关系
    2. 2用户空间的映射
    3. 3内核空间虚拟地址的映射
  4. 相关数据结构关系图

Ordeder原创文章,原文链接: http://blog.csdn.net/ordeder/article/details/41630945

源码版本 2.4.0

1. 虚拟空间

0-3G 用户空间  0x00000000  ~ 0xbfffffff

3-4G 内核空间     0xc0000000 ~ 0xffffffff

每个用户进程都有独立的用户空间(虚拟地址0-3),而内核空间是唯一的(相当于共享)

每个进程的用户空间用mm_struct描述,即task_struct.mm。

2.进程虚拟地址的组织

2.1 虚拟空间、用户空间

[cpp] view plain copy

  1. struct mm_struct {
  2. struct vm_area_struct * mmap;   /* list of VMAs */
  3. ...
  4. pgd_t * pgd;                //用于地址映射
  5. atomic_t mm_users;          /* How many users with user space? */
  6. atomic_t mm_count;          /* How many references to "struct mm_struct" (users count as 1) */
  7. int map_count;              /* number of VMAs */
  8. ...
  9. //描述用户空间的段分布:数据段,代码段,堆栈段
  10. unsigned long start_code, end_code, start_data, end_data;
  11. unsigned long start_brk, brk, start_stack;
  12. unsigned long arg_start, arg_end, env_start, env_end;
  13. unsigned long rss, total_vm, locked_vm;
  14. ...
  15. };

以上结构描述了进程的用户空间的结构,其中
pgd_t    是该进程用户空间地址映射到物理地址时使用
vm_area_struct 是进程用户空间已映射到物理空间的虚拟地址区间,mmap是该空间区块组成的链表。

虚拟空间的空洞:虚拟空间还未被映射的区块(即没有被使用),那么就没有vm_area_struct结构

2.2 内存区间

[cpp] view plain copy

  1. /*
  2. * This struct defines a memory VMM memory area. There is one of these
  3. * per VM-area/task.  A VM area is any part of the process virtual memory
  4. * space that has a special rule for the page-fault handlers (ie a shared
  5. * library, the executable area etc).
  6. */
  7. struct vm_area_struct {
  8. struct mm_struct * vm_mm;   /* VM area parameters */
  9. unsigned long vm_start;     //虚拟空间起始地址
  10. unsigned long vm_end;       //终止地址
  11. /* linked list of VM areas per task, sorted by address */
  12. struct vm_area_struct *vm_next;
  13. //该区间的权限及标志
  14. pgprot_t vm_page_prot;
  15. unsigned long vm_flags;
  16. //一些vm_area 的链接
  17. ...
  18. struct vm_operations_struct * vm_ops;
  19. unsigned long vm_pgoff;     /* offset in PAGE_SIZE units, *not* PAGE_CACHE_SIZE */
  20. struct file * vm_file;      //用于将磁盘文件映射至用户空间
  21. ...
  22. };

虚拟空间区间的描述中:
vm_start/vm_end    为该区块的起始和结束地址
vm_file    是在文件映射中使用到,即常用的mmap(fd,...)函数,简单说即将虚拟空间映射至文件在内核的缓冲区,那么这时候访问该虚拟空间将有别于pgd的映射。
vm_operations_struct 为本虚拟区间的操作,其中的nopage函数指针是处理内存缺页而使用的。对于通用的内存映射,该缺页处理函数为do_no_page()将虚拟地址映射到物理地址(匿名映射):分配物理页& 设置pgd & pte。
而对于mmap操作相关的虚拟地址,其缺页处理函数将和文件系统的缺页函数相关,filemap_nopage(),通过文件系统的缺页从磁盘将相关文件块加载如内核缓冲区.

[cpp] view plain copy

  1. struct vm_operations_struct {
  2. void (*open)(struct vm_area_struct * area);
  3. void (*close)(struct vm_area_struct * area);
  4. struct page * (*nopage)(struct vm_area_struct * area, unsigned long address, int write_access);     //缺页操作
  5. };

3.系统物理地址的组织

内核将物理地址按页来组织,struct page描述系统的物理页的信息,但是页的数据内容是不在该结构中的。系统有全局数据 struct page mem_map[],用于记录每个物理页。
页面大小为4kb,在源码中用体现为(PAGE_SHIFT = 12)

[cpp] view plain copy

  1. /*
  2. * Try to keep the most commonly accessed fields in single cache lines
  3. * here (16 bytes or greater).  This ordering should be particularly
  4. * beneficial on 32-bit processors.
  5. *
  6. * The first line is data used in page cache lookup, the second line
  7. * is used for linear searches (eg. clock algorithm scans).
  8. */
  9. typedef struct page {
  10. struct list_head list;
  11. struct address_space *mapping;
  12. unsigned long index;
  13. struct page *next_hash;
  14. atomic_t count;
  15. unsigned long flags;    /* atomic flags, some possibly updated asynchronously */
  16. struct list_head lru;
  17. unsigned long age;
  18. wait_queue_head_t wait;
  19. struct page **pprev_hash;
  20. struct buffer_head * buffers;
  21. void *virtual; /* non-NULL if kmapped */
  22. struct zone_struct *zone;
  23. } mem_map_t;

struct page是用于描述一个物理页面,该结构仅仅是作为描述,也就是说该页面的4kb数据时存储于某个连续的4kb的物理空间(由MMU决定,具体见下文)。其中:
lru    页面缓冲的调度策略(最少使用优先)

题外话:
page也可以用于文件缓冲,相关参数及作用:
buffer_head    是和设备文件相关的操作,例如在文件系统中,file的一个page有4个块,这些块就存储于buffer_head链表指定的内存中。
index 在文件系统中是用于file缓冲的页号。

3.1 用户空间页面目录(映射关系)

进程的虚拟空间描述中,pgd是用于页式存储的映射使用。当内核发生进程切换时,将新进程的pgd载入CR3寄存器,CPU中的MMU单元依据CR3寄存器进行页面映射。

pgd,pmd和pte可以看做是数组,为进程的地址空间到物理空间实现映射。其中虚拟地址的高位地址决定pgd,中间段地址决定pmd,而低位地址决定pte,pte是“page table entry”。
最终定位的pte中存放的即为对应物理页面的指针。

[cpp] view plain copy

  1. typedef struct { unsigned long pte; } pte_t;
  2. typedef struct { unsigned long pmd; } pmd_t;
  3. typedef struct { unsigned long pgd; } pgd_t;
  4. typedef struct { unsigned long pgprot; } pgprot_t;  //操作标志

3.2用户空间的映射:

1. 用户空间的虚拟地址vaddr通过MMU(pgd,pmd,pte)找到对应的页表项x(即为物理地址)
2. 页表项x的高20位是物理也好,物理页号index = x >> PAGE_SHIFT, 同理,index后面补上12个0就是物理页表的首地址。
3. 通过物理页号,我们可以再内核中找到该物理页的描述的指针mem_map[index],当然这个指针是虚拟地址,page结构见上文。

3.3内核空间虚拟地址的映射:

内核空间与物理地址之间有直接的映射关系,而不需要向用户空间那样通过mmu(pgd)。系统空间映射(3G开始)到物理空间0G起始:
例如:
系统内核映像载入的虚拟地址为3G+1M的起始地址,那么对应的物理地址为1M。
紧接着分配在3G+2M开始分配了8M的虚拟地址(物理地址为2-9M)用于PDG
之后预留了16M空间用DMA于存储。
而全局的page结构的mem_page[]数组是在0xc1000000开始的。
所以内核空间虚拟地址到物理地址的转换为:

[cpp] view plain copy

  1. PAGE_OFFSET = 3GB
  2. vitr_to_phys(kadd)
  3. return vadd - PAGE_OFFSET
  4. 内核空间的虚拟地址vaddr是通过如下方式找到它对应物理地址的page结构:
  5. vitr_to_page(vadd)
  6. index = virt_to_phys(kadd) >> PAGE_SHIFT
  7. return mem_map[index]

4. 相关数据结构关系图

说明:

1. 黑色+红色 箭头展示了虚拟地址空间到物理空间的映射关系

2. 蓝色箭头涉涉及到文件的映射操作mmap(),相比匿名映射,文件映射多了文件层的磁盘IO。

时间: 2024-10-24 22:41:30

[置顶] Linux 虚拟地址与物理地址的映射关系分析【转】的相关文章

Linux 虚拟地址与物理地址的映射关系分析

Ordeder原创文章,原文链接: http://blog.csdn.net/ordeder/article/details/41630945 源码版本 2.4.0 1. 虚拟空间 0-3G 用户空间  0x00000000  ~ 0xbfffffff 3-4G 内核空间     0xc0000000 ~ 0xffffffff 每个用户进程都有独立的用户空间(虚拟地址0-3),而内核空间是唯一的(相当于共享) 每个进程的用户空间用mm_struct描述,即task_struct.mm. 2.进程

Linux虚拟地址和物理地址的映射

?背景 一般情况下,Linux系统中,进程的4GB内存空间被划分成为两个部分------用户空间和内核空间,大小分别为0~3G,3~4G.用户进程通常情况下,只能访问用户空间的虚拟地址,不能访问到内核空间.每个进程的用户空间都是完全独立.互不相干的,用户进程各自有不同的页表.而内核空间是由内核负责映射,它并不会跟着进程改变,是固定的.内核空间地址有自己对应的页表,内核的虚拟空间独立于其他程序.3~4G之间的内核空间中,从低地址到高地址依次为:系统物理内存映射区-隔离带-vmalloc虚拟内存分配

Linux驱动虚拟地址和物理地址的映射(转)

原文地址:http://blog.chinaunix.net/uid-20792373-id-2979673.html 参考链接: Linux 虚拟地址与物理地址的映射关系分析  https://blog.csdn.net/ordeder/article/details/41630945 虚拟地址映射到物理地址的学习(linux篇) https://blog.csdn.net/chablin/article/details/79827226 linux--物理地址到虚拟地址映射,ioremap(

[置顶] Linux Malloc分析-从用户空间到内核空间【转】

转自:http://blog.csdn.net/ordeder/article/details/41654509 版权声明:本文为博主(http://blog.csdn.net/ordeder)原创文章,未经博主允许不得转载. 目录(?)[-] 1背景知识 1 进程的用户空间 12 地址映射 malloc 和free 1 用户层 2 内核层 3 虚拟地址与物理地址 总结 参考 附录 本文介绍malloc的实现及其malloc在进行堆扩展操作,并分析了虚拟地址到物理地址是如何实现映射关系. ord

Linux驱动虚拟地址和物理地址的映射

一般情况下,Linux系统中,进程的4GB内存空间被划分成为两个部分------用户空间和内核空间,大小分别为0~3G,3~4G. 用户进程通常情况下,只能访问用户空间的虚拟地址,不能访问到内核空间. 每个进程的用户空间都是完全独立.互不相干的,用户进程各自有不同的页表.而内核空间是由内核负责映射,它并不会跟着进程改变,是固定的.内核空间地址有自己对应的页表,内核的虚拟空间独立于其他程序. 3~4G之间的内核空间中,从低地址到高地址依次为:物理内存映射区-隔离带-vmalloc虚拟内存分配区-隔

虚拟地址与物理地址之间的关系

MMU 请点评 现代操作系统普遍采用虚拟内存管理(Virtual Memory Management)机制,这需要处理器中的MMU(Memory Management Unit,内存管理单元)提供支持,本节简要介绍MMU的作用. 首先引入两个概念,虚拟地址和物理地址.如果处理器没有MMU,或者有MMU但没有启用,CPU执行单元发出的内存地址将直接传到芯片引脚上,被内存芯片(以下称为物理内存,以便与虚拟内存区分)接收,这称为物理地址(Physical Address,以下简称PA),如下图所示.

x86虚拟地址到物理地址的映射学习

这里只谈分页管理的机制,也是目前最重要的内存管理机制. 最初的设计想法: 结构图如下: 页的尺寸是4KB,虚拟地址的前20位用于指定一个物理页,后12位用于访问页内偏移. 页表项的结构: 各个位的含义: P--位0是存在(Present)标志,用于指明表项对地址转换是否有效.P=1表示有效:P=0表示无效.在页转换过程中,如果说涉及的页目录或页表的表项无效,则会导致一个异常.如果P=0,那么除表示表项无效外,其余位可供程序自由使用,如图4-18b所示.例如,操作系统可以使用这些位来保存已存储在磁

虚拟地址与物理地址的映射

对于DSP的每个CPU而言,当由CPU发起的对corePac内部内存(L1,L2内存,片上寄存器地址)的访问(通过store或load指令)时,所访问内存的地址就是物理地址:但当CPU访问corePac外部的内存(如MSM,即多核共享内存或DDR)时,CPU所访问的32位地址就是虚拟地址了,在访问达到外部内存之前,corePac中的XMC模块就会将32位的虚拟地址映射(由16对MAPAX寄存器(同时有地址扩展功能)实现,MPAX支持16个用户自定义的地址段,对每个段执行内存保护与地址扩展(32-

[置顶] linux中fork()函数详解(原创!!实例讲解)

分类: 计算机系统 linux2010-06-01 23:35 60721人阅读 评论(105) 收藏 举报 linux2010存储  一.fork入门知识 一个进程,包括代码.数据和分配给进程的资源.fork()函数通过系统调用创建一个与原来进程几乎完全相同的进程,也就是两个进程可以做完全相同的事,但如果初始参数或者传入的变量不同,两个进程也可以做不同的事.    一个进程调用fork()函数后,系统先给新的进程分配资源,例如存储数据和代码的空间.然后把原来的进程的所有值都复制到新的新进程中,