efi/arm64: libstub: Split off kernel image relocation for builtin stub
authorArd Biesheuvel <ardb@kernel.org>
Thu, 13 Oct 2022 08:17:20 +0000 (10:17 +0200)
committerArd Biesheuvel <ardb@kernel.org>
Wed, 9 Nov 2022 11:42:03 +0000 (12:42 +0100)
The arm64 build of the EFI stub is part of the core kernel image, and
therefore accesses section markers directly when it needs to figure out
the size of the various section.

The zboot decompressor does not have access to those symbols, but
doesn't really need that either. So let's move handle_kernel_image()
into a separate file (or rather, move everything else into a separate
file) so that the zboot build does not pull in unused code that links to
symbols that it does not define.

While at it, introduce a helper routine that the generic zboot loader
will need to invoke after decompressing the image but before invoking
it, to ensure that the I-side view of memory is consistent.

Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
drivers/firmware/efi/libstub/Makefile
drivers/firmware/efi/libstub/arm64-entry.S
drivers/firmware/efi/libstub/arm64-stub.c
drivers/firmware/efi/libstub/arm64.c [new file with mode: 0644]
drivers/firmware/efi/libstub/efistub.h

index 5ec0635b498793d6ef82c1df2f1691a673b4d730..63e1eddf996b021ac02c30a6a5a3903d30265a37 100644 (file)
@@ -86,7 +86,7 @@ lib-$(CONFIG_EFI_GENERIC_STUB)        += efi-stub.o string.o intrinsics.o systable.o \
                                   screen_info.o efi-stub-entry.o
 
 lib-$(CONFIG_ARM)              += arm32-stub.o
-lib-$(CONFIG_ARM64)            += arm64-stub.o arm64-entry.o
+lib-$(CONFIG_ARM64)            += arm64.o arm64-stub.o arm64-entry.o
 lib-$(CONFIG_X86)              += x86-stub.o
 lib-$(CONFIG_RISCV)            += riscv.o riscv-stub.o
 lib-$(CONFIG_LOONGARCH)                += loongarch-stub.o
index 87082b222a8799c4e79a76e8b42039d60163cb1c..b5c17e89a4fc0c218ffbf3d349364a0915e67b83 100644 (file)
@@ -8,6 +8,16 @@
 #include <linux/linkage.h>
 #include <asm/assembler.h>
 
