Commit eb3f0624 authored by Punit Agrawal's avatar Punit Agrawal Committed by Marc Zyngier
Browse files

KVM: arm64: Support handling access faults for PUD hugepages



In preparation for creating larger hugepages at Stage 2, extend the
access fault handling at Stage 2 to support PUD hugepages when
encountered.

Provide trivial helpers for arm32 to allow sharing of code.

Signed-off-by: default avatarPunit Agrawal <punit.agrawal@arm.com>
Reviewed-by: default avatarChristoffer Dall <christoffer.dall@arm.com>
Cc: Russell King <linux@armlinux.org.uk>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
[ Replaced BUG() => WARN_ON(1) in PUD helpers ]
Signed-off-by: default avatarSuzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: default avatarMarc Zyngier <marc.zyngier@arm.com>
parent 86d1c55e
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -85,6 +85,9 @@ void kvm_clear_hyp_idmap(void);
#define kvm_pfn_pte(pfn, prot)	pfn_pte(pfn, prot)
#define kvm_pfn_pmd(pfn, prot)	pfn_pmd(pfn, prot)

#define kvm_pud_pfn(pud)	({ WARN_ON(1); 0; })


#define kvm_pmd_mkhuge(pmd)	pmd_mkhuge(pmd)

/*
@@ -108,6 +111,12 @@ static inline bool kvm_s2pud_exec(pud_t *pud)
	return false;
}

static inline pud_t kvm_s2pud_mkyoung(pud_t pud)
{
	BUG();
	return pud;
}

static inline pte_t kvm_s2pte_mkwrite(pte_t pte)
{
	pte_val(pte) |= L_PTE_S2_RDWR;
+7 −0
Original line number Diff line number Diff line
@@ -187,6 +187,8 @@ void kvm_clear_hyp_idmap(void);
#define kvm_pfn_pte(pfn, prot)		pfn_pte(pfn, prot)
#define kvm_pfn_pmd(pfn, prot)		pfn_pmd(pfn, prot)

#define kvm_pud_pfn(pud)		pud_pfn(pud)

#define kvm_pmd_mkhuge(pmd)		pmd_mkhuge(pmd)

static inline pte_t kvm_s2pte_mkwrite(pte_t pte)
@@ -266,6 +268,11 @@ static inline bool kvm_s2pud_exec(pud_t *pudp)
	return !(READ_ONCE(pud_val(*pudp)) & PUD_S2_XN);
}

static inline pud_t kvm_s2pud_mkyoung(pud_t pud)
{
	return pud_mkyoung(pud);
}

#define hyp_pte_table_empty(ptep) kvm_page_empty(ptep)

#ifdef __PAGETABLE_PMD_FOLDED
+6 −0
Original line number Diff line number Diff line
@@ -314,6 +314,11 @@ static inline pte_t pud_pte(pud_t pud)
	return __pte(pud_val(pud));
}

static inline pud_t pte_pud(pte_t pte)
{
	return __pud(pte_val(pte));
}

static inline pmd_t pud_pmd(pud_t pud)
{
	return __pmd(pud_val(pud));
@@ -381,6 +386,7 @@ static inline int pmd_protnone(pmd_t pmd)
#define pfn_pmd(pfn,prot)	__pmd(__phys_to_pmd_val((phys_addr_t)(pfn) << PAGE_SHIFT) | pgprot_val(prot))
#define mk_pmd(page,prot)	pfn_pmd(page_to_pfn(page),prot)

#define pud_mkyoung(pud)	pte_pud(pte_mkyoung(pud_pte(pud)))
#define pud_write(pud)		pte_write(pud_pte(pud))

#define __pud_to_phys(pud)	__pte_to_phys(pud_pte(pud))
+11 −11
Original line number Diff line number Diff line
@@ -1698,6 +1698,7 @@ out_unlock:
 */
static void handle_access_fault(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa)
{
	pud_t *pud;
	pmd_t *pmd;
	pte_t *pte;
	kvm_pfn_t pfn;
@@ -1707,24 +1708,23 @@ static void handle_access_fault(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa)

	spin_lock(&vcpu->kvm->mmu_lock);

	pmd = stage2_get_pmd(vcpu->kvm, NULL, fault_ipa);
	if (!pmd || pmd_none(*pmd))	/* Nothing there */
	if (!stage2_get_leaf_entry(vcpu->kvm, fault_ipa, &pud, &pmd, &pte))
		goto out;

	if (pmd_thp_or_huge(*pmd)) {	/* THP, HugeTLB */
	if (pud) {		/* HugeTLB */
		*pud = kvm_s2pud_mkyoung(*pud);
		pfn = kvm_pud_pfn(*pud);
		pfn_valid = true;
	} else	if (pmd) {	/* THP, HugeTLB */
		*pmd = pmd_mkyoung(*pmd);
		pfn = pmd_pfn(*pmd);
		pfn_valid = true;
		goto out;
	}

	pte = pte_offset_kernel(pmd, fault_ipa);
	if (pte_none(*pte))		/* Nothing there either */
		goto out;

	} else {
		*pte = pte_mkyoung(*pte);	/* Just a page... */
		pfn = pte_pfn(*pte);
		pfn_valid = true;
	}

out:
	spin_unlock(&vcpu->kvm->mmu_lock);
	if (pfn_valid)