static void __init create_idmap(void)
{
	u64 start = __pa_symbol(__idmap_text_start);
	u64 size = __pa_symbol(__idmap_text_end) - start;
	pgd_t *pgd = idmap_pg_dir;
	u64 pgd_phys;

	/* check if we need an additional level of translation */
	if (VA_BITS < 48 && idmap_t0sz < (64 - VA_BITS_MIN)) {
		pgd_phys = early_pgtable_alloc(PAGE_SHIFT);
		set_pgd(&idmap_pg_dir[start >> VA_BITS],
			__pgd(pgd_phys | P4D_TYPE_TABLE));
		pgd = __va(pgd_phys);
	}
	__create_pgd_mapping(pgd, start, start, size, PAGE_KERNEL_ROX,
			     early_pgtable_alloc, 0);

	if (IS_ENABLED(CONFIG_UNMAP_KERNEL_AT_EL0)) {
		extern u32 __idmap_kpti_flag;
		u64 pa = __pa_symbol(&__idmap_kpti_flag);

		/*
		 * The KPTI G-to-nG conversion code needs a read-write mapping
		 * of its synchronization flag in the ID map.
		 */
		__create_pgd_mapping(pgd, pa, pa, sizeof(u32), PAGE_KERNEL,
				     early_pgtable_alloc, 0);
	}
}

void __init paging_init(void)
{
	pgd_t *pgdp;
	#ifdef CONFIG_IEE
	unsigned long SP_EL0;
	void *new;
	void *init_token;
	struct task_token *token;
	unsigned long tcr;
	#endif

	// Check if cpu has PAN and HPDS.
	#ifdef CONFIG_IEE
	if(!cpuid_feature_extract_unsigned_field(read_cpuid(ID_AA64MMFR1_EL1),
						ID_AA64MMFR1_PAN_SHIFT))
		panic("Architecture doesn't support PAN, please disable CONFIG_IEE.\n");
	
	if(!cpuid_feature_extract_unsigned_field(read_cpuid(ID_AA64MMFR1_EL1),
						ID_AA64MMFR1_HPD_SHIFT))
		panic("Architecture doesn't support HPDS, please disable CONFIG_IEE.\n");
	#endif

	// Avoid using iee code to modify pgtable before iee initialized.
	#ifdef CONFIG_PTP
	pgdp = pgd_set_fixmap_init(__pa_symbol(swapper_pg_dir));
	#else
	pgdp = pgd_set_fixmap(__pa_symbol(swapper_pg_dir));
	#endif

	
	extern pgd_t init_idmap_pg_dir[];

	idmap_t0sz = 63UL - __fls(__pa_symbol(_end) | GENMASK(VA_BITS_MIN - 1, 0));

	map_kernel(pgdp);
	map_mem(pgdp);

	// Map the whole physical mem into IEE, but set invalid.
	#ifdef CONFIG_IEE
	map_iee(pgdp);
	#endif

	// Avoid using iee code to modify pgtable before iee initialized.
	#ifdef CONFIG_PTP
	pgd_clear_fixmap_init();
	#else
	pgd_clear_fixmap();
	#endif

	cpu_replace_ttbr1(lm_alias(swapper_pg_dir), init_idmap_pg_dir);
	init_mm.pgd = swapper_pg_dir;

	memblock_phys_free(__pa_symbol(init_pg_dir),
			   __pa_symbol(init_pg_end) - __pa_symbol(init_pg_dir));

	memblock_allow_resize();

	create_idmap();

	#ifdef CONFIG_IEE
	// Initialize init iee stack.
	#ifdef CONFIG_PTP
	iee_set_kernel_upage_pre_init((unsigned long)init_iee_stack_begin);
	#else
	iee_set_kernel_upage_early((unsigned long)init_iee_stack_begin, 2);
	#endif

	// Init token for init_task.
	// Change SP_EL0 from Image VA to Logical VA.
	SP_EL0 = (unsigned long)__va(__pa_symbol(&init_task));
	write_sysreg(SP_EL0, sp_el0);
	init_task.cpus_ptr = &(((struct task_struct *)(__va(__pa_symbol(&init_task))))->cpus_mask);
	init_task.children.prev = (__va(__pa_symbol(init_task.children.prev)));
	init_task.children.next = (__va(__pa_symbol(init_task.children.next)));
	// Alloc a page for init_token.
	new = __va(early_pgtable_alloc(0));
	init_token_page_vaddr = new;
	init_token = (void *)__phys_to_iee(__pa_symbol(&init_task));
	// Use lm to write token before IEE initialized.
	token = (struct task_token *)((unsigned long)new + (((unsigned long)&init_task) & ~PAGE_MASK));
	token->pgd = NULL;
	token->iee_stack = (void *)init_iee_stack_end;
	token->valid = true;
	iee_set_token_page_valid_pre_init(init_token, new);

	#ifdef CONFIG_PTP
	// Map the existing pgtable into IEE, set valid.
	init_iee();
	#endif

	sysreg_clear_set(sctlr_el1, 0, SCTLR_EL1_SPAN);

	// Set HPD1 as 1.
	tcr = read_sysreg(tcr_el1);
	tcr |= ((unsigned long)0x1 << 42);
	write_sysreg(tcr, tcr_el1);
	isb();

	// Flush tlb to enable IEE.
	flush_tlb_all();

	// mark that iee is prepared.
	iee_init_done = true;
	#endif
}