From mboxrd@z Thu Jan 1 00:00:00 1970 From: Marc Zyngier Subject: [PATCH v3 08/32] arm64: KVM: architecture specific MMU backend Date: Mon, 8 Apr 2013 17:17:10 +0100 Message-ID: <1365437854-30214-9-git-send-email-marc.zyngier@arm.com> References: <1365437854-30214-1-git-send-email-marc.zyngier@arm.com> Content-Type: text/plain; charset=WINDOWS-1252 Content-Transfer-Encoding: quoted-printable Cc: catalin.marinas@arm.com, will.deacon@arm.com, Christopher Covington To: linux-arm-kernel@lists.infradead.org, kvmarm@lists.cs.columbia.edu, kvm@vger.kernel.org Return-path: Received: from service87.mimecast.com ([91.220.42.44]:54590 "EHLO service87.mimecast.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S934911Ab3DHQSt (ORCPT ); Mon, 8 Apr 2013 12:18:49 -0400 In-Reply-To: <1365437854-30214-1-git-send-email-marc.zyngier@arm.com> Sender: kvm-owner@vger.kernel.org List-ID: Define the arm64 specific MMU backend: - HYP/kernel VA offset - S2 4/64kB definitions - S2 page table populating and flushing - icache cleaning Reviewed-by: Christopher Covington Signed-off-by: Marc Zyngier --- arch/arm64/include/asm/kvm_mmu.h | 136 +++++++++++++++++++++++++++++++++++= ++++ 1 file changed, 136 insertions(+) create mode 100644 arch/arm64/include/asm/kvm_mmu.h diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_= mmu.h new file mode 100644 index 0000000..2eb2230 --- /dev/null +++ b/arch/arm64/include/asm/kvm_mmu.h @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2012,2013 - ARM Ltd + * Author: Marc Zyngier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __ARM64_KVM_MMU_H__ +#define __ARM64_KVM_MMU_H__ + +#include +#include + +/* + * As we only have the TTBR0_EL2 register, we cannot express + * "negative" addresses. This makes it impossible to directly share + * mappings with the kernel. + * + * Instead, give the HYP mode its own VA region at a fixed offset from + * the kernel by just masking the top bits (which are all ones for a + * kernel address). + */ +#define HYP_PAGE_OFFSET_SHIFT=09VA_BITS +#define HYP_PAGE_OFFSET_MASK=09((UL(1) << HYP_PAGE_OFFSET_SHIFT) - 1) +#define HYP_PAGE_OFFSET=09=09(PAGE_OFFSET & HYP_PAGE_OFFSET_MASK) + +/* + * Our virtual mapping for the idmap-ed MMU-enable code. Must be + * shared across all the page-tables. Conveniently, we use the last + * possible page, where no kernel mapping will ever exist. + */ +#define TRAMPOLINE_VA=09=09(HYP_PAGE_OFFSET_MASK & PAGE_MASK) + +#ifdef __ASSEMBLY__ + +/* + * Convert a kernel VA into a HYP VA. + * reg: VA to be converted. + */ +.macro kern_hyp_va=09reg +=09and=09\reg, \reg, #HYP_PAGE_OFFSET_MASK +.endm + +#else + +#include + +#define KERN_TO_HYP(kva)=09((unsigned long)kva - PAGE_OFFSET + HYP_PAGE_OF= FSET) + +/* + * Align KVM with the kernel's view of physical memory. Should be + * 40bit IPA, with PGD being 8kB aligned. + */ +#define KVM_PHYS_SHIFT=09PHYS_MASK_SHIFT +#define KVM_PHYS_SIZE=09(1UL << KVM_PHYS_SHIFT) +#define KVM_PHYS_MASK=09(KVM_PHYS_SIZE - 1UL) + +#ifdef CONFIG_ARM64_64K_PAGES +#define PAGE_LEVELS=092 +#define BITS_PER_LEVEL=0913 +#else /* 4kB pages */ +#define PAGE_LEVELS=093 +#define BITS_PER_LEVEL=099 +#endif + +/* Make sure we get the right size, and thus the right alignment */ +#define BITS_PER_S2_PGD (KVM_PHYS_SHIFT - (PAGE_LEVELS - 1) * BITS_PER_LEV= EL - PAGE_SHIFT) +#define PTRS_PER_S2_PGD (1 << max(BITS_PER_LEVEL, BITS_PER_S2_PGD)) +#define S2_PGD_ORDER=09get_order(PTRS_PER_S2_PGD * sizeof(pgd_t)) +#define S2_PGD_SIZE=09(1 << S2_PGD_ORDER) + +int create_hyp_mappings(void *from, void *to); +int create_hyp_io_mappings(void *from, void *to, phys_addr_t); +void free_hyp_pgds(void); + +int kvm_alloc_stage2_pgd(struct kvm *kvm); +void kvm_free_stage2_pgd(struct kvm *kvm); +int kvm_phys_addr_ioremap(struct kvm *kvm, phys_addr_t guest_ipa, +=09=09=09 phys_addr_t pa, unsigned long size); + +int kvm_handle_guest_abort(struct kvm_vcpu *vcpu, struct kvm_run *run); + +void kvm_mmu_free_memory_caches(struct kvm_vcpu *vcpu); + +phys_addr_t kvm_mmu_get_httbr(void); +phys_addr_t kvm_mmu_get_boot_httbr(void); +phys_addr_t kvm_get_idmap_vector(void); +int kvm_mmu_init(void); +void kvm_clear_hyp_idmap(void); + +#define=09kvm_set_pte(ptep, pte)=09=09set_pte(ptep, pte) + +static inline bool kvm_is_write_fault(unsigned long esr) +{ +=09unsigned long esr_ec =3D esr >> ESR_EL2_EC_SHIFT; + +=09if (esr_ec =3D=3D ESR_EL2_EC_IABT) +=09=09return false; + +=09if ((esr & ESR_EL2_ISV) && !(esr & ESR_EL2_WNR)) +=09=09return false; + +=09return true; +} + +static inline void kvm_clean_pgd(pgd_t *pgd) {} +static inline void kvm_clean_pmd_entry(pmd_t *pmd) {} +static inline void kvm_clean_pte(pte_t *pte) {} + +static inline void kvm_set_s2pte_writable(pte_t *pte) +{ +=09pte_val(*pte) |=3D PTE_S2_RDWR; +} + +struct kvm; + +static inline void coherent_icache_guest_page(struct kvm *kvm, gfn_t gfn) +{ +=09unsigned long hva =3D gfn_to_hva(kvm, gfn); +=09flush_icache_range(hva, hva + PAGE_SIZE); +} + +#define kvm_flush_dcache_to_poc(a,l)=09__flush_dcache_area((a), (l)) + +#endif /* __ASSEMBLY__ */ +#endif /* __ARM64_KVM_MMU_H__ */ --=20 1.8.1.4