From patchwork Wed Aug 9 08:20:37 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sergej Proskurin X-Patchwork-Id: 9889835 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id C9A3B60384 for ; Wed, 9 Aug 2017 08:23:54 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id B26D6284C7 for ; Wed, 9 Aug 2017 08:23:54 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id A5BC4285B6; Wed, 9 Aug 2017 08:23:54 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-4.2 required=2.0 tests=BAYES_00, RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 6C0F028A30 for ; Wed, 9 Aug 2017 08:23:53 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1dfMF6-0006V0-Aj; Wed, 09 Aug 2017 08:21:28 +0000 Received: from mail6.bemta3.messagelabs.com ([195.245.230.39]) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1dfMF5-0006Tm-7n for xen-devel@lists.xenproject.org; Wed, 09 Aug 2017 08:21:27 +0000 Received: from [85.158.137.68] by server-11.bemta-3.messagelabs.com id 22/73-01724-606CA895; Wed, 09 Aug 2017 08:21:26 +0000 X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFnrCLMWRWlGSWpSXmKPExsXSPJ+BQ5f1WFe kwZrDehbft0xmcmD0OPzhCksAYxRrZl5SfkUCa8b2A/tZCk7YVMw/8Zi5gfGFdhcjF4eQwEZG iVlv9zJDOJsYJf5OagByODnYBAwkprxeyQpiiwgoSdxbNZkJpIhZoIlR4l7jAzaQhLCAh8SHn 9/BilgEVCWWdO9lBLF5BWwkXj76yA5iSwjIS0zsnQYW5wSK77gDYQsJWEtMO3aOeQIj9wJGhl WMGsWpRWWpRbpGBnpJRZnpGSW5iZk5uoYGxnq5qcXFiempOYlJxXrJ+bmbGIE+rmdgYNzB2Hz C7xCjJAeTkijvJu3OSCG+pPyUyozE4oz4otKc1OJDjDIcHEoSvD+OdEUKCRalpqdWpGXmAIMN Ji3BwaMkwnsbJM1bXJCYW5yZDpE6xajL8WrC/29MQix5+XmpUuK8m0GKBECKMkrz4EbAAv8So 6yUMC8jAwODEE9BalFuZgmq/CtGcQ5GJWHe3yBTeDLzSuA2vQI6ggnoiAjfTpAjShIRUlINjE 2l8y2XT3msHu/THVKusf2H3/tjM+ZqOR04HFb076dAS+tb/vVB/DoM3Y++huUvykoXO/d11Z6 kXM1wVrGpD4XNGw5dyjt65eGc6uDLfl5rOR/YvPNIXr3opCHz0k1ibXM3qZn8W9a7cZfoCY/n 6bx/mNd5q+50UFRcIhPRHuT1Y7GK6zLnSUosxRmJhlrMRcWJAMl2yUB3AgAA X-Env-Sender: proskurin@sec.in.tum.de X-Msg-Ref: server-8.tower-31.messagelabs.com!1502266885!109292522!1 X-Originating-IP: [131.159.0.8] X-SpamReason: No, hits=0.5 required=7.0 tests=BODY_RANDOM_LONG X-StarScan-Received: X-StarScan-Version: 9.4.45; banners=-,-,- X-VirusChecked: Checked Received: (qmail 59375 invoked from network); 9 Aug 2017 08:21:25 -0000 Received: from mail-out1.informatik.tu-muenchen.de (HELO mail-out1.informatik.tu-muenchen.de) (131.159.0.8) by server-8.tower-31.messagelabs.com with DHE-RSA-AES256-GCM-SHA384 encrypted SMTP; 9 Aug 2017 08:21:25 -0000 Received: from files.sec.in.tum.de (files.sec.in.tum.de [131.159.50.1]) by services.sec.in.tum.de (Postfix) with ESMTP id 3EC7010DD29F4; Wed, 9 Aug 2017 10:21:07 +0200 (CEST) Received: from thanatos.sec.in.tum.de (thanatos.sec.in.tum.de [131.159.50.57]) by files.sec.in.tum.de (Postfix) with ESMTP id 3AFAA1F048; Wed, 9 Aug 2017 10:21:07 +0200 (CEST) From: Sergej Proskurin To: xen-devel@lists.xenproject.org Date: Wed, 9 Aug 2017 10:20:37 +0200 Message-Id: <20170809082038.3236-13-proskurin@sec.in.tum.de> X-Mailer: git-send-email 2.13.3 In-Reply-To: <20170809082038.3236-1-proskurin@sec.in.tum.de> References: <20170809082038.3236-1-proskurin@sec.in.tum.de> Cc: Sergej Proskurin , Julien Grall , Stefano Stabellini Subject: [Xen-devel] [PATCH v8 12/13] arm/mem_access: Add short-descriptor based gpt X-BeenThere: xen-devel@lists.xen.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: xen-devel-bounces@lists.xen.org Sender: "Xen-devel" X-Virus-Scanned: ClamAV using ClamSMTP This commit adds functionality to walk the guest's page tables using the short-descriptor translation table format for both ARMv7 and ARMv8. The implementation is based on ARM DDI 0487B-a J1-6002 and ARM DDI 0406C-b B3-1506. Signed-off-by: Sergej Proskurin Acked-by: Julien Grall --- Cc: Stefano Stabellini Cc: Julien Grall --- v3: Move the implementation to ./xen/arch/arm/guest_copy.c. Use defines instead of hardcoded values. Cosmetic fixes & Added more coments. v4: Adjusted the names of short-descriptor data-types. Adapt the function to the new parameter of type "struct vcpu *". Cosmetic fixes. v5: Make use of the function vgic_access_guest_memory read page table entries in guest memory. At the same time, eliminate the offsets array, as there is no need for an array. Instead, we apply the associated masks to compute the GVA offsets directly in the code. Use GENMASK to compute complex masks to ease code readability. Use the type uint32_t for the TTBR register. Make use of L2DESC_{SMALL|LARGE}_PAGE_SHIFT instead of PAGE_SHIFT_{4K|64K} macros. Remove {L1|L2}DESC_* defines from this commit. Add comments and cosmetic fixes. v6: Remove the variable level from the function guest_walk_sd as it is a left-over from previous commits and is not used anymore. Remove the falsely added issue that applied the mask to the gva using the %-operator in the L1DESC_PAGE_TABLE case. Instead, use the &-operator as it should have been done in the first place. Make use of renamed function access_guest_memory_by_ipa instead of vgic_access_guest_memory. v7: Added Acked-by Julien Grall. v8: We cast pte.*.base to paddr_t to cope with C type promotion of types smaller than int. Otherwise pte.*.base would be casted to int and subsequently sign extended, thus leading to a wrong value. --- xen/arch/arm/guest_walk.c | 147 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 145 insertions(+), 2 deletions(-) diff --git a/xen/arch/arm/guest_walk.c b/xen/arch/arm/guest_walk.c index c6441ab2f8..7f34a2b1d3 100644 --- a/xen/arch/arm/guest_walk.c +++ b/xen/arch/arm/guest_walk.c @@ -19,6 +19,7 @@ #include #include #include +#include /* * The function guest_walk_sd translates a given GVA into an IPA using the @@ -31,8 +32,150 @@ static int guest_walk_sd(const struct vcpu *v, vaddr_t gva, paddr_t *ipa, unsigned int *perms) { - /* Not implemented yet. */ - return -EFAULT; + int ret; + bool disabled = true; + uint32_t ttbr; + paddr_t mask, paddr; + short_desc_t pte; + register_t ttbcr = READ_SYSREG(TCR_EL1); + unsigned int n = ttbcr & TTBCR_N_MASK; + struct domain *d = v->domain; + + mask = GENMASK_ULL(31, (32 - n)); + + if ( n == 0 || !(gva & mask) ) + { + /* + * Use TTBR0 for GVA to IPA translation. + * + * Note that on AArch32, the TTBR0_EL1 register is 32-bit wide. + * Nevertheless, we have to use the READ_SYSREG64 macro, as it is + * required for reading TTBR0_EL1. + */ + ttbr = READ_SYSREG64(TTBR0_EL1); + + /* If TTBCR.PD0 is set, translations using TTBR0 are disabled. */ + disabled = ttbcr & TTBCR_PD0; + } + else + { + /* + * Use TTBR1 for GVA to IPA translation. + * + * Note that on AArch32, the TTBR1_EL1 register is 32-bit wide. + * Nevertheless, we have to use the READ_SYSREG64 macro, as it is + * required for reading TTBR1_EL1. + */ + ttbr = READ_SYSREG64(TTBR1_EL1); + + /* If TTBCR.PD1 is set, translations using TTBR1 are disabled. */ + disabled = ttbcr & TTBCR_PD1; + + /* + * TTBR1 translation always works like n==0 TTBR0 translation (ARM DDI + * 0487B.a J1-6003). + */ + n = 0; + } + + if ( disabled ) + return -EFAULT; + + /* + * The address of the L1 descriptor for the initial lookup has the + * following format: [ttbr<31:14-n>:gva<31-n:20>:00] (ARM DDI 0487B.a + * J1-6003). Note that the following GPA computation already considers that + * the first level address translation might comprise up to four + * consecutive pages and does not need to be page-aligned if n > 2. + */ + mask = GENMASK(31, (14 - n)); + paddr = (ttbr & mask); + + mask = GENMASK((31 - n), 20); + paddr |= (gva & mask) >> 18; + + /* Access the guest's memory to read only one PTE. */ + ret = access_guest_memory_by_ipa(d, paddr, &pte, sizeof(short_desc_t), false); + if ( ret ) + return -EINVAL; + + switch ( pte.walk.dt ) + { + case L1DESC_INVALID: + return -EFAULT; + + case L1DESC_PAGE_TABLE: + /* + * The address of the L2 descriptor has the following format: + * [l1desc<31:10>:gva<19:12>:00] (ARM DDI 0487B.aJ1-6004). Note that + * the following address computation already considers that the second + * level translation table does not need to be page aligned. + */ + mask = GENMASK(19, 12); + /* + * Cast pte.walk.base to paddr_t to cope with C type promotion of types + * smaller than int. Otherwise pte.walk.base would be casted to int and + * subsequently sign extended, thus leading to a wrong value. + */ + paddr = ((paddr_t)pte.walk.base << 10) | ((gva & mask) >> 10); + + /* Access the guest's memory to read only one PTE. */ + ret = access_guest_memory_by_ipa(d, paddr, &pte, sizeof(short_desc_t), false); + if ( ret ) + return -EINVAL; + + if ( pte.walk.dt == L2DESC_INVALID ) + return -EFAULT; + + if ( pte.pg.page ) /* Small page. */ + { + mask = (1ULL << L2DESC_SMALL_PAGE_SHIFT) - 1; + *ipa = ((paddr_t)pte.pg.base << L2DESC_SMALL_PAGE_SHIFT) | (gva & mask); + + /* Set execute permissions associated with the small page. */ + if ( !pte.pg.xn ) + *perms |= GV2M_EXEC; + } + else /* Large page. */ + { + mask = (1ULL << L2DESC_LARGE_PAGE_SHIFT) - 1; + *ipa = ((paddr_t)pte.lpg.base << L2DESC_LARGE_PAGE_SHIFT) | (gva & mask); + + /* Set execute permissions associated with the large page. */ + if ( !pte.lpg.xn ) + *perms |= GV2M_EXEC; + } + + /* Set permissions so that the caller can check the flags by herself. */ + if ( !pte.pg.ro ) + *perms |= GV2M_WRITE; + + break; + + case L1DESC_SECTION: + case L1DESC_SECTION_PXN: + if ( !pte.sec.supersec ) /* Section */ + { + mask = (1ULL << L1DESC_SECTION_SHIFT) - 1; + *ipa = ((paddr_t)pte.sec.base << L1DESC_SECTION_SHIFT) | (gva & mask); + } + else /* Supersection */ + { + mask = (1ULL << L1DESC_SUPERSECTION_SHIFT) - 1; + *ipa = gva & mask; + *ipa |= (paddr_t)(pte.supersec.base) << L1DESC_SUPERSECTION_SHIFT; + *ipa |= (paddr_t)(pte.supersec.extbase1) << L1DESC_SUPERSECTION_EXT_BASE1_SHIFT; + *ipa |= (paddr_t)(pte.supersec.extbase2) << L1DESC_SUPERSECTION_EXT_BASE2_SHIFT; + } + + /* Set permissions so that the caller can check the flags by herself. */ + if ( !pte.sec.ro ) + *perms |= GV2M_WRITE; + if ( !pte.sec.xn ) + *perms |= GV2M_EXEC; + } + + return 0; } /*