From mboxrd@z Thu Jan 1 00:00:00 1970 From: Pavel Fedin Subject: [PATCH] KVM: arm: Fix crash in free_hyp_pgds() if timer initialization fails Date: Tue, 27 Oct 2015 10:40:08 +0300 Message-ID: <1445931608-8824-1-git-send-email-p.fedin@samsung.com> Mime-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Return-path: Received: from localhost (localhost [127.0.0.1]) by mm01.cs.columbia.edu (Postfix) with ESMTP id 996DC412D6 for ; Tue, 27 Oct 2015 03:37:27 -0400 (EDT) Received: from mm01.cs.columbia.edu ([127.0.0.1]) by localhost (mm01.cs.columbia.edu [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id M+UgSZvpdktD for ; Tue, 27 Oct 2015 03:37:25 -0400 (EDT) Received: from mailout1.w1.samsung.com (mailout1.w1.samsung.com [210.118.77.11]) by mm01.cs.columbia.edu (Postfix) with ESMTPS id 91BA840FAB for ; Tue, 27 Oct 2015 03:37:24 -0400 (EDT) Received: from eucpsbgm2.samsung.com (unknown [203.254.199.245]) by mailout1.w1.samsung.com (Oracle Communications Messaging Server 7.0.5.31.0 64bit (built May 5 2014)) with ESMTP id <0NWV006WRBZ14L40@mailout1.w1.samsung.com> for kvmarm@lists.cs.columbia.edu; Tue, 27 Oct 2015 07:40:13 +0000 (GMT) List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: kvmarm-bounces@lists.cs.columbia.edu Sender: kvmarm-bounces@lists.cs.columbia.edu To: kvmarm@lists.cs.columbia.edu, kvm@vger.kernel.org Cc: Marc Zyngier List-Id: kvmarm@lists.cs.columbia.edu After vGIC initialization succeeded, and timer initialization failed, the following crash can be observed on ARM32: kvm [1]: interrupt-controller@10484000 IRQ57 kvm [1]: kvm_arch_timer: can't find DT node Unable to handle kernel paging request at virtual address 90484000 pgd = c0003000 [90484000] *pgd=80000040006003, *pmd=00000000 Internal error: Oops: 2a06 [#1] PREEMPT SMP ARM ... [] (v7_flush_kern_dcache_area) from [] (kvm_flush_dcache_pte+0x48/0x5c) [] (kvm_flush_dcache_pte) from [] (unmap_range+0x24c/0x460) [] (unmap_range) from [] (free_hyp_pgds+0x84/0x160) [] (free_hyp_pgds) from [] (kvm_arch_init+0x254/0x41c) [] (kvm_arch_init) from [] (kvm_init+0x28/0x2b4) [] (kvm_init) from [] (do_one_initcall+0x9c/0x200) This happens when unmapping reaches mapped vGIC control registers. The problem root seems to be combination of two facts: 1. vGIC control region is defined in device trees as having size of 0x2000. But the specification defines only registers up to 0x1FC, therefore it is only one page, not two. 2. unmap_ptes() is expected to recognize device memory and omit cache flushing. However, it tests only for PAGE_S2_DEVICE, while devices mapped for HYP mode have PAGE_HYP_DEVICE, which is different. Therefore, cache flush is attempted, and it dies when hitting the nonexistent second page. This patch fixes the problem by adding missing recognition of PAGE_HYP_DEVICE protection value. The crash can be observed on Exynos 5410 (and probably on all Exynos5 family) with stock device trees (using MCT) and CONFIG_KVM enabled. Signed-off-by: Pavel Fedin --- arch/arm/kvm/mmu.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/arm/kvm/mmu.c b/arch/arm/kvm/mmu.c index 7b42012..839dd970 100644 --- a/arch/arm/kvm/mmu.c +++ b/arch/arm/kvm/mmu.c @@ -213,7 +213,10 @@ static void unmap_ptes(struct kvm *kvm, pmd_t *pmd, kvm_tlb_flush_vmid_ipa(kvm, addr); /* No need to invalidate the cache for device mappings */ - if ((pte_val(old_pte) & PAGE_S2_DEVICE) != PAGE_S2_DEVICE) + if (((pte_val(old_pte) & PAGE_S2_DEVICE) + != PAGE_S2_DEVICE) && + ((pte_val(old_pte) & PAGE_HYP_DEVICE) + != PAGE_HYP_DEVICE)) kvm_flush_dcache_pte(old_pte); put_page(virt_to_page(pte)); -- 2.4.4