From: James Morse <james.morse@arm.com>
To: Pavel Tatashin <pasha.tatashin@soleen.com>
Cc: 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,
vladimir.murzin@arm.com, matthias.bgg@gmail.com,
bhsharma@redhat.com, linux-mm@kvack.org, mark.rutland@arm.com
Subject: Re: [PATCH v6 16/17] arm64: kexec: configure trans_pgd page table for kexec
Date: Fri, 11 Oct 2019 19:21:58 +0100 [thread overview]
Message-ID: <45a2f0b8-5bac-8b5d-d595-f92e9acb27ad@arm.com> (raw)
In-Reply-To: <20191004185234.31471-17-pasha.tatashin@soleen.com>
Hi Pavel,
On 04/10/2019 19:52, Pavel Tatashin wrote:
> 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.
>
> Also, configure el2_vector, that is used to jump to new kernel from EL2 on
> non-VHE kernels.
> diff --git a/arch/arm64/include/asm/kexec.h b/arch/arm64/include/asm/kexec.h
> index d5b79d4c7fae..450d8440f597 100644
> --- a/arch/arm64/include/asm/kexec.h
> +++ b/arch/arm64/include/asm/kexec.h
> @@ -90,6 +90,23 @@ static inline void crash_prepare_suspend(void) {}
> static inline void crash_post_resume(void) {}
> #endif
>
> +#if defined(CONFIG_KEXEC_CORE)
> +/* Global variables for the arm64_relocate_new_kernel routine. */
> +extern const unsigned char arm64_relocate_new_kernel[];
> +extern const unsigned long arm64_relocate_new_kernel_size;
> +
> +/* Body of the vector for escalating to EL2 from relocation routine */
> +extern const unsigned char kexec_el1_sync[];
> +extern const unsigned long kexec_el1_sync_size;
> +#define KEXEC_EL2_VECTOR_TABLE_SIZE 2048
> +#define KEXEC_EL2_SYNC_OFFSET (KEXEC_EL2_VECTOR_TABLE_SIZE / 2)
Yuck.
Please don't generate one-off vectors like this. Create _all_ of them, and have the ones
that should never happen spin round a branch. Someone will hit one eventually, its a lot
easier to work out what happened if it stops on the first fault, instead of executing junk
and flying off into the weeds.
git grep invalid_vector
Having the vectors at a known offset in the page that does the relocation means you have a
fair idea what happened from just the PC.
> diff --git a/arch/arm64/kernel/machine_kexec.c b/arch/arm64/kernel/machine_kexec.c
> index fb6138a1c9ff..71479013dd24 100644
> --- a/arch/arm64/kernel/machine_kexec.c
> +++ b/arch/arm64/kernel/machine_kexec.c
> @@ -74,15 +71,124 @@ static void *kexec_page_alloc(void *arg)
> +/*
> + * 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;
> + }
It looks like you're building a swiss cheese.
If you disable RODATA_FULL_DEFAULT_ENABLED, the kernel will use block mappings for the
linear map. This dramatically reduces the amount of memory in use. On Juno running with
39bit/4K, there is typically 6G of contiguous memory with no firmware/uefi holes in it.
This is mapped by 6 1G block mappings, which take up no additional memory.
For the first go at supporting this in mainline please keep as close as possible to the
existing hibernate code. Please use the helpers that copy the linear map.
(if you cant do pa->va in the relocation assembly you'd need to generate a virtually
addressed structure, which could then use hibernate's relocation assembly)
If all this extra code turns out to be a significant performance improvement, I'd like to
see the numbers. We can come back to it after we've got the simplest way of running
kexec's relocation with the MMU on merged.
> +static int mmu_relocate_setup(struct kimage *kimage, unsigned long kern_reloc,
> + 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, __va(kern_reloc),
> + kern_reloc, PAGE_KERNEL_EXEC);
> + if (rc)
> + return rc;
You can't do this with the page table helpers. We support platforms with no memory in
range of TTBR0's VA space. See dd006da21646f
You will need some idmapped memory to turn the MMU off on a system that booted at EL1.
This will need to be in a set of page tables that the helpers can't easily touch - so it
should only be a single page. (like the arch code's existing idmap - although that may
have been overwritten).
(I have a machine where this is a problem, if I get the time I will have a stab at making
hibernate's safe page idmaped).
> int machine_kexec_post_load(struct kimage *kimage)
> {
> + unsigned long el2_vector = 0;
> unsigned long kern_reloc;
> struct kern_reloc_arg *kern_reloc_arg;
> + int rc = 0;
> +
> + /*
> + * Sanity check that relocation function + el2_vector fit into one
> + * page.
> + */
> + if (arm64_relocate_new_kernel_size > KEXEC_EL2_VECTOR_TABLE_SIZE) {
> + pr_err("can't fit relocation function and el2_vector in one page");
> + return -ENOMEM;
> + }
If you need them to fit in one page, why are the separate?
hibernate does this as a compile time check.
>
> kern_reloc = page_to_phys(kimage->control_code_page);
> memcpy(__va(kern_reloc), arm64_relocate_new_kernel,
> arm64_relocate_new_kernel_size);
>
> + /* Setup vector table only when EL2 is available, but no VHE */
> + if (is_hyp_mode_available() && !is_kernel_in_hyp_mode()) {
> + el2_vector = kern_reloc + KEXEC_EL2_VECTOR_TABLE_SIZE;
> + memcpy(__va(el2_vector + KEXEC_EL2_SYNC_OFFSET), kexec_el1_sync,
> + kexec_el1_sync_size);
> + }
> +
> kern_reloc_arg = kexec_page_alloc(kimage);
> if (!kern_reloc_arg)
> return -ENOMEM;
Thanks,
James
next prev parent reply other threads:[~2019-10-11 18:22 UTC|newest]
Thread overview: 30+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-10-04 18:52 [PATCH v6 00/17] arm64: MMU enabled kexec relocation Pavel Tatashin
2019-10-04 18:52 ` [PATCH v6 01/17] kexec: quiet down kexec reboot Pavel Tatashin
2019-10-04 18:52 ` [PATCH v6 02/17] arm64: hibernate: pass the allocated pgdp to ttbr0 Pavel Tatashin
2019-10-11 18:17 ` James Morse
2019-10-14 14:11 ` Pavel Tatashin
2019-10-04 18:52 ` [PATCH v6 03/17] arm64: hibernate: check pgd table allocation Pavel Tatashin
2019-10-11 18:17 ` James Morse
2019-10-14 14:51 ` Pavel Tatashin
2019-10-04 18:52 ` [PATCH v6 04/17] arm64: hibernate: use get_safe_page directly Pavel Tatashin
2019-10-04 18:52 ` [PATCH v6 05/17] arm64: hibernate: remove gotos as they are not needed Pavel Tatashin
2019-10-04 18:52 ` [PATCH v6 06/17] arm64: hibernate: rename dst to page in create_safe_exec_page Pavel Tatashin
2019-10-04 18:52 ` [PATCH v6 07/17] arm64: hibernate: add PUD_SECT_RDONLY Pavel Tatashin
2019-10-04 18:52 ` [PATCH v6 08/17] arm64: hibernate: add trans_pgd public functions Pavel Tatashin
2019-10-11 18:18 ` James Morse
2019-10-14 15:34 ` Pavel Tatashin
2019-10-04 18:52 ` [PATCH v6 09/17] arm64: hibernate: move page handling function to new trans_pgd.c Pavel Tatashin
2019-10-04 18:52 ` [PATCH v6 10/17] arm64: trans_pgd: make trans_pgd_map_page generic Pavel Tatashin
2019-10-04 18:52 ` [PATCH v6 11/17] arm64: trans_pgd: pass allocator trans_pgd_create_copy Pavel Tatashin
2019-10-04 18:52 ` [PATCH v6 12/17] arm64: trans_pgd: pass NULL instead of init_mm to *_populate functions Pavel Tatashin
2019-10-04 18:52 ` [PATCH v6 13/17] kexec: add machine_kexec_post_load() Pavel Tatashin
2019-10-04 18:52 ` [PATCH v6 14/17] arm64: kexec: move relocation function setup and clean up Pavel Tatashin
2019-10-11 18:19 ` James Morse
2019-10-14 19:29 ` Pavel Tatashin
2019-10-04 18:52 ` [PATCH v6 15/17] arm64: kexec: add expandable argument to relocation function Pavel Tatashin
2019-10-11 18:19 ` James Morse
2019-10-14 23:35 ` Pavel Tatashin
2019-10-04 18:52 ` [PATCH v6 16/17] arm64: kexec: configure trans_pgd page table for kexec Pavel Tatashin
2019-10-11 18:21 ` James Morse [this message]
2019-10-15 2:12 ` Pavel Tatashin
2019-10-04 18:52 ` [PATCH v6 17/17] arm64: kexec: enable MMU during kexec relocation Pavel Tatashin
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=45a2f0b8-5bac-8b5d-d595-f92e9acb27ad@arm.com \
--to=james.morse@arm.com \
--cc=bhsharma@redhat.com \
--cc=catalin.marinas@arm.com \
--cc=corbet@lwn.net \
--cc=ebiederm@xmission.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=pasha.tatashin@soleen.com \
--cc=sashal@kernel.org \
--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