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 } 高大上啊!
只能从精神是支持一下:victory:。 必须给楼主站岗。 {:1_1:}{:1_1:}{:1_1:} 只能说不明觉厉了这个真搞不了 路过,帮顶下。。。 怎么回事。。。。 大神啊!看都看不懂 http://bbs.chinaunix.net/thread-4172649-1-1.html 神啊,我看不懂,膜拜!!!
页:
[1]
2