Commit e6412f98 authored by Linus Torvalds's avatar Linus Torvalds

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
  ...
parents ed016af5 4d0a4388
......@@ -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 @@ create_efivars_bin_attributes(void)
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;
}
......
This diff is collapsed.
......@@ -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);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment