免费注册 查看新帖 |

Chinaunix

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

[FreeBSD] freebsd9.2-管理物理页框-相关数据结构 [复制链接]

论坛徽章:
0
发表于 2014-07-15 18:49 |显示全部楼层
本帖最后由 71v5 于 2014-07-17 19:14 编辑

内存系统在SI_SUB_VM对应的subsystem中初始化,可以看出内存系统的初始化函数被赋予较高的优先级:
  1. SI_SUB_VM                = 0x1000000,        /* virtual memory system init*/
复制代码
freebsd9.2中和内存相关的初始化函数如下:
  1. 100: SYSINIT(vm_mem, SI_SUB_VM, SI_ORDER_FIRST, vm_mem_init, NULL);
  2. [the above rsults in file /usr/src/sys/vm/vm_init.c]

  3. 145: SYSINIT(vm_page, SI_SUB_VM, SI_ORDER_SECOND, vm_page_init_fakepg, NULL);
  4. [the above rsults in file /usr/src/sys/vm/vm_page.c]

  5. 255: SYSINIT(uma_startup3, SI_SUB_VM_CONF, SI_ORDER_SECOND, uma_startup3, NULL);
  6. [the above rsults in file /usr/src/sys/vm/uma_core.c]

  7. 上面的初始化函数vm_page_init_fakepg和uma_startup3都和UMA相关,我们暂且不做分析。
复制代码
下面主要看看初始化初始化函数vm_mem_init:
  1. /**********************************************************************************
  2. * 函数vm_mem_init将依次调用7个初始化函数,这7个函数执行完后,内存系统就可以基本
  3.    上正常工作了。

  4.    函数vm_set_page_size比较简单,请见下面的描述。

  5.    我们先简要分析初始化函数vm_page_startup,后面5个初始化函数先简略描述一下,后续
  6.    再进行分析。

  7.    函数vm_object_init:
  8.    1:初始化两个静态定义的struct vm_object对象:
  9.       struct vm_object kernel_object_store;
  10.       struct vm_object kmem_object_store;
  11.    2:创建用来分配struct vm_object对象的UMA区域,并且由下面的变量来标识这个UMA区域:
  12.       static uma_zone_t obj_zone;

  13.    函数vm_map_startup:
  14.    1:创建用来分配struct vm_map对象的UMA区域.
  15.    2:创建用来给内核分配struct vm_map_entry对象的UMA区域.
  16.       kmapentzone指向这个UMA区域。
  17.    3:创建给普通请求者分配struct vm_map_entry对象的UMA区域.
  18.       mapentzone指向这个UMA区域。

  19.    函数kmem_init:
  20.    创建数据结构来描述内核的地址空间。

  21.    函数pmap_init:
  22.    1:Initialize the pmap module。
  23.    2:初始化描述保存内核页表的物理内存的页框描述符等。

  24.    函数vm_pager_init:
  25.    完成调页器接口的初始化,调页器接口提供了在后备存储和物理内存之间转移
  26.    数据的机制。
  27. ************************************/
  28.    102        /*
  29.    103         *        vm_init initializes the virtual memory system.
  30.    104         *        This is done only by the first cpu up.
  31.    105         *
  32.    106         *        The start and end address of physical memory is passed in.
  33.    107         */
  34.    108        /* ARGSUSED*/
  35.    109        static void
  36.    110        vm_mem_init(dummy)
  37.    111                void *dummy;
  38.    112        {
  39.    113                /*
  40.    114                 * Initializes resident memory structures. From here on, all physical
  41.    115                 * memory is accounted for, and we use only virtual addresses.
  42.    116                 */
  43.    117                vm_set_page_size();
  44.    118                virtual_avail = vm_page_startup(virtual_avail);
  45.    119               
  46.    120                /*
  47.    121                 * Initialize other VM packages
  48.    122                 */
  49.    123                vm_object_init();
  50.    124                vm_map_startup();
  51.    125                kmem_init(virtual_avail, virtual_end);
  52.    126                pmap_init();
  53.    127                vm_pager_init();
  54.    128        }
复制代码
[函数vm_set_page_size]:
  1. /**************************************************************************
  2. * vm_set_page_size:
  3. *
  4. * Sets the page size, perhaps based upon the memory
  5. * size.  Must be called before any use of page-size
  6. * dependent functions.

  7.    struct vmmeter cnt;是一个系统范围内的计数器。

  8.    u_int v_page_size;         page size in bytes               
  9. ************************************************/
  10.    197        void
  11.    198        vm_set_page_size(void)
  12.    199        {
  13.    200                if (cnt.v_page_size == 0)
  14.    201                        cnt.v_page_size = PAGE_SIZE;
  15.    202                if (((cnt.v_page_size - 1) & cnt.v_page_size) != 0)
  16.    203                        panic("vm_set_page_size: page size not a power of two");
  17.    204        }
复制代码
在分析初始化函数vm_page_startup之前,先来看看要用到的部分数据结构等,暂时只需要明白这些数据结构及其
成员的大概含义就行,后续在分析相关内核函数的实现时再回头看看这些数据结构及其成员到底如何使用。

[物理页框描述符--struct vm_page]-在freebsd9.2中,对于每一个物理页框,都有一个struct vm_page类型的数据对象来描述这个物理页框,该
结构体是虚拟内存系统使用物理内存的最底层数据结构:
  1. /******************************************************************************
  2. * typedef struct vm_page *vm_page_t;
  3.    成员大概含义可以参考每个成员的注释。现在只需要明白对于一个物理页框,都有
  4.    一个类型为struct vm_page类型的数据对象来描述它。

  5.    phys_addr:相应物理页框的物理地址。

  6.    md:用来管理映射到该物理页框的全部虚拟线性地址。

  7.    queue:在数组vm_page_queues中的索引。

  8.    segind:在数组vm_phys_segs中的索引,即相应的物理页框在数组元素
  9.            vm_phys_segs[segind]描述的物理内存段内。

  10.    pool:三维数组vm_phys_free_queues第二维的索引。

  11.    order:数组vm_phys_free_queues第三维的索引,比如链表
  12.           vm_phys_free_queues[VM_FREELIST_DEFAULT][VM_FREEPOOL_DEFAULT][order]
  13.           中链接的内存块大小为2^order个物理页框。
  14. ***********************/
  15.    130        struct vm_page {
  16.    131                TAILQ_ENTRY(vm_page) pageq;        /* queue info for FIFO queue or free list (Q) */
  17.    132                TAILQ_ENTRY(vm_page) listq;        /* pages in same object (O)         */
  18.    133                struct vm_page *left;                /* splay tree link (O)                */
  19.    134                struct vm_page *right;                /* splay tree link (O)                */
  20.    135        
  21.    136                vm_object_t object;                /* which object am I in (O,P)*/
  22.    137                vm_pindex_t pindex;                /* offset into object (O,P) */
  23.    138                vm_paddr_t phys_addr;                /* physical address of page */
  24.    139                struct md_page md;                /* machine dependant stuff */
  25.    140                uint8_t        queue;                        /* page queue index (P,Q) */
  26.    141                int8_t segind;
  27.    142                short hold_count;                /* page hold count (P) */
  28.    143                uint8_t        order;                        /* index of the buddy queue */
  29.    144                uint8_t pool;
  30.    145                u_short cow;                        /* page cow mapping count (P) */
  31.    146                u_int wire_count;                /* wired down maps refs (P) */
  32.    147                uint8_t aflags;                        /* access is atomic */
  33.    148                uint8_t flags;                        /* see below, often immutable after alloc */
  34.    149                u_short oflags;                        /* page flags (O) */
  35.    150                u_char        act_count;                /* page usage count (O) */
  36.    151                u_char        busy;                        /* page busy count (O) */
  37.    152                /* NOTE that these must support one bit per DEV_BSIZE in a page!!! */
  38.    153                /* so, on normal X86 kernels, they must be at least 8 bits wide */
  39.    154                vm_page_bits_t valid;                /* map of valid DEV_BSIZE chunks (O) */
  40.    155                vm_page_bits_t dirty;                /* map of dirty DEV_BSIZE chunks (M) */
  41.    156        };
复制代码
[相关全局变量]:
  1. /********************************************************************************
  2. * typedef struct vm_page *vm_page_t;

  3.    vm_page_array:类型为struct vm_page的数组,数组元素用来描述相应的物理页框。
  4.    vm_page_array_size:数组struct vm_page中元素的数目。
  5.    first_page:系统中可以使用的第一个物理页框号。
  6. ****************************************/
  7.    124        vm_page_t vm_page_array;
  8.    125        long vm_page_array_size;
  9.    126        long first_page;
复制代码
[管理相应状态物理页框的队列--struct vpgqueues]:
  1. /**********************************************************************
  2. * TAILQ_HEAD(pglist, vm_page); 展开宏TAILQ_HEAD如下所示:
  3.    struct pglist {
  4.          struct vm_page *tqh_first;
  5.          struct vm_page **tqh_last;
  6.          TRACEBUF
  7.    };
  8.    
  9.    pl:链接了相应状态的物理页框。
  10.    cnt:指向的对象记录了相应状态物理页框的数目。
  11. *****************************************/
  12.    184        struct vpgqueues {
  13.    185                struct pglist pl;
  14.    186                int        *cnt;
  15.    187        };
复制代码
[数组vm_page_queues]:
  1. /*********************************************************************
  2. * #define        PQ_COUNT        3
  3.    #define        PQ_NONE                255

  4.    数组vm_page_queues的索引如下:
  5.    #define        PQ_INACTIVE        0
  6.    #define        PQ_ACTIVE        1
  7.    #define        PQ_HOLD                2

  8.    vm_page_queues[PQ_INACTIVE]中的物理页框处于非活动状态。
  9.    vm_page_queues[PQ_ACTIVE]中的物理页框处于活动状态。
  10.    vm_page_queues[PQ_HOLD]中的物理页框当前的引用计数器非零。
  11. **************************************************/
  12. struct vpgqueues vm_page_queues[PQ_COUNT];
复制代码
[链接空闲物理页框--struct vm_freelist]:
  1. /**********************************************************************
  2. * TAILQ_HEAD(pglist, vm_page); 展开宏TAILQ_HEAD如下所示:
  3.    struct pglist {
  4.          struct vm_page *tqh_first;
  5.          struct vm_page **tqh_last;
  6.          TRACEBUF
  7.    };
  8.    
  9.    pl:链接了空闲物理页框。
  10.    cnt:相应内存块的数目。
  11. *****************************************/
  12.     67        struct vm_freelist {
  13.     68                struct pglist pl;
  14.     69                int lcnt;
  15.     70        };
复制代码
[管理空闲物理页框的队列--三维数组vm_phys_free_queues]:
  1. /****************************************************************************************************************
  2. * #define        VM_NDOMAIN                1
  3.    #define VM_RAW_NFREELIST        (VM_NFREELIST + VM_NDOMAIN - 1)

  4.    第一维索引可以取值如下:
  5.    #define        VM_NFREELIST                2
  6.    #define        VM_FREELIST_DEFAULT        0
  7.    #define        VM_FREELIST_ISADMA        1

  8.    第一维描述:
  9.    Create two free page lists: VM_FREELIST_DEFAULT is for physical pages that are above the largest
  10.    physical address that is accessible by ISA DMA and VM_FREELIST_ISADMA is for physical pages that
  11.    are below that address.
  12.    从这里可以看出,创建了两个空闲物理页框队列:
  13.    队列1:二维数组vm_phys_free_queues[VM_FREELIST_ISADMA],链接了ISADMA使用的空闲物理页框。
  14.    队列2:二维数组vm_phys_free_queues[VM_FREELIST_DEFAULT],链接了非ISADMA使用的空闲物理页框。



  15.    第二维索引可以取值如下:
  16.    #define        VM_NFREEPOOL                2
  17.    #define        VM_FREEPOOL_CACHE        1
  18.    #define        VM_FREEPOOL_DEFAULT        0
  19.    #define        VM_FREEPOOL_DIRECT        0

  20.    第二维描述:
  21.    Create two free page pools.  Since the i386 kernel virtual address space does not include a mapping
  22.    onto the machine's entire physical memory, VM_FREEPOOL_DIRECT is defined as an alias for the default
  23.    pool, VM_FREEPOOL_DEFAULT.
  24.    从这里可以看出,在上面每个空闲队列里,创建了两个空闲物理页框池,总共4个物理页框池:
  25.    页框池1:一维数组vm_phys_free_queues[VM_FREELIST_ISADMA][VM_FREEPOOL_DEFAULT]。
  26.    页框池2:一维数组vm_phys_free_queues[VM_FREELIST_ISADMA][VM_FREEPOOL_CACHE]。
  27.    页框池3:一维数组vm_phys_free_queues[VM_FREELIST_DEFAULT][VM_FREEPOOL_DEFAULT]。
  28.    页框池4:一维数组vm_phys_free_queues[VM_FREELIST_DEFAULT][VM_FREEPOOL_CACHE]。

  29.    页框池2和页框池4中的物理页框对应的页框描述符都设置了PG_CACHED标志。



  30.    第三维索引可以取值如下:
  31.    #ifdef PAE
  32.    #define        VM_NFREEORDER                10
  33.    #else
  34.    #define        VM_NFREEORDER                11
  35.    #endif

  36.    第三维描述:
  37.    The largest allocation size is 2MB under PAE and 4MB otherwise。
  38.    这里形象的描述一下,对于物理页框池vm_phys_free_queues[VM_FREELIST_DEFAULT][VM_FREEPOOL_DEFAULT]:
  39.    vm_phys_free_queues[VM_FREELIST_DEFAULT][VM_FREEPOOL_DEFAULT][0]中链接的内存块大小为2^0个物理页框(4KB)。
  40.    vm_phys_free_queues[VM_FREELIST_DEFAULT][VM_FREEPOOL_DEFAULT][1]中链接的内存块大小为2^1个物理页框(8KB)。
  41.    vm_phys_free_queues[VM_FREELIST_DEFAULT][VM_FREEPOOL_DEFAULT][2]中链接的内存块大小为2^2个物理页框(16KB)。
  42.    vm_phys_free_queues[VM_FREELIST_DEFAULT][VM_FREEPOOL_DEFAULT][3]中链接的内存块大小为2^3个物理页框(32KB)。
  43.    .....................................................
  44.    vm_phys_free_queues[VM_FREELIST_DEFAULT][VM_FREEPOOL_DEFAULT][10]中链接的内存块大小为2^10个物理页框(4MB)。
  45.    可见,对于没有启用PAE的系统,能请求的最大内存块为4MB;启用PAE的系统,能请求的最大内存块为2MB。         
  46. ***************************************************************************/
  47.     95        static struct vm_freelist  vm_phys_free_queues[VM_RAW_NFREELIST][VM_NFREEPOOL][VM_NFREEORDER];
