| PMD_SECT_AF | PMD_SECT_S | PMD_SECT_UXN)
#if ARM64_KERNEL_USES_PMD_MAPS
#define SWAPPER_MM_MMUFLAGS (PMD_ATTRINDX(MT_NORMAL) | SWAPPER_PMD_FLAGS) //段映射,这里要使用的
#else
#define SWAPPER_MM_MMUFLAGS (PTE_ATTRINDX(MT_NORMAL) | SWAPPER_PTE_FLAGS) //页映射
#endif
2.4.4 创建恒等映射
/*
* Create the identity mapping.
*/
adrp x0, idmap_pg_dir ---(1)
adrp x3, __idmap_text_start // __pa(__idmap_text_start) ---(2)
#ifdef CONFIG_ARM64_VA_BITS_52 ---(3)
mrs_s x6, SYS_ID_AA64MMFR2_EL1
and x6, x6, #(0xf << ID_AA64MMFR2_LVA_SHIFT)
mov x5, #52
cbnz x6, 1f
#endif
mov x5, #VA_BITS_MIN ---(4)
1:
adr_l x6, vabits_actual ---(5)
str x5, [x6]
dmb sy //内存屏障
dc ivac, x6 // Invalidate potentially stale cache line 把vabits_actual变量对应的缓存给clean掉
/*
* VA_BITS may be too small to allow for an ID mapping to be created
* that covers system RAM if that is located sufficiently high in the
* physical address space. So for the ID map, use an extended virtual
* range in that case, and configure an additional translation level
* if needed.
*
* Calculate the maximum allowed value for TCR_EL1.T0SZ so that the
* entire ID map region can be mapped. As T0SZ == (64 - #bits used),
* this number conveniently equals the number of leading zeroes in
* the physical address of __idmap_text_end.
*/
adrp x5, __idmap_text_end ---(6)
clz x5, x5 //前导0计数:第一个1前0的个数 ---(6)
cmp x5, TCR_T0SZ(VA_BITS_MIN) // default T0SZ small enough? ---(6)
b.ge 1f // .. then skip VA range extension
adr_l x6, idmap_t0sz
str x5, [x6]
dmb sy
dc ivac, x6 // Invalidate potentially stale cache line
#if (VA_BITS < 48)
#define EXTRA_SHIFT (PGDIR_SHIFT + PAGE_SHIFT - 3)
#define EXTRA_PTRS (1 << (PHYS_MASK_SHIFT - EXTRA_SHIFT))
/*
* If VA_BITS < 48, we have to configure an additional table level.
* First, we have to verify our assumption that the current value of
* VA_BITS was chosen such that all translation levels are fully
* utilised, and that lowering T0SZ will always result in an additional
* translation level to be configured.
*/
#if VA_BITS != EXTRA_SHIFT
#error "Mismatch between VA_BITS and page size/number of translation levels"
#endif
mov x4, EXTRA_PTRS
create_table_entry x0, x3, EXTRA_SHIFT, x4, x5, x6
#else
/*
* If VA_BITS == 48, we don't have to configure an additional
* translation level, but the top-level table has more entries.
*/
mov x4, #1 << (PHYS_MASK_SHIFT - PGDIR_SHIFT)
str_l x4, idmap_ptrs_per_pgd, x5
#endif
1:
ldr_l x4, idmap_ptrs_per_pgd ---(7)
adr_l x6, __idmap_text_end // __pa(__idmap_text_end) ---(8)
map_memory x0, x1, x3, x6, x7, x3, x4, x10, x11, x12, x13, x14 ---(9)
- 将加载idmap_pg_dir的物理地址到x0寄存器,idmap_pg_dir是恒等映射的一级页表起始地址,其定义在vmlinux.lds.S链接文件中
idmap_pg_dir = .;
. += IDMAP_DIR_SIZE;
idmap_pg_end = .;
??这里分配给idmap_pg_dir的页面大小为IDMAP_DIR_SIZE,而IDMAP_DIR_SIZE实现在arch/arm64/include/asm/kernel-pgtable.h头文件中,通常是3个连续的大小为4K页面。计算参考如下:
<1>#arch/arm64/include/asm/pgtable-hwdef.h
/*
* Number of page-table levels required to address 'va_bits' wide
* address, without section mapping. We resolve the top (va_bits - PAGE_SHIFT)
* bits with (PAGE_SHIFT - 3) bits at each page table level. Hence:
*
* levels = DIV_ROUND_UP((va_bits - PAGE_SHIFT), (PAGE_SHIFT - 3))
*
* where DIV_ROUND_UP(n, d) => (((n) + (d) - 1) / (d))
*
* We cannot include linux/kernel.h which defines DIV