* Re: [PATCH] efi/libstub: Move efi_relocate_kernel() into its only remaining user
2026-04-28 17:06 [PATCH] efi/libstub: Move efi_relocate_kernel() into its only remaining user Ard Biesheuvel
@ 2026-04-29 3:18 ` WANG Rui
2026-04-29 6:37 ` Thomas Huth
2026-04-29 7:56 ` 陈华才
2 siblings, 0 replies; 4+ messages in thread
From: WANG Rui @ 2026-04-29 3:18 UTC (permalink / raw)
To: Ard Biesheuvel; +Cc: linux-efi, Ard Biesheuvel, Huacai Chen
Hi Ard,
On Wed, Apr 29, 2026 at 1:06 AM Ard Biesheuvel <ardb+git@google.com> wrote:
>
> From: Ard Biesheuvel <ardb@kernel.org>
>
> LoongArch is the only arch that still uses efi_relocate_kernel(), so
> before making changes to it that LoongArch needs, turn it into a private
> function. Move efi_low_alloc_above() into mem.c while at it, and drop
> the relocate.c source file altogether.
>
> Cc: WANG Rui <r@hev.cc>
> Cc: Huacai Chen <chenhuacai@loongson.cn>
> Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Tested-by: WANG Rui <wangrui@loongson.cn>
Thanks,
Rui
> ---
> Unless there are any objections, I will queue this up and rebase the
> LoongArch changes adding efi_cache_sync_image() on top of it.
>
> drivers/firmware/efi/libstub/Makefile | 2 +-
> drivers/firmware/efi/libstub/efistub.h | 7 -
> drivers/firmware/efi/libstub/loongarch-stub.c | 79 ++++++++++
> drivers/firmware/efi/libstub/mem.c | 82 ++++++++++
> drivers/firmware/efi/libstub/relocate.c | 166 --------------------
> 5 files changed, 162 insertions(+), 174 deletions(-)
>
> diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile
> index 983a438e35f3..cfedb3025c26 100644
> --- a/drivers/firmware/efi/libstub/Makefile
> +++ b/drivers/firmware/efi/libstub/Makefile
> @@ -66,7 +66,7 @@ KBUILD_AFLAGS := $(KBUILD_CFLAGS) -D__ASSEMBLY__
> lib-y := efi-stub-helper.o gop.o secureboot.o tpm.o \
> file.o mem.o random.o randomalloc.o pci.o \
> skip_spaces.o lib-cmdline.o lib-ctype.o \
> - alignedmem.o relocate.o printk.o vsprintf.o
> + alignedmem.o printk.o vsprintf.o
>
> # include the stub's libfdt dependencies from lib/ when needed
> libfdt-deps := fdt_rw.c fdt_ro.c fdt_wip.c fdt.c \
> diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h
> index 979a21818cc1..fd91fc15ec81 100644
> --- a/drivers/firmware/efi/libstub/efistub.h
> +++ b/drivers/firmware/efi/libstub/efistub.h
> @@ -1104,13 +1104,6 @@ efi_status_t efi_allocate_pages_aligned(unsigned long size, unsigned long *addr,
> efi_status_t efi_low_alloc_above(unsigned long size, unsigned long align,
> unsigned long *addr, unsigned long min);
>
> -efi_status_t efi_relocate_kernel(unsigned long *image_addr,
> - unsigned long image_size,
> - unsigned long alloc_size,
> - unsigned long preferred_addr,
> - unsigned long alignment,
> - unsigned long min_addr);
> -
> efi_status_t efi_parse_options(char const *cmdline);
>
> void efi_parse_option_graphics(char *option);
> diff --git a/drivers/firmware/efi/libstub/loongarch-stub.c b/drivers/firmware/efi/libstub/loongarch-stub.c
> index 736b6aae323d..8c538a5243d9 100644
> --- a/drivers/firmware/efi/libstub/loongarch-stub.c
> +++ b/drivers/firmware/efi/libstub/loongarch-stub.c
> @@ -14,6 +14,85 @@ extern int kernel_asize;
> extern int kernel_fsize;
> extern int kernel_entry;
>
> +/**
> + * efi_relocate_kernel() - copy memory area
> + * @image_addr: pointer to address of memory area to copy
> + * @image_size: size of memory area to copy
> + * @alloc_size: minimum size of memory to allocate, must be greater or
> + * equal to image_size
> + * @preferred_addr: preferred target address
> + * @alignment: minimum alignment of the allocated memory area. It
> + * should be a power of two.
> + * @min_addr: minimum target address
> + *
> + * Copy a memory area to a newly allocated memory area aligned according
> + * to @alignment but at least EFI_ALLOC_ALIGN. If the preferred address
> + * is not available, the allocated address will not be below @min_addr.
> + * On exit, @image_addr is updated to the target copy address that was used.
> + *
> + * This function is used to copy the Linux kernel verbatim. It does not apply
> + * any relocation changes.
> + *
> + * Return: status code
> + */
> +static
> +efi_status_t efi_relocate_kernel(unsigned long *image_addr,
> + unsigned long image_size,
> + unsigned long alloc_size,
> + unsigned long preferred_addr,
> + unsigned long alignment,
> + unsigned long min_addr)
> +{
> + unsigned long cur_image_addr;
> + unsigned long new_addr = 0;
> + efi_status_t status;
> + unsigned long nr_pages;
> + efi_physical_addr_t efi_addr = preferred_addr;
> +
> + if (!image_addr || !image_size || !alloc_size)
> + return EFI_INVALID_PARAMETER;
> + if (alloc_size < image_size)
> + return EFI_INVALID_PARAMETER;
> +
> + cur_image_addr = *image_addr;
> +
> + /*
> + * The EFI firmware loader could have placed the kernel image
> + * anywhere in memory, but the kernel has restrictions on the
> + * max physical address it can run at. Some architectures
> + * also have a preferred address, so first try to relocate
> + * to the preferred address. If that fails, allocate as low
> + * as possible while respecting the required alignment.
> + */
> + nr_pages = round_up(alloc_size, EFI_ALLOC_ALIGN) / EFI_PAGE_SIZE;
> + status = efi_bs_call(allocate_pages, EFI_ALLOCATE_ADDRESS,
> + EFI_LOADER_DATA, nr_pages, &efi_addr);
> + new_addr = efi_addr;
> + /*
> + * If preferred address allocation failed allocate as low as
> + * possible.
> + */
> + if (status != EFI_SUCCESS) {
> + status = efi_low_alloc_above(alloc_size, alignment, &new_addr,
> + min_addr);
> + }
> + if (status != EFI_SUCCESS) {
> + efi_err("Failed to allocate usable memory for kernel.\n");
> + return status;
> + }
> +
> + /*
> + * We know source/dest won't overlap since both memory ranges
> + * have been allocated by UEFI, so we can safely use memcpy.
> + */
> + memcpy((void *)new_addr, (void *)cur_image_addr, image_size);
> +
> + /* Return the new address of the relocated image. */
> + *image_addr = new_addr;
> +
> + return status;
> +}
> +
> efi_status_t handle_kernel_image(unsigned long *image_addr,
> unsigned long *image_size,
> unsigned long *reserve_addr,
> diff --git a/drivers/firmware/efi/libstub/mem.c b/drivers/firmware/efi/libstub/mem.c
> index 9c82259eea81..59f3f83de50c 100644
> --- a/drivers/firmware/efi/libstub/mem.c
> +++ b/drivers/firmware/efi/libstub/mem.c
> @@ -124,3 +124,85 @@ void efi_free(unsigned long size, unsigned long addr)
> nr_pages = round_up(size, EFI_ALLOC_ALIGN) / EFI_PAGE_SIZE;
> efi_bs_call(free_pages, addr, nr_pages);
> }
> +
> +/**
> + * efi_low_alloc_above() - allocate pages at or above given address
> + * @size: size of the memory area to allocate
> + * @align: minimum alignment of the allocated memory area. It should
> + * a power of two.
> + * @addr: on exit the address of the allocated memory
> + * @min: minimum address to used for the memory allocation
> + *
> + * Allocate at the lowest possible address that is not below @min as
> + * EFI_LOADER_DATA. The allocated pages are aligned according to @align but at
> + * least EFI_ALLOC_ALIGN. The first allocated page will not below the address
> + * given by @min.
> + *
> + * Return: status code
> + */
> +efi_status_t efi_low_alloc_above(unsigned long size, unsigned long align,
> + unsigned long *addr, unsigned long min)
> +{
> + struct efi_boot_memmap *map __free(efi_pool) = NULL;
> + efi_status_t status;
> + unsigned long nr_pages;
> + int i;
> +
> + status = efi_get_memory_map(&map, false);
> + if (status != EFI_SUCCESS)
> + return status;
> +
> + /*
> + * Enforce minimum alignment that EFI or Linux requires when
> + * requesting a specific address. We are doing page-based (or
> + * larger) allocations, and both the address and size must meet
> + * alignment constraints.
> + */
> + if (align < EFI_ALLOC_ALIGN)
> + align = EFI_ALLOC_ALIGN;
> +
> + size = round_up(size, EFI_ALLOC_ALIGN);
> + nr_pages = size / EFI_PAGE_SIZE;
> + for (i = 0; i < map->map_size / map->desc_size; i++) {
> + efi_memory_desc_t *desc;
> + unsigned long m = (unsigned long)map->map;
> + u64 start, end;
> +
> + desc = efi_memdesc_ptr(m, map->desc_size, i);
> +
> + if (desc->type != EFI_CONVENTIONAL_MEMORY)
> + continue;
> +
> + if (desc->attribute & EFI_MEMORY_HOT_PLUGGABLE)
> + continue;
> +
> + if (efi_soft_reserve_enabled() &&
> + (desc->attribute & EFI_MEMORY_SP))
> + continue;
> +
> + if (desc->num_pages < nr_pages)
> + continue;
> +
> + start = desc->phys_addr;
> + end = start + desc->num_pages * EFI_PAGE_SIZE;
> +
> + if (start < min)
> + start = min;
> +
> + start = round_up(start, align);
> + if ((start + size) > end)
> + continue;
> +
> + status = efi_bs_call(allocate_pages, EFI_ALLOCATE_ADDRESS,
> + EFI_LOADER_DATA, nr_pages, &start);
> + if (status == EFI_SUCCESS) {
> + *addr = start;
> + break;
> + }
> + }
> +
> + if (i == map->map_size / map->desc_size)
> + return EFI_NOT_FOUND;
> +
> + return EFI_SUCCESS;
> +}
> diff --git a/drivers/firmware/efi/libstub/relocate.c b/drivers/firmware/efi/libstub/relocate.c
> deleted file mode 100644
> index d4264bfb6dc1..000000000000
> --- a/drivers/firmware/efi/libstub/relocate.c
> +++ /dev/null
> @@ -1,166 +0,0 @@
> -// SPDX-License-Identifier: GPL-2.0
> -
> -#include <linux/efi.h>
> -#include <asm/efi.h>
> -
> -#include "efistub.h"
> -
> -/**
> - * efi_low_alloc_above() - allocate pages at or above given address
> - * @size: size of the memory area to allocate
> - * @align: minimum alignment of the allocated memory area. It should
> - * a power of two.
> - * @addr: on exit the address of the allocated memory
> - * @min: minimum address to used for the memory allocation
> - *
> - * Allocate at the lowest possible address that is not below @min as
> - * EFI_LOADER_DATA. The allocated pages are aligned according to @align but at
> - * least EFI_ALLOC_ALIGN. The first allocated page will not below the address
> - * given by @min.
> - *
> - * Return: status code
> - */
> -efi_status_t efi_low_alloc_above(unsigned long size, unsigned long align,
> - unsigned long *addr, unsigned long min)
> -{
> - struct efi_boot_memmap *map __free(efi_pool) = NULL;
> - efi_status_t status;
> - unsigned long nr_pages;
> - int i;
> -
> - status = efi_get_memory_map(&map, false);
> - if (status != EFI_SUCCESS)
> - return status;
> -
> - /*
> - * Enforce minimum alignment that EFI or Linux requires when
> - * requesting a specific address. We are doing page-based (or
> - * larger) allocations, and both the address and size must meet
> - * alignment constraints.
> - */
> - if (align < EFI_ALLOC_ALIGN)
> - align = EFI_ALLOC_ALIGN;
> -
> - size = round_up(size, EFI_ALLOC_ALIGN);
> - nr_pages = size / EFI_PAGE_SIZE;
> - for (i = 0; i < map->map_size / map->desc_size; i++) {
> - efi_memory_desc_t *desc;
> - unsigned long m = (unsigned long)map->map;
> - u64 start, end;
> -
> - desc = efi_memdesc_ptr(m, map->desc_size, i);
> -
> - if (desc->type != EFI_CONVENTIONAL_MEMORY)
> - continue;
> -
> - if (desc->attribute & EFI_MEMORY_HOT_PLUGGABLE)
> - continue;
> -
> - if (efi_soft_reserve_enabled() &&
> - (desc->attribute & EFI_MEMORY_SP))
> - continue;
> -
> - if (desc->num_pages < nr_pages)
> - continue;
> -
> - start = desc->phys_addr;
> - end = start + desc->num_pages * EFI_PAGE_SIZE;
> -
> - if (start < min)
> - start = min;
> -
> - start = round_up(start, align);
> - if ((start + size) > end)
> - continue;
> -
> - status = efi_bs_call(allocate_pages, EFI_ALLOCATE_ADDRESS,
> - EFI_LOADER_DATA, nr_pages, &start);
> - if (status == EFI_SUCCESS) {
> - *addr = start;
> - break;
> - }
> - }
> -
> - if (i == map->map_size / map->desc_size)
> - return EFI_NOT_FOUND;
> -
> - return EFI_SUCCESS;
> -}
> -
> -/**
> - * efi_relocate_kernel() - copy memory area
> - * @image_addr: pointer to address of memory area to copy
> - * @image_size: size of memory area to copy
> - * @alloc_size: minimum size of memory to allocate, must be greater or
> - * equal to image_size
> - * @preferred_addr: preferred target address
> - * @alignment: minimum alignment of the allocated memory area. It
> - * should be a power of two.
> - * @min_addr: minimum target address
> - *
> - * Copy a memory area to a newly allocated memory area aligned according
> - * to @alignment but at least EFI_ALLOC_ALIGN. If the preferred address
> - * is not available, the allocated address will not be below @min_addr.
> - * On exit, @image_addr is updated to the target copy address that was used.
> - *
> - * This function is used to copy the Linux kernel verbatim. It does not apply
> - * any relocation changes.
> - *
> - * Return: status code
> - */
> -efi_status_t efi_relocate_kernel(unsigned long *image_addr,
> - unsigned long image_size,
> - unsigned long alloc_size,
> - unsigned long preferred_addr,
> - unsigned long alignment,
> - unsigned long min_addr)
> -{
> - unsigned long cur_image_addr;
> - unsigned long new_addr = 0;
> - efi_status_t status;
> - unsigned long nr_pages;
> - efi_physical_addr_t efi_addr = preferred_addr;
> -
> - if (!image_addr || !image_size || !alloc_size)
> - return EFI_INVALID_PARAMETER;
> - if (alloc_size < image_size)
> - return EFI_INVALID_PARAMETER;
> -
> - cur_image_addr = *image_addr;
> -
> - /*
> - * The EFI firmware loader could have placed the kernel image
> - * anywhere in memory, but the kernel has restrictions on the
> - * max physical address it can run at. Some architectures
> - * also have a preferred address, so first try to relocate
> - * to the preferred address. If that fails, allocate as low
> - * as possible while respecting the required alignment.
> - */
> - nr_pages = round_up(alloc_size, EFI_ALLOC_ALIGN) / EFI_PAGE_SIZE;
> - status = efi_bs_call(allocate_pages, EFI_ALLOCATE_ADDRESS,
> - EFI_LOADER_DATA, nr_pages, &efi_addr);
> - new_addr = efi_addr;
> - /*
> - * If preferred address allocation failed allocate as low as
> - * possible.
> - */
> - if (status != EFI_SUCCESS) {
> - status = efi_low_alloc_above(alloc_size, alignment, &new_addr,
> - min_addr);
> - }
> - if (status != EFI_SUCCESS) {
> - efi_err("Failed to allocate usable memory for kernel.\n");
> - return status;
> - }
> -
> - /*
> - * We know source/dest won't overlap since both memory ranges
> - * have been allocated by UEFI, so we can safely use memcpy.
> - */
> - memcpy((void *)new_addr, (void *)cur_image_addr, image_size);
> -
> - /* Return the new address of the relocated image. */
> - *image_addr = new_addr;
> -
> - return status;
> -}
> --
> 2.54.0.545.g6539524ca2-goog
>
^ permalink raw reply [flat|nested] 4+ messages in thread* Re: [PATCH] efi/libstub: Move efi_relocate_kernel() into its only remaining user
2026-04-28 17:06 [PATCH] efi/libstub: Move efi_relocate_kernel() into its only remaining user Ard Biesheuvel
2026-04-29 3:18 ` WANG Rui
@ 2026-04-29 6:37 ` Thomas Huth
2026-04-29 7:56 ` 陈华才
2 siblings, 0 replies; 4+ messages in thread
From: Thomas Huth @ 2026-04-29 6:37 UTC (permalink / raw)
To: Ard Biesheuvel, linux-efi; +Cc: Ard Biesheuvel, WANG Rui, Huacai Chen
On 28/04/2026 19.06, Ard Biesheuvel wrote:
> From: Ard Biesheuvel <ardb@kernel.org>
>
> LoongArch is the only arch that still uses efi_relocate_kernel(), so
> before making changes to it that LoongArch needs, turn it into a private
> function. Move efi_low_alloc_above() into mem.c while at it, and drop
> the relocate.c source file altogether.
>
> Cc: WANG Rui <r@hev.cc>
> Cc: Huacai Chen <chenhuacai@loongson.cn>
> Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
> ---
> Unless there are any objections, I will queue this up and rebase the
> LoongArch changes adding efi_cache_sync_image() on top of it.
>
> drivers/firmware/efi/libstub/Makefile | 2 +-
> drivers/firmware/efi/libstub/efistub.h | 7 -
> drivers/firmware/efi/libstub/loongarch-stub.c | 79 ++++++++++
> drivers/firmware/efi/libstub/mem.c | 82 ++++++++++
> drivers/firmware/efi/libstub/relocate.c | 166 --------------------
> 5 files changed, 162 insertions(+), 174 deletions(-)
Reviewed-by: Thomas Huth <thuth@redhat.com>
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] efi/libstub: Move efi_relocate_kernel() into its only remaining user
2026-04-28 17:06 [PATCH] efi/libstub: Move efi_relocate_kernel() into its only remaining user Ard Biesheuvel
2026-04-29 3:18 ` WANG Rui
2026-04-29 6:37 ` Thomas Huth
@ 2026-04-29 7:56 ` 陈华才
2 siblings, 0 replies; 4+ messages in thread
From: 陈华才 @ 2026-04-29 7:56 UTC (permalink / raw)
To: Ard Biesheuvel; +Cc: linux-efi, Ard Biesheuvel, WANG Rui
Hi, Ard,
> -----原始邮件-----
> 发件人: "Ard Biesheuvel" <ardb+git@google.com>
> 发送时间:2026-04-29 01:06:09 (星期三)
> 收件人: linux-efi@vger.kernel.org
> 抄送: "Ard Biesheuvel" <ardb@kernel.org>, "WANG Rui" <r@hev.cc>, "Huacai Chen" <chenhuacai@loongson.cn>
> 主题: [PATCH] efi/libstub: Move efi_relocate_kernel() into its only remaining user
>
> From: Ard Biesheuvel <ardb@kernel.org>
>
> LoongArch is the only arch that still uses efi_relocate_kernel(), so
> before making changes to it that LoongArch needs, turn it into a private
> function. Move efi_low_alloc_above() into mem.c while at it, and drop
> the relocate.c source file altogether.
>
> Cc: WANG Rui <r@hev.cc>
> Cc: Huacai Chen <chenhuacai@loongson.cn>
> Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
> ---
> Unless there are any objections, I will queue this up and rebase the
> LoongArch changes adding efi_cache_sync_image() on top of it.
>
> drivers/firmware/efi/libstub/Makefile | 2 +-
> drivers/firmware/efi/libstub/efistub.h | 7 -
> drivers/firmware/efi/libstub/loongarch-stub.c | 79 ++++++++++
> drivers/firmware/efi/libstub/mem.c | 82 ++++++++++
> drivers/firmware/efi/libstub/relocate.c | 166 --------------------
> 5 files changed, 162 insertions(+), 174 deletions(-)
>
> diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile
> index 983a438e35f3..cfedb3025c26 100644
> --- a/drivers/firmware/efi/libstub/Makefile
> +++ b/drivers/firmware/efi/libstub/Makefile
> @@ -66,7 +66,7 @@ KBUILD_AFLAGS := $(KBUILD_CFLAGS) -D__ASSEMBLY__
> lib-y := efi-stub-helper.o gop.o secureboot.o tpm.o \
> file.o mem.o random.o randomalloc.o pci.o \
> skip_spaces.o lib-cmdline.o lib-ctype.o \
> - alignedmem.o relocate.o printk.o vsprintf.o
> + alignedmem.o printk.o vsprintf.o
>
> # include the stub's libfdt dependencies from lib/ when needed
> libfdt-deps := fdt_rw.c fdt_ro.c fdt_wip.c fdt.c \
> diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h
> index 979a21818cc1..fd91fc15ec81 100644
> --- a/drivers/firmware/efi/libstub/efistub.h
> +++ b/drivers/firmware/efi/libstub/efistub.h
> @@ -1104,13 +1104,6 @@ efi_status_t efi_allocate_pages_aligned(unsigned long size, unsigned long *addr,
> efi_status_t efi_low_alloc_above(unsigned long size, unsigned long align,
> unsigned long *addr, unsigned long min);
>
> -efi_status_t efi_relocate_kernel(unsigned long *image_addr,
> - unsigned long image_size,
> - unsigned long alloc_size,
> - unsigned long preferred_addr,
> - unsigned long alignment,
> - unsigned long min_addr);
> -
> efi_status_t efi_parse_options(char const *cmdline);
>
> void efi_parse_option_graphics(char *option);
> diff --git a/drivers/firmware/efi/libstub/loongarch-stub.c b/drivers/firmware/efi/libstub/loongarch-stub.c
> index 736b6aae323d..8c538a5243d9 100644
> --- a/drivers/firmware/efi/libstub/loongarch-stub.c
> +++ b/drivers/firmware/efi/libstub/loongarch-stub.c
> @@ -14,6 +14,85 @@ extern int kernel_asize;
> extern int kernel_fsize;
> extern int kernel_entry;
>
> +/**
> + * efi_relocate_kernel() - copy memory area
> + * @image_addr: pointer to address of memory area to copy
> + * @image_size: size of memory area to copy
> + * @alloc_size: minimum size of memory to allocate, must be greater or
> + * equal to image_size
> + * @preferred_addr: preferred target address
> + * @alignment: minimum alignment of the allocated memory area. It
> + * should be a power of two.
> + * @min_addr: minimum target address
> + *
> + * Copy a memory area to a newly allocated memory area aligned according
> + * to @alignment but at least EFI_ALLOC_ALIGN. If the preferred address
> + * is not available, the allocated address will not be below @min_addr.
> + * On exit, @image_addr is updated to the target copy address that was used.
> + *
> + * This function is used to copy the Linux kernel verbatim. It does not apply
> + * any relocation changes.
> + *
> + * Return: status code
> + */
> +static
> +efi_status_t efi_relocate_kernel(unsigned long *image_addr,
> + unsigned long image_size,
> + unsigned long alloc_size,
> + unsigned long preferred_addr,
> + unsigned long alignment,
> + unsigned long min_addr)
> +{
> + unsigned long cur_image_addr;
> + unsigned long new_addr = 0;
> + efi_status_t status;
> + unsigned long nr_pages;
> + efi_physical_addr_t efi_addr = preferred_addr;
> +
> + if (!image_addr || !image_size || !alloc_size)
> + return EFI_INVALID_PARAMETER;
> + if (alloc_size < image_size)
> + return EFI_INVALID_PARAMETER;
> +
> + cur_image_addr = *image_addr;
> +
> + /*
> + * The EFI firmware loader could have placed the kernel image
> + * anywhere in memory, but the kernel has restrictions on the
> + * max physical address it can run at. Some architectures
> + * also have a preferred address, so first try to relocate
> + * to the preferred address. If that fails, allocate as low
> + * as possible while respecting the required alignment.
> + */
> + nr_pages = round_up(alloc_size, EFI_ALLOC_ALIGN) / EFI_PAGE_SIZE;
> + status = efi_bs_call(allocate_pages, EFI_ALLOCATE_ADDRESS,
> + EFI_LOADER_DATA, nr_pages, &efi_addr);
> + new_addr = efi_addr;
> + /*
> + * If preferred address allocation failed allocate as low as
> + * possible.
> + */
> + if (status != EFI_SUCCESS) {
> + status = efi_low_alloc_above(alloc_size, alignment, &new_addr,
> + min_addr);
> + }
> + if (status != EFI_SUCCESS) {
> + efi_err("Failed to allocate usable memory for kernel.\n");
> + return status;
> + }
> +
> + /*
> + * We know source/dest won't overlap since both memory ranges
> + * have been allocated by UEFI, so we can safely use memcpy.
> + */
> + memcpy((void *)new_addr, (void *)cur_image_addr, image_size);
> +
> + /* Return the new address of the relocated image. */
> + *image_addr = new_addr;
> +
> + return status;
> +}
> +
> efi_status_t handle_kernel_image(unsigned long *image_addr,
> unsigned long *image_size,
> unsigned long *reserve_addr,
> diff --git a/drivers/firmware/efi/libstub/mem.c b/drivers/firmware/efi/libstub/mem.c
> index 9c82259eea81..59f3f83de50c 100644
> --- a/drivers/firmware/efi/libstub/mem.c
> +++ b/drivers/firmware/efi/libstub/mem.c
> @@ -124,3 +124,85 @@ void efi_free(unsigned long size, unsigned long addr)
> nr_pages = round_up(size, EFI_ALLOC_ALIGN) / EFI_PAGE_SIZE;
> efi_bs_call(free_pages, addr, nr_pages);
> }
> +
> +/**
> + * efi_low_alloc_above() - allocate pages at or above given address
> + * @size: size of the memory area to allocate
> + * @align: minimum alignment of the allocated memory area. It should
> + * a power of two.
> + * @addr: on exit the address of the allocated memory
> + * @min: minimum address to used for the memory allocation
> + *
> + * Allocate at the lowest possible address that is not below @min as
> + * EFI_LOADER_DATA. The allocated pages are aligned according to @align but at
> + * least EFI_ALLOC_ALIGN. The first allocated page will not below the address
> + * given by @min.
> + *
> + * Return: status code
> + */
> +efi_status_t efi_low_alloc_above(unsigned long size, unsigned long align,
> + unsigned long *addr, unsigned long min)
Just a bike-sheeding, move this function to above efi_free() is a little better
because allocation functions will be together.
Acked-by: Huacai Chen <chenhuacai>
> +{
> + struct efi_boot_memmap *map __free(efi_pool) = NULL;
> + efi_status_t status;
> + unsigned long nr_pages;
> + int i;
> +
> + status = efi_get_memory_map(&map, false);
> + if (status != EFI_SUCCESS)
> + return status;
> +
> + /*
> + * Enforce minimum alignment that EFI or Linux requires when
> + * requesting a specific address. We are doing page-based (or
> + * larger) allocations, and both the address and size must meet
> + * alignment constraints.
> + */
> + if (align < EFI_ALLOC_ALIGN)
> + align = EFI_ALLOC_ALIGN;
> +
> + size = round_up(size, EFI_ALLOC_ALIGN);
> + nr_pages = size / EFI_PAGE_SIZE;
> + for (i = 0; i < map->map_size / map->desc_size; i++) {
> + efi_memory_desc_t *desc;
> + unsigned long m = (unsigned long)map->map;
> + u64 start, end;
> +
> + desc = efi_memdesc_ptr(m, map->desc_size, i);
> +
> + if (desc->type != EFI_CONVENTIONAL_MEMORY)
> + continue;
> +
> + if (desc->attribute & EFI_MEMORY_HOT_PLUGGABLE)
> + continue;
> +
> + if (efi_soft_reserve_enabled() &&
> + (desc->attribute & EFI_MEMORY_SP))
> + continue;
> +
> + if (desc->num_pages < nr_pages)
> + continue;
> +
> + start = desc->phys_addr;
> + end = start + desc->num_pages * EFI_PAGE_SIZE;
> +
> + if (start < min)
> + start = min;
> +
> + start = round_up(start, align);
> + if ((start + size) > end)
> + continue;
> +
> + status = efi_bs_call(allocate_pages, EFI_ALLOCATE_ADDRESS,
> + EFI_LOADER_DATA, nr_pages, &start);
> + if (status == EFI_SUCCESS) {
> + *addr = start;
> + break;
> + }
> + }
> +
> + if (i == map->map_size / map->desc_size)
> + return EFI_NOT_FOUND;
> +
> + return EFI_SUCCESS;
> +}
> diff --git a/drivers/firmware/efi/libstub/relocate.c b/drivers/firmware/efi/libstub/relocate.c
> deleted file mode 100644
> index d4264bfb6dc1..000000000000
> --- a/drivers/firmware/efi/libstub/relocate.c
> +++ /dev/null
> @@ -1,166 +0,0 @@
> -// SPDX-License-Identifier: GPL-2.0
> -
> -#include <linux/efi.h>
> -#include <asm/efi.h>
> -
> -#include "efistub.h"
> -
> -/**
> - * efi_low_alloc_above() - allocate pages at or above given address
> - * @size: size of the memory area to allocate
> - * @align: minimum alignment of the allocated memory area. It should
> - * a power of two.
> - * @addr: on exit the address of the allocated memory
> - * @min: minimum address to used for the memory allocation
> - *
> - * Allocate at the lowest possible address that is not below @min as
> - * EFI_LOADER_DATA. The allocated pages are aligned according to @align but at
> - * least EFI_ALLOC_ALIGN. The first allocated page will not below the address
> - * given by @min.
> - *
> - * Return: status code
> - */
> -efi_status_t efi_low_alloc_above(unsigned long size, unsigned long align,
> - unsigned long *addr, unsigned long min)
> -{
> - struct efi_boot_memmap *map __free(efi_pool) = NULL;
> - efi_status_t status;
> - unsigned long nr_pages;
> - int i;
> -
> - status = efi_get_memory_map(&map, false);
> - if (status != EFI_SUCCESS)
> - return status;
> -
> - /*
> - * Enforce minimum alignment that EFI or Linux requires when
> - * requesting a specific address. We are doing page-based (or
> - * larger) allocations, and both the address and size must meet
> - * alignment constraints.
> - */
> - if (align < EFI_ALLOC_ALIGN)
> - align = EFI_ALLOC_ALIGN;
> -
> - size = round_up(size, EFI_ALLOC_ALIGN);
> - nr_pages = size / EFI_PAGE_SIZE;
> - for (i = 0; i < map->map_size / map->desc_size; i++) {
> - efi_memory_desc_t *desc;
> - unsigned long m = (unsigned long)map->map;
> - u64 start, end;
> -
> - desc = efi_memdesc_ptr(m, map->desc_size, i);
> -
> - if (desc->type != EFI_CONVENTIONAL_MEMORY)
> - continue;
> -
> - if (desc->attribute & EFI_MEMORY_HOT_PLUGGABLE)
> - continue;
> -
> - if (efi_soft_reserve_enabled() &&
> - (desc->attribute & EFI_MEMORY_SP))
> - continue;
> -
> - if (desc->num_pages < nr_pages)
> - continue;
> -
> - start = desc->phys_addr;
> - end = start + desc->num_pages * EFI_PAGE_SIZE;
> -
> - if (start < min)
> - start = min;
> -
> - start = round_up(start, align);
> - if ((start + size) > end)
> - continue;
> -
> - status = efi_bs_call(allocate_pages, EFI_ALLOCATE_ADDRESS,
> - EFI_LOADER_DATA, nr_pages, &start);
> - if (status == EFI_SUCCESS) {
> - *addr = start;
> - break;
> - }
> - }
> -
> - if (i == map->map_size / map->desc_size)
> - return EFI_NOT_FOUND;
> -
> - return EFI_SUCCESS;
> -}
> -
> -/**
> - * efi_relocate_kernel() - copy memory area
> - * @image_addr: pointer to address of memory area to copy
> - * @image_size: size of memory area to copy
> - * @alloc_size: minimum size of memory to allocate, must be greater or
> - * equal to image_size
> - * @preferred_addr: preferred target address
> - * @alignment: minimum alignment of the allocated memory area. It
> - * should be a power of two.
> - * @min_addr: minimum target address
> - *
> - * Copy a memory area to a newly allocated memory area aligned according
> - * to @alignment but at least EFI_ALLOC_ALIGN. If the preferred address
> - * is not available, the allocated address will not be below @min_addr.
> - * On exit, @image_addr is updated to the target copy address that was used.
> - *
> - * This function is used to copy the Linux kernel verbatim. It does not apply
> - * any relocation changes.
> - *
> - * Return: status code
> - */
> -efi_status_t efi_relocate_kernel(unsigned long *image_addr,
> - unsigned long image_size,
> - unsigned long alloc_size,
> - unsigned long preferred_addr,
> - unsigned long alignment,
> - unsigned long min_addr)
> -{
> - unsigned long cur_image_addr;
> - unsigned long new_addr = 0;
> - efi_status_t status;
> - unsigned long nr_pages;
> - efi_physical_addr_t efi_addr = preferred_addr;
> -
> - if (!image_addr || !image_size || !alloc_size)
> - return EFI_INVALID_PARAMETER;
> - if (alloc_size < image_size)
> - return EFI_INVALID_PARAMETER;
> -
> - cur_image_addr = *image_addr;
> -
> - /*
> - * The EFI firmware loader could have placed the kernel image
> - * anywhere in memory, but the kernel has restrictions on the
> - * max physical address it can run at. Some architectures
> - * also have a preferred address, so first try to relocate
> - * to the preferred address. If that fails, allocate as low
> - * as possible while respecting the required alignment.
> - */
> - nr_pages = round_up(alloc_size, EFI_ALLOC_ALIGN) / EFI_PAGE_SIZE;
> - status = efi_bs_call(allocate_pages, EFI_ALLOCATE_ADDRESS,
> - EFI_LOADER_DATA, nr_pages, &efi_addr);
> - new_addr = efi_addr;
> - /*
> - * If preferred address allocation failed allocate as low as
> - * possible.
> - */
> - if (status != EFI_SUCCESS) {
> - status = efi_low_alloc_above(alloc_size, alignment, &new_addr,
> - min_addr);
> - }
> - if (status != EFI_SUCCESS) {
> - efi_err("Failed to allocate usable memory for kernel.\n");
> - return status;
> - }
> -
> - /*
> - * We know source/dest won't overlap since both memory ranges
> - * have been allocated by UEFI, so we can safely use memcpy.
> - */
> - memcpy((void *)new_addr, (void *)cur_image_addr, image_size);
> -
> - /* Return the new address of the relocated image. */
> - *image_addr = new_addr;
> -
> - return status;
> -}
> --
> 2.54.0.545.g6539524ca2-goog
本邮件及其附件含有龙芯中科的商业秘密信息,仅限于发送给上面地址中列出的个人或群组。禁止任何其他人以任何形式使用(包括但不限于全部或部分地泄露、复制或散发)本邮件及其附件中的信息。如果您错收本邮件,请您立即电话或邮件通知发件人并删除本邮件。
This email and its attachments contain confidential information from Loongson Technology , which is intended only for the person or entity whose address is listed above. Any use of the information contained herein in any way (including, but not limited to, total or partial disclosure, reproduction or dissemination) by persons other than the intended recipient(s) is prohibited. If you receive this email in error, please notify the sender by phone or email immediately and delete it.
^ permalink raw reply [flat|nested] 4+ messages in thread