mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
EFI updates for v7.4
- Set the LoaderDevicePartUUID EFI variable from the stub to help systemd discover the file system layout when booting straight into Linux without GRUB or systemd-boot (Vincent Mailhol) - Some GUID deduplication work from Vincent - Remove pointless UTF16->UTF8 and vice versa conversions from the stub, including some prerequisite work on the x86 decompressor to accommodate that - Some kmap() -> kmap_local_page() conversions in the capsule loader - Add a runtime control to en/disable EFI runtime services so that PREEMPT_RT systems can enable them as needed - Add a 'nostatfs' mount option to efivarfs so that the cost of querying the EFI variable store (which is already rate limited) can be avoided entirely on systems where it is disproportionately costly - Rework the EFI libstub Makefile to align x86 with other architectures, and inherit/adapt the global CFLAGS variable rather than reconstruct it from scratch - Constify attributes of statically allocated sysfs nodes - Avoid register x18 when building the arm64 EFI stub, in order to comply with the UEFI spec, and to permit it to execute in a context where x18 is special - Preserve the physical addresses of all EFI config tables that may be of interest to an incoming kexec kernel - Add some LKDTM tests for EFI runtime crashes where the faulting address is inside a EFI memory region - Other minor bug fixes and cosmetic cleanups -----BEGIN PGP SIGNATURE----- iHUEABYKAB0WIQQQm/3uucuRGn1Dmh0wbglWLn0tXAUCatSJtAAKCRAwbglWLn0t XEvXAQCpluirdoc3LaABTQUceGfFmM9EeETcB8FMuQv5+ATo8gEAy536vpGMlosG l3dwbsdEHBTGK0bvpViOqOelNH/5xQs= =3fkP -----END PGP SIGNATURE----- Merge tag 'efi-next-for-v7.4' of git://git.kernel.org/pub/scm/linux/kernel/git/efi/efi Pull EFI updates from Ard Biesheuvel: - Set the LoaderDevicePartUUID EFI variable from the stub to help systemd discover the file system layout when booting straight into Linux without GRUB or systemd-boot (Vincent Mailhol) - Some GUID deduplication work from Vincent - Remove pointless UTF16->UTF8 and vice versa conversions from the stub - Some kmap() -> kmap_local_page() conversions in the capsule loader - Add a runtime control to en/disable EFI runtime services so that PREEMPT_RT systems can enable them as needed - Add a 'nostatfs' mount option to efivarfs so that the cost of querying the EFI variable store (which is already rate limited) can be avoided entirely on systems where it is disproportionately costly - Rework the EFI libstub Makefile to align x86 with other architectures, and inherit/adapt the global CFLAGS variable rather than reconstruct it from scratch - Constify attributes of statically allocated sysfs nodes - Avoid register x18 when building the arm64 EFI stub, in order to comply with the UEFI spec, and to permit it to execute in a context where x18 is special - Preserve the physical addresses of all EFI config tables that may be of interest to an incoming kexec kernel - Add some LKDTM tests for EFI runtime crashes where the faulting address is inside a EFI memory region - Other minor bug fixes and cosmetic cleanups * tag 'efi-next-for-v7.4' of git://git.kernel.org/pub/scm/linux/kernel/git/efi/efi: (35 commits) lkdtm: Add more EFI runtime tests efi: Initialize all configuration table addresses to EFI_INVALID_TABLE_ADDR efi: Retain the address of the LINUX_EFI_MEMRESERVE table efi/libstub: Don't replace an existing LINUX_EFI_MEMRESERVE table efi/runtime-wrappers: Don't park the worker after a recovered firmware fault efi: Use sysfs_emit() not sprintf() to generate sysfs file contents efi: Constify sysfs attributes efi/libstub: Disable kernel stack erasing in the common flags efi/libstub: Build the x86 stub from KBUILD_CFLAGS efi/libstub: Declare the x86 stub's assembly entry points efi/libstub: arm64: Don't use the platform register x18 efi/libstub: Free cmdline_ptr in efi_pe_entry efi/riscv: libstub: Don't set image_size in handle_kernel_image() efi/libstub: Fix error unwind freeing fdt in allocate_new_fdt_and_exit_boot() efivarfs: add nostatfs mount option to skip QueryVariableInfo() efi/libstub: add initial Boot Loader Interface support efi/libstub: Add efi_snprintf() to construct wide strings efi/libstub: Add support for printing human readable GUIDs efi/libstub: Output UTF-16 directly from vsnprintf() efi/libstub: Avoid efi_puts() for compile time constant strings ...
This commit is contained in:
commit
89d2d7bf06
|
|
@ -37,6 +37,18 @@ accidentally.
|
|||
|4_bytes_of_attributes + efivar_data|
|
||||
+-----------------------------------+
|
||||
|
||||
Mount options
|
||||
=============
|
||||
|
||||
========== ==================================================================
|
||||
(no)statfs Control whether ``statfs(2)`` reports the variable-store
|
||||
used/available. Disabling it skips the ``QueryVariableInfo()``
|
||||
EFI runtime service call, which might block all CPUs for a few
|
||||
milliseconds, and reports 0/0 for used/available instead.
|
||||
Defaults to ``statfs``, except on ``CONFIG_PREEMPT_RT`` where
|
||||
it defaults to ``nostatfs``.
|
||||
========== ==================================================================
|
||||
|
||||
*See also:*
|
||||
|
||||
- Documentation/admin-guide/acpi/ssdt-overlays.rst
|
||||
|
|
|
|||
|
|
@ -891,20 +891,21 @@ bool efi_is_table_address(unsigned long phys_addr)
|
|||
|
||||
#define EFI_ATTR_SHOW(name) \
|
||||
static ssize_t name##_show(struct kobject *kobj, \
|
||||
struct kobj_attribute *attr, char *buf) \
|
||||
const struct kobj_attribute *attr, char *buf) \
|
||||
{ \
|
||||
return sprintf(buf, "0x%lx\n", EFI_FIELD(name)); \
|
||||
return sysfs_emit(buf, "0x%lx\n", EFI_FIELD(name)); \
|
||||
}
|
||||
|
||||
EFI_ATTR_SHOW(fw_vendor);
|
||||
EFI_ATTR_SHOW(runtime);
|
||||
EFI_ATTR_SHOW(config_table);
|
||||
|
||||
struct kobj_attribute efi_attr_fw_vendor = __ATTR_RO(fw_vendor);
|
||||
struct kobj_attribute efi_attr_runtime = __ATTR_RO(runtime);
|
||||
struct kobj_attribute efi_attr_config_table = __ATTR_RO(config_table);
|
||||
const struct kobj_attribute efi_attr_fw_vendor = __KOBJ_ATTR_RO(fw_vendor);
|
||||
const struct kobj_attribute efi_attr_runtime = __KOBJ_ATTR_RO(runtime);
|
||||
const struct kobj_attribute efi_attr_config_table = __KOBJ_ATTR_RO(config_table);
|
||||
|
||||
umode_t efi_attr_is_visible(struct kobject *kobj, struct attribute *attr, int n)
|
||||
umode_t efi_attr_is_visible(struct kobject *kobj, const struct attribute *attr,
|
||||
int n)
|
||||
{
|
||||
if (attr == &efi_attr_fw_vendor.attr) {
|
||||
if (efi_enabled(EFI_PARAVIRT) ||
|
||||
|
|
|
|||
|
|
@ -197,7 +197,7 @@ static ssize_t efi_capsule_write(struct file *file, const char __user *buff,
|
|||
page = cap_info->pages[cap_info->index - 1];
|
||||
}
|
||||
|
||||
kbuff = kmap(page);
|
||||
kbuff = kmap_local_page(page);
|
||||
kbuff += PAGE_SIZE - cap_info->page_bytes_remain;
|
||||
|
||||
/* Copy capsule binary data from user space to kernel space buffer */
|
||||
|
|
@ -217,7 +217,7 @@ static ssize_t efi_capsule_write(struct file *file, const char __user *buff,
|
|||
}
|
||||
|
||||
cap_info->count += write_byte;
|
||||
kunmap(page);
|
||||
kunmap_local(kbuff);
|
||||
|
||||
/* Submit the full binary to efi_capsule_update() API */
|
||||
if (cap_info->header.headersize > 0 &&
|
||||
|
|
@ -236,7 +236,7 @@ static ssize_t efi_capsule_write(struct file *file, const char __user *buff,
|
|||
return write_byte;
|
||||
|
||||
fail_unmap:
|
||||
kunmap(page);
|
||||
kunmap_local(kbuff);
|
||||
failed:
|
||||
efi_free_all_buff_pages(cap_info);
|
||||
return ret;
|
||||
|
|
|
|||
|
|
@ -245,7 +245,7 @@ int efi_capsule_update(efi_capsule_header_t *capsule, phys_addr_t *pages)
|
|||
for (i = 0; i < sg_count; i++) {
|
||||
efi_capsule_block_desc_t *sglist;
|
||||
|
||||
sglist = kmap_atomic(sg_pages[i]);
|
||||
sglist = kmap_local_page(sg_pages[i]);
|
||||
|
||||
for (j = 0; j < SGLIST_PER_PAGE && count > 0; j++) {
|
||||
u64 sz = min_t(u64, imagesize,
|
||||
|
|
@ -277,7 +277,7 @@ int efi_capsule_update(efi_capsule_header_t *capsule, phys_addr_t *pages)
|
|||
*/
|
||||
efi_capsule_flush_cache_range(sglist, PAGE_SIZE);
|
||||
#endif
|
||||
kunmap_atomic(sglist);
|
||||
kunmap_local(sglist);
|
||||
}
|
||||
|
||||
mutex_lock(&capsule_mutex);
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
* This code registers /sys/firmware/efi{,/efivars} when EFI is supported,
|
||||
* allowing the efivarfs to be mounted or the efivars module to be loaded.
|
||||
* The existance of /sys/firmware/efi may also be used by userspace to
|
||||
* The existence of /sys/firmware/efi may also be used by userspace to
|
||||
* determine that the system supports EFI.
|
||||
*/
|
||||
|
||||
|
|
@ -46,20 +46,14 @@ struct efi __read_mostly efi = {
|
|||
.tpm_log = EFI_INVALID_TABLE_ADDR,
|
||||
.tpm_final_log = EFI_INVALID_TABLE_ADDR,
|
||||
.ovmf_debug_log = EFI_INVALID_TABLE_ADDR,
|
||||
#ifdef CONFIG_LOAD_UEFI_KEYS
|
||||
.mem_reserve = EFI_INVALID_TABLE_ADDR,
|
||||
.mokvar_table = EFI_INVALID_TABLE_ADDR,
|
||||
#endif
|
||||
#ifdef CONFIG_EFI_COCO_SECRET
|
||||
.coco_secret = EFI_INVALID_TABLE_ADDR,
|
||||
#endif
|
||||
#ifdef CONFIG_UNACCEPTED_MEMORY
|
||||
.unaccepted = EFI_INVALID_TABLE_ADDR,
|
||||
#endif
|
||||
};
|
||||
EXPORT_SYMBOL(efi);
|
||||
|
||||
unsigned long __ro_after_init efi_rng_seed = EFI_INVALID_TABLE_ADDR;
|
||||
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;
|
||||
|
||||
|
|
@ -131,45 +125,45 @@ struct kobject *efi_kobj;
|
|||
* one value per file rule!
|
||||
*/
|
||||
static ssize_t systab_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, char *buf)
|
||||
const struct kobj_attribute *attr, char *buf)
|
||||
{
|
||||
char *str = buf;
|
||||
int offset = 0;
|
||||
|
||||
if (!kobj || !buf)
|
||||
return -EINVAL;
|
||||
|
||||
if (efi.acpi20 != EFI_INVALID_TABLE_ADDR)
|
||||
str += sprintf(str, "ACPI20=0x%lx\n", efi.acpi20);
|
||||
offset = sysfs_emit(buf, "ACPI20=0x%lx\n", efi.acpi20);
|
||||
if (efi.acpi != EFI_INVALID_TABLE_ADDR)
|
||||
str += sprintf(str, "ACPI=0x%lx\n", efi.acpi);
|
||||
offset += sysfs_emit_at(buf, offset, "ACPI=0x%lx\n", efi.acpi);
|
||||
/*
|
||||
* If both SMBIOS and SMBIOS3 entry points are implemented, the
|
||||
* SMBIOS3 entry point shall be preferred, so we list it first to
|
||||
* let applications stop parsing after the first match.
|
||||
*/
|
||||
if (efi.smbios3 != EFI_INVALID_TABLE_ADDR)
|
||||
str += sprintf(str, "SMBIOS3=0x%lx\n", efi.smbios3);
|
||||
offset += sysfs_emit_at(buf, offset, "SMBIOS3=0x%lx\n", efi.smbios3);
|
||||
if (efi.smbios != EFI_INVALID_TABLE_ADDR)
|
||||
str += sprintf(str, "SMBIOS=0x%lx\n", efi.smbios);
|
||||
offset += sysfs_emit_at(buf, offset, "SMBIOS=0x%lx\n", efi.smbios);
|
||||
|
||||
return str - buf;
|
||||
return offset;
|
||||
}
|
||||
|
||||
static struct kobj_attribute efi_attr_systab = __ATTR_RO_MODE(systab, 0400);
|
||||
static const struct kobj_attribute efi_attr_systab = __KOBJ_ATTR_RO_MODE(systab, 0400);
|
||||
|
||||
static ssize_t fw_platform_size_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, char *buf)
|
||||
const struct kobj_attribute *attr, char *buf)
|
||||
{
|
||||
return sprintf(buf, "%d\n", efi_enabled(EFI_64BIT) ? 64 : 32);
|
||||
return sysfs_emit(buf, "%d\n", efi_enabled(EFI_64BIT) ? 64 : 32);
|
||||
}
|
||||
|
||||
extern __weak struct kobj_attribute efi_attr_fw_vendor;
|
||||
extern __weak struct kobj_attribute efi_attr_runtime;
|
||||
extern __weak struct kobj_attribute efi_attr_config_table;
|
||||
static struct kobj_attribute efi_attr_fw_platform_size =
|
||||
__ATTR_RO(fw_platform_size);
|
||||
extern __weak const struct kobj_attribute efi_attr_fw_vendor;
|
||||
extern __weak const struct kobj_attribute efi_attr_runtime;
|
||||
extern __weak const struct kobj_attribute efi_attr_config_table;
|
||||
static const struct kobj_attribute efi_attr_fw_platform_size =
|
||||
__KOBJ_ATTR_RO(fw_platform_size);
|
||||
|
||||
static struct attribute *efi_subsys_attrs[] = {
|
||||
static const struct attribute *const efi_subsys_attrs[] = {
|
||||
&efi_attr_systab.attr,
|
||||
&efi_attr_fw_platform_size.attr,
|
||||
&efi_attr_fw_vendor.attr,
|
||||
|
|
@ -178,15 +172,16 @@ static struct attribute *efi_subsys_attrs[] = {
|
|||
NULL,
|
||||
};
|
||||
|
||||
umode_t __weak efi_attr_is_visible(struct kobject *kobj, struct attribute *attr,
|
||||
umode_t __weak efi_attr_is_visible(struct kobject *kobj,
|
||||
const struct attribute *attr,
|
||||
int n)
|
||||
{
|
||||
return attr->mode;
|
||||
}
|
||||
|
||||
static const struct attribute_group efi_subsys_attr_group = {
|
||||
.attrs = efi_subsys_attrs,
|
||||
.is_visible = efi_attr_is_visible,
|
||||
.attrs_const = efi_subsys_attrs,
|
||||
.is_visible_const = efi_attr_is_visible,
|
||||
};
|
||||
|
||||
struct blocking_notifier_head efivar_ops_nh;
|
||||
|
|
@ -401,6 +396,35 @@ static void __init efi_debugfs_init(void)
|
|||
static inline void efi_debugfs_init(void) {}
|
||||
#endif
|
||||
|
||||
static ssize_t efi_runtime_show(struct kobject *kobj,
|
||||
const struct kobj_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
return sysfs_emit(buf, "%d\n", efi_enabled(EFI_RUNTIME_SERVICES));
|
||||
}
|
||||
|
||||
static ssize_t efi_runtime_store(struct kobject *kobj,
|
||||
const struct kobj_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
int ret;
|
||||
bool enable;
|
||||
|
||||
ret = kstrtobool(buf, &enable);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (efi_runtime_set_enable_flag(enable) != EFI_SUCCESS) {
|
||||
pr_warn("unable to enable/disable efi runtime service\n");
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static const struct kobj_attribute efi_runtime_attr =
|
||||
__KOBJ_ATTR(runtime_enable, 0644, efi_runtime_show, efi_runtime_store);
|
||||
|
||||
static int __init efipostcore_init(void)
|
||||
{
|
||||
if (!efi_enabled(EFI_RUNTIME_SERVICES))
|
||||
|
|
@ -446,6 +470,11 @@ static int __init efisubsys_init(void)
|
|||
goto err_destroy_wq;
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_PREEMPT_RT) && efi.runtime_supported_mask) {
|
||||
if (sysfs_create_file(efi_kobj, &efi_runtime_attr.attr))
|
||||
pr_warn("unable to register efi dynamic sysfs interface\n");
|
||||
}
|
||||
|
||||
if (efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE |
|
||||
EFI_RT_SUPPORTED_GET_NEXT_VARIABLE_NAME)) {
|
||||
error = generic_ops_register();
|
||||
|
|
@ -628,7 +657,7 @@ static const efi_config_table_type_t common_tables[] __initconst = {
|
|||
{LINUX_EFI_TPM_EVENT_LOG_GUID, &efi.tpm_log, "TPMEventLog" },
|
||||
{EFI_TCG2_FINAL_EVENTS_TABLE_GUID, &efi.tpm_final_log, "TPMFinalLog" },
|
||||
{EFI_CC_FINAL_EVENTS_TABLE_GUID, &efi.tpm_final_log, "CCFinalLog" },
|
||||
{LINUX_EFI_MEMRESERVE_TABLE_GUID, &mem_reserve, "MEMRESERVE" },
|
||||
{LINUX_EFI_MEMRESERVE_TABLE_GUID, &efi.mem_reserve, "MEMRESERVE" },
|
||||
{LINUX_EFI_INITRD_MEDIA_GUID, &initrd, "INITRD" },
|
||||
{EFI_RT_PROPERTIES_TABLE_GUID, &rt_prop, "RTPROP" },
|
||||
#ifdef CONFIG_OVMF_DEBUG_LOG
|
||||
|
|
@ -771,8 +800,8 @@ int __init efi_config_parse_tables(const efi_config_table_t *config_tables,
|
|||
|
||||
efi_tpm_eventlog_init();
|
||||
|
||||
if (mem_reserve != EFI_INVALID_TABLE_ADDR) {
|
||||
unsigned long prsv = mem_reserve;
|
||||
if (efi.mem_reserve != EFI_INVALID_TABLE_ADDR) {
|
||||
unsigned long prsv = efi.mem_reserve;
|
||||
|
||||
while (prsv) {
|
||||
struct linux_efi_memreserve *rsv;
|
||||
|
|
@ -1059,10 +1088,10 @@ static struct linux_efi_memreserve *efi_memreserve_root __ro_after_init;
|
|||
|
||||
static int __init efi_memreserve_map_root(void)
|
||||
{
|
||||
if (mem_reserve == EFI_INVALID_TABLE_ADDR)
|
||||
if (efi.mem_reserve == EFI_INVALID_TABLE_ADDR)
|
||||
return -ENODEV;
|
||||
|
||||
efi_memreserve_root = memremap(mem_reserve,
|
||||
efi_memreserve_root = memremap(efi.mem_reserve,
|
||||
sizeof(*efi_memreserve_root),
|
||||
MEMREMAP_WB);
|
||||
if (WARN_ON_ONCE(!efi_memreserve_root))
|
||||
|
|
|
|||
|
|
@ -6,31 +6,31 @@
|
|||
# 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__ $(CC_FLAGS_DIALECT) \
|
||||
-fPIC -fno-strict-aliasing -mno-red-zone \
|
||||
-mno-mmx -mno-sse -fshort-wchar \
|
||||
-Wno-pointer-sign \
|
||||
$(call cc-disable-warning, address-of-packed-member) \
|
||||
-fno-asynchronous-unwind-tables \
|
||||
$(CLANG_FLAGS)
|
||||
# x86 links the stub into the decompressor rather than the kernel proper, so
|
||||
# drop the kernel's code model, calling convention, and stack alignment, and
|
||||
# the mitigations that rely on thunks and patch sites only the kernel has.
|
||||
cflags-$(CONFIG_X86) := $(filter-out -mcmodel=kernel \
|
||||
-mregparm=3 -freg-struct-return \
|
||||
-mpreferred-stack-boundary=% \
|
||||
-mstack-alignment=% \
|
||||
$(RETPOLINE_CFLAGS) $(RETHUNK_CFLAGS) \
|
||||
$(PADDING_CFLAGS), $(cflags-y))
|
||||
cflags-$(CONFIG_X86_32) += -march=i386
|
||||
cflags-$(CONFIG_X86_64) += -mcmodel=small
|
||||
cflags-$(CONFIG_X86) += -fPIC
|
||||
# Nothing enables IBT while the stub runs, so ENDBR would only take space.
|
||||
cflags-$(CONFIG_X86) += $(call cc-option,-fcf-protection=none)
|
||||
|
||||
# arm64 uses the full KBUILD_CFLAGS so it's necessary to explicitly
|
||||
# disable the stackleak plugin
|
||||
cflags-$(CONFIG_ARM64) += -fpie $(DISABLE_KSTACK_ERASE) \
|
||||
-fno-unwind-tables -fno-asynchronous-unwind-tables
|
||||
cflags-$(CONFIG_ARM64) += -fpie -ffixed-x18 -fno-unwind-tables \
|
||||
-fno-asynchronous-unwind-tables
|
||||
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) \
|
||||
$(DISABLE_KSTACK_ERASE)
|
||||
cflags-$(CONFIG_RISCV) += -fpic -DNO_ALTERNATIVE -mno-relax \
|
||||
$(DISABLE_KSTACK_ERASE)
|
||||
cflags-$(CONFIG_LOONGARCH) += -fpie $(DISABLE_KSTACK_ERASE)
|
||||
$(call cc-option,-mno-single-pic-base)
|
||||
cflags-$(CONFIG_RISCV) += -fpic -DNO_ALTERNATIVE -mno-relax
|
||||
cflags-$(CONFIG_LOONGARCH) += -fpie
|
||||
|
||||
cflags-$(CONFIG_EFI_PARAMS_FROM_FDT) += -I$(srctree)/scripts/dtc/libfdt
|
||||
|
||||
|
|
@ -40,6 +40,7 @@ KBUILD_CFLAGS := $(subst $(CC_FLAGS_FTRACE),,$(cflags-y)) \
|
|||
-D__NO_FORTIFY \
|
||||
-ffreestanding \
|
||||
-fno-stack-protector \
|
||||
$(DISABLE_KSTACK_ERASE) \
|
||||
$(CONFIG_CC_OPT_NO_ADDRSIG) \
|
||||
-D__DISABLE_EXPORTS
|
||||
|
||||
|
|
@ -66,7 +67,8 @@ KBUILD_AFLAGS := $(KBUILD_CFLAGS) -D__ASSEMBLY__
|
|||
lib-y := efi-stub-helper.o gop.o secureboot.o tpm.o \
|
||||
file.o mem.o random.o randomalloc.o pci.o \
|
||||
skip_spaces.o lib-cmdline.o lib-ctype.o \
|
||||
alignedmem.o printk.o vsprintf.o
|
||||
alignedmem.o printk.o vsprintf.o bli.o \
|
||||
lib-ucs2_string.o
|
||||
|
||||
# include the stub's libfdt dependencies from lib/ when needed
|
||||
libfdt-deps := fdt_rw.c fdt_ro.c fdt_wip.c fdt.c \
|
||||
|
|
|
|||
86
drivers/firmware/efi/libstub/bli.c
Normal file
86
drivers/firmware/efi/libstub/bli.c
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
#include <generated/utsrelease.h>
|
||||
|
||||
#include <linux/efi.h>
|
||||
#include <linux/unaligned.h>
|
||||
|
||||
#include "efistub.h"
|
||||
|
||||
static efi_guid_t loader_entry_guid = LINUX_EFI_LOADER_ENTRY_GUID;
|
||||
|
||||
static const struct efi_hd_dev_path *
|
||||
efi_bli_find_hd_node(const struct efi_dev_path *path)
|
||||
{
|
||||
const struct efi_dev_path *node;
|
||||
u16 node_len;
|
||||
|
||||
for (node = path;
|
||||
node->header.type != EFI_DEV_END_PATH &&
|
||||
node->header.type != EFI_DEV_END_PATH2;
|
||||
node = (const void *)node + node_len) {
|
||||
node_len = get_unaligned_le16(&node->header.length);
|
||||
|
||||
if (node_len < sizeof(node->header))
|
||||
return NULL;
|
||||
|
||||
if (node->header.type != EFI_DEV_MEDIA ||
|
||||
node->header.sub_type != EFI_DEV_MEDIA_HARD_DRIVE)
|
||||
continue;
|
||||
|
||||
if (node_len < sizeof(node->hd))
|
||||
return NULL;
|
||||
|
||||
if (node->hd.partition_format != EFI_HD_PARTITION_FORMAT_GPT ||
|
||||
node->hd.signature_type != EFI_HD_SIGNATURE_TYPE_GUID)
|
||||
continue;
|
||||
|
||||
return &node->hd;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void efi_bli_populate_loader_part_uuid(const efi_loaded_image_t *image)
|
||||
{
|
||||
static efi_guid_t device_path_guid = EFI_DEVICE_PATH_PROTOCOL_GUID;
|
||||
efi_char16_t partuuid[UUID_STRING_LEN + 1];
|
||||
const struct efi_hd_dev_path *hd_node;
|
||||
const struct efi_dev_path *path;
|
||||
|
||||
if (efi_bs_call(handle_protocol, efi_table_attr(image, device_handle),
|
||||
&device_path_guid, (void **)&path) != EFI_SUCCESS)
|
||||
return;
|
||||
|
||||
hd_node = efi_bli_find_hd_node(path);
|
||||
if (!hd_node)
|
||||
return;
|
||||
|
||||
if (efi_snprintf(partuuid, ARRAY_SIZE(partuuid), "%pUl",
|
||||
&hd_node->signature) != UUID_STRING_LEN)
|
||||
return;
|
||||
|
||||
set_efi_var(L"LoaderDevicePartUUID", &loader_entry_guid,
|
||||
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
|
||||
sizeof(partuuid), partuuid);
|
||||
}
|
||||
|
||||
void efi_bli_set_variables(const efi_loaded_image_t *image)
|
||||
{
|
||||
static efi_char16_t loader_info[] = L"Linux EFI stub " UTS_RELEASE;
|
||||
unsigned long size = 0;
|
||||
|
||||
if (!image)
|
||||
return;
|
||||
|
||||
if (get_efi_var(L"LoaderInfo", &loader_entry_guid,
|
||||
NULL, &size, NULL) != EFI_NOT_FOUND)
|
||||
return;
|
||||
|
||||
if (set_efi_var(L"LoaderInfo", &loader_entry_guid,
|
||||
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
|
||||
sizeof(loader_info), loader_info) != EFI_SUCCESS)
|
||||
return;
|
||||
|
||||
efi_bli_populate_loader_part_uuid(image);
|
||||
}
|
||||
|
|
@ -35,13 +35,12 @@ struct sysfb_display_info *alloc_primary_display(void)
|
|||
efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
|
||||
efi_system_table_t *systab)
|
||||
{
|
||||
static efi_guid_t loaded_image_proto = LOADED_IMAGE_PROTOCOL_GUID;
|
||||
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;
|
||||
|
||||
|
|
@ -63,6 +62,7 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
|
|||
return status;
|
||||
}
|
||||
|
||||
char *cmdline_ptr __free(efi_pool) = NULL;
|
||||
status = efi_handle_cmdline(image, &cmdline_ptr);
|
||||
if (status != EFI_SUCCESS)
|
||||
return status;
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
#include <linux/efi.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/overflow.h>
|
||||
#include <linux/ucs2_string.h>
|
||||
#include <asm/efi.h>
|
||||
#include <asm/setup.h>
|
||||
|
||||
|
|
@ -248,6 +249,7 @@ static efi_status_t efi_measure_tagged_event(unsigned long load_addr,
|
|||
unsigned long load_size,
|
||||
enum efistub_event_type event)
|
||||
{
|
||||
static efi_guid_t tcg2_guid = EFI_TCG2_PROTOCOL_GUID;
|
||||
union {
|
||||
efi_status_t
|
||||
(__efiapi *hash_log_extend_event)(void *, u64, efi_physical_addr_t,
|
||||
|
|
@ -257,7 +259,6 @@ static efi_status_t efi_measure_tagged_event(unsigned long load_addr,
|
|||
struct efistub_measured_event *evt __free(efi_pool) = NULL;
|
||||
int size = struct_size(evt, tagged_event.tagged_event_data,
|
||||
events[event].event_data_len);
|
||||
efi_guid_t tcg2_guid = EFI_TCG2_PROTOCOL_GUID;
|
||||
efi_tcg2_protocol_t *tcg2 = NULL;
|
||||
union efistub_event ev;
|
||||
efi_status_t status;
|
||||
|
|
@ -276,7 +277,7 @@ static efi_status_t efi_measure_tagged_event(unsigned long load_addr,
|
|||
method.hash_log_extend_event =
|
||||
(void *)efi_table_attr(tcg2, hash_log_extend_event);
|
||||
} else {
|
||||
efi_guid_t cc_guid = EFI_CC_MEASUREMENT_PROTOCOL_GUID;
|
||||
static efi_guid_t cc_guid = EFI_CC_MEASUREMENT_PROTOCOL_GUID;
|
||||
efi_cc_protocol_t *cc = NULL;
|
||||
|
||||
efi_bs_call(locate_protocol, &cc_guid, NULL, (void **)&cc);
|
||||
|
|
@ -334,81 +335,56 @@ char *efi_convert_cmdline(efi_loaded_image_t *image)
|
|||
{
|
||||
const efi_char16_t *options = efi_table_attr(image, load_options);
|
||||
u32 options_size = efi_table_attr(image, load_options_size);
|
||||
int options_bytes = 0, safe_options_bytes = 0; /* UTF-8 bytes */
|
||||
unsigned long cmdline_addr = 0;
|
||||
const efi_char16_t *s2;
|
||||
bool in_quote = false;
|
||||
unsigned long options_chars = 0;
|
||||
unsigned long cmdline_bytes;
|
||||
efi_status_t status;
|
||||
u32 options_chars;
|
||||
char *cmdline_addr;
|
||||
|
||||
if (options_size > 0)
|
||||
efi_measure_tagged_event((unsigned long)options, options_size,
|
||||
EFISTUB_EVT_LOAD_OPTIONS);
|
||||
|
||||
efi_apply_loadoptions_quirk((const void **)&options, &options_size);
|
||||
options_chars = options_size / sizeof(efi_char16_t);
|
||||
if (options)
|
||||
options_chars = ucs2_strnlen(options,
|
||||
options_size / sizeof(efi_char16_t));
|
||||
|
||||
if (options) {
|
||||
s2 = options;
|
||||
while (options_bytes < COMMAND_LINE_SIZE && options_chars--) {
|
||||
efi_char16_t c = *s2++;
|
||||
/* Each UCS-2 char takes up at most 3 UTF-8 bytes */
|
||||
cmdline_bytes = min(3 * options_chars, COMMAND_LINE_SIZE - 1) + 3;
|
||||
|
||||
if (c < 0x80) {
|
||||
if (c == L'\0' || c == L'\n')
|
||||
break;
|
||||
if (c == L'"')
|
||||
in_quote = !in_quote;
|
||||
else if (!in_quote && isspace((char)c))
|
||||
safe_options_bytes = options_bytes;
|
||||
|
||||
options_bytes++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the number of UTF-8 bytes corresponding to a
|
||||
* UTF-16 character.
|
||||
* The first part handles everything in the BMP.
|
||||
*/
|
||||
options_bytes += 2 + (c >= 0x800);
|
||||
/*
|
||||
* Add one more byte for valid surrogate pairs. Invalid
|
||||
* surrogates will be replaced with 0xfffd and take up
|
||||
* only 3 bytes.
|
||||
*/
|
||||
if ((c & 0xfc00) == 0xd800) {
|
||||
/*
|
||||
* If the very last word is a high surrogate,
|
||||
* we must ignore it since we can't access the
|
||||
* low surrogate.
|
||||
*/
|
||||
if (!options_chars) {
|
||||
options_bytes -= 3;
|
||||
} else if ((*s2 & 0xfc00) == 0xdc00) {
|
||||
options_bytes++;
|
||||
options_chars--;
|
||||
s2++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (options_bytes >= COMMAND_LINE_SIZE) {
|
||||
options_bytes = safe_options_bytes;
|
||||
efi_err("Command line is too long: truncated to %d bytes\n",
|
||||
options_bytes);
|
||||
}
|
||||
}
|
||||
|
||||
options_bytes++; /* NUL termination */
|
||||
|
||||
status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, options_bytes,
|
||||
status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, cmdline_bytes,
|
||||
(void **)&cmdline_addr);
|
||||
if (status != EFI_SUCCESS)
|
||||
return NULL;
|
||||
|
||||
snprintf((char *)cmdline_addr, options_bytes, "%.*ls",
|
||||
options_bytes - 1, options);
|
||||
if (ucs2_as_utf8_l(cmdline_addr, options, options_chars,
|
||||
cmdline_bytes) >= COMMAND_LINE_SIZE) {
|
||||
/*
|
||||
* The output fills up the entire buffer, and may have been
|
||||
* truncated. Work backwards through the buffer to find a safe
|
||||
* truncation point (i.e., a blank character not inside a
|
||||
* quoted string).
|
||||
*/
|
||||
int safe_pos[2] = {};
|
||||
int in_quote = 0;
|
||||
|
||||
return (char *)cmdline_addr;
|
||||
for (int i = COMMAND_LINE_SIZE - 1; i >= 0; i--) {
|
||||
char c = cmdline_addr[i];
|
||||
|
||||
if (!c)
|
||||
return cmdline_addr;
|
||||
else if (c == '"')
|
||||
in_quote ^= 1;
|
||||
else if (!safe_pos[in_quote] && isspace(c))
|
||||
safe_pos[in_quote] = i;
|
||||
}
|
||||
|
||||
efi_err("Command line is too long: truncated to %d bytes\n",
|
||||
safe_pos[in_quote]);
|
||||
cmdline_addr[safe_pos[in_quote]] = '\0';
|
||||
}
|
||||
|
||||
return cmdline_addr;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -552,7 +528,7 @@ static
|
|||
efi_status_t efi_load_initrd_dev_path(struct linux_efi_initrd *initrd,
|
||||
unsigned long max)
|
||||
{
|
||||
efi_guid_t lf2_proto_guid = EFI_LOAD_FILE2_PROTOCOL_GUID;
|
||||
static efi_guid_t lf2_proto_guid = EFI_LOAD_FILE2_PROTOCOL_GUID;
|
||||
efi_device_path_protocol_t *dp;
|
||||
efi_load_file2_protocol_t *lf2;
|
||||
efi_handle_t handle;
|
||||
|
|
@ -614,7 +590,7 @@ efi_status_t efi_load_initrd(efi_loaded_image_t *image,
|
|||
unsigned long hard_limit,
|
||||
const struct linux_efi_initrd **out)
|
||||
{
|
||||
efi_guid_t tbl_guid = LINUX_EFI_INITRD_MEDIA_GUID;
|
||||
static efi_guid_t tbl_guid = LINUX_EFI_INITRD_MEDIA_GUID;
|
||||
efi_status_t status = EFI_SUCCESS;
|
||||
struct linux_efi_initrd initrd, *tbl;
|
||||
|
||||
|
|
@ -725,7 +701,7 @@ efi_status_t efi_wait_for_key(unsigned long usec, efi_input_key_t *key)
|
|||
void efi_remap_image(unsigned long image_base, unsigned alloc_size,
|
||||
unsigned long code_size)
|
||||
{
|
||||
efi_guid_t guid = EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID;
|
||||
static efi_guid_t guid = EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID;
|
||||
efi_memory_attribute_protocol_t *memattr;
|
||||
efi_status_t status;
|
||||
u64 attr;
|
||||
|
|
|
|||
|
|
@ -79,10 +79,18 @@ static struct sysfb_display_info *setup_primary_display(void)
|
|||
|
||||
static void install_memreserve_table(void)
|
||||
{
|
||||
static efi_guid_t memreserve_table_guid = LINUX_EFI_MEMRESERVE_TABLE_GUID;
|
||||
struct linux_efi_memreserve *rsv;
|
||||
efi_guid_t memreserve_table_guid = LINUX_EFI_MEMRESERVE_TABLE_GUID;
|
||||
efi_status_t status;
|
||||
|
||||
/*
|
||||
* If an earlier boot stage installed a memreserve table already, e.g.,
|
||||
* a kexec loader passing on the persistent reservations made by the
|
||||
* previous kernel, use it as is: installing a new one would replace it.
|
||||
*/
|
||||
if (get_efi_config_table(memreserve_table_guid))
|
||||
return;
|
||||
|
||||
status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, sizeof(*rsv),
|
||||
(void **)&rsv);
|
||||
if (status != EFI_SUCCESS) {
|
||||
|
|
@ -165,6 +173,7 @@ efi_status_t efi_stub_common(efi_handle_t handle,
|
|||
dpy = setup_primary_display();
|
||||
|
||||
efi_retrieve_eventlog();
|
||||
efi_bli_set_variables(image);
|
||||
|
||||
/* Ask the firmware to clear memory on unclean shutdown */
|
||||
efi_enable_reset_attack_mitigation();
|
||||
|
|
|
|||
|
|
@ -224,8 +224,8 @@ typedef void (__efiapi *efi_event_notify_t)(efi_event_t, void *);
|
|||
* efi_set_event_at() - add event to events array
|
||||
*
|
||||
* @events: array of UEFI events
|
||||
* @ids: index where to put the event in the array
|
||||
* @event: event to add to the aray
|
||||
* @idx: index where to put the event in the array
|
||||
* @event: event to add to the array
|
||||
*
|
||||
* boottime->wait_for_event() takes an array of events as input.
|
||||
* Provide a helper to set it up correctly for mixed mode.
|
||||
|
|
@ -1072,17 +1072,21 @@ efi_status_t efi_random_alloc(unsigned long size, unsigned long align,
|
|||
int memory_type, unsigned long alloc_min,
|
||||
unsigned long alloc_max);
|
||||
|
||||
void efi_bli_set_variables(const efi_loaded_image_t *image);
|
||||
|
||||
efi_status_t efi_random_get_seed(void);
|
||||
|
||||
efi_status_t check_platform_features(void);
|
||||
|
||||
void *get_efi_config_table(efi_guid_t guid);
|
||||
|
||||
/* NOTE: These functions do not print a trailing newline after the string */
|
||||
void efi_char16_puts(efi_char16_t *);
|
||||
void efi_puts(const char *str);
|
||||
|
||||
int efi_vsnprintf(efi_char16_t *buf, size_t size, const char *fmt, va_list ap,
|
||||
bool crlf);
|
||||
|
||||
__printf(1, 2) int efi_printk(char const *fmt, ...);
|
||||
__printf(3, 4) int efi_snprintf(efi_char16_t *buf, size_t size, const char *fmt, ...);
|
||||
|
||||
void efi_free(unsigned long size, unsigned long addr);
|
||||
DEFINE_FREE(efi_pool, void *, if (_T) efi_bs_call(free_pool, _T));
|
||||
|
|
|
|||
|
|
@ -229,6 +229,7 @@ efi_status_t allocate_new_fdt_and_exit_boot(void *handle,
|
|||
u32 desc_ver;
|
||||
efi_status_t status;
|
||||
struct exit_boot_struct priv;
|
||||
unsigned long fdt_size_allocated = 0;
|
||||
unsigned long fdt_addr = 0;
|
||||
unsigned long fdt_size = 0;
|
||||
|
||||
|
|
@ -251,12 +252,13 @@ efi_status_t allocate_new_fdt_and_exit_boot(void *handle,
|
|||
if (strstr(cmdline_ptr, "dtb="))
|
||||
efi_err("Ignoring DTB from command line.\n");
|
||||
} else {
|
||||
status = efi_load_dtb(image, &fdt_addr, &fdt_size);
|
||||
status = efi_load_dtb(image, &fdt_addr, &fdt_size_allocated);
|
||||
|
||||
if (status != EFI_SUCCESS && status != EFI_NOT_READY) {
|
||||
efi_err("Failed to load device tree!\n");
|
||||
goto fail;
|
||||
}
|
||||
fdt_size = fdt_size_allocated;
|
||||
}
|
||||
|
||||
if (fdt_addr) {
|
||||
|
|
@ -334,7 +336,7 @@ efi_status_t allocate_new_fdt_and_exit_boot(void *handle,
|
|||
efi_free(MAX_FDT_SIZE, *new_fdt_addr);
|
||||
|
||||
fail:
|
||||
efi_free(fdt_size, fdt_addr);
|
||||
efi_free(fdt_size_allocated, fdt_addr);
|
||||
if (!efi_novamap)
|
||||
efi_bs_call(free_pool, priv.runtime_map);
|
||||
|
||||
|
|
|
|||
|
|
@ -29,6 +29,8 @@
|
|||
*/
|
||||
#define EFI_READ_CHUNK_SIZE SZ_1M
|
||||
|
||||
static efi_guid_t fs_proto = EFI_FILE_SYSTEM_GUID;
|
||||
|
||||
struct finfo {
|
||||
efi_file_info_t info;
|
||||
efi_char16_t filename[MAX_FILENAME_SIZE];
|
||||
|
|
@ -39,7 +41,7 @@ static efi_status_t efi_open_file(efi_file_protocol_t *volume,
|
|||
efi_file_protocol_t **handle,
|
||||
unsigned long *file_size)
|
||||
{
|
||||
efi_guid_t info_guid = EFI_FILE_INFO_ID;
|
||||
static efi_guid_t info_guid = EFI_FILE_INFO_ID;
|
||||
efi_file_protocol_t *fh;
|
||||
unsigned long info_sz;
|
||||
efi_status_t status;
|
||||
|
|
@ -74,7 +76,6 @@ 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)
|
||||
{
|
||||
efi_guid_t fs_proto = EFI_FILE_SYSTEM_GUID;
|
||||
efi_simple_file_system_protocol_t *io;
|
||||
efi_status_t status;
|
||||
|
||||
|
|
@ -128,9 +129,8 @@ static int find_file_option(const efi_char16_t *cmdline, int cmdline_len,
|
|||
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_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;
|
||||
|
|
|
|||
|
|
@ -24,6 +24,8 @@ enum efi_cmdline_option {
|
|||
EFI_CMDLINE_LIST
|
||||
};
|
||||
|
||||
static efi_guid_t graphics_output_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
|
||||
|
||||
static struct {
|
||||
enum efi_cmdline_option option;
|
||||
union {
|
||||
|
|
@ -309,12 +311,12 @@ static u32 choose_mode_list(efi_graphics_output_protocol_t *gop)
|
|||
efi_status_t status;
|
||||
|
||||
efi_printk("Available graphics modes are 0-%u\n", max_mode-1);
|
||||
efi_puts(" * = current mode\n"
|
||||
" - = unusable mode\n");
|
||||
efi_char16_puts(L" * = current mode\r\n"
|
||||
" - = unusable mode\r\n");
|
||||
|
||||
choose_mode(gop, match_list, (void *)cur_mode);
|
||||
|
||||
efi_puts("\nPress any key to continue (or wait 10 seconds)\n");
|
||||
efi_char16_puts(L"\r\nPress any key to continue (or wait 10 seconds)\r\n");
|
||||
status = efi_wait_for_key(10 * EFI_USEC_PER_SEC, &key);
|
||||
if (status != EFI_SUCCESS && status != EFI_TIMEOUT) {
|
||||
efi_err("Unable to read key, continuing in 10 seconds\n");
|
||||
|
|
@ -425,6 +427,7 @@ static void setup_edid_info(struct edid_info *edid, u32 gop_size_of_edid, u8 *go
|
|||
static efi_handle_t find_handle_with_primary_gop(unsigned long num, const efi_handle_t handles[],
|
||||
efi_graphics_output_protocol_t **found_gop)
|
||||
{
|
||||
static efi_guid_t console_out_device_guid = EFI_CONSOLE_OUT_DEVICE_GUID;
|
||||
efi_graphics_output_protocol_t *first_gop;
|
||||
efi_handle_t h, first_gop_handle;
|
||||
|
||||
|
|
@ -439,8 +442,7 @@ static efi_handle_t find_handle_with_primary_gop(unsigned long num, const efi_ha
|
|||
efi_graphics_output_mode_info_t *info;
|
||||
void *dummy = NULL;
|
||||
|
||||
status = efi_bs_call(handle_protocol, h,
|
||||
&EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID,
|
||||
status = efi_bs_call(handle_protocol, h, &graphics_output_guid,
|
||||
(void **)&gop);
|
||||
if (status != EFI_SUCCESS)
|
||||
continue;
|
||||
|
|
@ -462,7 +464,7 @@ static efi_handle_t find_handle_with_primary_gop(unsigned long num, const efi_ha
|
|||
* don't bother looking any further.
|
||||
*/
|
||||
status = efi_bs_call(handle_protocol, h,
|
||||
&EFI_CONSOLE_OUT_DEVICE_GUID, &dummy);
|
||||
&console_out_device_guid, &dummy);
|
||||
if (status == EFI_SUCCESS) {
|
||||
if (found_gop)
|
||||
*found_gop = gop;
|
||||
|
|
@ -480,6 +482,8 @@ static efi_handle_t find_handle_with_primary_gop(unsigned long num, const efi_ha
|
|||
|
||||
efi_status_t efi_setup_graphics(struct screen_info *si, struct edid_info *edid)
|
||||
{
|
||||
static efi_guid_t edid_active_guid = EFI_EDID_ACTIVE_PROTOCOL_GUID;
|
||||
static efi_guid_t edid_discovered_guid = EFI_EDID_DISCOVERED_PROTOCOL_GUID;
|
||||
efi_handle_t *handles __free(efi_pool) = NULL;
|
||||
efi_handle_t handle;
|
||||
efi_graphics_output_protocol_t *gop;
|
||||
|
|
@ -487,8 +491,7 @@ efi_status_t efi_setup_graphics(struct screen_info *si, struct edid_info *edid)
|
|||
unsigned long num;
|
||||
|
||||
status = efi_bs_call(locate_handle_buffer, EFI_LOCATE_BY_PROTOCOL,
|
||||
&EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID, NULL, &num,
|
||||
&handles);
|
||||
&graphics_output_guid, NULL, &num, &handles);
|
||||
if (status != EFI_SUCCESS)
|
||||
return status;
|
||||
|
||||
|
|
@ -510,14 +513,14 @@ efi_status_t efi_setup_graphics(struct screen_info *si, struct edid_info *edid)
|
|||
u32 gop_size_of_edid = 0;
|
||||
u8 *gop_edid = NULL;
|
||||
|
||||
status = efi_bs_call(handle_protocol, handle, &EFI_EDID_ACTIVE_PROTOCOL_GUID,
|
||||
status = efi_bs_call(handle_protocol, handle, &edid_active_guid,
|
||||
(void **)&active_edid);
|
||||
if (status == EFI_SUCCESS) {
|
||||
gop_size_of_edid = efi_table_attr(active_edid, size_of_edid);
|
||||
gop_edid = efi_table_attr(active_edid, edid);
|
||||
} else {
|
||||
status = efi_bs_call(handle_protocol, handle,
|
||||
&EFI_EDID_DISCOVERED_PROTOCOL_GUID,
|
||||
&edid_discovered_guid,
|
||||
(void **)&discovered_edid);
|
||||
if (status == EFI_SUCCESS) {
|
||||
gop_size_of_edid = efi_table_attr(discovered_edid, size_of_edid);
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
*/
|
||||
u32 efi_kaslr_get_phys_seed(efi_handle_t image_handle)
|
||||
{
|
||||
efi_guid_t li_fixed_proto = LINUX_EFI_LOADED_IMAGE_FIXED_GUID;
|
||||
static efi_guid_t li_fixed_proto = LINUX_EFI_LOADED_IMAGE_FIXED_GUID;
|
||||
void *p;
|
||||
|
||||
if (!IS_ENABLED(CONFIG_RANDOMIZE_BASE))
|
||||
|
|
@ -59,8 +59,7 @@ static bool check_image_region(u64 base, u64 size)
|
|||
{
|
||||
struct efi_boot_memmap *map __free(efi_pool) = NULL;
|
||||
efi_status_t status;
|
||||
bool ret = false;
|
||||
int map_offset;
|
||||
unsigned long map_offset;
|
||||
|
||||
status = efi_get_memory_map(&map, false);
|
||||
if (status != EFI_SUCCESS)
|
||||
|
|
@ -74,18 +73,16 @@ static bool check_image_region(u64 base, u64 size)
|
|||
* Find the region that covers base, and return whether
|
||||
* it covers base+size bytes.
|
||||
*/
|
||||
if (base >= md->phys_addr && base < end) {
|
||||
ret = (base + size) <= end;
|
||||
break;
|
||||
}
|
||||
if (base >= md->phys_addr && base < end)
|
||||
return (base + size) <= end;
|
||||
}
|
||||
|
||||
return ret;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* efi_kaslr_relocate_kernel() - Relocate the kernel (random if KASLR enabled)
|
||||
* @image_addr: Pointer to the current kernel location
|
||||
* @image_addr: Pointer to the current kernel location
|
||||
* @reserve_addr: Pointer to the relocated kernel location
|
||||
* @reserve_size: Size of the relocated kernel
|
||||
* @kernel_size: Size of the text + data
|
||||
|
|
@ -94,8 +91,8 @@ static bool check_image_region(u64 base, u64 size)
|
|||
* @phys_seed: Random seed used for the relocation
|
||||
*
|
||||
* If KASLR is not enabled, this function relocates the kernel to a fixed
|
||||
* address (or leave it as its current location). If KASLR is enabled, the
|
||||
* kernel physical location is randomized using the seed in parameter.
|
||||
* address or leaves it at its current location. If KASLR is enabled, the
|
||||
* kernel's physical location is randomized using the supplied seed.
|
||||
*
|
||||
* Return: status code, EFI_SUCCESS if relocation is successful
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -20,10 +20,10 @@
|
|||
efi_status_t efi_get_memory_map(struct efi_boot_memmap **map,
|
||||
bool install_cfg_tbl)
|
||||
{
|
||||
static efi_guid_t tbl_guid = LINUX_EFI_BOOT_MEMMAP_GUID;
|
||||
struct efi_boot_memmap tmp, *m __free(efi_pool) = NULL;
|
||||
int memtype = install_cfg_tbl ? EFI_ACPI_RECLAIM_MEMORY
|
||||
: EFI_LOADER_DATA;
|
||||
efi_guid_t tbl_guid = LINUX_EFI_BOOT_MEMMAP_GUID;
|
||||
efi_status_t status;
|
||||
unsigned long size;
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
void efi_pci_disable_bridge_busmaster(void)
|
||||
{
|
||||
efi_guid_t pci_proto = EFI_PCI_IO_PROTOCOL_GUID;
|
||||
static efi_guid_t pci_proto = EFI_PCI_IO_PROTOCOL_GUID;
|
||||
efi_handle_t *pci_handle __free(efi_pool) = NULL;
|
||||
unsigned long pci_handle_num;
|
||||
efi_handle_t handle;
|
||||
|
|
|
|||
|
|
@ -23,98 +23,20 @@ void efi_char16_puts(efi_char16_t *str)
|
|||
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.
|
||||
* message is suppressed. The message will be truncated to 255 characters
|
||||
* (ignoring surrogates).
|
||||
*
|
||||
* Return: number of printed characters
|
||||
*/
|
||||
int efi_printk(const char *fmt, ...)
|
||||
{
|
||||
char printf_buf[256];
|
||||
efi_char16_t printf_buf[256];
|
||||
va_list args;
|
||||
int printed;
|
||||
int loglevel = printk_get_level(fmt);
|
||||
|
|
@ -136,17 +58,18 @@ int efi_printk(const char *fmt, ...)
|
|||
return 0;
|
||||
|
||||
if (loglevel >= 0)
|
||||
efi_puts("EFI stub: ");
|
||||
efi_char16_puts(L"EFI stub: ");
|
||||
|
||||
fmt = printk_skip_level(fmt);
|
||||
|
||||
va_start(args, fmt);
|
||||
printed = vsnprintf(printf_buf, sizeof(printf_buf), fmt, args);
|
||||
printed = efi_vsnprintf(printf_buf, ARRAY_SIZE(printf_buf), fmt, args,
|
||||
true);
|
||||
va_end(args);
|
||||
|
||||
efi_puts(printf_buf);
|
||||
if (printed >= sizeof(printf_buf)) {
|
||||
efi_puts("[Message truncated]\n");
|
||||
efi_char16_puts(printf_buf);
|
||||
if (printed >= ARRAY_SIZE(printf_buf)) {
|
||||
efi_char16_puts(L"[Message truncated]\r\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@
|
|||
|
||||
#include "efistub.h"
|
||||
|
||||
static efi_guid_t rng_proto = EFI_RNG_PROTOCOL_GUID;
|
||||
|
||||
typedef union efi_rng_protocol efi_rng_protocol_t;
|
||||
|
||||
union efi_rng_protocol {
|
||||
|
|
@ -38,7 +40,6 @@ union efi_rng_protocol {
|
|||
*/
|
||||
efi_status_t efi_get_random_bytes(unsigned long size, u8 *out)
|
||||
{
|
||||
efi_guid_t rng_proto = EFI_RNG_PROTOCOL_GUID;
|
||||
efi_status_t status;
|
||||
efi_rng_protocol_t *rng = NULL;
|
||||
|
||||
|
|
@ -64,9 +65,8 @@ efi_status_t efi_get_random_bytes(unsigned long size, u8 *out)
|
|||
*/
|
||||
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;
|
||||
static efi_guid_t rng_algo_raw = EFI_RNG_ALGORITHM_RAW;
|
||||
static 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;
|
||||
|
|
|
|||
|
|
@ -37,17 +37,14 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
|
|||
kernel_codesize = __init_text_end - _start;
|
||||
kernel_memsize = kernel_size + (_end - _edata);
|
||||
*image_addr = (unsigned long)_start;
|
||||
*image_size = kernel_memsize;
|
||||
*reserve_size = *image_size;
|
||||
*reserve_size = kernel_memsize;
|
||||
|
||||
status = efi_kaslr_relocate_kernel(image_addr,
|
||||
reserve_addr, reserve_size,
|
||||
kernel_size, kernel_codesize, kernel_memsize,
|
||||
efi_kaslr_get_phys_seed(image_handle));
|
||||
if (status != EFI_SUCCESS) {
|
||||
if (status != EFI_SUCCESS)
|
||||
efi_err("Failed to relocate kernel\n");
|
||||
*image_size = 0;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ static int get_boot_hartid_from_fdt(void)
|
|||
|
||||
static efi_status_t get_boot_hartid_from_efi(void)
|
||||
{
|
||||
efi_guid_t boot_protocol_guid = RISCV_EFI_BOOT_PROTOCOL_GUID;
|
||||
static efi_guid_t boot_protocol_guid = RISCV_EFI_BOOT_PROTOCOL_GUID;
|
||||
struct riscv_efi_boot_protocol *boot_protocol;
|
||||
efi_status_t status;
|
||||
|
||||
|
|
|
|||
|
|
@ -35,12 +35,13 @@ union efi_smbios_protocol {
|
|||
|
||||
const struct efi_smbios_record *efi_get_smbios_record(u8 type)
|
||||
{
|
||||
static efi_guid_t smbios_guid = EFI_SMBIOS_PROTOCOL_GUID;
|
||||
struct efi_smbios_record *record;
|
||||
efi_smbios_protocol_t *smbios;
|
||||
efi_status_t status;
|
||||
u16 handle = 0xfffe;
|
||||
|
||||
status = efi_bs_call(locate_protocol, &EFI_SMBIOS_PROTOCOL_GUID, NULL,
|
||||
status = efi_bs_call(locate_protocol, &smbios_guid, NULL,
|
||||
(void **)&smbios) ?:
|
||||
efi_call_proto(smbios, get_next, &handle, &type, &record, NULL);
|
||||
if (status != EFI_SUCCESS)
|
||||
|
|
|
|||
|
|
@ -28,8 +28,8 @@ static const efi_char16_t efi_MemoryOverWriteRequest_name[] =
|
|||
*/
|
||||
void efi_enable_reset_attack_mitigation(void)
|
||||
{
|
||||
static efi_guid_t var_guid = MEMORY_ONLY_RESET_CONTROL_GUID;
|
||||
u8 val = 1;
|
||||
efi_guid_t var_guid = MEMORY_ONLY_RESET_CONTROL_GUID;
|
||||
efi_status_t status;
|
||||
unsigned long datasize = 0;
|
||||
|
||||
|
|
@ -52,7 +52,7 @@ static void efi_retrieve_tcg2_eventlog(int version, efi_physical_addr_t log_loca
|
|||
efi_bool_t truncated,
|
||||
struct efi_tcg2_final_events_table *final_events_table)
|
||||
{
|
||||
efi_guid_t linux_eventlog_guid = LINUX_EFI_TPM_EVENT_LOG_GUID;
|
||||
static efi_guid_t linux_eventlog_guid = LINUX_EFI_TPM_EVENT_LOG_GUID;
|
||||
efi_status_t status;
|
||||
struct linux_efi_tpm_eventlog *log_tbl = NULL;
|
||||
unsigned long first_entry_addr, last_entry_addr;
|
||||
|
|
@ -150,9 +150,9 @@ static void efi_retrieve_tcg2_eventlog(int version, efi_physical_addr_t log_loca
|
|||
|
||||
void efi_retrieve_eventlog(void)
|
||||
{
|
||||
static efi_guid_t tpm2_guid = EFI_TCG2_PROTOCOL_GUID;
|
||||
struct efi_tcg2_final_events_table *final_events_table = NULL;
|
||||
efi_physical_addr_t log_location = 0, log_last_entry = 0;
|
||||
efi_guid_t tpm2_guid = EFI_TCG2_PROTOCOL_GUID;
|
||||
int version = EFI_TCG2_EVENT_LOG_FORMAT_TCG_2;
|
||||
efi_tcg2_protocol_t *tpm2 = NULL;
|
||||
efi_bool_t truncated;
|
||||
|
|
@ -173,7 +173,7 @@ void efi_retrieve_eventlog(void)
|
|||
get_efi_config_table(EFI_TCG2_FINAL_EVENTS_TABLE_GUID);
|
||||
}
|
||||
} else {
|
||||
efi_guid_t cc_guid = EFI_CC_MEASUREMENT_PROTOCOL_GUID;
|
||||
static efi_guid_t cc_guid = EFI_CC_MEASUREMENT_PROTOCOL_GUID;
|
||||
efi_cc_protocol_t *cc = NULL;
|
||||
|
||||
status = efi_bs_call(locate_protocol, &cc_guid, NULL, (void **)&cc);
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ struct efi_unaccepted_memory *unaccepted_table;
|
|||
efi_status_t allocate_unaccepted_bitmap(__u32 nr_desc,
|
||||
struct efi_boot_memmap *map)
|
||||
{
|
||||
efi_guid_t unaccepted_table_guid = LINUX_EFI_UNACCEPTED_MEM_TABLE_GUID;
|
||||
static efi_guid_t unaccepted_table_guid = LINUX_EFI_UNACCEPTED_MEM_TABLE_GUID;
|
||||
u64 unaccepted_start = ULLONG_MAX, unaccepted_end = 0, bitmap_size;
|
||||
efi_status_t status;
|
||||
int i;
|
||||
|
|
|
|||
|
|
@ -14,10 +14,14 @@
|
|||
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/efi.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/limits.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/ucs2_string.h>
|
||||
|
||||
#include "efistub.h"
|
||||
|
||||
static
|
||||
int skip_atoi(const char **s)
|
||||
|
|
@ -109,6 +113,9 @@ char *put_dec(char *end, unsigned long long n)
|
|||
return p;
|
||||
}
|
||||
|
||||
/* we are called with base 8, 10 or 16, only, thus don't need "G..." */
|
||||
static const char digits[16] = "0123456789ABCDEF"; /* "GHIJKLMNOPQRSTUVWXYZ"; */
|
||||
|
||||
static
|
||||
char *number(char *end, unsigned long long num, int base, char locase)
|
||||
{
|
||||
|
|
@ -117,9 +124,6 @@ char *number(char *end, unsigned long long num, int base, char locase)
|
|||
* produces same digits or (maybe lowercased) letters
|
||||
*/
|
||||
|
||||
/* we are called with base 8, 10 or 16, only, thus don't need "G..." */
|
||||
static const char digits[16] = "0123456789ABCDEF"; /* "GHIJKLMNOPQRSTUVWXYZ"; */
|
||||
|
||||
switch (base) {
|
||||
case 10:
|
||||
if (num != 0)
|
||||
|
|
@ -140,6 +144,29 @@ char *number(char *end, unsigned long long num, int base, char locase)
|
|||
return end;
|
||||
}
|
||||
|
||||
static char *guid_to_str(const efi_guid_t *guid, char *out, char locase)
|
||||
{
|
||||
static const u8 guid_index[UUID_SIZE] = {
|
||||
3, 2, 1, 0, 5, 4, 7, 6, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
};
|
||||
|
||||
for (int i = 0, p = 0; i < ARRAY_SIZE(guid_index); i++) {
|
||||
u8 byte = guid->b[guid_index[i]];
|
||||
|
||||
out[p++] = locase | digits[byte >> 4];
|
||||
out[p++] = locase | digits[byte & 0xf];
|
||||
|
||||
switch (i) {
|
||||
case 3:
|
||||
case 5:
|
||||
case 7:
|
||||
case 9:
|
||||
out[p++] = '-';
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
#define ZEROPAD 1 /* pad with zero */
|
||||
#define SIGN 2 /* unsigned/signed long */
|
||||
#define PLUS 4 /* show plus */
|
||||
|
|
@ -239,58 +266,6 @@ char get_sign(long long *num, int flags)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
size_t utf16s_utf8nlen(const u16 *s16, size_t maxlen)
|
||||
{
|
||||
size_t len, clen;
|
||||
|
||||
for (len = 0; len < maxlen && *s16; len += clen) {
|
||||
u16 c0 = *s16++;
|
||||
|
||||
/* First, get the length for a BMP character */
|
||||
clen = 1 + (c0 >= 0x80) + (c0 >= 0x800);
|
||||
if (len + clen > maxlen)
|
||||
break;
|
||||
/*
|
||||
* If this is a high surrogate, and we're already at maxlen, we
|
||||
* can't include the character if it's a valid surrogate pair.
|
||||
* Avoid accessing one extra word just to check if it's valid
|
||||
* or not.
|
||||
*/
|
||||
if ((c0 & 0xfc00) == 0xd800) {
|
||||
if (len + clen == maxlen)
|
||||
break;
|
||||
if ((*s16 & 0xfc00) == 0xdc00) {
|
||||
++s16;
|
||||
++clen;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static
|
||||
u32 utf16_to_utf32(const u16 **s16)
|
||||
{
|
||||
u16 c0, c1;
|
||||
|
||||
c0 = *(*s16)++;
|
||||
/* not a surrogate */
|
||||
if ((c0 & 0xf800) != 0xd800)
|
||||
return c0;
|
||||
/* invalid: low surrogate instead of high */
|
||||
if (c0 & 0x0400)
|
||||
return 0xfffd;
|
||||
c1 = **s16;
|
||||
/* invalid: missing low surrogate */
|
||||
if ((c1 & 0xfc00) != 0xdc00)
|
||||
return 0xfffd;
|
||||
/* valid surrogate pair */
|
||||
++(*s16);
|
||||
return (0x10000 - (0xd800 << 10) - 0xdc00) + (c0 << 10) + c1;
|
||||
}
|
||||
|
||||
#define PUTC(c) \
|
||||
do { \
|
||||
if (pos < size) \
|
||||
|
|
@ -298,10 +273,10 @@ do { \
|
|||
++pos; \
|
||||
} while (0);
|
||||
|
||||
int vsnprintf(char *buf, size_t size, const char *fmt, va_list ap)
|
||||
int efi_vsnprintf(efi_char16_t *buf, size_t size, const char *fmt, va_list ap,
|
||||
bool crlf)
|
||||
{
|
||||
/* The maximum space required is to print a 64-bit number in octal */
|
||||
char tmp[(sizeof(unsigned long long) * 8 + 2) / 3];
|
||||
char tmp[UUID_STRING_LEN];
|
||||
char *tmp_end = &tmp[ARRAY_SIZE(tmp)];
|
||||
long long num;
|
||||
int base;
|
||||
|
|
@ -336,6 +311,8 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list ap)
|
|||
|
||||
for (pos = 0; *fmt; ++fmt) {
|
||||
if (*fmt != '%' || *++fmt == '%') {
|
||||
if (crlf && *fmt == '\n')
|
||||
PUTC('\r');
|
||||
PUTC(*fmt);
|
||||
continue;
|
||||
}
|
||||
|
|
@ -400,7 +377,7 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list ap)
|
|||
else if (qualifier == 'l') {
|
||||
wstring:
|
||||
flags |= WIDE;
|
||||
precision = len = utf16s_utf8nlen((const u16 *)s, precision);
|
||||
precision = len = ucs2_strnlen((const u16 *)s, precision);
|
||||
goto output;
|
||||
}
|
||||
precision = len = strnlen(s, precision);
|
||||
|
|
@ -412,6 +389,14 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list ap)
|
|||
break;
|
||||
|
||||
case 'p':
|
||||
if (fmt[1] == 'U' && (fmt[2] | 0x20) == 'l') {
|
||||
flags &= LEFT;
|
||||
s = guid_to_str(va_arg(args, efi_guid_t *), tmp, fmt[2] & 0x20);
|
||||
precision = len = UUID_STRING_LEN;
|
||||
fmt += 2;
|
||||
goto output;
|
||||
}
|
||||
|
||||
if (precision < 0)
|
||||
precision = 2 * sizeof(void *);
|
||||
fallthrough;
|
||||
|
|
@ -505,36 +490,9 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list ap)
|
|||
if (flags & WIDE) {
|
||||
const u16 *ws = (const u16 *)s;
|
||||
|
||||
while (len-- > 0) {
|
||||
u32 c32 = utf16_to_utf32(&ws);
|
||||
u8 *s8;
|
||||
size_t clen;
|
||||
|
||||
if (c32 < 0x80) {
|
||||
PUTC(c32);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Number of trailing octets */
|
||||
clen = 1 + (c32 >= 0x800) + (c32 >= 0x10000);
|
||||
|
||||
len -= clen;
|
||||
s8 = (u8 *)&buf[pos];
|
||||
|
||||
/* Avoid writing partial character */
|
||||
PUTC('\0');
|
||||
pos += clen;
|
||||
if (pos >= size)
|
||||
continue;
|
||||
|
||||
/* Set high bits of leading octet */
|
||||
*s8 = (0xf00 >> 1) >> clen;
|
||||
/* Write trailing octets in reverse order */
|
||||
for (s8 += clen; clen; --clen, c32 >>= 6)
|
||||
*s8-- = 0x80 | (c32 & 0x3f);
|
||||
/* Set low bits of leading octet */
|
||||
*s8 |= c32;
|
||||
}
|
||||
if (pos < size)
|
||||
memcpy(&buf[pos], ws, min(len, size - pos) * sizeof(*ws));
|
||||
pos += len;
|
||||
} else {
|
||||
while (len-- > 0)
|
||||
PUTC(*s++);
|
||||
|
|
@ -552,13 +510,13 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list ap)
|
|||
return pos;
|
||||
}
|
||||
|
||||
int snprintf(char *buf, size_t size, const char *fmt, ...)
|
||||
int efi_snprintf(efi_char16_t *buf, size_t size, const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
int i;
|
||||
|
||||
va_start(args, fmt);
|
||||
i = vsnprintf(buf, size, fmt, args);
|
||||
i = efi_vsnprintf(buf, size, fmt, args, false);
|
||||
va_end(args);
|
||||
return i;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -116,9 +116,9 @@ preserve_pci_rom_image(efi_pci_io_protocol_t *pci, struct pci_setup_rom **__rom)
|
|||
*/
|
||||
static void setup_efi_pci(struct boot_params *params)
|
||||
{
|
||||
static efi_guid_t pci_proto = EFI_PCI_IO_PROTOCOL_GUID;
|
||||
efi_status_t status;
|
||||
efi_handle_t *pci_handle __free(efi_pool) = NULL;
|
||||
efi_guid_t pci_proto = EFI_PCI_IO_PROTOCOL_GUID;
|
||||
struct setup_data *data;
|
||||
unsigned long num;
|
||||
efi_handle_t h;
|
||||
|
|
@ -157,7 +157,7 @@ static void setup_efi_pci(struct boot_params *params)
|
|||
|
||||
static void retrieve_apple_device_properties(struct boot_params *boot_params)
|
||||
{
|
||||
efi_guid_t guid = APPLE_PROPERTIES_PROTOCOL_GUID;
|
||||
static efi_guid_t guid = APPLE_PROPERTIES_PROTOCOL_GUID;
|
||||
struct setup_data *data, *new;
|
||||
efi_status_t status;
|
||||
u32 size = 0;
|
||||
|
|
@ -337,6 +337,7 @@ static bool apple_match_product_name(void)
|
|||
|
||||
static void apple_set_os(void)
|
||||
{
|
||||
static efi_guid_t apple_set_os_guid = APPLE_SET_OS_PROTOCOL_GUID;
|
||||
struct {
|
||||
unsigned long version;
|
||||
efi_status_t (__efiapi *set_os_version)(const char *);
|
||||
|
|
@ -347,7 +348,7 @@ static void apple_set_os(void)
|
|||
if (!efi_is_64bit() || !apple_match_product_name())
|
||||
return;
|
||||
|
||||
status = efi_bs_call(locate_protocol, &APPLE_SET_OS_PROTOCOL_GUID, NULL,
|
||||
status = efi_bs_call(locate_protocol, &apple_set_os_guid, NULL,
|
||||
(void **)&set_os);
|
||||
if (status != EFI_SUCCESS)
|
||||
return;
|
||||
|
|
@ -446,7 +447,7 @@ efi_status_t efi_adjust_memory_range_protection(unsigned long start,
|
|||
|
||||
static void setup_unaccepted_memory(void)
|
||||
{
|
||||
efi_guid_t mem_acceptance_proto = OVMF_SEV_MEMORY_ACCEPTANCE_PROTOCOL_GUID;
|
||||
static efi_guid_t mem_acceptance_proto = OVMF_SEV_MEMORY_ACCEPTANCE_PROTOCOL_GUID;
|
||||
sev_memory_acceptance_protocol_t *proto;
|
||||
efi_status_t status;
|
||||
|
||||
|
|
@ -509,7 +510,7 @@ static void __noreturn efi_exit(efi_handle_t handle, efi_status_t status)
|
|||
static efi_status_t efi_allocate_bootparams(efi_handle_t handle,
|
||||
struct boot_params **bp)
|
||||
{
|
||||
efi_guid_t proto = LOADED_IMAGE_PROTOCOL_GUID;
|
||||
static efi_guid_t proto = LOADED_IMAGE_PROTOCOL_GUID;
|
||||
struct boot_params *boot_params;
|
||||
struct setup_header *hdr;
|
||||
efi_status_t status;
|
||||
|
|
@ -650,7 +651,7 @@ setup_e820(struct boot_params *params, struct setup_data *e820ext, u32 e820ext_s
|
|||
}
|
||||
|
||||
if (nr_entries == ARRAY_SIZE(params->e820_table)) {
|
||||
u32 need = (nr_desc - i) * sizeof(struct e820_entry) +
|
||||
u32 need = (nr_desc - i) * sizeof(struct boot_e820_entry) +
|
||||
sizeof(struct setup_data);
|
||||
|
||||
if (!e820ext || e820ext_size < need)
|
||||
|
|
@ -686,7 +687,7 @@ static efi_status_t alloc_e820ext(u32 nr_desc, struct setup_data **e820ext,
|
|||
unsigned long size;
|
||||
|
||||
size = sizeof(struct setup_data) +
|
||||
sizeof(struct e820_entry) * nr_desc;
|
||||
sizeof(struct boot_e820_entry) * nr_desc;
|
||||
|
||||
if (*e820ext) {
|
||||
efi_bs_call(free_pool, *e820ext);
|
||||
|
|
@ -911,12 +912,13 @@ static void __noreturn enter_kernel(unsigned long kernel_addr,
|
|||
* return. On failure, it will exit to the firmware via efi_exit() instead of
|
||||
* returning.
|
||||
*/
|
||||
MIXED_EXTERN
|
||||
void __noreturn efi_stub_entry(efi_handle_t handle,
|
||||
efi_system_table_t *sys_table_arg,
|
||||
struct boot_params *boot_params)
|
||||
|
||||
{
|
||||
efi_guid_t guid = EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID;
|
||||
static efi_guid_t guid = EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID;
|
||||
const struct linux_efi_initrd *initrd = NULL;
|
||||
unsigned long kernel_entry;
|
||||
struct setup_header *hdr;
|
||||
|
|
@ -1016,6 +1018,7 @@ void __noreturn efi_stub_entry(efi_handle_t handle,
|
|||
efi_random_get_seed();
|
||||
|
||||
efi_retrieve_eventlog();
|
||||
efi_bli_set_variables(image);
|
||||
|
||||
setup_graphics(boot_params);
|
||||
|
||||
|
|
@ -1053,6 +1056,7 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
|
|||
}
|
||||
|
||||
#ifdef CONFIG_EFI_HANDOVER_PROTOCOL
|
||||
MIXED_EXTERN
|
||||
void efi_handover_entry(efi_handle_t handle, efi_system_table_t *sys_table_arg,
|
||||
struct boot_params *boot_params)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -8,6 +8,22 @@ extern const u16 trampoline_ljmp_imm_offset;
|
|||
efi_status_t efi_adjust_memory_range_protection(unsigned long start,
|
||||
unsigned long size);
|
||||
|
||||
#ifdef CONFIG_EFI_MIXED
|
||||
#define MIXED_EXTERN asmlinkage
|
||||
|
||||
struct boot_params;
|
||||
|
||||
asmlinkage void __noreturn efi_stub_entry(efi_handle_t handle,
|
||||
efi_system_table_t *sys_table_arg,
|
||||
struct boot_params *boot_params);
|
||||
asmlinkage void efi_handover_entry(efi_handle_t handle,
|
||||
efi_system_table_t *sys_table_arg,
|
||||
struct boot_params *boot_params);
|
||||
|
||||
#else
|
||||
#define MIXED_EXTERN static
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
efi_status_t efi_setup_5level_paging(void);
|
||||
void efi_5level_switch(void);
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ struct sysfb_display_info *alloc_primary_display(void)
|
|||
asmlinkage efi_status_t __efiapi
|
||||
efi_zboot_entry(efi_handle_t handle, efi_system_table_t *systab)
|
||||
{
|
||||
static efi_guid_t loaded_image_guid = LOADED_IMAGE_PROTOCOL_GUID;
|
||||
char *cmdline_ptr __free(efi_pool) = NULL;
|
||||
unsigned long image_base, alloc_size;
|
||||
efi_loaded_image_t *image;
|
||||
|
|
@ -42,7 +43,7 @@ efi_zboot_entry(efi_handle_t handle, efi_system_table_t *systab)
|
|||
WRITE_ONCE(efi_system_table, systab);
|
||||
|
||||
status = efi_bs_call(handle_protocol, handle,
|
||||
&LOADED_IMAGE_PROTOCOL_GUID, (void **)&image);
|
||||
&loaded_image_guid, (void **)&image);
|
||||
if (status != EFI_SUCCESS) {
|
||||
efi_err("Failed to locate parent's loaded image protocol\n");
|
||||
return status;
|
||||
|
|
|
|||
|
|
@ -126,6 +126,12 @@ struct efi_runtime_work efi_rts_work;
|
|||
*/
|
||||
#define EFI_RTS_TIMEOUT (120 * HZ)
|
||||
|
||||
/*
|
||||
* Set when __efi_queue_work() gives up waiting for a call that is wedged in
|
||||
* firmware. EFI runtime services are disabled for good at that point.
|
||||
*/
|
||||
static bool efi_rts_abandoned;
|
||||
|
||||
/*
|
||||
* efi_queue_work: Queue EFI runtime service call and wait for completion
|
||||
* @_rts: EFI runtime service function identifier
|
||||
|
|
@ -331,12 +337,42 @@ static void __nocfi efi_call_rts(struct work_struct *work)
|
|||
* function identifier into efi_rts_work->efi_rts_id
|
||||
*/
|
||||
pr_err("Requested executing invalid EFI Runtime Service.\n");
|
||||
break;
|
||||
|
||||
#if IS_ENABLED(CONFIG_LKDTM)
|
||||
case EFI_LKDTM_RUNTIME_RO_TEST:
|
||||
/*
|
||||
* Call GetTime() with the output argument pointing to
|
||||
* executable memory, which should be mapped read-only in the
|
||||
* EFI page tables.
|
||||
*/
|
||||
status = efi_call_virt(get_time,
|
||||
(void *)efi.runtime->set_virtual_address_map,
|
||||
NULL);
|
||||
break;
|
||||
case EFI_LKDTM_RUNTIME_NX_TEST:
|
||||
/*
|
||||
* Call efi.runtime, which points to a data object in a EFI
|
||||
* runtime region, as if it were a function pointer.
|
||||
*/
|
||||
{
|
||||
struct { efi_status_t (*f)(int); } *s = (void *)&efi.runtime;
|
||||
|
||||
status = arch_efi_call_virt(s, f, 0);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
efi_call_virt_check_flags(flags, efi_rts_work.caller);
|
||||
arch_efi_call_virt_teardown();
|
||||
|
||||
if (!efi_enabled(EFI_RUNTIME_SERVICES))
|
||||
/*
|
||||
* EFI runtime services may also have been disabled because the
|
||||
* firmware faulted, but the caller is still waiting for us in that
|
||||
* case. Only park the worker if the caller has given up on it.
|
||||
*/
|
||||
if (READ_ONCE(efi_rts_abandoned))
|
||||
efi_rts_park_worker();
|
||||
|
||||
efi_rts_work.status = status;
|
||||
|
|
@ -373,6 +409,7 @@ static efi_status_t __efi_queue_work(enum efi_rts_ids id,
|
|||
EFI_RTS_TIMEOUT)) {
|
||||
pr_err("EFI runtime service %d wedged in firmware; disabling EFI runtime services\n",
|
||||
id);
|
||||
WRITE_ONCE(efi_rts_abandoned, true);
|
||||
clear_bit(EFI_RUNTIME_SERVICES, &efi.flags);
|
||||
return EFI_ABORTED;
|
||||
}
|
||||
|
|
@ -612,6 +649,34 @@ static efi_status_t virt_efi_query_capsule_caps(efi_capsule_header_t **capsules,
|
|||
return status;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_LKDTM)
|
||||
static efi_status_t efi_lkdtm_rt_test(enum efi_rts_ids id)
|
||||
{
|
||||
efi_status_t status;
|
||||
|
||||
if (!efi_enabled(EFI_RUNTIME_SERVICES) || !efi_enabled(EFI_MEM_ATTR))
|
||||
return EFI_NOT_READY;
|
||||
|
||||
switch (id) {
|
||||
case EFI_LKDTM_RUNTIME_NX_TEST:
|
||||
break;
|
||||
case EFI_LKDTM_RUNTIME_RO_TEST:
|
||||
if (efi.get_time &&
|
||||
efi_rt_services_supported(EFI_RT_SUPPORTED_GET_TIME))
|
||||
break;
|
||||
fallthrough;
|
||||
default:
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
||||
|
||||
if (down_interruptible(&efi_runtime_lock))
|
||||
return EFI_NOT_READY;
|
||||
status = __efi_queue_work(id, NULL);
|
||||
up(&efi_runtime_lock);
|
||||
return status;
|
||||
}
|
||||
#endif
|
||||
|
||||
void __init efi_native_runtime_setup(void)
|
||||
{
|
||||
efi.get_time = virt_efi_get_time;
|
||||
|
|
@ -628,6 +693,10 @@ void __init efi_native_runtime_setup(void)
|
|||
efi.query_variable_info_nonblocking = virt_efi_query_variable_info_nb;
|
||||
efi.update_capsule = virt_efi_update_capsule;
|
||||
efi.query_capsule_caps = virt_efi_query_capsule_caps;
|
||||
|
||||
#if IS_ENABLED(CONFIG_LKDTM)
|
||||
efi.lkdtm_rt_test = efi_lkdtm_rt_test;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ACPI_PRMT
|
||||
|
|
@ -652,3 +721,31 @@ void efi_runtime_assert_lock_held(void)
|
|||
{
|
||||
WARN_ON(efi_runtime_lock_owner != current);
|
||||
}
|
||||
|
||||
efi_status_t efi_runtime_set_enable_flag(bool enable)
|
||||
{
|
||||
static bool runtime_disabled;
|
||||
efi_status_t ret = EFI_NOT_READY;
|
||||
|
||||
if (down_interruptible(&efi_runtime_lock))
|
||||
return EFI_ABORTED;
|
||||
|
||||
if (enable) {
|
||||
/* It could be enabled only if it is disabled here */
|
||||
if (runtime_disabled) {
|
||||
set_bit(EFI_RUNTIME_SERVICES, &efi.flags);
|
||||
runtime_disabled = false;
|
||||
ret = EFI_SUCCESS;
|
||||
}
|
||||
} else {
|
||||
if (efi_enabled(EFI_RUNTIME_SERVICES)) {
|
||||
clear_bit(EFI_RUNTIME_SERVICES, &efi.flags);
|
||||
runtime_disabled = true;
|
||||
ret = EFI_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
up(&efi_runtime_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -841,6 +841,37 @@ static void __maybe_unused lkdtm_EFI_RUNTIME_CRASH(void)
|
|||
status);
|
||||
}
|
||||
|
||||
static void efi_rt_test(enum efi_rts_ids id, const char *desc)
|
||||
{
|
||||
if (!efi_enabled(EFI_RUNTIME_SERVICES)) {
|
||||
pr_err("XFAIL: EFI runtime services have been disabled\n");
|
||||
return;
|
||||
} else if (!efi_enabled(EFI_MEM_ATTR)) {
|
||||
pr_err("XFAIL: EFI memory attributes table not provided by firmware\n");
|
||||
return;
|
||||
} else if (!efi.lkdtm_rt_test) {
|
||||
pr_err("XFAIL: Only supported with native EFI runtime services\n");
|
||||
return;
|
||||
}
|
||||
|
||||
efi_status_t status = efi.lkdtm_rt_test(id);
|
||||
if (status == EFI_UNSUPPORTED)
|
||||
pr_err("XFAIL: EFI runtime service not implemented by firmware\n");
|
||||
else if (status != EFI_ABORTED || efi_enabled(EFI_RUNTIME_SERVICES))
|
||||
pr_err("FAIL: EFI %s memory not caught (%#lx)\n",
|
||||
desc, status);
|
||||
}
|
||||
|
||||
static void __maybe_unused lkdtm_EFI_RUNTIME_WRITE_TO_RO(void)
|
||||
{
|
||||
efi_rt_test(EFI_LKDTM_RUNTIME_RO_TEST, "write to RO");
|
||||
}
|
||||
|
||||
static void __maybe_unused lkdtm_EFI_RUNTIME_BRANCH_TO_NX(void)
|
||||
{
|
||||
efi_rt_test(EFI_LKDTM_RUNTIME_NX_TEST, "branch to NX");
|
||||
}
|
||||
|
||||
static struct crashtype crashtypes[] = {
|
||||
CRASHTYPE(PANIC),
|
||||
CRASHTYPE(PANIC_STOP_IRQOFF),
|
||||
|
|
@ -876,6 +907,8 @@ static struct crashtype crashtypes[] = {
|
|||
CRASHTYPE(CORRUPT_PAC),
|
||||
#ifdef CONFIG_EFI
|
||||
CRASHTYPE(EFI_RUNTIME_CRASH),
|
||||
CRASHTYPE(EFI_RUNTIME_WRITE_TO_RO),
|
||||
CRASHTYPE(EFI_RUNTIME_BRANCH_TO_NX),
|
||||
#endif
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
struct efivarfs_mount_opts {
|
||||
kuid_t uid;
|
||||
kgid_t gid;
|
||||
bool nostatfs;
|
||||
};
|
||||
|
||||
struct efivarfs_fs_info {
|
||||
|
|
|
|||
|
|
@ -74,6 +74,8 @@ static int efivarfs_show_options(struct seq_file *m, struct dentry *root)
|
|||
if (!gid_eq(opts->gid, GLOBAL_ROOT_GID))
|
||||
seq_printf(m, ",gid=%u",
|
||||
from_kgid_munged(&init_user_ns, opts->gid));
|
||||
if (opts->nostatfs)
|
||||
seq_puts(m, ",nostatfs");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -82,13 +84,18 @@ static int efivarfs_statfs(struct dentry *dentry, struct kstatfs *buf)
|
|||
const u32 attr = EFI_VARIABLE_NON_VOLATILE |
|
||||
EFI_VARIABLE_BOOTSERVICE_ACCESS |
|
||||
EFI_VARIABLE_RUNTIME_ACCESS;
|
||||
struct efivarfs_fs_info *sfi = dentry->d_sb->s_fs_info;
|
||||
u64 storage_space, remaining_space, max_variable_size;
|
||||
u64 id = huge_encode_dev(dentry->d_sb->s_dev);
|
||||
efi_status_t status;
|
||||
|
||||
/* Some UEFI firmware does not implement QueryVariableInfo() */
|
||||
/*
|
||||
* With nostatfs, or on firmware that does not implement
|
||||
* QueryVariableInfo(), report zero used/available.
|
||||
*/
|
||||
storage_space = remaining_space = 0;
|
||||
if (efi_rt_services_supported(EFI_RT_SUPPORTED_QUERY_VARIABLE_INFO)) {
|
||||
if (!sfi->mount_opts.nostatfs &&
|
||||
efi_rt_services_supported(EFI_RT_SUPPORTED_QUERY_VARIABLE_INFO)) {
|
||||
static DEFINE_RATELIMIT_STATE(_rs, 2 * HZ, 5);
|
||||
static u64 storage, remaining;
|
||||
static DEFINE_SPINLOCK(lock);
|
||||
|
|
@ -323,12 +330,13 @@ static int efivarfs_callback(efi_char16_t *name16, efi_guid_t vendor,
|
|||
}
|
||||
|
||||
enum {
|
||||
Opt_uid, Opt_gid,
|
||||
Opt_uid, Opt_gid, Opt_statfs,
|
||||
};
|
||||
|
||||
static const struct fs_parameter_spec efivarfs_parameters[] = {
|
||||
fsparam_uid("uid", Opt_uid),
|
||||
fsparam_gid("gid", Opt_gid),
|
||||
fsparam_flag_no("statfs", Opt_statfs),
|
||||
{},
|
||||
};
|
||||
|
||||
|
|
@ -350,6 +358,9 @@ static int efivarfs_parse_param(struct fs_context *fc, struct fs_parameter *para
|
|||
case Opt_gid:
|
||||
opts->gid = result.gid;
|
||||
break;
|
||||
case Opt_statfs:
|
||||
opts->nostatfs = result.negated;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
@ -402,11 +413,17 @@ static int efivarfs_get_tree(struct fs_context *fc)
|
|||
|
||||
static int efivarfs_reconfigure(struct fs_context *fc)
|
||||
{
|
||||
struct efivarfs_fs_info *sfi = fc->root->d_sb->s_fs_info;
|
||||
struct efivarfs_fs_info *new_sfi = fc->s_fs_info;
|
||||
|
||||
if (!efivar_supports_writes() && !(fc->sb_flags & SB_RDONLY)) {
|
||||
pr_err("Firmware does not support SetVariableRT. Can not remount with rw\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* statfs()/show_options() read nostatfs locklessly; benign race. */
|
||||
data_race(sfi->mount_opts.nostatfs = new_sfi->mount_opts.nostatfs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -524,8 +541,17 @@ static int efivarfs_init_fs_context(struct fs_context *fc)
|
|||
if (!sfi)
|
||||
return -ENOMEM;
|
||||
|
||||
sfi->mount_opts.uid = GLOBAL_ROOT_UID;
|
||||
sfi->mount_opts.gid = GLOBAL_ROOT_GID;
|
||||
if (fc->purpose == FS_CONTEXT_FOR_RECONFIGURE) {
|
||||
/* nostatfs is writable via remount; keep it if not respecified. */
|
||||
struct efivarfs_fs_info *old = fc->root->d_sb->s_fs_info;
|
||||
|
||||
sfi->mount_opts.nostatfs = old->mount_opts.nostatfs;
|
||||
} else {
|
||||
sfi->mount_opts.uid = GLOBAL_ROOT_UID;
|
||||
sfi->mount_opts.gid = GLOBAL_ROOT_GID;
|
||||
/* QueryVariableInfo() stalls the CPU; default nostatfs on PREEMPT_RT. */
|
||||
sfi->mount_opts.nostatfs = IS_ENABLED(CONFIG_PREEMPT_RT);
|
||||
}
|
||||
|
||||
fc->s_fs_info = sfi;
|
||||
fc->ops = &efivarfs_context_ops;
|
||||
|
|
|
|||
|
|
@ -631,6 +631,8 @@ typedef struct {
|
|||
|
||||
extern unsigned long __ro_after_init efi_rng_seed; /* RNG Seed table */
|
||||
|
||||
enum efi_rts_ids;
|
||||
|
||||
/*
|
||||
* All runtime access to EFI goes through this structure:
|
||||
*/
|
||||
|
|
@ -650,6 +652,7 @@ extern struct efi {
|
|||
unsigned long mokvar_table; /* MOK variable config table */
|
||||
unsigned long coco_secret; /* Confidential computing secret table */
|
||||
unsigned long unaccepted; /* Unaccepted memory table */
|
||||
unsigned long mem_reserve; /* Persistent memory reservations */
|
||||
|
||||
efi_get_time_t *get_time;
|
||||
efi_set_time_t *set_time;
|
||||
|
|
@ -666,6 +669,10 @@ extern struct efi {
|
|||
efi_get_next_high_mono_count_t *get_next_high_mono_count;
|
||||
efi_reset_system_t *reset_system;
|
||||
|
||||
#if IS_ENABLED(CONFIG_LKDTM)
|
||||
efi_status_t (*lkdtm_rt_test)(enum efi_rts_ids id);
|
||||
#endif
|
||||
|
||||
struct efi_memory_map memmap;
|
||||
unsigned long flags;
|
||||
} efi;
|
||||
|
|
@ -957,6 +964,17 @@ extern int efi_status_to_err(efi_status_t status);
|
|||
#define EFI_DEV_END_INSTANCE 0x01
|
||||
#define EFI_DEV_END_ENTIRE 0xFF
|
||||
|
||||
enum efi_hd_partition_format {
|
||||
EFI_HD_PARTITION_FORMAT_MBR = 1,
|
||||
EFI_HD_PARTITION_FORMAT_GPT,
|
||||
};
|
||||
|
||||
enum efi_hd_signature_type {
|
||||
EFI_HD_SIGNATURE_TYPE_NONE,
|
||||
EFI_HD_SIGNATURE_TYPE_MBR,
|
||||
EFI_HD_SIGNATURE_TYPE_GUID,
|
||||
};
|
||||
|
||||
struct efi_generic_dev_path {
|
||||
u8 type;
|
||||
u8 sub_type;
|
||||
|
|
@ -988,6 +1006,16 @@ struct efi_rel_offset_dev_path {
|
|||
u64 ending_offset;
|
||||
} __packed;
|
||||
|
||||
struct efi_hd_dev_path {
|
||||
struct efi_generic_dev_path header;
|
||||
u32 partition_number;
|
||||
u64 partition_start;
|
||||
u64 partition_size;
|
||||
efi_guid_t signature;
|
||||
u8 partition_format;
|
||||
u8 signature_type;
|
||||
} __packed;
|
||||
|
||||
struct efi_mem_mapped_dev_path {
|
||||
struct efi_generic_dev_path header;
|
||||
u32 memory_type;
|
||||
|
|
@ -1007,6 +1035,7 @@ struct efi_dev_path {
|
|||
struct efi_pci_dev_path pci;
|
||||
struct efi_vendor_dev_path vendor;
|
||||
struct efi_rel_offset_dev_path rel_offset;
|
||||
struct efi_hd_dev_path hd;
|
||||
};
|
||||
} __packed;
|
||||
|
||||
|
|
@ -1109,6 +1138,7 @@ extern void efi_call_virt_check_flags(unsigned long flags, const void *caller);
|
|||
extern unsigned long efi_call_virt_save_flags(void);
|
||||
|
||||
void efi_runtime_assert_lock_held(void);
|
||||
efi_status_t efi_runtime_set_enable_flag(bool enable);
|
||||
|
||||
enum efi_secureboot_mode {
|
||||
efi_secureboot_mode_unset,
|
||||
|
|
@ -1230,6 +1260,10 @@ enum efi_rts_ids {
|
|||
EFI_UPDATE_CAPSULE,
|
||||
EFI_QUERY_CAPSULE_CAPS,
|
||||
EFI_ACPI_PRM_HANDLER,
|
||||
#if IS_ENABLED(CONFIG_LKDTM)
|
||||
EFI_LKDTM_RUNTIME_RO_TEST,
|
||||
EFI_LKDTM_RUNTIME_NX_TEST,
|
||||
#endif
|
||||
};
|
||||
|
||||
union efi_rts_args;
|
||||
|
|
@ -1330,7 +1364,8 @@ bool efi_config_table_is_usable(const efi_guid_t *guid, unsigned long table)
|
|||
return xen_efi_config_table_is_usable(guid, table);
|
||||
}
|
||||
|
||||
umode_t efi_attr_is_visible(struct kobject *kobj, struct attribute *attr, int n);
|
||||
umode_t efi_attr_is_visible(struct kobject *kobj, const struct attribute *attr,
|
||||
int n);
|
||||
|
||||
int ovmf_log_probe(unsigned long ovmf_debug_log_table);
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,16 @@ ssize_t ucs2_strscpy(ucs2_char_t *dst, const ucs2_char_t *src, size_t count);
|
|||
int ucs2_strncmp(const ucs2_char_t *a, const ucs2_char_t *b, size_t len);
|
||||
|
||||
unsigned long ucs2_utf8size(const ucs2_char_t *src);
|
||||
unsigned long
|
||||
ucs2_as_utf8_l(u8 *dest, const ucs2_char_t *src, unsigned long limit,
|
||||
unsigned long maxlength);
|
||||
|
||||
static inline
|
||||
unsigned long ucs2_as_utf8(u8 *dest, const ucs2_char_t *src,
|
||||
unsigned long maxlength);
|
||||
unsigned long maxlength)
|
||||
{
|
||||
return ucs2_as_utf8_l(dest, src, ucs2_strnlen(src, maxlength),
|
||||
maxlength);
|
||||
}
|
||||
|
||||
#endif /* _LINUX_UCS2_STRING_H_ */
|
||||
|
|
|
|||
|
|
@ -51,20 +51,18 @@ EXPORT_SYMBOL(ucs2_strsize);
|
|||
*/
|
||||
ssize_t ucs2_strscpy(ucs2_char_t *dst, const ucs2_char_t *src, size_t count)
|
||||
{
|
||||
long res;
|
||||
|
||||
/*
|
||||
* Ensure that we have a valid amount of space. We need to store at
|
||||
* least one NUL-character.
|
||||
*/
|
||||
if (count == 0 || WARN_ON_ONCE(count > INT_MAX / sizeof(*dst)))
|
||||
if (count == 0 || count > SSIZE_MAX)
|
||||
return -E2BIG;
|
||||
|
||||
/*
|
||||
* Copy at most 'count' characters, return early if we find a
|
||||
* NUL-terminator.
|
||||
*/
|
||||
for (res = 0; res < count; res++) {
|
||||
for (ssize_t res = 0; res < count; res++) {
|
||||
ucs2_char_t c;
|
||||
|
||||
c = src[res];
|
||||
|
|
@ -125,18 +123,19 @@ ucs2_utf8size(const ucs2_char_t *src)
|
|||
EXPORT_SYMBOL(ucs2_utf8size);
|
||||
|
||||
/*
|
||||
* copy at most maxlength bytes of whole utf8 characters to dest from the
|
||||
* ucs2 string src.
|
||||
* Copy at most @limit whole utf8 characters to @dest from the ucs2 string
|
||||
* @src, using no more than @maxlength bytes of buffer space.
|
||||
*
|
||||
* The return value is the number of characters copied, not including the
|
||||
* final NUL character.
|
||||
* The return value is the number of bytes copied, not including the final NUL
|
||||
* character. No NUL character will be appended if the output length equals
|
||||
* @maxlength.
|
||||
*/
|
||||
unsigned long
|
||||
ucs2_as_utf8(u8 *dest, const ucs2_char_t *src, unsigned long maxlength)
|
||||
ucs2_as_utf8_l(u8 *dest, const ucs2_char_t *src, unsigned long limit,
|
||||
unsigned long maxlength)
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned long j = 0;
|
||||
unsigned long limit = ucs2_strnlen(src, maxlength);
|
||||
|
||||
for (i = 0; maxlength && i < limit; i++) {
|
||||
u16 c = src[i];
|
||||
|
|
@ -163,7 +162,9 @@ ucs2_as_utf8(u8 *dest, const ucs2_char_t *src, unsigned long maxlength)
|
|||
dest[j] = '\0';
|
||||
return j;
|
||||
}
|
||||
EXPORT_SYMBOL(ucs2_as_utf8);
|
||||
EXPORT_SYMBOL(ucs2_as_utf8_l);
|
||||
|
||||
#ifndef __DISABLE_EXPORTS
|
||||
MODULE_DESCRIPTION("UCS2 string handling");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user