免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 8644 | 回复: 1

[FreeBSD] freebsd9.2-将物理页框添加到页框池中 [复制链接]

论坛徽章:
0
发表于 2014-07-17 22:55 |显示全部楼层
有了前面已经初始化后的数据结构做准备,函数vm_page_startup的最后一部分已经很容易理解了,下面简单分析一下,
为函数vm_page_startup做一个简单的收尾。

[函数vm_phys_add_page]:
  1. /***************************************************************************************
  2. * 在函数vm_page_startup的最后阶段,下面的for循环会将包含在物理内存区域
  3.    (phys_avail[i],phys_avail[i + 1])中的物理页框添加到相应的空闲物理
  4.    页框队列中。

  5.    426-427:
  6.    将下面两个系统范围内的计数器清零。
  7.    u_int v_page_count;        total number of pages in system
  8.    u_int v_free_count;         pages free

  9.    428:
  10.    "vm.blacklist"是kernel中的一个环境变量,这个环境变量在代码里面检索了一下,
  11.     没有明显的设置,貌似是在boot和loader阶段进行了相关设置。不过根据函数
  12.     vm_page_blacklist_lookup的实现来看,list上包含一些entries,这些entry通过
  13.     空格或者逗号分隔,vm_page_blacklist_lookup函数将这些entry转换成整数,然后
  14.     和待检查的物理页框的物理地址做比较,如果相等,就忽略待检查的物理页框,因为
  15.     其在"黑名列表中"。

  16.    429-441:
  17.    检查物理内存内存区域(phys_avail[i],phys_avail[i + 1])。
  18.    对于在待检查物理内存区域中的每一个物理页框:
  19.    如果list非空,就调用函数vm_page_blacklist_lookup检查其是否在"黑名单列表中",如果
  20.    在,就不对这个物理页框做进一步的处理。
  21.    
  22.    否则,调用函数vm_phys_add_page将物理页框添加空闲物理页框队列中。

  23.    439:检查下一个物理页框。
  24. *************************************************************/
  25.    422                /*
  26.    423                 * Add every available physical page that is not blacklisted to
  27.    424                 * the free lists.
  28.    425                 */
  29.    426                cnt.v_page_count = 0;
  30.    427                cnt.v_free_count = 0;
  31.    428                list = getenv("vm.blacklist");
  32.    429                for (i = 0; phys_avail[i + 1] != 0; i += 2) {
  33.    430                        pa = phys_avail[i];
  34.    431                        last_pa = phys_avail[i + 1];
  35.    432                        while (pa < last_pa) {
  36.    433                                if (list != NULL &&
  37.    434                                    vm_page_blacklist_lookup(list, pa))
  38.    435                                        printf("Skipping page with pa 0x%jx\n",
  39.    436                                            (uintmax_t)pa);
  40.    437                                else
  41.    438                                        vm_phys_add_page(pa);
  42.    439                                pa += PAGE_SIZE;
  43.    440                        }
  44.    441                }
  45.    442                freeenv(list);
复制代码
[函数vm_phys_add_page]:
  1. /****************************************************************************************
  2. * 参数描述:
  3.    pa:物理页框的物理地址。

  4.    408:递增相应的计数器。

  5.    409:vm_phys_paddr_to_vm_page函数返回描述物理页框的页框描述符。
  6.    412:vm_phys_paddr_to_segind函数返回一个索引值index,即物理页框pa
  7.         在数组元素vm_page_queues[index]描述的内存段内。

  8.    410:将物理页框的物理地址pa保存到对应页框描述符的phys_addr成员中,从这里可以看出,
  9.         对于一个页框描述符,内核能快速得到该页框描述符描述的物理页框的物理地址。

  10.    417:默认情况下,物理页框都被添加到页框池:
  11.         vm_phys_free_queues[VM_FREELIST_ISADMA][VM_FREEPOOL_DEFAULT]或
  12.         vm_phys_free_queues[VM_FREELIST_DEFAULT][VM_FREEPOOL_DEFAULT]中。

  13.    418:函数pmap_page_init初始化页框描述符的md成员。

  14.    421:函数vm_phys_free_pages将物理页框添加到数组vm_phys_free_queues中,根据伙伴
  15.         系统算法来管理的,大家可以在"$FreeBSD: release/9.2.0/sys/vm/vm_phys.c"
  16.         找到该函数看一下。
  17. ***************************************/
  18.    403        void
  19.    404        vm_phys_add_page(vm_paddr_t pa)
  20.    405        {
  21.    406                vm_page_t m;
  22.    407       
  23.    408                cnt.v_page_count++;
  24.    409                m = vm_phys_paddr_to_vm_page(pa);
  25.    410                m->phys_addr = pa;
  26.    411                m->queue = PQ_NONE;
  27.    412                m->segind = vm_phys_paddr_to_segind(pa);
  28.    413                m->flags = PG_FREE;
  29.    414                KASSERT(m->order == VM_NFREEORDER,
  30.    415                    ("vm_phys_add_page: page %p has unexpected order %d",
  31.    416                    m, m->order));
  32.    417                m->pool = VM_FREEPOOL_DEFAULT;
  33.    418                pmap_page_init(m);
  34.    419                mtx_lock(&vm_page_queue_free_mtx);
  35.    420                cnt.v_free_count++;
  36.    421                vm_phys_free_pages(m, 0);
  37.    422                mtx_unlock(&vm_page_queue_free_mtx);
  38.    423        }
复制代码
到这里,初始化函数vm_page_startup执行完毕,可用的物理页框已经添加到对应的页框池中,页框池中的每个物理页框都有其对应的页框描述符
来描述这个物理页框。

在随后分配页框时,相关页框分配函数就会从页框池中获取一个页框描述符,然后通过宏VM_PAGE_TO_PHYS立即得到其描述的物理页框的物理地址:
  1. #define VM_PAGE_TO_PHYS(entry)        ((entry)->phys_addr)
复制代码
对于一个物理地址pa,并且该物理地址pa在数组vm_phys_segs描述的一个物理内存段内,那么:
[函数vm_phys_paddr_to_segind]--返回数组索引index,即pa在vm_phys_segs[index]描述的物理内存段内:
  1.    691        static int
  2.    692        vm_phys_paddr_to_segind(vm_paddr_t pa)
  3.    693        {
  4.    694                struct vm_phys_seg *seg;
  5.    695                int segind;
  6.    696       
  7.    697                for (segind = 0; segind < vm_phys_nsegs; segind++) {
  8.    698                        seg = &vm_phys_segs[segind];
  9.    699                        if (pa >= seg->start && pa < seg->end)
  10.    700                                return (segind);
  11.    701                }
  12.    702                panic("vm_phys_paddr_to_segind: paddr %#jx is not in any segment" ,
  13.    703                    (uintmax_t)pa);
  14.    704        }
复制代码
[函数vm_phys_paddr_to_vm_page]--返回描述物理地址pa的页框描述符:
  1.    568        vm_page_t
  2.    569        vm_phys_paddr_to_vm_page(vm_paddr_t pa)
  3.    570        {
  4.    571                struct vm_phys_seg *seg;
  5.    572                int segind;
  6.    573       
  7.    574                for (segind = 0; segind < vm_phys_nsegs; segind++) {
  8.    575                        seg = &vm_phys_segs[segind];
  9.    576                        if (pa >= seg->start && pa < seg->end)
  10.    577                                return (&seg->first_page[atop(pa - seg->start)]);
  11.    578                }
  12.    579                return (NULL);
  13.    580        }
复制代码
不过从函数vm_phys_paddr_to_vm_page中可以看出一点不同,当要获取保存kernel代码等那段物理内存的页框描述符时,就不能使用函数vm_phys_paddr_to_vm_page,原因
是显而易见的,这时就要使用函数PHYS_TO_VM_PAGE:
  1.    632        vm_page_t
  2.    633        PHYS_TO_VM_PAGE(vm_paddr_t pa)
  3.    634        {
  4.    635                vm_page_t m;
  5.    636       
  6.    637                long pi;
  7.    638       
  8.    639                pi = atop(pa);
  9.    640                if (pi >= first_page && (pi - first_page) < vm_page_array_size) {
  10.    641                        m = &vm_page_array[pi - first_page];
  11.    642                        return (m);
  12.    643                }
  13.    644                return (vm_phys_fictitious_to_vm_page(pa)); // 虚构一个页框描述符,忽略
  14.    645        }
复制代码

论坛徽章:
0
发表于 2014-07-19 12:35 |显示全部楼层
回复 2# 力劈玄黄

能说清楚点么


   
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP