Tuesday 17 August 2021

Linux-5.4 arm64 early_fixmap_init analysis

The early_fixmap_init function analysis based on the following configuration, 
there is no pud, so the key code can be extracted as follows

CONFIG_ARM64_VA_BITS=39
CONFIG_ARM64_4K_PAGES=y
CONFIG_PGTABLE_LEVELS=3 

#dfine PAGE_SHIFT 12
#define STRUCT_PAGE_MAX_SHIFT 6
__end_of_permanent_fixed_addresses =0x405 

/*
* Size of the PCI I/O space. This must remain a power of two so that
* IO_SPACE_LIMIT acts as a mask for the low bits of I/O addresses.
*/

#define PCI_IO_SIZE SZ_16M
//(0xffffff4000000000 -0xffffff8000000000 ) >> (12-6) = FFFF FFFF00000000
#define VMEMMAP_SIZE ((_PAGE_END(VA_BITS_MIN) - PAGE_OFFSET) \
  >> (PAGE_SHIFT - STRUCT_PAGE_MAX_SHIFT)) 

/*
* PAGE_OFFSET - the virtual address of the start of the linear map, at the
*               start of the TTBR1 address space.
* PAGE_END - the end of the linear map, where all other kernel mappings begin.
* KIMAGE_VADDR - the virtual address of the start of the kernel image.
* VA_BITS - the maximum number of bits for virtual addresses.
*/
#define VA_BITS (CONFIG_ARM64_VA_BITS) //39
#define VA_BITS_MIN (VA_BITS) // if VA_BITS > 48, it is 48 bit
#define _PAGE_OFFSET(va) (-(UL(1) << (va)))
#define PAGE_OFFSET (_PAGE_OFFSET(VA_BITS)) //0xffffff8000000000 
#define KIMAGE_VADDR (MODULES_END) //0xFFFFFFC010000000
#define BPF_JIT_REGION_START (KASAN_SHADOW_END) //(_PAGE_END(VA_BITS_MIN)) 0xffffffc000000000
#define BPF_JIT_REGION_SIZE (SZ_128M) //0x8000000
#define BPF_JIT_REGION_END (BPF_JIT_REGION_START + BPF_JIT_REGION_SIZE) //(0xffffffc000000000 + 0x8000000)=0xFFFFFFC008000000
#define MODULES_END (MODULES_VADDR + MODULES_VSIZE)//(0xFFFFFFC008000000+0x8000000) =0xFFFFFFC010000000
#define MODULES_VADDR (BPF_JIT_REGION_END) //0xFFFFFFC008000000
#define MODULES_VSIZE (SZ_128M) //0x8000000
#define VMEMMAP_START (-VMEMMAP_SIZE - SZ_2M) (-FFFFFFFF00000000- 0x200000) 0xFFFFFFFEFFE00000
#define PCI_IO_END (VMEMMAP_START - SZ_2M) //0xfffffffeffc00000 
#define PCI_IO_START (PCI_IO_END - PCI_IO_SIZE) //0xfffffffefec00000
#define FIXADDR_TOP (PCI_IO_START - SZ_2M) //fffffffefea00000
#define KASAN_SHADOW_END     (_PAGE_END(VA_BITS_MIN)) // 0xffffffc000000000
#define _PAGE_END(va)     (-(UL(1) << ((va) - 1))) 

#define FIXADDR_SIZE (__end_of_permanent_fixed_addresses << PAGE_SHIFT) (0x405 << 12) //0x405000
#define FIXADDR_START (FIXADDR_TOP - FIXADDR_SIZE) //0xFFFFFFFEFE5FB000

/*
 * The p*d_populate functions call virt_to_phys implicitly so they can't be used
 * directly on kernel symbols (bm_p*d). This function is called too early to use
 * lm_alias so __p*d_populate functions must be used to populate with the
 * physical address from __pa_symbol.
 */
void __init early_fixmap_init(void)
{
	pgd_t *pgdp;
	p4d_t *p4dp, p4d;
	pud_t *pudp;
	pmd_t *pmdp;
	unsigned long addr = FIXADDR_START;

	pgdp = pgd_offset_k(addr);
	p4dp = p4d_offset(pgdp, addr);
	p4d = READ_ONCE(*p4dp);
	if (CONFIG_PGTABLE_LEVELS > 3 &&
	    !(p4d_none(p4d) || p4d_page_paddr(p4d) == __pa_symbol(bm_pud))) {
		/*
		 * We only end up here if the kernel mapping and the fixmap
		 * share the top level pgd entry, which should only happen on
		 * 16k/4 levels configurations.
		 */
		BUG_ON(!IS_ENABLED(CONFIG_ARM64_16K_PAGES));
		pudp = pud_offset_kimg(p4dp, addr);
	} else {
		if (p4d_none(p4d))
			__p4d_populate(p4dp, __pa_symbol(bm_pud), P4D_TYPE_TABLE);
		pudp = fixmap_pud(addr);
	}
	if (pud_none(READ_ONCE(*pudp)))
		__pud_populate(pudp, __pa_symbol(bm_pmd), PUD_TYPE_TABLE);
	pmdp = fixmap_pmd(addr);
	__pmd_populate(pmdp, __pa_symbol(bm_pte), PMD_TYPE_TABLE);

	/*
	 * The boot-ioremap range spans multiple pmds, for which
	 * we are not prepared:
	 */
	BUILD_BUG_ON((__fix_to_virt(FIX_BTMAP_BEGIN) >> PMD_SHIFT)
		     != (__fix_to_virt(FIX_BTMAP_END) >> PMD_SHIFT));

	if ((pmdp != fixmap_pmd(fix_to_virt(FIX_BTMAP_BEGIN)))
	     || pmdp != fixmap_pmd(fix_to_virt(FIX_BTMAP_END))) {
		WARN_ON(1);
		pr_warn("pmdp %p != %p, %p\n",
			pmdp, fixmap_pmd(fix_to_virt(FIX_BTMAP_BEGIN)),
			fixmap_pmd(fix_to_virt(FIX_BTMAP_END)));
		pr_warn("fix_to_virt(FIX_BTMAP_BEGIN): %08lx\n",
			fix_to_virt(FIX_BTMAP_BEGIN));
		pr_warn("fix_to_virt(FIX_BTMAP_END):   %08lx\n",
			fix_to_virt(FIX_BTMAP_END));

		pr_warn("FIX_BTMAP_END:       %d\n", FIX_BTMAP_END);
		pr_warn("FIX_BTMAP_BEGIN:     %d\n", FIX_BTMAP_BEGIN);
	}
}
This function is to create a mapping for the virtual address FIXADDR_START, 
but there is no corresponding physical address, which means that the mapping is only part of it, 
and no value is assigned to pte.

No comments:

Post a Comment