71v5 发表于 2015-03-21 23:41

Freebsd10.1-X64-创建内核页表-函数create_pagetables

本帖最后由 71v5 于 2015-03-21 23:45 编辑

错误的地方麻烦各位大牛及时指出啊.

内存管理采用逐个击破的方法,最后来个大统一,应该就明白内存等的初始化过程,现在大家看起来估计有点没有头绪哈.

下面部分图摘自intel手册,对于使用direct map和映射kernel自身的PML4-table的宏或者函数没有去分析,
不过有了大概的结构,相信这些宏或者函数会比较简单.

Every paging structure is 4096 Bytes in size and comprises a number of individual entries. With 32-bit paging,
each entry is 32 bits (4 bytes); there are thus 1024 entries in each structure. With PAE paging and IA-32e paging,
each entry is 64 bits (8 bytes); there are thus 512 entries in each structure. (PAE paging includes one exception, a
paging structure that is 32 bytes in size, containing 4 64-bit entries.)

[函数create_pagetables]:
      /*
               * 参数firstaddr:
               * kernel后第一个可用物理地址.
               *
               * 每一次调用allocpages函数,firstaddr都会被更新.
               */
   685        static void
   686        create_pagetables(vm_paddr_t *firstaddr)
   687        {
   688                int i, j, ndm1g, nkpdpe;
   689                pt_entry_t *pt_p;
   690                pd_entry_t *pd_p;
   691                pdp_entry_t *pdp_p;
   692                pml4_entry_t *p4_p;
   693       
   694                /* Allocate page table pages for the direct map */
            /*
                       * #define        PDPSHIFT        30                LOG2(NBPDP)
                       * #define        NBPDP                (1<<PDPSHIFT) bytes/page dir ptr table
                       *
                       * ndmpdp:
                       * 该变量以1G为单位描述了系统中可以direct map的内存,可以
                       * 理解为Page-Directory-Pointer-Table中entry的数目,同时
                       * 间接指定了Page-Directory的数目.
                       * 因为是64位系统,将ndmpdp的最小值限制为4,即4G.
                       */
   695                ndmpdp = (ptoa(Maxmem) + NBPDP - 1) >> PDPSHIFT;
   696                if (ndmpdp < 4)                /* Minimum 4GB of dirmap */
   697                        ndmpdp = 4;
            /*
                       * Every paging structure is 4096 Bytes in size and comprises a number of individual entries
                       *
                       * #define PAGE_SHIFT        12                /* LOG2(PAGE_SIZE) */
                       * #define PAGE_SIZE        (1<<PAGE_SHIFT)        /* bytes/page */
                       *
                       * 宏NPDPEPG:
                       * #define        NPDPEPG                (PAGE_SIZE/(sizeof (pdp_entry_t))) 这里为512
                       * 每个大小为PAGE_SIZE的page包含多少个Page-Directory-Pointer-Table Entry
                       * ,每个Page-Directory-Pointer-Table Entry的大小为64bit.
                       *
                       * ndmpdpphys:Page-Directory-Pointer-Table的数目,同时间接指定了
                       * PML4-table中entry的数目.
                       *
                       * 699-708:
                       * #define        NDMPML4E        8
                       * NDMPML4E is the maximum number of PML4 entries that will be
             * used to implement the direct map.
                       * PML4-table中一个entry可以确定512G的内存,在这里,可以direct map
                       * 的系统内存大小限制为8*512.
                       */
   698                ndmpdpphys = howmany(ndmpdp, NPDPEPG);
   699                if (ndmpdpphys > NDMPML4E) {
   700                        /*
   701                       * Each NDMPML4E allows 512 GB, so limit to that,
   702                       * and then readjust ndmpdp and ndmpdpphys.
               *
   703                       */
   704                        printf("NDMPML4E limits system to %d GB\n", NDMPML4E * 512);
   705                        Maxmem = atop(NDMPML4E * NBPML4);
   706                        ndmpdpphys = NDMPML4E;
   707                        ndmpdp = NDMPML4E * NPDEPG;
   708                }
            /*
                       * DMPDPphys:在direct map下,Page-Directory-Pointer-Table
                       * 的起始物理地址,分配大小为(ndmpdpphys * PAGE_SIZE)的内存
                       * 空间用来保存Page-Directory-Pointer-Table.
                       *
                       * DMPDphys:在direct map下,Page-Directory的起始物理地址,
                       * 即分配大小为((ndmpdp - ndm1g) * PAGE_SIZE)的内存空间用来
                       * 保存Page-Directory.
                       *
                       * 在支持大小为1G的page时:
                       * ndm1g:以1G为单位描述系统内存大小,此时ndm1g非零.
                       * 保存在DMPDphys处的Page-Directory以2M的page映射
                       * 之间的内存.
                       * 之间的内存以1G的page进行映射.
                       *
                       * 在不支持大小为1G的page时;
                       * ndm1g:以1G为单位描述系统内存大小,此时ndm1g为零.                       
                       * 保存在DMPDphys处的Page-Directory以2M的page映射
                       * 之间的内存.
                       *
                       * dmaplimit:系统对可以direct map的内存大小进行了限制.                       
                       */
   709                DMPDPphys = allocpages(firstaddr, ndmpdpphys);
   710                ndm1g = 0;
            /*
                       * #define        AMDID_PAGE1GB        0x04000000
                       * #define        PDPSHIFT        30
                       */
   711                if ((amd_feature & AMDID_PAGE1GB) != 0)
   712                        ndm1g = ptoa(Maxmem) >> PDPSHIFT;
   713                if (ndm1g < ndmpdp)
   714                        DMPDphys = allocpages(firstaddr, ndmpdp - ndm1g);
   715                dmaplimit = (vm_paddr_t)ndmpdp << PDPSHIFT;
   716       
   717                /* Allocate pages */
                        /*
                       * #define NKPML4E                4
                       *
                       * KPML4phys:PML4-table的起始物理地址,分配一个大小为PAGE_SIZE的内存
                       * 空间用来保存PML4-table.
                       *
                       * KPDPphys:Page-Directory-Pointer-Table的起始物理地址,分配一个大小为
                       * NKPML4E*PAGE_SIZE的内存空间用来保存Page-Directory-Pointer-Table.
                       *
                       * 同时也可以看出,kernel在PML4-table中占用4个entry.
                       */
   718                KPML4phys = allocpages(firstaddr, 1);
   719                KPDPphys = allocpages(firstaddr, NKPML4E);
   720       
   721                /*
   722               * Allocate the initial number of kernel page table pages required to
   723               * bootstrap.We defer this until after all memory-size dependent
   724               * allocations are done (e.g. direct map), so that we don't have to
   725               * build in too much slop in our estimate.
   726               *
   727               * Note that when NKPML4E > 1, we have an empty page underneath
   728               * all but the KPML4I'th one, so we need NKPML4E-1 extra (zeroed)
   729               * pages.(pmap_enter requires a PD page to exist for each KPML4E.)
   730               */
            /*
                       * 731:
                       * 函数nkpt_init初始化变量nkpt,该变量可以理解为映射物理地址范围
                       * 需要的Page-Directory-Entry的数目,也间接指定了Page-Table的数目.
                       *
                       * 732:
                       * #define        NPDEPG                (PAGE_SIZE/(sizeof (pd_entry_t))) 这里为512
                       * #define        NKPDPE(ptpgs)                howmany((ptpgs), NPDEPG)
                       *
                       * nkpdpe的含义为:保存nkpt个Page-Directory-Entry需要的paging structure的数目或者
                       * 为Page-Directory的数目,该变量同时间接指定了Page-Directory-Pointer-Table中entry的数目.
                       */
   731                nkpt_init(*firstaddr);
   732                nkpdpe = NKPDPE(nkpt);
   733          /*
             * KPTphys:Page-Table的起始物理地址.
                       * KPDphys:Page-Directory-Table的起始物理地址.
                       * 个人感觉这里的函数调用顺序应该为:
                       *KPDphys = allocpages(firstaddr, nkpdpe);
                       *KPTphys = allocpages(firstaddr, nkpt);
                       */
   734                KPTphys = allocpages(firstaddr, nkpt);
   735                KPDphys = allocpages(firstaddr, nkpdpe);
   736       
   737                /* Fill in the underlying page table pages */
   738                /* Nominally read-only (but really R/W) from zero to physfree */
   739                /* XXX not fully used, underneath 2M pages */
            /* 填充页表项 */
   740                pt_p = (pt_entry_t *)KPTphys;
   741                for (i = 0; ptoa(i) < *firstaddr; i++)
   742                        pt_p = ptoa(i) | X86_PG_RW | X86_PG_V | X86_PG_G;
   743       
   744                /* Now map the page tables at their location within PTmap */
            /*
                       * 填充Page-Directory-Entry,使用4KB的page时。
                       *
                       * 变量nkpt:该变量可以理解为映射物理地址范围
                       * 需要的Page-Directory-Entry的数目,也间接指定了Page-Table的数目.
                       *
                       * 使用上面已经初始化好的页表充页目录项.
                       */
   745                pd_p = (pd_entry_t *)KPDphys;
   746                for (i = 0; i < nkpt; i++)
   747                        pd_p = (KPTphys + ptoa(i)) | X86_PG_RW | X86_PG_V;
   748       
   749                /* Map from zero to end of allocations under 2M pages */
   750                /* This replaces some of the KPTphys entries above */
            /* #define        PDRSHIFT        21 */
                        /*
                       * 在64位系统下使用2M的page.
                       * 使用2M的page重新填充Page-Directory-Table,
                       * 此时保存在KPTphys位置的Page-Table貌似没有实际用途.
                       */
   751                for (i = 0; (i << PDRSHIFT) < *firstaddr; i++)
   752                        pd_p = (i << PDRSHIFT) | X86_PG_RW | X86_PG_V | PG_PS |
   753                          X86_PG_G;
   754       
   755                /* And connect up the PD to the PDP (leaving room for L4 pages) */
            /*
                       * #define        NPML4EPG        (PAGE_SIZE/(sizeof (pml4_entry_t))) 这里为512
                       * #defineNKPML4E                4
                       * #define        KPML4BASE        (NPML4EPG-NKPML4E) 508
                       * #define        KPML4I                (NPML4EPG-1) 511
                       *
                       * #define        NPDPEPG                (PAGE_SIZE/(sizeof (pdp_entry_t))) 这里为512
                       * #define        KPDPI                (NPDPEPG-2)510 kernbase at -2GB
                       *
                       * nkpdpe的含义为:保存nkpt个Page-Directory-Entry需要的paging structure的数目或者
                       * 为Page-Directory的数目,该变量同时间接指定了Page-Directory-Pointer-Table中entry的数目.
                       *
                       * KPDPphys:Page-Directory-Pointer-Table的起始物理地址
                       * pdp_p:(pdp_entry_t *)(KPDPphys + ptoa(KPML4I - KPML4BASE));
                       *
                       * kernel在第三个Page-Directory-Pointer-Table中进行映射.
                       */
   756                pdp_p = (pdp_entry_t *)(KPDPphys + ptoa(KPML4I - KPML4BASE));
   757                for (i = 0; i < nkpdpe; i++)
   758                        pdp_p = (KPDphys + ptoa(i)) | X86_PG_RW | X86_PG_V |
   759                          PG_U;
   760       
   761                /*
   762               * Now, set up the direct map region using 2MB and/or 1GB pages.If
   763               * the end of physical memory is not aligned to a 1GB page boundary,
   764               * then the residual physical memory is mapped with 2MB pages.Later,
   765               * if pmap_mapdev{_attr}() uses the direct map for non-write-back
   766               * memory, pmap_change_attr() will demote any 2MB or 1GB page mappings
   767               * that are partially used.
   768               */
            /*
                       * #define        NPDEPG                (PAGE_SIZE/(sizeof (pd_entry_t))) 这里为512.
                       * #define        PDRSHIFT        21
                       *
                       * ndmpdp:
                       * 该变量以1G为单位描述了系统中全部可以用内存,可以
                       * 理解为Page-Directory-Pointer-Table中entry的数目,同时
                       * 间接指定了Page Directory的数目. NPDEPG * ndmpdp为Page-Directory-entry
                       * 的数目,每个Page Directory entry映射2M的page.
                       *
                       */
   769                pd_p = (pd_entry_t *)DMPDphys;
   770                for (i = NPDEPG * ndm1g, j = 0; i < NPDEPG * ndmpdp; i++, j++) {
   771                        pd_p = (vm_paddr_t)i << PDRSHIFT;
   772                        /* Preset PG_M and PG_A because demotion expects it. */
   773                        pd_p |= X86_PG_RW | X86_PG_V | PG_PS | X86_PG_G |
   774                          X86_PG_M | X86_PG_A;
   775                }
            /*
                       * #define        PDPSHIFT        30                LOG2(NBPDP)
                       * 在支持大小为1G的page时,ndm1g非零:
                       * 此时776-782:填充Page-Directory-Pointer-Table,这部分entry直接映射
                       * 1G大小的page.
                       * 783-786:映射Page Directory
                       *
                       * 在不支持大小为1G的page时,ndm1g为零:
                       * 783-786:映射Page Directory
                       */
   776                pdp_p = (pdp_entry_t *)DMPDPphys;
   777                for (i = 0; i < ndm1g; i++) {
   778                        pdp_p = (vm_paddr_t)i << PDPSHIFT;
   779                        /* Preset PG_M and PG_A because demotion expects it. */
   780                        pdp_p |= X86_PG_RW | X86_PG_V | PG_PS | X86_PG_G |
   781                          X86_PG_M | X86_PG_A;
   782                }
   783                for (j = 0; i < ndmpdp; i++, j++) {
   784                        pdp_p = DMPDphys + ptoa(j);
   785                        pdp_p |= X86_PG_RW | X86_PG_V | PG_U;
   786                }
   787       
   788                /* And recursively map PML4 to itself in order to get PTmap */
            /*
                       * #define        NPML4EPG        (PAGE_SIZE/(sizeof (pml4_entry_t))) 这里为512
                       * #define        PML4PML4I        (NPML4EPG/2)        Index of recursive pml4 mapping 这里为256
                       * p4_p映射自身.
                       */
   789                p4_p = (pml4_entry_t *)KPML4phys;
   790                p4_p = KPML4phys;
   791                p4_p |= X86_PG_RW | X86_PG_V | PG_U;
   792       
   793                /* Connect the Direct Map slot(s) up to the PML4. */
            /*
                       * 在direct map下:
                       * ndmpdpphys:Page-Directory-Pointer-Table的数目,同时间接指定了
                       * PML4-table中entry的数目.
                       *
                       * DMPDPphys:在direct map下,Page-Directory-Pointer-Table
                       * 的起始物理地址,分配大小为(ndmpdpphys * PAGE_SIZE)的内存
                       * 空间用来保存Page-Directory-Pointer-Table.
                       *
                       * #define        KPML4BASE        (NPML4EPG-NKPML4E) 508
                       * #define        NDMPML4E        8
                       * NDMPML4E is the maximum number of PML4 entries that will be
             * used to implement the direct map
                       * #define        DMPML4I                rounddown(KPML4BASE-NDMPML4E, NDMPML4E)
                       *
                       * 近似为index从500开始的PML4 table entry进行映射.
                       */
   794                for (i = 0; i < ndmpdpphys; i++) {
   795                        p4_p = DMPDPphys + ptoa(i);
   796                        p4_p |= X86_PG_RW | X86_PG_V | PG_U;
   797                }
   798       
   799                /* Connect the KVA slots up to the PML4 */
            /*
                       * #define NKPML4E                4
                       * #define        KPML4BASE        (NPML4EPG-NKPML4E) 508
                       * 从index为508开始映射.
                       */
   800                for (i = 0; i < NKPML4E; i++) {
   801                        p4_p = KPDPphys + ptoa(i);
   802                        p4_p |= X86_PG_RW | X86_PG_V | PG_U;
   803                }

lsstarboy 发表于 2015-03-22 12:21

高大上啊!
只能从精神是支持一下:victory:。

gvim 发表于 2015-03-22 22:19

必须给楼主站岗。

bfmo 发表于 2015-03-24 23:22

{:1_1:}{:1_1:}{:1_1:}

forgaoqiang 发表于 2015-04-11 18:07

只能说不明觉厉了这个真搞不了

qq830406 发表于 2015-04-18 08:10

路过,帮顶下。。。

elenson 发表于 2015-05-13 01:46

怎么回事。。。。

埃菲尔铁塔下的小石头 发表于 2015-05-26 16:46

大神啊!看都看不懂

埃菲尔铁塔下的小石头 发表于 2015-05-26 16:47

http://bbs.chinaunix.net/thread-4172649-1-1.html

zgjacky 发表于 2015-08-18 13:39

神啊,我看不懂,膜拜!!!
页: [1] 2
查看完整版本: Freebsd10.1-X64-创建内核页表-函数create_pagetables