复制代码
[指针数组vm_phys_lookup_lists]:
  1. /***********************************************************************************************************
  2. * #define VM_RAW_NFREELIST        (VM_NFREELIST + VM_NDOMAIN - 1)

  3.    从这个指针数组的定义来看,物理内存的组织应该是存储器域->空闲物理页框链表->空闲物理页框池->空闲物理页框。
  4.    为了降低复杂性,这里假设只有一个存储器域,VM_NDOMAIN的值为1。

  5.    在i386平台,freebsd9.2默认只有一个存储器域。
  6.    Only one memory domain.
  7.    #ifndef VM_NDOMAIN
  8.    #define        VM_NDOMAIN                1
  9.    #endif
  10. ***************************************************/  
  11. static struct vm_freelist (*vm_phys_lookup_lists[VM_NDOMAIN][VM_RAW_NFREELIST])[VM_NFREEPOOL][VM_NFREEORDER];
复制代码
[描述物理内存区--struct vm_phys_seg]:
  1. /*******************************************************************************************
  2. * #define        VM_PHYSSEG_MAX                17
  3.    static struct vm_phys_seg vm_phys_segs[VM_PHYSSEG_MAX]
  4.    static int vm_phys_nsegs;

  5.    之前可用物理内存区由数组phys_avail来描述,初始化完成后,将由数组vm_phys_segs来描述。

  6.    start:
  7.    相应物理内存段的起始物理地址。

  8.    end:
  9.    相应物理内存段的结尾物理地址。

  10.    domain:
  11.    所属的存储器域。

  12.    first_page:
  13.    可以将该成员看成为struct vm_page类型的数组,每个数组元素用来描述该物理内存段一个
  14.    物理页框:
  15.    first_page[0]用来描述该物理内存段内第一个物理页框。
  16.    first_page[1]用来描述该物理内存段内第二个物理页框。
  17.    first_page[2]用来描述该物理内存段内第三个物理页框。
  18.    ...................................................

  19.    free_queues:
  20.    指向上面两个空闲物理页框队列中的一个。
  21. ***********************************************************/
  22.     72        struct vm_phys_seg {
  23.     73                vm_paddr_t        start;
  24.     74                vm_paddr_t        end;
  25.     75                vm_page_t        first_page;
  26.     76                int                domain;
  27.     77                struct vm_freelist (*free_queues)[VM_NFREEPOOL][VM_NFREEORDER];
  28.     78        };
复制代码
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

DTCC2020中国数据库技术大会

【架构革新 高效可控】2020年12月21日-23日第十一届中国数据库技术大会将在北京隆重召开。

大会设置2大主会场,20+技术专场,将邀请超百位行业专家,重点围绕数据架构、AI与大数据、传统企业数据库实践和国产开源数据库等内容展开分享和探讨,为广大数据领域从业人士提供一场年度盛会和交流平台。

http://dtcc.it168.com


大会官网>>
  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP