forked from Minki/linux
EFI changes for v5.10:
- Preliminary RISC-V enablement - the bulk of it will arrive via the RISCV tree. - Relax decompressed image placement rules for 32-bit ARM - Add support for passing MOK certificate table contents via a config table rather than a EFI variable. - Add support for 18 bit DIMM row IDs in the CPER records. - Work around broken Dell firmware that passes the entire Boot#### variable contents as the command line - Add definition of the EFI_MEMORY_CPU_CRYPTO memory attribute so we can identify it in the memory map listings. - Don't abort the boot on arm64 if the EFI RNG protocol is available but returns with an error - Replace slashes with exclamation marks in efivarfs file names - Split efi-pstore from the deprecated efivars sysfs code, so we can disable the latter on !x86. - Misc fixes, cleanups and updates. Signed-off-by: Ingo Molnar <mingo@kernel.org> -----BEGIN PGP SIGNATURE----- iQJFBAABCgAvFiEEBpT5eoXrXCwVQwEKEnMQ0APhK1gFAl+Ec9QRHG1pbmdvQGtl cm5lbC5vcmcACgkQEnMQ0APhK1inTQ//TYj3kJq/7sWfUAxmAsWnUEC005YCNf0T x3kJQv3zYX4Rl4eEwkff8S1PrqqvwUP5yUZYApp8HD9s9CYvzz5iG5xtf/jX+QaV 06JnTMnkoycx2NaOlbr1cmcIn4/cAhQVYbVCeVrlf7QL8enNTBr5IIQmo4mgP8Lc mauSsO1XU8ZuMQM+JcZSxAkAPxlhz3dbR5GteP4o2K4ShQKpiTCOfOG1J3FvUYba s1HGnhHFlkQr6m3pC+iG8dnAG0YtwHMH1eJVP7mbeKUsMXz944U8OVXDWxtn81pH /Xt/aFZXnoqwlSXythAr6vFTuEEn40n+qoOK6jhtcGPUeiAFPJgiaeAXw3gO0YBe Y8nEgdGfdNOMih94McRd4M6gB/N3vdqAGt+vjiZSCtzE+nTWRyIXSGCXuDVpkvL4 VpEXpPINnt1FZZ3T/7dPro4X7pXALhODE+pl36RCbfHVBZKRfLV1Mc1prAUGXPxW E0MfaM9TxDnVhs3VPWlHmRgavee2MT1Tl/ES4CrRHEoz8ZCcu4MfROQyao8+Gobr VR+jVk+xbyDrykEc6jdAK4sDFXpTambuV624LiKkh6Mc4yfHRhPGrmP5c5l7SnCd aLp+scQ4T7sqkLuYlXpausXE3h4sm5uur5hNIRpdlvnwZBXpDEpkzI8x0C9OYr0Q kvFrreQWPLQ= =ZNI8 -----END PGP SIGNATURE----- Merge tag 'efi-core-2020-10-12' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip Pull EFI changes from Ingo Molnar: - Preliminary RISC-V enablement - the bulk of it will arrive via the RISCV tree. - Relax decompressed image placement rules for 32-bit ARM - Add support for passing MOK certificate table contents via a config table rather than a EFI variable. - Add support for 18 bit DIMM row IDs in the CPER records. - Work around broken Dell firmware that passes the entire Boot#### variable contents as the command line - Add definition of the EFI_MEMORY_CPU_CRYPTO memory attribute so we can identify it in the memory map listings. - Don't abort the boot on arm64 if the EFI RNG protocol is available but returns with an error - Replace slashes with exclamation marks in efivarfs file names - Split efi-pstore from the deprecated efivars sysfs code, so we can disable the latter on !x86. - Misc fixes, cleanups and updates. * tag 'efi-core-2020-10-12' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (26 commits) efi: mokvar: add missing include of asm/early_ioremap.h efi: efivars: limit availability to X86 builds efi: remove some false dependencies on CONFIG_EFI_VARS efi: gsmi: fix false dependency on CONFIG_EFI_VARS efi: efivars: un-export efivars_sysfs_init() efi: pstore: move workqueue handling out of efivars efi: pstore: disentangle from deprecated efivars module efi: mokvar-table: fix some issues in new code efi/arm64: libstub: Deal gracefully with EFI_RNG_PROTOCOL failure efivarfs: Replace invalid slashes with exclamation marks in dentries. efi: Delete deprecated parameter comments efi/libstub: Fix missing-prototypes in string.c efi: Add definition of EFI_MEMORY_CPU_CRYPTO and ability to report it cper,edac,efi: Memory Error Record: bank group/address and chip id edac,ghes,cper: Add Row Extension to Memory Error Record efi/x86: Add a quirk to support command line arguments on Dell EFI firmware efi/libstub: Add efi_warn and *_once logging helpers integrity: Load certs from the EFI MOK config table integrity: Move import of MokListRT certs to a separate routine efi: Support for MOK variable config table ...
This commit is contained in:
commit
e6412f9833
@ -23,7 +23,7 @@ makes it possible for the kernel to support additional features:
|
||||
For actually enabling [U]EFI support, enable:
|
||||
|
||||
- CONFIG_EFI=y
|
||||
- CONFIG_EFI_VARS=y or m
|
||||
- CONFIG_EFIVAR_FS=y or m
|
||||
|
||||
The implementation depends on receiving information about the UEFI environment
|
||||
in a Flattened Device Tree (FDT) - so is only available with CONFIG_OF.
|
||||
|
@ -66,25 +66,24 @@ static inline void efifb_setup_from_dmi(struct screen_info *si, const char *opt)
|
||||
#define MAX_UNCOMP_KERNEL_SIZE SZ_32M
|
||||
|
||||
/*
|
||||
* The kernel zImage should preferably be located between 32 MB and 128 MB
|
||||
* from the base of DRAM. The min address leaves space for a maximal size
|
||||
* uncompressed image, and the max address is due to how the zImage decompressor
|
||||
* picks a destination address.
|
||||
* phys-to-virt patching requires that the physical to virtual offset fits
|
||||
* into the immediate field of an add/sub instruction, which comes down to the
|
||||
* 24 least significant bits being zero, and so the offset should be a multiple
|
||||
* of 16 MB. Since PAGE_OFFSET itself is a multiple of 16 MB, the physical
|
||||
* base should be aligned to 16 MB as well.
|
||||
*/
|
||||
#define ZIMAGE_OFFSET_LIMIT SZ_128M
|
||||
#define MIN_ZIMAGE_OFFSET MAX_UNCOMP_KERNEL_SIZE
|
||||
#define EFI_PHYS_ALIGN SZ_16M
|
||||
|
||||
/* on ARM, the FDT should be located in the first 128 MB of RAM */
|
||||
static inline unsigned long efi_get_max_fdt_addr(unsigned long dram_base)
|
||||
/* on ARM, the FDT should be located in a lowmem region */
|
||||
static inline unsigned long efi_get_max_fdt_addr(unsigned long image_addr)
|
||||
{
|
||||
return dram_base + ZIMAGE_OFFSET_LIMIT;
|
||||
return round_down(image_addr, EFI_PHYS_ALIGN) + SZ_512M;
|
||||
}
|
||||
|
||||
/* on ARM, the initrd should be loaded in a lowmem region */
|
||||
static inline unsigned long efi_get_max_initrd_addr(unsigned long dram_base,
|
||||
unsigned long image_addr)
|
||||
static inline unsigned long efi_get_max_initrd_addr(unsigned long image_addr)
|
||||
{
|
||||
return dram_base + SZ_512M;
|
||||
return round_down(image_addr, EFI_PHYS_ALIGN) + SZ_512M;
|
||||
}
|
||||
|
||||
struct efi_arm_entry_state {
|
||||
|
@ -65,7 +65,7 @@ efi_status_t __efi_rt_asm_wrapper(void *, const char *, ...);
|
||||
(SEGMENT_ALIGN > THREAD_ALIGN ? SEGMENT_ALIGN : THREAD_ALIGN)
|
||||
|
||||
/* on arm64, the FDT may be located anywhere in system RAM */
|
||||
static inline unsigned long efi_get_max_fdt_addr(unsigned long dram_base)
|
||||
static inline unsigned long efi_get_max_fdt_addr(unsigned long image_addr)
|
||||
{
|
||||
return ULONG_MAX;
|
||||
}
|
||||
@ -80,8 +80,7 @@ static inline unsigned long efi_get_max_fdt_addr(unsigned long dram_base)
|
||||
* apply to other bootloaders, and are required for some kernel
|
||||
* configurations.
|
||||
*/
|
||||
static inline unsigned long efi_get_max_initrd_addr(unsigned long dram_base,
|
||||
unsigned long image_addr)
|
||||
static inline unsigned long efi_get_max_initrd_addr(unsigned long image_addr)
|
||||
{
|
||||
return (image_addr & ~(SZ_1G - 1UL)) + (1UL << (VA_BITS_MIN - 1));
|
||||
}
|
||||
|
@ -1077,6 +1077,7 @@ void __init setup_arch(char **cmdline_p)
|
||||
efi_fake_memmap();
|
||||
efi_find_mirror();
|
||||
efi_esrt_init();
|
||||
efi_mokvar_table_init();
|
||||
|
||||
/*
|
||||
* The EFI specification says that boot service code won't be
|
||||
|
@ -90,6 +90,9 @@ static const unsigned long * const efi_tables[] = {
|
||||
&efi.tpm_log,
|
||||
&efi.tpm_final_log,
|
||||
&efi_rng_seed,
|
||||
#ifdef CONFIG_LOAD_UEFI_KEYS
|
||||
&efi.mokvar_table,
|
||||
#endif
|
||||
};
|
||||
|
||||
u64 efi_setup; /* efi setup_data physical address */
|
||||
|
@ -372,8 +372,18 @@ void ghes_edac_report_mem_error(int sev, struct cper_sec_mem_err *mem_err)
|
||||
p += sprintf(p, "rank:%d ", mem_err->rank);
|
||||
if (mem_err->validation_bits & CPER_MEM_VALID_BANK)
|
||||
p += sprintf(p, "bank:%d ", mem_err->bank);
|
||||
if (mem_err->validation_bits & CPER_MEM_VALID_ROW)
|
||||
p += sprintf(p, "row:%d ", mem_err->row);
|
||||
if (mem_err->validation_bits & CPER_MEM_VALID_BANK_GROUP)
|
||||
p += sprintf(p, "bank_group:%d ",
|
||||
mem_err->bank >> CPER_MEM_BANK_GROUP_SHIFT);
|
||||
if (mem_err->validation_bits & CPER_MEM_VALID_BANK_ADDRESS)
|
||||
p += sprintf(p, "bank_address:%d ",
|
||||
mem_err->bank & CPER_MEM_BANK_ADDRESS_MASK);
|
||||
if (mem_err->validation_bits & (CPER_MEM_VALID_ROW | CPER_MEM_VALID_ROW_EXT)) {
|
||||
u32 row = mem_err->row;
|
||||
|
||||
row |= cper_get_mem_extension(mem_err->validation_bits, mem_err->extended);
|
||||
p += sprintf(p, "row:%d ", row);
|
||||
}
|
||||
if (mem_err->validation_bits & CPER_MEM_VALID_COLUMN)
|
||||
p += sprintf(p, "col:%d ", mem_err->column);
|
||||
if (mem_err->validation_bits & CPER_MEM_VALID_BIT_POSITION)
|
||||
@ -395,6 +405,9 @@ void ghes_edac_report_mem_error(int sev, struct cper_sec_mem_err *mem_err)
|
||||
strcpy(e->label, dimm->label);
|
||||
}
|
||||
}
|
||||
if (mem_err->validation_bits & CPER_MEM_VALID_CHIP_ID)
|
||||
p += sprintf(p, "chipID: %d ",
|
||||
mem_err->extended >> CPER_MEM_CHIP_ID_SHIFT);
|
||||
if (p > e->location)
|
||||
*(p - 1) = '\0';
|
||||
|
||||
|
@ -4,20 +4,15 @@ menu "EFI (Extensible Firmware Interface) Support"
|
||||
|
||||
config EFI_VARS
|
||||
tristate "EFI Variable Support via sysfs"
|
||||
depends on EFI
|
||||
depends on EFI && (X86 || IA64)
|
||||
default n
|
||||
help
|
||||
If you say Y here, you are able to get EFI (Extensible Firmware
|
||||
Interface) variable information via sysfs. You may read,
|
||||
write, create, and destroy EFI variables through this interface.
|
||||
|
||||
Note that using this driver in concert with efibootmgr requires
|
||||
at least test release version 0.5.0-test3 or later, which is
|
||||
available from:
|
||||
<http://linux.dell.com/efibootmgr/testing/efibootmgr-0.5.0-test3.tar.gz>
|
||||
|
||||
Subsequent efibootmgr releases may be found at:
|
||||
<http://github.com/vathpela/efibootmgr>
|
||||
Note that this driver is only retained for compatibility with
|
||||
legacy users: new users should use the efivarfs filesystem
|
||||
instead.
|
||||
|
||||
config EFI_ESRT
|
||||
bool
|
||||
@ -26,7 +21,7 @@ config EFI_ESRT
|
||||
|
||||
config EFI_VARS_PSTORE
|
||||
tristate "Register efivars backend for pstore"
|
||||
depends on EFI_VARS && PSTORE
|
||||
depends on PSTORE
|
||||
default y
|
||||
help
|
||||
Say Y here to enable use efivars as a backend to pstore. This
|
||||
@ -137,7 +132,6 @@ config EFI_GENERIC_STUB_INITRD_CMDLINE_LOADER
|
||||
|
||||
config EFI_BOOTLOADER_CONTROL
|
||||
tristate "EFI Bootloader Control"
|
||||
depends on EFI_VARS
|
||||
default n
|
||||
help
|
||||
This module installs a reboot hook, such that if reboot() is
|
||||
@ -281,7 +275,7 @@ config EFI_EARLYCON
|
||||
|
||||
config EFI_CUSTOM_SSDT_OVERLAYS
|
||||
bool "Load custom ACPI SSDT overlay from an EFI variable"
|
||||
depends on EFI_VARS && ACPI
|
||||
depends on EFI && ACPI
|
||||
default ACPI_TABLE_UPGRADE
|
||||
help
|
||||
Allow loading of an ACPI SSDT overlay from an EFI variable specified
|
||||
|
@ -28,11 +28,12 @@ obj-$(CONFIG_EFI_DEV_PATH_PARSER) += dev-path-parser.o
|
||||
obj-$(CONFIG_APPLE_PROPERTIES) += apple-properties.o
|
||||
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
|
||||
|
||||
arm-obj-$(CONFIG_EFI) := arm-init.o arm-runtime.o
|
||||
arm-obj-$(CONFIG_EFI) := efi-init.o arm-runtime.o
|
||||
obj-$(CONFIG_ARM) += $(arm-obj-y)
|
||||
obj-$(CONFIG_ARM64) += $(arm-obj-y)
|
||||
obj-$(CONFIG_EFI_CAPSULE_LOADER) += capsule-loader.o
|
||||
|
@ -232,10 +232,20 @@ static int cper_mem_err_location(struct cper_mem_err_compact *mem, char *msg)
|
||||
n += scnprintf(msg + n, len - n, "rank: %d ", mem->rank);
|
||||
if (mem->validation_bits & CPER_MEM_VALID_BANK)
|
||||
n += scnprintf(msg + n, len - n, "bank: %d ", mem->bank);
|
||||
if (mem->validation_bits & CPER_MEM_VALID_BANK_GROUP)
|
||||
n += scnprintf(msg + n, len - n, "bank_group: %d ",
|
||||
mem->bank >> CPER_MEM_BANK_GROUP_SHIFT);
|
||||
if (mem->validation_bits & CPER_MEM_VALID_BANK_ADDRESS)
|
||||
n += scnprintf(msg + n, len - n, "bank_address: %d ",
|
||||
mem->bank & CPER_MEM_BANK_ADDRESS_MASK);
|
||||
if (mem->validation_bits & CPER_MEM_VALID_DEVICE)
|
||||
n += scnprintf(msg + n, len - n, "device: %d ", mem->device);
|
||||
if (mem->validation_bits & CPER_MEM_VALID_ROW)
|
||||
n += scnprintf(msg + n, len - n, "row: %d ", mem->row);
|
||||
if (mem->validation_bits & (CPER_MEM_VALID_ROW | CPER_MEM_VALID_ROW_EXT)) {
|
||||
u32 row = mem->row;
|
||||
|
||||
row |= cper_get_mem_extension(mem->validation_bits, mem->extended);
|
||||
n += scnprintf(msg + n, len - n, "row: %d ", row);
|
||||
}
|
||||
if (mem->validation_bits & CPER_MEM_VALID_COLUMN)
|
||||
n += scnprintf(msg + n, len - n, "column: %d ", mem->column);
|
||||
if (mem->validation_bits & CPER_MEM_VALID_BIT_POSITION)
|
||||
@ -250,6 +260,9 @@ static int cper_mem_err_location(struct cper_mem_err_compact *mem, char *msg)
|
||||
if (mem->validation_bits & CPER_MEM_VALID_TARGET_ID)
|
||||
scnprintf(msg + n, len - n, "target_id: 0x%016llx ",
|
||||
mem->target_id);
|
||||
if (mem->validation_bits & CPER_MEM_VALID_CHIP_ID)
|
||||
scnprintf(msg + n, len - n, "chip_id: %d ",
|
||||
mem->extended >> CPER_MEM_CHIP_ID_SHIFT);
|
||||
|
||||
msg[n] = '\0';
|
||||
return n;
|
||||
@ -292,6 +305,7 @@ void cper_mem_err_pack(const struct cper_sec_mem_err *mem,
|
||||
cmem->requestor_id = mem->requestor_id;
|
||||
cmem->responder_id = mem->responder_id;
|
||||
cmem->target_id = mem->target_id;
|
||||
cmem->extended = mem->extended;
|
||||
cmem->rank = mem->rank;
|
||||
cmem->mem_array_handle = mem->mem_array_handle;
|
||||
cmem->mem_dev_handle = mem->mem_dev_handle;
|
||||
|
@ -236,6 +236,7 @@ void __init efi_init(void)
|
||||
|
||||
reserve_regions();
|
||||
efi_esrt_init();
|
||||
efi_mokvar_table_init();
|
||||
|
||||
memblock_reserve(data.phys_map & PAGE_MASK,
|
||||
PAGE_ALIGN(data.size + (data.phys_map & ~PAGE_MASK)));
|
@ -8,6 +8,8 @@
|
||||
|
||||
#define DUMP_NAME_LEN 66
|
||||
|
||||
#define EFIVARS_DATA_SIZE_MAX 1024
|
||||
|
||||
static bool efivars_pstore_disable =
|
||||
IS_ENABLED(CONFIG_EFI_VARS_PSTORE_DEFAULT_DISABLE);
|
||||
|
||||
@ -18,6 +20,9 @@ module_param_named(pstore_disable, efivars_pstore_disable, bool, 0644);
|
||||
EFI_VARIABLE_BOOTSERVICE_ACCESS | \
|
||||
EFI_VARIABLE_RUNTIME_ACCESS)
|
||||
|
||||
static LIST_HEAD(efi_pstore_list);
|
||||
static DECLARE_WORK(efivar_work, NULL);
|
||||
|
||||
static int efi_pstore_open(struct pstore_info *psi)
|
||||
{
|
||||
psi->data = NULL;
|
||||
@ -126,7 +131,7 @@ static inline int __efi_pstore_scan_sysfs_exit(struct efivar_entry *entry,
|
||||
if (entry->deleting) {
|
||||
list_del(&entry->list);
|
||||
efivar_entry_iter_end();
|
||||
efivar_unregister(entry);
|
||||
kfree(entry);
|
||||
if (efivar_entry_iter_begin())
|
||||
return -EINTR;
|
||||
} else if (turn_off_scanning)
|
||||
@ -169,7 +174,7 @@ static int efi_pstore_sysfs_entry_iter(struct pstore_record *record)
|
||||
{
|
||||
struct efivar_entry **pos = (struct efivar_entry **)&record->psi->data;
|
||||
struct efivar_entry *entry, *n;
|
||||
struct list_head *head = &efivar_sysfs_list;
|
||||
struct list_head *head = &efi_pstore_list;
|
||||
int size = 0;
|
||||
int ret;
|
||||
|
||||
@ -263,8 +268,9 @@ static int efi_pstore_write(struct pstore_record *record)
|
||||
ret = efivar_entry_set_safe(efi_name, vendor, PSTORE_EFI_ATTRIBUTES,
|
||||
preemptible(), record->size, record->psi->buf);
|
||||
|
||||
if (record->reason == KMSG_DUMP_OOPS)
|
||||
efivar_run_worker();
|
||||
if (record->reason == KMSG_DUMP_OOPS && try_module_get(THIS_MODULE))
|
||||
if (!schedule_work(&efivar_work))
|
||||
module_put(THIS_MODULE);
|
||||
|
||||
return ret;
|
||||
};
|
||||
@ -314,12 +320,12 @@ static int efi_pstore_erase_name(const char *name)
|
||||
if (efivar_entry_iter_begin())
|
||||
return -EINTR;
|
||||
|
||||
found = __efivar_entry_iter(efi_pstore_erase_func, &efivar_sysfs_list,
|
||||
found = __efivar_entry_iter(efi_pstore_erase_func, &efi_pstore_list,
|
||||
efi_name, &entry);
|
||||
efivar_entry_iter_end();
|
||||
|
||||
if (found && !entry->scanning)
|
||||
efivar_unregister(entry);
|
||||
kfree(entry);
|
||||
|
||||
return found ? 0 : -ENOENT;
|
||||
}
|
||||
@ -354,14 +360,77 @@ static struct pstore_info efi_pstore_info = {
|
||||
.erase = efi_pstore_erase,
|
||||
};
|
||||
|
||||
static int efi_pstore_callback(efi_char16_t *name, efi_guid_t vendor,
|
||||
unsigned long name_size, void *data)
|
||||
{
|
||||
struct efivar_entry *entry;
|
||||
int ret;
|
||||
|
||||
entry = kzalloc(sizeof(*entry), GFP_KERNEL);
|
||||
if (!entry)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(entry->var.VariableName, name, name_size);
|
||||
entry->var.VendorGuid = vendor;
|
||||
|
||||
ret = efivar_entry_add(entry, &efi_pstore_list);
|
||||
if (ret)
|
||||
kfree(entry);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int efi_pstore_update_entry(efi_char16_t *name, efi_guid_t vendor,
|
||||
unsigned long name_size, void *data)
|
||||
{
|
||||
struct efivar_entry *entry = data;
|
||||
|
||||
if (efivar_entry_find(name, vendor, &efi_pstore_list, false))
|
||||
return 0;
|
||||
|
||||
memcpy(entry->var.VariableName, name, name_size);
|
||||
memcpy(&(entry->var.VendorGuid), &vendor, sizeof(efi_guid_t));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void efi_pstore_update_entries(struct work_struct *work)
|
||||
{
|
||||
struct efivar_entry *entry;
|
||||
int err;
|
||||
|
||||
/* Add new sysfs entries */
|
||||
while (1) {
|
||||
entry = kzalloc(sizeof(*entry), GFP_KERNEL);
|
||||
if (!entry)
|
||||
return;
|
||||
|
||||
err = efivar_init(efi_pstore_update_entry, entry,
|
||||
false, &efi_pstore_list);
|
||||
if (!err)
|
||||
break;
|
||||
|
||||
efivar_entry_add(entry, &efi_pstore_list);
|
||||
}
|
||||
|
||||
kfree(entry);
|
||||
module_put(THIS_MODULE);
|
||||
}
|
||||
|
||||
static __init int efivars_pstore_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!efivars_kobject() || !efivar_supports_writes())
|
||||
return 0;
|
||||
|
||||
if (efivars_pstore_disable)
|
||||
return 0;
|
||||
|
||||
ret = efivar_init(efi_pstore_callback, NULL, true, &efi_pstore_list);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
efi_pstore_info.buf = kmalloc(4096, GFP_KERNEL);
|
||||
if (!efi_pstore_info.buf)
|
||||
return -ENOMEM;
|
||||
@ -374,6 +443,8 @@ static __init int efivars_pstore_init(void)
|
||||
efi_pstore_info.bufsize = 0;
|
||||
}
|
||||
|
||||
INIT_WORK(&efivar_work, efi_pstore_update_entries);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -43,6 +43,9 @@ struct efi __read_mostly efi = {
|
||||
.esrt = EFI_INVALID_TABLE_ADDR,
|
||||
.tpm_log = EFI_INVALID_TABLE_ADDR,
|
||||
.tpm_final_log = EFI_INVALID_TABLE_ADDR,
|
||||
#ifdef CONFIG_LOAD_UEFI_KEYS
|
||||
.mokvar_table = EFI_INVALID_TABLE_ADDR,
|
||||
#endif
|
||||
};
|
||||
EXPORT_SYMBOL(efi);
|
||||
|
||||
@ -518,6 +521,9 @@ static const efi_config_table_type_t common_tables[] __initconst = {
|
||||
{EFI_RT_PROPERTIES_TABLE_GUID, &rt_prop, "RTPROP" },
|
||||
#ifdef CONFIG_EFI_RCI2_TABLE
|
||||
{DELLEMC_EFI_RCI2_TABLE_GUID, &rci2_table_phys },
|
||||
#endif
|
||||
#ifdef CONFIG_LOAD_UEFI_KEYS
|
||||
{LINUX_EFI_MOK_VARIABLE_TABLE_GUID, &efi.mokvar_table, "MOKvar" },
|
||||
#endif
|
||||
{},
|
||||
};
|
||||
@ -714,7 +720,7 @@ void __init efi_systab_report_header(const efi_table_hdr_t *systab_hdr,
|
||||
vendor);
|
||||
}
|
||||
|
||||
static __initdata char memory_type_name[][20] = {
|
||||
static __initdata char memory_type_name[][13] = {
|
||||
"Reserved",
|
||||
"Loader Code",
|
||||
"Loader Data",
|
||||
@ -722,14 +728,14 @@ static __initdata char memory_type_name[][20] = {
|
||||
"Boot Data",
|
||||
"Runtime Code",
|
||||
"Runtime Data",
|
||||
"Conventional Memory",
|
||||
"Unusable Memory",
|
||||
"ACPI Reclaim Memory",
|
||||
"ACPI Memory NVS",
|
||||
"Memory Mapped I/O",
|
||||
"MMIO Port Space",
|
||||
"Conventional",
|
||||
"Unusable",
|
||||
"ACPI Reclaim",
|
||||
"ACPI Mem NVS",
|
||||
"MMIO",
|
||||
"MMIO Port",
|
||||
"PAL Code",
|
||||
"Persistent Memory",
|
||||
"Persistent",
|
||||
};
|
||||
|
||||
char * __init efi_md_typeattr_format(char *buf, size_t size,
|
||||
@ -756,26 +762,27 @@ char * __init efi_md_typeattr_format(char *buf, size_t size,
|
||||
if (attr & ~(EFI_MEMORY_UC | EFI_MEMORY_WC | EFI_MEMORY_WT |
|
||||
EFI_MEMORY_WB | EFI_MEMORY_UCE | EFI_MEMORY_RO |
|
||||
EFI_MEMORY_WP | EFI_MEMORY_RP | EFI_MEMORY_XP |
|
||||
EFI_MEMORY_NV | EFI_MEMORY_SP |
|
||||
EFI_MEMORY_NV | EFI_MEMORY_SP | EFI_MEMORY_CPU_CRYPTO |
|
||||
EFI_MEMORY_RUNTIME | EFI_MEMORY_MORE_RELIABLE))
|
||||
snprintf(pos, size, "|attr=0x%016llx]",
|
||||
(unsigned long long)attr);
|
||||
else
|
||||
snprintf(pos, size,
|
||||
"|%3s|%2s|%2s|%2s|%2s|%2s|%2s|%2s|%3s|%2s|%2s|%2s|%2s]",
|
||||
attr & EFI_MEMORY_RUNTIME ? "RUN" : "",
|
||||
attr & EFI_MEMORY_MORE_RELIABLE ? "MR" : "",
|
||||
attr & EFI_MEMORY_SP ? "SP" : "",
|
||||
attr & EFI_MEMORY_NV ? "NV" : "",
|
||||
attr & EFI_MEMORY_XP ? "XP" : "",
|
||||
attr & EFI_MEMORY_RP ? "RP" : "",
|
||||
attr & EFI_MEMORY_WP ? "WP" : "",
|
||||
attr & EFI_MEMORY_RO ? "RO" : "",
|
||||
attr & EFI_MEMORY_UCE ? "UCE" : "",
|
||||
attr & EFI_MEMORY_WB ? "WB" : "",
|
||||
attr & EFI_MEMORY_WT ? "WT" : "",
|
||||
attr & EFI_MEMORY_WC ? "WC" : "",
|
||||
attr & EFI_MEMORY_UC ? "UC" : "");
|
||||
"|%3s|%2s|%2s|%2s|%2s|%2s|%2s|%2s|%2s|%3s|%2s|%2s|%2s|%2s]",
|
||||
attr & EFI_MEMORY_RUNTIME ? "RUN" : "",
|
||||
attr & EFI_MEMORY_MORE_RELIABLE ? "MR" : "",
|
||||
attr & EFI_MEMORY_CPU_CRYPTO ? "CC" : "",
|
||||
attr & EFI_MEMORY_SP ? "SP" : "",
|
||||
attr & EFI_MEMORY_NV ? "NV" : "",
|
||||
attr & EFI_MEMORY_XP ? "XP" : "",
|
||||
attr & EFI_MEMORY_RP ? "RP" : "",
|
||||
attr & EFI_MEMORY_WP ? "WP" : "",
|
||||
attr & EFI_MEMORY_RO ? "RO" : "",
|
||||
attr & EFI_MEMORY_UCE ? "UCE" : "",
|
||||
attr & EFI_MEMORY_WB ? "WB" : "",
|
||||
attr & EFI_MEMORY_WT ? "WT" : "",
|
||||
attr & EFI_MEMORY_WC ? "WC" : "",
|
||||
attr & EFI_MEMORY_UC ? "UC" : "");
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
@ -22,10 +22,8 @@ MODULE_AUTHOR("Matt Domsch <Matt_Domsch@Dell.com>");
|
||||
MODULE_DESCRIPTION("sysfs interface to EFI Variables");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_VERSION(EFIVARS_VERSION);
|
||||
MODULE_ALIAS("platform:efivars");
|
||||
|
||||
LIST_HEAD(efivar_sysfs_list);
|
||||
EXPORT_SYMBOL_GPL(efivar_sysfs_list);
|
||||
static LIST_HEAD(efivar_sysfs_list);
|
||||
|
||||
static struct kset *efivars_kset;
|
||||
|
||||
@ -591,42 +589,6 @@ out_free:
|
||||
return error;
|
||||
}
|
||||
|
||||
static int efivar_update_sysfs_entry(efi_char16_t *name, efi_guid_t vendor,
|
||||
unsigned long name_size, void *data)
|
||||
{
|
||||
struct efivar_entry *entry = data;
|
||||
|
||||
if (efivar_entry_find(name, vendor, &efivar_sysfs_list, false))
|
||||
return 0;
|
||||
|
||||
memcpy(entry->var.VariableName, name, name_size);
|
||||
memcpy(&(entry->var.VendorGuid), &vendor, sizeof(efi_guid_t));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void efivar_update_sysfs_entries(struct work_struct *work)
|
||||
{
|
||||
struct efivar_entry *entry;
|
||||
int err;
|
||||
|
||||
/* Add new sysfs entries */
|
||||
while (1) {
|
||||
entry = kzalloc(sizeof(*entry), GFP_KERNEL);
|
||||
if (!entry)
|
||||
return;
|
||||
|
||||
err = efivar_init(efivar_update_sysfs_entry, entry,
|
||||
false, &efivar_sysfs_list);
|
||||
if (!err)
|
||||
break;
|
||||
|
||||
efivar_create_sysfs_entry(entry);
|
||||
}
|
||||
|
||||
kfree(entry);
|
||||
}
|
||||
|
||||
static int efivars_sysfs_callback(efi_char16_t *name, efi_guid_t vendor,
|
||||
unsigned long name_size, void *data)
|
||||
{
|
||||
@ -675,7 +637,7 @@ static void efivars_sysfs_exit(void)
|
||||
kset_unregister(efivars_kset);
|
||||
}
|
||||
|
||||
int efivars_sysfs_init(void)
|
||||
static int efivars_sysfs_init(void)
|
||||
{
|
||||
struct kobject *parent_kobj = efivars_kobject();
|
||||
int error = 0;
|
||||
@ -701,11 +663,8 @@ int efivars_sysfs_init(void)
|
||||
return error;
|
||||
}
|
||||
|
||||
INIT_WORK(&efivar_work, efivar_update_sysfs_entries);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(efivars_sysfs_init);
|
||||
|
||||
module_init(efivars_sysfs_init);
|
||||
module_exit(efivars_sysfs_exit);
|
||||
|
@ -113,162 +113,58 @@ void free_screen_info(struct screen_info *si)
|
||||
efi_bs_call(free_pool, si);
|
||||
}
|
||||
|
||||
static efi_status_t reserve_kernel_base(unsigned long dram_base,
|
||||
unsigned long *reserve_addr,
|
||||
unsigned long *reserve_size)
|
||||
{
|
||||
efi_physical_addr_t alloc_addr;
|
||||
efi_memory_desc_t *memory_map;
|
||||
unsigned long nr_pages, map_size, desc_size, buff_size;
|
||||
efi_status_t status;
|
||||
unsigned long l;
|
||||
|
||||
struct efi_boot_memmap map = {
|
||||
.map = &memory_map,
|
||||
.map_size = &map_size,
|
||||
.desc_size = &desc_size,
|
||||
.desc_ver = NULL,
|
||||
.key_ptr = NULL,
|
||||
.buff_size = &buff_size,
|
||||
};
|
||||
|
||||
/*
|
||||
* Reserve memory for the uncompressed kernel image. This is
|
||||
* all that prevents any future allocations from conflicting
|
||||
* with the kernel. Since we can't tell from the compressed
|
||||
* image how much DRAM the kernel actually uses (due to BSS
|
||||
* size uncertainty) we allocate the maximum possible size.
|
||||
* Do this very early, as prints can cause memory allocations
|
||||
* that may conflict with this.
|
||||
*/
|
||||
alloc_addr = dram_base + MAX_UNCOMP_KERNEL_SIZE;
|
||||
nr_pages = MAX_UNCOMP_KERNEL_SIZE / EFI_PAGE_SIZE;
|
||||
status = efi_bs_call(allocate_pages, EFI_ALLOCATE_MAX_ADDRESS,
|
||||
EFI_BOOT_SERVICES_DATA, nr_pages, &alloc_addr);
|
||||
if (status == EFI_SUCCESS) {
|
||||
if (alloc_addr == dram_base) {
|
||||
*reserve_addr = alloc_addr;
|
||||
*reserve_size = MAX_UNCOMP_KERNEL_SIZE;
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
/*
|
||||
* If we end up here, the allocation succeeded but starts below
|
||||
* dram_base. This can only occur if the real base of DRAM is
|
||||
* not a multiple of 128 MB, in which case dram_base will have
|
||||
* been rounded up. Since this implies that a part of the region
|
||||
* was already occupied, we need to fall through to the code
|
||||
* below to ensure that the existing allocations don't conflict.
|
||||
* For this reason, we use EFI_BOOT_SERVICES_DATA above and not
|
||||
* EFI_LOADER_DATA, which we wouldn't able to distinguish from
|
||||
* allocations that we want to disallow.
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
* If the allocation above failed, we may still be able to proceed:
|
||||
* if the only allocations in the region are of types that will be
|
||||
* released to the OS after ExitBootServices(), the decompressor can
|
||||
* safely overwrite them.
|
||||
*/
|
||||
status = efi_get_memory_map(&map);
|
||||
if (status != EFI_SUCCESS) {
|
||||
efi_err("reserve_kernel_base(): Unable to retrieve memory map.\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
for (l = 0; l < map_size; l += desc_size) {
|
||||
efi_memory_desc_t *desc;
|
||||
u64 start, end;
|
||||
|
||||
desc = (void *)memory_map + l;
|
||||
start = desc->phys_addr;
|
||||
end = start + desc->num_pages * EFI_PAGE_SIZE;
|
||||
|
||||
/* Skip if entry does not intersect with region */
|
||||
if (start >= dram_base + MAX_UNCOMP_KERNEL_SIZE ||
|
||||
end <= dram_base)
|
||||
continue;
|
||||
|
||||
switch (desc->type) {
|
||||
case EFI_BOOT_SERVICES_CODE:
|
||||
case EFI_BOOT_SERVICES_DATA:
|
||||
/* Ignore types that are released to the OS anyway */
|
||||
continue;
|
||||
|
||||
case EFI_CONVENTIONAL_MEMORY:
|
||||
/* Skip soft reserved conventional memory */
|
||||
if (efi_soft_reserve_enabled() &&
|
||||
(desc->attribute & EFI_MEMORY_SP))
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Reserve the intersection between this entry and the
|
||||
* region.
|
||||
*/
|
||||
start = max(start, (u64)dram_base);
|
||||
end = min(end, (u64)dram_base + MAX_UNCOMP_KERNEL_SIZE);
|
||||
|
||||
status = efi_bs_call(allocate_pages,
|
||||
EFI_ALLOCATE_ADDRESS,
|
||||
EFI_LOADER_DATA,
|
||||
(end - start) / EFI_PAGE_SIZE,
|
||||
&start);
|
||||
if (status != EFI_SUCCESS) {
|
||||
efi_err("reserve_kernel_base(): alloc failed.\n");
|
||||
goto out;
|
||||
}
|
||||
break;
|
||||
|
||||
case EFI_LOADER_CODE:
|
||||
case EFI_LOADER_DATA:
|
||||
/*
|
||||
* These regions may be released and reallocated for
|
||||
* another purpose (including EFI_RUNTIME_SERVICE_DATA)
|
||||
* at any time during the execution of the OS loader,
|
||||
* so we cannot consider them as safe.
|
||||
*/
|
||||
default:
|
||||
/*
|
||||
* Treat any other allocation in the region as unsafe */
|
||||
status = EFI_OUT_OF_RESOURCES;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
status = EFI_SUCCESS;
|
||||
out:
|
||||
efi_bs_call(free_pool, memory_map);
|
||||
return status;
|
||||
}
|
||||
|
||||
efi_status_t handle_kernel_image(unsigned long *image_addr,
|
||||
unsigned long *image_size,
|
||||
unsigned long *reserve_addr,
|
||||
unsigned long *reserve_size,
|
||||
unsigned long dram_base,
|
||||
efi_loaded_image_t *image)
|
||||
{
|
||||
unsigned long kernel_base;
|
||||
const int slack = TEXT_OFFSET - 5 * PAGE_SIZE;
|
||||
int alloc_size = MAX_UNCOMP_KERNEL_SIZE + EFI_PHYS_ALIGN;
|
||||
unsigned long alloc_base, kernel_base;
|
||||
efi_status_t status;
|
||||
|
||||
/* use a 16 MiB aligned base for the decompressed kernel */
|
||||
kernel_base = round_up(dram_base, SZ_16M) + TEXT_OFFSET;
|
||||
|
||||
/*
|
||||
* Note that some platforms (notably, the Raspberry Pi 2) put
|
||||
* spin-tables and other pieces of firmware at the base of RAM,
|
||||
* abusing the fact that the window of TEXT_OFFSET bytes at the
|
||||
* base of the kernel image is only partially used at the moment.
|
||||
* (Up to 5 pages are used for the swapper page tables)
|
||||
* Allocate space for the decompressed kernel as low as possible.
|
||||
* The region should be 16 MiB aligned, but the first 'slack' bytes
|
||||
* are not used by Linux, so we allow those to be occupied by the
|
||||
* firmware.
|
||||
*/
|
||||
status = reserve_kernel_base(kernel_base - 5 * PAGE_SIZE, reserve_addr,
|
||||
reserve_size);
|
||||
status = efi_low_alloc_above(alloc_size, EFI_PAGE_SIZE, &alloc_base, 0x0);
|
||||
if (status != EFI_SUCCESS) {
|
||||
efi_err("Unable to allocate memory for uncompressed kernel.\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
*image_addr = kernel_base;
|
||||
if ((alloc_base % EFI_PHYS_ALIGN) > slack) {
|
||||
/*
|
||||
* More than 'slack' bytes are already occupied at the base of
|
||||
* the allocation, so we need to advance to the next 16 MiB block.
|
||||
*/
|
||||
kernel_base = round_up(alloc_base, EFI_PHYS_ALIGN);
|
||||
efi_info("Free memory starts at 0x%lx, setting kernel_base to 0x%lx\n",
|
||||
alloc_base, kernel_base);
|
||||
} else {
|
||||
kernel_base = round_down(alloc_base, EFI_PHYS_ALIGN);
|
||||
}
|
||||
|
||||
*reserve_addr = kernel_base + slack;
|
||||
*reserve_size = MAX_UNCOMP_KERNEL_SIZE;
|
||||
|
||||
/* now free the parts that we will not use */
|
||||
if (*reserve_addr > alloc_base) {
|
||||
efi_bs_call(free_pages, alloc_base,
|
||||
(*reserve_addr - alloc_base) / EFI_PAGE_SIZE);
|
||||
alloc_size -= *reserve_addr - alloc_base;
|
||||
}
|
||||
efi_bs_call(free_pages, *reserve_addr + MAX_UNCOMP_KERNEL_SIZE,
|
||||
(alloc_size - MAX_UNCOMP_KERNEL_SIZE) / EFI_PAGE_SIZE);
|
||||
|
||||
*image_addr = kernel_base + TEXT_OFFSET;
|
||||
*image_size = 0;
|
||||
|
||||
efi_debug("image addr == 0x%lx, reserve_addr == 0x%lx\n",
|
||||
*image_addr, *reserve_addr);
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
@ -50,7 +50,6 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
|
||||
unsigned long *image_size,
|
||||
unsigned long *reserve_addr,
|
||||
unsigned long *reserve_size,
|
||||
unsigned long dram_base,
|
||||
efi_loaded_image_t *image)
|
||||
{
|
||||
efi_status_t status;
|
||||
@ -62,10 +61,12 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
|
||||
status = efi_get_random_bytes(sizeof(phys_seed),
|
||||
(u8 *)&phys_seed);
|
||||
if (status == EFI_NOT_FOUND) {
|
||||
efi_info("EFI_RNG_PROTOCOL unavailable, no randomness supplied\n");
|
||||
efi_info("EFI_RNG_PROTOCOL unavailable, KASLR will be disabled\n");
|
||||
efi_nokaslr = true;
|
||||
} else if (status != EFI_SUCCESS) {
|
||||
efi_err("efi_get_random_bytes() failed\n");
|
||||
return status;
|
||||
efi_err("efi_get_random_bytes() failed (0x%lx), KASLR will be disabled\n",
|
||||
status);
|
||||
efi_nokaslr = true;
|
||||
}
|
||||
} else {
|
||||
efi_info("KASLR disabled on kernel command line\n");
|
||||
|
@ -238,6 +238,102 @@ efi_status_t efi_parse_options(char const *cmdline)
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* The EFI_LOAD_OPTION descriptor has the following layout:
|
||||
* u32 Attributes;
|
||||
* u16 FilePathListLength;
|
||||
* u16 Description[];
|
||||
* efi_device_path_protocol_t FilePathList[];
|
||||
* u8 OptionalData[];
|
||||
*
|
||||
* This function validates and unpacks the variable-size data fields.
|
||||
*/
|
||||
static
|
||||
bool efi_load_option_unpack(efi_load_option_unpacked_t *dest,
|
||||
const efi_load_option_t *src, size_t size)
|
||||
{
|
||||
const void *pos;
|
||||
u16 c;
|
||||
efi_device_path_protocol_t header;
|
||||
const efi_char16_t *description;
|
||||
const efi_device_path_protocol_t *file_path_list;
|
||||
|
||||
if (size < offsetof(efi_load_option_t, variable_data))
|
||||
return false;
|
||||
pos = src->variable_data;
|
||||
size -= offsetof(efi_load_option_t, variable_data);
|
||||
|
||||
if ((src->attributes & ~EFI_LOAD_OPTION_MASK) != 0)
|
||||
return false;
|
||||
|
||||
/* Scan description. */
|
||||
description = pos;
|
||||
do {
|
||||
if (size < sizeof(c))
|
||||
return false;
|
||||
c = *(const u16 *)pos;
|
||||
pos += sizeof(c);
|
||||
size -= sizeof(c);
|
||||
} while (c != L'\0');
|
||||
|
||||
/* Scan file_path_list. */
|
||||
file_path_list = pos;
|
||||
do {
|
||||
if (size < sizeof(header))
|
||||
return false;
|
||||
header = *(const efi_device_path_protocol_t *)pos;
|
||||
if (header.length < sizeof(header))
|
||||
return false;
|
||||
if (size < header.length)
|
||||
return false;
|
||||
pos += header.length;
|
||||
size -= header.length;
|
||||
} while ((header.type != EFI_DEV_END_PATH && header.type != EFI_DEV_END_PATH2) ||
|
||||
(header.sub_type != EFI_DEV_END_ENTIRE));
|
||||
if (pos != (const void *)file_path_list + src->file_path_list_length)
|
||||
return false;
|
||||
|
||||
dest->attributes = src->attributes;
|
||||
dest->file_path_list_length = src->file_path_list_length;
|
||||
dest->description = description;
|
||||
dest->file_path_list = file_path_list;
|
||||
dest->optional_data_size = size;
|
||||
dest->optional_data = size ? pos : NULL;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* At least some versions of Dell firmware pass the entire contents of the
|
||||
* Boot#### variable, i.e. the EFI_LOAD_OPTION descriptor, rather than just the
|
||||
* OptionalData field.
|
||||
*
|
||||
* Detect this case and extract OptionalData.
|
||||
*/
|
||||
void efi_apply_loadoptions_quirk(const void **load_options, int *load_options_size)
|
||||
{
|
||||
const efi_load_option_t *load_option = *load_options;
|
||||
efi_load_option_unpacked_t load_option_unpacked;
|
||||
|
||||
if (!IS_ENABLED(CONFIG_X86))
|
||||
return;
|
||||
if (!load_option)
|
||||
return;
|
||||
if (*load_options_size < sizeof(*load_option))
|
||||
return;
|
||||
if ((load_option->attributes & ~EFI_LOAD_OPTION_BOOT_MASK) != 0)
|
||||
return;
|
||||
|
||||
if (!efi_load_option_unpack(&load_option_unpacked, load_option, *load_options_size))
|
||||
return;
|
||||
|
||||
efi_warn_once(FW_BUG "LoadOptions is an EFI_LOAD_OPTION descriptor\n");
|
||||
efi_warn_once(FW_BUG "Using OptionalData as a workaround\n");
|
||||
|
||||
*load_options = load_option_unpacked.optional_data;
|
||||
*load_options_size = load_option_unpacked.optional_data_size;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert the unicode UEFI command line to ASCII to pass to kernel.
|
||||
* Size of memory allocated return in *cmd_line_len.
|
||||
@ -247,12 +343,15 @@ char *efi_convert_cmdline(efi_loaded_image_t *image, int *cmd_line_len)
|
||||
{
|
||||
const u16 *s2;
|
||||
unsigned long cmdline_addr = 0;
|
||||
int options_chars = efi_table_attr(image, load_options_size) / 2;
|
||||
int options_chars = efi_table_attr(image, load_options_size);
|
||||
const u16 *options = efi_table_attr(image, load_options);
|
||||
int options_bytes = 0, safe_options_bytes = 0; /* UTF-8 bytes */
|
||||
bool in_quote = false;
|
||||
efi_status_t status;
|
||||
|
||||
efi_apply_loadoptions_quirk((const void **)&options, &options_chars);
|
||||
options_chars /= sizeof(*options);
|
||||
|
||||
if (options) {
|
||||
s2 = options;
|
||||
while (options_bytes < COMMAND_LINE_SIZE && options_chars--) {
|
||||
|
@ -87,40 +87,6 @@ static void install_memreserve_table(void)
|
||||
efi_err("Failed to install memreserve config table!\n");
|
||||
}
|
||||
|
||||
static unsigned long get_dram_base(void)
|
||||
{
|
||||
efi_status_t status;
|
||||
unsigned long map_size, buff_size;
|
||||
unsigned long membase = EFI_ERROR;
|
||||
struct efi_memory_map map;
|
||||
efi_memory_desc_t *md;
|
||||
struct efi_boot_memmap boot_map;
|
||||
|
||||
boot_map.map = (efi_memory_desc_t **)&map.map;
|
||||
boot_map.map_size = &map_size;
|
||||
boot_map.desc_size = &map.desc_size;
|
||||
boot_map.desc_ver = NULL;
|
||||
boot_map.key_ptr = NULL;
|
||||
boot_map.buff_size = &buff_size;
|
||||
|
||||
status = efi_get_memory_map(&boot_map);
|
||||
if (status != EFI_SUCCESS)
|
||||
return membase;
|
||||
|
||||
map.map_end = map.map + map_size;
|
||||
|
||||
for_each_efi_memory_desc_in_map(&map, md) {
|
||||
if (md->attribute & EFI_MEMORY_WB) {
|
||||
if (membase > md->phys_addr)
|
||||
membase = md->phys_addr;
|
||||
}
|
||||
}
|
||||
|
||||
efi_bs_call(free_pool, map.map);
|
||||
|
||||
return membase;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
@ -134,7 +100,6 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
|
||||
efi_status_t status;
|
||||
unsigned long image_addr;
|
||||
unsigned long image_size = 0;
|
||||
unsigned long dram_base;
|
||||
/* addr/point and size pairs for memory management*/
|
||||
unsigned long initrd_addr = 0;
|
||||
unsigned long initrd_size = 0;
|
||||
@ -174,13 +139,6 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
|
||||
goto fail;
|
||||
}
|
||||
|
||||
dram_base = get_dram_base();
|
||||
if (dram_base == EFI_ERROR) {
|
||||
efi_err("Failed to find DRAM base\n");
|
||||
status = EFI_LOAD_ERROR;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the command line from EFI, using the LOADED_IMAGE
|
||||
* protocol. We are going to copy the command line into the
|
||||
@ -218,7 +176,7 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
|
||||
status = handle_kernel_image(&image_addr, &image_size,
|
||||
&reserve_addr,
|
||||
&reserve_size,
|
||||
dram_base, image);
|
||||
image);
|
||||
if (status != EFI_SUCCESS) {
|
||||
efi_err("Failed to relocate kernel\n");
|
||||
goto fail_free_screeninfo;
|
||||
@ -262,7 +220,7 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
|
||||
efi_info("Generating empty DTB\n");
|
||||
|
||||
if (!efi_noinitrd) {
|
||||
max_addr = efi_get_max_initrd_addr(dram_base, image_addr);
|
||||
max_addr = efi_get_max_initrd_addr(image_addr);
|
||||
status = efi_load_initrd(image, &initrd_addr, &initrd_size,
|
||||
ULONG_MAX, max_addr);
|
||||
if (status != EFI_SUCCESS)
|
||||
@ -306,7 +264,7 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
|
||||
install_memreserve_table();
|
||||
|
||||
status = allocate_new_fdt_and_exit_boot(handle, &fdt_addr,
|
||||
efi_get_max_fdt_addr(dram_base),
|
||||
efi_get_max_fdt_addr(image_addr),
|
||||
initrd_addr, initrd_size,
|
||||
cmdline_ptr, fdt_addr, fdt_size);
|
||||
if (status != EFI_SUCCESS)
|
||||
|
@ -10,9 +10,6 @@
|
||||
#include <linux/types.h>
|
||||
#include <asm/efi.h>
|
||||
|
||||
/* error code which can't be mistaken for valid address */
|
||||
#define EFI_ERROR (~0UL)
|
||||
|
||||
/*
|
||||
* __init annotations should not be used in the EFI stub, since the code is
|
||||
* either included in the decompressor (x86, ARM) where they have no effect,
|
||||
@ -55,11 +52,34 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
|
||||
|
||||
#define efi_info(fmt, ...) \
|
||||
efi_printk(KERN_INFO fmt, ##__VA_ARGS__)
|
||||
#define efi_warn(fmt, ...) \
|
||||
efi_printk(KERN_WARNING "WARNING: " fmt, ##__VA_ARGS__)
|
||||
#define efi_err(fmt, ...) \
|
||||
efi_printk(KERN_ERR "ERROR: " fmt, ##__VA_ARGS__)
|
||||
#define efi_debug(fmt, ...) \
|
||||
efi_printk(KERN_DEBUG "DEBUG: " fmt, ##__VA_ARGS__)
|
||||
|
||||
#define efi_printk_once(fmt, ...) \
|
||||
({ \
|
||||
static bool __print_once; \
|
||||
bool __ret_print_once = !__print_once; \
|
||||
\
|
||||
if (!__print_once) { \
|
||||
__print_once = true; \
|
||||
efi_printk(fmt, ##__VA_ARGS__); \
|
||||
} \
|
||||
__ret_print_once; \
|
||||
})
|
||||
|
||||
#define efi_info_once(fmt, ...) \
|
||||
efi_printk_once(KERN_INFO fmt, ##__VA_ARGS__)
|
||||
#define efi_warn_once(fmt, ...) \
|
||||
efi_printk_once(KERN_WARNING "WARNING: " fmt, ##__VA_ARGS__)
|
||||
#define efi_err_once(fmt, ...) \
|
||||
efi_printk_once(KERN_ERR "ERROR: " fmt, ##__VA_ARGS__)
|
||||
#define efi_debug_once(fmt, ...) \
|
||||
efi_printk_once(KERN_DEBUG "DEBUG: " fmt, ##__VA_ARGS__)
|
||||
|
||||
/* Helper macros for the usual case of using simple C variables: */
|
||||
#ifndef fdt_setprop_inplace_var
|
||||
#define fdt_setprop_inplace_var(fdt, node_offset, name, var) \
|
||||
@ -688,6 +708,35 @@ union efi_load_file_protocol {
|
||||
} mixed_mode;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
u32 attributes;
|
||||
u16 file_path_list_length;
|
||||
u8 variable_data[];
|
||||
// efi_char16_t description[];
|
||||
// efi_device_path_protocol_t file_path_list[];
|
||||
// u8 optional_data[];
|
||||
} __packed efi_load_option_t;
|
||||
|
||||
#define EFI_LOAD_OPTION_ACTIVE 0x0001U
|
||||
#define EFI_LOAD_OPTION_FORCE_RECONNECT 0x0002U
|
||||
#define EFI_LOAD_OPTION_HIDDEN 0x0008U
|
||||
#define EFI_LOAD_OPTION_CATEGORY 0x1f00U
|
||||
#define EFI_LOAD_OPTION_CATEGORY_BOOT 0x0000U
|
||||
#define EFI_LOAD_OPTION_CATEGORY_APP 0x0100U
|
||||
|
||||
#define EFI_LOAD_OPTION_BOOT_MASK \
|
||||
(EFI_LOAD_OPTION_ACTIVE|EFI_LOAD_OPTION_HIDDEN|EFI_LOAD_OPTION_CATEGORY)
|
||||
#define EFI_LOAD_OPTION_MASK (EFI_LOAD_OPTION_FORCE_RECONNECT|EFI_LOAD_OPTION_BOOT_MASK)
|
||||
|
||||
typedef struct {
|
||||
u32 attributes;
|
||||
u16 file_path_list_length;
|
||||
const efi_char16_t *description;
|
||||
const efi_device_path_protocol_t *file_path_list;
|
||||
size_t optional_data_size;
|
||||
const void *optional_data;
|
||||
} efi_load_option_unpacked_t;
|
||||
|
||||
void efi_pci_disable_bridge_busmaster(void);
|
||||
|
||||
typedef efi_status_t (*efi_exit_boot_map_processing)(
|
||||
@ -730,6 +779,8 @@ __printf(1, 2) int efi_printk(char const *fmt, ...);
|
||||
|
||||
void efi_free(unsigned long size, unsigned long addr);
|
||||
|
||||
void efi_apply_loadoptions_quirk(const void **load_options, int *load_options_size);
|
||||
|
||||
char *efi_convert_cmdline(efi_loaded_image_t *image, int *cmd_line_len);
|
||||
|
||||
efi_status_t efi_get_memory_map(struct efi_boot_memmap *map);
|
||||
@ -740,6 +791,9 @@ efi_status_t efi_allocate_pages(unsigned long size, unsigned long *addr,
|
||||
efi_status_t efi_allocate_pages_aligned(unsigned long size, unsigned long *addr,
|
||||
unsigned long max, unsigned long align);
|
||||
|
||||
efi_status_t efi_low_alloc_above(unsigned long size, unsigned long align,
|
||||
unsigned long *addr, unsigned long min);
|
||||
|
||||
efi_status_t efi_relocate_kernel(unsigned long *image_addr,
|
||||
unsigned long image_size,
|
||||
unsigned long alloc_size,
|
||||
@ -786,7 +840,6 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
|
||||
unsigned long *image_size,
|
||||
unsigned long *reserve_addr,
|
||||
unsigned long *reserve_size,
|
||||
unsigned long dram_base,
|
||||
efi_loaded_image_t *image);
|
||||
|
||||
asmlinkage void __noreturn efi_enter_kernel(unsigned long entrypoint,
|
||||
|
@ -136,7 +136,7 @@ static efi_status_t update_fdt(void *orig_fdt, unsigned long orig_fdt_size,
|
||||
if (status)
|
||||
goto fdt_set_fail;
|
||||
|
||||
if (IS_ENABLED(CONFIG_RANDOMIZE_BASE)) {
|
||||
if (IS_ENABLED(CONFIG_RANDOMIZE_BASE) && !efi_nokaslr) {
|
||||
efi_status_t efi_status;
|
||||
|
||||
efi_status = efi_get_random_bytes(sizeof(fdt_val64),
|
||||
@ -145,8 +145,6 @@ static efi_status_t update_fdt(void *orig_fdt, unsigned long orig_fdt_size,
|
||||
status = fdt_setprop_var(fdt, node, "kaslr-seed", fdt_val64);
|
||||
if (status)
|
||||
goto fdt_set_fail;
|
||||
} else if (efi_status != EFI_NOT_FOUND) {
|
||||
return efi_status;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -136,7 +136,7 @@ efi_status_t handle_cmdline_files(efi_loaded_image_t *image,
|
||||
unsigned long *load_size)
|
||||
{
|
||||
const efi_char16_t *cmdline = image->load_options;
|
||||
int cmdline_len = image->load_options_size / 2;
|
||||
int cmdline_len = image->load_options_size;
|
||||
unsigned long efi_chunk_size = ULONG_MAX;
|
||||
efi_file_protocol_t *volume = NULL;
|
||||
efi_file_protocol_t *file;
|
||||
@ -148,6 +148,9 @@ efi_status_t handle_cmdline_files(efi_loaded_image_t *image,
|
||||
if (!load_addr || !load_size)
|
||||
return EFI_INVALID_PARAMETER;
|
||||
|
||||
efi_apply_loadoptions_quirk((const void **)&cmdline, &cmdline_len);
|
||||
cmdline_len /= sizeof(*cmdline);
|
||||
|
||||
if (IS_ENABLED(CONFIG_X86) && !efi_nochunk)
|
||||
efi_chunk_size = EFI_READ_CHUNK_SIZE;
|
||||
|
||||
|
@ -20,8 +20,8 @@
|
||||
*
|
||||
* Return: status code
|
||||
*/
|
||||
static efi_status_t efi_low_alloc_above(unsigned long size, unsigned long align,
|
||||
unsigned long *addr, unsigned long min)
|
||||
efi_status_t efi_low_alloc_above(unsigned long size, unsigned long align,
|
||||
unsigned long *addr, unsigned long min)
|
||||
{
|
||||
unsigned long map_size, desc_size, buff_size;
|
||||
efi_memory_desc_t *map;
|
||||
|
@ -7,6 +7,7 @@
|
||||
*/
|
||||
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
|
@ -135,7 +135,7 @@ char *number(char *end, unsigned long long num, int base, char locase)
|
||||
break;
|
||||
default:
|
||||
unreachable();
|
||||
};
|
||||
}
|
||||
|
||||
return end;
|
||||
}
|
||||
|
359
drivers/firmware/efi/mokvar-table.c
Normal file
359
drivers/firmware/efi/mokvar-table.c
Normal file
@ -0,0 +1,359 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* mokvar-table.c
|
||||
*
|
||||
* Copyright (c) 2020 Red Hat
|
||||
* Author: Lenny Szubowicz <lszubowi@redhat.com>
|
||||
*
|
||||
* This module contains the kernel support for the Linux EFI Machine
|
||||
* Owner Key (MOK) variable configuration table, which is identified by
|
||||
* the LINUX_EFI_MOK_VARIABLE_TABLE_GUID.
|
||||
*
|
||||
* This EFI configuration table provides a more robust alternative to
|
||||
* EFI volatile variables by which an EFI boot loader can pass the
|
||||
* contents of the Machine Owner Key (MOK) certificate stores to the
|
||||
* kernel during boot. If both the EFI MOK config table and corresponding
|
||||
* EFI MOK variables are present, the table should be considered as
|
||||
* more authoritative.
|
||||
*
|
||||
* This module includes code that validates and maps the EFI MOK table,
|
||||
* if it's presence was detected very early in boot.
|
||||
*
|
||||
* Kernel interface routines are provided to walk through all the
|
||||
* entries in the MOK config table or to search for a specific named
|
||||
* entry.
|
||||
*
|
||||
* The contents of the individual named MOK config table entries are
|
||||
* made available to user space via read-only sysfs binary files under:
|
||||
*
|
||||
* /sys/firmware/efi/mok-variables/
|
||||
*
|
||||
*/
|
||||
#define pr_fmt(fmt) "mokvar: " fmt
|
||||
|
||||
#include <linux/capability.h>
|
||||
#include <linux/efi.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kobject.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <asm/early_ioremap.h>
|
||||
|
||||
/*
|
||||
* The LINUX_EFI_MOK_VARIABLE_TABLE_GUID config table is a packed
|
||||
* sequence of struct efi_mokvar_table_entry, one for each named
|
||||
* MOK variable. The sequence is terminated by an entry with a
|
||||
* completely NULL name and 0 data size.
|
||||
*
|
||||
* efi_mokvar_table_size is set to the computed size of the
|
||||
* MOK config table by efi_mokvar_table_init(). This will be
|
||||
* non-zero if and only if the table if present and has been
|
||||
* validated by efi_mokvar_table_init().
|
||||
*/
|
||||
static size_t efi_mokvar_table_size;
|
||||
|
||||
/*
|
||||
* efi_mokvar_table_va is the kernel virtual address at which the
|
||||
* EFI MOK config table has been mapped by efi_mokvar_sysfs_init().
|
||||
*/
|
||||
static struct efi_mokvar_table_entry *efi_mokvar_table_va;
|
||||
|
||||
/*
|
||||
* Each /sys/firmware/efi/mok-variables/ sysfs file is represented by
|
||||
* an instance of struct efi_mokvar_sysfs_attr on efi_mokvar_sysfs_list.
|
||||
* bin_attr.private points to the associated EFI MOK config table entry.
|
||||
*
|
||||
* This list is created during boot and then remains unchanged.
|
||||
* So no synchronization is currently required to walk the list.
|
||||
*/
|
||||
struct efi_mokvar_sysfs_attr {
|
||||
struct bin_attribute bin_attr;
|
||||
struct list_head node;
|
||||
};
|
||||
|
||||
static LIST_HEAD(efi_mokvar_sysfs_list);
|
||||
static struct kobject *mokvar_kobj;
|
||||
|
||||
/*
|
||||
* efi_mokvar_table_init() - Early boot validation of EFI MOK config table
|
||||
*
|
||||
* If present, validate and compute the size of the EFI MOK variable
|
||||
* configuration table. This table may be provided by an EFI boot loader
|
||||
* as an alternative to ordinary EFI variables, due to platform-dependent
|
||||
* limitations. The memory occupied by this table is marked as reserved.
|
||||
*
|
||||
* This routine must be called before efi_free_boot_services() in order
|
||||
* to guarantee that it can mark the table as reserved.
|
||||
*
|
||||
* Implicit inputs:
|
||||
* efi.mokvar_table: Physical address of EFI MOK variable config table
|
||||
* or special value that indicates no such table.
|
||||
*
|
||||
* Implicit outputs:
|
||||
* efi_mokvar_table_size: Computed size of EFI MOK variable config table.
|
||||
* The table is considered present and valid if this
|
||||
* is non-zero.
|
||||
*/
|
||||
void __init efi_mokvar_table_init(void)
|
||||
{
|
||||
efi_memory_desc_t md;
|
||||
void *va = NULL;
|
||||
unsigned long cur_offset = 0;
|
||||
unsigned long offset_limit;
|
||||
unsigned long map_size = 0;
|
||||
unsigned long map_size_needed = 0;
|
||||
unsigned long size;
|
||||
struct efi_mokvar_table_entry *mokvar_entry;
|
||||
int err;
|
||||
|
||||
if (!efi_enabled(EFI_MEMMAP))
|
||||
return;
|
||||
|
||||
if (efi.mokvar_table == EFI_INVALID_TABLE_ADDR)
|
||||
return;
|
||||
/*
|
||||
* The EFI MOK config table must fit within a single EFI memory
|
||||
* descriptor range.
|
||||
*/
|
||||
err = efi_mem_desc_lookup(efi.mokvar_table, &md);
|
||||
if (err) {
|
||||
pr_warn("EFI MOKvar config table is not within the EFI memory map\n");
|
||||
return;
|
||||
}
|
||||
|
||||
offset_limit = efi_mem_desc_end(&md) - efi.mokvar_table;
|
||||
|
||||
/*
|
||||
* Validate the MOK config table. Since there is no table header
|
||||
* from which we could get the total size of the MOK config table,
|
||||
* we compute the total size as we validate each variably sized
|
||||
* entry, remapping as necessary.
|
||||
*/
|
||||
err = -EINVAL;
|
||||
while (cur_offset + sizeof(*mokvar_entry) <= offset_limit) {
|
||||
mokvar_entry = va + cur_offset;
|
||||
map_size_needed = cur_offset + sizeof(*mokvar_entry);
|
||||
if (map_size_needed > map_size) {
|
||||
if (va)
|
||||
early_memunmap(va, map_size);
|
||||
/*
|
||||
* Map a little more than the fixed size entry
|
||||
* header, anticipating some data. It's safe to
|
||||
* do so as long as we stay within current memory
|
||||
* descriptor.
|
||||
*/
|
||||
map_size = min(map_size_needed + 2*EFI_PAGE_SIZE,
|
||||
offset_limit);
|
||||
va = early_memremap(efi.mokvar_table, map_size);
|
||||
if (!va) {
|
||||
pr_err("Failed to map EFI MOKvar config table pa=0x%lx, size=%lu.\n",
|
||||
efi.mokvar_table, map_size);
|
||||
return;
|
||||
}
|
||||
mokvar_entry = va + cur_offset;
|
||||
}
|
||||
|
||||
/* Check for last sentinel entry */
|
||||
if (mokvar_entry->name[0] == '\0') {
|
||||
if (mokvar_entry->data_size != 0)
|
||||
break;
|
||||
err = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Sanity check that the name is null terminated */
|
||||
size = strnlen(mokvar_entry->name,
|
||||
sizeof(mokvar_entry->name));
|
||||
if (size >= sizeof(mokvar_entry->name))
|
||||
break;
|
||||
|
||||
/* Advance to the next entry */
|
||||
cur_offset = map_size_needed + mokvar_entry->data_size;
|
||||
}
|
||||
|
||||
if (va)
|
||||
early_memunmap(va, map_size);
|
||||
if (err) {
|
||||
pr_err("EFI MOKvar config table is not valid\n");
|
||||
return;
|
||||
}
|
||||
efi_mem_reserve(efi.mokvar_table, map_size_needed);
|
||||
efi_mokvar_table_size = map_size_needed;
|
||||
}
|
||||
|
||||
/*
|
||||
* efi_mokvar_entry_next() - Get next entry in the EFI MOK config table
|
||||
*
|
||||
* mokvar_entry: Pointer to current EFI MOK config table entry
|
||||
* or null. Null indicates get first entry.
|
||||
* Passed by reference. This is updated to the
|
||||
* same value as the return value.
|
||||
*
|
||||
* Returns: Pointer to next EFI MOK config table entry
|
||||
* or null, if there are no more entries.
|
||||
* Same value is returned in the mokvar_entry
|
||||
* parameter.
|
||||
*
|
||||
* This routine depends on the EFI MOK config table being entirely
|
||||
* mapped with it's starting virtual address in efi_mokvar_table_va.
|
||||
*/
|
||||
struct efi_mokvar_table_entry *efi_mokvar_entry_next(
|
||||
struct efi_mokvar_table_entry **mokvar_entry)
|
||||
{
|
||||
struct efi_mokvar_table_entry *mokvar_cur;
|
||||
struct efi_mokvar_table_entry *mokvar_next;
|
||||
size_t size_cur;
|
||||
|
||||
mokvar_cur = *mokvar_entry;
|
||||
*mokvar_entry = NULL;
|
||||
|
||||
if (efi_mokvar_table_va == NULL)
|
||||
return NULL;
|
||||
|
||||
if (mokvar_cur == NULL) {
|
||||
mokvar_next = efi_mokvar_table_va;
|
||||
} else {
|
||||
if (mokvar_cur->name[0] == '\0')
|
||||
return NULL;
|
||||
size_cur = sizeof(*mokvar_cur) + mokvar_cur->data_size;
|
||||
mokvar_next = (void *)mokvar_cur + size_cur;
|
||||
}
|
||||
|
||||
if (mokvar_next->name[0] == '\0')
|
||||
return NULL;
|
||||
|
||||
*mokvar_entry = mokvar_next;
|
||||
return mokvar_next;
|
||||
}
|
||||
|
||||
/*
|
||||
* efi_mokvar_entry_find() - Find EFI MOK config entry by name
|
||||
*
|
||||
* name: Name of the entry to look for.
|
||||
*
|
||||
* Returns: Pointer to EFI MOK config table entry if found;
|
||||
* null otherwise.
|
||||
*
|
||||
* This routine depends on the EFI MOK config table being entirely
|
||||
* mapped with it's starting virtual address in efi_mokvar_table_va.
|
||||
*/
|
||||
struct efi_mokvar_table_entry *efi_mokvar_entry_find(const char *name)
|
||||
{
|
||||
struct efi_mokvar_table_entry *mokvar_entry = NULL;
|
||||
|
||||
while (efi_mokvar_entry_next(&mokvar_entry)) {
|
||||
if (!strncmp(name, mokvar_entry->name,
|
||||
sizeof(mokvar_entry->name)))
|
||||
return mokvar_entry;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* efi_mokvar_sysfs_read() - sysfs binary file read routine
|
||||
*
|
||||
* Returns: Count of bytes read.
|
||||
*
|
||||
* Copy EFI MOK config table entry data for this mokvar sysfs binary file
|
||||
* to the supplied buffer, starting at the specified offset into mokvar table
|
||||
* entry data, for the specified count bytes. The copy is limited by the
|
||||
* amount of data in this mokvar config table entry.
|
||||
*/
|
||||
static ssize_t efi_mokvar_sysfs_read(struct file *file, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr, char *buf,
|
||||
loff_t off, size_t count)
|
||||
{
|
||||
struct efi_mokvar_table_entry *mokvar_entry = bin_attr->private;
|
||||
|
||||
if (!capable(CAP_SYS_ADMIN))
|
||||
return 0;
|
||||
|
||||
if (off >= mokvar_entry->data_size)
|
||||
return 0;
|
||||
if (count > mokvar_entry->data_size - off)
|
||||
count = mokvar_entry->data_size - off;
|
||||
|
||||
memcpy(buf, mokvar_entry->data + off, count);
|
||||
return count;
|
||||
}
|
||||
|
||||
/*
|
||||
* efi_mokvar_sysfs_init() - Map EFI MOK config table and create sysfs
|
||||
*
|
||||
* Map the EFI MOK variable config table for run-time use by the kernel
|
||||
* and create the sysfs entries in /sys/firmware/efi/mok-variables/
|
||||
*
|
||||
* This routine just returns if a valid EFI MOK variable config table
|
||||
* was not found earlier during boot.
|
||||
*
|
||||
* This routine must be called during a "middle" initcall phase, i.e.
|
||||
* after efi_mokvar_table_init() but before UEFI certs are loaded
|
||||
* during late init.
|
||||
*
|
||||
* Implicit inputs:
|
||||
* efi.mokvar_table: Physical address of EFI MOK variable config table
|
||||
* or special value that indicates no such table.
|
||||
*
|
||||
* efi_mokvar_table_size: Computed size of EFI MOK variable config table.
|
||||
* The table is considered present and valid if this
|
||||
* is non-zero.
|
||||
*
|
||||
* Implicit outputs:
|
||||
* efi_mokvar_table_va: Start virtual address of the EFI MOK config table.
|
||||
*/
|
||||
static int __init efi_mokvar_sysfs_init(void)
|
||||
{
|
||||
void *config_va;
|
||||
struct efi_mokvar_table_entry *mokvar_entry = NULL;
|
||||
struct efi_mokvar_sysfs_attr *mokvar_sysfs = NULL;
|
||||
int err = 0;
|
||||
|
||||
if (efi_mokvar_table_size == 0)
|
||||
return -ENOENT;
|
||||
|
||||
config_va = memremap(efi.mokvar_table, efi_mokvar_table_size,
|
||||
MEMREMAP_WB);
|
||||
if (!config_va) {
|
||||
pr_err("Failed to map EFI MOKvar config table\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
efi_mokvar_table_va = config_va;
|
||||
|
||||
mokvar_kobj = kobject_create_and_add("mok-variables", efi_kobj);
|
||||
if (!mokvar_kobj) {
|
||||
pr_err("Failed to create EFI mok-variables sysfs entry\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
while (efi_mokvar_entry_next(&mokvar_entry)) {
|
||||
mokvar_sysfs = kzalloc(sizeof(*mokvar_sysfs), GFP_KERNEL);
|
||||
if (!mokvar_sysfs) {
|
||||
err = -ENOMEM;
|
||||
break;
|
||||
}
|
||||
|
||||
sysfs_bin_attr_init(&mokvar_sysfs->bin_attr);
|
||||
mokvar_sysfs->bin_attr.private = mokvar_entry;
|
||||
mokvar_sysfs->bin_attr.attr.name = mokvar_entry->name;
|
||||
mokvar_sysfs->bin_attr.attr.mode = 0400;
|
||||
mokvar_sysfs->bin_attr.size = mokvar_entry->data_size;
|
||||
mokvar_sysfs->bin_attr.read = efi_mokvar_sysfs_read;
|
||||
|
||||
err = sysfs_create_bin_file(mokvar_kobj,
|
||||
&mokvar_sysfs->bin_attr);
|
||||
if (err)
|
||||
break;
|
||||
|
||||
list_add_tail(&mokvar_sysfs->node, &efi_mokvar_sysfs_list);
|
||||
}
|
||||
|
||||
if (err) {
|
||||
pr_err("Failed to create some EFI mok-variables sysfs entries\n");
|
||||
kfree(mokvar_sysfs);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
device_initcall(efi_mokvar_sysfs_init);
|
@ -32,10 +32,6 @@ static struct efivars *__efivars;
|
||||
*/
|
||||
static DEFINE_SEMAPHORE(efivars_lock);
|
||||
|
||||
static bool efivar_wq_enabled = true;
|
||||
DECLARE_WORK(efivar_work, NULL);
|
||||
EXPORT_SYMBOL_GPL(efivar_work);
|
||||
|
||||
static bool
|
||||
validate_device_path(efi_char16_t *var_name, int match, u8 *buffer,
|
||||
unsigned long len)
|
||||
@ -391,13 +387,6 @@ static void dup_variable_bug(efi_char16_t *str16, efi_guid_t *vendor_guid,
|
||||
size_t i, len8 = len16 / sizeof(efi_char16_t);
|
||||
char *str8;
|
||||
|
||||
/*
|
||||
* Disable the workqueue since the algorithm it uses for
|
||||
* detecting new variables won't work with this buggy
|
||||
* implementation of GetNextVariableName().
|
||||
*/
|
||||
efivar_wq_enabled = false;
|
||||
|
||||
str8 = kzalloc(len8, GFP_KERNEL);
|
||||
if (!str8)
|
||||
return;
|
||||
@ -414,7 +403,6 @@ static void dup_variable_bug(efi_char16_t *str16, efi_guid_t *vendor_guid,
|
||||
* efivar_init - build the initial list of EFI variables
|
||||
* @func: callback function to invoke for every variable
|
||||
* @data: function-specific data to pass to @func
|
||||
* @atomic: do we need to execute the @func-loop atomically?
|
||||
* @duplicates: error if we encounter duplicates on @head?
|
||||
* @head: initialised head of variable list
|
||||
*
|
||||
@ -1157,16 +1145,6 @@ struct kobject *efivars_kobject(void)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(efivars_kobject);
|
||||
|
||||
/**
|
||||
* efivar_run_worker - schedule the efivar worker thread
|
||||
*/
|
||||
void efivar_run_worker(void)
|
||||
{
|
||||
if (efivar_wq_enabled)
|
||||
schedule_work(&efivar_work);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(efivar_run_worker);
|
||||
|
||||
/**
|
||||
* efivars_register - register an efivars
|
||||
* @efivars: efivars to register
|
||||
|
@ -15,7 +15,7 @@ config GOOGLE_SMI
|
||||
help
|
||||
Say Y here if you want to enable SMI callbacks for Google
|
||||
platforms. This provides an interface for writing to and
|
||||
clearing the event log. If EFI_VARS is also enabled this
|
||||
clearing the event log. If CONFIG_EFI is also enabled this
|
||||
driver provides an interface for reading and writing NVRAM
|
||||
variables.
|
||||
|
||||
|
@ -302,7 +302,7 @@ static int gsmi_exec(u8 func, u8 sub)
|
||||
return rc;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_EFI_VARS
|
||||
#ifdef CONFIG_EFI
|
||||
|
||||
static struct efivars efivars;
|
||||
|
||||
@ -483,7 +483,7 @@ static const struct efivar_operations efivar_ops = {
|
||||
.get_next_variable = gsmi_get_next_variable,
|
||||
};
|
||||
|
||||
#endif /* CONFIG_EFI_VARS */
|
||||
#endif /* CONFIG_EFI */
|
||||
|
||||
static ssize_t eventlog_write(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
@ -1007,7 +1007,7 @@ static __init int gsmi_init(void)
|
||||
goto out_remove_bin_file;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_EFI_VARS
|
||||
#ifdef CONFIG_EFI
|
||||
ret = efivars_register(&efivars, &efivar_ops, gsmi_kobj);
|
||||
if (ret) {
|
||||
printk(KERN_INFO "gsmi: Failed to register efivars\n");
|
||||
@ -1047,7 +1047,7 @@ static void __exit gsmi_exit(void)
|
||||
unregister_die_notifier(&gsmi_die_notifier);
|
||||
atomic_notifier_chain_unregister(&panic_notifier_list,
|
||||
&gsmi_panic_notifier);
|
||||
#ifdef CONFIG_EFI_VARS
|
||||
#ifdef CONFIG_EFI
|
||||
efivars_unregister(&efivars);
|
||||
#endif
|
||||
|
||||
|
@ -141,6 +141,9 @@ static int efivarfs_callback(efi_char16_t *name16, efi_guid_t vendor,
|
||||
|
||||
name[len + EFI_VARIABLE_GUID_LEN+1] = '\0';
|
||||
|
||||
/* replace invalid slashes like kobject_set_name_vargs does for /sys/firmware/efi/vars. */
|
||||
strreplace(name, '/', '!');
|
||||
|
||||
inode = efivarfs_get_inode(sb, d_inode(root), S_IFREG | 0644, 0,
|
||||
is_removable);
|
||||
if (!inode)
|
||||
|
@ -230,6 +230,18 @@ enum {
|
||||
#define CPER_MEM_VALID_RANK_NUMBER 0x8000
|
||||
#define CPER_MEM_VALID_CARD_HANDLE 0x10000
|
||||
#define CPER_MEM_VALID_MODULE_HANDLE 0x20000
|
||||
#define CPER_MEM_VALID_ROW_EXT 0x40000
|
||||
#define CPER_MEM_VALID_BANK_GROUP 0x80000
|
||||
#define CPER_MEM_VALID_BANK_ADDRESS 0x100000
|
||||
#define CPER_MEM_VALID_CHIP_ID 0x200000
|
||||
|
||||
#define CPER_MEM_EXT_ROW_MASK 0x3
|
||||
#define CPER_MEM_EXT_ROW_SHIFT 16
|
||||
|
||||
#define CPER_MEM_BANK_ADDRESS_MASK 0xff
|
||||
#define CPER_MEM_BANK_GROUP_SHIFT 8
|
||||
|
||||
#define CPER_MEM_CHIP_ID_SHIFT 5
|
||||
|
||||
#define CPER_PCIE_VALID_PORT_TYPE 0x0001
|
||||
#define CPER_PCIE_VALID_VERSION 0x0002
|
||||
@ -443,7 +455,7 @@ struct cper_sec_mem_err_old {
|
||||
u8 error_type;
|
||||
};
|
||||
|
||||
/* Memory Error Section (UEFI >= v2.3), UEFI v2.7 sec N.2.5 */
|
||||
/* Memory Error Section (UEFI >= v2.3), UEFI v2.8 sec N.2.5 */
|
||||
struct cper_sec_mem_err {
|
||||
u64 validation_bits;
|
||||
u64 error_status;
|
||||
@ -461,7 +473,7 @@ struct cper_sec_mem_err {
|
||||
u64 responder_id;
|
||||
u64 target_id;
|
||||
u8 error_type;
|
||||
u8 reserved;
|
||||
u8 extended;
|
||||
u16 rank;
|
||||
u16 mem_array_handle; /* "card handle" in UEFI 2.4 */
|
||||
u16 mem_dev_handle; /* "module handle" in UEFI 2.4 */
|
||||
@ -483,8 +495,16 @@ struct cper_mem_err_compact {
|
||||
u16 rank;
|
||||
u16 mem_array_handle;
|
||||
u16 mem_dev_handle;
|
||||
u8 extended;
|
||||
};
|
||||
|
||||
static inline u32 cper_get_mem_extension(u64 mem_valid, u8 mem_extended)
|
||||
{
|
||||
if (!(mem_valid & CPER_MEM_VALID_ROW_EXT))
|
||||
return 0;
|
||||
return (mem_extended & CPER_MEM_EXT_ROW_MASK) << CPER_MEM_EXT_ROW_SHIFT;
|
||||
}
|
||||
|
||||
/* PCI Express Error Section, UEFI v2.7 sec N.2.7 */
|
||||
struct cper_sec_pcie {
|
||||
u64 validation_bits;
|
||||
|
@ -122,6 +122,7 @@ typedef struct {
|
||||
((u64)0x0000000000010000ULL) /* higher reliability */
|
||||
#define EFI_MEMORY_RO ((u64)0x0000000000020000ULL) /* read-only */
|
||||
#define EFI_MEMORY_SP ((u64)0x0000000000040000ULL) /* soft reserved */
|
||||
#define EFI_MEMORY_CPU_CRYPTO ((u64)0x0000000000080000ULL) /* supports encryption */
|
||||
#define EFI_MEMORY_RUNTIME ((u64)0x8000000000000000ULL) /* range requires runtime mapping */
|
||||
#define EFI_MEMORY_DESCRIPTOR_VERSION 1
|
||||
|
||||
@ -357,6 +358,7 @@ 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_MOK_VARIABLE_TABLE_GUID EFI_GUID(0xc451ed2b, 0x9694, 0x45d3, 0xba, 0xba, 0xed, 0x9f, 0x89, 0x88, 0xa3, 0x89)
|
||||
|
||||
/* OEM GUIDs */
|
||||
#define DELLEMC_EFI_RCI2_TABLE_GUID EFI_GUID(0x2d9f28a2, 0xa886, 0x456a, 0x97, 0xa8, 0xf1, 0x1e, 0xf2, 0x4f, 0xf4, 0x55)
|
||||
@ -546,6 +548,7 @@ extern struct efi {
|
||||
unsigned long esrt; /* ESRT table */
|
||||
unsigned long tpm_log; /* TPM2 Event Log table */
|
||||
unsigned long tpm_final_log; /* TPM2 Final Events Log table */
|
||||
unsigned long mokvar_table; /* MOK variable config table */
|
||||
|
||||
efi_get_time_t *get_time;
|
||||
efi_set_time_t *set_time;
|
||||
@ -984,8 +987,6 @@ struct efivar_entry {
|
||||
bool deleting;
|
||||
};
|
||||
|
||||
extern struct list_head efivar_sysfs_list;
|
||||
|
||||
static inline void
|
||||
efivar_unregister(struct efivar_entry *var)
|
||||
{
|
||||
@ -1037,15 +1038,6 @@ bool efivar_validate(efi_guid_t vendor, efi_char16_t *var_name, u8 *data,
|
||||
bool efivar_variable_is_removable(efi_guid_t vendor, const char *name,
|
||||
size_t len);
|
||||
|
||||
extern struct work_struct efivar_work;
|
||||
void efivar_run_worker(void);
|
||||
|
||||
#if defined(CONFIG_EFI_VARS) || defined(CONFIG_EFI_VARS_MODULE)
|
||||
int efivars_sysfs_init(void);
|
||||
|
||||
#define EFIVARS_DATA_SIZE_MAX 1024
|
||||
|
||||
#endif /* CONFIG_EFI_VARS */
|
||||
extern bool efi_capsule_pending(int *reset_type);
|
||||
|
||||
extern int efi_capsule_supported(efi_guid_t guid, u32 flags,
|
||||
@ -1252,4 +1244,36 @@ void __init efi_arch_mem_reserve(phys_addr_t addr, u64 size);
|
||||
|
||||
char *efi_systab_show_arch(char *str);
|
||||
|
||||
/*
|
||||
* The LINUX_EFI_MOK_VARIABLE_TABLE_GUID config table can be provided
|
||||
* to the kernel by an EFI boot loader. The table contains a packed
|
||||
* sequence of these entries, one for each named MOK variable.
|
||||
* The sequence is terminated by an entry with a completely NULL
|
||||
* name and 0 data size.
|
||||
*/
|
||||
struct efi_mokvar_table_entry {
|
||||
char name[256];
|
||||
u64 data_size;
|
||||
u8 data[];
|
||||
} __attribute((packed));
|
||||
|
||||
#ifdef CONFIG_LOAD_UEFI_KEYS
|
||||
extern void __init efi_mokvar_table_init(void);
|
||||
extern struct efi_mokvar_table_entry *efi_mokvar_entry_next(
|
||||
struct efi_mokvar_table_entry **mokvar_entry);
|
||||
extern struct efi_mokvar_table_entry *efi_mokvar_entry_find(const char *name);
|
||||
#else
|
||||
static inline void efi_mokvar_table_init(void) { }
|
||||
static inline struct efi_mokvar_table_entry *efi_mokvar_entry_next(
|
||||
struct efi_mokvar_table_entry **mokvar_entry)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
static inline struct efi_mokvar_table_entry *efi_mokvar_entry_find(
|
||||
const char *name)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _LINUX_EFI_H */
|
||||
|
@ -55,6 +55,9 @@
|
||||
#define IMAGE_FILE_MACHINE_POWERPC 0x01f0
|
||||
#define IMAGE_FILE_MACHINE_POWERPCFP 0x01f1
|
||||
#define IMAGE_FILE_MACHINE_R4000 0x0166
|
||||
#define IMAGE_FILE_MACHINE_RISCV32 0x5032
|
||||
#define IMAGE_FILE_MACHINE_RISCV64 0x5064
|
||||
#define IMAGE_FILE_MACHINE_RISCV128 0x5128
|
||||
#define IMAGE_FILE_MACHINE_SH3 0x01a2
|
||||
#define IMAGE_FILE_MACHINE_SH3DSP 0x01a3
|
||||
#define IMAGE_FILE_MACHINE_SH3E 0x01a4
|
||||
|
@ -66,6 +66,65 @@ static __init void *get_cert_list(efi_char16_t *name, efi_guid_t *guid,
|
||||
}
|
||||
|
||||
/*
|
||||
* load_moklist_certs() - Load MokList certs
|
||||
*
|
||||
* Load the certs contained in the UEFI MokListRT database into the
|
||||
* platform trusted keyring.
|
||||
*
|
||||
* This routine checks the EFI MOK config table first. If and only if
|
||||
* that fails, this routine uses the MokListRT ordinary UEFI variable.
|
||||
*
|
||||
* Return: Status
|
||||
*/
|
||||
static int __init load_moklist_certs(void)
|
||||
{
|
||||
struct efi_mokvar_table_entry *mokvar_entry;
|
||||
efi_guid_t mok_var = EFI_SHIM_LOCK_GUID;
|
||||
void *mok;
|
||||
unsigned long moksize;
|
||||
efi_status_t status;
|
||||
int rc;
|
||||
|
||||
/* First try to load certs from the EFI MOKvar config table.
|
||||
* It's not an error if the MOKvar config table doesn't exist
|
||||
* or the MokListRT entry is not found in it.
|
||||
*/
|
||||
mokvar_entry = efi_mokvar_entry_find("MokListRT");
|
||||
if (mokvar_entry) {
|
||||
rc = parse_efi_signature_list("UEFI:MokListRT (MOKvar table)",
|
||||
mokvar_entry->data,
|
||||
mokvar_entry->data_size,
|
||||
get_handler_for_db);
|
||||
/* All done if that worked. */
|
||||
if (!rc)
|
||||
return rc;
|
||||
|
||||
pr_err("Couldn't parse MokListRT signatures from EFI MOKvar config table: %d\n",
|
||||
rc);
|
||||
}
|
||||
|
||||
/* Get MokListRT. It might not exist, so it isn't an error
|
||||
* if we can't get it.
|
||||
*/
|
||||
mok = get_cert_list(L"MokListRT", &mok_var, &moksize, &status);
|
||||
if (mok) {
|
||||
rc = parse_efi_signature_list("UEFI:MokListRT",
|
||||
mok, moksize, get_handler_for_db);
|
||||
kfree(mok);
|
||||
if (rc)
|
||||
pr_err("Couldn't parse MokListRT signatures: %d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
if (status == EFI_NOT_FOUND)
|
||||
pr_debug("MokListRT variable wasn't found\n");
|
||||
else
|
||||
pr_info("Couldn't get UEFI MokListRT\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* load_uefi_certs() - Load certs from UEFI sources
|
||||
*
|
||||
* Load the certs contained in the UEFI databases into the platform trusted
|
||||
* keyring and the UEFI blacklisted X.509 cert SHA256 hashes into the blacklist
|
||||
* keyring.
|
||||
@ -73,17 +132,16 @@ static __init void *get_cert_list(efi_char16_t *name, efi_guid_t *guid,
|
||||
static int __init load_uefi_certs(void)
|
||||
{
|
||||
efi_guid_t secure_var = EFI_IMAGE_SECURITY_DATABASE_GUID;
|
||||
efi_guid_t mok_var = EFI_SHIM_LOCK_GUID;
|
||||
void *db = NULL, *dbx = NULL, *mok = NULL;
|
||||
unsigned long dbsize = 0, dbxsize = 0, moksize = 0;
|
||||
void *db = NULL, *dbx = NULL;
|
||||
unsigned long dbsize = 0, dbxsize = 0;
|
||||
efi_status_t status;
|
||||
int rc = 0;
|
||||
|
||||
if (!efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE))
|
||||
return false;
|
||||
|
||||
/* Get db, MokListRT, and dbx. They might not exist, so it isn't
|
||||
* an error if we can't get them.
|
||||
/* Get db and dbx. They might not exist, so it isn't an error
|
||||
* if we can't get them.
|
||||
*/
|
||||
if (!uefi_check_ignore_db()) {
|
||||
db = get_cert_list(L"db", &secure_var, &dbsize, &status);
|
||||
@ -102,20 +160,6 @@ static int __init load_uefi_certs(void)
|
||||
}
|
||||
}
|
||||
|
||||
mok = get_cert_list(L"MokListRT", &mok_var, &moksize, &status);
|
||||
if (!mok) {
|
||||
if (status == EFI_NOT_FOUND)
|
||||
pr_debug("MokListRT variable wasn't found\n");
|
||||
else
|
||||
pr_info("Couldn't get UEFI MokListRT\n");
|
||||
} else {
|
||||
rc = parse_efi_signature_list("UEFI:MokListRT",
|
||||
mok, moksize, get_handler_for_db);
|
||||
if (rc)
|
||||
pr_err("Couldn't parse MokListRT signatures: %d\n", rc);
|
||||
kfree(mok);
|
||||
}
|
||||
|
||||
dbx = get_cert_list(L"dbx", &secure_var, &dbxsize, &status);
|
||||
if (!dbx) {
|
||||
if (status == EFI_NOT_FOUND)
|
||||
@ -131,6 +175,9 @@ static int __init load_uefi_certs(void)
|
||||
kfree(dbx);
|
||||
}
|
||||
|
||||
/* Load the MokListRT certs */
|
||||
rc = load_moklist_certs();
|
||||
|
||||
return rc;
|
||||
}
|
||||
late_initcall(load_uefi_certs);
|
||||
|
Loading…
Reference in New Issue
Block a user