zoukankan      html  css  js  c++  java
  • Linux 虚拟地址与物理地址的映射关系分析【转】

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

    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 虚拟空间、用户空间

    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 内存区间

    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.  
       
    12.  
      /* linked list of VM areas per task, sorted by address */
    13.  
      struct vm_area_struct *vm_next;
    14.  
       
    15.  
      //该区间的权限及标志
    16.  
      pgprot_t vm_page_prot;
    17.  
      unsigned long vm_flags;
    18.  
       
    19.  
      //一些vm_area 的链接
    20.  
      ...
    21.  
      struct vm_operations_struct * vm_ops;
    22.  
      unsigned long vm_pgoff; /* offset in PAGE_SIZE units, *not* PAGE_CACHE_SIZE */
    23.  
      struct file * vm_file; //用于将磁盘文件映射至用户空间
    24.  
      ...
    25.  
      };


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

    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)

    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中存放的即为对应物理页面的指针。

    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开始的。
    所以内核空间虚拟地址到物理地址的转换为:

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

    4. 相关数据结构关系图

    说明:

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

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

  • 相关阅读:
    element表格添加序号
    ZOJ 3822 Domination(概率dp)
    HDU 3037(Lucas定理)
    HDU 5033 Building(单调栈维护凸包)
    HDU 5037 Frog(贪心)
    HDU 5040 Instrusive(BFS+优先队列)
    HDU 5120 Intersection(几何模板题)
    HDU 5115 Dire Wolf(区间dp)
    HDU 5119 Happy Matt Friends(dp+位运算)
    C++ string详解
  • 原文地址:https://www.cnblogs.com/sky-heaven/p/13526745.html
Copyright © 2011-2022 走看看