From patchwork Wed Aug 30 18:32:52 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sergej Proskurin X-Patchwork-Id: 9930601 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 9EA296032A for ; Wed, 30 Aug 2017 18:36:00 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 91DC9285C8 for ; Wed, 30 Aug 2017 18:36:00 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 86C292874B; Wed, 30 Aug 2017 18:36:00 +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 DF161285C8 for ; Wed, 30 Aug 2017 18:35:59 +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 1dn7nz-00022G-HC; Wed, 30 Aug 2017 18:33:35 +0000 Received: from mail6.bemta3.messagelabs.com ([195.245.230.39]) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1dn7nv-0001ij-Eu for xen-devel@lists.xenproject.org; Wed, 30 Aug 2017 18:33:31 +0000 Received: from [85.158.137.68] by server-7.bemta-3.messagelabs.com id 16/9B-02224-AF407A95; Wed, 30 Aug 2017 18:33:30 +0000 X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFrrOLMWRWlGSWpSXmKPExsXSPJ+BQ/cny/J Ig9tvzCy+b5nM5MDocfjDFZYAxijWzLyk/IoE1owFz5tYCj7bV8zc/JO5gfGQYRcjF4eQwEZG icOf5rJCOJsYJe5+uMTUxcjJwSZgIDHl9UpWEFtEQEni3qrJTCBFzAJNjBL3Gh+wgSSEBewk/ k/+DdbAIqAq8e7JeyCbg4NXwFbiw2dbkLCEgLzEuQe3mUFsTqDwmQMzwGYKCdhI3Jt7nnkCI/ cCRoZVjBrFqUVlqUW6RgZ6SUWZ6RkluYmZObqGBsZ6uanFxYnpqTmJScV6yfm5mxiBHq5nYGD cwdh8wu8QoyQHk5Io7wrm5ZFCfEn5KZUZicUZ8UWlOanFhxhlODiUJHjZgQEjJFiUmp5akZaZ Aww1mLQEB4+SCC8LSJq3uCAxtzgzHSJ1ilFRSpx3MchMAZBERmkeXBssvC8xykoJ8zIyMDAI8 RSkFuVmlqDKv2IU52BUEuZlAxnPk5lXAjf9FdBiJqDFsV5LQRaXJCKkpBoYG1wesW/KCvl/et n7UqcX1tzbOreL37mvdulB+Cp7ewPDTVtFNBJm1L96cvtnXdzrWjcPq5//Z7b9dD+m4BWkd26 utcupWeWvHfY+2Ptv251JxpM9O+8dMvO0eHJZPfrsZMNret+ae/KWpUl5RhYkmLCdzz/xuWu5 nmpeXd6zne/3b793KsJTV4mlOCPRUIu5qDgRAFZZV4BqAgAA X-Env-Sender: proskurin@sec.in.tum.de X-Msg-Ref: server-11.tower-31.messagelabs.com!1504118009!81499005!1 X-Originating-IP: [131.159.0.8] X-SpamReason: No, hits=0.0 required=7.0 tests= X-StarScan-Received: X-StarScan-Version: 9.4.45; banners=-,-,- X-VirusChecked: Checked Received: (qmail 64753 invoked from network); 30 Aug 2017 18:33:29 -0000 Received: from mail-out1.informatik.tu-muenchen.de (HELO mail-out1.informatik.tu-muenchen.de) (131.159.0.8) by server-11.tower-31.messagelabs.com with DHE-RSA-AES256-GCM-SHA384 encrypted SMTP; 30 Aug 2017 18:33:29 -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 7AAEE10CB7DF7; Wed, 30 Aug 2017 20:33:09 +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 75294491F5; Wed, 30 Aug 2017 20:33:09 +0200 (CEST) From: Sergej Proskurin To: xen-devel@lists.xenproject.org Date: Wed, 30 Aug 2017 20:32:52 +0200 Message-Id: <20170830183258.14612-34-proskurin@sec.in.tum.de> X-Mailer: git-send-email 2.14.1 In-Reply-To: <20170830183258.14612-1-proskurin@sec.in.tum.de> References: <20170830183258.14612-1-proskurin@sec.in.tum.de> Cc: Sergej Proskurin , Julien Grall , Stefano Stabellini Subject: [Xen-devel] [PATCH v4 33/39] arm/p2m: Add altp2m paging mechanism 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 the function "altp2m_lazy_copy" implementing the altp2m paging mechanism. The function "altp2m_lazy_copy" lazily copies the hostp2m's mapping into the currently active altp2m view on 2nd stage translation faults on instruction or data access. Signed-off-by: Sergej Proskurin --- Cc: Stefano Stabellini Cc: Julien Grall --- v3: Cosmetic fixes. Locked hostp2m in the function "altp2m_lazy_copy" to avoid a mapping being changed in hostp2m before it has been inserted into the valtp2m view. Removed unnecessary calls to "p2m_mem_access_check" in the functions "do_trap_instr_abort_guest" and "do_trap_data_abort_guest" after a translation fault has been handled by the function "altp2m_lazy_copy". Adapted "altp2m_lazy_copy" to return the value "true" if the encountered translation fault encounters a valid entry inside of the currently active altp2m view. If multiple vcpus are using the same altp2m, it is likely that both generate a translation fault, whereas the first one will be already handled by "altp2m_lazy_copy". With this change the 2nd vcpu will retry accessing the faulting address. Changed order of altp2m checking and MMIO emulation within the function "do_trap_data_abort_guest". Now, altp2m is checked and handled only if the MMIO does not have to be emulated. Changed the function prototype of "altp2m_lazy_copy". This commit removes the unnecessary struct p2m_domain* from the previous function prototype. Also, this commit removes the unnecessary argument gva. Finally, this commit changes the address of the function parameter gpa from paddr_t to gfn_t and renames it to gfn. Moved the altp2m handling mechanism into a separate function "try_handle_altp2m". Moved the functions "p2m_altp2m_check" and "altp2m_switch_vcpu_altp2m_by_id" out of this patch. Moved applied code movement into a separate patch. v4: Cosmetic fixes. Changed the function prototype of "altp2m_lazy_copy" and "try_handle_altp2m" by removing the unused function parameter of type "struct npfec". Removed the function "try_handle_altp2m". Please note that we cannot reorder the calls to "altp2m_lazy_copy" and "gfn_to_mfn" as to deprioritize altp2m. If the call to "gfn_to_mfn" would be performed before "altp2m_lazy_copy", the system would likely stall if altp2m was active. This is because the "p2m_lookup" routine in "gfn_to_mfn" considers only the host's p2m, which will most likely return a mfn != INVALID_MFN and thus entirely skip the call to "altp2m_lazy_copy". Use the functions "p2m_(set|get)_entry" instead of the helpers "p2m_lookup_attr" and "modify_altp2m_entry" in the function "altp2m_lazy_copy". Therefore, we write-lock the altp2m view throughout the entire function. Moved read-locking of hp2m to the beginning of the function "altp2m_lazy_copy". --- xen/arch/arm/altp2m.c | 66 ++++++++++++++++++++++++++++++++++++++++++++ xen/arch/arm/traps.c | 17 ++++++++++++ xen/include/asm-arm/altp2m.h | 4 +++ 3 files changed, 87 insertions(+) diff --git a/xen/arch/arm/altp2m.c b/xen/arch/arm/altp2m.c index 9c9876c932..fd455bdbfc 100644 --- a/xen/arch/arm/altp2m.c +++ b/xen/arch/arm/altp2m.c @@ -155,6 +155,72 @@ int altp2m_set_mem_access(struct domain *d, return rc; } +/* + * The function altp2m_lazy_copy returns "false" on error. The return value + * "true" signals that either the mapping has been successfully lazy-copied + * from the hostp2m to the currently active altp2m view or that the altp2m view + * holds already a valid mapping. The latter is the case if multiple vcpus + * using the same altp2m view generate a translation fault that is led back in + * both cases to the same mapping and the first fault has been already handled. + */ +bool altp2m_lazy_copy(struct vcpu *v, gfn_t gfn) +{ + struct domain *d = v->domain; + struct p2m_domain *hp2m = p2m_get_hostp2m(d), *ap2m = NULL; + p2m_type_t p2mt; + p2m_access_t p2ma; + mfn_t mfn; + unsigned int page_order; + int rc; + + ap2m = altp2m_get_altp2m(v); + if ( unlikely(!ap2m) ) + return false; + + /* + * Lock hp2m to prevent the hostp2m to change a mapping before it is added + * to the altp2m view. + */ + p2m_read_lock(hp2m); + p2m_write_lock(ap2m); + + /* Check if entry is part of the altp2m view. */ + mfn = p2m_get_entry(ap2m, gfn, NULL, NULL, NULL); + + /* + * If multiple vcpus are using the same altp2m, it is likely that both + * generate a translation fault, whereas the first one will be handled + * successfully and the second will encounter a valid mapping that has + * already been added as a result of the previous translation fault. In + * this case, the 2nd vcpu needs to retry accessing the faulting address. + */ + if ( !mfn_eq(mfn, INVALID_MFN) ) + goto out; + + /* Check if entry is part of the host p2m view. */ + mfn = p2m_get_entry(hp2m, gfn, &p2mt, &p2ma, &page_order); + if ( mfn_eq(mfn, INVALID_MFN) ) + goto out; + + /* Align the gfn and mfn to the given pager order. */ + gfn = _gfn(gfn_x(gfn) & ~((1UL << page_order) - 1)); + mfn = _mfn(mfn_x(mfn) & ~((1UL << page_order) - 1)); + + rc = p2m_set_entry(ap2m, gfn, (1UL << page_order), mfn, p2mt, p2ma); + if ( rc ) + { + gdprintk(XENLOG_ERR, "altp2m[%u] failed to set entry for %#"PRI_gfn" -> %#"PRI_mfn"\n", + v->arch.ap2m_idx, gfn_x(gfn), mfn_x(mfn)); + domain_crash(d); + } + +out: + p2m_write_unlock(ap2m); + p2m_read_unlock(hp2m); + + return true; +} + static inline void altp2m_reset(struct p2m_domain *p2m) { p2m_write_lock(p2m); diff --git a/xen/arch/arm/traps.c b/xen/arch/arm/traps.c index aa838e8e77..3ef15d3100 100644 --- a/xen/arch/arm/traps.c +++ b/xen/arch/arm/traps.c @@ -52,6 +52,8 @@ #include #include +#include + /* The base of the stack must always be double-word aligned, which means * that both the kernel half of struct cpu_user_regs (which is pushed in * entry.S) and struct cpu_info (which lives at the bottom of a Xen @@ -2634,6 +2636,14 @@ static void do_trap_instr_abort_guest(struct cpu_user_regs *regs, } case FSC_FLT_TRANS: /* + * The guest shall retry accessing the page if the altp2m handler + * succeeds. Otherwise, we continue injecting an instruction abort + * exception. + */ + if ( altp2m_lazy_copy(current, _gfn(paddr_to_pfn(gpa))) ) + return; + + /* * The PT walk may have failed because someone was playing * with the Stage-2 page table. Walk the Stage-2 PT to check * if the entry exists. If it's the case, return to the guest @@ -2774,6 +2784,13 @@ static void do_trap_data_abort_guest(struct cpu_user_regs *regs, } /* + * The guest shall retry accessing the page if the altp2m handler + * succeeds. Otherwise, we continue injecting a data abort exception. + */ + if ( altp2m_lazy_copy(current, _gfn(paddr_to_pfn(info.gpa))) ) + return; + + /* * The PT walk may have failed because someone was playing * with the Stage-2 page table. Walk the Stage-2 PT to check * if the entry exists. If it's the case, return to the guest diff --git a/xen/include/asm-arm/altp2m.h b/xen/include/asm-arm/altp2m.h index eff6bd5a38..4cdca63f01 100644 --- a/xen/include/asm-arm/altp2m.h +++ b/xen/include/asm-arm/altp2m.h @@ -81,6 +81,10 @@ int altp2m_set_mem_access(struct domain *d, p2m_access_t a, gfn_t gfn); +/* Alternate p2m paging mechanism. */ +bool altp2m_lazy_copy(struct vcpu *v, + gfn_t gfn); + /* Propagates changes made to hostp2m to affected altp2m views. */ int altp2m_propagate_change(struct domain *d, gfn_t sgfn,