···43434444/* arch specific definitions used by the stub code */45454646-struct screen_info *alloc_screen_info(void);4747-void free_screen_info(struct screen_info *si);4848-4946/*5047 * A reasonable upper bound for the uncompressed kernel size is 32 MBytes,5148 * so we will reserve that amount of memory. We have no easy way to tell what
+5-26
arch/arm/kernel/efi.c
···7575 return 0;7676}77777878-static unsigned long __initdata screen_info_table = EFI_INVALID_TABLE_ADDR;7978static unsigned long __initdata cpu_state_table = EFI_INVALID_TABLE_ADDR;80798180const efi_config_table_type_t efi_arch_tables[] __initconst = {8282- {LINUX_EFI_ARM_SCREEN_INFO_TABLE_GUID, &screen_info_table},8381 {LINUX_EFI_ARM_CPU_STATE_TABLE_GUID, &cpu_state_table},8482 {}8583};8686-8787-static void __init load_screen_info_table(void)8888-{8989- struct screen_info *si;9090-9191- if (screen_info_table != EFI_INVALID_TABLE_ADDR) {9292- si = early_memremap_ro(screen_info_table, sizeof(*si));9393- if (!si) {9494- pr_err("Could not map screen_info config table\n");9595- return;9696- }9797- screen_info = *si;9898- early_memunmap(si, sizeof(*si));9999-100100- /* dummycon on ARM needs non-zero values for columns/lines */101101- screen_info.orig_video_cols = 80;102102- screen_info.orig_video_lines = 25;103103-104104- if (memblock_is_map_memory(screen_info.lfb_base))105105- memblock_mark_nomap(screen_info.lfb_base,106106- screen_info.lfb_size);107107- }108108-}1098411085static void __init load_cpu_state_table(void)11186{···120145{121146 efi_init();122147123123- load_screen_info_table();148148+ if (screen_info.orig_video_isVGA == VIDEO_TYPE_EFI) {149149+ /* dummycon on ARM needs non-zero values for columns/lines */150150+ screen_info.orig_video_cols = 80;151151+ screen_info.orig_video_lines = 25;152152+ }124153125154 /* ARM does not permit early mappings to persist across paging_init() */126155 efi_memmap_unmap();
+12-3
arch/arm64/include/asm/efi.h
···8484 return (image_addr & ~(SZ_1G - 1UL)) + (1UL << (VA_BITS_MIN - 1));8585}86868787-#define alloc_screen_info(x...) &screen_info8888-8989-static inline void free_screen_info(struct screen_info *si)8787+static inline unsigned long efi_get_kimg_min_align(void)9088{8989+ extern bool efi_nokaslr;9090+9191+ /*9292+ * Although relocatable kernels can fix up the misalignment with9393+ * respect to MIN_KIMG_ALIGN, the resulting virtual text addresses are9494+ * subtly out of sync with those recorded in the vmlinux when kaslr is9595+ * disabled but the image required relocation anyway. Therefore retain9696+ * 2M alignment if KASLR was explicitly disabled, even if it was not9797+ * going to be activated to begin with.9898+ */9999+ return efi_nokaslr ? MIN_KIMG_ALIGN : EFI_KIMG_ALIGN;91100}9210193102#define EFI_ALLOC_ALIGN SZ_64K
···11-/* SPDX-License-Identifier: GPL-2.0-only */22-/*33- * EFI entry point.44- *55- * Copyright (C) 2013, 2014 Red Hat, Inc.66- * Author: Mark Salter <msalter@redhat.com>77- */88-#include <linux/linkage.h>99-#include <linux/init.h>1010-1111-#include <asm/assembler.h>1212-1313- __INIT1414-1515-SYM_CODE_START(efi_enter_kernel)1616- /*1717- * efi_pe_entry() will have copied the kernel image if necessary and we1818- * end up here with device tree address in x1 and the kernel entry1919- * point stored in x0. Save those values in registers which are2020- * callee preserved.2121- */2222- ldr w2, =primary_entry_offset2323- add x19, x0, x2 // relocated Image entrypoint2424- mov x20, x1 // DTB address2525-2626- /*2727- * Clean the copied Image to the PoC, and ensure it is not shadowed by2828- * stale icache entries from before relocation.2929- */3030- ldr w1, =kernel_size3131- add x1, x0, x13232- bl dcache_clean_poc3333- ic ialluis3434-3535- /*3636- * Clean the remainder of this routine to the PoC3737- * so that we can safely disable the MMU and caches.3838- */3939- adr x0, 0f4040- adr x1, 3f4141- bl dcache_clean_poc4242-0:4343- /* Turn off Dcache and MMU */4444- mrs x0, CurrentEL4545- cmp x0, #CurrentEL_EL24646- b.ne 1f4747- mrs x0, sctlr_el24848- bic x0, x0, #1 << 0 // clear SCTLR.M4949- bic x0, x0, #1 << 2 // clear SCTLR.C5050- pre_disable_mmu_workaround5151- msr sctlr_el2, x05252- isb5353- b 2f5454-1:5555- mrs x0, sctlr_el15656- bic x0, x0, #1 << 0 // clear SCTLR.M5757- bic x0, x0, #1 << 2 // clear SCTLR.C5858- pre_disable_mmu_workaround5959- msr sctlr_el1, x06060- isb6161-2:6262- /* Jump to kernel entry point */6363- mov x0, x206464- mov x1, xzr6565- mov x2, xzr6666- mov x3, xzr6767- br x196868-3:6969-SYM_CODE_END(efi_enter_kernel)
-8
arch/arm64/kernel/image-vars.h
···1010#error This file should only be included in vmlinux.lds.S1111#endif12121313-PROVIDE(__efistub_kernel_size = _edata - _text);1413PROVIDE(__efistub_primary_entry_offset = primary_entry - _text);15141615/*···2122 * linked at. The routines below are all implemented in assembler in a2223 * position independent manner2324 */2424-PROVIDE(__efistub_memcmp = __pi_memcmp);2525-PROVIDE(__efistub_memchr = __pi_memchr);2626-PROVIDE(__efistub_strlen = __pi_strlen);2727-PROVIDE(__efistub_strnlen = __pi_strnlen);2828-PROVIDE(__efistub_strcmp = __pi_strcmp);2929-PROVIDE(__efistub_strncmp = __pi_strncmp);3030-PROVIDE(__efistub_strrchr = __pi_strrchr);3125PROVIDE(__efistub_dcache_clean_poc = __pi_dcache_clean_poc);32263327PROVIDE(__efistub__text = _text);
+9-9
arch/loongarch/include/asm/efi.h
···1919#define EFI_ALLOC_ALIGN SZ_64K2020#define EFI_RT_VIRTUAL_OFFSET CSR_DMW0_BASE21212222-static inline struct screen_info *alloc_screen_info(void)2323-{2424- return &screen_info;2525-}2626-2727-static inline void free_screen_info(struct screen_info *si)2828-{2929-}3030-3122static inline unsigned long efi_get_max_initrd_addr(unsigned long image_addr)3223{3324 return ULONG_MAX;3425}2626+2727+static inline unsigned long efi_get_kimg_min_align(void)2828+{2929+ return SZ_2M;3030+}3131+3232+#define EFI_KIMG_PREFERRED_ADDRESS PHYSADDR(VMLINUX_LOAD_ADDRESS)3333+3434+unsigned long kernel_entry_address(void);35353636#endif /* _ASM_LOONGARCH_EFI_H */
+22-2
arch/loongarch/kernel/efi.c
···5252 set_bit(EFI_RUNTIME_SERVICES, &efi.flags);5353}54545555+unsigned long __initdata screen_info_table = EFI_INVALID_TABLE_ADDR;5656+5757+static void __init init_screen_info(void)5858+{5959+ struct screen_info *si;6060+6161+ if (screen_info_table == EFI_INVALID_TABLE_ADDR)6262+ return;6363+6464+ si = early_memremap(screen_info_table, sizeof(*si));6565+ if (!si) {6666+ pr_err("Could not map screen_info config table\n");6767+ return;6868+ }6969+ screen_info = *si;7070+ memset(si, 0, sizeof(*si));7171+ early_memunmap(si, sizeof(*si));7272+7373+ memblock_reserve(screen_info.lfb_base, screen_info.lfb_size);7474+}7575+5576void __init efi_init(void)5677{5778 int size;···1018010281 set_bit(EFI_CONFIG_TABLES, &efi.flags);10382104104- if (screen_info.orig_video_isVGA == VIDEO_TYPE_EFI)105105- memblock_reserve(screen_info.lfb_base, screen_info.lfb_size);8383+ init_screen_info();1068410785 if (boot_memmap == EFI_INVALID_TABLE_ADDR)10886 return;
···55# things like ftrace and stack-protector are likely to cause trouble if left66# enabled, even if doing so doesn't break the build.77#88+99+# non-x86 reuses KBUILD_CFLAGS, x86 does not1010+cflags-y := $(KBUILD_CFLAGS)1111+812cflags-$(CONFIG_X86_32) := -march=i386913cflags-$(CONFIG_X86_64) := -mcmodel=small1014cflags-$(CONFIG_X86) += -m$(BITS) -D__KERNEL__ \···22182319# arm64 uses the full KBUILD_CFLAGS so it's necessary to explicitly2420# disable the stackleak plugin2525-cflags-$(CONFIG_ARM64) := $(subst $(CC_FLAGS_FTRACE),,$(KBUILD_CFLAGS)) \2626- -fpie $(DISABLE_STACKLEAK_PLUGIN) \2121+cflags-$(CONFIG_ARM64) += -fpie $(DISABLE_STACKLEAK_PLUGIN) \2722 $(call cc-option,-mbranch-protection=none)2828-cflags-$(CONFIG_ARM) := $(subst $(CC_FLAGS_FTRACE),,$(KBUILD_CFLAGS)) \2929- -fno-builtin -fpic \2323+cflags-$(CONFIG_ARM) += -DEFI_HAVE_STRLEN -DEFI_HAVE_STRNLEN \2424+ -DEFI_HAVE_MEMCHR -DEFI_HAVE_STRRCHR \2525+ -DEFI_HAVE_STRCMP -fno-builtin -fpic \3026 $(call cc-option,-mno-single-pic-base)3131-cflags-$(CONFIG_RISCV) := $(subst $(CC_FLAGS_FTRACE),,$(KBUILD_CFLAGS)) \3232- -fpic3333-cflags-$(CONFIG_LOONGARCH) := $(subst $(CC_FLAGS_FTRACE),,$(KBUILD_CFLAGS)) \3434- -fpie2727+cflags-$(CONFIG_RISCV) += -fpic2828+cflags-$(CONFIG_LOONGARCH) += -fpie35293630cflags-$(CONFIG_EFI_PARAMS_FROM_FDT) += -I$(srctree)/scripts/dtc/libfdt37313838-KBUILD_CFLAGS := $(cflags-y) -Os -DDISABLE_BRANCH_PROFILING \3232+KBUILD_CFLAGS := $(subst $(CC_FLAGS_FTRACE),,$(cflags-y)) \3333+ -Os -DDISABLE_BRANCH_PROFILING \3934 -include $(srctree)/include/linux/hidden.h \4035 -D__NO_FORTIFY \4136 -ffreestanding \···7067lib-y := efi-stub-helper.o gop.o secureboot.o tpm.o \7168 file.o mem.o random.o randomalloc.o pci.o \7269 skip_spaces.o lib-cmdline.o lib-ctype.o \7373- alignedmem.o relocate.o vsprintf.o7070+ alignedmem.o relocate.o printk.o vsprintf.o74717572# include the stub's libfdt dependencies from lib/ when needed7673libfdt-deps := fdt_rw.c fdt_ro.c fdt_wip.c fdt.c \···8279$(obj)/lib-%.o: $(srctree)/lib/%.c FORCE8380 $(call if_changed_rule,cc_o_c)84818585-lib-$(CONFIG_EFI_GENERIC_STUB) += efi-stub.o string.o intrinsics.o systable.o8282+lib-$(CONFIG_EFI_GENERIC_STUB) += efi-stub.o string.o intrinsics.o systable.o \8383+ screen_info.o efi-stub-entry.o86848785lib-$(CONFIG_ARM) += arm32-stub.o8888-lib-$(CONFIG_ARM64) += arm64-stub.o smbios.o8686+lib-$(CONFIG_ARM64) += arm64.o arm64-stub.o arm64-entry.o smbios.o8987lib-$(CONFIG_X86) += x86-stub.o9090-lib-$(CONFIG_RISCV) += riscv-stub.o9191-lib-$(CONFIG_LOONGARCH) += loongarch-stub.o8888+lib-$(CONFIG_RISCV) += riscv.o riscv-stub.o8989+lib-$(CONFIG_LOONGARCH) += loongarch.o loongarch-stub.o92909391CFLAGS_arm32-stub.o := -DTEXT_OFFSET=$(TEXT_OFFSET)9492···140136#141137STUBCOPY_FLAGS-$(CONFIG_ARM64) += --prefix-alloc-sections=.init \142138 --prefix-symbols=__efistub_143143-STUBCOPY_RELOC-$(CONFIG_ARM64) := R_AARCH64_ABS139139+STUBCOPY_RELOC-$(CONFIG_ARM64) := R_AARCH64_ABS64144140145141# For RISC-V, we don't need anything special other than arm64. Keep all the146142# symbols in .init section and make sure that no absolute symbols references
+10-12
drivers/firmware/efi/libstub/Makefile.zboot
···1010comp-type-$(CONFIG_KERNEL_XZ) := xzkern1111comp-type-$(CONFIG_KERNEL_ZSTD) := zstd2212121313-# in GZIP, the appended le32 carrying the uncompressed size is part of the1414-# format, but in other cases, we just append it at the end for convenience,1515-# causing the original tools to complain when checking image integrity.1616-# So disregard it when calculating the payload size in the zimage header.1717-zboot-method-y := $(comp-type-y)_with_size1818-zboot-size-len-y := 41919-2020-zboot-method-$(CONFIG_KERNEL_GZIP) := gzip2121-zboot-size-len-$(CONFIG_KERNEL_GZIP) := 01313+# Copy the SizeOfHeaders, SizeOfCode and SizeOfImage fields from the payload to1414+# the end of the compressed image. Note that this presupposes a PE header1515+# offset of 64 bytes, which is what arm64, RISC-V and LoongArch use.1616+quiet_cmd_compwithsize = $(quiet_cmd_$(comp-type-y))1717+ cmd_compwithsize = $(cmd_$(comp-type-y)) && ( \1818+ dd status=none if=$< bs=4 count=1 skip=37 ; \1919+ dd status=none if=$< bs=4 count=1 skip=23 ; \2020+ dd status=none if=$< bs=4 count=1 skip=36 ) >> $@22212322$(obj)/vmlinuz: $(obj)/$(EFI_ZBOOT_PAYLOAD) FORCE2424- $(call if_changed,$(zboot-method-y))2323+ $(call if_changed,compwithsize)25242625OBJCOPYFLAGS_vmlinuz.o := -I binary -O $(EFI_ZBOOT_BFD_TARGET) \2726 --rename-section .data=.gzdata,load,alloc,readonly,contents···29303031AFLAGS_zboot-header.o += -DMACHINE_TYPE=IMAGE_FILE_MACHINE_$(EFI_ZBOOT_MACH_TYPE) \3132 -DZBOOT_EFI_PATH="\"$(realpath $(obj)/vmlinuz.efi.elf)\"" \3232- -DZBOOT_SIZE_LEN=$(zboot-size-len-y) \3333 -DCOMP_TYPE="\"$(comp-type-y)\""34343535$(obj)/zboot-header.o: $(srctree)/drivers/firmware/efi/libstub/zboot-header.S FORCE···4446$(obj)/vmlinuz.efi: $(obj)/vmlinuz.efi.elf FORCE4547 $(call if_changed,objcopy)46484747-targets += zboot-header.o vmlinuz vmlinuz.o vmlinuz.efi.elf vmlinuz.efi4949+targets += zboot-header.o vmlinuz.o vmlinuz.efi.elf vmlinuz.efi
-37
drivers/firmware/efi/libstub/arm32-stub.c
···7676 &efi_entry_state->sctlr_after_ebs);7777}78787979-static efi_guid_t screen_info_guid = LINUX_EFI_ARM_SCREEN_INFO_TABLE_GUID;8080-8181-struct screen_info *alloc_screen_info(void)8282-{8383- struct screen_info *si;8484- efi_status_t status;8585-8686- /*8787- * Unlike on arm64, where we can directly fill out the screen_info8888- * structure from the stub, we need to allocate a buffer to hold8989- * its contents while we hand over to the kernel proper from the9090- * decompressor.9191- */9292- status = efi_bs_call(allocate_pool, EFI_RUNTIME_SERVICES_DATA,9393- sizeof(*si), (void **)&si);9494-9595- if (status != EFI_SUCCESS)9696- return NULL;9797-9898- status = efi_bs_call(install_configuration_table,9999- &screen_info_guid, si);100100- if (status == EFI_SUCCESS)101101- return si;102102-103103- efi_bs_call(free_pool, si);104104- return NULL;105105-}106106-107107-void free_screen_info(struct screen_info *si)108108-{109109- if (!si)110110- return;111111-112112- efi_bs_call(install_configuration_table, &screen_info_guid, NULL);113113- efi_bs_call(free_pool, si);114114-}115115-11679efi_status_t handle_kernel_image(unsigned long *image_addr,11780 unsigned long *image_size,11881 unsigned long *reserve_addr,
+67
drivers/firmware/efi/libstub/arm64-entry.S
···11+/* SPDX-License-Identifier: GPL-2.0-only */22+/*33+ * EFI entry point.44+ *55+ * Copyright (C) 2013, 2014 Red Hat, Inc.66+ * Author: Mark Salter <msalter@redhat.com>77+ */88+#include <linux/linkage.h>99+#include <asm/assembler.h>1010+1111+ /*1212+ * The entrypoint of a arm64 bare metal image is at offset #0 of the1313+ * image, so this is a reasonable default for primary_entry_offset.1414+ * Only when the EFI stub is integrated into the core kernel, it is not1515+ * guaranteed that the PE/COFF header has been copied to memory too, so1616+ * in this case, primary_entry_offset should be overridden by the1717+ * linker and point to primary_entry() directly.1818+ */1919+ .weak primary_entry_offset2020+2121+SYM_CODE_START(efi_enter_kernel)2222+ /*2323+ * efi_pe_entry() will have copied the kernel image if necessary and we2424+ * end up here with device tree address in x1 and the kernel entry2525+ * point stored in x0. Save those values in registers which are2626+ * callee preserved.2727+ */2828+ ldr w2, =primary_entry_offset2929+ add x19, x0, x2 // relocated Image entrypoint3030+3131+ mov x0, x1 // DTB address3232+ mov x1, xzr3333+ mov x2, xzr3434+ mov x3, xzr3535+3636+ /*3737+ * Clean the remainder of this routine to the PoC3838+ * so that we can safely disable the MMU and caches.3939+ */4040+ adr x4, 1f4141+ dc civac, x44242+ dsb sy4343+4444+ /* Turn off Dcache and MMU */4545+ mrs x4, CurrentEL4646+ cmp x4, #CurrentEL_EL24747+ mrs x4, sctlr_el14848+ b.ne 0f4949+ mrs x4, sctlr_el25050+0: bic x4, x4, #SCTLR_ELx_M5151+ bic x4, x4, #SCTLR_ELx_C5252+ b.eq 1f5353+ b 2f5454+5555+ .balign 325656+1: pre_disable_mmu_workaround5757+ msr sctlr_el2, x45858+ isb5959+ br x19 // jump to kernel entrypoint6060+6161+2: pre_disable_mmu_workaround6262+ msr sctlr_el1, x46363+ isb6464+ br x19 // jump to kernel entrypoint6565+6666+ .org 1b + 326767+SYM_CODE_END(efi_enter_kernel)
+10-54
drivers/firmware/efi/libstub/arm64-stub.c
···1111#include <asm/efi.h>1212#include <asm/memory.h>1313#include <asm/sections.h>1414-#include <asm/sysreg.h>15141615#include "efistub.h"1717-1818-static bool system_needs_vamap(void)1919-{2020- const u8 *type1_family = efi_get_smbios_string(1, family);2121-2222- /*2323- * Ampere Altra machines crash in SetTime() if SetVirtualAddressMap()2424- * has not been called prior.2525- */2626- if (!type1_family || strcmp(type1_family, "Altra"))2727- return false;2828-2929- efi_warn("Working around broken SetVirtualAddressMap()\n");3030- return true;3131-}3232-3333-efi_status_t check_platform_features(void)3434-{3535- u64 tg;3636-3737- /*3838- * If we have 48 bits of VA space for TTBR0 mappings, we can map the3939- * UEFI runtime regions 1:1 and so calling SetVirtualAddressMap() is4040- * unnecessary.4141- */4242- if (VA_BITS_MIN >= 48 && !system_needs_vamap())4343- efi_novamap = true;4444-4545- /* UEFI mandates support for 4 KB granularity, no need to check */4646- if (IS_ENABLED(CONFIG_ARM64_4K_PAGES))4747- return EFI_SUCCESS;4848-4949- tg = (read_cpuid(ID_AA64MMFR0_EL1) >> ID_AA64MMFR0_EL1_TGRAN_SHIFT) & 0xf;5050- if (tg < ID_AA64MMFR0_EL1_TGRAN_SUPPORTED_MIN || tg > ID_AA64MMFR0_EL1_TGRAN_SUPPORTED_MAX) {5151- if (IS_ENABLED(CONFIG_ARM64_64K_PAGES))5252- efi_err("This 64 KB granular kernel is not supported by your CPU\n");5353- else5454- efi_err("This 16 KB granular kernel is not supported by your CPU\n");5555- return EFI_UNSUPPORTED;5656- }5757- return EFI_SUCCESS;5858-}59166017/*6118 * Distro versions of GRUB may ignore the BSS allocation entirely (i.e., fail···60103 efi_status_t status;61104 unsigned long kernel_size, kernel_memsize = 0;62105 u32 phys_seed = 0;6363-6464- /*6565- * Although relocatable kernels can fix up the misalignment with6666- * respect to MIN_KIMG_ALIGN, the resulting virtual text addresses are6767- * subtly out of sync with those recorded in the vmlinux when kaslr is6868- * disabled but the image required relocation anyway. Therefore retain6969- * 2M alignment if KASLR was explicitly disabled, even if it was not7070- * going to be activated to begin with.7171- */7272- u64 min_kimg_align = efi_nokaslr ? MIN_KIMG_ALIGN : EFI_KIMG_ALIGN;106106+ u64 min_kimg_align = efi_get_kimg_min_align();7310774108 if (IS_ENABLED(CONFIG_RANDOMIZE_BASE)) {75109 efi_guid_t li_fixed_proto = LINUX_EFI_LOADED_IMAGE_FIXED_GUID;···119171 */120172 *image_addr = (u64)_text;121173 *reserve_size = 0;122122- return EFI_SUCCESS;174174+ goto clean_image_to_poc;123175 }124176125177 status = efi_allocate_pages_aligned(*reserve_size, reserve_addr,···134186135187 *image_addr = *reserve_addr;136188 memcpy((void *)*image_addr, _text, kernel_size);189189+190190+clean_image_to_poc:191191+ /*192192+ * Clean the copied Image to the PoC, and ensure it is not shadowed by193193+ * stale icache entries from before relocation.194194+ */195195+ dcache_clean_poc(*image_addr, *image_addr + kernel_size);196196+ asm("ic ialluis");137197138198 return EFI_SUCCESS;139199}
+76
drivers/firmware/efi/libstub/arm64.c
···11+// SPDX-License-Identifier: GPL-2.022+/*33+ * Copyright (C) 2013, 2014 Linaro Ltd; <roy.franz@linaro.org>44+ *55+ * This file implements the EFI boot stub for the arm64 kernel.66+ * Adapted from ARM version by Mark Salter <msalter@redhat.com>77+ */88+99+1010+#include <linux/efi.h>1111+#include <asm/efi.h>1212+#include <asm/memory.h>1313+#include <asm/sysreg.h>1414+1515+#include "efistub.h"1616+1717+static bool system_needs_vamap(void)1818+{1919+ const u8 *type1_family = efi_get_smbios_string(1, family);2020+2121+ /*2222+ * Ampere Altra machines crash in SetTime() if SetVirtualAddressMap()2323+ * has not been called prior.2424+ */2525+ if (!type1_family || strcmp(type1_family, "Altra"))2626+ return false;2727+2828+ efi_warn("Working around broken SetVirtualAddressMap()\n");2929+ return true;3030+}3131+3232+efi_status_t check_platform_features(void)3333+{3434+ u64 tg;3535+3636+ /*3737+ * If we have 48 bits of VA space for TTBR0 mappings, we can map the3838+ * UEFI runtime regions 1:1 and so calling SetVirtualAddressMap() is3939+ * unnecessary.4040+ */4141+ if (VA_BITS_MIN >= 48 && !system_needs_vamap())4242+ efi_novamap = true;4343+4444+ /* UEFI mandates support for 4 KB granularity, no need to check */4545+ if (IS_ENABLED(CONFIG_ARM64_4K_PAGES))4646+ return EFI_SUCCESS;4747+4848+ tg = (read_cpuid(ID_AA64MMFR0_EL1) >> ID_AA64MMFR0_EL1_TGRAN_SHIFT) & 0xf;4949+ if (tg < ID_AA64MMFR0_EL1_TGRAN_SUPPORTED_MIN || tg > ID_AA64MMFR0_EL1_TGRAN_SUPPORTED_MAX) {5050+ if (IS_ENABLED(CONFIG_ARM64_64K_PAGES))5151+ efi_err("This 64 KB granular kernel is not supported by your CPU\n");5252+ else5353+ efi_err("This 16 KB granular kernel is not supported by your CPU\n");5454+ return EFI_UNSUPPORTED;5555+ }5656+ return EFI_SUCCESS;5757+}5858+5959+void efi_cache_sync_image(unsigned long image_base,6060+ unsigned long alloc_size,6161+ unsigned long code_size)6262+{6363+ u32 ctr = read_cpuid_effective_cachetype();6464+ u64 lsize = 4 << cpuid_feature_extract_unsigned_field(ctr,6565+ CTR_EL0_DminLine_SHIFT);6666+6767+ do {6868+ asm("dc civac, %0" :: "r"(image_base));6969+ image_base += lsize;7070+ alloc_size -= lsize;7171+ } while (alloc_size >= lsize);7272+7373+ asm("ic ialluis");7474+ dsb(ish);7575+ isb();7676+}
+65
drivers/firmware/efi/libstub/efi-stub-entry.c
···11+// SPDX-License-Identifier: GPL-2.0-only22+33+#include <linux/efi.h>44+#include <asm/efi.h>55+66+#include "efistub.h"77+88+/*99+ * EFI entry point for the generic EFI stub used by ARM, arm64, RISC-V and1010+ * LoongArch. This is the entrypoint that is described in the PE/COFF header1111+ * of the core kernel.1212+ */1313+efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,1414+ efi_system_table_t *systab)1515+{1616+ efi_loaded_image_t *image;1717+ efi_status_t status;1818+ unsigned long image_addr;1919+ unsigned long image_size = 0;2020+ /* addr/point and size pairs for memory management*/2121+ char *cmdline_ptr = NULL;2222+ efi_guid_t loaded_image_proto = LOADED_IMAGE_PROTOCOL_GUID;2323+ unsigned long reserve_addr = 0;2424+ unsigned long reserve_size = 0;2525+2626+ WRITE_ONCE(efi_system_table, systab);2727+2828+ /* Check if we were booted by the EFI firmware */2929+ if (efi_system_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)3030+ return EFI_INVALID_PARAMETER;3131+3232+ /*3333+ * Get a handle to the loaded image protocol. This is used to get3434+ * information about the running image, such as size and the command3535+ * line.3636+ */3737+ status = efi_bs_call(handle_protocol, handle, &loaded_image_proto,3838+ (void *)&image);3939+ if (status != EFI_SUCCESS) {4040+ efi_err("Failed to get loaded image protocol\n");4141+ return status;4242+ }4343+4444+ status = efi_handle_cmdline(image, &cmdline_ptr);4545+ if (status != EFI_SUCCESS)4646+ return status;4747+4848+ efi_info("Booting Linux Kernel...\n");4949+5050+ status = handle_kernel_image(&image_addr, &image_size,5151+ &reserve_addr,5252+ &reserve_size,5353+ image, handle);5454+ if (status != EFI_SUCCESS) {5555+ efi_err("Failed to relocate kernel\n");5656+ return status;5757+ }5858+5959+ status = efi_stub_common(handle, image, image_addr, cmdline_ptr);6060+6161+ efi_free(image_size, image_addr);6262+ efi_free(reserve_size, reserve_addr);6363+6464+ return status;6565+}
-143
drivers/firmware/efi/libstub/efi-stub-helper.c
···991010#include <linux/stdarg.h>11111212-#include <linux/ctype.h>1312#include <linux/efi.h>1413#include <linux/kernel.h>1515-#include <linux/printk.h> /* For CONSOLE_LOGLEVEL_* */1614#include <asm/efi.h>1715#include <asm/setup.h>1816···18201921bool efi_nochunk;2022bool efi_nokaslr = !IS_ENABLED(CONFIG_RANDOMIZE_BASE);2121-int efi_loglevel = CONSOLE_LOGLEVEL_DEFAULT;2223bool efi_novamap;23242425static bool efi_noinitrd;···2730bool __pure __efi_soft_reserve_enabled(void)2831{2932 return !efi_nosoftreserve;3030-}3131-3232-/**3333- * efi_char16_puts() - Write a UCS-2 encoded string to the console3434- * @str: UCS-2 encoded string3535- */3636-void efi_char16_puts(efi_char16_t *str)3737-{3838- efi_call_proto(efi_table_attr(efi_system_table, con_out),3939- output_string, str);4040-}4141-4242-static4343-u32 utf8_to_utf32(const u8 **s8)4444-{4545- u32 c32;4646- u8 c0, cx;4747- size_t clen, i;4848-4949- c0 = cx = *(*s8)++;5050- /*5151- * The position of the most-significant 0 bit gives us the length of5252- * a multi-octet encoding.5353- */5454- for (clen = 0; cx & 0x80; ++clen)5555- cx <<= 1;5656- /*5757- * If the 0 bit is in position 8, this is a valid single-octet5858- * encoding. If the 0 bit is in position 7 or positions 1-3, the5959- * encoding is invalid.6060- * In either case, we just return the first octet.6161- */6262- if (clen < 2 || clen > 4)6363- return c0;6464- /* Get the bits from the first octet. */6565- c32 = cx >> clen--;6666- for (i = 0; i < clen; ++i) {6767- /* Trailing octets must have 10 in most significant bits. */6868- cx = (*s8)[i] ^ 0x80;6969- if (cx & 0xc0)7070- return c0;7171- c32 = (c32 << 6) | cx;7272- }7373- /*7474- * Check for validity:7575- * - The character must be in the Unicode range.7676- * - It must not be a surrogate.7777- * - It must be encoded using the correct number of octets.7878- */7979- if (c32 > 0x10ffff ||8080- (c32 & 0xf800) == 0xd800 ||8181- clen != (c32 >= 0x80) + (c32 >= 0x800) + (c32 >= 0x10000))8282- return c0;8383- *s8 += clen;8484- return c32;8585-}8686-8787-/**8888- * efi_puts() - Write a UTF-8 encoded string to the console8989- * @str: UTF-8 encoded string9090- */9191-void efi_puts(const char *str)9292-{9393- efi_char16_t buf[128];9494- size_t pos = 0, lim = ARRAY_SIZE(buf);9595- const u8 *s8 = (const u8 *)str;9696- u32 c32;9797-9898- while (*s8) {9999- if (*s8 == '\n')100100- buf[pos++] = L'\r';101101- c32 = utf8_to_utf32(&s8);102102- if (c32 < 0x10000) {103103- /* Characters in plane 0 use a single word. */104104- buf[pos++] = c32;105105- } else {106106- /*107107- * Characters in other planes encode into a surrogate108108- * pair.109109- */110110- buf[pos++] = (0xd800 - (0x10000 >> 10)) + (c32 >> 10);111111- buf[pos++] = 0xdc00 + (c32 & 0x3ff);112112- }113113- if (*s8 == '\0' || pos >= lim - 2) {114114- buf[pos] = L'\0';115115- efi_char16_puts(buf);116116- pos = 0;117117- }118118- }119119-}120120-121121-/**122122- * efi_printk() - Print a kernel message123123- * @fmt: format string124124- *125125- * The first letter of the format string is used to determine the logging level126126- * of the message. If the level is less then the current EFI logging level, the127127- * message is suppressed. The message will be truncated to 255 bytes.128128- *129129- * Return: number of printed characters130130- */131131-int efi_printk(const char *fmt, ...)132132-{133133- char printf_buf[256];134134- va_list args;135135- int printed;136136- int loglevel = printk_get_level(fmt);137137-138138- switch (loglevel) {139139- case '0' ... '9':140140- loglevel -= '0';141141- break;142142- default:143143- /*144144- * Use loglevel -1 for cases where we just want to print to145145- * the screen.146146- */147147- loglevel = -1;148148- break;149149- }150150-151151- if (loglevel >= efi_loglevel)152152- return 0;153153-154154- if (loglevel >= 0)155155- efi_puts("EFI stub: ");156156-157157- fmt = printk_skip_level(fmt);158158-159159- va_start(args, fmt);160160- printed = vsnprintf(printf_buf, sizeof(printf_buf), fmt, args);161161- va_end(args);162162-163163- efi_puts(printf_buf);164164- if (printed >= sizeof(printf_buf)) {165165- efi_puts("[Message truncated]\n");166166- return -1;167167- }168168-169169- return printed;17033}1713417235/**
+35-105
drivers/firmware/efi/libstub/efi-stub.c
···3535 * as well to minimize the code churn.3636 */3737#define EFI_RT_VIRTUAL_BASE SZ_512M3838-#define EFI_RT_VIRTUAL_SIZE SZ_512M3939-4040-#ifdef CONFIG_ARM644141-# define EFI_RT_VIRTUAL_LIMIT DEFAULT_MAP_WINDOW_644242-#elif defined(CONFIG_RISCV) || defined(CONFIG_LOONGARCH)4343-# define EFI_RT_VIRTUAL_LIMIT TASK_SIZE_MIN4444-#else /* Only if TASK_SIZE is a constant */4545-# define EFI_RT_VIRTUAL_LIMIT TASK_SIZE4646-#endif47384839/*4940 * Some architectures map the EFI regions into the kernel's linear map using a···46554756static u64 virtmap_base = EFI_RT_VIRTUAL_BASE;4857static bool flat_va_mapping = (EFI_RT_VIRTUAL_OFFSET != 0);5858+5959+struct screen_info * __weak alloc_screen_info(void)6060+{6161+ return &screen_info;6262+}6363+6464+void __weak free_screen_info(struct screen_info *si)6565+{6666+}49675068static struct screen_info *setup_graphics(void)5169{···115115 return supported;116116}117117118118-/*119119- * EFI entry point for the arm/arm64 EFI stubs. This is the entrypoint120120- * that is described in the PE/COFF header. Most of the code is the same121121- * for both archictectures, with the arch-specific code provided in the122122- * handle_kernel_image() function.123123- */124124-efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,125125- efi_system_table_t *sys_table_arg)118118+efi_status_t efi_handle_cmdline(efi_loaded_image_t *image, char **cmdline_ptr)126119{127127- efi_loaded_image_t *image;128128- efi_status_t status;129129- unsigned long image_addr;130130- unsigned long image_size = 0;131131- /* addr/point and size pairs for memory management*/132132- char *cmdline_ptr = NULL;133120 int cmdline_size = 0;134134- efi_guid_t loaded_image_proto = LOADED_IMAGE_PROTOCOL_GUID;135135- unsigned long reserve_addr = 0;136136- unsigned long reserve_size = 0;137137- struct screen_info *si;138138- efi_properties_table_t *prop_tbl;139139-140140- efi_system_table = sys_table_arg;141141-142142- /* Check if we were booted by the EFI firmware */143143- if (efi_system_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) {144144- status = EFI_INVALID_PARAMETER;145145- goto fail;146146- }147147-148148- status = check_platform_features();149149- if (status != EFI_SUCCESS)150150- goto fail;151151-152152- /*153153- * Get a handle to the loaded image protocol. This is used to get154154- * information about the running image, such as size and the command155155- * line.156156- */157157- status = efi_bs_call(handle_protocol, handle, &loaded_image_proto,158158- (void *)&image);159159- if (status != EFI_SUCCESS) {160160- efi_err("Failed to get loaded image protocol\n");161161- goto fail;162162- }121121+ efi_status_t status;122122+ char *cmdline;163123164124 /*165125 * Get the command line from EFI, using the LOADED_IMAGE166126 * protocol. We are going to copy the command line into the167127 * device tree, so this can be allocated anywhere.168128 */169169- cmdline_ptr = efi_convert_cmdline(image, &cmdline_size);170170- if (!cmdline_ptr) {129129+ cmdline = efi_convert_cmdline(image, &cmdline_size);130130+ if (!cmdline) {171131 efi_err("getting command line via LOADED_IMAGE_PROTOCOL\n");172172- status = EFI_OUT_OF_RESOURCES;173173- goto fail;132132+ return EFI_OUT_OF_RESOURCES;174133 }175134176135 if (IS_ENABLED(CONFIG_CMDLINE_EXTEND) ||···143184 }144185145186 if (!IS_ENABLED(CONFIG_CMDLINE_FORCE) && cmdline_size > 0) {146146- status = efi_parse_options(cmdline_ptr);187187+ status = efi_parse_options(cmdline);147188 if (status != EFI_SUCCESS) {148189 efi_err("Failed to parse options\n");149190 goto fail_free_cmdline;150191 }151192 }152193153153- efi_info("Booting Linux Kernel...\n");194194+ *cmdline_ptr = cmdline;195195+ return EFI_SUCCESS;196196+197197+fail_free_cmdline:198198+ efi_bs_call(free_pool, cmdline_ptr);199199+ return status;200200+}201201+202202+efi_status_t efi_stub_common(efi_handle_t handle,203203+ efi_loaded_image_t *image,204204+ unsigned long image_addr,205205+ char *cmdline_ptr)206206+{207207+ struct screen_info *si;208208+ efi_status_t status;209209+210210+ status = check_platform_features();211211+ if (status != EFI_SUCCESS)212212+ return status;154213155214 si = setup_graphics();156156-157157- status = handle_kernel_image(&image_addr, &image_size,158158- &reserve_addr,159159- &reserve_size,160160- image, handle);161161- if (status != EFI_SUCCESS) {162162- efi_err("Failed to relocate kernel\n");163163- goto fail_free_screeninfo;164164- }165215166216 efi_retrieve_tpm2_eventlog();167217···182214183215 efi_random_get_seed();184216185185- /*186186- * If the NX PE data feature is enabled in the properties table, we187187- * should take care not to create a virtual mapping that changes the188188- * relative placement of runtime services code and data regions, as189189- * they may belong to the same PE/COFF executable image in memory.190190- * The easiest way to achieve that is to simply use a 1:1 mapping.191191- */192192- prop_tbl = get_efi_config_table(EFI_PROPERTIES_TABLE_GUID);193193- flat_va_mapping |= prop_tbl &&194194- (prop_tbl->memory_protection_attribute &195195- EFI_PROPERTIES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA);196196-197217 /* force efi_novamap if SetVirtualAddressMap() is unsupported */198218 efi_novamap |= !(get_supported_rt_services() &199219 EFI_RT_SUPPORTED_SET_VIRTUAL_ADDRESS_MAP);200200-201201- /* hibernation expects the runtime regions to stay in the same place */202202- if (!IS_ENABLED(CONFIG_HIBERNATION) && !efi_nokaslr && !flat_va_mapping) {203203- /*204204- * Randomize the base of the UEFI runtime services region.205205- * Preserve the 2 MB alignment of the region by taking a206206- * shift of 21 bit positions into account when scaling207207- * the headroom value using a 32-bit random value.208208- */209209- static const u64 headroom = EFI_RT_VIRTUAL_LIMIT -210210- EFI_RT_VIRTUAL_BASE -211211- EFI_RT_VIRTUAL_SIZE;212212- u32 rnd;213213-214214- status = efi_get_random_bytes(sizeof(rnd), (u8 *)&rnd);215215- if (status == EFI_SUCCESS) {216216- virtmap_base = EFI_RT_VIRTUAL_BASE +217217- (((headroom >> 21) * rnd) >> (32 - 21));218218- }219219- }220220221221 install_memreserve_table();222222223223 status = efi_boot_kernel(handle, image, image_addr, cmdline_ptr);224224225225- efi_free(image_size, image_addr);226226- efi_free(reserve_size, reserve_addr);227227-fail_free_screeninfo:228225 free_screen_info(si);229229-fail_free_cmdline:230230- efi_bs_call(free_pool, cmdline_ptr);231231-fail:232226 return status;233227}234228
+15
drivers/firmware/efi/libstub/efistub.h
···958958 efi_loaded_image_t *image,959959 efi_handle_t image_handle);960960961961+/* shared entrypoint between the normal stub and the zboot stub */962962+efi_status_t efi_stub_common(efi_handle_t handle,963963+ efi_loaded_image_t *image,964964+ unsigned long image_addr,965965+ char *cmdline_ptr);966966+967967+efi_status_t efi_handle_cmdline(efi_loaded_image_t *image, char **cmdline_ptr);968968+961969asmlinkage void __noreturn efi_enter_kernel(unsigned long entrypoint,962970 unsigned long fdt_addr,963971 unsigned long fdt_size);···982974#endif983975984976void efi_retrieve_tpm2_eventlog(void);977977+978978+struct screen_info *alloc_screen_info(void);979979+void free_screen_info(struct screen_info *si);980980+981981+void efi_cache_sync_image(unsigned long image_base,982982+ unsigned long alloc_size,983983+ unsigned long code_size);985984986985struct efi_smbios_record {987986 u8 type;
-18
drivers/firmware/efi/libstub/file.c
···6666static efi_status_t efi_open_volume(efi_loaded_image_t *image,6767 efi_file_protocol_t **fh)6868{6969- struct efi_vendor_dev_path *dp = image->file_path;7070- efi_guid_t li_proto = LOADED_IMAGE_PROTOCOL_GUID;7169 efi_guid_t fs_proto = EFI_FILE_SYSTEM_GUID;7270 efi_simple_file_system_protocol_t *io;7371 efi_status_t status;7474-7575- // If we are using EFI zboot, we should look for the file system7676- // protocol on the parent image's handle instead7777- if (IS_ENABLED(CONFIG_EFI_ZBOOT) &&7878- image->parent_handle != NULL &&7979- dp != NULL &&8080- dp->header.type == EFI_DEV_MEDIA &&8181- dp->header.sub_type == EFI_DEV_MEDIA_VENDOR &&8282- !efi_guidcmp(dp->vendorguid, LINUX_EFI_ZBOOT_MEDIA_GUID)) {8383- status = efi_bs_call(handle_protocol, image->parent_handle,8484- &li_proto, (void *)&image);8585- if (status != EFI_SUCCESS) {8686- efi_err("Failed to locate parent image handle\n");8787- return status;8888- }8989- }90729173 status = efi_bs_call(handle_protocol, image->device_handle, &fs_proto,9274 (void **)&io);
+18
drivers/firmware/efi/libstub/intrinsics.c
···2828 efi_bs_call(set_mem, dst, len, c & U8_MAX);2929 return dst;3030}3131+3232+/**3333+ * memcmp - Compare two areas of memory3434+ * @cs: One area of memory3535+ * @ct: Another area of memory3636+ * @count: The size of the area.3737+ */3838+#undef memcmp3939+int memcmp(const void *cs, const void *ct, size_t count)4040+{4141+ const unsigned char *su1, *su2;4242+ int res = 0;4343+4444+ for (su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--)4545+ if ((res = *su1 - *su2) != 0)4646+ break;4747+ return res;4848+}
+20-69
drivers/firmware/efi/libstub/loongarch-stub.c
···99#include <asm/addrspace.h>1010#include "efistub.h"11111212-typedef void __noreturn (*kernel_entry_t)(bool efi, unsigned long cmdline,1313- unsigned long systab);1414-1512extern int kernel_asize;1613extern int kernel_fsize;1714extern int kernel_offset;1818-extern kernel_entry_t kernel_entry;1919-2020-efi_status_t check_platform_features(void)2121-{2222- return EFI_SUCCESS;2323-}1515+extern int kernel_entry;24162517efi_status_t handle_kernel_image(unsigned long *image_addr,2618 unsigned long *image_size,···2129 efi_loaded_image_t *image,2230 efi_handle_t image_handle)2331{3232+ int nr_pages = round_up(kernel_asize, EFI_ALLOC_ALIGN) / EFI_PAGE_SIZE;3333+ efi_physical_addr_t kernel_addr = EFI_KIMG_PREFERRED_ADDRESS;2434 efi_status_t status;2525- unsigned long kernel_addr = 0;26352727- kernel_addr = (unsigned long)&kernel_offset - kernel_offset;3636+ /*3737+ * Allocate space for the kernel image at the preferred offset. This is3838+ * the only location in memory from where we can execute the image, so3939+ * no point in falling back to another allocation.4040+ */4141+ status = efi_bs_call(allocate_pages, EFI_ALLOCATE_ADDRESS,4242+ EFI_LOADER_DATA, nr_pages, &kernel_addr);4343+ if (status != EFI_SUCCESS)4444+ return status;28452929- status = efi_relocate_kernel(&kernel_addr, kernel_fsize, kernel_asize,3030- PHYSADDR(VMLINUX_LOAD_ADDRESS), SZ_2M, 0x0);3131-3232- *image_addr = kernel_addr;4646+ *image_addr = EFI_KIMG_PREFERRED_ADDRESS;3347 *image_size = kernel_asize;4848+4949+ memcpy((void *)EFI_KIMG_PREFERRED_ADDRESS,5050+ (void *)&kernel_offset - kernel_offset,5151+ kernel_fsize);34523553 return status;3654}37553838-struct exit_boot_struct {3939- efi_memory_desc_t *runtime_map;4040- int runtime_entry_count;4141-};4242-4343-static efi_status_t exit_boot_func(struct efi_boot_memmap *map, void *priv)5656+unsigned long kernel_entry_address(void)4457{4545- struct exit_boot_struct *p = priv;5858+ unsigned long base = (unsigned long)&kernel_offset - kernel_offset;46594747- /*4848- * Update the memory map with virtual addresses. The function will also4949- * populate @runtime_map with copies of just the EFI_MEMORY_RUNTIME5050- * entries so that we can pass it straight to SetVirtualAddressMap()5151- */5252- efi_get_virtmap(map->map, map->map_size, map->desc_size,5353- p->runtime_map, &p->runtime_entry_count);5454-5555- return EFI_SUCCESS;5656-}5757-5858-efi_status_t efi_boot_kernel(void *handle, efi_loaded_image_t *image,5959- unsigned long kernel_addr, char *cmdline_ptr)6060-{6161- kernel_entry_t real_kernel_entry;6262- struct exit_boot_struct priv;6363- unsigned long desc_size;6464- efi_status_t status;6565- u32 desc_ver;6666-6767- status = efi_alloc_virtmap(&priv.runtime_map, &desc_size, &desc_ver);6868- if (status != EFI_SUCCESS) {6969- efi_err("Unable to retrieve UEFI memory map.\n");7070- return status;7171- }7272-7373- efi_info("Exiting boot services\n");7474-7575- efi_novamap = false;7676- status = efi_exit_boot_services(handle, &priv, exit_boot_func);7777- if (status != EFI_SUCCESS)7878- return status;7979-8080- /* Install the new virtual address map */8181- efi_rt_call(set_virtual_address_map,8282- priv.runtime_entry_count * desc_size, desc_size,8383- desc_ver, priv.runtime_map);8484-8585- /* Config Direct Mapping */8686- csr_write64(CSR_DMW0_INIT, LOONGARCH_CSR_DMWIN0);8787- csr_write64(CSR_DMW1_INIT, LOONGARCH_CSR_DMWIN1);8888-8989- real_kernel_entry = (kernel_entry_t)9090- ((unsigned long)&kernel_entry - kernel_addr + VMLINUX_LOAD_ADDRESS);9191-9292- real_kernel_entry(true, (unsigned long)cmdline_ptr,9393- (unsigned long)efi_system_table);6060+ return (unsigned long)&kernel_entry - base + VMLINUX_LOAD_ADDRESS;9461}
+80
drivers/firmware/efi/libstub/loongarch.c
···11+// SPDX-License-Identifier: GPL-2.022+/*33+ * Author: Yun Liu <liuyun@loongson.cn>44+ * Huacai Chen <chenhuacai@loongson.cn>55+ * Copyright (C) 2020-2022 Loongson Technology Corporation Limited66+ */77+88+#include <asm/efi.h>99+#include <asm/addrspace.h>1010+#include "efistub.h"1111+1212+typedef void __noreturn (*kernel_entry_t)(bool efi, unsigned long cmdline,1313+ unsigned long systab);1414+1515+efi_status_t check_platform_features(void)1616+{1717+ return EFI_SUCCESS;1818+}1919+2020+struct exit_boot_struct {2121+ efi_memory_desc_t *runtime_map;2222+ int runtime_entry_count;2323+};2424+2525+static efi_status_t exit_boot_func(struct efi_boot_memmap *map, void *priv)2626+{2727+ struct exit_boot_struct *p = priv;2828+2929+ /*3030+ * Update the memory map with virtual addresses. The function will also3131+ * populate @runtime_map with copies of just the EFI_MEMORY_RUNTIME3232+ * entries so that we can pass it straight to SetVirtualAddressMap()3333+ */3434+ efi_get_virtmap(map->map, map->map_size, map->desc_size,3535+ p->runtime_map, &p->runtime_entry_count);3636+3737+ return EFI_SUCCESS;3838+}3939+4040+unsigned long __weak kernel_entry_address(void)4141+{4242+ return *(unsigned long *)(PHYSADDR(VMLINUX_LOAD_ADDRESS) + 8);4343+}4444+4545+efi_status_t efi_boot_kernel(void *handle, efi_loaded_image_t *image,4646+ unsigned long kernel_addr, char *cmdline_ptr)4747+{4848+ kernel_entry_t real_kernel_entry;4949+ struct exit_boot_struct priv;5050+ unsigned long desc_size;5151+ efi_status_t status;5252+ u32 desc_ver;5353+5454+ status = efi_alloc_virtmap(&priv.runtime_map, &desc_size, &desc_ver);5555+ if (status != EFI_SUCCESS) {5656+ efi_err("Unable to retrieve UEFI memory map.\n");5757+ return status;5858+ }5959+6060+ efi_info("Exiting boot services\n");6161+6262+ efi_novamap = false;6363+ status = efi_exit_boot_services(handle, &priv, exit_boot_func);6464+ if (status != EFI_SUCCESS)6565+ return status;6666+6767+ /* Install the new virtual address map */6868+ efi_rt_call(set_virtual_address_map,6969+ priv.runtime_entry_count * desc_size, desc_size,7070+ desc_ver, priv.runtime_map);7171+7272+ /* Config Direct Mapping */7373+ csr_write64(CSR_DMW0_INIT, LOONGARCH_CSR_DMWIN0);7474+ csr_write64(CSR_DMW1_INIT, LOONGARCH_CSR_DMWIN1);7575+7676+ real_kernel_entry = (void *)kernel_entry_address();7777+7878+ real_kernel_entry(true, (unsigned long)cmdline_ptr,7979+ (unsigned long)efi_system_table);8080+}
+154
drivers/firmware/efi/libstub/printk.c
···11+// SPDX-License-Identifier: GPL-2.022+33+#include <linux/stdarg.h>44+55+#include <linux/ctype.h>66+#include <linux/efi.h>77+#include <linux/kernel.h>88+#include <linux/printk.h> /* For CONSOLE_LOGLEVEL_* */99+#include <asm/efi.h>1010+#include <asm/setup.h>1111+1212+#include "efistub.h"1313+1414+int efi_loglevel = CONSOLE_LOGLEVEL_DEFAULT;1515+1616+/**1717+ * efi_char16_puts() - Write a UCS-2 encoded string to the console1818+ * @str: UCS-2 encoded string1919+ */2020+void efi_char16_puts(efi_char16_t *str)2121+{2222+ efi_call_proto(efi_table_attr(efi_system_table, con_out),2323+ output_string, str);2424+}2525+2626+static2727+u32 utf8_to_utf32(const u8 **s8)2828+{2929+ u32 c32;3030+ u8 c0, cx;3131+ size_t clen, i;3232+3333+ c0 = cx = *(*s8)++;3434+ /*3535+ * The position of the most-significant 0 bit gives us the length of3636+ * a multi-octet encoding.3737+ */3838+ for (clen = 0; cx & 0x80; ++clen)3939+ cx <<= 1;4040+ /*4141+ * If the 0 bit is in position 8, this is a valid single-octet4242+ * encoding. If the 0 bit is in position 7 or positions 1-3, the4343+ * encoding is invalid.4444+ * In either case, we just return the first octet.4545+ */4646+ if (clen < 2 || clen > 4)4747+ return c0;4848+ /* Get the bits from the first octet. */4949+ c32 = cx >> clen--;5050+ for (i = 0; i < clen; ++i) {5151+ /* Trailing octets must have 10 in most significant bits. */5252+ cx = (*s8)[i] ^ 0x80;5353+ if (cx & 0xc0)5454+ return c0;5555+ c32 = (c32 << 6) | cx;5656+ }5757+ /*5858+ * Check for validity:5959+ * - The character must be in the Unicode range.6060+ * - It must not be a surrogate.6161+ * - It must be encoded using the correct number of octets.6262+ */6363+ if (c32 > 0x10ffff ||6464+ (c32 & 0xf800) == 0xd800 ||6565+ clen != (c32 >= 0x80) + (c32 >= 0x800) + (c32 >= 0x10000))6666+ return c0;6767+ *s8 += clen;6868+ return c32;6969+}7070+7171+/**7272+ * efi_puts() - Write a UTF-8 encoded string to the console7373+ * @str: UTF-8 encoded string7474+ */7575+void efi_puts(const char *str)7676+{7777+ efi_char16_t buf[128];7878+ size_t pos = 0, lim = ARRAY_SIZE(buf);7979+ const u8 *s8 = (const u8 *)str;8080+ u32 c32;8181+8282+ while (*s8) {8383+ if (*s8 == '\n')8484+ buf[pos++] = L'\r';8585+ c32 = utf8_to_utf32(&s8);8686+ if (c32 < 0x10000) {8787+ /* Characters in plane 0 use a single word. */8888+ buf[pos++] = c32;8989+ } else {9090+ /*9191+ * Characters in other planes encode into a surrogate9292+ * pair.9393+ */9494+ buf[pos++] = (0xd800 - (0x10000 >> 10)) + (c32 >> 10);9595+ buf[pos++] = 0xdc00 + (c32 & 0x3ff);9696+ }9797+ if (*s8 == '\0' || pos >= lim - 2) {9898+ buf[pos] = L'\0';9999+ efi_char16_puts(buf);100100+ pos = 0;101101+ }102102+ }103103+}104104+105105+/**106106+ * efi_printk() - Print a kernel message107107+ * @fmt: format string108108+ *109109+ * The first letter of the format string is used to determine the logging level110110+ * of the message. If the level is less then the current EFI logging level, the111111+ * message is suppressed. The message will be truncated to 255 bytes.112112+ *113113+ * Return: number of printed characters114114+ */115115+int efi_printk(const char *fmt, ...)116116+{117117+ char printf_buf[256];118118+ va_list args;119119+ int printed;120120+ int loglevel = printk_get_level(fmt);121121+122122+ switch (loglevel) {123123+ case '0' ... '9':124124+ loglevel -= '0';125125+ break;126126+ default:127127+ /*128128+ * Use loglevel -1 for cases where we just want to print to129129+ * the screen.130130+ */131131+ loglevel = -1;132132+ break;133133+ }134134+135135+ if (loglevel >= efi_loglevel)136136+ return 0;137137+138138+ if (loglevel >= 0)139139+ efi_puts("EFI stub: ");140140+141141+ fmt = printk_skip_level(fmt);142142+143143+ va_start(args, fmt);144144+ printed = vsnprintf(printf_buf, sizeof(printf_buf), fmt, args);145145+ va_end(args);146146+147147+ efi_puts(printf_buf);148148+ if (printed >= sizeof(printf_buf)) {149149+ efi_puts("[Message truncated]\n");150150+ return -1;151151+ }152152+153153+ return printed;154154+}
+10-86
drivers/firmware/efi/libstub/riscv-stub.c
···44 */5566#include <linux/efi.h>77-#include <linux/libfdt.h>8798#include <asm/efi.h>109#include <asm/sections.h>···11121213#include "efistub.h"13141414-/*1515- * RISC-V requires the kernel image to placed 2 MB aligned base for 64 bit and1616- * 4MB for 32 bit.1717- */1818-#ifdef CONFIG_64BIT1919-#define MIN_KIMG_ALIGN SZ_2M2020-#else2121-#define MIN_KIMG_ALIGN SZ_4M2222-#endif2323-2424-typedef void __noreturn (*jump_kernel_func)(unsigned long, unsigned long);2525-2626-static unsigned long hartid;2727-2828-static int get_boot_hartid_from_fdt(void)1515+unsigned long stext_offset(void)2916{3030- const void *fdt;3131- int chosen_node, len;3232- const void *prop;3333-3434- fdt = get_efi_config_table(DEVICE_TREE_GUID);3535- if (!fdt)3636- return -EINVAL;3737-3838- chosen_node = fdt_path_offset(fdt, "/chosen");3939- if (chosen_node < 0)4040- return -EINVAL;4141-4242- prop = fdt_getprop((void *)fdt, chosen_node, "boot-hartid", &len);4343- if (!prop)4444- return -EINVAL;4545-4646- if (len == sizeof(u32))4747- hartid = (unsigned long) fdt32_to_cpu(*(fdt32_t *)prop);4848- else if (len == sizeof(u64))4949- hartid = (unsigned long) fdt64_to_cpu(__get_unaligned_t(fdt64_t, prop));5050- else5151- return -EINVAL;5252-5353- return 0;5454-}5555-5656-static efi_status_t get_boot_hartid_from_efi(void)5757-{5858- efi_guid_t boot_protocol_guid = RISCV_EFI_BOOT_PROTOCOL_GUID;5959- struct riscv_efi_boot_protocol *boot_protocol;6060- efi_status_t status;6161-6262- status = efi_bs_call(locate_protocol, &boot_protocol_guid, NULL,6363- (void **)&boot_protocol);6464- if (status != EFI_SUCCESS)6565- return status;6666- return efi_call_proto(boot_protocol, get_boot_hartid, &hartid);6767-}6868-6969-efi_status_t check_platform_features(void)7070-{7171- efi_status_t status;7272- int ret;7373-7474- status = get_boot_hartid_from_efi();7575- if (status != EFI_SUCCESS) {7676- ret = get_boot_hartid_from_fdt();7777- if (ret) {7878- efi_err("Failed to get boot hartid!\n");7979- return EFI_UNSUPPORTED;8080- }8181- }8282- return EFI_SUCCESS;8383-}8484-8585-void __noreturn efi_enter_kernel(unsigned long entrypoint, unsigned long fdt,8686- unsigned long fdt_size)8787-{8888- unsigned long stext_offset = _start_kernel - _start;8989- unsigned long kernel_entry = entrypoint + stext_offset;9090- jump_kernel_func jump_kernel = (jump_kernel_func)kernel_entry;9191-9217 /*9393- * Jump to real kernel here with following constraints.9494- * 1. MMU should be disabled.9595- * 2. a0 should contain hartid9696- * 3. a1 should DT address1818+ * When built as part of the kernel, the EFI stub cannot branch to the1919+ * kernel proper via the image header, as the PE/COFF header is2020+ * strictly not part of the in-memory presentation of the image, only2121+ * of the file representation. So instead, we need to jump to the2222+ * actual entrypoint in the .text region of the image.9723 */9898- csr_write(CSR_SATP, 0);9999- jump_kernel(hartid, fdt);2424+ return _start_kernel - _start;10025}1012610227efi_status_t handle_kernel_image(unsigned long *image_addr,···48125 * lowest possible memory region as long as the address and size meets49126 * the alignment constraints.50127 */5151- preferred_addr = MIN_KIMG_ALIGN;128128+ preferred_addr = EFI_KIMG_PREFERRED_ADDRESS;52129 status = efi_relocate_kernel(image_addr, kernel_size, *image_size,5353- preferred_addr, MIN_KIMG_ALIGN, 0x0);130130+ preferred_addr, efi_get_kimg_min_align(),131131+ 0x0);5413255133 if (status != EFI_SUCCESS) {56134 efi_err("Failed to relocate kernel\n");
+98
drivers/firmware/efi/libstub/riscv.c
···11+// SPDX-License-Identifier: GPL-2.022+/*33+ * Copyright (C) 2020 Western Digital Corporation or its affiliates.44+ */55+66+#include <linux/efi.h>77+#include <linux/libfdt.h>88+99+#include <asm/efi.h>1010+#include <asm/unaligned.h>1111+1212+#include "efistub.h"1313+1414+typedef void __noreturn (*jump_kernel_func)(unsigned long, unsigned long);1515+1616+static unsigned long hartid;1717+1818+static int get_boot_hartid_from_fdt(void)1919+{2020+ const void *fdt;2121+ int chosen_node, len;2222+ const void *prop;2323+2424+ fdt = get_efi_config_table(DEVICE_TREE_GUID);2525+ if (!fdt)2626+ return -EINVAL;2727+2828+ chosen_node = fdt_path_offset(fdt, "/chosen");2929+ if (chosen_node < 0)3030+ return -EINVAL;3131+3232+ prop = fdt_getprop((void *)fdt, chosen_node, "boot-hartid", &len);3333+ if (!prop)3434+ return -EINVAL;3535+3636+ if (len == sizeof(u32))3737+ hartid = (unsigned long) fdt32_to_cpu(*(fdt32_t *)prop);3838+ else if (len == sizeof(u64))3939+ hartid = (unsigned long) fdt64_to_cpu(__get_unaligned_t(fdt64_t, prop));4040+ else4141+ return -EINVAL;4242+4343+ return 0;4444+}4545+4646+static efi_status_t get_boot_hartid_from_efi(void)4747+{4848+ efi_guid_t boot_protocol_guid = RISCV_EFI_BOOT_PROTOCOL_GUID;4949+ struct riscv_efi_boot_protocol *boot_protocol;5050+ efi_status_t status;5151+5252+ status = efi_bs_call(locate_protocol, &boot_protocol_guid, NULL,5353+ (void **)&boot_protocol);5454+ if (status != EFI_SUCCESS)5555+ return status;5656+ return efi_call_proto(boot_protocol, get_boot_hartid, &hartid);5757+}5858+5959+efi_status_t check_platform_features(void)6060+{6161+ efi_status_t status;6262+ int ret;6363+6464+ status = get_boot_hartid_from_efi();6565+ if (status != EFI_SUCCESS) {6666+ ret = get_boot_hartid_from_fdt();6767+ if (ret) {6868+ efi_err("Failed to get boot hartid!\n");6969+ return EFI_UNSUPPORTED;7070+ }7171+ }7272+ return EFI_SUCCESS;7373+}7474+7575+unsigned long __weak stext_offset(void)7676+{7777+ /*7878+ * This fallback definition is used by the EFI zboot stub, which loads7979+ * the entire image so it can branch via the image header at offset #0.8080+ */8181+ return 0;8282+}8383+8484+void __noreturn efi_enter_kernel(unsigned long entrypoint, unsigned long fdt,8585+ unsigned long fdt_size)8686+{8787+ unsigned long kernel_entry = entrypoint + stext_offset();8888+ jump_kernel_func jump_kernel = (jump_kernel_func)kernel_entry;8989+9090+ /*9191+ * Jump to real kernel here with following constraints.9292+ * 1. MMU should be disabled.9393+ * 2. a0 should contain hartid9494+ * 3. a1 should DT address9595+ */9696+ csr_write(CSR_SATP, 0);9797+ jump_kernel(hartid, fdt);9898+}
+56
drivers/firmware/efi/libstub/screen_info.c
···11+// SPDX-License-Identifier: GPL-2.022+33+#include <linux/efi.h>44+#include <asm/efi.h>55+66+#include "efistub.h"77+88+/*99+ * There are two ways of populating the core kernel's struct screen_info via the stub:1010+ * - using a configuration table, like below, which relies on the EFI init code1111+ * to locate the table and copy the contents;1212+ * - by linking directly to the core kernel's copy of the global symbol.1313+ *1414+ * The latter is preferred because it makes the EFIFB earlycon available very1515+ * early, but it only works if the EFI stub is part of the core kernel image1616+ * itself. The zboot decompressor can only use the configuration table1717+ * approach.1818+ *1919+ * In order to support both methods from the same build of the EFI stub2020+ * library, provide this dummy global definition of struct screen_info. If it2121+ * is required to satisfy a link dependency, it means we need to override the2222+ * __weak alloc and free methods with the ones below, and those will be pulled2323+ * in as well.2424+ */2525+struct screen_info screen_info;2626+2727+static efi_guid_t screen_info_guid = LINUX_EFI_SCREEN_INFO_TABLE_GUID;2828+2929+struct screen_info *alloc_screen_info(void)3030+{3131+ struct screen_info *si;3232+ efi_status_t status;3333+3434+ status = efi_bs_call(allocate_pool, EFI_ACPI_RECLAIM_MEMORY,3535+ sizeof(*si), (void **)&si);3636+3737+ if (status != EFI_SUCCESS)3838+ return NULL;3939+4040+ status = efi_bs_call(install_configuration_table,4141+ &screen_info_guid, si);4242+ if (status == EFI_SUCCESS)4343+ return si;4444+4545+ efi_bs_call(free_pool, si);4646+ return NULL;4747+}4848+4949+void free_screen_info(struct screen_info *si)5050+{5151+ if (!si)5252+ return;5353+5454+ efi_bs_call(install_configuration_table, &screen_info_guid, NULL);5555+ efi_bs_call(free_pool, si);5656+}
+92-3
drivers/firmware/efi/libstub/string.c
···1111#include <linux/types.h>1212#include <linux/string.h>13131414-#ifndef __HAVE_ARCH_STRSTR1414+#ifndef EFI_HAVE_STRLEN1515+/**1616+ * strlen - Find the length of a string1717+ * @s: The string to be sized1818+ */1919+size_t strlen(const char *s)2020+{2121+ const char *sc;2222+2323+ for (sc = s; *sc != '\0'; ++sc)2424+ /* nothing */;2525+ return sc - s;2626+}2727+#endif2828+2929+#ifndef EFI_HAVE_STRNLEN3030+/**3131+ * strnlen - Find the length of a length-limited string3232+ * @s: The string to be sized3333+ * @count: The maximum number of bytes to search3434+ */3535+size_t strnlen(const char *s, size_t count)3636+{3737+ const char *sc;3838+3939+ for (sc = s; count-- && *sc != '\0'; ++sc)4040+ /* nothing */;4141+ return sc - s;4242+}4343+#endif4444+1545/**1646 * strstr - Find the first substring in a %NUL terminated string1747 * @s1: The string to be searched···6333 }6434 return NULL;6535}3636+3737+#ifndef EFI_HAVE_STRCMP3838+/**3939+ * strcmp - Compare two strings4040+ * @cs: One string4141+ * @ct: Another string4242+ */4343+int strcmp(const char *cs, const char *ct)4444+{4545+ unsigned char c1, c2;4646+4747+ while (1) {4848+ c1 = *cs++;4949+ c2 = *ct++;5050+ if (c1 != c2)5151+ return c1 < c2 ? -1 : 1;5252+ if (!c1)5353+ break;5454+ }5555+ return 0;5656+}6657#endif67586868-#ifndef __HAVE_ARCH_STRNCMP6959/**7060 * strncmp - Compare two length-limited strings7161 * @cs: One string···10757 }10858 return 0;10959}110110-#endif1116011261/* Works only for digits and letters, but small and fast */11362#define TOLOWER(x) ((x) | 0x20)···162113163114 return simple_strtoull(cp, endp, base);164115}116116+117117+#ifdef CONFIG_EFI_PARAMS_FROM_FDT118118+#ifndef EFI_HAVE_STRRCHR119119+/**120120+ * strrchr - Find the last occurrence of a character in a string121121+ * @s: The string to be searched122122+ * @c: The character to search for123123+ */124124+char *strrchr(const char *s, int c)125125+{126126+ const char *last = NULL;127127+ do {128128+ if (*s == (char)c)129129+ last = s;130130+ } while (*s++);131131+ return (char *)last;132132+}133133+#endif134134+#ifndef EFI_HAVE_MEMCHR135135+/**136136+ * memchr - Find a character in an area of memory.137137+ * @s: The memory area138138+ * @c: The byte to search for139139+ * @n: The size of the area.140140+ *141141+ * returns the address of the first occurrence of @c, or %NULL142142+ * if @c is not found143143+ */144144+void *memchr(const void *s, int c, size_t n)145145+{146146+ const unsigned char *p = s;147147+ while (n-- != 0) {148148+ if ((unsigned char)c == *p++) {149149+ return (void *)(p - 1);150150+ }151151+ }152152+ return NULL;153153+}154154+#endif155155+#endif