EFI updates for v6.2:
- Refactor the zboot code so that it incorporates all the EFI stub logic, rather than calling the decompressed kernel as a EFI app. - Add support for initrd= command line option to x86 mixed mode. - Allow initrd= to be used with arbitrary EFI accessible file systems instead of just the one the kernel itself was loaded from. - Move some x86-only handling and manipulation of the EFI memory map into arch/x86, as it is not used anywhere else. - More flexible handling of any random seeds provided by the boot environment (i.e., systemd-boot) so that it becomes available much earlier during the boot. - Allow improved arch-agnostic EFI support in loaders, by setting a uniform baseline of supported features, and adding a generic magic number to the DOS/PE header. This should allow loaders such as GRUB or systemd-boot to reduce the amount of arch-specific handling substantially. - (arm64) Run EFI runtime services from a dedicated stack, and use it to recover from synchronous exceptions that might occur in the firmware code. - (arm64) Ensure that we don't allocate memory outside of the 48-bit addressable physical range. - Make EFI pstore record size configurable - Add support for decoding CXL specific CPER records -----BEGIN PGP SIGNATURE----- iQGzBAABCgAdFiEE+9lifEBpyUIVN1cpw08iOZLZjyQFAmOTQ1cACgkQw08iOZLZ jyQRkAv+LqaZFWeVwhAQHiw/N3RnRM0nZHea6++D2p1y/ZbCpwv3pdLl2YHQ1KmW wDG9Nr4C1ITLtfy1YZKeYpwloQtq9S1GZDWnFpVv/hdo7L924eRAwIlxowWn1OnP ruxv2PaYXyb0plh1YD1f6E1BqrfUOtajET55Kxs9ZsxmnMtDpIX3NiYy4LKMBIZC +Eywt41M3uBX+wgmSujFBMVVJjhOX60WhUYXqy0RXwDKOyrz/oW5td+eotSCreB6 FVbjvwQvUdtzn4s1FayOMlTrkxxLw4vLhsaUGAdDOHd3rg3sZT9Xh1HqFFD6nss6 ZAzAYQ6BzdiV/5WSB9meJe+BeG1hjTNKjJI6JPO2lctzYJqlnJJzI6JzBuH9vzQ0 dffLB8NITeEW2rphIh+q+PAKFFNbXWkJtV4BMRpqmzZ/w7HwupZbUXAzbWE8/5km qlFpr0kmq8GlVcbXNOFjmnQVrJ8jPYn+O3AwmEiVAXKZJOsMH0sjlXHKsonme9oV Sk71c6Em =JEXz -----END PGP SIGNATURE----- Merge tag 'efi-next-for-v6.2' of git://git.kernel.org/pub/scm/linux/kernel/git/efi/efi Pull EFI updates from Ard Biesheuvel: "Another fairly sizable pull request, by EFI subsystem standards. Most of the work was done by me, some of it in collaboration with the distro and bootloader folks (GRUB, systemd-boot), where the main focus has been on removing pointless per-arch differences in the way EFI boots a Linux kernel. - Refactor the zboot code so that it incorporates all the EFI stub logic, rather than calling the decompressed kernel as a EFI app. - Add support for initrd= command line option to x86 mixed mode. - Allow initrd= to be used with arbitrary EFI accessible file systems instead of just the one the kernel itself was loaded from. - Move some x86-only handling and manipulation of the EFI memory map into arch/x86, as it is not used anywhere else. - More flexible handling of any random seeds provided by the boot environment (i.e., systemd-boot) so that it becomes available much earlier during the boot. - Allow improved arch-agnostic EFI support in loaders, by setting a uniform baseline of supported features, and adding a generic magic number to the DOS/PE header. This should allow loaders such as GRUB or systemd-boot to reduce the amount of arch-specific handling substantially. - (arm64) Run EFI runtime services from a dedicated stack, and use it to recover from synchronous exceptions that might occur in the firmware code. - (arm64) Ensure that we don't allocate memory outside of the 48-bit addressable physical range. - Make EFI pstore record size configurable - Add support for decoding CXL specific CPER records" * tag 'efi-next-for-v6.2' of git://git.kernel.org/pub/scm/linux/kernel/git/efi/efi: (43 commits) arm64: efi: Recover from synchronous exceptions occurring in firmware arm64: efi: Execute runtime services from a dedicated stack arm64: efi: Limit allocations to 48-bit addressable physical region efi: Put Linux specific magic number in the DOS header efi: libstub: Always enable initrd command line loader and bump version efi: stub: use random seed from EFI variable efi: vars: prohibit reading random seed variables efi: random: combine bootloader provided RNG seed with RNG protocol output efi/cper, cxl: Decode CXL Error Log efi/cper, cxl: Decode CXL Protocol Error Section efi: libstub: fix efi_load_initrd_dev_path() kernel-doc comment efi: x86: Move EFI runtime map sysfs code to arch/x86 efi: runtime-maps: Clarify purpose and enable by default for kexec efi: pstore: Add module parameter for setting the record size efi: xen: Set EFI_PARAVIRT for Xen dom0 boot on all architectures efi: memmap: Move manipulation routines into x86 arch tree efi: memmap: Move EFI fake memmap support into x86 arch tree efi: libstub: Undeprecate the command line initrd loader efi: libstub: Add mixed mode support to command line initrd loader efi: libstub: Permit mixed mode return types other than efi_status_t ...
This commit is contained in:
commit
fc4c9f4504
|
@ -7839,7 +7839,6 @@ F: Documentation/admin-guide/efi-stub.rst
|
|||
F: arch/*/include/asm/efi.h
|
||||
F: arch/*/kernel/efi.c
|
||||
F: arch/arm/boot/compressed/efi-header.S
|
||||
F: arch/arm64/kernel/efi-entry.S
|
||||
F: arch/x86/platform/efi/
|
||||
F: drivers/firmware/efi/
|
||||
F: include/linux/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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -14,8 +14,16 @@
|
|||
|
||||
#ifdef CONFIG_EFI
|
||||
extern void efi_init(void);
|
||||
|
||||
bool efi_runtime_fixup_exception(struct pt_regs *regs, const char *msg);
|
||||
#else
|
||||
#define efi_init()
|
||||
|
||||
static inline
|
||||
bool efi_runtime_fixup_exception(struct pt_regs *regs, const char *msg)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
int efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md);
|
||||
|
@ -25,6 +33,7 @@ int efi_set_mapping_permissions(struct mm_struct *mm, efi_memory_desc_t *md);
|
|||
({ \
|
||||
efi_virtmap_load(); \
|
||||
__efi_fpsimd_begin(); \
|
||||
spin_lock(&efi_rt_lock); \
|
||||
})
|
||||
|
||||
#undef arch_efi_call_virt
|
||||
|
@ -33,10 +42,12 @@ int efi_set_mapping_permissions(struct mm_struct *mm, efi_memory_desc_t *md);
|
|||
|
||||
#define arch_efi_call_virt_teardown() \
|
||||
({ \
|
||||
spin_unlock(&efi_rt_lock); \
|
||||
__efi_fpsimd_end(); \
|
||||
efi_virtmap_unload(); \
|
||||
})
|
||||
|
||||
extern spinlock_t efi_rt_lock;
|
||||
efi_status_t __efi_rt_asm_wrapper(void *, const char *, ...);
|
||||
|
||||
#define ARCH_EFI_IRQ_FLAGS_MASK (PSR_D_BIT | PSR_A_BIT | PSR_I_BIT | PSR_F_BIT)
|
||||
|
@ -76,13 +87,23 @@ 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)
|
||||
static inline unsigned long efi_get_kimg_min_align(void)
|
||||
{
|
||||
extern bool efi_nokaslr;
|
||||
|
||||
/*
|
||||
* Although relocatable kernels can fix up the misalignment with
|
||||
* respect to MIN_KIMG_ALIGN, the resulting virtual text addresses are
|
||||
* subtly out of sync with those recorded in the vmlinux when kaslr is
|
||||
* disabled but the image required relocation anyway. Therefore retain
|
||||
* 2M alignment if KASLR was explicitly disabled, even if it was not
|
||||
* going to be activated to begin with.
|
||||
*/
|
||||
return efi_nokaslr ? MIN_KIMG_ALIGN : EFI_KIMG_ALIGN;
|
||||
}
|
||||
|
||||
#define EFI_ALLOC_ALIGN SZ_64K
|
||||
#define EFI_ALLOC_LIMIT ((1UL << 48) - 1)
|
||||
|
||||
/*
|
||||
* On ARM systems, virtually remapped UEFI runtime services are set up in two
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,69 +0,0 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* EFI entry point.
|
||||
*
|
||||
* Copyright (C) 2013, 2014 Red Hat, Inc.
|
||||
* Author: Mark Salter <msalter@redhat.com>
|
||||
*/
|
||||
#include <linux/linkage.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
#include <asm/assembler.h>
|
||||
|
||||
__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 x20, x1 // DTB address
|
||||
|
||||
/*
|
||||
* Clean the copied Image to the PoC, and ensure it is not shadowed by
|
||||
* stale icache entries from before relocation.
|
||||
*/
|
||||
ldr w1, =kernel_size
|
||||
add x1, x0, x1
|
||||
bl dcache_clean_poc
|
||||
ic ialluis
|
||||
|
||||
/*
|
||||
* Clean the remainder of this routine to the PoC
|
||||
* so that we can safely disable the MMU and caches.
|
||||
*/
|
||||
adr x0, 0f
|
||||
adr x1, 3f
|
||||
bl dcache_clean_poc
|
||||
0:
|
||||
/* Turn off Dcache and MMU */
|
||||
mrs x0, CurrentEL
|
||||
cmp x0, #CurrentEL_EL2
|
||||
b.ne 1f
|
||||
mrs x0, sctlr_el2
|
||||
bic x0, x0, #1 << 0 // clear SCTLR.M
|
||||
bic x0, x0, #1 << 2 // clear SCTLR.C
|
||||
pre_disable_mmu_workaround
|
||||
msr sctlr_el2, x0
|
||||
isb
|
||||
b 2f
|
||||
1:
|
||||
mrs x0, sctlr_el1
|
||||
bic x0, x0, #1 << 0 // clear SCTLR.M
|
||||
bic x0, x0, #1 << 2 // clear SCTLR.C
|
||||
pre_disable_mmu_workaround
|
||||
msr sctlr_el1, x0
|
||||
isb
|
||||
2:
|
||||
/* Jump to kernel entry point */
|
||||
mov x0, x20
|
||||
mov x1, xzr
|
||||
mov x2, xzr
|
||||
mov x3, xzr
|
||||
br x19
|
||||
3:
|
||||
SYM_CODE_END(efi_enter_kernel)
|
|
@ -6,7 +6,7 @@
|
|||
#include <linux/linkage.h>
|
||||
|
||||
SYM_FUNC_START(__efi_rt_asm_wrapper)
|
||||
stp x29, x30, [sp, #-32]!
|
||||
stp x29, x30, [sp, #-112]!
|
||||
mov x29, sp
|
||||
|
||||
/*
|
||||
|
@ -16,6 +16,22 @@ SYM_FUNC_START(__efi_rt_asm_wrapper)
|
|||
*/
|
||||
stp x1, x18, [sp, #16]
|
||||
|
||||
/*
|
||||
* Preserve all callee saved registers and preserve the stack pointer
|
||||
* value at the base of the EFI runtime stack so we can recover from
|
||||
* synchronous exceptions occurring while executing the firmware
|
||||
* routines.
|
||||
*/
|
||||
stp x19, x20, [sp, #32]
|
||||
stp x21, x22, [sp, #48]
|
||||
stp x23, x24, [sp, #64]
|
||||
stp x25, x26, [sp, #80]
|
||||
stp x27, x28, [sp, #96]
|
||||
|
||||
ldr_l x16, efi_rt_stack_top
|
||||
mov sp, x16
|
||||
stp x18, x29, [sp, #-16]!
|
||||
|
||||
/*
|
||||
* We are lucky enough that no EFI runtime services take more than
|
||||
* 5 arguments, so all are passed in registers rather than via the
|
||||
|
@ -29,9 +45,10 @@ SYM_FUNC_START(__efi_rt_asm_wrapper)
|
|||
mov x4, x6
|
||||
blr x8
|
||||
|
||||
mov sp, x29
|
||||
ldp x1, x2, [sp, #16]
|
||||
cmp x2, x18
|
||||
ldp x29, x30, [sp], #32
|
||||
ldp x29, x30, [sp], #112
|
||||
b.ne 0f
|
||||
ret
|
||||
0:
|
||||
|
@ -42,6 +59,22 @@ SYM_FUNC_START(__efi_rt_asm_wrapper)
|
|||
* called with preemption disabled and a separate shadow stack is used
|
||||
* for interrupts.
|
||||
*/
|
||||
mov x18, x2
|
||||
#ifdef CONFIG_SHADOW_CALL_STACK
|
||||
ldr_l x18, efi_rt_stack_top
|
||||
ldr x18, [x18, #-16]
|
||||
#endif
|
||||
|
||||
b efi_handle_corrupted_x18 // tail call
|
||||
SYM_FUNC_END(__efi_rt_asm_wrapper)
|
||||
|
||||
SYM_CODE_START(__efi_rt_asm_recover)
|
||||
mov sp, x30
|
||||
|
||||
ldp x19, x20, [sp, #32]
|
||||
ldp x21, x22, [sp, #48]
|
||||
ldp x23, x24, [sp, #64]
|
||||
ldp x25, x26, [sp, #80]
|
||||
ldp x27, x28, [sp, #96]
|
||||
ldp x29, x30, [sp], #112
|
||||
ret
|
||||
SYM_CODE_END(__efi_rt_asm_recover)
|
||||
|
|
|
@ -144,3 +144,52 @@ asmlinkage efi_status_t efi_handle_corrupted_x18(efi_status_t s, const char *f)
|
|||
pr_err_ratelimited(FW_BUG "register x18 corrupted by EFI %s\n", f);
|
||||
return s;
|
||||
}
|
||||
|
||||
DEFINE_SPINLOCK(efi_rt_lock);
|
||||
|
||||
asmlinkage u64 *efi_rt_stack_top __ro_after_init;
|
||||
|
||||
asmlinkage efi_status_t __efi_rt_asm_recover(void);
|
||||
|
||||
bool efi_runtime_fixup_exception(struct pt_regs *regs, const char *msg)
|
||||
{
|
||||
/* Check whether the exception occurred while running the firmware */
|
||||
if (current_work() != &efi_rts_work.work || regs->pc >= TASK_SIZE_64)
|
||||
return false;
|
||||
|
||||
pr_err(FW_BUG "Unable to handle %s in EFI runtime service\n", msg);
|
||||
add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_STILL_OK);
|
||||
clear_bit(EFI_RUNTIME_SERVICES, &efi.flags);
|
||||
|
||||
regs->regs[0] = EFI_ABORTED;
|
||||
regs->regs[30] = efi_rt_stack_top[-1];
|
||||
regs->pc = (u64)__efi_rt_asm_recover;
|
||||
|
||||
if (IS_ENABLED(CONFIG_SHADOW_CALL_STACK))
|
||||
regs->regs[18] = efi_rt_stack_top[-2];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* EFI requires 8 KiB of stack space for runtime services */
|
||||
static_assert(THREAD_SIZE >= SZ_8K);
|
||||
|
||||
static int __init arm64_efi_rt_init(void)
|
||||
{
|
||||
void *p;
|
||||
|
||||
if (!efi_enabled(EFI_RUNTIME_SERVICES))
|
||||
return 0;
|
||||
|
||||
p = __vmalloc_node(THREAD_SIZE, THREAD_ALIGN, GFP_KERNEL,
|
||||
NUMA_NO_NODE, &&l);
|
||||
l: if (!p) {
|
||||
pr_warn("Failed to allocate EFI runtime stack\n");
|
||||
clear_bit(EFI_RUNTIME_SERVICES, &efi.flags);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
efi_rt_stack_top = p + THREAD_SIZE;
|
||||
return 0;
|
||||
}
|
||||
core_initcall(arm64_efi_rt_init);
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
#error This file should only be included in vmlinux.lds.S
|
||||
#endif
|
||||
|
||||
PROVIDE(__efistub_kernel_size = _edata - _text);
|
||||
PROVIDE(__efistub_primary_entry_offset = primary_entry - _text);
|
||||
|
||||
/*
|
||||
|
@ -22,13 +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_memcmp = __pi_memcmp);
|
||||
PROVIDE(__efistub_memchr = __pi_memchr);
|
||||
PROVIDE(__efistub_strlen = __pi_strlen);
|
||||
PROVIDE(__efistub_strnlen = __pi_strnlen);
|
||||
PROVIDE(__efistub_strcmp = __pi_strcmp);
|
||||
PROVIDE(__efistub_strncmp = __pi_strncmp);
|
||||
PROVIDE(__efistub_strrchr = __pi_strrchr);
|
||||
PROVIDE(__efistub_dcache_clean_poc = __pi_dcache_clean_poc);
|
||||
|
||||
PROVIDE(__efistub__text = _text);
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include <asm/bug.h>
|
||||
#include <asm/cmpxchg.h>
|
||||
#include <asm/cpufeature.h>
|
||||
#include <asm/efi.h>
|
||||
#include <asm/exception.h>
|
||||
#include <asm/daifflags.h>
|
||||
#include <asm/debug-monitors.h>
|
||||
|
@ -397,6 +398,9 @@ static void __do_kernel_fault(unsigned long addr, unsigned long esr,
|
|||
msg = "paging request";
|
||||
}
|
||||
|
||||
if (efi_runtime_fixup_exception(regs, msg))
|
||||
return;
|
||||
|
||||
die_kernel_fault(msg, addr, esr, regs);
|
||||
}
|
||||
|
||||
|
|
|
@ -19,18 +19,18 @@ 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;
|
||||
}
|
||||
|
||||
static inline unsigned long efi_get_kimg_min_align(void)
|
||||
{
|
||||
return SZ_2M;
|
||||
}
|
||||
|
||||
#define EFI_KIMG_PREFERRED_ADDRESS PHYSADDR(VMLINUX_LOAD_ADDRESS)
|
||||
|
||||
unsigned long kernel_entry_address(void);
|
||||
|
||||
#endif /* _ASM_LOONGARCH_EFI_H */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -25,7 +25,8 @@ _head:
|
|||
.dword kernel_entry /* Kernel entry point */
|
||||
.dword _end - _text /* Kernel image effective size */
|
||||
.quad 0 /* Kernel image load offset from start of RAM */
|
||||
.org 0x3c /* 0x20 ~ 0x3b reserved */
|
||||
.org 0x38 /* 0x20 ~ 0x37 reserved */
|
||||
.long LINUX_PE_MAGIC
|
||||
.long pe_header - _head /* Offset to the PE header */
|
||||
|
||||
pe_header:
|
||||
|
|
|
@ -7,15 +7,7 @@
|
|||
|
||||
#ifdef CONFIG_EFI_STUB
|
||||
|
||||
__efistub_memcmp = memcmp;
|
||||
__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;
|
||||
__efistub_kernel_fsize = kernel_fsize;
|
||||
|
|
|
@ -35,13 +35,20 @@ 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)
|
||||
static inline unsigned long efi_get_kimg_min_align(void)
|
||||
{
|
||||
/*
|
||||
* RISC-V requires the kernel image to placed 2 MB aligned base for 64
|
||||
* bit and 4MB for 32 bit.
|
||||
*/
|
||||
return IS_ENABLED(CONFIG_64BIT) ? SZ_2M : SZ_4M;
|
||||
}
|
||||
|
||||
#define EFI_KIMG_PREFERRED_ADDRESS efi_get_kimg_min_align()
|
||||
|
||||
void efi_virtmap_load(void);
|
||||
void efi_virtmap_unload(void);
|
||||
|
||||
unsigned long stext_offset(void);
|
||||
|
||||
#endif /* _ASM_EFI_H */
|
||||
|
|
|
@ -23,13 +23,7 @@
|
|||
* linked at. The routines below are all implemented in assembler in a
|
||||
* position independent manner
|
||||
*/
|
||||
__efistub_memcmp = memcmp;
|
||||
__efistub_memchr = memchr;
|
||||
__efistub_strlen = strlen;
|
||||
__efistub_strnlen = strnlen;
|
||||
__efistub_strcmp = strcmp;
|
||||
__efistub_strncmp = strncmp;
|
||||
__efistub_strrchr = strrchr;
|
||||
|
||||
__efistub__start = _start;
|
||||
__efistub__start_kernel = _start_kernel;
|
||||
|
|
|
@ -1995,6 +1995,37 @@ config EFI_MIXED
|
|||
|
||||
If unsure, say N.
|
||||
|
||||
config EFI_FAKE_MEMMAP
|
||||
bool "Enable EFI fake memory map"
|
||||
depends on EFI
|
||||
help
|
||||
Saying Y here will enable "efi_fake_mem" boot option. By specifying
|
||||
this parameter, you can add arbitrary attribute to specific memory
|
||||
range by updating original (firmware provided) EFI memmap. This is
|
||||
useful for debugging of EFI memmap related feature, e.g., Address
|
||||
Range Mirroring feature.
|
||||
|
||||
config EFI_MAX_FAKE_MEM
|
||||
int "maximum allowable number of ranges in efi_fake_mem boot option"
|
||||
depends on EFI_FAKE_MEMMAP
|
||||
range 1 128
|
||||
default 8
|
||||
help
|
||||
Maximum allowable number of ranges in efi_fake_mem boot option.
|
||||
Ranges can be set up to this value using comma-separated list.
|
||||
The default value is 8.
|
||||
|
||||
config EFI_RUNTIME_MAP
|
||||
bool "Export EFI runtime maps to sysfs" if EXPERT
|
||||
depends on EFI
|
||||
default KEXEC_CORE
|
||||
help
|
||||
Export EFI runtime memory regions to /sys/firmware/efi/runtime-map.
|
||||
That memory map is required by the 2nd kernel to set up EFI virtual
|
||||
mappings after kexec, but can also be used for debugging purposes.
|
||||
|
||||
See also Documentation/ABI/testing/sysfs-firmware-efi-runtime-map.
|
||||
|
||||
source "kernel/Kconfig.hz"
|
||||
|
||||
config KEXEC
|
||||
|
|
|
@ -93,12 +93,6 @@ SYM_FUNC_START(__efi64_thunk)
|
|||
movl %ebx, %fs
|
||||
movl %ebx, %gs
|
||||
|
||||
/*
|
||||
* Convert 32-bit status code into 64-bit.
|
||||
*/
|
||||
roll $1, %eax
|
||||
rorq $1, %rax
|
||||
|
||||
pop %rbx
|
||||
pop %rbp
|
||||
RET
|
||||
|
|
|
@ -80,10 +80,11 @@ bs_die:
|
|||
ljmp $0xf000,$0xfff0
|
||||
|
||||
#ifdef CONFIG_EFI_STUB
|
||||
.org 0x3c
|
||||
.org 0x38
|
||||
#
|
||||
# Offset to the PE header.
|
||||
#
|
||||
.long LINUX_PE_MAGIC
|
||||
.long pe_header
|
||||
#endif /* CONFIG_EFI_STUB */
|
||||
|
||||
|
|
|
@ -178,7 +178,7 @@ struct efi_setup_data {
|
|||
extern u64 efi_setup;
|
||||
|
||||
#ifdef CONFIG_EFI
|
||||
extern efi_status_t __efi64_thunk(u32, ...);
|
||||
extern u64 __efi64_thunk(u32, ...);
|
||||
|
||||
#define efi64_thunk(...) ({ \
|
||||
u64 __pad[3]; /* must have space for 3 args on the stack */ \
|
||||
|
@ -228,16 +228,15 @@ static inline bool efi_is_native(void)
|
|||
return efi_is_64bit();
|
||||
}
|
||||
|
||||
#define efi_mixed_mode_cast(attr) \
|
||||
__builtin_choose_expr( \
|
||||
__builtin_types_compatible_p(u32, __typeof__(attr)), \
|
||||
(unsigned long)(attr), (attr))
|
||||
|
||||
#define efi_table_attr(inst, attr) \
|
||||
(efi_is_native() \
|
||||
? inst->attr \
|
||||
: (__typeof__(inst->attr)) \
|
||||
efi_mixed_mode_cast(inst->mixed_mode.attr))
|
||||
(efi_is_native() ? (inst)->attr \
|
||||
: efi_mixed_table_attr((inst), attr))
|
||||
|
||||
#define efi_mixed_table_attr(inst, attr) \
|
||||
(__typeof__(inst->attr)) \
|
||||
_Generic(inst->mixed_mode.attr, \
|
||||
u32: (unsigned long)(inst->mixed_mode.attr), \
|
||||
default: (inst->mixed_mode.attr))
|
||||
|
||||
/*
|
||||
* The following macros allow translating arguments if necessary from native to
|
||||
|
@ -325,6 +324,17 @@ static inline u32 efi64_convert_status(efi_status_t status)
|
|||
#define __efi64_argmap_set_memory_space_attributes(phys, size, flags) \
|
||||
(__efi64_split(phys), __efi64_split(size), __efi64_split(flags))
|
||||
|
||||
/* file protocol */
|
||||
#define __efi64_argmap_open(prot, newh, fname, mode, attr) \
|
||||
((prot), efi64_zero_upper(newh), (fname), __efi64_split(mode), \
|
||||
__efi64_split(attr))
|
||||
|
||||
#define __efi64_argmap_set_position(pos) (__efi64_split(pos))
|
||||
|
||||
/* file system protocol */
|
||||
#define __efi64_argmap_open_volume(prot, file) \
|
||||
((prot), efi64_zero_upper(file))
|
||||
|
||||
/*
|
||||
* The macros below handle the plumbing for the argument mapping. To add a
|
||||
* mapping for a specific EFI method, simply define a macro
|
||||
|
@ -344,31 +354,27 @@ static inline u32 efi64_convert_status(efi_status_t status)
|
|||
#define __efi_eat(...)
|
||||
#define __efi_eval(...) __VA_ARGS__
|
||||
|
||||
/* The three macros below handle dispatching via the thunk if needed */
|
||||
static inline efi_status_t __efi64_widen_efi_status(u64 status)
|
||||
{
|
||||
/* use rotate to move the value of bit #31 into position #63 */
|
||||
return ror64(rol32(status, 1), 1);
|
||||
}
|
||||
|
||||
#define efi_call_proto(inst, func, ...) \
|
||||
(efi_is_native() \
|
||||
? inst->func(inst, ##__VA_ARGS__) \
|
||||
: __efi64_thunk_map(inst, func, inst, ##__VA_ARGS__))
|
||||
/* The macro below handles dispatching via the thunk if needed */
|
||||
|
||||
#define efi_bs_call(func, ...) \
|
||||
(efi_is_native() \
|
||||
? efi_system_table->boottime->func(__VA_ARGS__) \
|
||||
: __efi64_thunk_map(efi_table_attr(efi_system_table, \
|
||||
boottime), \
|
||||
func, __VA_ARGS__))
|
||||
#define efi_fn_call(inst, func, ...) \
|
||||
(efi_is_native() ? (inst)->func(__VA_ARGS__) \
|
||||
: efi_mixed_call((inst), func, ##__VA_ARGS__))
|
||||
|
||||
#define efi_rt_call(func, ...) \
|
||||
(efi_is_native() \
|
||||
? efi_system_table->runtime->func(__VA_ARGS__) \
|
||||
: __efi64_thunk_map(efi_table_attr(efi_system_table, \
|
||||
runtime), \
|
||||
func, __VA_ARGS__))
|
||||
|
||||
#define efi_dxe_call(func, ...) \
|
||||
(efi_is_native() \
|
||||
? efi_dxe_table->func(__VA_ARGS__) \
|
||||
: __efi64_thunk_map(efi_dxe_table, func, __VA_ARGS__))
|
||||
#define efi_mixed_call(inst, func, ...) \
|
||||
_Generic(inst->func(__VA_ARGS__), \
|
||||
efi_status_t: \
|
||||
__efi64_widen_efi_status( \
|
||||
__efi64_thunk_map(inst, func, ##__VA_ARGS__)), \
|
||||
u64: ({ BUILD_BUG(); ULONG_MAX; }), \
|
||||
default: \
|
||||
(__typeof__(inst->func(__VA_ARGS__))) \
|
||||
__efi64_thunk_map(inst, func, ##__VA_ARGS__))
|
||||
|
||||
#else /* CONFIG_EFI_MIXED */
|
||||
|
||||
|
@ -400,13 +406,52 @@ static inline void efi_reserve_boot_services(void)
|
|||
|
||||
#ifdef CONFIG_EFI_FAKE_MEMMAP
|
||||
extern void __init efi_fake_memmap_early(void);
|
||||
extern void __init efi_fake_memmap(void);
|
||||
#else
|
||||
static inline void efi_fake_memmap_early(void)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void efi_fake_memmap(void)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
extern int __init efi_memmap_alloc(unsigned int num_entries,
|
||||
struct efi_memory_map_data *data);
|
||||
extern void __efi_memmap_free(u64 phys, unsigned long size,
|
||||
unsigned long flags);
|
||||
#define __efi_memmap_free __efi_memmap_free
|
||||
|
||||
extern int __init efi_memmap_install(struct efi_memory_map_data *data);
|
||||
extern int __init efi_memmap_split_count(efi_memory_desc_t *md,
|
||||
struct range *range);
|
||||
extern void __init efi_memmap_insert(struct efi_memory_map *old_memmap,
|
||||
void *buf, struct efi_mem_range *mem);
|
||||
|
||||
#define arch_ima_efi_boot_mode \
|
||||
({ extern struct boot_params boot_params; boot_params.secure_boot; })
|
||||
|
||||
#ifdef CONFIG_EFI_RUNTIME_MAP
|
||||
int efi_get_runtime_map_size(void);
|
||||
int efi_get_runtime_map_desc_size(void);
|
||||
int efi_runtime_map_copy(void *buf, size_t bufsz);
|
||||
#else
|
||||
static inline int efi_get_runtime_map_size(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int efi_get_runtime_map_desc_size(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int efi_runtime_map_copy(void *buf, size_t bufsz)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* _ASM_X86_EFI_H */
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include <xen/xen.h>
|
||||
|
||||
#include <asm/apic.h>
|
||||
#include <asm/efi.h>
|
||||
#include <asm/numa.h>
|
||||
#include <asm/bios_ebda.h>
|
||||
#include <asm/bugs.h>
|
||||
|
|
|
@ -2,5 +2,8 @@
|
|||
KASAN_SANITIZE := n
|
||||
GCOV_PROFILE := n
|
||||
|
||||
obj-$(CONFIG_EFI) += quirks.o efi.o efi_$(BITS).o efi_stub_$(BITS).o
|
||||
obj-$(CONFIG_EFI) += memmap.o quirks.o efi.o efi_$(BITS).o \
|
||||
efi_stub_$(BITS).o
|
||||
obj-$(CONFIG_EFI_MIXED) += efi_thunk_$(BITS).o
|
||||
obj-$(CONFIG_EFI_FAKE_MEMMAP) += fake_mem.o
|
||||
obj-$(CONFIG_EFI_RUNTIME_MAP) += runtime-map.o
|
||||
|
|
|
@ -214,9 +214,11 @@ int __init efi_memblock_x86_reserve_range(void)
|
|||
data.desc_size = e->efi_memdesc_size;
|
||||
data.desc_version = e->efi_memdesc_version;
|
||||
|
||||
rv = efi_memmap_init_early(&data);
|
||||
if (rv)
|
||||
return rv;
|
||||
if (!efi_enabled(EFI_PARAVIRT)) {
|
||||
rv = efi_memmap_init_early(&data);
|
||||
if (rv)
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (add_efi_memmap || do_efi_soft_reserve())
|
||||
do_add_efi_memmap();
|
||||
|
|
|
@ -17,10 +17,13 @@
|
|||
#include <linux/memblock.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/sort.h>
|
||||
#include "fake_mem.h"
|
||||
#include <asm/e820/api.h>
|
||||
#include <asm/efi.h>
|
||||
|
||||
struct efi_mem_range efi_fake_mems[EFI_MAX_FAKEMEM];
|
||||
int nr_fake_mem;
|
||||
#define EFI_MAX_FAKEMEM CONFIG_EFI_MAX_FAKE_MEM
|
||||
|
||||
static struct efi_mem_range efi_fake_mems[EFI_MAX_FAKEMEM];
|
||||
static int nr_fake_mem;
|
||||
|
||||
static int __init cmp_fake_mem(const void *x1, const void *x2)
|
||||
{
|
||||
|
@ -122,3 +125,73 @@ static int __init setup_fake_mem(char *p)
|
|||
}
|
||||
|
||||
early_param("efi_fake_mem", setup_fake_mem);
|
||||
|
||||
void __init efi_fake_memmap_early(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
/*
|
||||
* The late efi_fake_mem() call can handle all requests if
|
||||
* EFI_MEMORY_SP support is disabled.
|
||||
*/
|
||||
if (!efi_soft_reserve_enabled())
|
||||
return;
|
||||
|
||||
if (!efi_enabled(EFI_MEMMAP) || !nr_fake_mem)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Given that efi_fake_memmap() needs to perform memblock
|
||||
* allocations it needs to run after e820__memblock_setup().
|
||||
* However, if efi_fake_mem specifies EFI_MEMORY_SP for a given
|
||||
* address range that potentially needs to mark the memory as
|
||||
* reserved prior to e820__memblock_setup(). Update e820
|
||||
* directly if EFI_MEMORY_SP is specified for an
|
||||
* EFI_CONVENTIONAL_MEMORY descriptor.
|
||||
*/
|
||||
for (i = 0; i < nr_fake_mem; i++) {
|
||||
struct efi_mem_range *mem = &efi_fake_mems[i];
|
||||
efi_memory_desc_t *md;
|
||||
u64 m_start, m_end;
|
||||
|
||||
if ((mem->attribute & EFI_MEMORY_SP) == 0)
|
||||
continue;
|
||||
|
||||
m_start = mem->range.start;
|
||||
m_end = mem->range.end;
|
||||
for_each_efi_memory_desc(md) {
|
||||
u64 start, end, size;
|
||||
|
||||
if (md->type != EFI_CONVENTIONAL_MEMORY)
|
||||
continue;
|
||||
|
||||
start = md->phys_addr;
|
||||
end = md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT) - 1;
|
||||
|
||||
if (m_start <= end && m_end >= start)
|
||||
/* fake range overlaps descriptor */;
|
||||
else
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Trim the boundary of the e820 update to the
|
||||
* descriptor in case the fake range overlaps
|
||||
* !EFI_CONVENTIONAL_MEMORY
|
||||
*/
|
||||
start = max(start, m_start);
|
||||
end = min(end, m_end);
|
||||
size = end - start + 1;
|
||||
|
||||
if (end <= start)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Ensure each efi_fake_mem instance results in
|
||||
* a unique e820 resource
|
||||
*/
|
||||
e820__range_remove(start, size, E820_TYPE_RAM, 1);
|
||||
e820__range_add(start, size, E820_TYPE_SOFT_RESERVED);
|
||||
e820__update_table(e820_table);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,239 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Common EFI memory map functions.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "efi: " fmt
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/efi.h>
|
||||
#include <linux/io.h>
|
||||
#include <asm/early_ioremap.h>
|
||||
#include <asm/efi.h>
|
||||
#include <linux/memblock.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
static phys_addr_t __init __efi_memmap_alloc_early(unsigned long size)
|
||||
{
|
||||
return memblock_phys_alloc(size, SMP_CACHE_BYTES);
|
||||
}
|
||||
|
||||
static phys_addr_t __init __efi_memmap_alloc_late(unsigned long size)
|
||||
{
|
||||
unsigned int order = get_order(size);
|
||||
struct page *p = alloc_pages(GFP_KERNEL, order);
|
||||
|
||||
if (!p)
|
||||
return 0;
|
||||
|
||||
return PFN_PHYS(page_to_pfn(p));
|
||||
}
|
||||
|
||||
void __init __efi_memmap_free(u64 phys, unsigned long size, unsigned long flags)
|
||||
{
|
||||
if (flags & EFI_MEMMAP_MEMBLOCK) {
|
||||
if (slab_is_available())
|
||||
memblock_free_late(phys, size);
|
||||
else
|
||||
memblock_phys_free(phys, size);
|
||||
} else if (flags & EFI_MEMMAP_SLAB) {
|
||||
struct page *p = pfn_to_page(PHYS_PFN(phys));
|
||||
unsigned int order = get_order(size);
|
||||
|
||||
free_pages((unsigned long) page_address(p), order);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* efi_memmap_alloc - Allocate memory for the EFI memory map
|
||||
* @num_entries: Number of entries in the allocated map.
|
||||
* @data: efi memmap installation parameters
|
||||
*
|
||||
* Depending on whether mm_init() has already been invoked or not,
|
||||
* either memblock or "normal" page allocation is used.
|
||||
*
|
||||
* Returns zero on success, a negative error code on failure.
|
||||
*/
|
||||
int __init efi_memmap_alloc(unsigned int num_entries,
|
||||
struct efi_memory_map_data *data)
|
||||
{
|
||||
/* Expect allocation parameters are zero initialized */
|
||||
WARN_ON(data->phys_map || data->size);
|
||||
|
||||
data->size = num_entries * efi.memmap.desc_size;
|
||||
data->desc_version = efi.memmap.desc_version;
|
||||
data->desc_size = efi.memmap.desc_size;
|
||||
data->flags &= ~(EFI_MEMMAP_SLAB | EFI_MEMMAP_MEMBLOCK);
|
||||
data->flags |= efi.memmap.flags & EFI_MEMMAP_LATE;
|
||||
|
||||
if (slab_is_available()) {
|
||||
data->flags |= EFI_MEMMAP_SLAB;
|
||||
data->phys_map = __efi_memmap_alloc_late(data->size);
|
||||
} else {
|
||||
data->flags |= EFI_MEMMAP_MEMBLOCK;
|
||||
data->phys_map = __efi_memmap_alloc_early(data->size);
|
||||
}
|
||||
|
||||
if (!data->phys_map)
|
||||
return -ENOMEM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* efi_memmap_install - Install a new EFI memory map in efi.memmap
|
||||
* @ctx: map allocation parameters (address, size, flags)
|
||||
*
|
||||
* Unlike efi_memmap_init_*(), this function does not allow the caller
|
||||
* to switch from early to late mappings. It simply uses the existing
|
||||
* mapping function and installs the new memmap.
|
||||
*
|
||||
* Returns zero on success, a negative error code on failure.
|
||||
*/
|
||||
int __init efi_memmap_install(struct efi_memory_map_data *data)
|
||||
{
|
||||
efi_memmap_unmap();
|
||||
|
||||
if (efi_enabled(EFI_PARAVIRT))
|
||||
return 0;
|
||||
|
||||
return __efi_memmap_init(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* efi_memmap_split_count - Count number of additional EFI memmap entries
|
||||
* @md: EFI memory descriptor to split
|
||||
* @range: Address range (start, end) to split around
|
||||
*
|
||||
* Returns the number of additional EFI memmap entries required to
|
||||
* accommodate @range.
|
||||
*/
|
||||
int __init efi_memmap_split_count(efi_memory_desc_t *md, struct range *range)
|
||||
{
|
||||
u64 m_start, m_end;
|
||||
u64 start, end;
|
||||
int count = 0;
|
||||
|
||||
start = md->phys_addr;
|
||||
end = start + (md->num_pages << EFI_PAGE_SHIFT) - 1;
|
||||
|
||||
/* modifying range */
|
||||
m_start = range->start;
|
||||
m_end = range->end;
|
||||
|
||||
if (m_start <= start) {
|
||||
/* split into 2 parts */
|
||||
if (start < m_end && m_end < end)
|
||||
count++;
|
||||
}
|
||||
|
||||
if (start < m_start && m_start < end) {
|
||||
/* split into 3 parts */
|
||||
if (m_end < end)
|
||||
count += 2;
|
||||
/* split into 2 parts */
|
||||
if (end <= m_end)
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* efi_memmap_insert - Insert a memory region in an EFI memmap
|
||||
* @old_memmap: The existing EFI memory map structure
|
||||
* @buf: Address of buffer to store new map
|
||||
* @mem: Memory map entry to insert
|
||||
*
|
||||
* It is suggested that you call efi_memmap_split_count() first
|
||||
* to see how large @buf needs to be.
|
||||
*/
|
||||
void __init efi_memmap_insert(struct efi_memory_map *old_memmap, void *buf,
|
||||
struct efi_mem_range *mem)
|
||||
{
|
||||
u64 m_start, m_end, m_attr;
|
||||
efi_memory_desc_t *md;
|
||||
u64 start, end;
|
||||
void *old, *new;
|
||||
|
||||
/* modifying range */
|
||||
m_start = mem->range.start;
|
||||
m_end = mem->range.end;
|
||||
m_attr = mem->attribute;
|
||||
|
||||
/*
|
||||
* The EFI memory map deals with regions in EFI_PAGE_SIZE
|
||||
* units. Ensure that the region described by 'mem' is aligned
|
||||
* correctly.
|
||||
*/
|
||||
if (!IS_ALIGNED(m_start, EFI_PAGE_SIZE) ||
|
||||
!IS_ALIGNED(m_end + 1, EFI_PAGE_SIZE)) {
|
||||
WARN_ON(1);
|
||||
return;
|
||||
}
|
||||
|
||||
for (old = old_memmap->map, new = buf;
|
||||
old < old_memmap->map_end;
|
||||
old += old_memmap->desc_size, new += old_memmap->desc_size) {
|
||||
|
||||
/* copy original EFI memory descriptor */
|
||||
memcpy(new, old, old_memmap->desc_size);
|
||||
md = new;
|
||||
start = md->phys_addr;
|
||||
end = md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT) - 1;
|
||||
|
||||
if (m_start <= start && end <= m_end)
|
||||
md->attribute |= m_attr;
|
||||
|
||||
if (m_start <= start &&
|
||||
(start < m_end && m_end < end)) {
|
||||
/* first part */
|
||||
md->attribute |= m_attr;
|
||||
md->num_pages = (m_end - md->phys_addr + 1) >>
|
||||
EFI_PAGE_SHIFT;
|
||||
/* latter part */
|
||||
new += old_memmap->desc_size;
|
||||
memcpy(new, old, old_memmap->desc_size);
|
||||
md = new;
|
||||
md->phys_addr = m_end + 1;
|
||||
md->num_pages = (end - md->phys_addr + 1) >>
|
||||
EFI_PAGE_SHIFT;
|
||||
}
|
||||
|
||||
if ((start < m_start && m_start < end) && m_end < end) {
|
||||
/* first part */
|
||||
md->num_pages = (m_start - md->phys_addr) >>
|
||||
EFI_PAGE_SHIFT;
|
||||
/* middle part */
|
||||
new += old_memmap->desc_size;
|
||||
memcpy(new, old, old_memmap->desc_size);
|
||||
md = new;
|
||||
md->attribute |= m_attr;
|
||||
md->phys_addr = m_start;
|
||||
md->num_pages = (m_end - m_start + 1) >>
|
||||
EFI_PAGE_SHIFT;
|
||||
/* last part */
|
||||
new += old_memmap->desc_size;
|
||||
memcpy(new, old, old_memmap->desc_size);
|
||||
md = new;
|
||||
md->phys_addr = m_end + 1;
|
||||
md->num_pages = (end - m_end) >>
|
||||
EFI_PAGE_SHIFT;
|
||||
}
|
||||
|
||||
if ((start < m_start && m_start < end) &&
|
||||
(end <= m_end)) {
|
||||
/* first part */
|
||||
md->num_pages = (m_start - md->phys_addr) >>
|
||||
EFI_PAGE_SHIFT;
|
||||
/* latter part */
|
||||
new += old_memmap->desc_size;
|
||||
memcpy(new, old, old_memmap->desc_size);
|
||||
md = new;
|
||||
md->phys_addr = m_start;
|
||||
md->num_pages = (end - md->phys_addr + 1) >>
|
||||
EFI_PAGE_SHIFT;
|
||||
md->attribute |= m_attr;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,5 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* linux/drivers/efi/runtime-map.c
|
||||
* Copyright (C) 2013 Red Hat, Inc., Dave Young <dyoung@redhat.com>
|
||||
*/
|
||||
|
||||
|
@ -11,6 +10,7 @@
|
|||
#include <linux/efi.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <asm/efi.h>
|
||||
#include <asm/setup.h>
|
||||
|
||||
struct efi_runtime_map_entry {
|
||||
|
@ -157,13 +157,13 @@ int efi_runtime_map_copy(void *buf, size_t bufsz)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int __init efi_runtime_map_init(struct kobject *efi_kobj)
|
||||
static int __init efi_runtime_map_init(void)
|
||||
{
|
||||
int i, j, ret = 0;
|
||||
struct efi_runtime_map_entry *entry;
|
||||
efi_memory_desc_t *md;
|
||||
|
||||
if (!efi_enabled(EFI_MEMMAP))
|
||||
if (!efi_enabled(EFI_MEMMAP) || !efi_kobj)
|
||||
return 0;
|
||||
|
||||
map_entries = kcalloc(efi.memmap.nr_map, sizeof(entry), GFP_KERNEL);
|
||||
|
@ -191,3 +191,4 @@ out_add_entry:
|
|||
out:
|
||||
return ret;
|
||||
}
|
||||
subsys_initcall_sync(efi_runtime_map_init);
|
|
@ -26,39 +26,6 @@ config EFI_VARS_PSTORE_DEFAULT_DISABLE
|
|||
backend for pstore by default. This setting can be overridden
|
||||
using the efivars module's pstore_disable parameter.
|
||||
|
||||
config EFI_RUNTIME_MAP
|
||||
bool "Export efi runtime maps to sysfs"
|
||||
depends on X86 && EFI && KEXEC_CORE
|
||||
default y
|
||||
help
|
||||
Export efi runtime memory maps to /sys/firmware/efi/runtime-map.
|
||||
That memory map is used for example by kexec to set up efi virtual
|
||||
mapping the 2nd kernel, but can also be used for debugging purposes.
|
||||
|
||||
See also Documentation/ABI/testing/sysfs-firmware-efi-runtime-map.
|
||||
|
||||
config EFI_FAKE_MEMMAP
|
||||
bool "Enable EFI fake memory map"
|
||||
depends on EFI && X86
|
||||
default n
|
||||
help
|
||||
Saying Y here will enable "efi_fake_mem" boot option.
|
||||
By specifying this parameter, you can add arbitrary attribute
|
||||
to specific memory range by updating original (firmware provided)
|
||||
EFI memmap.
|
||||
This is useful for debugging of EFI memmap related feature.
|
||||
e.g. Address Range Mirroring feature.
|
||||
|
||||
config EFI_MAX_FAKE_MEM
|
||||
int "maximum allowable number of ranges in efi_fake_mem boot option"
|
||||
depends on EFI_FAKE_MEMMAP
|
||||
range 1 128
|
||||
default 8
|
||||
help
|
||||
Maximum allowable number of ranges in efi_fake_mem boot option.
|
||||
Ranges can be set up to this value using comma-separated list.
|
||||
The default value is 8.
|
||||
|
||||
config EFI_SOFT_RESERVE
|
||||
bool "Reserve EFI Specific Purpose Memory"
|
||||
depends on EFI && EFI_STUB && ACPI_HMAT
|
||||
|
@ -139,18 +106,6 @@ config EFI_ARMSTUB_DTB_LOADER
|
|||
functionality for bootloaders that do not have such support
|
||||
this option is necessary.
|
||||
|
||||
config EFI_GENERIC_STUB_INITRD_CMDLINE_LOADER
|
||||
bool "Enable the command line initrd loader" if !X86
|
||||
depends on EFI_STUB && (EFI_GENERIC_STUB || X86)
|
||||
default y if X86
|
||||
depends on !RISCV && !LOONGARCH
|
||||
help
|
||||
Select this config option to add support for the initrd= command
|
||||
line parameter, allowing an initrd that resides on the same volume
|
||||
as the kernel image to be loaded into memory.
|
||||
|
||||
This method is deprecated.
|
||||
|
||||
config EFI_BOOTLOADER_CONTROL
|
||||
tristate "EFI Bootloader Control"
|
||||
select UCS2_STRING
|
||||
|
|
|
@ -19,11 +19,9 @@ endif
|
|||
obj-$(CONFIG_EFI_PARAMS_FROM_FDT) += fdtparams.o
|
||||
obj-$(CONFIG_EFI_ESRT) += esrt.o
|
||||
obj-$(CONFIG_EFI_VARS_PSTORE) += efi-pstore.o
|
||||
obj-$(CONFIG_UEFI_CPER) += cper.o
|
||||
obj-$(CONFIG_EFI_RUNTIME_MAP) += runtime-map.o
|
||||
obj-$(CONFIG_UEFI_CPER) += cper.o cper_cxl.o
|
||||
obj-$(CONFIG_EFI_RUNTIME_WRAPPERS) += runtime-wrappers.o
|
||||
subdir-$(CONFIG_EFI_STUB) += libstub
|
||||
obj-$(CONFIG_EFI_FAKE_MEMMAP) += fake_map.o
|
||||
obj-$(CONFIG_EFI_BOOTLOADER_CONTROL) += efibc.o
|
||||
obj-$(CONFIG_EFI_TEST) += test/
|
||||
obj-$(CONFIG_EFI_DEV_PATH_PARSER) += dev-path-parser.o
|
||||
|
@ -32,9 +30,6 @@ obj-$(CONFIG_EFI_RCI2_TABLE) += rci2-table.o
|
|||
obj-$(CONFIG_EFI_EMBEDDED_FIRMWARE) += embedded-firmware.o
|
||||
obj-$(CONFIG_LOAD_UEFI_KEYS) += mokvar-table.o
|
||||
|
||||
fake_map-y += fake_mem.o
|
||||
fake_map-$(CONFIG_X86) += x86_fake_mem.o
|
||||
|
||||
obj-$(CONFIG_SYSFB) += sysfb_efi.o
|
||||
|
||||
arm-obj-$(CONFIG_EFI) := efi-init.o arm-runtime.o
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <linux/bcd.h>
|
||||
#include <acpi/ghes.h>
|
||||
#include <ras/ras_event.h>
|
||||
#include "cper_cxl.h"
|
||||
|
||||
/*
|
||||
* CPER record ID need to be unique even after reboot, because record
|
||||
|
@ -598,6 +599,14 @@ cper_estatus_print_section(const char *pfx, struct acpi_hest_generic_data *gdata
|
|||
cper_print_fw_err(newpfx, gdata, fw_err);
|
||||
else
|
||||
goto err_section_too_small;
|
||||
} else if (guid_equal(sec_type, &CPER_SEC_CXL_PROT_ERR)) {
|
||||
struct cper_sec_prot_err *prot_err = acpi_hest_get_payload(gdata);
|
||||
|
||||
printk("%ssection_type: CXL Protocol Error\n", newpfx);
|
||||
if (gdata->error_data_length >= sizeof(*prot_err))
|
||||
cper_print_prot_err(newpfx, prot_err);
|
||||
else
|
||||
goto err_section_too_small;
|
||||
} else {
|
||||
const void *err = acpi_hest_get_payload(gdata);
|
||||
|
||||
|
|
|
@ -0,0 +1,179 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* UEFI Common Platform Error Record (CPER) support for CXL Section.
|
||||
*
|
||||
* Copyright (C) 2022 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* Author: Smita Koralahalli <Smita.KoralahalliChannabasappa@amd.com>
|
||||
*/
|
||||
|
||||
#include <linux/cper.h>
|
||||
#include "cper_cxl.h"
|
||||
#include <linux/cxl_err.h>
|
||||
|
||||
#define PROT_ERR_VALID_AGENT_TYPE BIT_ULL(0)
|
||||
#define PROT_ERR_VALID_AGENT_ADDRESS BIT_ULL(1)
|
||||
#define PROT_ERR_VALID_DEVICE_ID BIT_ULL(2)
|
||||
#define PROT_ERR_VALID_SERIAL_NUMBER BIT_ULL(3)
|
||||
#define PROT_ERR_VALID_CAPABILITY BIT_ULL(4)
|
||||
#define PROT_ERR_VALID_DVSEC BIT_ULL(5)
|
||||
#define PROT_ERR_VALID_ERROR_LOG BIT_ULL(6)
|
||||
|
||||
static const char * const prot_err_agent_type_strs[] = {
|
||||
"Restricted CXL Device",
|
||||
"Restricted CXL Host Downstream Port",
|
||||
"CXL Device",
|
||||
"CXL Logical Device",
|
||||
"CXL Fabric Manager managed Logical Device",
|
||||
"CXL Root Port",
|
||||
"CXL Downstream Switch Port",
|
||||
"CXL Upstream Switch Port",
|
||||
};
|
||||
|
||||
/*
|
||||
* The layout of the enumeration and the values matches CXL Agent Type
|
||||
* field in the UEFI 2.10 Section N.2.13,
|
||||
*/
|
||||
enum {
|
||||
RCD, /* Restricted CXL Device */
|
||||
RCH_DP, /* Restricted CXL Host Downstream Port */
|
||||
DEVICE, /* CXL Device */
|
||||
LD, /* CXL Logical Device */
|
||||
FMLD, /* CXL Fabric Manager managed Logical Device */
|
||||
RP, /* CXL Root Port */
|
||||
DSP, /* CXL Downstream Switch Port */
|
||||
USP, /* CXL Upstream Switch Port */
|
||||
};
|
||||
|
||||
void cper_print_prot_err(const char *pfx, const struct cper_sec_prot_err *prot_err)
|
||||
{
|
||||
if (prot_err->valid_bits & PROT_ERR_VALID_AGENT_TYPE)
|
||||
pr_info("%s agent_type: %d, %s\n", pfx, prot_err->agent_type,
|
||||
prot_err->agent_type < ARRAY_SIZE(prot_err_agent_type_strs)
|
||||
? prot_err_agent_type_strs[prot_err->agent_type]
|
||||
: "unknown");
|
||||
|
||||
if (prot_err->valid_bits & PROT_ERR_VALID_AGENT_ADDRESS) {
|
||||
switch (prot_err->agent_type) {
|
||||
/*
|
||||
* According to UEFI 2.10 Section N.2.13, the term CXL Device
|
||||
* is used to refer to Restricted CXL Device, CXL Device, CXL
|
||||
* Logical Device or a CXL Fabric Manager Managed Logical
|
||||
* Device.
|
||||
*/
|
||||
case RCD:
|
||||
case DEVICE:
|
||||
case LD:
|
||||
case FMLD:
|
||||
case RP:
|
||||
case DSP:
|
||||
case USP:
|
||||
pr_info("%s agent_address: %04x:%02x:%02x.%x\n",
|
||||
pfx, prot_err->agent_addr.segment,
|
||||
prot_err->agent_addr.bus,
|
||||
prot_err->agent_addr.device,
|
||||
prot_err->agent_addr.function);
|
||||
break;
|
||||
case RCH_DP:
|
||||
pr_info("%s rcrb_base_address: 0x%016llx\n", pfx,
|
||||
prot_err->agent_addr.rcrb_base_addr);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (prot_err->valid_bits & PROT_ERR_VALID_DEVICE_ID) {
|
||||
const __u8 *class_code;
|
||||
|
||||
switch (prot_err->agent_type) {
|
||||
case RCD:
|
||||
case DEVICE:
|
||||
case LD:
|
||||
case FMLD:
|
||||
case RP:
|
||||
case DSP:
|
||||
case USP:
|
||||
pr_info("%s slot: %d\n", pfx,
|
||||
prot_err->device_id.slot >> CPER_PCIE_SLOT_SHIFT);
|
||||
pr_info("%s vendor_id: 0x%04x, device_id: 0x%04x\n",
|
||||
pfx, prot_err->device_id.vendor_id,
|
||||
prot_err->device_id.device_id);
|
||||
pr_info("%s sub_vendor_id: 0x%04x, sub_device_id: 0x%04x\n",
|
||||
pfx, prot_err->device_id.subsystem_vendor_id,
|
||||
prot_err->device_id.subsystem_id);
|
||||
class_code = prot_err->device_id.class_code;
|
||||
pr_info("%s class_code: %02x%02x\n", pfx,
|
||||
class_code[1], class_code[0]);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (prot_err->valid_bits & PROT_ERR_VALID_SERIAL_NUMBER) {
|
||||
switch (prot_err->agent_type) {
|
||||
case RCD:
|
||||
case DEVICE:
|
||||
case LD:
|
||||
case FMLD:
|
||||
pr_info("%s lower_dw: 0x%08x, upper_dw: 0x%08x\n", pfx,
|
||||
prot_err->dev_serial_num.lower_dw,
|
||||
prot_err->dev_serial_num.upper_dw);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (prot_err->valid_bits & PROT_ERR_VALID_CAPABILITY) {
|
||||
switch (prot_err->agent_type) {
|
||||
case RCD:
|
||||
case DEVICE:
|
||||
case LD:
|
||||
case FMLD:
|
||||
case RP:
|
||||
case DSP:
|
||||
case USP:
|
||||
print_hex_dump(pfx, "", DUMP_PREFIX_OFFSET, 16, 4,
|
||||
prot_err->capability,
|
||||
sizeof(prot_err->capability), 0);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (prot_err->valid_bits & PROT_ERR_VALID_DVSEC) {
|
||||
pr_info("%s DVSEC length: 0x%04x\n", pfx, prot_err->dvsec_len);
|
||||
|
||||
pr_info("%s CXL DVSEC:\n", pfx);
|
||||
print_hex_dump(pfx, "", DUMP_PREFIX_OFFSET, 16, 4, (prot_err + 1),
|
||||
prot_err->dvsec_len, 0);
|
||||
}
|
||||
|
||||
if (prot_err->valid_bits & PROT_ERR_VALID_ERROR_LOG) {
|
||||
size_t size = sizeof(*prot_err) + prot_err->dvsec_len;
|
||||
struct cxl_ras_capability_regs *cxl_ras;
|
||||
|
||||
pr_info("%s Error log length: 0x%04x\n", pfx, prot_err->err_len);
|
||||
|
||||
pr_info("%s CXL Error Log:\n", pfx);
|
||||
cxl_ras = (struct cxl_ras_capability_regs *)((long)prot_err + size);
|
||||
pr_info("%s cxl_ras_uncor_status: 0x%08x", pfx,
|
||||
cxl_ras->uncor_status);
|
||||
pr_info("%s cxl_ras_uncor_mask: 0x%08x\n", pfx,
|
||||
cxl_ras->uncor_mask);
|
||||
pr_info("%s cxl_ras_uncor_severity: 0x%08x\n", pfx,
|
||||
cxl_ras->uncor_severity);
|
||||
pr_info("%s cxl_ras_cor_status: 0x%08x", pfx,
|
||||
cxl_ras->cor_status);
|
||||
pr_info("%s cxl_ras_cor_mask: 0x%08x\n", pfx,
|
||||
cxl_ras->cor_mask);
|
||||
pr_info("%s cap_control: 0x%08x\n", pfx,
|
||||
cxl_ras->cap_control);
|
||||
pr_info("%s Header Log Registers:\n", pfx);
|
||||
print_hex_dump(pfx, "", DUMP_PREFIX_OFFSET, 16, 4, cxl_ras->header_log,
|
||||
sizeof(cxl_ras->header_log), 0);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* UEFI Common Platform Error Record (CPER) support for CXL Section.
|
||||
*
|
||||
* Copyright (C) 2022 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* Author: Smita Koralahalli <Smita.KoralahalliChannabasappa@amd.com>
|
||||
*/
|
||||
|
||||
#ifndef LINUX_CPER_CXL_H
|
||||
#define LINUX_CPER_CXL_H
|
||||
|
||||
/* CXL Protocol Error Section */
|
||||
#define CPER_SEC_CXL_PROT_ERR \
|
||||
GUID_INIT(0x80B9EFB4, 0x52B5, 0x4DE3, 0xA7, 0x77, 0x68, 0x78, \
|
||||
0x4B, 0x77, 0x10, 0x48)
|
||||
|
||||
#pragma pack(1)
|
||||
|
||||
/* Compute Express Link Protocol Error Section, UEFI v2.10 sec N.2.13 */
|
||||
struct cper_sec_prot_err {
|
||||
u64 valid_bits;
|
||||
u8 agent_type;
|
||||
u8 reserved[7];
|
||||
|
||||
/*
|
||||
* Except for RCH Downstream Port, all the remaining CXL Agent
|
||||
* types are uniquely identified by the PCIe compatible SBDF number.
|
||||
*/
|
||||
union {
|
||||
u64 rcrb_base_addr;
|
||||
struct {
|
||||
u8 function;
|
||||
u8 device;
|
||||
u8 bus;
|
||||
u16 segment;
|
||||
u8 reserved_1[3];
|
||||
};
|
||||
} agent_addr;
|
||||
|
||||
struct {
|
||||
u16 vendor_id;
|
||||
u16 device_id;
|
||||
u16 subsystem_vendor_id;
|
||||
u16 subsystem_id;
|
||||
u8 class_code[2];
|
||||
u16 slot;
|
||||
u8 reserved_1[4];
|
||||
} device_id;
|
||||
|
||||
struct {
|
||||
u32 lower_dw;
|
||||
u32 upper_dw;
|
||||
} dev_serial_num;
|
||||
|
||||
u8 capability[60];
|
||||
u16 dvsec_len;
|
||||
u16 err_len;
|
||||
u8 reserved_2[4];
|
||||
};
|
||||
|
||||
#pragma pack()
|
||||
|
||||
void cper_print_prot_err(const char *pfx, const struct cper_sec_prot_err *prot_err);
|
||||
|
||||
#endif //__CPER_CXL_
|
|
@ -22,6 +22,8 @@
|
|||
|
||||
#include <asm/efi.h>
|
||||
|
||||
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)
|
||||
|
|
|
@ -10,7 +10,9 @@ MODULE_IMPORT_NS(EFIVAR);
|
|||
|
||||
#define DUMP_NAME_LEN 66
|
||||
|
||||
#define EFIVARS_DATA_SIZE_MAX 1024
|
||||
static unsigned int record_size = 1024;
|
||||
module_param(record_size, uint, 0444);
|
||||
MODULE_PARM_DESC(record_size, "size of each pstore UEFI var (in bytes, min/default=1024)");
|
||||
|
||||
static bool efivars_pstore_disable =
|
||||
IS_ENABLED(CONFIG_EFI_VARS_PSTORE_DEFAULT_DISABLE);
|
||||
|
@ -30,7 +32,7 @@ static int efi_pstore_open(struct pstore_info *psi)
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
psi->data = kzalloc(EFIVARS_DATA_SIZE_MAX, GFP_KERNEL);
|
||||
psi->data = kzalloc(record_size, GFP_KERNEL);
|
||||
if (!psi->data)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -52,7 +54,7 @@ static inline u64 generic_id(u64 timestamp, unsigned int part, int count)
|
|||
static int efi_pstore_read_func(struct pstore_record *record,
|
||||
efi_char16_t *varname)
|
||||
{
|
||||
unsigned long wlen, size = EFIVARS_DATA_SIZE_MAX;
|
||||
unsigned long wlen, size = record_size;
|
||||
char name[DUMP_NAME_LEN], data_type;
|
||||
efi_status_t status;
|
||||
int cnt;
|
||||
|
@ -133,7 +135,7 @@ static ssize_t efi_pstore_read(struct pstore_record *record)
|
|||
efi_status_t status;
|
||||
|
||||
for (;;) {
|
||||
varname_size = EFIVARS_DATA_SIZE_MAX;
|
||||
varname_size = 1024;
|
||||
|
||||
/*
|
||||
* If this is the first read() call in the pstore enumeration,
|
||||
|
@ -224,11 +226,20 @@ static __init int efivars_pstore_init(void)
|
|||
if (efivars_pstore_disable)
|
||||
return 0;
|
||||
|
||||
efi_pstore_info.buf = kmalloc(4096, GFP_KERNEL);
|
||||
/*
|
||||
* Notice that 1024 is the minimum here to prevent issues with
|
||||
* decompression algorithms that were spotted during tests;
|
||||
* even in the case of not using compression, smaller values would
|
||||
* just pollute more the pstore FS with many small collected files.
|
||||
*/
|
||||
if (record_size < 1024)
|
||||
record_size = 1024;
|
||||
|
||||
efi_pstore_info.buf = kmalloc(record_size, GFP_KERNEL);
|
||||
if (!efi_pstore_info.buf)
|
||||
return -ENOMEM;
|
||||
|
||||
efi_pstore_info.bufsize = 1024;
|
||||
efi_pstore_info.bufsize = record_size;
|
||||
|
||||
if (pstore_register(&efi_pstore_info)) {
|
||||
kfree(efi_pstore_info.buf);
|
||||
|
|
|
@ -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),
|
||||
|
@ -412,10 +414,6 @@ static int __init efisubsys_init(void)
|
|||
goto err_unregister;
|
||||
}
|
||||
|
||||
error = efi_runtime_map_init(efi_kobj);
|
||||
if (error)
|
||||
goto err_remove_group;
|
||||
|
||||
/* and the standard mountpoint for efivarfs */
|
||||
error = sysfs_create_mount_point(efi_kobj, "efivars");
|
||||
if (error) {
|
||||
|
@ -442,6 +440,7 @@ err_unregister:
|
|||
generic_ops_unregister();
|
||||
err_put:
|
||||
kobject_put(efi_kobj);
|
||||
efi_kobj = NULL;
|
||||
destroy_workqueue(efi_rts_wq);
|
||||
return error;
|
||||
}
|
||||
|
@ -565,6 +564,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
|
||||
{},
|
||||
};
|
||||
|
@ -630,7 +632,7 @@ int __init efi_config_parse_tables(const efi_config_table_t *config_tables,
|
|||
|
||||
seed = early_memremap(efi_rng_seed, sizeof(*seed));
|
||||
if (seed != NULL) {
|
||||
size = min(seed->size, EFI_RANDOM_SEED_SIZE);
|
||||
size = min_t(u32, seed->size, SZ_1K); // sanity check
|
||||
early_memunmap(seed, sizeof(*seed));
|
||||
} else {
|
||||
pr_err("Could not map UEFI random seed!\n");
|
||||
|
@ -639,8 +641,8 @@ int __init efi_config_parse_tables(const efi_config_table_t *config_tables,
|
|||
seed = early_memremap(efi_rng_seed,
|
||||
sizeof(*seed) + size);
|
||||
if (seed != NULL) {
|
||||
pr_notice("seeding entropy pool\n");
|
||||
add_bootloader_randomness(seed->bits, size);
|
||||
memzero_explicit(seed->bits, size);
|
||||
early_memunmap(seed, sizeof(*seed) + size);
|
||||
} else {
|
||||
pr_err("Could not map UEFI random seed!\n");
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef __EFI_FAKE_MEM_H__
|
||||
#define __EFI_FAKE_MEM_H__
|
||||
#include <asm/efi.h>
|
||||
|
||||
#define EFI_MAX_FAKEMEM CONFIG_EFI_MAX_FAKE_MEM
|
||||
|
||||
extern struct efi_mem_range efi_fake_mems[EFI_MAX_FAKEMEM];
|
||||
extern int nr_fake_mem;
|
||||
#endif /* __EFI_FAKE_MEM_H__ */
|
|
@ -30,11 +30,13 @@ static __initconst const char name[][22] = {
|
|||
|
||||
static __initconst const struct {
|
||||
const char path[17];
|
||||
u8 paravirt;
|
||||
const char params[PARAMCOUNT][26];
|
||||
} dt_params[] = {
|
||||
{
|
||||
#ifdef CONFIG_XEN // <-------17------>
|
||||
.path = "/hypervisor/uefi",
|
||||
.paravirt = 1,
|
||||
.params = {
|
||||
[SYSTAB] = "xen,uefi-system-table",
|
||||
[MMBASE] = "xen,uefi-mmap-start",
|
||||
|
@ -121,6 +123,8 @@ u64 __init efi_get_fdt_params(struct efi_memory_map_data *mm)
|
|||
pr_err("Can't find property '%s' in DT!\n", pname);
|
||||
return 0;
|
||||
}
|
||||
if (dt_params[i].paravirt)
|
||||
set_bit(EFI_PARAVIRT, &efi.flags);
|
||||
return systab;
|
||||
}
|
||||
notfound:
|
||||
|
|
|
@ -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,21 +22,20 @@ 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) \
|
||||
-fno-unwind-tables -fno-asynchronous-unwind-tables \
|
||||
$(call cc-option,-mbranch-protection=none)
|
||||
cflags-$(CONFIG_ARM) := $(subst $(CC_FLAGS_FTRACE),,$(KBUILD_CFLAGS)) \
|
||||
-fno-builtin -fpic \
|
||||
cflags-$(CONFIG_ARM) += -DEFI_HAVE_STRLEN -DEFI_HAVE_STRNLEN \
|
||||
-DEFI_HAVE_MEMCHR -DEFI_HAVE_STRRCHR \
|
||||
-DEFI_HAVE_STRCMP -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 \
|
||||
|
@ -68,7 +71,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 \
|
||||
|
@ -80,13 +83,14 @@ 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 efi-stub-entry.o
|
||||
|
||||
lib-$(CONFIG_ARM) += arm32-stub.o
|
||||
lib-$(CONFIG_ARM64) += arm64-stub.o smbios.o
|
||||
lib-$(CONFIG_ARM64) += arm64.o arm64-stub.o arm64-entry.o smbios.o
|
||||
lib-$(CONFIG_X86) += x86-stub.o
|
||||
lib-$(CONFIG_RISCV) += riscv-stub.o
|
||||
lib-$(CONFIG_LOONGARCH) += loongarch-stub.o
|
||||
lib-$(CONFIG_RISCV) += riscv.o riscv-stub.o
|
||||
lib-$(CONFIG_LOONGARCH) += loongarch.o loongarch-stub.o
|
||||
|
||||
CFLAGS_arm32-stub.o := -DTEXT_OFFSET=$(TEXT_OFFSET)
|
||||
|
||||
|
@ -137,7 +141,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
|
||||
|
|
|
@ -10,18 +10,17 @@ comp-type-$(CONFIG_KERNEL_LZO) := lzo
|
|||
comp-type-$(CONFIG_KERNEL_XZ) := xzkern
|
||||
comp-type-$(CONFIG_KERNEL_ZSTD) := zstd22
|
||||
|
||||
# in GZIP, the appended le32 carrying the uncompressed size is part of the
|
||||
# format, but in other cases, we just append it at the end for convenience,
|
||||
# causing the original tools to complain when checking image integrity.
|
||||
# So disregard it when calculating the payload size in the zimage header.
|
||||
zboot-method-y := $(comp-type-y)_with_size
|
||||
zboot-size-len-y := 4
|
||||
|
||||
zboot-method-$(CONFIG_KERNEL_GZIP) := gzip
|
||||
zboot-size-len-$(CONFIG_KERNEL_GZIP) := 0
|
||||
# Copy the SizeOfHeaders, SizeOfCode and SizeOfImage fields from the payload to
|
||||
# the end of the compressed image. Note that this presupposes a PE header
|
||||
# offset of 64 bytes, which is what arm64, RISC-V and LoongArch use.
|
||||
quiet_cmd_compwithsize = $(quiet_cmd_$(comp-type-y))
|
||||
cmd_compwithsize = $(cmd_$(comp-type-y)) && ( \
|
||||
dd status=none if=$< bs=4 count=1 skip=37 ; \
|
||||
dd status=none if=$< bs=4 count=1 skip=23 ; \
|
||||
dd status=none if=$< bs=4 count=1 skip=36 ) >> $@
|
||||
|
||||
$(obj)/vmlinuz: $(obj)/$(EFI_ZBOOT_PAYLOAD) FORCE
|
||||
$(call if_changed,$(zboot-method-y))
|
||||
$(call if_changed,compwithsize)
|
||||
|
||||
OBJCOPYFLAGS_vmlinuz.o := -I binary -O $(EFI_ZBOOT_BFD_TARGET) \
|
||||
--rename-section .data=.gzdata,load,alloc,readonly,contents
|
||||
|
@ -30,7 +29,6 @@ $(obj)/vmlinuz.o: $(obj)/vmlinuz FORCE
|
|||
|
||||
AFLAGS_zboot-header.o += -DMACHINE_TYPE=IMAGE_FILE_MACHINE_$(EFI_ZBOOT_MACH_TYPE) \
|
||||
-DZBOOT_EFI_PATH="\"$(realpath $(obj)/vmlinuz.efi.elf)\"" \
|
||||
-DZBOOT_SIZE_LEN=$(zboot-size-len-y) \
|
||||
-DCOMP_TYPE="\"$(comp-type-y)\""
|
||||
|
||||
$(obj)/zboot-header.o: $(srctree)/drivers/firmware/efi/libstub/zboot-header.S FORCE
|
||||
|
@ -46,4 +44,4 @@ OBJCOPYFLAGS_vmlinuz.efi := -O binary
|
|||
$(obj)/vmlinuz.efi: $(obj)/vmlinuz.efi.elf FORCE
|
||||
$(call if_changed,objcopy)
|
||||
|
||||
targets += zboot-header.o vmlinuz vmlinuz.o vmlinuz.efi.elf vmlinuz.efi
|
||||
targets += zboot-header.o vmlinuz.o vmlinuz.efi.elf vmlinuz.efi
|
||||
|
|
|
@ -22,12 +22,15 @@
|
|||
* Return: status code
|
||||
*/
|
||||
efi_status_t efi_allocate_pages_aligned(unsigned long size, unsigned long *addr,
|
||||
unsigned long max, unsigned long align)
|
||||
unsigned long max, unsigned long align,
|
||||
int memory_type)
|
||||
{
|
||||
efi_physical_addr_t alloc_addr;
|
||||
efi_status_t status;
|
||||
int slack;
|
||||
|
||||
max = min(max, EFI_ALLOC_LIMIT);
|
||||
|
||||
if (align < EFI_ALLOC_ALIGN)
|
||||
align = EFI_ALLOC_ALIGN;
|
||||
|
||||
|
@ -36,7 +39,7 @@ efi_status_t efi_allocate_pages_aligned(unsigned long size, unsigned long *addr,
|
|||
slack = align / EFI_PAGE_SIZE - 1;
|
||||
|
||||
status = efi_bs_call(allocate_pages, EFI_ALLOCATE_MAX_ADDRESS,
|
||||
EFI_LOADER_DATA, size / EFI_PAGE_SIZE + slack,
|
||||
memory_type, size / EFI_PAGE_SIZE + slack,
|
||||
&alloc_addr);
|
||||
if (status != EFI_SUCCESS)
|
||||
return status;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* EFI entry point.
|
||||
*
|
||||
* Copyright (C) 2013, 2014 Red Hat, Inc.
|
||||
* Author: Mark Salter <msalter@redhat.com>
|
||||
*/
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/assembler.h>
|
||||
|
||||
/*
|
||||
* The entrypoint of a arm64 bare metal image is at offset #0 of the
|
||||
* image, so this is a reasonable default for primary_entry_offset.
|
||||
* Only when the EFI stub is integrated into the core kernel, it is not
|
||||
* guaranteed that the PE/COFF header has been copied to memory too, so
|
||||
* in this case, primary_entry_offset should be overridden by the
|
||||
* linker and point to primary_entry() directly.
|
||||
*/
|
||||
.weak primary_entry_offset
|
||||
|
||||
SYM_CODE_START(efi_enter_kernel)
|
||||
/*
|
||||
* efi_pe_entry() will have copied the kernel image if necessary and we
|
||||
* 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)
|
|
@ -11,52 +11,9 @@
|
|||
#include <asm/efi.h>
|
||||
#include <asm/memory.h>
|
||||
#include <asm/sections.h>
|
||||
#include <asm/sysreg.h>
|
||||
|
||||
#include "efistub.h"
|
||||
|
||||
static bool system_needs_vamap(void)
|
||||
{
|
||||
const u8 *type1_family = efi_get_smbios_string(1, family);
|
||||
|
||||
/*
|
||||
* Ampere Altra machines crash in SetTime() if SetVirtualAddressMap()
|
||||
* has not been called prior.
|
||||
*/
|
||||
if (!type1_family || strcmp(type1_family, "Altra"))
|
||||
return false;
|
||||
|
||||
efi_warn("Working around broken SetVirtualAddressMap()\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
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 && !system_needs_vamap())
|
||||
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
|
||||
|
@ -103,16 +60,7 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
|
|||
efi_status_t status;
|
||||
unsigned long kernel_size, kernel_memsize = 0;
|
||||
u32 phys_seed = 0;
|
||||
|
||||
/*
|
||||
* Although relocatable kernels can fix up the misalignment with
|
||||
* respect to MIN_KIMG_ALIGN, the resulting virtual text addresses are
|
||||
* subtly out of sync with those recorded in the vmlinux when kaslr is
|
||||
* disabled but the image required relocation anyway. Therefore retain
|
||||
* 2M alignment if KASLR was explicitly disabled, even if it was not
|
||||
* going to be activated to begin with.
|
||||
*/
|
||||
u64 min_kimg_align = efi_nokaslr ? MIN_KIMG_ALIGN : EFI_KIMG_ALIGN;
|
||||
u64 min_kimg_align = efi_get_kimg_min_align();
|
||||
|
||||
if (IS_ENABLED(CONFIG_RANDOMIZE_BASE)) {
|
||||
efi_guid_t li_fixed_proto = LINUX_EFI_LOADED_IMAGE_FIXED_GUID;
|
||||
|
@ -154,7 +102,8 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
|
|||
* locate the kernel at a randomized offset in physical memory.
|
||||
*/
|
||||
status = efi_random_alloc(*reserve_size, min_kimg_align,
|
||||
reserve_addr, phys_seed);
|
||||
reserve_addr, phys_seed,
|
||||
EFI_LOADER_CODE);
|
||||
if (status != EFI_SUCCESS)
|
||||
efi_warn("efi_random_alloc() failed: 0x%lx\n", status);
|
||||
} else {
|
||||
|
@ -164,18 +113,20 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
|
|||
if (status != EFI_SUCCESS) {
|
||||
if (!check_image_region((u64)_text, kernel_memsize)) {
|
||||
efi_err("FIRMWARE BUG: Image BSS overlaps adjacent EFI memory region\n");
|
||||
} else if (IS_ALIGNED((u64)_text, min_kimg_align)) {
|
||||
} else if (IS_ALIGNED((u64)_text, min_kimg_align) &&
|
||||
(u64)_end < EFI_ALLOC_LIMIT) {
|
||||
/*
|
||||
* Just execute from wherever we were loaded by the
|
||||
* UEFI PE/COFF loader if the alignment is suitable.
|
||||
* UEFI PE/COFF loader if the placement is suitable.
|
||||
*/
|
||||
*image_addr = (u64)_text;
|
||||
*reserve_size = 0;
|
||||
return EFI_SUCCESS;
|
||||
goto clean_image_to_poc;
|
||||
}
|
||||
|
||||
status = efi_allocate_pages_aligned(*reserve_size, reserve_addr,
|
||||
ULONG_MAX, min_kimg_align);
|
||||
ULONG_MAX, min_kimg_align,
|
||||
EFI_LOADER_CODE);
|
||||
|
||||
if (status != EFI_SUCCESS) {
|
||||
efi_err("Failed to relocate kernel\n");
|
||||
|
@ -187,5 +138,13 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
|
|||
*image_addr = *reserve_addr;
|
||||
memcpy((void *)*image_addr, _text, kernel_size);
|
||||
|
||||
clean_image_to_poc:
|
||||
/*
|
||||
* Clean the copied Image to the PoC, and ensure it is not shadowed by
|
||||
* stale icache entries from before relocation.
|
||||
*/
|
||||
dcache_clean_poc(*image_addr, *image_addr + kernel_size);
|
||||
asm("ic ialluis");
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2013, 2014 Linaro Ltd; <roy.franz@linaro.org>
|
||||
*
|
||||
* This file implements the EFI boot stub for the arm64 kernel.
|
||||
* Adapted from ARM version by Mark Salter <msalter@redhat.com>
|
||||
*/
|
||||
|
||||
|
||||
#include <linux/efi.h>
|
||||
#include <asm/efi.h>
|
||||
#include <asm/memory.h>
|
||||
#include <asm/sysreg.h>
|
||||
|
||||
#include "efistub.h"
|
||||
|
||||
static bool system_needs_vamap(void)
|
||||
{
|
||||
const u8 *type1_family = efi_get_smbios_string(1, family);
|
||||
|
||||
/*
|
||||
* Ampere Altra machines crash in SetTime() if SetVirtualAddressMap()
|
||||
* has not been called prior.
|
||||
*/
|
||||
if (!type1_family || strcmp(type1_family, "Altra"))
|
||||
return false;
|
||||
|
||||
efi_warn("Working around broken SetVirtualAddressMap()\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
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 && !system_needs_vamap())
|
||||
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();
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
#include <linux/efi.h>
|
||||
#include <asm/efi.h>
|
||||
|
||||
#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;
|
||||
}
|
|
@ -9,10 +9,8 @@
|
|||
|
||||
#include <linux/stdarg.h>
|
||||
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/efi.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/printk.h> /* For CONSOLE_LOGLEVEL_* */
|
||||
#include <asm/efi.h>
|
||||
#include <asm/setup.h>
|
||||
|
||||
|
@ -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
|
||||
|
@ -626,8 +483,8 @@ static const struct {
|
|||
|
||||
/**
|
||||
* efi_load_initrd_dev_path() - load the initrd from the Linux initrd device path
|
||||
* @load_addr: pointer to store the address where the initrd was loaded
|
||||
* @load_size: pointer to store the size of the loaded initrd
|
||||
* @initrd: pointer of struct to store the address where the initrd was loaded
|
||||
* and the size of the loaded initrd
|
||||
* @max: upper limit for the initrd memory allocation
|
||||
*
|
||||
* Return:
|
||||
|
@ -681,8 +538,7 @@ efi_status_t efi_load_initrd_cmdline(efi_loaded_image_t *image,
|
|||
unsigned long soft_limit,
|
||||
unsigned long hard_limit)
|
||||
{
|
||||
if (!IS_ENABLED(CONFIG_EFI_GENERIC_STUB_INITRD_CMDLINE_LOADER) ||
|
||||
(IS_ENABLED(CONFIG_X86) && (!efi_is_native() || image == NULL)))
|
||||
if (image == NULL)
|
||||
return EFI_UNSUPPORTED;
|
||||
|
||||
return handle_cmdline_files(image, L"initrd=", sizeof(L"initrd=") - 2,
|
||||
|
|
|
@ -35,15 +35,6 @@
|
|||
* as well to minimize the code churn.
|
||||
*/
|
||||
#define EFI_RT_VIRTUAL_BASE SZ_512M
|
||||
#define EFI_RT_VIRTUAL_SIZE SZ_512M
|
||||
|
||||
#ifdef CONFIG_ARM64
|
||||
# define EFI_RT_VIRTUAL_LIMIT DEFAULT_MAP_WINDOW_64
|
||||
#elif defined(CONFIG_RISCV) || defined(CONFIG_LOONGARCH)
|
||||
# define EFI_RT_VIRTUAL_LIMIT TASK_SIZE_MIN
|
||||
#else /* Only if TASK_SIZE is a constant */
|
||||
# define EFI_RT_VIRTUAL_LIMIT TASK_SIZE
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Some architectures map the EFI regions into the kernel's linear map using a
|
||||
|
@ -56,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;
|
||||
|
@ -115,62 +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_properties_table_t *prop_tbl;
|
||||
|
||||
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) ||
|
||||
|
@ -184,26 +143,35 @@ 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;
|
||||
|
||||
fail_free_cmdline:
|
||||
efi_bs_call(free_pool, cmdline_ptr);
|
||||
return status;
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
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_retrieve_tpm2_eventlog();
|
||||
|
||||
/* Ask the firmware to clear memory on unclean shutdown */
|
||||
|
@ -214,53 +182,15 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
|
|||
|
||||
efi_random_get_seed();
|
||||
|
||||
/*
|
||||
* If the NX PE data feature is enabled in the properties table, we
|
||||
* should take care not to create a virtual mapping that changes the
|
||||
* relative placement of runtime services code and data regions, as
|
||||
* they may belong to the same PE/COFF executable image in memory.
|
||||
* The easiest way to achieve that is to simply use a 1:1 mapping.
|
||||
*/
|
||||
prop_tbl = get_efi_config_table(EFI_PROPERTIES_TABLE_GUID);
|
||||
flat_va_mapping |= prop_tbl &&
|
||||
(prop_tbl->memory_protection_attribute &
|
||||
EFI_PROPERTIES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA);
|
||||
|
||||
/* force efi_novamap if SetVirtualAddressMap() is unsupported */
|
||||
efi_novamap |= !(get_supported_rt_services() &
|
||||
EFI_RT_SUPPORTED_SET_VIRTUAL_ADDRESS_MAP);
|
||||
|
||||
/* hibernation expects the runtime regions to stay in the same place */
|
||||
if (!IS_ENABLED(CONFIG_HIBERNATION) && !efi_nokaslr && !flat_va_mapping) {
|
||||
/*
|
||||
* Randomize the base of the UEFI runtime services region.
|
||||
* Preserve the 2 MB alignment of the region by taking a
|
||||
* shift of 21 bit positions into account when scaling
|
||||
* the headroom value using a 32-bit random value.
|
||||
*/
|
||||
static const u64 headroom = EFI_RT_VIRTUAL_LIMIT -
|
||||
EFI_RT_VIRTUAL_BASE -
|
||||
EFI_RT_VIRTUAL_SIZE;
|
||||
u32 rnd;
|
||||
|
||||
status = efi_get_random_bytes(sizeof(rnd), (u8 *)&rnd);
|
||||
if (status == EFI_SUCCESS) {
|
||||
virtmap_base = EFI_RT_VIRTUAL_BASE +
|
||||
(((headroom >> 21) * rnd) >> (32 - 21));
|
||||
}
|
||||
}
|
||||
|
||||
install_memreserve_table();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -29,6 +29,10 @@
|
|||
#define EFI_ALLOC_ALIGN EFI_PAGE_SIZE
|
||||
#endif
|
||||
|
||||
#ifndef EFI_ALLOC_LIMIT
|
||||
#define EFI_ALLOC_LIMIT ULONG_MAX
|
||||
#endif
|
||||
|
||||
extern bool efi_nochunk;
|
||||
extern bool efi_nokaslr;
|
||||
extern int efi_loglevel;
|
||||
|
@ -44,15 +48,23 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
|
|||
|
||||
#ifndef ARCH_HAS_EFISTUB_WRAPPERS
|
||||
|
||||
#define efi_is_native() (true)
|
||||
#define efi_bs_call(func, ...) efi_system_table->boottime->func(__VA_ARGS__)
|
||||
#define efi_rt_call(func, ...) efi_system_table->runtime->func(__VA_ARGS__)
|
||||
#define efi_dxe_call(func, ...) efi_dxe_table->func(__VA_ARGS__)
|
||||
#define efi_table_attr(inst, attr) (inst->attr)
|
||||
#define efi_call_proto(inst, func, ...) inst->func(inst, ##__VA_ARGS__)
|
||||
#define efi_is_native() (true)
|
||||
#define efi_table_attr(inst, attr) (inst)->attr
|
||||
#define efi_fn_call(inst, func, ...) (inst)->func(__VA_ARGS__)
|
||||
|
||||
#endif
|
||||
|
||||
#define efi_call_proto(inst, func, ...) ({ \
|
||||
__typeof__(inst) __inst = (inst); \
|
||||
efi_fn_call(__inst, func, __inst, ##__VA_ARGS__); \
|
||||
})
|
||||
#define efi_bs_call(func, ...) \
|
||||
efi_fn_call(efi_table_attr(efi_system_table, boottime), func, ##__VA_ARGS__)
|
||||
#define efi_rt_call(func, ...) \
|
||||
efi_fn_call(efi_table_attr(efi_system_table, runtime), func, ##__VA_ARGS__)
|
||||
#define efi_dxe_call(func, ...) \
|
||||
efi_fn_call(efi_dxe_table, func, ##__VA_ARGS__)
|
||||
|
||||
#define efi_info(fmt, ...) \
|
||||
efi_printk(KERN_INFO fmt, ##__VA_ARGS__)
|
||||
#define efi_warn(fmt, ...) \
|
||||
|
@ -179,6 +191,21 @@ union efi_device_path_to_text_protocol {
|
|||
|
||||
typedef union efi_device_path_to_text_protocol efi_device_path_to_text_protocol_t;
|
||||
|
||||
union efi_device_path_from_text_protocol {
|
||||
struct {
|
||||
efi_device_path_protocol_t *
|
||||
(__efiapi *convert_text_to_device_node)(const efi_char16_t *);
|
||||
efi_device_path_protocol_t *
|
||||
(__efiapi *convert_text_to_device_path)(const efi_char16_t *);
|
||||
};
|
||||
struct {
|
||||
u32 convert_text_to_device_node;
|
||||
u32 convert_text_to_device_path;
|
||||
} mixed_mode;
|
||||
};
|
||||
|
||||
typedef union efi_device_path_from_text_protocol efi_device_path_from_text_protocol_t;
|
||||
|
||||
typedef void *efi_event_t;
|
||||
/* Note that notifications won't work in mixed mode */
|
||||
typedef void (__efiapi *efi_event_notify_t)(efi_event_t, void *);
|
||||
|
@ -572,36 +599,63 @@ typedef struct {
|
|||
efi_char16_t filename[];
|
||||
} efi_file_info_t;
|
||||
|
||||
typedef struct efi_file_protocol efi_file_protocol_t;
|
||||
typedef union efi_file_protocol efi_file_protocol_t;
|
||||
|
||||
struct efi_file_protocol {
|
||||
u64 revision;
|
||||
efi_status_t (__efiapi *open) (efi_file_protocol_t *,
|
||||
efi_file_protocol_t **,
|
||||
efi_char16_t *, u64, u64);
|
||||
efi_status_t (__efiapi *close) (efi_file_protocol_t *);
|
||||
efi_status_t (__efiapi *delete) (efi_file_protocol_t *);
|
||||
efi_status_t (__efiapi *read) (efi_file_protocol_t *,
|
||||
unsigned long *, void *);
|
||||
efi_status_t (__efiapi *write) (efi_file_protocol_t *,
|
||||
unsigned long, void *);
|
||||
efi_status_t (__efiapi *get_position)(efi_file_protocol_t *, u64 *);
|
||||
efi_status_t (__efiapi *set_position)(efi_file_protocol_t *, u64);
|
||||
efi_status_t (__efiapi *get_info) (efi_file_protocol_t *,
|
||||
efi_guid_t *, unsigned long *,
|
||||
void *);
|
||||
efi_status_t (__efiapi *set_info) (efi_file_protocol_t *,
|
||||
efi_guid_t *, unsigned long,
|
||||
void *);
|
||||
efi_status_t (__efiapi *flush) (efi_file_protocol_t *);
|
||||
union efi_file_protocol {
|
||||
struct {
|
||||
u64 revision;
|
||||
efi_status_t (__efiapi *open) (efi_file_protocol_t *,
|
||||
efi_file_protocol_t **,
|
||||
efi_char16_t *, u64,
|
||||
u64);
|
||||
efi_status_t (__efiapi *close) (efi_file_protocol_t *);
|
||||
efi_status_t (__efiapi *delete) (efi_file_protocol_t *);
|
||||
efi_status_t (__efiapi *read) (efi_file_protocol_t *,
|
||||
unsigned long *,
|
||||
void *);
|
||||
efi_status_t (__efiapi *write) (efi_file_protocol_t *,
|
||||
unsigned long, void *);
|
||||
efi_status_t (__efiapi *get_position)(efi_file_protocol_t *,
|
||||
u64 *);
|
||||
efi_status_t (__efiapi *set_position)(efi_file_protocol_t *,
|
||||
u64);
|
||||
efi_status_t (__efiapi *get_info) (efi_file_protocol_t *,
|
||||
efi_guid_t *,
|
||||
unsigned long *,
|
||||
void *);
|
||||
efi_status_t (__efiapi *set_info) (efi_file_protocol_t *,
|
||||
efi_guid_t *,
|
||||
unsigned long,
|
||||
void *);
|
||||
efi_status_t (__efiapi *flush) (efi_file_protocol_t *);
|
||||
};
|
||||
struct {
|
||||
u64 revision;
|
||||
u32 open;
|
||||
u32 close;
|
||||
u32 delete;
|
||||
u32 read;
|
||||
u32 write;
|
||||
u32 get_position;
|
||||
u32 set_position;
|
||||
u32 get_info;
|
||||
u32 set_info;
|
||||
u32 flush;
|
||||
} mixed_mode;
|
||||
};
|
||||
|
||||
typedef struct efi_simple_file_system_protocol efi_simple_file_system_protocol_t;
|
||||
typedef union efi_simple_file_system_protocol efi_simple_file_system_protocol_t;
|
||||
|
||||
struct efi_simple_file_system_protocol {
|
||||
u64 revision;
|
||||
int (__efiapi *open_volume)(efi_simple_file_system_protocol_t *,
|
||||
efi_file_protocol_t **);
|
||||
union efi_simple_file_system_protocol {
|
||||
struct {
|
||||
u64 revision;
|
||||
efi_status_t (__efiapi *open_volume)(efi_simple_file_system_protocol_t *,
|
||||
efi_file_protocol_t **);
|
||||
};
|
||||
struct {
|
||||
u64 revision;
|
||||
u32 open_volume;
|
||||
} mixed_mode;
|
||||
};
|
||||
|
||||
#define EFI_FILE_MODE_READ 0x0000000000000001
|
||||
|
@ -880,7 +934,10 @@ void efi_get_virtmap(efi_memory_desc_t *memory_map, unsigned long map_size,
|
|||
efi_status_t efi_get_random_bytes(unsigned long size, u8 *out);
|
||||
|
||||
efi_status_t efi_random_alloc(unsigned long size, unsigned long align,
|
||||
unsigned long *addr, unsigned long random_seed);
|
||||
unsigned long *addr, unsigned long random_seed,
|
||||
int memory_type);
|
||||
|
||||
efi_status_t efi_random_get_seed(void);
|
||||
|
||||
efi_status_t check_platform_features(void);
|
||||
|
||||
|
@ -905,7 +962,8 @@ efi_status_t efi_allocate_pages(unsigned long size, unsigned long *addr,
|
|||
unsigned long max);
|
||||
|
||||
efi_status_t efi_allocate_pages_aligned(unsigned long size, unsigned long *addr,
|
||||
unsigned long max, unsigned long align);
|
||||
unsigned long max, unsigned long align,
|
||||
int memory_type);
|
||||
|
||||
efi_status_t efi_low_alloc_above(unsigned long size, unsigned long align,
|
||||
unsigned long *addr, unsigned long min);
|
||||
|
@ -958,6 +1016,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);
|
||||
|
@ -975,6 +1041,13 @@ 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);
|
||||
|
||||
void efi_cache_sync_image(unsigned long image_base,
|
||||
unsigned long alloc_size,
|
||||
unsigned long code_size);
|
||||
|
||||
struct efi_smbios_record {
|
||||
u8 type;
|
||||
u8 length;
|
||||
|
|
|
@ -43,18 +43,26 @@ static efi_status_t efi_open_file(efi_file_protocol_t *volume,
|
|||
efi_file_protocol_t *fh;
|
||||
unsigned long info_sz;
|
||||
efi_status_t status;
|
||||
efi_char16_t *c;
|
||||
|
||||
status = volume->open(volume, &fh, fi->filename, EFI_FILE_MODE_READ, 0);
|
||||
/* Replace UNIX dir separators with EFI standard ones */
|
||||
for (c = fi->filename; *c != L'\0'; c++) {
|
||||
if (*c == L'/')
|
||||
*c = L'\\';
|
||||
}
|
||||
|
||||
status = efi_call_proto(volume, open, &fh, fi->filename,
|
||||
EFI_FILE_MODE_READ, 0);
|
||||
if (status != EFI_SUCCESS) {
|
||||
efi_err("Failed to open file: %ls\n", fi->filename);
|
||||
return status;
|
||||
}
|
||||
|
||||
info_sz = sizeof(struct finfo);
|
||||
status = fh->get_info(fh, &info_guid, &info_sz, fi);
|
||||
status = efi_call_proto(fh, get_info, &info_guid, &info_sz, fi);
|
||||
if (status != EFI_SUCCESS) {
|
||||
efi_err("Failed to get file info\n");
|
||||
fh->close(fh);
|
||||
efi_call_proto(fh, close);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
@ -66,36 +74,18 @@ static efi_status_t efi_open_file(efi_file_protocol_t *volume,
|
|||
static efi_status_t efi_open_volume(efi_loaded_image_t *image,
|
||||
efi_file_protocol_t **fh)
|
||||
{
|
||||
struct efi_vendor_dev_path *dp = image->file_path;
|
||||
efi_guid_t li_proto = LOADED_IMAGE_PROTOCOL_GUID;
|
||||
efi_guid_t fs_proto = EFI_FILE_SYSTEM_GUID;
|
||||
efi_simple_file_system_protocol_t *io;
|
||||
efi_status_t status;
|
||||
|
||||
// If we are using EFI zboot, we should look for the file system
|
||||
// protocol on the parent image's handle instead
|
||||
if (IS_ENABLED(CONFIG_EFI_ZBOOT) &&
|
||||
image->parent_handle != NULL &&
|
||||
dp != NULL &&
|
||||
dp->header.type == EFI_DEV_MEDIA &&
|
||||
dp->header.sub_type == EFI_DEV_MEDIA_VENDOR &&
|
||||
!efi_guidcmp(dp->vendorguid, LINUX_EFI_ZBOOT_MEDIA_GUID)) {
|
||||
status = efi_bs_call(handle_protocol, image->parent_handle,
|
||||
&li_proto, (void *)&image);
|
||||
if (status != EFI_SUCCESS) {
|
||||
efi_err("Failed to locate parent image handle\n");
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
status = efi_bs_call(handle_protocol, image->device_handle, &fs_proto,
|
||||
(void **)&io);
|
||||
status = efi_bs_call(handle_protocol, efi_table_attr(image, device_handle),
|
||||
&fs_proto, (void **)&io);
|
||||
if (status != EFI_SUCCESS) {
|
||||
efi_err("Failed to handle fs_proto\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
status = io->open_volume(io, fh);
|
||||
status = efi_call_proto(io, open_volume, fh);
|
||||
if (status != EFI_SUCCESS)
|
||||
efi_err("Failed to open volume\n");
|
||||
|
||||
|
@ -129,16 +119,62 @@ static int find_file_option(const efi_char16_t *cmdline, int cmdline_len,
|
|||
|
||||
if (c == L'\0' || c == L'\n' || c == L' ')
|
||||
break;
|
||||
else if (c == L'/')
|
||||
/* Replace UNIX dir separators with EFI standard ones */
|
||||
*result++ = L'\\';
|
||||
else
|
||||
*result++ = c;
|
||||
*result++ = c;
|
||||
}
|
||||
*result = L'\0';
|
||||
return i;
|
||||
}
|
||||
|
||||
static efi_status_t efi_open_device_path(efi_file_protocol_t **volume,
|
||||
struct finfo *fi)
|
||||
{
|
||||
efi_guid_t text_to_dp_guid = EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL_GUID;
|
||||
static efi_device_path_from_text_protocol_t *text_to_dp = NULL;
|
||||
efi_guid_t fs_proto = EFI_FILE_SYSTEM_GUID;
|
||||
efi_device_path_protocol_t *initrd_dp;
|
||||
efi_simple_file_system_protocol_t *io;
|
||||
struct efi_file_path_dev_path *fpath;
|
||||
efi_handle_t handle;
|
||||
efi_status_t status;
|
||||
|
||||
/* See if the text to device path protocol exists */
|
||||
if (!text_to_dp &&
|
||||
efi_bs_call(locate_protocol, &text_to_dp_guid, NULL,
|
||||
(void **)&text_to_dp) != EFI_SUCCESS)
|
||||
return EFI_UNSUPPORTED;
|
||||
|
||||
|
||||
/* Convert the filename wide string into a device path */
|
||||
initrd_dp = efi_fn_call(text_to_dp, convert_text_to_device_path,
|
||||
fi->filename);
|
||||
|
||||
/* Check whether the device path in question implements simple FS */
|
||||
if ((efi_bs_call(locate_device_path, &fs_proto, &initrd_dp, &handle) ?:
|
||||
efi_bs_call(handle_protocol, handle, &fs_proto, (void **)&io))
|
||||
!= EFI_SUCCESS)
|
||||
return EFI_NOT_FOUND;
|
||||
|
||||
/* Check whether the remaining device path is a file device path */
|
||||
if (initrd_dp->type != EFI_DEV_MEDIA ||
|
||||
initrd_dp->sub_type != EFI_DEV_MEDIA_FILE) {
|
||||
efi_warn("Unexpected device path node type: (%x, %x)\n",
|
||||
initrd_dp->type, initrd_dp->sub_type);
|
||||
return EFI_LOAD_ERROR;
|
||||
}
|
||||
|
||||
/* Copy the remaining file path into the fi structure */
|
||||
fpath = (struct efi_file_path_dev_path *)initrd_dp;
|
||||
memcpy(fi->filename, fpath->filename,
|
||||
min(sizeof(fi->filename),
|
||||
fpath->header.length - sizeof(fpath->header)));
|
||||
|
||||
status = efi_call_proto(io, open_volume, volume);
|
||||
if (status != EFI_SUCCESS)
|
||||
efi_err("Failed to open volume\n");
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check the cmdline for a LILO-style file= arguments.
|
||||
*
|
||||
|
@ -153,8 +189,8 @@ efi_status_t handle_cmdline_files(efi_loaded_image_t *image,
|
|||
unsigned long *load_addr,
|
||||
unsigned long *load_size)
|
||||
{
|
||||
const efi_char16_t *cmdline = image->load_options;
|
||||
u32 cmdline_len = image->load_options_size;
|
||||
const efi_char16_t *cmdline = efi_table_attr(image, load_options);
|
||||
u32 cmdline_len = efi_table_attr(image, load_options_size);
|
||||
unsigned long efi_chunk_size = ULONG_MAX;
|
||||
efi_file_protocol_t *volume = NULL;
|
||||
efi_file_protocol_t *file;
|
||||
|
@ -188,11 +224,13 @@ efi_status_t handle_cmdline_files(efi_loaded_image_t *image,
|
|||
cmdline += offset;
|
||||
cmdline_len -= offset;
|
||||
|
||||
if (!volume) {
|
||||
status = efi_open_device_path(&volume, &fi);
|
||||
if (status == EFI_UNSUPPORTED || status == EFI_NOT_FOUND)
|
||||
/* try the volume that holds the kernel itself */
|
||||
status = efi_open_volume(image, &volume);
|
||||
if (status != EFI_SUCCESS)
|
||||
return status;
|
||||
}
|
||||
|
||||
if (status != EFI_SUCCESS)
|
||||
goto err_free_alloc;
|
||||
|
||||
status = efi_open_file(volume, &fi, &file, &size);
|
||||
if (status != EFI_SUCCESS)
|
||||
|
@ -240,7 +278,7 @@ efi_status_t handle_cmdline_files(efi_loaded_image_t *image,
|
|||
while (size) {
|
||||
unsigned long chunksize = min(size, efi_chunk_size);
|
||||
|
||||
status = file->read(file, &chunksize, addr);
|
||||
status = efi_call_proto(file, read, &chunksize, addr);
|
||||
if (status != EFI_SUCCESS) {
|
||||
efi_err("Failed to read file\n");
|
||||
goto err_close_file;
|
||||
|
@ -248,24 +286,24 @@ efi_status_t handle_cmdline_files(efi_loaded_image_t *image,
|
|||
addr += chunksize;
|
||||
size -= chunksize;
|
||||
}
|
||||
file->close(file);
|
||||
efi_call_proto(file, close);
|
||||
efi_call_proto(volume, close);
|
||||
} while (offset > 0);
|
||||
|
||||
*load_addr = alloc_addr;
|
||||
*load_size = alloc_size;
|
||||
|
||||
if (volume)
|
||||
volume->close(volume);
|
||||
|
||||
if (*load_size == 0)
|
||||
return EFI_NOT_READY;
|
||||
return EFI_SUCCESS;
|
||||
|
||||
err_close_file:
|
||||
file->close(file);
|
||||
efi_call_proto(file, close);
|
||||
|
||||
err_close_volume:
|
||||
volume->close(volume);
|
||||
efi_call_proto(volume, close);
|
||||
|
||||
err_free_alloc:
|
||||
efi_free(alloc_size, alloc_addr);
|
||||
return status;
|
||||
}
|
||||
|
|
|
@ -28,3 +28,21 @@ void *memset(void *dst, int c, size_t len)
|
|||
efi_bs_call(set_mem, dst, len, c & U8_MAX);
|
||||
return dst;
|
||||
}
|
||||
|
||||
/**
|
||||
* memcmp - Compare two areas of memory
|
||||
* @cs: One area of memory
|
||||
* @ct: Another area of memory
|
||||
* @count: The size of the area.
|
||||
*/
|
||||
#undef memcmp
|
||||
int memcmp(const void *cs, const void *ct, size_t count)
|
||||
{
|
||||
const unsigned char *su1, *su2;
|
||||
int res = 0;
|
||||
|
||||
for (su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--)
|
||||
if ((res = *su1 - *su2) != 0)
|
||||
break;
|
||||
return res;
|
||||
}
|
||||
|
|
|
@ -9,18 +9,10 @@
|
|||
#include <asm/addrspace.h>
|
||||
#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,
|
||||
|
@ -29,74 +21,33 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
|
|||
efi_loaded_image_t *image,
|
||||
efi_handle_t image_handle)
|
||||
{
|
||||
int nr_pages = round_up(kernel_asize, EFI_ALLOC_ALIGN) / EFI_PAGE_SIZE;
|
||||
efi_physical_addr_t kernel_addr = EFI_KIMG_PREFERRED_ADDRESS;
|
||||
efi_status_t status;
|
||||
unsigned long kernel_addr = 0;
|
||||
|
||||
kernel_addr = (unsigned long)&kernel_offset - kernel_offset;
|
||||
/*
|
||||
* Allocate space for the kernel image at the preferred offset. This is
|
||||
* the only location in memory from where we can execute the image, so
|
||||
* no point in falling back to another allocation.
|
||||
*/
|
||||
status = efi_bs_call(allocate_pages, EFI_ALLOCATE_ADDRESS,
|
||||
EFI_LOADER_DATA, nr_pages, &kernel_addr);
|
||||
if (status != EFI_SUCCESS)
|
||||
return status;
|
||||
|
||||
status = efi_relocate_kernel(&kernel_addr, kernel_fsize, kernel_asize,
|
||||
PHYSADDR(VMLINUX_LOAD_ADDRESS), SZ_2M, 0x0);
|
||||
|
||||
*image_addr = kernel_addr;
|
||||
*image_addr = EFI_KIMG_PREFERRED_ADDRESS;
|
||||
*image_size = kernel_asize;
|
||||
|
||||
memcpy((void *)EFI_KIMG_PREFERRED_ADDRESS,
|
||||
(void *)&kernel_offset - kernel_offset,
|
||||
kernel_fsize);
|
||||
|
||||
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)
|
||||
unsigned long kernel_entry_address(void)
|
||||
{
|
||||
struct exit_boot_struct *p = priv;
|
||||
unsigned long base = (unsigned long)&kernel_offset - kernel_offset;
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
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 = (kernel_entry_t)
|
||||
((unsigned long)&kernel_entry - kernel_addr + VMLINUX_LOAD_ADDRESS);
|
||||
|
||||
real_kernel_entry(true, (unsigned long)cmdline_ptr,
|
||||
(unsigned long)efi_system_table);
|
||||
return (unsigned long)&kernel_entry - base + VMLINUX_LOAD_ADDRESS;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Author: Yun Liu <liuyun@loongson.cn>
|
||||
* Huacai Chen <chenhuacai@loongson.cn>
|
||||
* Copyright (C) 2020-2022 Loongson Technology Corporation Limited
|
||||
*/
|
||||
|
||||
#include <asm/efi.h>
|
||||
#include <asm/addrspace.h>
|
||||
#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);
|
||||
}
|
|
@ -89,9 +89,12 @@ efi_status_t efi_allocate_pages(unsigned long size, unsigned long *addr,
|
|||
efi_physical_addr_t alloc_addr;
|
||||
efi_status_t status;
|
||||
|
||||
max = min(max, EFI_ALLOC_LIMIT);
|
||||
|
||||
if (EFI_ALLOC_ALIGN > EFI_PAGE_SIZE)
|
||||
return efi_allocate_pages_aligned(size, addr, max,
|
||||
EFI_ALLOC_ALIGN);
|
||||
EFI_ALLOC_ALIGN,
|
||||
EFI_LOADER_DATA);
|
||||
|
||||
alloc_addr = ALIGN_DOWN(max + 1, EFI_ALLOC_ALIGN) - 1;
|
||||
status = efi_bs_call(allocate_pages, EFI_ALLOCATE_MAX_ADDRESS,
|
||||
|
|
|
@ -0,0 +1,154 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
#include <linux/stdarg.h>
|
||||
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/efi.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/printk.h> /* For CONSOLE_LOGLEVEL_* */
|
||||
#include <asm/efi.h>
|
||||
#include <asm/setup.h>
|
||||
|
||||
#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;
|
||||
}
|
|
@ -67,47 +67,113 @@ efi_status_t efi_random_get_seed(void)
|
|||
efi_guid_t rng_proto = EFI_RNG_PROTOCOL_GUID;
|
||||
efi_guid_t rng_algo_raw = EFI_RNG_ALGORITHM_RAW;
|
||||
efi_guid_t rng_table_guid = LINUX_EFI_RANDOM_SEED_TABLE_GUID;
|
||||
struct linux_efi_random_seed *prev_seed, *seed = NULL;
|
||||
int prev_seed_size = 0, seed_size = EFI_RANDOM_SEED_SIZE;
|
||||
unsigned long nv_seed_size = 0, offset = 0;
|
||||
efi_rng_protocol_t *rng = NULL;
|
||||
struct linux_efi_random_seed *seed = NULL;
|
||||
efi_status_t status;
|
||||
|
||||
status = efi_bs_call(locate_protocol, &rng_proto, NULL, (void **)&rng);
|
||||
if (status != EFI_SUCCESS)
|
||||
seed_size = 0;
|
||||
|
||||
// Call GetVariable() with a zero length buffer to obtain the size
|
||||
get_efi_var(L"RandomSeed", &rng_table_guid, NULL, &nv_seed_size, NULL);
|
||||
if (!seed_size && !nv_seed_size)
|
||||
return status;
|
||||
|
||||
seed_size += nv_seed_size;
|
||||
|
||||
/*
|
||||
* Check whether a seed was provided by a prior boot stage. In that
|
||||
* case, instead of overwriting it, let's create a new buffer that can
|
||||
* hold both, and concatenate the existing and the new seeds.
|
||||
* Note that we should read the seed size with caution, in case the
|
||||
* table got corrupted in memory somehow.
|
||||
*/
|
||||
prev_seed = get_efi_config_table(rng_table_guid);
|
||||
if (prev_seed && prev_seed->size <= 512U) {
|
||||
prev_seed_size = prev_seed->size;
|
||||
seed_size += prev_seed_size;
|
||||
}
|
||||
|
||||
/*
|
||||
* Use EFI_ACPI_RECLAIM_MEMORY here so that it is guaranteed that the
|
||||
* allocation will survive a kexec reboot (although we refresh the seed
|
||||
* beforehand)
|
||||
*/
|
||||
status = efi_bs_call(allocate_pool, EFI_ACPI_RECLAIM_MEMORY,
|
||||
sizeof(*seed) + EFI_RANDOM_SEED_SIZE,
|
||||
struct_size(seed, bits, seed_size),
|
||||
(void **)&seed);
|
||||
if (status != EFI_SUCCESS)
|
||||
return status;
|
||||
if (status != EFI_SUCCESS) {
|
||||
efi_warn("Failed to allocate memory for RNG seed.\n");
|
||||
goto err_warn;
|
||||
}
|
||||
|
||||
status = efi_call_proto(rng, get_rng, &rng_algo_raw,
|
||||
EFI_RANDOM_SEED_SIZE, seed->bits);
|
||||
|
||||
if (status == EFI_UNSUPPORTED)
|
||||
/*
|
||||
* Use whatever algorithm we have available if the raw algorithm
|
||||
* is not implemented.
|
||||
*/
|
||||
status = efi_call_proto(rng, get_rng, NULL,
|
||||
if (rng) {
|
||||
status = efi_call_proto(rng, get_rng, &rng_algo_raw,
|
||||
EFI_RANDOM_SEED_SIZE, seed->bits);
|
||||
|
||||
if (status != EFI_SUCCESS)
|
||||
if (status == EFI_UNSUPPORTED)
|
||||
/*
|
||||
* Use whatever algorithm we have available if the raw algorithm
|
||||
* is not implemented.
|
||||
*/
|
||||
status = efi_call_proto(rng, get_rng, NULL,
|
||||
EFI_RANDOM_SEED_SIZE, seed->bits);
|
||||
|
||||
if (status == EFI_SUCCESS)
|
||||
offset = EFI_RANDOM_SEED_SIZE;
|
||||
}
|
||||
|
||||
if (nv_seed_size) {
|
||||
status = get_efi_var(L"RandomSeed", &rng_table_guid, NULL,
|
||||
&nv_seed_size, seed->bits + offset);
|
||||
|
||||
if (status == EFI_SUCCESS)
|
||||
/*
|
||||
* We delete the seed here, and /hope/ that this causes
|
||||
* EFI to also zero out its representation on disk.
|
||||
* This is somewhat idealistic, but overwriting the
|
||||
* variable with zeros is likely just as fraught too.
|
||||
* TODO: in the future, maybe we can hash it forward
|
||||
* instead, and write a new seed.
|
||||
*/
|
||||
status = set_efi_var(L"RandomSeed", &rng_table_guid, 0,
|
||||
0, NULL);
|
||||
|
||||
if (status == EFI_SUCCESS)
|
||||
offset += nv_seed_size;
|
||||
else
|
||||
memzero_explicit(seed->bits + offset, nv_seed_size);
|
||||
}
|
||||
|
||||
if (!offset)
|
||||
goto err_freepool;
|
||||
|
||||
seed->size = EFI_RANDOM_SEED_SIZE;
|
||||
if (prev_seed_size) {
|
||||
memcpy(seed->bits + offset, prev_seed->bits, prev_seed_size);
|
||||
offset += prev_seed_size;
|
||||
}
|
||||
|
||||
seed->size = offset;
|
||||
status = efi_bs_call(install_configuration_table, &rng_table_guid, seed);
|
||||
if (status != EFI_SUCCESS)
|
||||
goto err_freepool;
|
||||
|
||||
if (prev_seed_size) {
|
||||
/* wipe and free the old seed if we managed to install the new one */
|
||||
memzero_explicit(prev_seed->bits, prev_seed_size);
|
||||
efi_bs_call(free_pool, prev_seed);
|
||||
}
|
||||
return EFI_SUCCESS;
|
||||
|
||||
err_freepool:
|
||||
memzero_explicit(seed, struct_size(seed, bits, seed_size));
|
||||
efi_bs_call(free_pool, seed);
|
||||
efi_warn("Failed to obtain seed from EFI_RNG_PROTOCOL or EFI variable\n");
|
||||
err_warn:
|
||||
if (prev_seed)
|
||||
efi_warn("Retaining bootloader-supplied seed only");
|
||||
return status;
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ static unsigned long get_entry_num_slots(efi_memory_desc_t *md,
|
|||
return 0;
|
||||
|
||||
region_end = min(md->phys_addr + md->num_pages * EFI_PAGE_SIZE - 1,
|
||||
(u64)ULONG_MAX);
|
||||
(u64)EFI_ALLOC_LIMIT);
|
||||
if (region_end < size)
|
||||
return 0;
|
||||
|
||||
|
@ -53,7 +53,8 @@ static unsigned long get_entry_num_slots(efi_memory_desc_t *md,
|
|||
efi_status_t efi_random_alloc(unsigned long size,
|
||||
unsigned long align,
|
||||
unsigned long *addr,
|
||||
unsigned long random_seed)
|
||||
unsigned long random_seed,
|
||||
int memory_type)
|
||||
{
|
||||
unsigned long total_slots = 0, target_slot;
|
||||
unsigned long total_mirrored_slots = 0;
|
||||
|
@ -118,7 +119,7 @@ efi_status_t efi_random_alloc(unsigned long size,
|
|||
pages = size / EFI_PAGE_SIZE;
|
||||
|
||||
status = efi_bs_call(allocate_pages, EFI_ALLOCATE_ADDRESS,
|
||||
EFI_LOADER_DATA, pages, &target);
|
||||
memory_type, pages, &target);
|
||||
if (status == EFI_SUCCESS)
|
||||
*addr = target;
|
||||
break;
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
*/
|
||||
|
||||
#include <linux/efi.h>
|
||||
#include <linux/libfdt.h>
|
||||
|
||||
#include <asm/efi.h>
|
||||
#include <asm/sections.h>
|
||||
|
@ -12,92 +11,16 @@
|
|||
|
||||
#include "efistub.h"
|
||||
|
||||
/*
|
||||
* RISC-V requires the kernel image to placed 2 MB aligned base for 64 bit and
|
||||
* 4MB for 32 bit.
|
||||
*/
|
||||
#ifdef CONFIG_64BIT
|
||||
#define MIN_KIMG_ALIGN SZ_2M
|
||||
#else
|
||||
#define MIN_KIMG_ALIGN SZ_4M
|
||||
#endif
|
||||
|
||||
typedef void __noreturn (*jump_kernel_func)(unsigned long, unsigned long);
|
||||
|
||||
static unsigned long hartid;
|
||||
|
||||
static int get_boot_hartid_from_fdt(void)
|
||||
unsigned long stext_offset(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;
|
||||
}
|
||||
|
||||
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,
|
||||
|
@ -125,9 +48,10 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
|
|||
* lowest possible memory region as long as the address and size meets
|
||||
* the alignment constraints.
|
||||
*/
|
||||
preferred_addr = MIN_KIMG_ALIGN;
|
||||
preferred_addr = EFI_KIMG_PREFERRED_ADDRESS;
|
||||
status = efi_relocate_kernel(image_addr, kernel_size, *image_size,
|
||||
preferred_addr, MIN_KIMG_ALIGN, 0x0);
|
||||
preferred_addr, efi_get_kimg_min_align(),
|
||||
0x0);
|
||||
|
||||
if (status != EFI_SUCCESS) {
|
||||
efi_err("Failed to relocate kernel\n");
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2020 Western Digital Corporation or its affiliates.
|
||||
*/
|
||||
|
||||
#include <linux/efi.h>
|
||||
#include <linux/libfdt.h>
|
||||
|
||||
#include <asm/efi.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#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);
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
#include <linux/efi.h>
|
||||
#include <asm/efi.h>
|
||||
|
||||
#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);
|
||||
}
|
|
@ -11,7 +11,37 @@
|
|||
#include <linux/types.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
#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,9 +63,29 @@ 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
|
||||
|
||||
#ifndef __HAVE_ARCH_STRNCMP
|
||||
/**
|
||||
* strncmp - Compare two length-limited strings
|
||||
* @cs: One string
|
||||
|
@ -57,7 +107,6 @@ int strncmp(const char *cs, const char *ct, size_t count)
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Works only for digits and letters, but small and fast */
|
||||
#define TOLOWER(x) ((x) | 0x20)
|
||||
|
@ -113,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
|
||||
|
|
|
@ -17,10 +17,11 @@ __efistub_efi_zboot_header:
|
|||
.long MZ_MAGIC
|
||||
.ascii "zimg" // image type
|
||||
.long __efistub__gzdata_start - .Ldoshdr // payload offset
|
||||
.long __efistub__gzdata_size - ZBOOT_SIZE_LEN // payload size
|
||||
.long __efistub__gzdata_size - 12 // payload size
|
||||
.long 0, 0 // reserved
|
||||
.asciz COMP_TYPE // compression type
|
||||
.org .Ldoshdr + 0x3c
|
||||
.org .Ldoshdr + 0x38
|
||||
.long LINUX_PE_MAGIC
|
||||
.long .Lpehdr - .Ldoshdr // PE header offset
|
||||
|
||||
.Lpehdr:
|
||||
|
|
|
@ -32,271 +32,116 @@ 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);
|
||||
}
|
||||
|
||||
// Local version to avoid pulling in memcmp()
|
||||
static bool guids_eq(const efi_guid_t *a, const efi_guid_t *b)
|
||||
static unsigned long alloc_preferred_address(unsigned long alloc_size)
|
||||
{
|
||||
const u32 *l = (u32 *)a;
|
||||
const u32 *r = (u32 *)b;
|
||||
#ifdef EFI_KIMG_PREFERRED_ADDRESS
|
||||
efi_physical_addr_t efi_addr = EFI_KIMG_PREFERRED_ADDRESS;
|
||||
|
||||
return l[0] == r[0] && l[1] == r[1] && l[2] == r[2] && l[3] == r[3];
|
||||
if (efi_bs_call(allocate_pages, EFI_ALLOCATE_ADDRESS, EFI_LOADER_DATA,
|
||||
alloc_size / EFI_PAGE_SIZE, &efi_addr) == EFI_SUCCESS)
|
||||
return efi_addr;
|
||||
#endif
|
||||
return ULONG_MAX;
|
||||
}
|
||||
|
||||
static efi_status_t __efiapi
|
||||
load_file(efi_load_file_protocol_t *this, efi_device_path_protocol_t *rem,
|
||||
bool boot_policy, unsigned long *bufsize, void *buffer)
|
||||
void __weak efi_cache_sync_image(unsigned long image_base,
|
||||
unsigned long alloc_size,
|
||||
unsigned long code_size)
|
||||
{
|
||||
unsigned long compressed_size = _gzdata_end - _gzdata_start;
|
||||
struct efi_vendor_dev_path *vendor_dp;
|
||||
bool decompress = false;
|
||||
unsigned long size;
|
||||
int ret;
|
||||
|
||||
if (rem == NULL || bufsize == NULL)
|
||||
return EFI_INVALID_PARAMETER;
|
||||
|
||||
if (boot_policy)
|
||||
return EFI_UNSUPPORTED;
|
||||
|
||||
// Look for our vendor media device node in the remaining file path
|
||||
if (rem->type == EFI_DEV_MEDIA &&
|
||||
rem->sub_type == EFI_DEV_MEDIA_VENDOR) {
|
||||
vendor_dp = container_of(rem, struct efi_vendor_dev_path, header);
|
||||
if (!guids_eq(&vendor_dp->vendorguid, &LINUX_EFI_ZBOOT_MEDIA_GUID))
|
||||
return EFI_NOT_FOUND;
|
||||
|
||||
decompress = true;
|
||||
rem = (void *)(vendor_dp + 1);
|
||||
}
|
||||
|
||||
if (rem->type != EFI_DEV_END_PATH ||
|
||||
rem->sub_type != EFI_DEV_END_ENTIRE)
|
||||
return EFI_NOT_FOUND;
|
||||
|
||||
// The uncompressed size of the payload is appended to the raw bit
|
||||
// stream, and may therefore appear misaligned in memory
|
||||
size = decompress ? get_unaligned_le32(_gzdata_end - 4)
|
||||
: compressed_size;
|
||||
if (buffer == NULL || *bufsize < size) {
|
||||
*bufsize = size;
|
||||
return EFI_BUFFER_TOO_SMALL;
|
||||
}
|
||||
|
||||
if (decompress) {
|
||||
ret = __decompress(_gzdata_start, compressed_size, NULL, NULL,
|
||||
buffer, size, NULL, error);
|
||||
if (ret < 0) {
|
||||
log(L"Decompression failed");
|
||||
return EFI_DEVICE_ERROR;
|
||||
}
|
||||
} else {
|
||||
memcpy(buffer, _gzdata_start, compressed_size);
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
// Return the length in bytes of the device path up to the first end node.
|
||||
static int device_path_length(const efi_device_path_protocol_t *dp)
|
||||
{
|
||||
int len = 0;
|
||||
|
||||
while (dp->type != EFI_DEV_END_PATH) {
|
||||
len += dp->length;
|
||||
dp = (void *)((u8 *)dp + dp->length);
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
static void append_rel_offset_node(efi_device_path_protocol_t **dp,
|
||||
unsigned long start, unsigned long end)
|
||||
{
|
||||
struct efi_rel_offset_dev_path *rodp = (void *)*dp;
|
||||
|
||||
rodp->header.type = EFI_DEV_MEDIA;
|
||||
rodp->header.sub_type = EFI_DEV_MEDIA_REL_OFFSET;
|
||||
rodp->header.length = sizeof(struct efi_rel_offset_dev_path);
|
||||
rodp->reserved = 0;
|
||||
rodp->starting_offset = start;
|
||||
rodp->ending_offset = end;
|
||||
|
||||
*dp = (void *)(rodp + 1);
|
||||
}
|
||||
|
||||
static void append_ven_media_node(efi_device_path_protocol_t **dp,
|
||||
efi_guid_t *guid)
|
||||
{
|
||||
struct efi_vendor_dev_path *vmdp = (void *)*dp;
|
||||
|
||||
vmdp->header.type = EFI_DEV_MEDIA;
|
||||
vmdp->header.sub_type = EFI_DEV_MEDIA_VENDOR;
|
||||
vmdp->header.length = sizeof(struct efi_vendor_dev_path);
|
||||
vmdp->vendorguid = *guid;
|
||||
|
||||
*dp = (void *)(vmdp + 1);
|
||||
}
|
||||
|
||||
static void append_end_node(efi_device_path_protocol_t **dp)
|
||||
{
|
||||
(*dp)->type = EFI_DEV_END_PATH;
|
||||
(*dp)->sub_type = EFI_DEV_END_ENTIRE;
|
||||
(*dp)->length = sizeof(struct efi_generic_dev_path);
|
||||
|
||||
++*dp;
|
||||
// Provided by the arch to perform the cache maintenance necessary for
|
||||
// executable code loaded into memory to be safe for execution.
|
||||
}
|
||||
|
||||
asmlinkage efi_status_t __efiapi
|
||||
efi_zboot_entry(efi_handle_t handle, efi_system_table_t *systab)
|
||||
{
|
||||
struct efi_mem_mapped_dev_path mmdp = {
|
||||
.header.type = EFI_DEV_HW,
|
||||
.header.sub_type = EFI_DEV_MEM_MAPPED,
|
||||
.header.length = sizeof(struct efi_mem_mapped_dev_path)
|
||||
};
|
||||
efi_device_path_protocol_t *parent_dp, *dpp, *lf2_dp, *li_dp;
|
||||
efi_load_file2_protocol_t zboot_load_file2;
|
||||
efi_loaded_image_t *parent, *child;
|
||||
unsigned long exit_data_size;
|
||||
efi_handle_t child_handle;
|
||||
efi_handle_t zboot_handle;
|
||||
efi_char16_t *exit_data;
|
||||
unsigned long compressed_size = _gzdata_end - _gzdata_start;
|
||||
unsigned long image_base, alloc_size, code_size;
|
||||
efi_loaded_image_t *image;
|
||||
efi_status_t status;
|
||||
void *dp_alloc;
|
||||
int dp_len;
|
||||
char *cmdline_ptr;
|
||||
int ret;
|
||||
|
||||
WRITE_ONCE(efi_system_table, systab);
|
||||
|
||||
free_mem_ptr = (unsigned long)&zboot_heap;
|
||||
free_mem_end_ptr = free_mem_ptr + sizeof(zboot_heap);
|
||||
|
||||
exit_data = NULL;
|
||||
exit_data_size = 0;
|
||||
|
||||
status = efi_bs_call(handle_protocol, handle,
|
||||
&LOADED_IMAGE_PROTOCOL_GUID, (void **)&parent);
|
||||
&LOADED_IMAGE_PROTOCOL_GUID, (void **)&image);
|
||||
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;
|
||||
}
|
||||
|
||||
status = efi_bs_call(handle_protocol, handle,
|
||||
&LOADED_IMAGE_DEVICE_PATH_PROTOCOL_GUID,
|
||||
(void **)&parent_dp);
|
||||
if (status != EFI_SUCCESS || parent_dp == NULL) {
|
||||
// Create a MemoryMapped() device path node to describe
|
||||
// the parent image if no device path was provided.
|
||||
mmdp.memory_type = parent->image_code_type;
|
||||
mmdp.starting_addr = (unsigned long)parent->image_base;
|
||||
mmdp.ending_addr = (unsigned long)parent->image_base +
|
||||
parent->image_size - 1;
|
||||
parent_dp = &mmdp.header;
|
||||
dp_len = sizeof(mmdp);
|
||||
} else {
|
||||
dp_len = device_path_length(parent_dp);
|
||||
}
|
||||
|
||||
// Allocate some pool memory for device path protocol data
|
||||
status = efi_bs_call(allocate_pool, EFI_LOADER_DATA,
|
||||
2 * (dp_len + sizeof(struct efi_rel_offset_dev_path) +
|
||||
sizeof(struct efi_generic_dev_path)) +
|
||||
sizeof(struct efi_vendor_dev_path),
|
||||
(void **)&dp_alloc);
|
||||
if (status != EFI_SUCCESS) {
|
||||
log(L"Failed to allocate device path pool memory");
|
||||
status = efi_handle_cmdline(image, &cmdline_ptr);
|
||||
if (status != EFI_SUCCESS)
|
||||
return status;
|
||||
|
||||
efi_info("Decompressing Linux Kernel...\n");
|
||||
|
||||
// SizeOfImage from the compressee's PE/COFF header
|
||||
alloc_size = round_up(get_unaligned_le32(_gzdata_end - 4),
|
||||
EFI_ALLOC_ALIGN);
|
||||
|
||||
// SizeOfHeaders and SizeOfCode from the compressee's PE/COFF header
|
||||
code_size = get_unaligned_le32(_gzdata_end - 8) +
|
||||
get_unaligned_le32(_gzdata_end - 12);
|
||||
|
||||
// If the architecture has a preferred address for the image,
|
||||
// try that first.
|
||||
image_base = alloc_preferred_address(alloc_size);
|
||||
if (image_base == ULONG_MAX) {
|
||||
unsigned long min_kimg_align = efi_get_kimg_min_align();
|
||||
u32 seed = U32_MAX;
|
||||
|
||||
if (!IS_ENABLED(CONFIG_RANDOMIZE_BASE)) {
|
||||
// Setting the random seed to 0x0 is the same as
|
||||
// allocating as low as possible
|
||||
seed = 0;
|
||||
} else if (efi_nokaslr) {
|
||||
efi_info("KASLR disabled on kernel command line\n");
|
||||
} else {
|
||||
status = efi_get_random_bytes(sizeof(seed), (u8 *)&seed);
|
||||
if (status == EFI_NOT_FOUND) {
|
||||
efi_info("EFI_RNG_PROTOCOL unavailable\n");
|
||||
efi_nokaslr = true;
|
||||
} else if (status != EFI_SUCCESS) {
|
||||
efi_err("efi_get_random_bytes() failed (0x%lx)\n",
|
||||
status);
|
||||
efi_nokaslr = true;
|
||||
}
|
||||
}
|
||||
|
||||
status = efi_random_alloc(alloc_size, min_kimg_align, &image_base,
|
||||
seed, EFI_LOADER_CODE);
|
||||
if (status != EFI_SUCCESS) {
|
||||
efi_err("Failed to allocate memory\n");
|
||||
goto free_cmdline;
|
||||
}
|
||||
}
|
||||
|
||||
// Create a device path describing the compressed payload in this image
|
||||
// <...parent_dp...>/Offset(<start>, <end>)
|
||||
lf2_dp = memcpy(dp_alloc, parent_dp, dp_len);
|
||||
dpp = (void *)((u8 *)lf2_dp + dp_len);
|
||||
append_rel_offset_node(&dpp,
|
||||
(unsigned long)(_gzdata_start - efi_zboot_header),
|
||||
(unsigned long)(_gzdata_end - efi_zboot_header - 1));
|
||||
append_end_node(&dpp);
|
||||
|
||||
// Create a device path describing the decompressed payload in this image
|
||||
// <...parent_dp...>/Offset(<start>, <end>)/VenMedia(ZBOOT_MEDIA_GUID)
|
||||
dp_len += sizeof(struct efi_rel_offset_dev_path);
|
||||
li_dp = memcpy(dpp, lf2_dp, dp_len);
|
||||
dpp = (void *)((u8 *)li_dp + dp_len);
|
||||
append_ven_media_node(&dpp, &LINUX_EFI_ZBOOT_MEDIA_GUID);
|
||||
append_end_node(&dpp);
|
||||
|
||||
zboot_handle = NULL;
|
||||
zboot_load_file2.load_file = load_file;
|
||||
status = efi_bs_call(install_multiple_protocol_interfaces,
|
||||
&zboot_handle,
|
||||
&EFI_DEVICE_PATH_PROTOCOL_GUID, lf2_dp,
|
||||
&EFI_LOAD_FILE2_PROTOCOL_GUID, &zboot_load_file2,
|
||||
NULL);
|
||||
if (status != EFI_SUCCESS) {
|
||||
log(L"Failed to install LoadFile2 protocol and device path");
|
||||
goto free_dpalloc;
|
||||
// Decompress the payload into the newly allocated buffer.
|
||||
ret = __decompress(_gzdata_start, compressed_size, NULL, NULL,
|
||||
(void *)image_base, alloc_size, NULL, error);
|
||||
if (ret < 0) {
|
||||
error("Decompression failed");
|
||||
status = EFI_DEVICE_ERROR;
|
||||
goto free_image;
|
||||
}
|
||||
|
||||
status = efi_bs_call(load_image, false, handle, li_dp, NULL, 0,
|
||||
&child_handle);
|
||||
if (status != EFI_SUCCESS) {
|
||||
log(L"Failed to load image");
|
||||
goto uninstall_lf2;
|
||||
}
|
||||
efi_cache_sync_image(image_base, alloc_size, code_size);
|
||||
|
||||
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");
|
||||
goto unload_image;
|
||||
}
|
||||
status = efi_stub_common(handle, image, image_base, cmdline_ptr);
|
||||
|
||||
// Copy the kernel command line
|
||||
child->load_options = parent->load_options;
|
||||
child->load_options_size = parent->load_options_size;
|
||||
|
||||
status = efi_bs_call(start_image, child_handle, &exit_data_size,
|
||||
&exit_data);
|
||||
if (status != EFI_SUCCESS) {
|
||||
log(L"StartImage() returned with error");
|
||||
if (exit_data_size > 0)
|
||||
log(exit_data);
|
||||
|
||||
// If StartImage() returns EFI_SECURITY_VIOLATION, the image is
|
||||
// not unloaded so we need to do it by hand.
|
||||
if (status == EFI_SECURITY_VIOLATION)
|
||||
unload_image:
|
||||
efi_bs_call(unload_image, child_handle);
|
||||
}
|
||||
|
||||
uninstall_lf2:
|
||||
efi_bs_call(uninstall_multiple_protocol_interfaces,
|
||||
zboot_handle,
|
||||
&EFI_DEVICE_PATH_PROTOCOL_GUID, lf2_dp,
|
||||
&EFI_LOAD_FILE2_PROTOCOL_GUID, &zboot_load_file2,
|
||||
NULL);
|
||||
|
||||
free_dpalloc:
|
||||
efi_bs_call(free_pool, dp_alloc);
|
||||
|
||||
efi_bs_call(exit, handle, status, exit_data_size, exit_data);
|
||||
|
||||
// Free ExitData in case Exit() returned with a failure code,
|
||||
// but return the original status code.
|
||||
log(L"Exit() returned with failure code");
|
||||
if (exit_data != NULL)
|
||||
efi_bs_call(free_pool, exit_data);
|
||||
free_image:
|
||||
efi_free(alloc_size, image_base);
|
||||
free_cmdline:
|
||||
efi_bs_call(free_pool, cmdline_ptr);
|
||||
return status;
|
||||
}
|
||||
|
|
|
@ -9,82 +9,15 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/efi.h>
|
||||
#include <linux/io.h>
|
||||
#include <asm/early_ioremap.h>
|
||||
#include <linux/memblock.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
static phys_addr_t __init __efi_memmap_alloc_early(unsigned long size)
|
||||
{
|
||||
return memblock_phys_alloc(size, SMP_CACHE_BYTES);
|
||||
}
|
||||
#include <asm/early_ioremap.h>
|
||||
#include <asm/efi.h>
|
||||
|
||||
static phys_addr_t __init __efi_memmap_alloc_late(unsigned long size)
|
||||
{
|
||||
unsigned int order = get_order(size);
|
||||
struct page *p = alloc_pages(GFP_KERNEL, order);
|
||||
|
||||
if (!p)
|
||||
return 0;
|
||||
|
||||
return PFN_PHYS(page_to_pfn(p));
|
||||
}
|
||||
|
||||
void __init __efi_memmap_free(u64 phys, unsigned long size, unsigned long flags)
|
||||
{
|
||||
if (flags & EFI_MEMMAP_MEMBLOCK) {
|
||||
if (slab_is_available())
|
||||
memblock_free_late(phys, size);
|
||||
else
|
||||
memblock_phys_free(phys, size);
|
||||
} else if (flags & EFI_MEMMAP_SLAB) {
|
||||
struct page *p = pfn_to_page(PHYS_PFN(phys));
|
||||
unsigned int order = get_order(size);
|
||||
|
||||
free_pages((unsigned long) page_address(p), order);
|
||||
}
|
||||
}
|
||||
|
||||
static void __init efi_memmap_free(void)
|
||||
{
|
||||
__efi_memmap_free(efi.memmap.phys_map,
|
||||
efi.memmap.desc_size * efi.memmap.nr_map,
|
||||
efi.memmap.flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* efi_memmap_alloc - Allocate memory for the EFI memory map
|
||||
* @num_entries: Number of entries in the allocated map.
|
||||
* @data: efi memmap installation parameters
|
||||
*
|
||||
* Depending on whether mm_init() has already been invoked or not,
|
||||
* either memblock or "normal" page allocation is used.
|
||||
*
|
||||
* Returns zero on success, a negative error code on failure.
|
||||
*/
|
||||
int __init efi_memmap_alloc(unsigned int num_entries,
|
||||
struct efi_memory_map_data *data)
|
||||
{
|
||||
/* Expect allocation parameters are zero initialized */
|
||||
WARN_ON(data->phys_map || data->size);
|
||||
|
||||
data->size = num_entries * efi.memmap.desc_size;
|
||||
data->desc_version = efi.memmap.desc_version;
|
||||
data->desc_size = efi.memmap.desc_size;
|
||||
data->flags &= ~(EFI_MEMMAP_SLAB | EFI_MEMMAP_MEMBLOCK);
|
||||
data->flags |= efi.memmap.flags & EFI_MEMMAP_LATE;
|
||||
|
||||
if (slab_is_available()) {
|
||||
data->flags |= EFI_MEMMAP_SLAB;
|
||||
data->phys_map = __efi_memmap_alloc_late(data->size);
|
||||
} else {
|
||||
data->flags |= EFI_MEMMAP_MEMBLOCK;
|
||||
data->phys_map = __efi_memmap_alloc_early(data->size);
|
||||
}
|
||||
|
||||
if (!data->phys_map)
|
||||
return -ENOMEM;
|
||||
return 0;
|
||||
}
|
||||
#ifndef __efi_memmap_free
|
||||
#define __efi_memmap_free(phys, size, flags) do { } while (0)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* __efi_memmap_init - Common code for mapping the EFI memory map
|
||||
|
@ -101,14 +34,11 @@ int __init efi_memmap_alloc(unsigned int num_entries,
|
|||
*
|
||||
* Returns zero on success, a negative error code on failure.
|
||||
*/
|
||||
static int __init __efi_memmap_init(struct efi_memory_map_data *data)
|
||||
int __init __efi_memmap_init(struct efi_memory_map_data *data)
|
||||
{
|
||||
struct efi_memory_map map;
|
||||
phys_addr_t phys_map;
|
||||
|
||||
if (efi_enabled(EFI_PARAVIRT))
|
||||
return 0;
|
||||
|
||||
phys_map = data->phys_map;
|
||||
|
||||
if (data->flags & EFI_MEMMAP_LATE)
|
||||
|
@ -121,8 +51,10 @@ static int __init __efi_memmap_init(struct efi_memory_map_data *data)
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* NOP if data->flags & (EFI_MEMMAP_MEMBLOCK | EFI_MEMMAP_SLAB) == 0 */
|
||||
efi_memmap_free();
|
||||
if (efi.memmap.flags & (EFI_MEMMAP_MEMBLOCK | EFI_MEMMAP_SLAB))
|
||||
__efi_memmap_free(efi.memmap.phys_map,
|
||||
efi.memmap.desc_size * efi.memmap.nr_map,
|
||||
efi.memmap.flags);
|
||||
|
||||
map.phys_map = data->phys_map;
|
||||
map.nr_map = data->size / data->desc_size;
|
||||
|
@ -220,158 +152,3 @@ int __init efi_memmap_init_late(phys_addr_t addr, unsigned long size)
|
|||
|
||||
return __efi_memmap_init(&data);
|
||||
}
|
||||
|
||||
/**
|
||||
* efi_memmap_install - Install a new EFI memory map in efi.memmap
|
||||
* @ctx: map allocation parameters (address, size, flags)
|
||||
*
|
||||
* Unlike efi_memmap_init_*(), this function does not allow the caller
|
||||
* to switch from early to late mappings. It simply uses the existing
|
||||
* mapping function and installs the new memmap.
|
||||
*
|
||||
* Returns zero on success, a negative error code on failure.
|
||||
*/
|
||||
int __init efi_memmap_install(struct efi_memory_map_data *data)
|
||||
{
|
||||
efi_memmap_unmap();
|
||||
|
||||
return __efi_memmap_init(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* efi_memmap_split_count - Count number of additional EFI memmap entries
|
||||
* @md: EFI memory descriptor to split
|
||||
* @range: Address range (start, end) to split around
|
||||
*
|
||||
* Returns the number of additional EFI memmap entries required to
|
||||
* accommodate @range.
|
||||
*/
|
||||
int __init efi_memmap_split_count(efi_memory_desc_t *md, struct range *range)
|
||||
{
|
||||
u64 m_start, m_end;
|
||||
u64 start, end;
|
||||
int count = 0;
|
||||
|
||||
start = md->phys_addr;
|
||||
end = start + (md->num_pages << EFI_PAGE_SHIFT) - 1;
|
||||
|
||||
/* modifying range */
|
||||
m_start = range->start;
|
||||
m_end = range->end;
|
||||
|
||||
if (m_start <= start) {
|
||||
/* split into 2 parts */
|
||||
if (start < m_end && m_end < end)
|
||||
count++;
|
||||
}
|
||||
|
||||
if (start < m_start && m_start < end) {
|
||||
/* split into 3 parts */
|
||||
if (m_end < end)
|
||||
count += 2;
|
||||
/* split into 2 parts */
|
||||
if (end <= m_end)
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* efi_memmap_insert - Insert a memory region in an EFI memmap
|
||||
* @old_memmap: The existing EFI memory map structure
|
||||
* @buf: Address of buffer to store new map
|
||||
* @mem: Memory map entry to insert
|
||||
*
|
||||
* It is suggested that you call efi_memmap_split_count() first
|
||||
* to see how large @buf needs to be.
|
||||
*/
|
||||
void __init efi_memmap_insert(struct efi_memory_map *old_memmap, void *buf,
|
||||
struct efi_mem_range *mem)
|
||||
{
|
||||
u64 m_start, m_end, m_attr;
|
||||
efi_memory_desc_t *md;
|
||||
u64 start, end;
|
||||
void *old, *new;
|
||||
|
||||
/* modifying range */
|
||||
m_start = mem->range.start;
|
||||
m_end = mem->range.end;
|
||||
m_attr = mem->attribute;
|
||||
|
||||
/*
|
||||
* The EFI memory map deals with regions in EFI_PAGE_SIZE
|
||||
* units. Ensure that the region described by 'mem' is aligned
|
||||
* correctly.
|
||||
*/
|
||||
if (!IS_ALIGNED(m_start, EFI_PAGE_SIZE) ||
|
||||
!IS_ALIGNED(m_end + 1, EFI_PAGE_SIZE)) {
|
||||
WARN_ON(1);
|
||||
return;
|
||||
}
|
||||
|
||||
for (old = old_memmap->map, new = buf;
|
||||
old < old_memmap->map_end;
|
||||
old += old_memmap->desc_size, new += old_memmap->desc_size) {
|
||||
|
||||
/* copy original EFI memory descriptor */
|
||||
memcpy(new, old, old_memmap->desc_size);
|
||||
md = new;
|
||||
start = md->phys_addr;
|
||||
end = md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT) - 1;
|
||||
|
||||
if (m_start <= start && end <= m_end)
|
||||
md->attribute |= m_attr;
|
||||
|
||||
if (m_start <= start &&
|
||||
(start < m_end && m_end < end)) {
|
||||
/* first part */
|
||||
md->attribute |= m_attr;
|
||||
md->num_pages = (m_end - md->phys_addr + 1) >>
|
||||
EFI_PAGE_SHIFT;
|
||||
/* latter part */
|
||||
new += old_memmap->desc_size;
|
||||
memcpy(new, old, old_memmap->desc_size);
|
||||
md = new;
|
||||
md->phys_addr = m_end + 1;
|
||||
md->num_pages = (end - md->phys_addr + 1) >>
|
||||
EFI_PAGE_SHIFT;
|
||||
}
|
||||
|
||||
if ((start < m_start && m_start < end) && m_end < end) {
|
||||
/* first part */
|
||||
md->num_pages = (m_start - md->phys_addr) >>
|
||||
EFI_PAGE_SHIFT;
|
||||
/* middle part */
|
||||
new += old_memmap->desc_size;
|
||||
memcpy(new, old, old_memmap->desc_size);
|
||||
md = new;
|
||||
md->attribute |= m_attr;
|
||||
md->phys_addr = m_start;
|
||||
md->num_pages = (m_end - m_start + 1) >>
|
||||
EFI_PAGE_SHIFT;
|
||||
/* last part */
|
||||
new += old_memmap->desc_size;
|
||||
memcpy(new, old, old_memmap->desc_size);
|
||||
md = new;
|
||||
md->phys_addr = m_end + 1;
|
||||
md->num_pages = (end - m_end) >>
|
||||
EFI_PAGE_SHIFT;
|
||||
}
|
||||
|
||||
if ((start < m_start && m_start < end) &&
|
||||
(end <= m_end)) {
|
||||
/* first part */
|
||||
md->num_pages = (m_start - md->phys_addr) >>
|
||||
EFI_PAGE_SHIFT;
|
||||
/* latter part */
|
||||
new += old_memmap->desc_size;
|
||||
memcpy(new, old, old_memmap->desc_size);
|
||||
md = new;
|
||||
md->phys_addr = m_start;
|
||||
md->num_pages = (end - md->phys_addr + 1) >>
|
||||
EFI_PAGE_SHIFT;
|
||||
md->attribute |= m_attr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -83,6 +83,7 @@ struct efi_runtime_work efi_rts_work;
|
|||
else \
|
||||
pr_err("Failed to queue work to efi_rts_wq.\n"); \
|
||||
\
|
||||
WARN_ON_ONCE(efi_rts_work.status == EFI_ABORTED); \
|
||||
exit: \
|
||||
efi_rts_work.efi_rts_id = EFI_NONE; \
|
||||
efi_rts_work.status; \
|
||||
|
|
|
@ -1,75 +0,0 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright(c) 2019 Intel Corporation. All rights reserved. */
|
||||
#include <linux/efi.h>
|
||||
#include <asm/e820/api.h>
|
||||
#include "fake_mem.h"
|
||||
|
||||
void __init efi_fake_memmap_early(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
/*
|
||||
* The late efi_fake_mem() call can handle all requests if
|
||||
* EFI_MEMORY_SP support is disabled.
|
||||
*/
|
||||
if (!efi_soft_reserve_enabled())
|
||||
return;
|
||||
|
||||
if (!efi_enabled(EFI_MEMMAP) || !nr_fake_mem)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Given that efi_fake_memmap() needs to perform memblock
|
||||
* allocations it needs to run after e820__memblock_setup().
|
||||
* However, if efi_fake_mem specifies EFI_MEMORY_SP for a given
|
||||
* address range that potentially needs to mark the memory as
|
||||
* reserved prior to e820__memblock_setup(). Update e820
|
||||
* directly if EFI_MEMORY_SP is specified for an
|
||||
* EFI_CONVENTIONAL_MEMORY descriptor.
|
||||
*/
|
||||
for (i = 0; i < nr_fake_mem; i++) {
|
||||
struct efi_mem_range *mem = &efi_fake_mems[i];
|
||||
efi_memory_desc_t *md;
|
||||
u64 m_start, m_end;
|
||||
|
||||
if ((mem->attribute & EFI_MEMORY_SP) == 0)
|
||||
continue;
|
||||
|
||||
m_start = mem->range.start;
|
||||
m_end = mem->range.end;
|
||||
for_each_efi_memory_desc(md) {
|
||||
u64 start, end, size;
|
||||
|
||||
if (md->type != EFI_CONVENTIONAL_MEMORY)
|
||||
continue;
|
||||
|
||||
start = md->phys_addr;
|
||||
end = md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT) - 1;
|
||||
|
||||
if (m_start <= end && m_end >= start)
|
||||
/* fake range overlaps descriptor */;
|
||||
else
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Trim the boundary of the e820 update to the
|
||||
* descriptor in case the fake range overlaps
|
||||
* !EFI_CONVENTIONAL_MEMORY
|
||||
*/
|
||||
start = max(start, m_start);
|
||||
end = min(end, m_end);
|
||||
size = end - start + 1;
|
||||
|
||||
if (end <= start)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Ensure each efi_fake_mem instance results in
|
||||
* a unique e820 resource
|
||||
*/
|
||||
e820__range_remove(start, size, E820_TYPE_RAM, 1);
|
||||
e820__range_add(start, size, E820_TYPE_SOFT_RESERVED);
|
||||
e820__update_table(e820_table);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -91,6 +91,10 @@ static int efivarfs_create(struct user_namespace *mnt_userns, struct inode *dir,
|
|||
err = guid_parse(dentry->d_name.name + namelen + 1, &var->var.VendorGuid);
|
||||
if (err)
|
||||
goto out;
|
||||
if (guid_equal(&var->var.VendorGuid, &LINUX_EFI_RANDOM_SEED_TABLE_GUID)) {
|
||||
err = -EPERM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (efivar_variable_is_removable(var->var.VendorGuid,
|
||||
dentry->d_name.name, namelen))
|
||||
|
|
|
@ -116,6 +116,9 @@ static int efivarfs_callback(efi_char16_t *name16, efi_guid_t vendor,
|
|||
int err = -ENOMEM;
|
||||
bool is_removable = false;
|
||||
|
||||
if (guid_equal(&vendor, &LINUX_EFI_RANDOM_SEED_TABLE_GUID))
|
||||
return 0;
|
||||
|
||||
entry = kzalloc(sizeof(*entry), GFP_KERNEL);
|
||||
if (!entry)
|
||||
return err;
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (C) 2022 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* Author: Smita Koralahalli <Smita.KoralahalliChannabasappa@amd.com>
|
||||
*/
|
||||
|
||||
#ifndef LINUX_CXL_ERR_H
|
||||
#define LINUX_CXL_ERR_H
|
||||
|
||||
/* CXL RAS Capability Structure, CXL v3.1 sec 8.2.4.16 */
|
||||
struct cxl_ras_capability_regs {
|
||||
u32 uncor_status;
|
||||
u32 uncor_mask;
|
||||
u32 uncor_severity;
|
||||
u32 cor_status;
|
||||
u32 cor_mask;
|
||||
u32 cap_control;
|
||||
u32 header_log[16];
|
||||
};
|
||||
|
||||
#endif //__CXL_ERR_
|
|
@ -371,6 +371,7 @@ void efi_native_runtime_setup(void);
|
|||
#define LOADED_IMAGE_DEVICE_PATH_PROTOCOL_GUID EFI_GUID(0xbc62157e, 0x3e33, 0x4fec, 0x99, 0x20, 0x2d, 0x3b, 0x36, 0xd7, 0x50, 0xdf)
|
||||
#define EFI_DEVICE_PATH_PROTOCOL_GUID EFI_GUID(0x09576e91, 0x6d3f, 0x11d2, 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b)
|
||||
#define EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID EFI_GUID(0x8b843e20, 0x8132, 0x4852, 0x90, 0xcc, 0x55, 0x1a, 0x4e, 0x4a, 0x7f, 0x1c)
|
||||
#define EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL_GUID EFI_GUID(0x05c99a21, 0xc70f, 0x4ad2, 0x8a, 0x5f, 0x35, 0xdf, 0x33, 0x43, 0xf5, 0x1e)
|
||||
#define EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID EFI_GUID(0x9042a9de, 0x23dc, 0x4a38, 0x96, 0xfb, 0x7a, 0xde, 0xd0, 0x80, 0x51, 0x6a)
|
||||
#define EFI_UGA_PROTOCOL_GUID EFI_GUID(0x982c298b, 0xf4fa, 0x41cb, 0xb8, 0x38, 0x77, 0xaa, 0x68, 0x8f, 0xb8, 0x39)
|
||||
#define EFI_PCI_IO_PROTOCOL_GUID EFI_GUID(0x4cf5b200, 0x68b8, 0x4ca5, 0x9e, 0xec, 0xb2, 0x3e, 0x3f, 0x50, 0x02, 0x9a)
|
||||
|
@ -404,7 +405,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)
|
||||
|
@ -412,7 +413,6 @@ void efi_native_runtime_setup(void);
|
|||
#define LINUX_EFI_TPM_FINAL_LOG_GUID EFI_GUID(0x1e2ed096, 0x30e2, 0x4254, 0xbd, 0x89, 0x86, 0x3b, 0xbe, 0xf8, 0x23, 0x25)
|
||||
#define LINUX_EFI_MEMRESERVE_TABLE_GUID EFI_GUID(0x888eb0c6, 0x8ede, 0x4ff5, 0xa8, 0xf0, 0x9a, 0xee, 0x5c, 0xb9, 0x77, 0xc2)
|
||||
#define LINUX_EFI_INITRD_MEDIA_GUID EFI_GUID(0x5568e427, 0x68fc, 0x4f3d, 0xac, 0x74, 0xca, 0x55, 0x52, 0x31, 0xcc, 0x68)
|
||||
#define LINUX_EFI_ZBOOT_MEDIA_GUID EFI_GUID(0xe565a30d, 0x47da, 0x4dbd, 0xb3, 0x54, 0x9b, 0xb5, 0xc8, 0x4f, 0x8b, 0xe2)
|
||||
#define LINUX_EFI_MOK_VARIABLE_TABLE_GUID EFI_GUID(0xc451ed2b, 0x9694, 0x45d3, 0xba, 0xba, 0xed, 0x9f, 0x89, 0x88, 0xa3, 0x89)
|
||||
#define LINUX_EFI_COCO_SECRET_AREA_GUID EFI_GUID(0xadf956ad, 0xe98c, 0x484c, 0xae, 0x11, 0xb5, 0x1c, 0x7d, 0x33, 0x64, 0x47)
|
||||
#define LINUX_EFI_BOOT_MEMMAP_GUID EFI_GUID(0x800f683f, 0xd08b, 0x423a, 0xa2, 0x93, 0x96, 0x5c, 0x3c, 0x6f, 0xe2, 0xb4)
|
||||
|
@ -707,18 +707,10 @@ static inline efi_status_t efi_query_variable_store(u32 attributes,
|
|||
#endif
|
||||
extern void __iomem *efi_lookup_mapped_addr(u64 phys_addr);
|
||||
|
||||
extern int __init efi_memmap_alloc(unsigned int num_entries,
|
||||
struct efi_memory_map_data *data);
|
||||
extern void __efi_memmap_free(u64 phys, unsigned long size,
|
||||
unsigned long flags);
|
||||
extern int __init __efi_memmap_init(struct efi_memory_map_data *data);
|
||||
extern int __init efi_memmap_init_early(struct efi_memory_map_data *data);
|
||||
extern int __init efi_memmap_init_late(phys_addr_t addr, unsigned long size);
|
||||
extern void __init efi_memmap_unmap(void);
|
||||
extern int __init efi_memmap_install(struct efi_memory_map_data *data);
|
||||
extern int __init efi_memmap_split_count(efi_memory_desc_t *md,
|
||||
struct range *range);
|
||||
extern void __init efi_memmap_insert(struct efi_memory_map *old_memmap,
|
||||
void *buf, struct efi_mem_range *mem);
|
||||
|
||||
#ifdef CONFIG_EFI_ESRT
|
||||
extern void __init efi_esrt_init(void);
|
||||
|
@ -749,12 +741,6 @@ extern struct kobject *efi_kobj;
|
|||
extern int efi_reboot_quirk_mode;
|
||||
extern bool efi_poweroff_required(void);
|
||||
|
||||
#ifdef CONFIG_EFI_FAKE_MEMMAP
|
||||
extern void __init efi_fake_memmap(void);
|
||||
#else
|
||||
static inline void efi_fake_memmap(void) { }
|
||||
#endif
|
||||
|
||||
extern unsigned long efi_mem_attr_table;
|
||||
|
||||
/*
|
||||
|
@ -1012,6 +998,11 @@ struct efi_mem_mapped_dev_path {
|
|||
u64 ending_addr;
|
||||
} __packed;
|
||||
|
||||
struct efi_file_path_dev_path {
|
||||
struct efi_generic_dev_path header;
|
||||
efi_char16_t filename[];
|
||||
} __packed;
|
||||
|
||||
struct efi_dev_path {
|
||||
union {
|
||||
struct efi_generic_dev_path header;
|
||||
|
@ -1098,34 +1089,6 @@ extern int efi_capsule_update(efi_capsule_header_t *capsule,
|
|||
static inline bool efi_capsule_pending(int *reset_type) { return false; }
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_EFI_RUNTIME_MAP
|
||||
int efi_runtime_map_init(struct kobject *);
|
||||
int efi_get_runtime_map_size(void);
|
||||
int efi_get_runtime_map_desc_size(void);
|
||||
int efi_runtime_map_copy(void *buf, size_t bufsz);
|
||||
#else
|
||||
static inline int efi_runtime_map_init(struct kobject *kobj)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int efi_get_runtime_map_size(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int efi_get_runtime_map_desc_size(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int efi_runtime_map_copy(void *buf, size_t bufsz)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_EFI
|
||||
extern bool efi_runtime_disabled(void);
|
||||
#else
|
||||
|
@ -1170,8 +1133,6 @@ void efi_check_for_embedded_firmwares(void);
|
|||
static inline void efi_check_for_embedded_firmwares(void) { }
|
||||
#endif
|
||||
|
||||
efi_status_t efi_random_get_seed(void);
|
||||
|
||||
#define arch_efi_call_virt(p, f, args...) ((p)->f(args))
|
||||
|
||||
/*
|
||||
|
|
|
@ -29,7 +29,14 @@
|
|||
* handover_offset and xloadflags fields in the bootparams structure.
|
||||
*/
|
||||
#define LINUX_EFISTUB_MAJOR_VERSION 0x1
|
||||
#define LINUX_EFISTUB_MINOR_VERSION 0x0
|
||||
#define LINUX_EFISTUB_MINOR_VERSION 0x1
|
||||
|
||||
/*
|
||||
* LINUX_PE_MAGIC appears at offset 0x38 into the MS-DOS header of EFI bootable
|
||||
* Linux kernel images that target the architecture as specified by the PE/COFF
|
||||
* header machine type field.
|
||||
*/
|
||||
#define LINUX_PE_MAGIC 0x818223cd
|
||||
|
||||
#define MZ_MAGIC 0x5a4d /* "MZ" */
|
||||
|
||||
|
|
Loading…
Reference in New Issue