1 linux 6.10 xilinx内核的内存配置
在.config配置文件中可以看到如下的配置
配置内存的虚拟地址和物理地址总线位宽为48位,页面粒度为4K大小。
内存page size设置为4K 虚拟地址位宽为48位 物理地址位宽为48位 页表级别的配置:配置为4级页表 有3种不同粒度的内存页面设置:4KB,16KB,64KB。
When you use a 4kB granule size, the hardware can use a 4-level look up process. The 48-bit address has nine address bits per level translated, that is 512 entries each, with the final 12 bits selecting a byte within the 4kB coming directly from the original address.
Bits 47:39 of the Virtual Address index into the 512 entry L0 table. Each of these table entries spans a 512 GB range and points to an L1 table. Within that 512 entry L1 table, bits 38:30 are used as index to select an entry and each entry points to either a 1GB block or an L2 table. Bits 29:21 index into a 512 entry L2 table and each entry points to a 2MB block or next table level. At the last level, bits 20:12 index into a 512 entry L2 table and each entry points to a 4kB block.


When you use a 16kB granule size, the hardware can use a 4-level look up process. The 48-bit address has 11 address bits per level translated, that is 2048 entries each, with the final 14 bits selecting a byte within the 4kB coming directly from the original address. The level 0 table contains only two entries. Bit 47 of the Virtual Address selects a descriptor from the two entry L0 table. Each of these table entries spans a 128 TB range and points to an L1 table. Within that 2048 entry L1 table, bits 46:36 are used as an index to select an entry and each entrypoints to an L2 table. Bits 35:25 index into a 2048 entry L2 table and each entry points to a 32 MB block or next table level. At the final translation stage, bits 24:14 index into a 2048 entry L2 table and each entry points to a 16kB block.


When you use a 64kB granule size, the hardware can use a 3-level look up process. The level 1 table contains only 64 entries.
Bits 47:42 of the Virtual Address select a descriptor from the 64 entry L1 table. Each of these table entries spans a 4TB range and points to an L2 table. Within that 8192 entry L2 table, bits 41:29 are used as index to select an entry and each entry points to either a 512 MB block or an L2 table. At the final translation stage, bits 28:16 index into an 8192 entry L3 table and each entry points to a 64kB block.


In the VMSAv8-64 translation table format, the difference in the formats of the level 0, level 1 and level 2
descriptors is:
Whether a Block descriptor is permitted.If a Block descriptor is permitted, the size of the memory region described by that entry.The maximum OA size, depending on whether ARMv8.2-LPA is implemented. These differences depend on the translation granule, as follows:
4KB granule Level 0 translation tables do not support Block descriptors. A block descriptor: In a level 1 table describes the mapping of the associated 1GB input address range.In a level 2 table describes the mapping of the associated 2MB input address range. The maximum OA size of a lookup is 48 bits. 16KB granule Level 0 and level 1 translation tables do not support Block descriptors. A Block descriptor in a level 2 table describes the mapping of the associated 32MB input address range.The maximum OA size of a lookup is 48 bits. 64KB granule Level 0 lookup is not supported. In ARMv8.7 LPA is default is implemented A block descriptor: In a level 1 table describes the mapping of the associated 4TB input address range.In a level 2 table describes the mapping of the associated 512MB input address range. The maximum OA size of a lookup is 48 bits. 如果页表描述符的最低位为0则表示当前页表描述符是一个无效的页表描述符,对于L0 ~ L3页表描述符表都适用。

根据L0 ~ L2页表描述符表的bit 1位为0还是1来区分当前的输出是一个块地址还是一个指向下一级页表的地址
0 表示当前是一个块类型页表描述符,输出的为一个块地址 The descriptor gives the base address of a block of memory, and the attributes for that memory region. 1 表示当前是一个页表类型,指向下一级页表的地址 The descriptor gives the address of the next level of translation table, and for a stage 1 translation, some attributes for that translation.

L3页表描述符表根据页面page size设置的不同,描述符表的格式有略微的区别
For the 4KB granule size, each entry in a level 3 table describes the mapping of the associated 4KB input address range.For the 16KB granule size, each entry in a level 3 table describes the mapping of the associated 16KB input address range.For the 64KB granule size, each entry in a level 3 table describes the mapping of the associated 64KB input address range.

