From: Matt Fleming <matt-HNK1S37rvNbeXh+fF434Mdi2O/JbrIOy@public.gmane.org>
To: Ard Biesheuvel <ard.biesheuvel-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org,
linux-efi-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
leif.lindholm-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org,
roy.franz-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org,
mark.rutland-5wv7dgnIgG8@public.gmane.org,
catalin.marinas-5wv7dgnIgG8@public.gmane.org,
will.deacon-5wv7dgnIgG8@public.gmane.org,
matt.fleming-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org,
bp-Gina5bIWoIWzQB+pC5nmwQ@public.gmane.org,
dyoung-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org,
geoff.levand-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org,
msalter-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org
Subject: Re: [PATCH v4 6/8] arm64/efi: move SetVirtualAddressMap() to UEFI stub
Date: Mon, 5 Jan 2015 16:54:02 +0000 [thread overview]
Message-ID: <20150105165402.GE3163@console-pimps.org> (raw)
In-Reply-To: <1419245944-2424-7-git-send-email-ard.biesheuvel-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
On Mon, 22 Dec, at 10:59:02AM, Ard Biesheuvel wrote:
> In order to support kexec, the kernel needs to be able to deal with the
> state of the UEFI firmware after SetVirtualAddressMap() has been called.
> To avoid having separate code paths for non-kexec and kexec, let's move
> the call to SetVirtualAddressMap() to the stub: this will guarantee us
> that it will only be called once (since the stub is not executed during
> kexec), and ensures that the UEFI state is identical between kexec and
> normal boot.
>
> This implies that the layout of the virtual mapping needs to be created
> by the stub as well. All regions are rounded up to a naturally aligned
> multiple of 64 KB (for compatibility with 64k pages kernels) and recorded
> in the UEFI memory map. The kernel proper reads those values and installs
> the mappings in a dedicated set of page tables that are swapped in during
> UEFI Runtime Services calls.
>
> Signed-off-by: Ard Biesheuvel <ard.biesheuvel-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> ---
> arch/arm64/include/asm/efi.h | 20 +++-
> arch/arm64/kernel/efi.c | 223 ++++++++++++++++++++-----------------
> arch/arm64/kernel/setup.c | 1 +
> drivers/firmware/efi/libstub/fdt.c | 137 ++++++++++++++++++++++-
> 4 files changed, 270 insertions(+), 111 deletions(-)
[...]
> @@ -45,5 +53,9 @@ extern void efi_idmap_init(void);
> #define efi_call_early(f, ...) sys_table_arg->boottime->f(__VA_ARGS__)
>
> #define EFI_ALLOC_ALIGN SZ_64K
> +#define EFI_VIRTMAP EFI_ARCH_1
Any chance of documenting what EFI_VIRTMAP means for posterity and why
you want to use one of the EFI arch config bits? How is this different
from EFI_RUNTIME_SERVICES?
Take a look at EFI_OLD_MEMMAP in arch/x86/include/asm/efi.h for a
crackingly well documented example from Borislav.
[...]
> diff --git a/drivers/firmware/efi/libstub/fdt.c b/drivers/firmware/efi/libstub/fdt.c
> index c846a9608cbd..76bc8abf41d1 100644
> --- a/drivers/firmware/efi/libstub/fdt.c
> +++ b/drivers/firmware/efi/libstub/fdt.c
> @@ -167,6 +167,94 @@ fdt_set_fail:
> #define EFI_FDT_ALIGN EFI_PAGE_SIZE
> #endif
>
> +static efi_status_t get_memory_map(efi_system_table_t *sys_table_arg,
> + efi_memory_desc_t **map,
> + unsigned long *map_size,
> + unsigned long *desc_size,
> + u32 *desc_ver, unsigned long *key_ptr)
> +{
> + efi_status_t status;
> +
> + /*
> + * Call get_memory_map() with 0 size to retrieve the size of the
> + * required allocation.
> + */
> + *map_size = 0;
> + status = efi_call_early(get_memory_map, map_size, NULL,
> + key_ptr, desc_size, desc_ver);
> + if (status != EFI_BUFFER_TOO_SMALL)
> + return EFI_LOAD_ERROR;
> +
> + /*
> + * Add an additional efi_memory_desc_t to map_size because we're doing
> + * an allocation which may be in a new descriptor region. Then double it
> + * to give us some scratch space to prepare the input virtmap to give
> + * to SetVirtualAddressMap(). Note that this is EFI_LOADER_DATA memory,
> + * and the kernel memblock_reserve()'s only the size of the actual
> + * memory map, so the scratch space is freed again automatically.
> + */
> + *map_size += *desc_size;
> + status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
> + *map_size * 2, (void **)map);
> + if (status != EFI_SUCCESS)
> + return status;
> +
> + status = efi_call_early(get_memory_map, map_size, *map,
> + key_ptr, desc_size, desc_ver);
> + if (status != EFI_SUCCESS)
> + efi_call_early(free_pool, *map);
> + return status;
> +}
We've now got two (slightly different) versions of this function. Is
there any way we could make do with just one?
> +/*
> + * This is the base address at which to start allocating virtual memory ranges
> + * for UEFI Runtime Services. This is a userland range so that we can use any
> + * allocation we choose, and eliminate the risk of a conflict after kexec.
> + */
> +#define EFI_RT_VIRTUAL_BASE 0x40000000
> +
> +static void update_memory_map(efi_memory_desc_t *memory_map,
> + unsigned long map_size, unsigned long desc_size,
> + int *count)
> +{
> + u64 efi_virt_base = EFI_RT_VIRTUAL_BASE;
> + efi_memory_desc_t *out = (void *)memory_map + map_size;
> + int l;
> +
> + for (l = 0; l < map_size; l += desc_size) {
> + efi_memory_desc_t *in = (void *)memory_map + l;
> + u64 paddr, size;
> +
> + if (!(in->attribute & EFI_MEMORY_RUNTIME))
> + continue;
> +
> + /*
> + * Make the mapping compatible with 64k pages: this allows
> + * a 4k page size kernel to kexec a 64k page size kernel and
> + * vice versa.
> + */
> + paddr = round_down(in->phys_addr, SZ_64K);
> + size = round_up(in->num_pages * EFI_PAGE_SIZE +
> + in->phys_addr - paddr, SZ_64K);
> +
> + /*
> + * Avoid wasting memory on PTEs by choosing a virtual base that
> + * is compatible with section mappings if this region has the
> + * appropriate size and physical alignment. (Sections are 2 MB
> + * on 4k granule kernels)
> + */
> + if (IS_ALIGNED(in->phys_addr, SZ_2M) && size >= SZ_2M)
> + efi_virt_base = round_up(efi_virt_base, SZ_2M);
> +
> + in->virt_addr = efi_virt_base + in->phys_addr - paddr;
> + efi_virt_base += size;
> +
> + memcpy(out, in, desc_size);
> + out = (void *)out + desc_size;
> + ++*count;
> + }
> +}
> +
fdt.c is starting to become a dumping ground for arm*-specific stuff :-(
Is there no general solution for sharing code between arm and aarch64 in
the kernel so we don't have to stick things like this in
drivers/firmware/efi/?
--
Matt Fleming, Intel Open Source Technology Center
WARNING: multiple messages have this Message-ID (diff)
From: matt@console-pimps.org (Matt Fleming)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH v4 6/8] arm64/efi: move SetVirtualAddressMap() to UEFI stub
Date: Mon, 5 Jan 2015 16:54:02 +0000 [thread overview]
Message-ID: <20150105165402.GE3163@console-pimps.org> (raw)
In-Reply-To: <1419245944-2424-7-git-send-email-ard.biesheuvel@linaro.org>
On Mon, 22 Dec, at 10:59:02AM, Ard Biesheuvel wrote:
> In order to support kexec, the kernel needs to be able to deal with the
> state of the UEFI firmware after SetVirtualAddressMap() has been called.
> To avoid having separate code paths for non-kexec and kexec, let's move
> the call to SetVirtualAddressMap() to the stub: this will guarantee us
> that it will only be called once (since the stub is not executed during
> kexec), and ensures that the UEFI state is identical between kexec and
> normal boot.
>
> This implies that the layout of the virtual mapping needs to be created
> by the stub as well. All regions are rounded up to a naturally aligned
> multiple of 64 KB (for compatibility with 64k pages kernels) and recorded
> in the UEFI memory map. The kernel proper reads those values and installs
> the mappings in a dedicated set of page tables that are swapped in during
> UEFI Runtime Services calls.
>
> Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> ---
> arch/arm64/include/asm/efi.h | 20 +++-
> arch/arm64/kernel/efi.c | 223 ++++++++++++++++++++-----------------
> arch/arm64/kernel/setup.c | 1 +
> drivers/firmware/efi/libstub/fdt.c | 137 ++++++++++++++++++++++-
> 4 files changed, 270 insertions(+), 111 deletions(-)
[...]
> @@ -45,5 +53,9 @@ extern void efi_idmap_init(void);
> #define efi_call_early(f, ...) sys_table_arg->boottime->f(__VA_ARGS__)
>
> #define EFI_ALLOC_ALIGN SZ_64K
> +#define EFI_VIRTMAP EFI_ARCH_1
Any chance of documenting what EFI_VIRTMAP means for posterity and why
you want to use one of the EFI arch config bits? How is this different
from EFI_RUNTIME_SERVICES?
Take a look at EFI_OLD_MEMMAP in arch/x86/include/asm/efi.h for a
crackingly well documented example from Borislav.
[...]
> diff --git a/drivers/firmware/efi/libstub/fdt.c b/drivers/firmware/efi/libstub/fdt.c
> index c846a9608cbd..76bc8abf41d1 100644
> --- a/drivers/firmware/efi/libstub/fdt.c
> +++ b/drivers/firmware/efi/libstub/fdt.c
> @@ -167,6 +167,94 @@ fdt_set_fail:
> #define EFI_FDT_ALIGN EFI_PAGE_SIZE
> #endif
>
> +static efi_status_t get_memory_map(efi_system_table_t *sys_table_arg,
> + efi_memory_desc_t **map,
> + unsigned long *map_size,
> + unsigned long *desc_size,
> + u32 *desc_ver, unsigned long *key_ptr)
> +{
> + efi_status_t status;
> +
> + /*
> + * Call get_memory_map() with 0 size to retrieve the size of the
> + * required allocation.
> + */
> + *map_size = 0;
> + status = efi_call_early(get_memory_map, map_size, NULL,
> + key_ptr, desc_size, desc_ver);
> + if (status != EFI_BUFFER_TOO_SMALL)
> + return EFI_LOAD_ERROR;
> +
> + /*
> + * Add an additional efi_memory_desc_t to map_size because we're doing
> + * an allocation which may be in a new descriptor region. Then double it
> + * to give us some scratch space to prepare the input virtmap to give
> + * to SetVirtualAddressMap(). Note that this is EFI_LOADER_DATA memory,
> + * and the kernel memblock_reserve()'s only the size of the actual
> + * memory map, so the scratch space is freed again automatically.
> + */
> + *map_size += *desc_size;
> + status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
> + *map_size * 2, (void **)map);
> + if (status != EFI_SUCCESS)
> + return status;
> +
> + status = efi_call_early(get_memory_map, map_size, *map,
> + key_ptr, desc_size, desc_ver);
> + if (status != EFI_SUCCESS)
> + efi_call_early(free_pool, *map);
> + return status;
> +}
We've now got two (slightly different) versions of this function. Is
there any way we could make do with just one?
> +/*
> + * This is the base address at which to start allocating virtual memory ranges
> + * for UEFI Runtime Services. This is a userland range so that we can use any
> + * allocation we choose, and eliminate the risk of a conflict after kexec.
> + */
> +#define EFI_RT_VIRTUAL_BASE 0x40000000
> +
> +static void update_memory_map(efi_memory_desc_t *memory_map,
> + unsigned long map_size, unsigned long desc_size,
> + int *count)
> +{
> + u64 efi_virt_base = EFI_RT_VIRTUAL_BASE;
> + efi_memory_desc_t *out = (void *)memory_map + map_size;
> + int l;
> +
> + for (l = 0; l < map_size; l += desc_size) {
> + efi_memory_desc_t *in = (void *)memory_map + l;
> + u64 paddr, size;
> +
> + if (!(in->attribute & EFI_MEMORY_RUNTIME))
> + continue;
> +
> + /*
> + * Make the mapping compatible with 64k pages: this allows
> + * a 4k page size kernel to kexec a 64k page size kernel and
> + * vice versa.
> + */
> + paddr = round_down(in->phys_addr, SZ_64K);
> + size = round_up(in->num_pages * EFI_PAGE_SIZE +
> + in->phys_addr - paddr, SZ_64K);
> +
> + /*
> + * Avoid wasting memory on PTEs by choosing a virtual base that
> + * is compatible with section mappings if this region has the
> + * appropriate size and physical alignment. (Sections are 2 MB
> + * on 4k granule kernels)
> + */
> + if (IS_ALIGNED(in->phys_addr, SZ_2M) && size >= SZ_2M)
> + efi_virt_base = round_up(efi_virt_base, SZ_2M);
> +
> + in->virt_addr = efi_virt_base + in->phys_addr - paddr;
> + efi_virt_base += size;
> +
> + memcpy(out, in, desc_size);
> + out = (void *)out + desc_size;
> + ++*count;
> + }
> +}
> +
fdt.c is starting to become a dumping ground for arm*-specific stuff :-(
Is there no general solution for sharing code between arm and aarch64 in
the kernel so we don't have to stick things like this in
drivers/firmware/efi/?
--
Matt Fleming, Intel Open Source Technology Center
next prev parent reply other threads:[~2015-01-05 16:54 UTC|newest]
Thread overview: 60+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-12-22 10:58 [PATCH v4 0/8] stable UEFI virtual mappings for kexec Ard Biesheuvel
2014-12-22 10:58 ` Ard Biesheuvel
[not found] ` <1419245944-2424-1-git-send-email-ard.biesheuvel-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
2014-12-22 10:58 ` [PATCH v4 1/8] arm64/mm: add explicit struct_mm argument to __create_mapping() Ard Biesheuvel
2014-12-22 10:58 ` Ard Biesheuvel
2014-12-22 10:58 ` [PATCH v4 2/8] arm64/mm: add create_pgd_mapping() to create private page tables Ard Biesheuvel
2014-12-22 10:58 ` Ard Biesheuvel
2014-12-22 10:58 ` [PATCH v4 3/8] efi: split off remapping code from efi_config_init() Ard Biesheuvel
2014-12-22 10:58 ` Ard Biesheuvel
[not found] ` <1419245944-2424-4-git-send-email-ard.biesheuvel-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
2015-01-05 14:55 ` Matt Fleming
2015-01-05 14:55 ` Matt Fleming
2015-01-05 21:56 ` Borislav Petkov
2015-01-05 21:56 ` Borislav Petkov
2014-12-22 10:59 ` [PATCH v4 4/8] efi: efistub: allow allocation alignment larger than EFI_PAGE_SIZE Ard Biesheuvel
2014-12-22 10:59 ` Ard Biesheuvel
[not found] ` <1419245944-2424-5-git-send-email-ard.biesheuvel-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
2014-12-23 16:45 ` Borislav Petkov
2014-12-23 16:45 ` Borislav Petkov
[not found] ` <20141223164549.GB3810-fF5Pk5pvG8Y@public.gmane.org>
2014-12-29 9:25 ` Ard Biesheuvel
2014-12-29 9:25 ` Ard Biesheuvel
[not found] ` <CAKv+Gu_+scCHYuXccgsvn9THsbP24OfyjvjN9XtEVe4nMdQtig-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2014-12-29 9:47 ` Borislav Petkov
2014-12-29 9:47 ` Borislav Petkov
[not found] ` <20141229094732.GA16051-K5JNixvcfoxupOikMc4+xw@public.gmane.org>
2015-01-05 11:24 ` Ard Biesheuvel
2015-01-05 11:24 ` Ard Biesheuvel
2014-12-22 10:59 ` [PATCH v4 5/8] arm64/efi: set EFI_ALLOC_ALIGN to 64 KB Ard Biesheuvel
2014-12-22 10:59 ` Ard Biesheuvel
2015-01-06 16:37 ` Leif Lindholm
2015-01-06 16:37 ` Leif Lindholm
2014-12-22 10:59 ` [PATCH v4 6/8] arm64/efi: move SetVirtualAddressMap() to UEFI stub Ard Biesheuvel
2014-12-22 10:59 ` Ard Biesheuvel
[not found] ` <1419245944-2424-7-git-send-email-ard.biesheuvel-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
2015-01-05 16:20 ` Mark Rutland
2015-01-05 16:20 ` Mark Rutland
2015-01-06 17:13 ` Leif Lindholm
2015-01-06 17:13 ` Leif Lindholm
2015-01-07 18:05 ` Ard Biesheuvel
2015-01-07 18:05 ` Ard Biesheuvel
2015-01-05 16:54 ` Matt Fleming [this message]
2015-01-05 16:54 ` Matt Fleming
[not found] ` <20150105165402.GE3163-HNK1S37rvNbeXh+fF434Mdi2O/JbrIOy@public.gmane.org>
2015-01-06 18:01 ` Leif Lindholm
2015-01-06 18:01 ` Leif Lindholm
[not found] ` <20150106180120.GF3827-t77nlHhSwNqAroYi2ySoxKxOck334EZe@public.gmane.org>
2015-01-12 10:43 ` Matt Fleming
2015-01-12 10:43 ` Matt Fleming
2015-01-07 18:15 ` Ard Biesheuvel
2015-01-07 18:15 ` Ard Biesheuvel
2015-01-07 12:06 ` Leif Lindholm
2015-01-07 12:06 ` Leif Lindholm
[not found] ` <20150107120608.GJ3827-t77nlHhSwNqAroYi2ySoxKxOck334EZe@public.gmane.org>
2015-01-07 12:16 ` Ard Biesheuvel
2015-01-07 12:16 ` Ard Biesheuvel
[not found] ` <CAKv+Gu_k0_anqvm24P8J4WaMrFLMxOhQETAfUb6xmzaJ+Z2vBQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2015-01-07 12:25 ` Leif Lindholm
2015-01-07 12:25 ` Leif Lindholm
[not found] ` <20150107122515.GK3827-t77nlHhSwNqAroYi2ySoxKxOck334EZe@public.gmane.org>
2015-01-07 12:30 ` Ard Biesheuvel
2015-01-07 12:30 ` Ard Biesheuvel
[not found] ` <CAKv+Gu-aRkoRj5zVXrsBc0APCehZ9W926J6fxH380K9EURXe_Q-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2015-01-07 12:56 ` Leif Lindholm
2015-01-07 12:56 ` Leif Lindholm
2014-12-22 10:59 ` [PATCH v4 7/8] arm64/efi: remove free_boot_services() and friends Ard Biesheuvel
2014-12-22 10:59 ` Ard Biesheuvel
[not found] ` <1419245944-2424-8-git-send-email-ard.biesheuvel-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
2015-01-06 18:06 ` Leif Lindholm
2015-01-06 18:06 ` Leif Lindholm
2014-12-22 10:59 ` [PATCH v4 8/8] arm64/efi: remove idmap manipulations from UEFI code Ard Biesheuvel
2014-12-22 10:59 ` Ard Biesheuvel
[not found] ` <1419245944-2424-9-git-send-email-ard.biesheuvel-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
2015-01-06 18:17 ` Leif Lindholm
2015-01-06 18:17 ` Leif Lindholm
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=20150105165402.GE3163@console-pimps.org \
--to=matt-hnk1s37rvnbexh+ff434mdi2o/jbrioy@public.gmane.org \
--cc=ard.biesheuvel-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org \
--cc=bp-Gina5bIWoIWzQB+pC5nmwQ@public.gmane.org \
--cc=catalin.marinas-5wv7dgnIgG8@public.gmane.org \
--cc=dyoung-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org \
--cc=geoff.levand-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org \
--cc=leif.lindholm-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org \
--cc=linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org \
--cc=linux-efi-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
--cc=mark.rutland-5wv7dgnIgG8@public.gmane.org \
--cc=matt.fleming-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org \
--cc=msalter-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org \
--cc=roy.franz-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org \
--cc=will.deacon-5wv7dgnIgG8@public.gmane.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.