Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2151438
  • 博文数量: 438
  • 博客积分: 3871
  • 博客等级: 中校
  • 技术积分: 6075
  • 用 户 组: 普通用户
  • 注册时间: 2011-09-10 00:11
个人简介

邮箱: wangcong02345@163.com

文章分类

全部博文(438)

文章存档

2017年(15)

2016年(119)

2015年(91)

2014年(62)

2013年(56)

2012年(79)

2011年(16)

分类: LINUX

2016-12-01 17:19:16

一.总体说明


二.代码分析
2.1 在arch/i386/mm/init.c-->paging_init-->pagetable_init
  1. static void __init pagetable_init (void)
  2. {
  3.     //将ZONE_HIGHMEM部分的页目录表修改一下
  4.     //执行后vaddr=0xffc00000(物理地址1020M)(虚拟地址4092M)
  5.     //0xc0101ff0 : 0x00000000 0x00000000 0x00000000 0x00003063
  6.     vaddr = __fix_to_virt(__end_of_fixed_addresses - 1) & PMD_MASK;        //执行后vaddr=0xffc00000
  7.     fixrange_init(vaddr, 0, pgd_base);                                     -->0xc0101ffc处写入0x00003063

  8. #if CONFIG_HIGHMEM
  9.     //执行后vaddr=0xfe000000(物理地址992M)(虚地址4064M离4G还有32M),end=996M  虚地址(4064M-4068M之间)
  10.     //执行后0xc0101fe0 : 0x00004063 0x00000000 0x00000000 0x00000000
  11.     vaddr = PKMAP_BASE;                                                    -->执行后vaddr=0xfe000000
  12.     fixrange_init(vaddr, vaddr + PAGE_SIZE*LAST_PKMAP, pgd_base);          -->0xc0101fe0处写入0x00004063

  13.     pgd = swapper_pg_dir + __pgd_offset(vaddr);   //vaddr=0xfe000000,其pgd_offset=0x3F8,加法运算时0x3F8*4执行后pgd=0xc0101fe0
  14.     pmd = pmd_offset(pgd, vaddr);                 //在pgtable-2level.h中pmd=pgd,所以执行后pmd=0xc0101fe0
  15.     pte = pte_offset(pmd, vaddr);                 //pte=0xc0004000
  16.     pkmap_page_table = pte;                       //pkmap_pate_talbe=0xc0004000  
  17. #endif
  18. }
完成之后页目录表的内容如下:
  1. (gdb) x /1024wx 0xc0101000
  2. ...
  3. 0xc0101f50 <swapper_pg_dir+3920>:    0x350001e3    0x354001e3    0x358001e3    0x35c001e3
  4. 0xc0101f60 <swapper_pg_dir+3936>:    0x360001e3    0x364001e3    0x368001e3    0x36c001e3
  5. 0xc0101f70 <swapper_pg_dir+3952>:    0x370001e3    0x374001e3    0x378001e3    0x37c001e3
  6. 0xc0101f80 <swapper_pg_dir+3968>:    0x00000000    0x00000000    0x00000000    0x00000000   -->这部分是用作vmalloc的
  7. 0xc0101f90 <swapper_pg_dir+3984>:    0x00000000    0x00000000    0x00000000    0x00000000
  8. 0xc0101fa0 <swapper_pg_dir+4000>:    0x00000000    0x00000000    0x00000000    0x00000000
  9. 0xc0101fb0 <swapper_pg_dir+4016>:    0x00000000    0x00000000    0x00000000    0x00000000
  10. 0xc0101fc0 <swapper_pg_dir+4032>:    0x00000000    0x00000000    0x00000000    0x00000000
  11. 0xc0101fd0 <swapper_pg_dir+4048>:    0x00000000    0x00000000    0x00000000    0x00000000
  12. 0xc0101fe0 <swapper_pg_dir+4064>:    0x00004063    0x00000000    0x00000000    0x00000000    -->这部分是用作highmem的
  13. 0xc0101ff0 <swapper_pg_dir+4080>:    0x00000000    0x00000000    0x00000000    0x00003063


2.1 在arch/i386/mm/init.c中L81 paging_init-->kmap_init()
  1. //初始化几个变量kmap_vstart=0xffff5000,kmap_pte=0xc0003fd4,kmap_prot=0x163
  2. void __init kmap_init(void)
  3. {
  4.     unsigned long kmap_vstart;

  5. //FIX_KMAP_BEGIN=9, FIXADDR_TOP=0xffffe000(差2个page到4G),kmap_vstart=(FIXADDR_TOP - ((x) << PAGE_SHIFT))
  6.     kmap_vstart = __fix_to_virt(FIX_KMAP_BEGIN);       //执行后kmap_vstart=0xffff5000 
  7.     kmap_pte = kmap_get_fixmap_pte(kmap_vstart);       //执行后kmap_pte=0xc0003fd4

  8.     kmap_prot = PAGE_KERNEL;
  9. }



2.1 在include/asm/highmem.h中L62
  1. static inline void *kmap(struct page *page)
  2. {
  3.     if (in_interrupt())
  4.         BUG();
  5. //这儿传入参数page=0xc1f56f44,highmem_start_page=0xc1ee0010,所以不能返回直接映射
  6.     if (page < highmem_start_page)    //高端内存在page管理区的地址=0xc1000010+0x38000*68=0xc1ee0010
  7.         return page_address(page);    //如果是直接映射的话,返回page->virtual
  8.     return kmap_high(page);
  9. }
如果是直接映射的话,可直接返回page->virtual
  1. (gdb) p *(struct page*)0xc1000010
  2. $5 = {list = {next = 0xc1000010, prev = 0xc1000010}, mapping = 0x0, index = 0, next_hash = 0x0, count = {counter = 0}, flags = 16384, lru = {next = 0x0, prev = 0x0}, 
  3.     wait = {lock = {lock = 1, magic = 3735899821}, task_list = {next = 0xc100003c, prev = 0xc100003c}}, pprev_hash = 0x0, buffers = 0x0, virtual = 0xc0000000,  //物理地址0x0
  4.   zone = 0xc02cf9c0 <contig_page_data>}

  5. (gdb) p *(struct page*)0xc1000054
  6. $8 = {list = {next = 0xc1000054, prev = 0xc1000054}, mapping = 0x0, index = 0, next_hash = 0x0, count = {counter = 0}, flags = 16384, lru = {next = 0x0, prev = 0x0}, 
  7.     wait = {lock = {lock = 1, magic = 3735899821}, task_list = {next = 0xc1000080, prev = 0xc1000080}}, pprev_hash = 0x0, buffers = 0x0, virtual = 0xc0001000,  //物理地址4096
  8.   zone = 0xc02cf9c0 <contig_page_data>}

2.1 在mm/highmem.c中L128
  1. void *kmap_high(struct page *page)
  2. {
  3.     unsigned long vaddr;
  4.     spin_lock(&kmap_lock);
  5.     vaddr = (unsigned long) page->virtual;
  6.     if (!vaddr)
  7.         vaddr = map_new_virtual(page);
  8.     pkmap_count[PKMAP_NR(vaddr)]++;             //pkmap_count[1]由1-->2
  9.     if (pkmap_count[PKMAP_NR(vaddr)] < 2)
  10.         BUG();
  11.     spin_unlock(&kmap_lock);
  12.     return (void*) vaddr;                      //vaddr=0xfe001000
  13. }
下面是参数page的打印
  1. (gdb) p *page 的地址=0xc1f56f44
  2. $11 = {list = {next = 0xf7daf3bc, prev = 0xf7daf3bc}, mapping = 0xf7daf3bc, index = 0, next_hash = 0x0, count = {counter = 3}, flags = 2113, 
  3.      lru = {next = 0xc1ed562c, prev = 0xc035b42c <inactive_list>}, wait = {lock = {lock = 1, magic = 3735899821}, task_list = {next = 0xc1f56f70, prev = 0xc1f56f70}}, 
  4.      pprev_hash = 0xf7e6cc68,  buffers = 0xf7db6700, virtual = 0x0, zone = 0xc02cfb18 <contig_page_data+344>}
*(struct zone_struct*)0xc02cf9c0 -->zone_DMA
*(struct zone_struct*)0xC02CFA6C -->zone_Normal
*(struct zone_struct*)0xc02cfb18  --> zone_HighMem



在mm/highmem.c中
  1. static inline unsigned long map_new_virtual(struct page *page)
  2. {
  3.     unsigned long vaddr;
  4.     int count;

  5. start:
  6.     count = LAST_PKMAP;                                           //count=1024=0x400
  7.     /* Find an empty entry */
  8.     for (;;) {
  9.         last_pkmap_nr = (last_pkmap_nr + 1) & LAST_PKMAP_MASK;   //执行后last_pkmap_nr=1
  10.         if (!last_pkmap_nr) {
  11.             flush_all_zero_pkmaps();
  12.             count = LAST_PKMAP;
  13.         }
  14.         if (!pkmap_count[last_pkmap_nr])                         //现在数组pkmap_count中都是0
  15.             break;    /* Found a usable entry */
  16.         if (--count)
  17.             continue;

  18.         /*
  19.          * Sleep for somebody else to unmap their entries
  20.          */
  21.         {
  22.             DECLARE_WAITQUEUE(wait, current);

  23.             current->state = TASK_UNINTERRUPTIBLE;
  24.             add_wait_queue(&pkmap_map_wait, &wait);
  25.             spin_unlock(&kmap_lock);
  26.             schedule();
  27.             remove_wait_queue(&pkmap_map_wait, &wait);
  28.             spin_lock(&kmap_lock);

  29.             /* Somebody else might have mapped it while we slept */
  30.             if (page->virtual)
  31.                 return (unsigned long) page->virtual;

  32.             /* Re-start */
  33.             goto start;
  34.         }
  35.     }
  36. //PKMAP_BASE=0xfe000000UL=4064M(离4G有32M)
  37. //#define PKMAP_ADDR(nr)  (PKMAP_BASE + ((nr) << PAGE_SHIFT))是从4064M开始依次加1个page
  38.     vaddr = PKMAP_ADDR(last_pkmap_nr);            //执行后vaddr=0xfe001000
  39.     set_pte(&(pkmap_page_table[last_pkmap_nr]), mk_pte(page, kmap_prot));

  40.     pkmap_count[last_pkmap_nr] = 1;              //last_pkmap_nr=1,pkmap_count[last_pkmap_nr]=1
  41.     page->virtual = (void *) vaddr;              //vaddr0xfe001000

  42.     return vaddr;
  43. }
set_pte前后页表项的数据改变:
  1. (gdb) x /4wx 0xc0004004= &(pkmap_page_table[last_pkmap_nr])
  2. 0xc0004004:    0x00000000    0x00000000    0x00000000    0x00000000
  3. (gdb) x /4wx 0xc0004004
  4. 0xc0004004:    0x3fffd163    0x00000000    0x00000000    0x00000000







阅读(1982) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~