From patchwork Thu Sep 1 07:56:39 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Julien Grall X-Patchwork-Id: 75179 Delivered-To: patch@linaro.org Received: by 10.140.29.8 with SMTP id a8csp154001qga; Thu, 1 Sep 2016 00:58:50 -0700 (PDT) X-Received: by 10.36.47.76 with SMTP id j73mr20797562itj.27.1472716730786; Thu, 01 Sep 2016 00:58:50 -0700 (PDT) Return-Path: Received: from lists.xenproject.org (lists.xenproject.org. [192.237.175.120]) by mx.google.com with ESMTPS id r66si33695972itb.91.2016.09.01.00.58.50 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 01 Sep 2016 00:58:50 -0700 (PDT) Received-SPF: neutral (google.com: 192.237.175.120 is neither permitted nor denied by best guess record for domain of xen-devel-bounces@lists.xen.org) client-ip=192.237.175.120; Authentication-Results: mx.google.com; spf=neutral (google.com: 192.237.175.120 is neither permitted nor denied by best guess record for domain of xen-devel-bounces@lists.xen.org) smtp.mailfrom=xen-devel-bounces@lists.xen.org Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1bfMri-0002XD-3W; Thu, 01 Sep 2016 07:56:50 +0000 Received: from mail6.bemta5.messagelabs.com ([195.245.231.135]) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1bfMrh-0002X7-3M for xen-devel@lists.xen.org; Thu, 01 Sep 2016 07:56:49 +0000 Received: from [85.158.139.211] by server-10.bemta-5.messagelabs.com id B9/D2-19922-04FD7C75; Thu, 01 Sep 2016 07:56:48 +0000 X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFtrHLMWRWlGSWpSXmKPExsVysyfVTdf+/vF wg2VNuhZLPi5mcWD0OLr7N1MAYxRrZl5SfkUCa8aUe8eZCw5oVFzdLN3A+Fu2i5GLQ0hgI6PE tU9tzBDOaUaJOeumMXUxcnKwCWhK3Pn8CcwWEZCWuPb5MiOIzSwQKfFk5g1mEFtYIEriZuMiN hCbRUBVouPzZLA4r4CzxLXJl8DiEgJyEiePTWadwMi5gJFhFaNGcWpRWWqRrpGBXlJRZnpGSW 5iZo6uoYGpXm5qcXFiempOYlKxXnJ+7iZGoL/qGRgYdzA2zvY7xCjJwaQkyqsWdzxciC8pP6U yI7E4I76oNCe1+BCjDAeHkgQv2z2gnGBRanpqRVpmDjBwYNISHDxKIrwv7gKleYsLEnOLM9Mh UqcYFaXEeZeBJARAEhmleXBtsGC9xCgrJczLyMDAIMRTkFqUm1mCKv+KUZyDUUmY9wTIFJ7Mv BK46a+AFjMBLS65Bra4JBEhJdXAqDX5yOq9d+R8Kub+n5b5Iqcls1L+Bm+Jzapt/ivtnj2a51 lhpr4sxfOj+xuVqLknl/6fUXJmy2Pu61d6lrP8bJjubxWqEvF64Wep+imzP0yocvx2YqWntd+ Su43XbV77s9tXz2A5Or/4wtL+xa/XhfdZvgnpK5XKU2jmqWtNL9kduPXD6mnMAkosxRmJhlrM RcWJABKPv9RRAgAA X-Env-Sender: julien.grall@arm.com X-Msg-Ref: server-7.tower-206.messagelabs.com!1472716607!57094665!1 X-Originating-IP: [217.140.101.70] X-SpamReason: No, hits=0.0 required=7.0 tests= X-StarScan-Received: X-StarScan-Version: 8.84; banners=-,-,- X-VirusChecked: Checked Received: (qmail 14316 invoked from network); 1 Sep 2016 07:56:47 -0000 Received: from foss.arm.com (HELO foss.arm.com) (217.140.101.70) by server-7.tower-206.messagelabs.com with SMTP; 1 Sep 2016 07:56:47 -0000 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.72.51.249]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 42A3F2B; Thu, 1 Sep 2016 00:56:46 -0700 (PDT) Received: from e108454-lin.cambridge.arm.com (e108454-lin.cambridge.arm.com [10.1.218.32]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id E6C783F220; Thu, 1 Sep 2016 00:56:44 -0700 (PDT) From: Julien Grall To: xen-devel@lists.xen.org Date: Thu, 1 Sep 2016 08:56:39 +0100 Message-Id: <1472716599-2894-1-git-send-email-julien.grall@arm.com> X-Mailer: git-send-email 1.9.1 Cc: Julien Grall , sstabellini@kernel.org Subject: [Xen-devel] [PATCH] xen/arm: alternative: Make it possible to patch outside of the hypervisor 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" With livepatch the alternatives that should be patched are outside of the Xen hypervisor _start -> _end. The current code is assuming that only Xen could be patched and therefore will explode when a payload contains alternatives. Given that alt_instr contains a relative offset, the function __apply_alternatives could directly take in parameter the virtual address of the alt_instr set of the re-mapped region. So we can mandate the callers of __apply_alternatives to ensure the region has read-write access beforehand. The only caller that will patch directly the Xen binary is the function __apply_alternatives_multi_stop. The other caller apply_alternatives will work on the payload which will still have read-write access at that time. Signed-off-by: Julien Grall --- Cc: Konrad Rzeszutek Wilk This is an alternative of the patch suggested by Konrad [1] to fix alternatives patching with livepatching. [1] https://lists.xenproject.org/archives/html/xen-devel/2016-08/msg02880.html --- xen/arch/arm/alternative.c | 58 +++++++++++++++++++++++++--------------------- 1 file changed, 31 insertions(+), 27 deletions(-) diff --git a/xen/arch/arm/alternative.c b/xen/arch/arm/alternative.c index 8ee5a11..db4bd0f 100644 --- a/xen/arch/arm/alternative.c +++ b/xen/arch/arm/alternative.c @@ -97,26 +97,11 @@ static u32 get_alt_insn(const struct alt_instr *alt, static int __apply_alternatives(const struct alt_region *region) { const struct alt_instr *alt; - const u32 *origptr, *replptr; - u32 *writeptr, *writemap; - mfn_t text_mfn = _mfn(virt_to_mfn(_stext)); - unsigned int text_order = get_order_from_bytes(_end - _start); + const u32 *replptr; + u32 *origptr; printk(XENLOG_INFO "alternatives: Patching kernel code\n"); - /* - * The text section is read-only. So re-map Xen to be able to patch - * the code. - */ - writemap = __vmap(&text_mfn, 1 << text_order, 1, 1, PAGE_HYPERVISOR, - VMAP_DEFAULT); - if ( !writemap ) - { - printk(XENLOG_ERR "alternatives: Unable to map the text section (size %u)\n", - 1 << text_order); - return -ENOMEM; - } - for ( alt = region->begin; alt < region->end; alt++ ) { u32 insn; @@ -128,7 +113,6 @@ static int __apply_alternatives(const struct alt_region *region) BUG_ON(alt->alt_len != alt->orig_len); origptr = ALT_ORIG_PTR(alt); - writeptr = origptr - (u32 *)_start + writemap; replptr = ALT_REPL_PTR(alt); nr_inst = alt->alt_len / sizeof(insn); @@ -136,19 +120,17 @@ static int __apply_alternatives(const struct alt_region *region) for ( i = 0; i < nr_inst; i++ ) { insn = get_alt_insn(alt, origptr + i, replptr + i); - *(writeptr + i) = cpu_to_le32(insn); + *(origptr + i) = cpu_to_le32(insn); } /* Ensure the new instructions reached the memory and nuke */ - clean_and_invalidate_dcache_va_range(writeptr, - (sizeof (*writeptr) * nr_inst)); + clean_and_invalidate_dcache_va_range(origptr, + (sizeof (*origptr) * nr_inst)); } /* Nuke the instruction cache */ invalidate_icache(); - vunmap(writemap); - return 0; } @@ -159,10 +141,6 @@ static int __apply_alternatives(const struct alt_region *region) static int __apply_alternatives_multi_stop(void *unused) { static int patched = 0; - const struct alt_region region = { - .begin = __alt_instructions, - .end = __alt_instructions_end, - }; /* We always have a CPU 0 at this point (__init) */ if ( smp_processor_id() ) @@ -174,12 +152,38 @@ static int __apply_alternatives_multi_stop(void *unused) else { int ret; + struct alt_region region; + mfn_t xen_mfn = _mfn(virt_to_mfn(_start)); + unsigned int xen_order = get_order_from_bytes(_end - _start); + char *xenmap; BUG_ON(patched); + + /* + * The text and inittext section is read-only. So re-map Xen to + * be able to patch the code. + */ + xenmap = __vmap(&xen_mfn, 1U << xen_order, 1, 1, PAGE_HYPERVISOR, + VMAP_DEFAULT); + /* Re-mapping Xen is not expected to fail during boot. */ + BUG_ON(!xenmap); + + /* + * Find the virtual address of the alternative region in the new + * mapping. + * alt_instr contains relative offset, so the function + * __apply_alternatives will patch in the re-mapped version of + * Xen. + */ + region.begin = (void *)((char *)__alt_instructions - _start + xenmap); + region.end = (void *)((char *)__alt_instructions_end - _start + xenmap); + ret = __apply_alternatives(®ion); /* The patching is not expected to fail during boot. */ BUG_ON(ret != 0); + vunmap(xenmap); + /* Barriers provided by the cache flushing */ write_atomic(&patched, 1); }