From 0d60ffeec53cc378cc282d51e870275c642532c6 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Wed, 12 Oct 2022 09:53:40 +0200 Subject: efi: libstub: Deduplicate ftrace command line argument filtering No need for the same pattern to be used four times for each architecture individually if we can just apply it once later. Signed-off-by: Ard Biesheuvel --- drivers/firmware/efi/libstub/Makefile | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) (limited to 'drivers/firmware/efi/libstub/Makefile') diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile index b1601aad7e1a..26b0a421a286 100644 --- a/drivers/firmware/efi/libstub/Makefile +++ b/drivers/firmware/efi/libstub/Makefile @@ -5,6 +5,10 @@ # things like ftrace and stack-protector are likely to cause trouble if left # enabled, even if doing so doesn't break the build. # + +# non-x86 reuses KBUILD_CFLAGS, x86 does not +cflags-y := $(KBUILD_CFLAGS) + cflags-$(CONFIG_X86_32) := -march=i386 cflags-$(CONFIG_X86_64) := -mcmodel=small cflags-$(CONFIG_X86) += -m$(BITS) -D__KERNEL__ \ @@ -18,20 +22,17 @@ cflags-$(CONFIG_X86) += -m$(BITS) -D__KERNEL__ \ # arm64 uses the full KBUILD_CFLAGS so it's necessary to explicitly # disable the stackleak plugin -cflags-$(CONFIG_ARM64) := $(subst $(CC_FLAGS_FTRACE),,$(KBUILD_CFLAGS)) \ - -fpie $(DISABLE_STACKLEAK_PLUGIN) \ +cflags-$(CONFIG_ARM64) += -fpie $(DISABLE_STACKLEAK_PLUGIN) \ $(call cc-option,-mbranch-protection=none) -cflags-$(CONFIG_ARM) := $(subst $(CC_FLAGS_FTRACE),,$(KBUILD_CFLAGS)) \ - -fno-builtin -fpic \ +cflags-$(CONFIG_ARM) += -fno-builtin -fpic \ $(call cc-option,-mno-single-pic-base) -cflags-$(CONFIG_RISCV) := $(subst $(CC_FLAGS_FTRACE),,$(KBUILD_CFLAGS)) \ - -fpic -cflags-$(CONFIG_LOONGARCH) := $(subst $(CC_FLAGS_FTRACE),,$(KBUILD_CFLAGS)) \ - -fpie +cflags-$(CONFIG_RISCV) += -fpic +cflags-$(CONFIG_LOONGARCH) += -fpie cflags-$(CONFIG_EFI_PARAMS_FROM_FDT) += -I$(srctree)/scripts/dtc/libfdt -KBUILD_CFLAGS := $(cflags-y) -Os -DDISABLE_BRANCH_PROFILING \ +KBUILD_CFLAGS := $(subst $(CC_FLAGS_FTRACE),,$(cflags-y)) \ + -Os -DDISABLE_BRANCH_PROFILING \ -include $(srctree)/include/linux/hidden.h \ -D__NO_FORTIFY \ -ffreestanding \ -- cgit v1.2.3 From 4ef806096bdbbe9e77c29c17c3ed636d00d6d6f3 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Mon, 17 Oct 2022 17:14:41 +0200 Subject: arm64: efi: Move efi-entry.S into the libstub source directory We will be sharing efi-entry.S with the zboot decompressor build, which does not link against vmlinux directly. So move it into the libstub source directory so we can include in the libstub static library. Signed-off-by: Ard Biesheuvel Acked-by: Catalin Marinas --- arch/arm64/kernel/Makefile | 9 +---- arch/arm64/kernel/efi-entry.S | 61 ------------------------------ drivers/firmware/efi/libstub/Makefile | 4 +- drivers/firmware/efi/libstub/arm64-entry.S | 57 ++++++++++++++++++++++++++++ 4 files changed, 60 insertions(+), 71 deletions(-) delete mode 100644 arch/arm64/kernel/efi-entry.S create mode 100644 drivers/firmware/efi/libstub/arm64-entry.S (limited to 'drivers/firmware/efi/libstub/Makefile') diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile index 2f361a883d8c..2a3b0e4950f2 100644 --- a/arch/arm64/kernel/Makefile +++ b/arch/arm64/kernel/Makefile @@ -36,12 +36,6 @@ obj-y := debug-monitors.o entry.o irq.o fpsimd.o \ syscall.o proton-pack.o idreg-override.o idle.o \ patching.o -targets += efi-entry.o - -OBJCOPYFLAGS := --prefix-symbols=__efistub_ -$(obj)/%.stub.o: $(obj)/%.o FORCE - $(call if_changed,objcopy) - obj-$(CONFIG_COMPAT) += sys32.o signal32.o \ sys_compat.o obj-$(CONFIG_COMPAT) += sigreturn32.o @@ -57,8 +51,7 @@ obj-$(CONFIG_CPU_PM) += sleep.o suspend.o obj-$(CONFIG_CPU_IDLE) += cpuidle.o obj-$(CONFIG_JUMP_LABEL) += jump_label.o obj-$(CONFIG_KGDB) += kgdb.o -obj-$(CONFIG_EFI) += efi.o efi-entry.stub.o \ - efi-rt-wrapper.o +obj-$(CONFIG_EFI) += efi.o efi-rt-wrapper.o obj-$(CONFIG_PCI) += pci.o obj-$(CONFIG_ARMV8_DEPRECATED) += armv8_deprecated.o obj-$(CONFIG_ACPI) += acpi.o diff --git a/arch/arm64/kernel/efi-entry.S b/arch/arm64/kernel/efi-entry.S deleted file mode 100644 index 8bce13356e29..000000000000 --- a/arch/arm64/kernel/efi-entry.S +++ /dev/null @@ -1,61 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * EFI entry point. - * - * Copyright (C) 2013, 2014 Red Hat, Inc. - * Author: Mark Salter - */ -#include -#include - -#include - - __INIT - -SYM_CODE_START(efi_enter_kernel) - /* - * efi_pe_entry() will have copied the kernel image if necessary and we - * end up here with device tree address in x1 and the kernel entry - * point stored in x0. Save those values in registers which are - * callee preserved. - */ - ldr w2, =primary_entry_offset - add x19, x0, x2 // relocated Image entrypoint - - mov x0, x1 // DTB address - mov x1, xzr - mov x2, xzr - mov x3, xzr - - /* - * Clean the remainder of this routine to the PoC - * so that we can safely disable the MMU and caches. - */ - adr x4, 1f - dc civac, x4 - dsb sy - - /* Turn off Dcache and MMU */ - mrs x4, CurrentEL - cmp x4, #CurrentEL_EL2 - mrs x4, sctlr_el1 - b.ne 0f - mrs x4, sctlr_el2 -0: bic x4, x4, #SCTLR_ELx_M - bic x4, x4, #SCTLR_ELx_C - b.eq 1f - b 2f - - .balign 32 -1: pre_disable_mmu_workaround - msr sctlr_el2, x4 - isb - br x19 // jump to kernel entrypoint - -2: pre_disable_mmu_workaround - msr sctlr_el1, x4 - isb - br x19 // jump to kernel entrypoint - - .org 1b + 32 -SYM_CODE_END(efi_enter_kernel) diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile index 26b0a421a286..01a0be468a66 100644 --- a/drivers/firmware/efi/libstub/Makefile +++ b/drivers/firmware/efi/libstub/Makefile @@ -83,7 +83,7 @@ $(obj)/lib-%.o: $(srctree)/lib/%.c FORCE lib-$(CONFIG_EFI_GENERIC_STUB) += efi-stub.o string.o intrinsics.o systable.o lib-$(CONFIG_ARM) += arm32-stub.o -lib-$(CONFIG_ARM64) += arm64-stub.o +lib-$(CONFIG_ARM64) += arm64-stub.o arm64-entry.o lib-$(CONFIG_X86) += x86-stub.o lib-$(CONFIG_RISCV) += riscv-stub.o lib-$(CONFIG_LOONGARCH) += loongarch-stub.o @@ -137,7 +137,7 @@ STUBCOPY_RELOC-$(CONFIG_ARM) := R_ARM_ABS # STUBCOPY_FLAGS-$(CONFIG_ARM64) += --prefix-alloc-sections=.init \ --prefix-symbols=__efistub_ -STUBCOPY_RELOC-$(CONFIG_ARM64) := R_AARCH64_ABS +STUBCOPY_RELOC-$(CONFIG_ARM64) := R_AARCH64_ABS64 # For RISC-V, we don't need anything special other than arm64. Keep all the # symbols in .init section and make sure that no absolute symbols references diff --git a/drivers/firmware/efi/libstub/arm64-entry.S b/drivers/firmware/efi/libstub/arm64-entry.S new file mode 100644 index 000000000000..87082b222a87 --- /dev/null +++ b/drivers/firmware/efi/libstub/arm64-entry.S @@ -0,0 +1,57 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * EFI entry point. + * + * Copyright (C) 2013, 2014 Red Hat, Inc. + * Author: Mark Salter + */ +#include +#include + +SYM_CODE_START(efi_enter_kernel) + /* + * efi_pe_entry() will have copied the kernel image if necessary and we + * end up here with device tree address in x1 and the kernel entry + * point stored in x0. Save those values in registers which are + * callee preserved. + */ + ldr w2, =primary_entry_offset + add x19, x0, x2 // relocated Image entrypoint + + mov x0, x1 // DTB address + mov x1, xzr + mov x2, xzr + mov x3, xzr + + /* + * Clean the remainder of this routine to the PoC + * so that we can safely disable the MMU and caches. + */ + adr x4, 1f + dc civac, x4 + dsb sy + + /* Turn off Dcache and MMU */ + mrs x4, CurrentEL + cmp x4, #CurrentEL_EL2 + mrs x4, sctlr_el1 + b.ne 0f + mrs x4, sctlr_el2 +0: bic x4, x4, #SCTLR_ELx_M + bic x4, x4, #SCTLR_ELx_C + b.eq 1f + b 2f + + .balign 32 +1: pre_disable_mmu_workaround + msr sctlr_el2, x4 + isb + br x19 // jump to kernel entrypoint + +2: pre_disable_mmu_workaround + msr sctlr_el1, x4 + isb + br x19 // jump to kernel entrypoint + + .org 1b + 32 +SYM_CODE_END(efi_enter_kernel) -- cgit v1.2.3 From 2e6fa86f2d484ff9a0047e20a48c1400314a5bb6 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Tue, 11 Oct 2022 15:27:45 +0200 Subject: efi: libstub: Enable efi_printk() in zboot decompressor Split the efi_printk() routine into its own source file, and provide local implementations of strlen() and strnlen() so that the standalone zboot app can efi_err and efi_info etc. Signed-off-by: Ard Biesheuvel --- arch/arm64/kernel/image-vars.h | 2 - arch/loongarch/kernel/image-vars.h | 2 - arch/riscv/kernel/image-vars.h | 2 - drivers/firmware/efi/libstub/Makefile | 5 +- drivers/firmware/efi/libstub/efi-stub-helper.c | 143 ----------------------- drivers/firmware/efi/libstub/printk.c | 154 +++++++++++++++++++++++++ drivers/firmware/efi/libstub/string.c | 33 +++++- drivers/firmware/efi/libstub/zboot.c | 30 ++--- 8 files changed, 198 insertions(+), 173 deletions(-) create mode 100644 drivers/firmware/efi/libstub/printk.c (limited to 'drivers/firmware/efi/libstub/Makefile') diff --git a/arch/arm64/kernel/image-vars.h b/arch/arm64/kernel/image-vars.h index f7c8cdf0c302..ace584e0b065 100644 --- a/arch/arm64/kernel/image-vars.h +++ b/arch/arm64/kernel/image-vars.h @@ -22,8 +22,6 @@ PROVIDE(__efistub_primary_entry_offset = primary_entry - _text); * position independent manner */ PROVIDE(__efistub_memchr = __pi_memchr); -PROVIDE(__efistub_strlen = __pi_strlen); -PROVIDE(__efistub_strnlen = __pi_strnlen); PROVIDE(__efistub_strcmp = __pi_strcmp); PROVIDE(__efistub_strrchr = __pi_strrchr); PROVIDE(__efistub_dcache_clean_poc = __pi_dcache_clean_poc); diff --git a/arch/loongarch/kernel/image-vars.h b/arch/loongarch/kernel/image-vars.h index 5b6c7f079942..28bc632ec296 100644 --- a/arch/loongarch/kernel/image-vars.h +++ b/arch/loongarch/kernel/image-vars.h @@ -10,10 +10,8 @@ __efistub_memchr = memchr; __efistub_strcat = strcat; __efistub_strcmp = strcmp; -__efistub_strlen = strlen; __efistub_strncat = strncat; __efistub_strnstr = strnstr; -__efistub_strnlen = strnlen; __efistub_strrchr = strrchr; __efistub_kernel_entry = kernel_entry; __efistub_kernel_asize = kernel_asize; diff --git a/arch/riscv/kernel/image-vars.h b/arch/riscv/kernel/image-vars.h index 9229cfe0754d..4913abd6dd10 100644 --- a/arch/riscv/kernel/image-vars.h +++ b/arch/riscv/kernel/image-vars.h @@ -24,8 +24,6 @@ * position independent manner */ __efistub_memchr = memchr; -__efistub_strlen = strlen; -__efistub_strnlen = strnlen; __efistub_strcmp = strcmp; __efistub_strrchr = strrchr; diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile index 01a0be468a66..5b0ae755180e 100644 --- a/drivers/firmware/efi/libstub/Makefile +++ b/drivers/firmware/efi/libstub/Makefile @@ -24,7 +24,8 @@ cflags-$(CONFIG_X86) += -m$(BITS) -D__KERNEL__ \ # disable the stackleak plugin cflags-$(CONFIG_ARM64) += -fpie $(DISABLE_STACKLEAK_PLUGIN) \ $(call cc-option,-mbranch-protection=none) -cflags-$(CONFIG_ARM) += -fno-builtin -fpic \ +cflags-$(CONFIG_ARM) += -DEFI_HAVE_STRLEN -DEFI_HAVE_STRNLEN \ + -fno-builtin -fpic \ $(call cc-option,-mno-single-pic-base) cflags-$(CONFIG_RISCV) += -fpic cflags-$(CONFIG_LOONGARCH) += -fpie @@ -68,7 +69,7 @@ KCOV_INSTRUMENT := n 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 vsprintf.o + alignedmem.o relocate.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/efi-stub-helper.c b/drivers/firmware/efi/libstub/efi-stub-helper.c index 0c493521b25b..2184f3f153ef 100644 --- a/drivers/firmware/efi/libstub/efi-stub-helper.c +++ b/drivers/firmware/efi/libstub/efi-stub-helper.c @@ -9,10 +9,8 @@ #include -#include #include #include -#include /* For CONSOLE_LOGLEVEL_* */ #include #include @@ -20,7 +18,6 @@ bool efi_nochunk; bool efi_nokaslr = !IS_ENABLED(CONFIG_RANDOMIZE_BASE); -int efi_loglevel = CONSOLE_LOGLEVEL_DEFAULT; bool efi_novamap; static bool efi_noinitrd; @@ -32,146 +29,6 @@ bool __pure __efi_soft_reserve_enabled(void) return !efi_nosoftreserve; } -/** - * efi_char16_puts() - Write a UCS-2 encoded string to the console - * @str: UCS-2 encoded string - */ -void efi_char16_puts(efi_char16_t *str) -{ - efi_call_proto(efi_table_attr(efi_system_table, con_out), - output_string, str); -} - -static -u32 utf8_to_utf32(const u8 **s8) -{ - u32 c32; - u8 c0, cx; - size_t clen, i; - - c0 = cx = *(*s8)++; - /* - * The position of the most-significant 0 bit gives us the length of - * a multi-octet encoding. - */ - for (clen = 0; cx & 0x80; ++clen) - cx <<= 1; - /* - * If the 0 bit is in position 8, this is a valid single-octet - * encoding. If the 0 bit is in position 7 or positions 1-3, the - * encoding is invalid. - * In either case, we just return the first octet. - */ - if (clen < 2 || clen > 4) - return c0; - /* Get the bits from the first octet. */ - c32 = cx >> clen--; - for (i = 0; i < clen; ++i) { - /* Trailing octets must have 10 in most significant bits. */ - cx = (*s8)[i] ^ 0x80; - if (cx & 0xc0) - return c0; - c32 = (c32 << 6) | cx; - } - /* - * Check for validity: - * - The character must be in the Unicode range. - * - It must not be a surrogate. - * - It must be encoded using the correct number of octets. - */ - if (c32 > 0x10ffff || - (c32 & 0xf800) == 0xd800 || - clen != (c32 >= 0x80) + (c32 >= 0x800) + (c32 >= 0x10000)) - return c0; - *s8 += clen; - return c32; -} - -/** - * efi_puts() - Write a UTF-8 encoded string to the console - * @str: UTF-8 encoded string - */ -void efi_puts(const char *str) -{ - efi_char16_t buf[128]; - size_t pos = 0, lim = ARRAY_SIZE(buf); - const u8 *s8 = (const u8 *)str; - u32 c32; - - while (*s8) { - if (*s8 == '\n') - buf[pos++] = L'\r'; - c32 = utf8_to_utf32(&s8); - if (c32 < 0x10000) { - /* Characters in plane 0 use a single word. */ - buf[pos++] = c32; - } else { - /* - * Characters in other planes encode into a surrogate - * pair. - */ - buf[pos++] = (0xd800 - (0x10000 >> 10)) + (c32 >> 10); - buf[pos++] = 0xdc00 + (c32 & 0x3ff); - } - if (*s8 == '\0' || pos >= lim - 2) { - buf[pos] = L'\0'; - efi_char16_puts(buf); - pos = 0; - } - } -} - -/** - * efi_printk() - Print a kernel message - * @fmt: format string - * - * The first letter of the format string is used to determine the logging level - * of the message. If the level is less then the current EFI logging level, the - * message is suppressed. The message will be truncated to 255 bytes. - * - * Return: number of printed characters - */ -int efi_printk(const char *fmt, ...) -{ - char printf_buf[256]; - va_list args; - int printed; - int loglevel = printk_get_level(fmt); - - switch (loglevel) { - case '0' ... '9': - loglevel -= '0'; - break; - default: - /* - * Use loglevel -1 for cases where we just want to print to - * the screen. - */ - loglevel = -1; - break; - } - - if (loglevel >= efi_loglevel) - return 0; - - if (loglevel >= 0) - efi_puts("EFI stub: "); - - fmt = printk_skip_level(fmt); - - va_start(args, fmt); - printed = vsnprintf(printf_buf, sizeof(printf_buf), fmt, args); - va_end(args); - - efi_puts(printf_buf); - if (printed >= sizeof(printf_buf)) { - efi_puts("[Message truncated]\n"); - return -1; - } - - return printed; -} - /** * efi_parse_options() - Parse EFI command line options * @cmdline: kernel command line diff --git a/drivers/firmware/efi/libstub/printk.c b/drivers/firmware/efi/libstub/printk.c new file mode 100644 index 000000000000..3a67a2cea7bd --- /dev/null +++ b/drivers/firmware/efi/libstub/printk.c @@ -0,0 +1,154 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include + +#include +#include +#include +#include /* For CONSOLE_LOGLEVEL_* */ +#include +#include + +#include "efistub.h" + +int efi_loglevel = CONSOLE_LOGLEVEL_DEFAULT; + +/** + * efi_char16_puts() - Write a UCS-2 encoded string to the console + * @str: UCS-2 encoded string + */ +void efi_char16_puts(efi_char16_t *str) +{ + efi_call_proto(efi_table_attr(efi_system_table, con_out), + output_string, str); +} + +static +u32 utf8_to_utf32(const u8 **s8) +{ + u32 c32; + u8 c0, cx; + size_t clen, i; + + c0 = cx = *(*s8)++; + /* + * The position of the most-significant 0 bit gives us the length of + * a multi-octet encoding. + */ + for (clen = 0; cx & 0x80; ++clen) + cx <<= 1; + /* + * If the 0 bit is in position 8, this is a valid single-octet + * encoding. If the 0 bit is in position 7 or positions 1-3, the + * encoding is invalid. + * In either case, we just return the first octet. + */ + if (clen < 2 || clen > 4) + return c0; + /* Get the bits from the first octet. */ + c32 = cx >> clen--; + for (i = 0; i < clen; ++i) { + /* Trailing octets must have 10 in most significant bits. */ + cx = (*s8)[i] ^ 0x80; + if (cx & 0xc0) + return c0; + c32 = (c32 << 6) | cx; + } + /* + * Check for validity: + * - The character must be in the Unicode range. + * - It must not be a surrogate. + * - It must be encoded using the correct number of octets. + */ + if (c32 > 0x10ffff || + (c32 & 0xf800) == 0xd800 || + clen != (c32 >= 0x80) + (c32 >= 0x800) + (c32 >= 0x10000)) + return c0; + *s8 += clen; + return c32; +} + +/** + * efi_puts() - Write a UTF-8 encoded string to the console + * @str: UTF-8 encoded string + */ +void efi_puts(const char *str) +{ + efi_char16_t buf[128]; + size_t pos = 0, lim = ARRAY_SIZE(buf); + const u8 *s8 = (const u8 *)str; + u32 c32; + + while (*s8) { + if (*s8 == '\n') + buf[pos++] = L'\r'; + c32 = utf8_to_utf32(&s8); + if (c32 < 0x10000) { + /* Characters in plane 0 use a single word. */ + buf[pos++] = c32; + } else { + /* + * Characters in other planes encode into a surrogate + * pair. + */ + buf[pos++] = (0xd800 - (0x10000 >> 10)) + (c32 >> 10); + buf[pos++] = 0xdc00 + (c32 & 0x3ff); + } + if (*s8 == '\0' || pos >= lim - 2) { + buf[pos] = L'\0'; + efi_char16_puts(buf); + pos = 0; + } + } +} + +/** + * efi_printk() - Print a kernel message + * @fmt: format string + * + * The first letter of the format string is used to determine the logging level + * of the message. If the level is less then the current EFI logging level, the + * message is suppressed. The message will be truncated to 255 bytes. + * + * Return: number of printed characters + */ +int efi_printk(const char *fmt, ...) +{ + char printf_buf[256]; + va_list args; + int printed; + int loglevel = printk_get_level(fmt); + + switch (loglevel) { + case '0' ... '9': + loglevel -= '0'; + break; + default: + /* + * Use loglevel -1 for cases where we just want to print to + * the screen. + */ + loglevel = -1; + break; + } + + if (loglevel >= efi_loglevel) + return 0; + + if (loglevel >= 0) + efi_puts("EFI stub: "); + + fmt = printk_skip_level(fmt); + + va_start(args, fmt); + printed = vsnprintf(printf_buf, sizeof(printf_buf), fmt, args); + va_end(args); + + efi_puts(printf_buf); + if (printed >= sizeof(printf_buf)) { + efi_puts("[Message truncated]\n"); + return -1; + } + + return printed; +} diff --git a/drivers/firmware/efi/libstub/string.c b/drivers/firmware/efi/libstub/string.c index 9f5810d86646..5a1519d435bf 100644 --- a/drivers/firmware/efi/libstub/string.c +++ b/drivers/firmware/efi/libstub/string.c @@ -11,7 +11,37 @@ #include #include -#ifndef __HAVE_ARCH_STRSTR +#ifndef EFI_HAVE_STRLEN +/** + * strlen - Find the length of a string + * @s: The string to be sized + */ +size_t strlen(const char *s) +{ + const char *sc; + + for (sc = s; *sc != '\0'; ++sc) + /* nothing */; + return sc - s; +} +#endif + +#ifndef EFI_HAVE_STRNLEN +/** + * strnlen - Find the length of a length-limited string + * @s: The string to be sized + * @count: The maximum number of bytes to search + */ +size_t strnlen(const char *s, size_t count) +{ + const char *sc; + + for (sc = s; count-- && *sc != '\0'; ++sc) + /* nothing */; + return sc - s; +} +#endif + /** * strstr - Find the first substring in a %NUL terminated string * @s1: The string to be searched @@ -33,7 +63,6 @@ char *strstr(const char *s1, const char *s2) } return NULL; } -#endif /** * strncmp - Compare two length-limited strings diff --git a/drivers/firmware/efi/libstub/zboot.c b/drivers/firmware/efi/libstub/zboot.c index 38173ec29cd5..5f41a5b17d6e 100644 --- a/drivers/firmware/efi/libstub/zboot.c +++ b/drivers/firmware/efi/libstub/zboot.c @@ -32,19 +32,9 @@ static unsigned long free_mem_ptr, free_mem_end_ptr; extern char efi_zboot_header[]; extern char _gzdata_start[], _gzdata_end[]; -static void log(efi_char16_t str[]) -{ - efi_call_proto(efi_table_attr(efi_system_table, con_out), - output_string, L"EFI decompressor: "); - efi_call_proto(efi_table_attr(efi_system_table, con_out), - output_string, str); - efi_call_proto(efi_table_attr(efi_system_table, con_out), - output_string, L"\n"); -} - static void error(char *x) { - log(L"error() called from decompressor library\n"); + efi_err("EFI decompressor: %s\n", x); } static efi_status_t __efiapi @@ -91,7 +81,7 @@ load_file(efi_load_file_protocol_t *this, efi_device_path_protocol_t *rem, ret = __decompress(_gzdata_start, compressed_size, NULL, NULL, buffer, size, NULL, error); if (ret < 0) { - log(L"Decompression failed"); + error("Decompression failed"); return EFI_DEVICE_ERROR; } } else { @@ -180,7 +170,7 @@ efi_zboot_entry(efi_handle_t handle, efi_system_table_t *systab) status = efi_bs_call(handle_protocol, handle, &LOADED_IMAGE_PROTOCOL_GUID, (void **)&parent); if (status != EFI_SUCCESS) { - log(L"Failed to locate parent's loaded image protocol"); + error("Failed to locate parent's loaded image protocol"); return status; } @@ -207,7 +197,7 @@ efi_zboot_entry(efi_handle_t handle, efi_system_table_t *systab) sizeof(struct efi_vendor_dev_path), (void **)&dp_alloc); if (status != EFI_SUCCESS) { - log(L"Failed to allocate device path pool memory"); + error("Failed to allocate device path pool memory"); return status; } @@ -236,21 +226,21 @@ efi_zboot_entry(efi_handle_t handle, efi_system_table_t *systab) &EFI_LOAD_FILE2_PROTOCOL_GUID, &zboot_load_file2, NULL); if (status != EFI_SUCCESS) { - log(L"Failed to install LoadFile2 protocol and device path"); + error("Failed to install LoadFile2 protocol and device path"); goto free_dpalloc; } status = efi_bs_call(load_image, false, handle, li_dp, NULL, 0, &child_handle); if (status != EFI_SUCCESS) { - log(L"Failed to load image"); + error("Failed to load image"); goto uninstall_lf2; } status = efi_bs_call(handle_protocol, child_handle, &LOADED_IMAGE_PROTOCOL_GUID, (void **)&child); if (status != EFI_SUCCESS) { - log(L"Failed to locate child's loaded image protocol"); + error("Failed to locate child's loaded image protocol"); goto unload_image; } @@ -261,9 +251,9 @@ efi_zboot_entry(efi_handle_t handle, efi_system_table_t *systab) status = efi_bs_call(start_image, child_handle, &exit_data_size, &exit_data); if (status != EFI_SUCCESS) { - log(L"StartImage() returned with error"); + error("StartImage() returned with error:"); if (exit_data_size > 0) - log(exit_data); + efi_err("%ls\n", exit_data); // If StartImage() returns EFI_SECURITY_VIOLATION, the image is // not unloaded so we need to do it by hand. @@ -286,7 +276,7 @@ free_dpalloc: // Free ExitData in case Exit() returned with a failure code, // but return the original status code. - log(L"Exit() returned with failure code"); + error("Exit() returned with failure code"); if (exit_data != NULL) efi_bs_call(free_pool, exit_data); return status; -- cgit v1.2.3 From 732ea9db9d8a6a0444d18ed810cccb2428d8766b Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Tue, 11 Oct 2022 17:10:39 +0200 Subject: efi: libstub: Move screen_info handling to common code Currently, arm64, RISC-V and LoongArch rely on the fact that struct screen_info can be accessed directly, due to the fact that the EFI stub and the core kernel are part of the same image. This will change after a future patch, so let's ensure that the screen_info handling is able to deal with this, by adopting the arm32 approach of passing it as a configuration table. While at it, switch to ACPI reclaim memory to hold the screen_info data, which is more appropriate for this kind of allocation. Signed-off-by: Ard Biesheuvel --- arch/arm/include/asm/efi.h | 3 -- arch/arm/kernel/efi.c | 31 +++-------------- arch/arm64/include/asm/efi.h | 6 ---- arch/loongarch/include/asm/efi.h | 9 ----- arch/loongarch/kernel/efi.c | 24 +++++++++++-- arch/riscv/include/asm/efi.h | 6 ---- drivers/firmware/efi/efi-init.c | 21 +++++++++-- drivers/firmware/efi/efi.c | 5 +++ drivers/firmware/efi/libstub/Makefile | 3 +- drivers/firmware/efi/libstub/arm32-stub.c | 37 -------------------- drivers/firmware/efi/libstub/efi-stub.c | 9 +++++ drivers/firmware/efi/libstub/efistub.h | 3 ++ drivers/firmware/efi/libstub/screen_info.c | 56 ++++++++++++++++++++++++++++++ include/linux/efi.h | 2 +- 14 files changed, 121 insertions(+), 94 deletions(-) create mode 100644 drivers/firmware/efi/libstub/screen_info.c (limited to 'drivers/firmware/efi/libstub/Makefile') diff --git a/arch/arm/include/asm/efi.h b/arch/arm/include/asm/efi.h index 4bdd930167c0..b95241b1ca65 100644 --- a/arch/arm/include/asm/efi.h +++ b/arch/arm/include/asm/efi.h @@ -43,9 +43,6 @@ void efi_virtmap_unload(void); /* arch specific definitions used by the stub code */ -struct screen_info *alloc_screen_info(void); -void free_screen_info(struct screen_info *si); - /* * A reasonable upper bound for the uncompressed kernel size is 32 MBytes, * so we will reserve that amount of memory. We have no easy way to tell what diff --git a/arch/arm/kernel/efi.c b/arch/arm/kernel/efi.c index e50ad7eefc02..882104f43b3b 100644 --- a/arch/arm/kernel/efi.c +++ b/arch/arm/kernel/efi.c @@ -75,38 +75,13 @@ int __init efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md) return 0; } -static unsigned long __initdata screen_info_table = EFI_INVALID_TABLE_ADDR; static unsigned long __initdata cpu_state_table = EFI_INVALID_TABLE_ADDR; const efi_config_table_type_t efi_arch_tables[] __initconst = { - {LINUX_EFI_ARM_SCREEN_INFO_TABLE_GUID, &screen_info_table}, {LINUX_EFI_ARM_CPU_STATE_TABLE_GUID, &cpu_state_table}, {} }; -static void __init load_screen_info_table(void) -{ - struct screen_info *si; - - if (screen_info_table != EFI_INVALID_TABLE_ADDR) { - si = early_memremap_ro(screen_info_table, sizeof(*si)); - if (!si) { - pr_err("Could not map screen_info config table\n"); - return; - } - screen_info = *si; - early_memunmap(si, sizeof(*si)); - - /* dummycon on ARM needs non-zero values for columns/lines */ - screen_info.orig_video_cols = 80; - screen_info.orig_video_lines = 25; - - if (memblock_is_map_memory(screen_info.lfb_base)) - memblock_mark_nomap(screen_info.lfb_base, - screen_info.lfb_size); - } -} - static void __init load_cpu_state_table(void) { if (cpu_state_table != EFI_INVALID_TABLE_ADDR) { @@ -145,7 +120,11 @@ void __init arm_efi_init(void) { efi_init(); - load_screen_info_table(); + if (screen_info.orig_video_isVGA == VIDEO_TYPE_EFI) { + /* dummycon on ARM needs non-zero values for columns/lines */ + screen_info.orig_video_cols = 80; + screen_info.orig_video_lines = 25; + } /* ARM does not permit early mappings to persist across paging_init() */ efi_memmap_unmap(); diff --git a/arch/arm64/include/asm/efi.h b/arch/arm64/include/asm/efi.h index d6cf535d8352..8604473a85b8 100644 --- a/arch/arm64/include/asm/efi.h +++ b/arch/arm64/include/asm/efi.h @@ -84,12 +84,6 @@ static inline unsigned long efi_get_max_initrd_addr(unsigned long image_addr) return (image_addr & ~(SZ_1G - 1UL)) + (1UL << (VA_BITS_MIN - 1)); } -#define alloc_screen_info(x...) &screen_info - -static inline void free_screen_info(struct screen_info *si) -{ -} - #define EFI_ALLOC_ALIGN SZ_64K /* diff --git a/arch/loongarch/include/asm/efi.h b/arch/loongarch/include/asm/efi.h index 174567b00ddb..60d6a170c18d 100644 --- a/arch/loongarch/include/asm/efi.h +++ b/arch/loongarch/include/asm/efi.h @@ -19,15 +19,6 @@ void efifb_setup_from_dmi(struct screen_info *si, const char *opt); #define EFI_ALLOC_ALIGN SZ_64K #define EFI_RT_VIRTUAL_OFFSET CSR_DMW0_BASE -static inline struct screen_info *alloc_screen_info(void) -{ - return &screen_info; -} - -static inline void free_screen_info(struct screen_info *si) -{ -} - static inline unsigned long efi_get_max_initrd_addr(unsigned long image_addr) { return ULONG_MAX; diff --git a/arch/loongarch/kernel/efi.c b/arch/loongarch/kernel/efi.c index a31329971133..d75ce73e8ff8 100644 --- a/arch/loongarch/kernel/efi.c +++ b/arch/loongarch/kernel/efi.c @@ -52,6 +52,27 @@ void __init efi_runtime_init(void) set_bit(EFI_RUNTIME_SERVICES, &efi.flags); } +unsigned long __initdata screen_info_table = EFI_INVALID_TABLE_ADDR; + +static void __init init_screen_info(void) +{ + struct screen_info *si; + + if (screen_info_table == EFI_INVALID_TABLE_ADDR) + return; + + si = early_memremap(screen_info_table, sizeof(*si)); + if (!si) { + pr_err("Could not map screen_info config table\n"); + return; + } + screen_info = *si; + memset(si, 0, sizeof(*si)); + early_memunmap(si, sizeof(*si)); + + memblock_reserve(screen_info.lfb_base, screen_info.lfb_size); +} + void __init efi_init(void) { int size; @@ -80,8 +101,7 @@ void __init efi_init(void) set_bit(EFI_CONFIG_TABLES, &efi.flags); - if (screen_info.orig_video_isVGA == VIDEO_TYPE_EFI) - memblock_reserve(screen_info.lfb_base, screen_info.lfb_size); + init_screen_info(); if (boot_memmap == EFI_INVALID_TABLE_ADDR) return; diff --git a/arch/riscv/include/asm/efi.h b/arch/riscv/include/asm/efi.h index f74879a8f1ea..d0570936cb8c 100644 --- a/arch/riscv/include/asm/efi.h +++ b/arch/riscv/include/asm/efi.h @@ -31,12 +31,6 @@ static inline unsigned long efi_get_max_initrd_addr(unsigned long image_addr) return ULONG_MAX; } -#define alloc_screen_info(x...) (&screen_info) - -static inline void free_screen_info(struct screen_info *si) -{ -} - void efi_virtmap_load(void); void efi_virtmap_unload(void); diff --git a/drivers/firmware/efi/efi-init.c b/drivers/firmware/efi/efi-init.c index 2fd770b499a3..1639159493e3 100644 --- a/drivers/firmware/efi/efi-init.c +++ b/drivers/firmware/efi/efi-init.c @@ -22,6 +22,8 @@ #include +unsigned long __initdata screen_info_table = EFI_INVALID_TABLE_ADDR; + static int __init is_memory(efi_memory_desc_t *md) { if (md->attribute & (EFI_MEMORY_WB|EFI_MEMORY_WT|EFI_MEMORY_WC)) @@ -55,9 +57,22 @@ extern __weak const efi_config_table_type_t efi_arch_tables[]; static void __init init_screen_info(void) { - if (screen_info.orig_video_isVGA == VIDEO_TYPE_EFI && - memblock_is_map_memory(screen_info.lfb_base)) - memblock_mark_nomap(screen_info.lfb_base, screen_info.lfb_size); + struct screen_info *si; + + if (screen_info_table != EFI_INVALID_TABLE_ADDR) { + si = early_memremap(screen_info_table, sizeof(*si)); + if (!si) { + pr_err("Could not map screen_info config table\n"); + return; + } + screen_info = *si; + memset(si, 0, sizeof(*si)); + early_memunmap(si, sizeof(*si)); + + if (memblock_is_map_memory(screen_info.lfb_base)) + memblock_mark_nomap(screen_info.lfb_base, + screen_info.lfb_size); + } } static int __init uefi_init(u64 efi_system_table) diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index a46df5d1d094..951a42d27cf4 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c @@ -58,6 +58,8 @@ static unsigned long __initdata mem_reserve = EFI_INVALID_TABLE_ADDR; static unsigned long __initdata rt_prop = EFI_INVALID_TABLE_ADDR; static unsigned long __initdata initrd = EFI_INVALID_TABLE_ADDR; +extern unsigned long screen_info_table; + struct mm_struct efi_mm = { .mm_mt = MTREE_INIT_EXT(mm_mt, MM_MT_FLAGS, efi_mm.mmap_lock), .mm_users = ATOMIC_INIT(2), @@ -546,6 +548,9 @@ static const efi_config_table_type_t common_tables[] __initconst = { #endif #ifdef CONFIG_EFI_COCO_SECRET {LINUX_EFI_COCO_SECRET_AREA_GUID, &efi.coco_secret, "CocoSecret" }, +#endif +#ifdef CONFIG_EFI_GENERIC_STUB + {LINUX_EFI_SCREEN_INFO_TABLE_GUID, &screen_info_table }, #endif {}, }; diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile index 5b0ae755180e..3f44e272ff9c 100644 --- a/drivers/firmware/efi/libstub/Makefile +++ b/drivers/firmware/efi/libstub/Makefile @@ -81,7 +81,8 @@ lib-$(CONFIG_EFI_PARAMS_FROM_FDT) += fdt.o \ $(obj)/lib-%.o: $(srctree)/lib/%.c FORCE $(call if_changed_rule,cc_o_c) -lib-$(CONFIG_EFI_GENERIC_STUB) += efi-stub.o string.o intrinsics.o systable.o +lib-$(CONFIG_EFI_GENERIC_STUB) += efi-stub.o string.o intrinsics.o systable.o \ + screen_info.o lib-$(CONFIG_ARM) += arm32-stub.o lib-$(CONFIG_ARM64) += arm64-stub.o arm64-entry.o diff --git a/drivers/firmware/efi/libstub/arm32-stub.c b/drivers/firmware/efi/libstub/arm32-stub.c index 0131e3aaa605..1073dd947516 100644 --- a/drivers/firmware/efi/libstub/arm32-stub.c +++ b/drivers/firmware/efi/libstub/arm32-stub.c @@ -76,43 +76,6 @@ void efi_handle_post_ebs_state(void) &efi_entry_state->sctlr_after_ebs); } -static efi_guid_t screen_info_guid = LINUX_EFI_ARM_SCREEN_INFO_TABLE_GUID; - -struct screen_info *alloc_screen_info(void) -{ - struct screen_info *si; - efi_status_t status; - - /* - * Unlike on arm64, where we can directly fill out the screen_info - * structure from the stub, we need to allocate a buffer to hold - * its contents while we hand over to the kernel proper from the - * decompressor. - */ - status = efi_bs_call(allocate_pool, EFI_RUNTIME_SERVICES_DATA, - sizeof(*si), (void **)&si); - - if (status != EFI_SUCCESS) - return NULL; - - status = efi_bs_call(install_configuration_table, - &screen_info_guid, si); - if (status == EFI_SUCCESS) - return si; - - efi_bs_call(free_pool, si); - return NULL; -} - -void free_screen_info(struct screen_info *si) -{ - if (!si) - return; - - efi_bs_call(install_configuration_table, &screen_info_guid, NULL); - efi_bs_call(free_pool, si); -} - 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/efi-stub.c b/drivers/firmware/efi/libstub/efi-stub.c index b55d1009d4c8..8521dc09c6ae 100644 --- a/drivers/firmware/efi/libstub/efi-stub.c +++ b/drivers/firmware/efi/libstub/efi-stub.c @@ -47,6 +47,15 @@ static u64 virtmap_base = EFI_RT_VIRTUAL_BASE; static bool flat_va_mapping = (EFI_RT_VIRTUAL_OFFSET != 0); +struct screen_info * __weak alloc_screen_info(void) +{ + return &screen_info; +} + +void __weak free_screen_info(struct screen_info *si) +{ +} + static struct screen_info *setup_graphics(void) { efi_guid_t gop_proto = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID; diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h index a30fb5d8ef05..a4cb51e2cae3 100644 --- a/drivers/firmware/efi/libstub/efistub.h +++ b/drivers/firmware/efi/libstub/efistub.h @@ -975,4 +975,7 @@ efi_enable_reset_attack_mitigation(void) { } void efi_retrieve_tpm2_eventlog(void); +struct screen_info *alloc_screen_info(void); +void free_screen_info(struct screen_info *si); + #endif diff --git a/drivers/firmware/efi/libstub/screen_info.c b/drivers/firmware/efi/libstub/screen_info.c new file mode 100644 index 000000000000..8e76a8b384ba --- /dev/null +++ b/drivers/firmware/efi/libstub/screen_info.c @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include + +#include "efistub.h" + +/* + * There are two ways of populating the core kernel's struct screen_info via the stub: + * - using a configuration table, like below, which relies on the EFI init code + * to locate the table and copy the contents; + * - by linking directly to the core kernel's copy of the global symbol. + * + * The latter is preferred because it makes the EFIFB earlycon available very + * early, but it only works if the EFI stub is part of the core kernel image + * itself. The zboot decompressor can only use the configuration table + * approach. + * + * In order to support both methods from the same build of the EFI stub + * library, provide this dummy global definition of struct screen_info. If it + * is required to satisfy a link dependency, it means we need to override the + * __weak alloc and free methods with the ones below, and those will be pulled + * in as well. + */ +struct screen_info screen_info; + +static efi_guid_t screen_info_guid = LINUX_EFI_SCREEN_INFO_TABLE_GUID; + +struct screen_info *alloc_screen_info(void) +{ + struct screen_info *si; + efi_status_t status; + + status = efi_bs_call(allocate_pool, EFI_ACPI_RECLAIM_MEMORY, + sizeof(*si), (void **)&si); + + if (status != EFI_SUCCESS) + return NULL; + + status = efi_bs_call(install_configuration_table, + &screen_info_guid, si); + if (status == EFI_SUCCESS) + return si; + + efi_bs_call(free_pool, si); + return NULL; +} + +void free_screen_info(struct screen_info *si) +{ + if (!si) + return; + + efi_bs_call(install_configuration_table, &screen_info_guid, NULL); + efi_bs_call(free_pool, si); +} diff --git a/include/linux/efi.h b/include/linux/efi.h index 929d559ad41d..dfa6cc8bbef9 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -403,7 +403,7 @@ void efi_native_runtime_setup(void); * structure that was populated by the stub based on the GOP protocol instance * associated with ConOut */ -#define LINUX_EFI_ARM_SCREEN_INFO_TABLE_GUID EFI_GUID(0xe03fc20a, 0x85dc, 0x406e, 0xb9, 0x0e, 0x4a, 0xb5, 0x02, 0x37, 0x1d, 0x95) +#define LINUX_EFI_SCREEN_INFO_TABLE_GUID EFI_GUID(0xe03fc20a, 0x85dc, 0x406e, 0xb9, 0x0e, 0x4a, 0xb5, 0x02, 0x37, 0x1d, 0x95) #define LINUX_EFI_ARM_CPU_STATE_TABLE_GUID EFI_GUID(0xef79e4aa, 0x3c3d, 0x4989, 0xb9, 0x02, 0x07, 0xa9, 0x43, 0xe5, 0x50, 0xd2) #define LINUX_EFI_LOADER_ENTRY_GUID EFI_GUID(0x4a67b082, 0x0a4c, 0x41cf, 0xb6, 0xc7, 0x44, 0x0b, 0x29, 0xbb, 0x8c, 0x4f) #define LINUX_EFI_RANDOM_SEED_TABLE_GUID EFI_GUID(0x1ce1e5bc, 0x7ceb, 0x42f2, 0x81, 0xe5, 0x8a, 0xad, 0xf1, 0x80, 0xf5, 0x7b) -- cgit v1.2.3 From da8dd0c75b3f82eb366eb1745fb473ea92c8c087 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Tue, 11 Oct 2022 18:21:52 +0200 Subject: efi: libstub: Provide local implementations of strrchr() and memchr() Clone the implementations of strrchr() and memchr() in lib/string.c so we can use them in the standalone zboot decompressor app. These routines are used by the FDT handling code. Signed-off-by: Ard Biesheuvel --- arch/arm64/kernel/image-vars.h | 3 -- arch/riscv/kernel/image-vars.h | 2 -- drivers/firmware/efi/libstub/Makefile | 3 +- drivers/firmware/efi/libstub/string.c | 62 +++++++++++++++++++++++++++++++++++ 4 files changed, 64 insertions(+), 6 deletions(-) (limited to 'drivers/firmware/efi/libstub/Makefile') diff --git a/arch/arm64/kernel/image-vars.h b/arch/arm64/kernel/image-vars.h index ace584e0b065..f31130ba0233 100644 --- a/arch/arm64/kernel/image-vars.h +++ b/arch/arm64/kernel/image-vars.h @@ -21,9 +21,6 @@ PROVIDE(__efistub_primary_entry_offset = primary_entry - _text); * linked at. The routines below are all implemented in assembler in a * position independent manner */ -PROVIDE(__efistub_memchr = __pi_memchr); -PROVIDE(__efistub_strcmp = __pi_strcmp); -PROVIDE(__efistub_strrchr = __pi_strrchr); PROVIDE(__efistub_dcache_clean_poc = __pi_dcache_clean_poc); PROVIDE(__efistub__text = _text); diff --git a/arch/riscv/kernel/image-vars.h b/arch/riscv/kernel/image-vars.h index 4913abd6dd10..7e2962ef73f9 100644 --- a/arch/riscv/kernel/image-vars.h +++ b/arch/riscv/kernel/image-vars.h @@ -23,9 +23,7 @@ * linked at. The routines below are all implemented in assembler in a * position independent manner */ -__efistub_memchr = memchr; __efistub_strcmp = strcmp; -__efistub_strrchr = strrchr; __efistub__start = _start; __efistub__start_kernel = _start_kernel; diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile index 3f44e272ff9c..4964d3106dcb 100644 --- a/drivers/firmware/efi/libstub/Makefile +++ b/drivers/firmware/efi/libstub/Makefile @@ -25,7 +25,8 @@ cflags-$(CONFIG_X86) += -m$(BITS) -D__KERNEL__ \ cflags-$(CONFIG_ARM64) += -fpie $(DISABLE_STACKLEAK_PLUGIN) \ $(call cc-option,-mbranch-protection=none) cflags-$(CONFIG_ARM) += -DEFI_HAVE_STRLEN -DEFI_HAVE_STRNLEN \ - -fno-builtin -fpic \ + -DEFI_HAVE_MEMCHR -DEFI_HAVE_STRRCHR \ + -DEFI_HAVE_STRCMP -fno-builtin -fpic \ $(call cc-option,-mno-single-pic-base) cflags-$(CONFIG_RISCV) += -fpic cflags-$(CONFIG_LOONGARCH) += -fpie diff --git a/drivers/firmware/efi/libstub/string.c b/drivers/firmware/efi/libstub/string.c index 5a1519d435bf..168fe8e79abc 100644 --- a/drivers/firmware/efi/libstub/string.c +++ b/drivers/firmware/efi/libstub/string.c @@ -64,6 +64,28 @@ char *strstr(const char *s1, const char *s2) return NULL; } +#ifndef EFI_HAVE_STRCMP +/** + * strcmp - Compare two strings + * @cs: One string + * @ct: Another string + */ +int strcmp(const char *cs, const char *ct) +{ + unsigned char c1, c2; + + while (1) { + c1 = *cs++; + c2 = *ct++; + if (c1 != c2) + return c1 < c2 ? -1 : 1; + if (!c1) + break; + } + return 0; +} +#endif + /** * strncmp - Compare two length-limited strings * @cs: One string @@ -140,3 +162,43 @@ long simple_strtol(const char *cp, char **endp, unsigned int base) return simple_strtoull(cp, endp, base); } + +#ifdef CONFIG_EFI_PARAMS_FROM_FDT +#ifndef EFI_HAVE_STRRCHR +/** + * strrchr - Find the last occurrence of a character in a string + * @s: The string to be searched + * @c: The character to search for + */ +char *strrchr(const char *s, int c) +{ + const char *last = NULL; + do { + if (*s == (char)c) + last = s; + } while (*s++); + return (char *)last; +} +#endif +#ifndef EFI_HAVE_MEMCHR +/** + * memchr - Find a character in an area of memory. + * @s: The memory area + * @c: The byte to search for + * @n: The size of the area. + * + * returns the address of the first occurrence of @c, or %NULL + * if @c is not found + */ +void *memchr(const void *s, int c, size_t n) +{ + const unsigned char *p = s; + while (n-- != 0) { + if ((unsigned char)c == *p++) { + return (void *)(p - 1); + } + } + return NULL; +} +#endif +#endif -- cgit v1.2.3 From 42c8ea3dca094ab82776ca706fb7a9cbe8ac3dc9 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Wed, 12 Oct 2022 12:55:11 +0200 Subject: efi: libstub: Factor out EFI stub entrypoint into separate file In preparation for allowing the EFI zboot decompressor to reuse most of the EFI stub machinery, factor out the actual EFI PE/COFF entrypoint into a separate file. Signed-off-by: Ard Biesheuvel --- drivers/firmware/efi/libstub/Makefile | 2 +- drivers/firmware/efi/libstub/efi-stub-entry.c | 65 +++++++++++++++++++ drivers/firmware/efi/libstub/efi-stub.c | 89 ++++++++------------------- drivers/firmware/efi/libstub/efistub.h | 8 +++ 4 files changed, 100 insertions(+), 64 deletions(-) create mode 100644 drivers/firmware/efi/libstub/efi-stub-entry.c (limited to 'drivers/firmware/efi/libstub/Makefile') diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile index 4964d3106dcb..ea96405bfd31 100644 --- a/drivers/firmware/efi/libstub/Makefile +++ b/drivers/firmware/efi/libstub/Makefile @@ -83,7 +83,7 @@ $(obj)/lib-%.o: $(srctree)/lib/%.c FORCE $(call if_changed_rule,cc_o_c) lib-$(CONFIG_EFI_GENERIC_STUB) += efi-stub.o string.o intrinsics.o systable.o \ - screen_info.o + screen_info.o efi-stub-entry.o lib-$(CONFIG_ARM) += arm32-stub.o lib-$(CONFIG_ARM64) += arm64-stub.o arm64-entry.o diff --git a/drivers/firmware/efi/libstub/efi-stub-entry.c b/drivers/firmware/efi/libstub/efi-stub-entry.c new file mode 100644 index 000000000000..5245c4f031c0 --- /dev/null +++ b/drivers/firmware/efi/libstub/efi-stub-entry.c @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include +#include + +#include "efistub.h" + +/* + * EFI entry point for the generic EFI stub used by ARM, arm64, RISC-V and + * LoongArch. This is the entrypoint that is described in the PE/COFF header + * of the core kernel. + */ +efi_status_t __efiapi efi_pe_entry(efi_handle_t handle, + efi_system_table_t *systab) +{ + efi_loaded_image_t *image; + efi_status_t status; + unsigned long image_addr; + unsigned long image_size = 0; + /* addr/point and size pairs for memory management*/ + char *cmdline_ptr = NULL; + efi_guid_t loaded_image_proto = LOADED_IMAGE_PROTOCOL_GUID; + unsigned long reserve_addr = 0; + unsigned long reserve_size = 0; + + WRITE_ONCE(efi_system_table, systab); + + /* Check if we were booted by the EFI firmware */ + if (efi_system_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) + return EFI_INVALID_PARAMETER; + + /* + * Get a handle to the loaded image protocol. This is used to get + * information about the running image, such as size and the command + * line. + */ + status = efi_bs_call(handle_protocol, handle, &loaded_image_proto, + (void *)&image); + if (status != EFI_SUCCESS) { + efi_err("Failed to get loaded image protocol\n"); + return status; + } + + status = efi_handle_cmdline(image, &cmdline_ptr); + if (status != EFI_SUCCESS) + return status; + + efi_info("Booting Linux Kernel...\n"); + + status = handle_kernel_image(&image_addr, &image_size, + &reserve_addr, + &reserve_size, + image, handle); + if (status != EFI_SUCCESS) { + efi_err("Failed to relocate kernel\n"); + return status; + } + + status = efi_stub_common(handle, image, image_addr, cmdline_ptr); + + efi_free(image_size, image_addr); + efi_free(reserve_size, reserve_addr); + + return status; +} diff --git a/drivers/firmware/efi/libstub/efi-stub.c b/drivers/firmware/efi/libstub/efi-stub.c index 8521dc09c6ae..2955c1ac6a36 100644 --- a/drivers/firmware/efi/libstub/efi-stub.c +++ b/drivers/firmware/efi/libstub/efi-stub.c @@ -115,61 +115,21 @@ static u32 get_supported_rt_services(void) return supported; } -/* - * EFI entry point for the arm/arm64 EFI stubs. This is the entrypoint - * that is described in the PE/COFF header. Most of the code is the same - * for both archictectures, with the arch-specific code provided in the - * handle_kernel_image() function. - */ -efi_status_t __efiapi efi_pe_entry(efi_handle_t handle, - efi_system_table_t *sys_table_arg) +efi_status_t efi_handle_cmdline(efi_loaded_image_t *image, char **cmdline_ptr) { - efi_loaded_image_t *image; - efi_status_t status; - unsigned long image_addr; - unsigned long image_size = 0; - /* addr/point and size pairs for memory management*/ - char *cmdline_ptr = NULL; int cmdline_size = 0; - efi_guid_t loaded_image_proto = LOADED_IMAGE_PROTOCOL_GUID; - unsigned long reserve_addr = 0; - unsigned long reserve_size = 0; - struct screen_info *si; - - efi_system_table = sys_table_arg; - - /* Check if we were booted by the EFI firmware */ - if (efi_system_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) { - status = EFI_INVALID_PARAMETER; - goto fail; - } - - status = check_platform_features(); - if (status != EFI_SUCCESS) - goto fail; - - /* - * Get a handle to the loaded image protocol. This is used to get - * information about the running image, such as size and the command - * line. - */ - status = efi_bs_call(handle_protocol, handle, &loaded_image_proto, - (void *)&image); - if (status != EFI_SUCCESS) { - efi_err("Failed to get loaded image protocol\n"); - goto fail; - } + efi_status_t status; + char *cmdline; /* * Get the command line from EFI, using the LOADED_IMAGE * protocol. We are going to copy the command line into the * device tree, so this can be allocated anywhere. */ - cmdline_ptr = efi_convert_cmdline(image, &cmdline_size); - if (!cmdline_ptr) { + cmdline = efi_convert_cmdline(image, &cmdline_size); + if (!cmdline) { efi_err("getting command line via LOADED_IMAGE_PROTOCOL\n"); - status = EFI_OUT_OF_RESOURCES; - goto fail; + return EFI_OUT_OF_RESOURCES; } if (IS_ENABLED(CONFIG_CMDLINE_EXTEND) || @@ -183,25 +143,34 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle, } if (!IS_ENABLED(CONFIG_CMDLINE_FORCE) && cmdline_size > 0) { - status = efi_parse_options(cmdline_ptr); + status = efi_parse_options(cmdline); if (status != EFI_SUCCESS) { efi_err("Failed to parse options\n"); goto fail_free_cmdline; } } - efi_info("Booting Linux Kernel...\n"); + *cmdline_ptr = cmdline; + return EFI_SUCCESS; - si = setup_graphics(); +fail_free_cmdline: + efi_bs_call(free_pool, cmdline_ptr); + return status; +} - status = handle_kernel_image(&image_addr, &image_size, - &reserve_addr, - &reserve_size, - image, handle); - if (status != EFI_SUCCESS) { - efi_err("Failed to relocate kernel\n"); - goto fail_free_screeninfo; - } +efi_status_t efi_stub_common(efi_handle_t handle, + efi_loaded_image_t *image, + unsigned long image_addr, + char *cmdline_ptr) +{ + struct screen_info *si; + efi_status_t status; + + status = check_platform_features(); + if (status != EFI_SUCCESS) + return status; + + si = setup_graphics(); efi_retrieve_tpm2_eventlog(); @@ -221,13 +190,7 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle, status = efi_boot_kernel(handle, image, image_addr, cmdline_ptr); - efi_free(image_size, image_addr); - efi_free(reserve_size, reserve_addr); -fail_free_screeninfo: free_screen_info(si); -fail_free_cmdline: - efi_bs_call(free_pool, cmdline_ptr); -fail: return status; } diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h index a4cb51e2cae3..fd6953ed2d0b 100644 --- a/drivers/firmware/efi/libstub/efistub.h +++ b/drivers/firmware/efi/libstub/efistub.h @@ -958,6 +958,14 @@ efi_status_t handle_kernel_image(unsigned long *image_addr, efi_loaded_image_t *image, efi_handle_t image_handle); +/* shared entrypoint between the normal stub and the zboot stub */ +efi_status_t efi_stub_common(efi_handle_t handle, + efi_loaded_image_t *image, + unsigned long image_addr, + char *cmdline_ptr); + +efi_status_t efi_handle_cmdline(efi_loaded_image_t *image, char **cmdline_ptr); + asmlinkage void __noreturn efi_enter_kernel(unsigned long entrypoint, unsigned long fdt_addr, unsigned long fdt_size); -- cgit v1.2.3 From f1a116c055e3aee0c579d39bd777c9155e8bf5d1 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Wed, 12 Oct 2022 20:23:46 +0200 Subject: efi/riscv: libstub: Split off kernel image relocation for builtin stub The RISC-V 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. Signed-off-by: Ard Biesheuvel --- arch/riscv/include/asm/efi.h | 2 + drivers/firmware/efi/libstub/Makefile | 2 +- drivers/firmware/efi/libstub/riscv-stub.c | 81 +++---------------------- drivers/firmware/efi/libstub/riscv.c | 98 +++++++++++++++++++++++++++++++ 4 files changed, 108 insertions(+), 75 deletions(-) create mode 100644 drivers/firmware/efi/libstub/riscv.c (limited to 'drivers/firmware/efi/libstub/Makefile') diff --git a/arch/riscv/include/asm/efi.h b/arch/riscv/include/asm/efi.h index a742868eb23c..6cbc7437d886 100644 --- a/arch/riscv/include/asm/efi.h +++ b/arch/riscv/include/asm/efi.h @@ -45,4 +45,6 @@ static inline unsigned long efi_get_kimg_min_align(void) void efi_virtmap_load(void); void efi_virtmap_unload(void); +unsigned long stext_offset(void); + #endif /* _ASM_EFI_H */ diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile index ea96405bfd31..5ec0635b4987 100644 --- a/drivers/firmware/efi/libstub/Makefile +++ b/drivers/firmware/efi/libstub/Makefile @@ -88,7 +88,7 @@ lib-$(CONFIG_EFI_GENERIC_STUB) += efi-stub.o string.o intrinsics.o systable.o \ lib-$(CONFIG_ARM) += arm32-stub.o lib-$(CONFIG_ARM64) += arm64-stub.o arm64-entry.o lib-$(CONFIG_X86) += x86-stub.o -lib-$(CONFIG_RISCV) += riscv-stub.o +lib-$(CONFIG_RISCV) += riscv.o riscv-stub.o lib-$(CONFIG_LOONGARCH) += loongarch-stub.o CFLAGS_arm32-stub.o := -DTEXT_OFFSET=$(TEXT_OFFSET) diff --git a/drivers/firmware/efi/libstub/riscv-stub.c b/drivers/firmware/efi/libstub/riscv-stub.c index c5a551f69a7f..145c9f0ba217 100644 --- a/drivers/firmware/efi/libstub/riscv-stub.c +++ b/drivers/firmware/efi/libstub/riscv-stub.c @@ -4,7 +4,6 @@ */ #include -#include #include #include @@ -12,82 +11,16 @@ #include "efistub.h" -typedef void __noreturn (*jump_kernel_func)(unsigned long, unsigned long); - -static unsigned long hartid; - -static int get_boot_hartid_from_fdt(void) -{ - const void *fdt; - int chosen_node, len; - const void *prop; - - fdt = get_efi_config_table(DEVICE_TREE_GUID); - if (!fdt) - return -EINVAL; - - chosen_node = fdt_path_offset(fdt, "/chosen"); - if (chosen_node < 0) - return -EINVAL; - - prop = fdt_getprop((void *)fdt, chosen_node, "boot-hartid", &len); - if (!prop) - return -EINVAL; - - if (len == sizeof(u32)) - hartid = (unsigned long) fdt32_to_cpu(*(fdt32_t *)prop); - else if (len == sizeof(u64)) - hartid = (unsigned long) fdt64_to_cpu(__get_unaligned_t(fdt64_t, prop)); - else - return -EINVAL; - - return 0; -} - -static efi_status_t get_boot_hartid_from_efi(void) +unsigned long stext_offset(void) { - efi_guid_t boot_protocol_guid = RISCV_EFI_BOOT_PROTOCOL_GUID; - struct riscv_efi_boot_protocol *boot_protocol; - efi_status_t status; - - status = efi_bs_call(locate_protocol, &boot_protocol_guid, NULL, - (void **)&boot_protocol); - if (status != EFI_SUCCESS) - return status; - return efi_call_proto(boot_protocol, get_boot_hartid, &hartid); -} - -efi_status_t check_platform_features(void) -{ - efi_status_t status; - int ret; - - status = get_boot_hartid_from_efi(); - if (status != EFI_SUCCESS) { - ret = get_boot_hartid_from_fdt(); - if (ret) { - efi_err("Failed to get boot hartid!\n"); - return EFI_UNSUPPORTED; - } - } - return EFI_SUCCESS; -} - -void __noreturn efi_enter_kernel(unsigned long entrypoint, unsigned long fdt, - unsigned long fdt_size) -{ - unsigned long stext_offset = _start_kernel - _start; - unsigned long kernel_entry = entrypoint + stext_offset; - jump_kernel_func jump_kernel = (jump_kernel_func)kernel_entry; - /* - * Jump to real kernel here with following constraints. - * 1. MMU should be disabled. - * 2. a0 should contain hartid - * 3. a1 should DT address + * When built as part of the kernel, the EFI stub cannot branch to the + * kernel proper via the image header, as the PE/COFF header is + * strictly not part of the in-memory presentation of the image, only + * of the file representation. So instead, we need to jump to the + * actual entrypoint in the .text region of the image. */ - csr_write(CSR_SATP, 0); - jump_kernel(hartid, fdt); + return _start_kernel - _start; } efi_status_t handle_kernel_image(unsigned long *image_addr, diff --git a/drivers/firmware/efi/libstub/riscv.c b/drivers/firmware/efi/libstub/riscv.c new file mode 100644 index 000000000000..8022b104c3e6 --- /dev/null +++ b/drivers/firmware/efi/libstub/riscv.c @@ -0,0 +1,98 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2020 Western Digital Corporation or its affiliates. + */ + +#include +#include + +#include +#include + +#include "efistub.h" + +typedef void __noreturn (*jump_kernel_func)(unsigned long, unsigned long); + +static unsigned long hartid; + +static int get_boot_hartid_from_fdt(void) +{ + const void *fdt; + int chosen_node, len; + const void *prop; + + fdt = get_efi_config_table(DEVICE_TREE_GUID); + if (!fdt) + return -EINVAL; + + chosen_node = fdt_path_offset(fdt, "/chosen"); + if (chosen_node < 0) + return -EINVAL; + + prop = fdt_getprop((void *)fdt, chosen_node, "boot-hartid", &len); + if (!prop) + return -EINVAL; + + if (len == sizeof(u32)) + hartid = (unsigned long) fdt32_to_cpu(*(fdt32_t *)prop); + else if (len == sizeof(u64)) + hartid = (unsigned long) fdt64_to_cpu(__get_unaligned_t(fdt64_t, prop)); + else + return -EINVAL; + + return 0; +} + +static efi_status_t get_boot_hartid_from_efi(void) +{ + efi_guid_t boot_protocol_guid = RISCV_EFI_BOOT_PROTOCOL_GUID; + struct riscv_efi_boot_protocol *boot_protocol; + efi_status_t status; + + status = efi_bs_call(locate_protocol, &boot_protocol_guid, NULL, + (void **)&boot_protocol); + if (status != EFI_SUCCESS) + return status; + return efi_call_proto(boot_protocol, get_boot_hartid, &hartid); +} + +efi_status_t check_platform_features(void) +{ + efi_status_t status; + int ret; + + status = get_boot_hartid_from_efi(); + if (status != EFI_SUCCESS) { + ret = get_boot_hartid_from_fdt(); + if (ret) { + efi_err("Failed to get boot hartid!\n"); + return EFI_UNSUPPORTED; + } + } + return EFI_SUCCESS; +} + +unsigned long __weak stext_offset(void) +{ + /* + * This fallback definition is used by the EFI zboot stub, which loads + * the entire image so it can branch via the image header at offset #0. + */ + return 0; +} + +void __noreturn efi_enter_kernel(unsigned long entrypoint, unsigned long fdt, + unsigned long fdt_size) +{ + unsigned long kernel_entry = entrypoint + stext_offset(); + jump_kernel_func jump_kernel = (jump_kernel_func)kernel_entry; + + /* + * Jump to real kernel here with following constraints. + * 1. MMU should be disabled. + * 2. a0 should contain hartid + * 3. a1 should DT address + */ + csr_write(CSR_SATP, 0); + jump_kernel(hartid, fdt); +} -- cgit v1.2.3 From d9ffe524a538720328b5bf98733a6c641e236bc8 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Thu, 13 Oct 2022 10:17:20 +0200 Subject: efi/arm64: libstub: Split off kernel image relocation for builtin stub 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 --- drivers/firmware/efi/libstub/Makefile | 2 +- drivers/firmware/efi/libstub/arm64-entry.S | 10 +++++ drivers/firmware/efi/libstub/arm64-stub.c | 28 -------------- drivers/firmware/efi/libstub/arm64.c | 61 ++++++++++++++++++++++++++++++ drivers/firmware/efi/libstub/efistub.h | 4 ++ 5 files changed, 76 insertions(+), 29 deletions(-) create mode 100644 drivers/firmware/efi/libstub/arm64.c (limited to 'drivers/firmware/efi/libstub/Makefile') diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile index 5ec0635b4987..63e1eddf996b 100644 --- a/drivers/firmware/efi/libstub/Makefile +++ b/drivers/firmware/efi/libstub/Makefile @@ -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 diff --git a/drivers/firmware/efi/libstub/arm64-entry.S b/drivers/firmware/efi/libstub/arm64-entry.S index 87082b222a87..b5c17e89a4fc 100644 --- a/drivers/firmware/efi/libstub/arm64-entry.S +++ b/drivers/firmware/efi/libstub/arm64-entry.S @@ -8,6 +8,16 @@ #include #include + /* + * 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 diff --git a/drivers/firmware/efi/libstub/arm64-stub.c b/drivers/firmware/efi/libstub/arm64-stub.c index f35c0e54e294..c14028b625b4 100644 --- a/drivers/firmware/efi/libstub/arm64-stub.c +++ b/drivers/firmware/efi/libstub/arm64-stub.c @@ -11,37 +11,9 @@ #include #include #include -#include #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 index 000000000000..d2e94972c5fa --- /dev/null +++ b/drivers/firmware/efi/libstub/arm64.c @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2013, 2014 Linaro Ltd; + * + * This file implements the EFI boot stub for the arm64 kernel. + * Adapted from ARM version by Mark Salter + */ + + +#include +#include +#include +#include + +#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(); +} diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h index fd6953ed2d0b..b5e1095b0016 100644 --- a/drivers/firmware/efi/libstub/efistub.h +++ b/drivers/firmware/efi/libstub/efistub.h @@ -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 -- cgit v1.2.3 From d729b554e17904e16498ab5c36122d70406f70ae Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Thu, 13 Oct 2022 12:39:37 +0200 Subject: efi/loongarch: libstub: Split off kernel image relocation for builtin stub The LoongArch 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. Signed-off-by: Ard Biesheuvel --- drivers/firmware/efi/libstub/Makefile | 2 +- drivers/firmware/efi/libstub/loongarch-stub.c | 67 +--------------------- drivers/firmware/efi/libstub/loongarch.c | 80 +++++++++++++++++++++++++++ 3 files changed, 82 insertions(+), 67 deletions(-) create mode 100644 drivers/firmware/efi/libstub/loongarch.c (limited to 'drivers/firmware/efi/libstub/Makefile') diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile index 63e1eddf996b..402dfb30ddc7 100644 --- a/drivers/firmware/efi/libstub/Makefile +++ b/drivers/firmware/efi/libstub/Makefile @@ -89,7 +89,7 @@ lib-$(CONFIG_ARM) += arm32-stub.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 +lib-$(CONFIG_LOONGARCH) += loongarch.o loongarch-stub.o CFLAGS_arm32-stub.o := -DTEXT_OFFSET=$(TEXT_OFFSET) diff --git a/drivers/firmware/efi/libstub/loongarch-stub.c b/drivers/firmware/efi/libstub/loongarch-stub.c index 6b30fc281458..eee7ed43cdfb 100644 --- a/drivers/firmware/efi/libstub/loongarch-stub.c +++ b/drivers/firmware/efi/libstub/loongarch-stub.c @@ -9,18 +9,10 @@ #include #include "efistub.h" -typedef void __noreturn (*kernel_entry_t)(bool efi, unsigned long cmdline, - unsigned long systab); - extern int kernel_asize; extern int kernel_fsize; extern int kernel_offset; -extern kernel_entry_t kernel_entry; - -efi_status_t check_platform_features(void) -{ - return EFI_SUCCESS; -} +extern int kernel_entry; efi_status_t handle_kernel_image(unsigned long *image_addr, unsigned long *image_size, @@ -53,66 +45,9 @@ efi_status_t handle_kernel_image(unsigned long *image_addr, return status; } -struct exit_boot_struct { - efi_memory_desc_t *runtime_map; - int runtime_entry_count; -}; - -static efi_status_t exit_boot_func(struct efi_boot_memmap *map, void *priv) -{ - struct exit_boot_struct *p = priv; - - /* - * Update the memory map with virtual addresses. The function will also - * populate @runtime_map with copies of just the EFI_MEMORY_RUNTIME - * entries so that we can pass it straight to SetVirtualAddressMap() - */ - efi_get_virtmap(map->map, map->map_size, map->desc_size, - p->runtime_map, &p->runtime_entry_count); - - return EFI_SUCCESS; -} - unsigned long kernel_entry_address(void) { unsigned long base = (unsigned long)&kernel_offset - kernel_offset; return (unsigned long)&kernel_entry - base + VMLINUX_LOAD_ADDRESS; } - -efi_status_t efi_boot_kernel(void *handle, efi_loaded_image_t *image, - unsigned long kernel_addr, char *cmdline_ptr) -{ - kernel_entry_t real_kernel_entry; - struct exit_boot_struct priv; - unsigned long desc_size; - efi_status_t status; - u32 desc_ver; - - status = efi_alloc_virtmap(&priv.runtime_map, &desc_size, &desc_ver); - if (status != EFI_SUCCESS) { - efi_err("Unable to retrieve UEFI memory map.\n"); - return status; - } - - efi_info("Exiting boot services\n"); - - efi_novamap = false; - status = efi_exit_boot_services(handle, &priv, exit_boot_func); - if (status != EFI_SUCCESS) - return status; - - /* Install the new virtual address map */ - efi_rt_call(set_virtual_address_map, - priv.runtime_entry_count * desc_size, desc_size, - desc_ver, priv.runtime_map); - - /* Config Direct Mapping */ - csr_write64(CSR_DMW0_INIT, LOONGARCH_CSR_DMWIN0); - csr_write64(CSR_DMW1_INIT, LOONGARCH_CSR_DMWIN1); - - real_kernel_entry = (void *)kernel_entry_address(); - - real_kernel_entry(true, (unsigned long)cmdline_ptr, - (unsigned long)efi_system_table); -} diff --git a/drivers/firmware/efi/libstub/loongarch.c b/drivers/firmware/efi/libstub/loongarch.c new file mode 100644 index 000000000000..807cba2693fc --- /dev/null +++ b/drivers/firmware/efi/libstub/loongarch.c @@ -0,0 +1,80 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Author: Yun Liu + * Huacai Chen + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ + +#include +#include +#include "efistub.h" + +typedef void __noreturn (*kernel_entry_t)(bool efi, unsigned long cmdline, + unsigned long systab); + +efi_status_t check_platform_features(void) +{ + return EFI_SUCCESS; +} + +struct exit_boot_struct { + efi_memory_desc_t *runtime_map; + int runtime_entry_count; +}; + +static efi_status_t exit_boot_func(struct efi_boot_memmap *map, void *priv) +{ + struct exit_boot_struct *p = priv; + + /* + * Update the memory map with virtual addresses. The function will also + * populate @runtime_map with copies of just the EFI_MEMORY_RUNTIME + * entries so that we can pass it straight to SetVirtualAddressMap() + */ + efi_get_virtmap(map->map, map->map_size, map->desc_size, + p->runtime_map, &p->runtime_entry_count); + + return EFI_SUCCESS; +} + +unsigned long __weak kernel_entry_address(void) +{ + return *(unsigned long *)(PHYSADDR(VMLINUX_LOAD_ADDRESS) + 8); +} + +efi_status_t efi_boot_kernel(void *handle, efi_loaded_image_t *image, + unsigned long kernel_addr, char *cmdline_ptr) +{ + kernel_entry_t real_kernel_entry; + struct exit_boot_struct priv; + unsigned long desc_size; + efi_status_t status; + u32 desc_ver; + + status = efi_alloc_virtmap(&priv.runtime_map, &desc_size, &desc_ver); + if (status != EFI_SUCCESS) { + efi_err("Unable to retrieve UEFI memory map.\n"); + return status; + } + + efi_info("Exiting boot services\n"); + + efi_novamap = false; + status = efi_exit_boot_services(handle, &priv, exit_boot_func); + if (status != EFI_SUCCESS) + return status; + + /* Install the new virtual address map */ + efi_rt_call(set_virtual_address_map, + priv.runtime_entry_count * desc_size, desc_size, + desc_ver, priv.runtime_map); + + /* Config Direct Mapping */ + csr_write64(CSR_DMW0_INIT, LOONGARCH_CSR_DMWIN0); + csr_write64(CSR_DMW1_INIT, LOONGARCH_CSR_DMWIN1); + + real_kernel_entry = (void *)kernel_entry_address(); + + real_kernel_entry(true, (unsigned long)cmdline_ptr, + (unsigned long)efi_system_table); +} -- cgit v1.2.3