static void __split_huge_zero_page_pmd(struct vm_area_struct *vma,
		unsigned long haddr, pmd_t *pmd)
{
	struct mm_struct *mm = vma->vm_mm;
	pgtable_t pgtable;
	pmd_t _pmd, old_pmd;
	unsigned long addr;
	pte_t *pte;
	int i;
	#ifdef CONFIG_PTP
	pte_t *ptep;
	unsigned long iee_addr;
	#endif

	/*
	 * Leave pmd empty until pte is filled note that it is fine to delay
	 * notification until mmu_notifier_invalidate_range_end() as we are
	 * replacing a zero pmd write protected page with a zero pte write
	 * protected page.
	 *
	 * See Documentation/mm/mmu_notifier.rst
	 */
	old_pmd = pmdp_huge_clear_flush(vma, haddr, pmd);

	pgtable = pgtable_trans_huge_withdraw(mm, pmd);
	#ifdef CONFIG_PTP
	ptep = (pte_t *)page_address(pgtable);
	iee_addr = __phys_to_iee(__pa(ptep));
	set_iee_page_valid(iee_addr);
	iee_set_logical_mem_ro((unsigned long)ptep);
	#endif
	_pmd = __pmd(__phys_to_pmd_val(page_to_phys(pgtable)) | PMD_TYPE_TABLE);

	pte = pte_offset_map(&_pmd, haddr);
	VM_BUG_ON(!pte);
	for (i = 0, addr = haddr; i < HPAGE_PMD_NR; i++, addr += PAGE_SIZE) {
		pte_t entry;

		entry = pfn_pte(my_zero_pfn(addr), vma->vm_page_prot);
		entry = pte_mkspecial(entry);
		if (pmd_uffd_wp(old_pmd))
			entry = pte_mkuffd_wp(entry);
		VM_BUG_ON(!pte_none(ptep_get(pte)));
		set_pte_at(mm, addr, pte, entry);
		pte++;
	}
	pte_unmap(pte - 1);
	smp_wmb(); /* make pte visible before pmd */
	pmd_populate(mm, pmd, pgtable);
}