- 论坛徽章:
- 0
|
本帖最后由 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映射
- * [ndm1g<<PDPSHIFT,ndmpdp<<PDPSHIFT]之间的内存.
- * [0,ndm1g<<PDPSHIFT]之间的内存以1G的page进行映射.
- *
- * 在不支持大小为1G的page时;
- * ndm1g:以1G为单位描述系统内存大小,此时ndm1g为零.
- * 保存在DMPDphys处的Page-Directory以2M的page映射
- * [ndm1g<<PDPSHIFT,ndmpdp<<PDPSHIFT]之间的内存.
- *
- * 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,该变量可以理解为映射物理地址范围[0,*firstaddr]
- * 需要的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[i] = 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:该变量可以理解为映射物理地址范围[0,*firstaddr]
- * 需要的Page-Directory-Entry的数目,也间接指定了Page-Table的数目.
- *
- * 使用上面已经初始化好的页表充页目录项.
- */
- 745 pd_p = (pd_entry_t *)KPDphys;
- 746 for (i = 0; i < nkpt; i++)
- 747 pd_p[i] = (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] = (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
- * #define NKPML4E 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[i + KPDPI] = (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[j] = (vm_paddr_t)i << PDRSHIFT;
- 772 /* Preset PG_M and PG_A because demotion expects it. */
- 773 pd_p[j] |= 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[i] = (vm_paddr_t)i << PDPSHIFT;
- 779 /* Preset PG_M and PG_A because demotion expects it. */
- 780 pdp_p[i] |= 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[i] = DMPDphys + ptoa(j);
- 785 pdp_p[i] |= 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[PML4PML4I]映射自身.
- */
- 789 p4_p = (pml4_entry_t *)KPML4phys;
- 790 p4_p[PML4PML4I] = KPML4phys;
- 791 p4_p[PML4PML4I] |= 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[DMPML4I + i] = DMPDPphys + ptoa(i);
- 796 p4_p[DMPML4I + i] |= 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[KPML4BASE + i] = KPDPphys + ptoa(i);
- 802 p4_p[KPML4BASE + i] |= X86_PG_RW | X86_PG_V | PG_U;
- 803 }
复制代码 |
|