Descriptor bit[1] identifies the descriptor type, and is encoded as:0, Reserved, invalid Behaves identically to encodings with bit[0] set to 0.This encoding must not be used in level 3 translation tables. 1, Page Gives the address and attributes of a 4KB, 16KB, or 64KB page of memory. At this level, the only valid format is the Page descriptor. The other fields in the Page descriptor are:Page descriptor
Gives the output address of a page of memory, as follows: 4KB translation granule Bits[47:12] are bits[47:12] of the output address for a page of memory 16KB translation granule Bits[47:14] are bits[47:14] of the output address for a page of memory. 64KB translation granule bits[47:16] are bits[47:16] of the output address for a page of memory 在linux系统中,arm64的页表映射是通过__create_pgd_mapping函数实现的,在linux 系统中,页表的级别分为为PGD,PUD,PMD,PTE。这分别和arm64的L0,L1,L2,L3相对应。
以4KB页面4级页表为例来分析

__create_pgd_mapping函数__create_pgd_mapping_locked实现后续的页表映射工作。
pgd_t *pgdir 表示的pgd页表的起始地址pgd_t *pgdp = pgd_offset_pgd(pgdir, virt);获取当前pgd页表的地址next = pgd_addr_end(addr, end);获取当前pgd管理页表地址的结束地址,其管理范围为512G(2^39)alloc_init_pud(pgdp, addr, next, phys, prot, pgtable_alloc, flags);分配并配置当前的pud页表映射phys += next - addr;下次要配置的pgd页表项的地址while (pgdp++, addr = next, addr != end)这段代码中的 addr = next表示要获取下一个pgd页表项的起始地址 alloc_init_pud函数就是要在配置pud(即L1)级别的页表项
p4d_none(p4d)判断当前的pgd页表项是否为空,如果为空则需要配置当前的pgd页表项pud_phys = pgtable_alloc(PUD_SHIFT);分配pud页表项__p4d_populate(p4dp, pud_phys, p4dval);将申请的pud页表的地址配置到pgd页表项中pudp = pud_set_fixmap_offset(p4dp, addr);获取pud页表项的地址next = pud_addr_end(addr, end);获取当前pud页表项管理的结束地址,其管理范围为1G (2^30)pud_set_huge(pudp, phys, prot);如果当前的页表描述符表类型为块设备,则输出当前的内存地址为一个1G大小粒度的huge 内存块。alloc_init_cont_pmd(pudp, addr, next, phys, prot, pgtable_alloc, flags);如果当前内存是一个连续的内存,则需要继续设置其下一级页表PMD alloc_init_cont_pmd函数用于设置其pmd页表
pud_none(pud)判断当前的pud页表是否为空,如果为空,则申请PMD页表,并将PMD页表的起始地址配置到pud页表项中next = pmd_cont_addr_end(addr, end);获取当前pmd页表项管理的内存地址的结束地址,其范围为2M (2^21)init_pmd(pudp, addr, next, phys, __prot, pgtable_alloc, flags);映射pmd页表项 init_pmd函数用于配置pmd页表项
pmdp = pmd_set_fixmap_offset(pudp, addr);获取当前pmd页表的基地址next = pmd_addr_end(addr, end);获取当前pmd页表项所管理范围的结束地址,其粒度为2M (2^21)alloc_init_cont_pte(pmdp, addr, next, phys, prot, pgtable_alloc, flags);分配并映射pte页表 alloc_init_cont_pte函数用于做pte页表的映射工作。
pmd_none(pmd)判断当前的pmd页表是否为空,如果为空,则分配pte页表并配置到pmd页表项中init_pte(pmdp, addr, next, phys, __prot) pte页表项的映射配置 init_pte函数用于做pte页表的映射工作
ptep = pte_set_fixmap_offset(pmdp, addr);获取当前pte页表的起始地址set_pte(ptep, pfn_pte(__phys_to_pfn(phys), prot));配置pte页表项phys += PAGE_SIZE;每次往后移一个PAGE,即配置下一个内存页面。