+       /*
+        * The entrypoint of a arm64 bare metal image is at offset #0 of the
+        * image, so this is a reasonable default for primary_entry_offset.
+        * Only when the EFI stub is integrated into the core kernel, it is not
+        * guaranteed that the PE/COFF header has been copied to memory too, so
+        * in this case, primary_entry_offset should be overridden by the
+        * linker and point to primary_entry() directly.
+        */
+       .weak   primary_entry_offset
+
 SYM_CODE_START(efi_enter_kernel)
        /*
         * efi_pe_entry() will have copied the kernel image if necessary and we
index f35c0e54e2940c7a7c22893fff6d3ca0f980a553..c14028b625b4b92fbaf34209a2625ec876ea3462 100644 (file)
 #include <asm/efi.h>
 #include <asm/memory.h>
 #include <asm/sections.h>
-#include <asm/sysreg.h>
 
 #include "efistub.h"
 
-efi_status_t check_platform_features(void)
-{
-       u64 tg;
-
-       /*
-        * If we have 48 bits of VA space for TTBR0 mappings, we can map the
-        * UEFI runtime regions 1:1 and so calling SetVirtualAddressMap() is
-        * unnecessary.
-        */
-       if (VA_BITS_MIN >= 48)
-               efi_novamap = true;
-
-       /* UEFI mandates support for 4 KB granularity, no need to check */
-       if (IS_ENABLED(CONFIG_ARM64_4K_PAGES))
-               return EFI_SUCCESS;
-
-       tg = (read_cpuid(ID_AA64MMFR0_EL1) >> ID_AA64MMFR0_EL1_TGRAN_SHIFT) & 0xf;
-       if (tg < ID_AA64MMFR0_EL1_TGRAN_SUPPORTED_MIN || tg > ID_AA64MMFR0_EL1_TGRAN_SUPPORTED_MAX) {
-               if (IS_ENABLED(CONFIG_ARM64_64K_PAGES))
-                       efi_err("This 64 KB granular kernel is not supported by your CPU\n");
-               else
-                       efi_err("This 16 KB granular kernel is not supported by your CPU\n");
-               return EFI_UNSUPPORTED;
-       }
-       return EFI_SUCCESS;
-}
-
 /*
  * Distro versions of GRUB may ignore the BSS allocation entirely (i.e., fail
  * to provide space, and fail to zero it). Check for this condition by double
diff --git a/drivers/firmware/efi/libstub/arm64.c b/drivers/firmware/efi/libstub/arm64.c
new file mode 100644 (file)
index 0000000..d2e9497
--- /dev/null
@@ -0,0 +1,61 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2013, 2014 Linaro Ltd;  <roy.franz@linaro.org>
+ *
+ * This file implements the EFI boot stub for the arm64 kernel.
+ * Adapted from ARM version by Mark Salter <msalter@redhat.com>
+ */
+
+
+#include <linux/efi.h>
+#include <asm/efi.h>
+#include <asm/memory.h>
+#include <asm/sysreg.h>
+
+#include "efistub.h"
+
+efi_status_t check_platform_features(void)
+{
+       u64 tg;
+
+       /*
+        * If we have 48 bits of VA space for TTBR0 mappings, we can map the
+        * UEFI runtime regions 1:1 and so calling SetVirtualAddressMap() is
+        * unnecessary.
+        */
+       if (VA_BITS_MIN >= 48)
+               efi_novamap = true;
+
+       /* UEFI mandates support for 4 KB granularity, no need to check */
+       if (IS_ENABLED(CONFIG_ARM64_4K_PAGES))
+               return EFI_SUCCESS;
+
+       tg = (read_cpuid(ID_AA64MMFR0_EL1) >> ID_AA64MMFR0_EL1_TGRAN_SHIFT) & 0xf;
+       if (tg < ID_AA64MMFR0_EL1_TGRAN_SUPPORTED_MIN || tg > ID_AA64MMFR0_EL1_TGRAN_SUPPORTED_MAX) {
+               if (IS_ENABLED(CONFIG_ARM64_64K_PAGES))
+                       efi_err("This 64 KB granular kernel is not supported by your CPU\n");
+               else
+                       efi_err("This 16 KB granular kernel is not supported by your CPU\n");
+               return EFI_UNSUPPORTED;
+       }
+       return EFI_SUCCESS;
+}
+
+void efi_cache_sync_image(unsigned long image_base,
+                         unsigned long alloc_size,
+                         unsigned long code_size)
+{
+       u32 ctr = read_cpuid_effective_cachetype();
+       u64 lsize = 4 << cpuid_feature_extract_unsigned_field(ctr,
+                                               CTR_EL0_DminLine_SHIFT);
+
+       do {
+               asm("dc civac, %0" :: "r"(image_base));
+               image_base += lsize;
+               alloc_size -= lsize;
+       } while (alloc_size >= lsize);
+
+       asm("ic ialluis");
+       dsb(ish);
+       isb();
+}
index fd6953ed2d0bfd0a6b81aa85fcd651fa99166748..b5e1095b0016256fcc2f29f9977f7c7b732bd5db 100644 (file)
@@ -986,4 +986,8 @@ void efi_retrieve_tpm2_eventlog(void);
 struct screen_info *alloc_screen_info(void);
 void free_screen_info(struct screen_info *si);
 
+void efi_cache_sync_image(unsigned long image_base,
+                         unsigned long alloc_size,
+                         unsigned long code_size);
+
 #endif