From: Pavel Tatashin <pasha.tatashin@soleen.com>
To: pasha.tatashin@soleen.com, jmorris@namei.org, sashal@kernel.org,
ebiederm@xmission.com, kexec@lists.infradead.org,
linux-kernel@vger.kernel.org, corbet@lwn.net,
catalin.marinas@arm.com, will@kernel.org,
linux-arm-kernel@lists.infradead.org, marc.zyngier@arm.com,
james.morse@arm.com, vladimir.murzin@arm.com,
matthias.bgg@gmail.com, bhsharma@redhat.com, linux-mm@kvack.org,
mark.rutland@arm.com, steve.capper@arm.com, rfontana@redhat.com,
tglx@linutronix.de
Subject: [PATCH v8 23/25] arm64: kexec: configure trans_pgd page table for kexec
Date: Wed, 4 Dec 2019 10:59:36 -0500 [thread overview]
Message-ID: <20191204155938.2279686-24-pasha.tatashin@soleen.com> (raw)
In-Reply-To: <20191204155938.2279686-1-pasha.tatashin@soleen.com>
Configure a page table located in kexec-safe memory that has
the following mappings:
1. identity mapping for text of relocation function with executable
permission.
2. identity mapping for argument for relocation function.
3. linear mappings for all source ranges
4. linear mappings for all destination ranges.
Signed-off-by: Pavel Tatashin <pasha.tatashin@soleen.com>
---
arch/arm64/include/asm/kexec.h | 14 ++++
arch/arm64/kernel/asm-offsets.c | 5 ++
arch/arm64/kernel/machine_kexec.c | 104 +++++++++++++++++++++++++++++-
3 files changed, 122 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/include/asm/kexec.h b/arch/arm64/include/asm/kexec.h
index 414a0a41a60a..df911a4aa8ce 100644
--- a/arch/arm64/include/asm/kexec.h
+++ b/arch/arm64/include/asm/kexec.h
@@ -98,6 +98,10 @@ extern const unsigned long kexec_kern_reloc_offset;
extern const unsigned long kexec_el2_vectors_offset;
#endif
+#define KEXEC_SRC_START PAGE_OFFSET
+#define KEXEC_DST_START (PAGE_OFFSET + \
+ ((UL(0xffffffffffffffff) - PAGE_OFFSET) >> 1) + 1)
+
/*
* kern_reloc_arg is passed to kernel relocation function as an argument.
* head kimage->head, allows to traverse through relocation segments.
@@ -108,6 +112,11 @@ extern const unsigned long kexec_el2_vectors_offset;
* el2_vector If present means that relocation routine will go to EL1
* from EL2 to do the copy, and then back to EL2 to do the jump
* to new world.
+ * trans_ttbr0 idmap for relocation function and its argument
+ * trans_ttbr1 linear map for source/destination addresses.
+ * src_addr linear map for source pages.
+ * dst_addr linear map for destination pages.
+ * copy_len Number of bytes that need to be copied
*/
struct kern_reloc_arg {
phys_addr_t head;
@@ -117,6 +126,11 @@ struct kern_reloc_arg {
phys_addr_t kern_arg2;
phys_addr_t kern_arg3;
phys_addr_t el2_vector;
+ phys_addr_t trans_ttbr0;
+ phys_addr_t trans_ttbr1;
+ void *src_addr;
+ void *dst_addr;
+ unsigned long copy_len;
};
#define ARCH_HAS_KIMAGE_ARCH
diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c
index ff974b648347..63060ea51727 100644
--- a/arch/arm64/kernel/asm-offsets.c
+++ b/arch/arm64/kernel/asm-offsets.c
@@ -137,6 +137,11 @@ int main(void)
DEFINE(KEXEC_KRELOC_KERN_ARG2, offsetof(struct kern_reloc_arg, kern_arg2));
DEFINE(KEXEC_KRELOC_KERN_ARG3, offsetof(struct kern_reloc_arg, kern_arg3));
DEFINE(KEXEC_KRELOC_EL2_VECTOR, offsetof(struct kern_reloc_arg, el2_vector));
+ DEFINE(KEXEC_KRELOC_TRANS_TTBR0, offsetof(struct kern_reloc_arg, trans_ttbr0));
+ DEFINE(KEXEC_KRELOC_TRANS_TTBR1, offsetof(struct kern_reloc_arg, trans_ttbr1));
+ DEFINE(KEXEC_KRELOC_SRC_ADDR, offsetof(struct kern_reloc_arg, src_addr));
+ DEFINE(KEXEC_KRELOC_DST_ADDR, offsetof(struct kern_reloc_arg, dst_addr));
+ DEFINE(KEXEC_KRELOC_COPY_LEN, offsetof(struct kern_reloc_arg, copy_len));
#endif
return 0;
}
diff --git a/arch/arm64/kernel/machine_kexec.c b/arch/arm64/kernel/machine_kexec.c
index ac6ade7c96ff..8edcc4be0b15 100644
--- a/arch/arm64/kernel/machine_kexec.c
+++ b/arch/arm64/kernel/machine_kexec.c
@@ -20,6 +20,7 @@
#include <asm/mmu.h>
#include <asm/mmu_context.h>
#include <asm/page.h>
+#include <asm/trans_pgd.h>
#include "cpu-reset.h"
@@ -70,10 +71,102 @@ static void *kexec_page_alloc(void *arg)
return page_address(page);
}
+/*
+ * Map source segments starting from KEXEC_SRC_START, and map destination
+ * segments starting from KEXEC_DST_START, and return size of copy in
+ * *copy_len argument.
+ * Relocation function essentially needs to do:
+ * memcpy(KEXEC_DST_START, KEXEC_SRC_START, copy_len);
+ */
+static int map_segments(struct kimage *kimage, pgd_t *pgdp,
+ struct trans_pgd_info *info,
+ unsigned long *copy_len)
+{
+ unsigned long *ptr = 0;
+ unsigned long dest = 0;
+ unsigned long src_va = KEXEC_SRC_START;
+ unsigned long dst_va = KEXEC_DST_START;
+ unsigned long len = 0;
+ unsigned long entry, addr;
+ int rc;
+
+ for (entry = kimage->head; !(entry & IND_DONE); entry = *ptr++) {
+ addr = entry & PAGE_MASK;
+
+ switch (entry & IND_FLAGS) {
+ case IND_DESTINATION:
+ dest = addr;
+ break;
+ case IND_INDIRECTION:
+ ptr = __va(addr);
+ if (rc)
+ return rc;
+ break;
+ case IND_SOURCE:
+ rc = trans_pgd_map_page(info, pgdp, __va(addr),
+ src_va, PAGE_KERNEL);
+ if (rc)
+ return rc;
+ rc = trans_pgd_map_page(info, pgdp, __va(dest),
+ dst_va, PAGE_KERNEL);
+ if (rc)
+ return rc;
+ dest += PAGE_SIZE;
+ src_va += PAGE_SIZE;
+ dst_va += PAGE_SIZE;
+ len += PAGE_SIZE;
+ }
+ }
+ *copy_len = len;
+
+ return 0;
+}
+
+static int mmu_relocate_setup(struct kimage *kimage, void *reloc_code,
+ struct kern_reloc_arg *kern_reloc_arg)
+{
+ struct trans_pgd_info info = {
+ .trans_alloc_page = kexec_page_alloc,
+ .trans_alloc_arg = kimage,
+ };
+
+ pgd_t *trans_ttbr0 = kexec_page_alloc(kimage);
+ pgd_t *trans_ttbr1 = kexec_page_alloc(kimage);
+ int rc;
+
+ if (!trans_ttbr0 || !trans_ttbr1)
+ return -ENOMEM;
+
+ rc = map_segments(kimage, trans_ttbr1, &info,
+ &kern_reloc_arg->copy_len);
+ if (rc)
+ return rc;
+
+ /* Map relocation function va == pa */
+ rc = trans_pgd_map_page(&info, trans_ttbr0, reloc_code,
+ __pa(reloc_code), PAGE_KERNEL_EXEC);
+ if (rc)
+ return rc;
+
+ /* Map relocation function argument va == pa */
+ rc = trans_pgd_map_page(&info, trans_ttbr0, kern_reloc_arg,
+ __pa(kern_reloc_arg), PAGE_KERNEL);
+ if (rc)
+ return rc;
+
+ kern_reloc_arg->trans_ttbr0 = phys_to_ttbr(__pa(trans_ttbr0));
+ kern_reloc_arg->trans_ttbr1 = phys_to_ttbr(__pa(trans_ttbr1));
+ kern_reloc_arg->src_addr = (void *)KEXEC_SRC_START;
+ kern_reloc_arg->dst_addr = (void *)KEXEC_DST_START;
+
+ return 0;
+}
+
int machine_kexec_post_load(struct kimage *kimage)
{
void *reloc_code = page_to_virt(kimage->control_code_page);
struct kern_reloc_arg *kern_reloc_arg = kexec_page_alloc(kimage);
+ int rc = 0;
if (!kern_reloc_arg)
return -ENOMEM;
@@ -89,9 +182,18 @@ int machine_kexec_post_load(struct kimage *kimage)
kern_reloc_arg->el2_vector = __pa(reloc_code)
+ kexec_el2_vectors_offset;
}
+
+ /*
+ * If relocation is not needed, we do not need to enable MMU in
+ * relocation routine, therefore do not create page tables for
+ * scenarios such as crash kernel
+ */
+ if (!(kimage->head & IND_DONE))
+ rc = mmu_relocate_setup(kimage, reloc_code, kern_reloc_arg);
+
kexec_image_info(kimage);
- return 0;
+ return rc;
}
--
2.24.0
next prev parent reply other threads:[~2019-12-04 16:00 UTC|newest]
Thread overview: 29+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-12-04 15:59 [PATCH v8 00/25] arm64: MMU enabled kexec relocation Pavel Tatashin
2019-12-04 15:59 ` [PATCH v8 01/25] kexec: quiet down kexec reboot Pavel Tatashin
2019-12-04 15:59 ` [PATCH v8 02/25] kexec: add machine_kexec_post_load() Pavel Tatashin
2019-12-04 15:59 ` [PATCH v8 03/25] arm64: kexec: remove unnecessary debug prints Pavel Tatashin
2019-12-04 15:59 ` [PATCH v8 04/25] arm64: kexec: make dtb_mem always enabled Pavel Tatashin
2019-12-04 15:59 ` [PATCH v8 05/25] arm64: hibernate: pass the allocated pgdp to ttbr0 Pavel Tatashin
2019-12-04 15:59 ` [PATCH v8 06/25] arm64: hibernate: use get_safe_page directly Pavel Tatashin
2019-12-04 15:59 ` [PATCH v8 07/25] arm64: hibernate: remove gotos as they are not needed Pavel Tatashin
2019-12-04 15:59 ` [PATCH v8 08/25] arm64: hibernate: rename dst to page in create_safe_exec_page Pavel Tatashin
2019-12-04 15:59 ` [PATCH v8 09/25] arm64: hibernate: add PUD_SECT_RDONLY Pavel Tatashin
2019-12-04 15:59 ` [PATCH v8 10/25] arm64: hibernate: add trans_pgd public functions Pavel Tatashin
2019-12-04 15:59 ` [PATCH v8 11/25] arm64: hibernate: move page handling function to new trans_pgd.c Pavel Tatashin
2019-12-04 15:59 ` [PATCH v8 12/25] arm64: trans_pgd: make trans_pgd_map_page generic Pavel Tatashin
2019-12-04 15:59 ` [PATCH v8 13/25] arm64: trans_pgd: pass allocator trans_pgd_create_copy Pavel Tatashin
2019-12-04 15:59 ` [PATCH v8 14/25] arm64: trans_pgd: pass NULL instead of init_mm to *_populate functions Pavel Tatashin
2019-12-04 15:59 ` [PATCH v8 15/25] arm64: kexec: move relocation function setup Pavel Tatashin
2019-12-04 15:59 ` [PATCH v8 16/25] arm64: kexec: call kexec_image_info only once Pavel Tatashin
2019-12-04 15:59 ` [PATCH v8 17/25] arm64: kexec: cpu_soft_restart change argument types Pavel Tatashin
2019-12-04 15:59 ` [PATCH v8 18/25] arm64: kexec: arm64_relocate_new_kernel clean-ups Pavel Tatashin
2019-12-04 15:59 ` [PATCH v8 19/25] arm64: kexec: arm64_relocate_new_kernel don't use x0 as temp Pavel Tatashin
2019-12-04 15:59 ` [PATCH v8 20/25] arm64: kexec: add expandable argument to relocation function Pavel Tatashin
2019-12-04 15:59 ` [PATCH v8 21/25] arm64: kexec: offset for " Pavel Tatashin
2019-12-04 15:59 ` [PATCH v8 22/25] arm64: kexec: kexec EL2 vectors Pavel Tatashin
2019-12-04 15:59 ` Pavel Tatashin [this message]
2019-12-04 15:59 ` [PATCH v8 24/25] arm64: kexec: enable MMU during kexec relocation Pavel Tatashin
2019-12-04 15:59 ` [PATCH v8 25/25] arm64: kexec: remove head from relocation argument Pavel Tatashin
2020-01-08 17:32 ` [PATCH v8 00/25] arm64: MMU enabled kexec relocation Will Deacon
2020-01-08 17:59 ` Pavel Tatashin
2020-01-15 14:36 ` James Morse
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20191204155938.2279686-24-pasha.tatashin@soleen.com \
--to=pasha.tatashin@soleen.com \
--cc=bhsharma@redhat.com \
--cc=catalin.marinas@arm.com \
--cc=corbet@lwn.net \
--cc=ebiederm@xmission.com \
--cc=james.morse@arm.com \
--cc=jmorris@namei.org \
--cc=kexec@lists.infradead.org \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=marc.zyngier@arm.com \
--cc=mark.rutland@arm.com \
--cc=matthias.bgg@gmail.com \
--cc=rfontana@redhat.com \
--cc=sashal@kernel.org \
--cc=steve.capper@arm.com \
--cc=tglx@linutronix.de \
--cc=vladimir.murzin@arm.com \
--cc=will@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox