Merge tag 'efi-next-for-v5.20' of git://git.kernel.org/pub/scm/linux/kernel/git/efi/efi
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 3 Aug 2022 21:38:02 +0000 (14:38 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 3 Aug 2022 21:38:02 +0000 (14:38 -0700)
Pull EFI updates from Ard Biesheuvel:

 - Enable mirrored memory for arm64

 - Fix up several abuses of the efivar API

 - Refactor the efivar API in preparation for moving the 'business
   logic' part of it into efivarfs

 - Enable ACPI PRM on arm64

* tag 'efi-next-for-v5.20' of git://git.kernel.org/pub/scm/linux/kernel/git/efi/efi: (24 commits)
  ACPI: Move PRM config option under the main ACPI config
  ACPI: Enable Platform Runtime Mechanism(PRM) support on ARM64
  ACPI: PRM: Change handler_addr type to void pointer
  efi: Simplify arch_efi_call_virt() macro
  drivers: fix typo in firmware/efi/memmap.c
  efi: vars: Drop __efivar_entry_iter() helper which is no longer used
  efi: vars: Use locking version to iterate over efivars linked lists
  efi: pstore: Omit efivars caching EFI varstore access layer
  efi: vars: Add thin wrapper around EFI get/set variable interface
  efi: vars: Don't drop lock in the middle of efivar_init()
  pstore: Add priv field to pstore_record for backend specific use
  Input: applespi - avoid efivars API and invoke EFI services directly
  selftests/kexec: remove broken EFI_VARS secure boot fallback check
  brcmfmac: Switch to appropriate helper to load EFI variable contents
  iwlwifi: Switch to proper EFI variable store interface
  media: atomisp_gmin_platform: stop abusing efivar API
  efi: efibc: avoid efivar API for setting variables
  efi: avoid efivars layer when loading SSDTs from variables
  efi: Correct comment on efi_memmap_alloc
  memblock: Disable mirror feature if kernelcore is not specified
  ...

31 files changed:
arch/arm/include/asm/efi.h
arch/arm64/include/asm/efi.h
arch/arm64/mm/init.c
arch/loongarch/include/asm/efi.h
arch/riscv/include/asm/efi.h
arch/x86/include/asm/efi.h
arch/x86/platform/efi/efi.c
drivers/acpi/Kconfig
drivers/acpi/prmt.c
drivers/firmware/efi/Kconfig
drivers/firmware/efi/efi-init.c
drivers/firmware/efi/efi-pstore.c
drivers/firmware/efi/efi.c
drivers/firmware/efi/efibc.c
drivers/firmware/efi/efivars.c
drivers/firmware/efi/memmap.c
drivers/firmware/efi/vars.c
drivers/input/keyboard/applespi.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
drivers/net/wireless/intel/iwlwifi/fw/uefi.c
drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c
fs/efivarfs/super.c
fs/pstore/inode.c
fs/pstore/platform.c
include/linux/efi.h
include/linux/pstore.h
mm/internal.h
mm/memblock.c
mm/page_alloc.c
mm/sparse-vmemmap.c
tools/testing/selftests/kexec/kexec_common_lib.sh

index 27218ea..3088ef7 100644 (file)
@@ -24,13 +24,6 @@ int efi_set_mapping_permissions(struct mm_struct *mm, efi_memory_desc_t *md);
 #define arch_efi_call_virt_setup()     efi_virtmap_load()
 #define arch_efi_call_virt_teardown()  efi_virtmap_unload()
 
-#define arch_efi_call_virt(p, f, args...)                              \
-({                                                                     \
-       efi_##f##_t *__f;                                               \
-       __f = p->f;                                                     \
-       __f(args);                                                      \
-})
-
 #define ARCH_EFI_IRQ_FLAGS_MASK \
        (PSR_J_BIT | PSR_E_BIT | PSR_A_BIT | PSR_I_BIT | PSR_F_BIT | \
         PSR_T_BIT | MODE_MASK)
index ad55079..439e2bc 100644 (file)
@@ -27,12 +27,9 @@ int efi_set_mapping_permissions(struct mm_struct *mm, efi_memory_desc_t *md);
        __efi_fpsimd_begin();                                           \
 })
 
+#undef arch_efi_call_virt
 #define arch_efi_call_virt(p, f, args...)                              \
-({                                                                     \
-       efi_##f##_t *__f;                                               \
-       __f = p->f;                                                     \
-       __efi_rt_asm_wrapper(__f, #f, args);                            \
-})
+       __efi_rt_asm_wrapper((p)->f, #f, args)
 
 #define arch_efi_call_virt_teardown()                                  \
 ({                                                                     \
index b6ef26f..b9af30b 100644 (file)
@@ -350,8 +350,8 @@ void __init arm64_memblock_init(void)
                        "initrd not fully accessible via the linear mapping -- please check your bootloader ...\n")) {
                        phys_initrd_size = 0;
                } else {
-                       memblock_remove(base, size); /* clear MEMBLOCK_ flags */
                        memblock_add(base, size);
+                       memblock_clear_nomap(base, size);
                        memblock_reserve(base, size);
                }
        }
index 0127d84..9d44c69 100644 (file)
@@ -13,20 +13,8 @@ void efifb_setup_from_dmi(struct screen_info *si, const char *opt);
 
 #define ARCH_EFI_IRQ_FLAGS_MASK  0x00000004  /* Bit 2: CSR.CRMD.IE */
 
-#define arch_efi_call_virt_setup()               \
-({                                               \
-})
-
-#define arch_efi_call_virt(p, f, args...)        \
-({                                               \
-       efi_##f##_t * __f;                       \
-       __f = p->f;                              \
-       __f(args);                               \
-})
-
-#define arch_efi_call_virt_teardown()            \
-({                                               \
-})
+#define arch_efi_call_virt_setup()
+#define arch_efi_call_virt_teardown()
 
 #define EFI_ALLOC_ALIGN                SZ_64K
 
index cc4f678..f74879a 100644 (file)
@@ -23,8 +23,6 @@ int efi_set_mapping_permissions(struct mm_struct *mm, efi_memory_desc_t *md);
 #define arch_efi_call_virt_setup()      efi_virtmap_load()
 #define arch_efi_call_virt_teardown()   efi_virtmap_unload()
 
-#define arch_efi_call_virt(p, f, args...) p->f(args)
-
 #define ARCH_EFI_IRQ_FLAGS_MASK (SR_IE | SR_SPIE)
 
 /* Load initrd anywhere in system RAM */
index 9636742..233ae69 100644 (file)
@@ -100,8 +100,6 @@ static inline void efi_fpu_end(void)
        efi_fpu_end();                                                  \
 })
 
-#define arch_efi_call_virt(p, f, args...)      p->f(args)
-
 #else /* !CONFIG_X86_32 */
 
 #define EFI_LOADER_SIGNATURE   "EL64"
@@ -121,6 +119,7 @@ extern asmlinkage u64 __efi_call(void *fp, ...);
        efi_enter_mm();                                                 \
 })
 
+#undef arch_efi_call_virt
 #define arch_efi_call_virt(p, f, args...) ({                           \
        u64 ret, ibt = ibt_save();                                      \
        ret = efi_call((void *)p->f, args);                             \
@@ -383,7 +382,6 @@ static inline bool efi_is_64bit(void)
 extern bool efi_reboot_required(void);
 extern bool efi_is_table_address(unsigned long phys_addr);
 
-extern void efi_find_mirror(void);
 extern void efi_reserve_boot_services(void);
 #else
 static inline void parse_efi_setup(u64 phys_addr, u32 data_len) {}
@@ -395,9 +393,6 @@ static inline  bool efi_is_table_address(unsigned long phys_addr)
 {
        return false;
 }
-static inline void efi_find_mirror(void)
-{
-}
 static inline void efi_reserve_boot_services(void)
 {
 }
index 1591d67..6e598bd 100644 (file)
@@ -108,29 +108,6 @@ static int __init setup_add_efi_memmap(char *arg)
 }
 early_param("add_efi_memmap", setup_add_efi_memmap);
 
-void __init efi_find_mirror(void)
-{
-       efi_memory_desc_t *md;
-       u64 mirror_size = 0, total_size = 0;
-
-       if (!efi_enabled(EFI_MEMMAP))
-               return;
-
-       for_each_efi_memory_desc(md) {
-               unsigned long long start = md->phys_addr;
-               unsigned long long size = md->num_pages << EFI_PAGE_SHIFT;
-
-               total_size += size;
-               if (md->attribute & EFI_MEMORY_MORE_RELIABLE) {
-                       memblock_mark_mirror(start, size);
-                       mirror_size += size;
-               }
-       }
-       if (mirror_size)
-               pr_info("Memory: %lldM/%lldM mirrored memory\n",
-                       mirror_size>>20, total_size>>20);
-}
-
 /*
  * Tell the kernel about the EFI memory map.  This might include
  * more than the max 128 entries that can fit in the passed in e820
index 9b51c56..7802d88 100644 (file)
@@ -572,6 +572,21 @@ source "drivers/acpi/pmic/Kconfig"
 config ACPI_VIOT
        bool
 
+config ACPI_PRMT
+       bool "Platform Runtime Mechanism Support"
+       depends on EFI && (X86_64 || ARM64)
+       default y
+       help
+         Platform Runtime Mechanism (PRM) is a firmware interface exposing a
+         set of binary executables that can be called from the AML interpreter
+         or directly from device drivers.
+
+         Say Y to enable the AML interpreter to execute the PRM code.
+
+         While this feature is optional in principle, leaving it out may
+         substantially increase computational overhead related to the
+         initialization of some server systems.
+
 endif  # ACPI
 
 config X86_PM_TIMER
@@ -589,18 +604,3 @@ config X86_PM_TIMER
 
          You should nearly always say Y here because many modern
          systems require this timer.
-
-config ACPI_PRMT
-       bool "Platform Runtime Mechanism Support"
-       depends on EFI && X86_64
-       default y
-       help
-         Platform Runtime Mechanism (PRM) is a firmware interface exposing a
-         set of binary executables that can be called from the AML interpreter
-         or directly from device drivers.
-
-         Say Y to enable the AML interpreter to execute the PRM code.
-
-         While this feature is optional in principle, leaving it out may
-         substantially increase computational overhead related to the
-         initialization of some server systems.
index 4d3a219..998101c 100644 (file)
@@ -53,7 +53,7 @@ static LIST_HEAD(prm_module_list);
 
 struct prm_handler_info {
        guid_t guid;
-       u64 handler_addr;
+       void *handler_addr;
        u64 static_data_buffer_addr;
        u64 acpi_param_buffer_addr;
 
@@ -148,7 +148,7 @@ acpi_parse_prmt(union acpi_subtable_headers *header, const unsigned long end)
                th = &tm->handlers[cur_handler];
 
                guid_copy(&th->guid, (guid_t *)handler_info->handler_guid);
-               th->handler_addr = efi_pa_va_lookup(handler_info->handler_address);
+               th->handler_addr = (void *)efi_pa_va_lookup(handler_info->handler_address);
                th->static_data_buffer_addr = efi_pa_va_lookup(handler_info->static_data_buffer_address);
                th->acpi_param_buffer_addr = efi_pa_va_lookup(handler_info->acpi_param_buffer_address);
        } while (++cur_handler < tm->handler_count && (handler_info = get_next_handler(handler_info)));
index 7aa4717..7fe8b5c 100644 (file)
@@ -22,6 +22,7 @@ config EFI_ESRT
 config EFI_VARS_PSTORE
        tristate "Register efivars backend for pstore"
        depends on PSTORE
+       select UCS2_STRING
        default y
        help
          Say Y here to enable use efivars as a backend to pstore. This
@@ -145,6 +146,7 @@ config EFI_GENERIC_STUB_INITRD_CMDLINE_LOADER
 
 config EFI_BOOTLOADER_CONTROL
        tristate "EFI Bootloader Control"
+       select UCS2_STRING
        default n
        help
          This module installs a reboot hook, such that if reboot() is
index b2c829e..3928dbf 100644 (file)
@@ -240,6 +240,7 @@ void __init efi_init(void)
         * And now, memblock is fully populated, it is time to do capping.
         */
        early_init_dt_check_for_usable_mem_range();
+       efi_find_mirror();
        efi_esrt_init();
        efi_mokvar_table_init();
 
index 7e771c5..3bddc15 100644 (file)
@@ -6,6 +6,8 @@
 #include <linux/slab.h>
 #include <linux/ucs2_string.h>
 
+MODULE_IMPORT_NS(EFIVAR);
+
 #define DUMP_NAME_LEN 66
 
 #define EFIVARS_DATA_SIZE_MAX 1024
@@ -20,18 +22,25 @@ 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;
+       int err;
+
+       err = efivar_lock();
+       if (err)
+               return err;
+
+       psi->data = kzalloc(EFIVARS_DATA_SIZE_MAX, GFP_KERNEL);
+       if (!psi->data)
+               return -ENOMEM;
+
        return 0;
 }
 
 static int efi_pstore_close(struct pstore_info *psi)
 {
-       psi->data = NULL;
+       efivar_unlock();
+       kfree(psi->data);
        return 0;
 }
 
@@ -40,22 +49,17 @@ static inline u64 generic_id(u64 timestamp, unsigned int part, int count)
        return (timestamp * 100 + part) * 1000 + count;
 }
 
-static int efi_pstore_read_func(struct efivar_entry *entry,
-                               struct pstore_record *record)
+static int efi_pstore_read_func(struct pstore_record *record,
+                               efi_char16_t *varname)
 {
-       efi_guid_t vendor = LINUX_EFI_CRASH_GUID;
+       unsigned long wlen, size = EFIVARS_DATA_SIZE_MAX;
        char name[DUMP_NAME_LEN], data_type;
-       int i;
+       efi_status_t status;
        int cnt;
        unsigned int part;
-       unsigned long size;
        u64 time;
 
-       if (efi_guidcmp(entry->var.VendorGuid, vendor))
-               return 0;
-
-       for (i = 0; i < DUMP_NAME_LEN; i++)
-               name[i] = entry->var.VariableName[i];
+       ucs2_as_utf8(name, varname, DUMP_NAME_LEN);
 
        if (sscanf(name, "dump-type%u-%u-%d-%llu-%c",
                   &record->type, &part, &cnt, &time, &data_type) == 5) {
@@ -95,161 +99,75 @@ static int efi_pstore_read_func(struct efivar_entry *entry,
        } else
                return 0;
 
-       entry->var.DataSize = 1024;
-       __efivar_entry_get(entry, &entry->var.Attributes,
-                          &entry->var.DataSize, entry->var.Data);
-       size = entry->var.DataSize;
-       memcpy(record->buf, entry->var.Data,
-              (size_t)min_t(unsigned long, EFIVARS_DATA_SIZE_MAX, size));
-
-       return size;
-}
-
-/**
- * efi_pstore_scan_sysfs_enter
- * @pos: scanning entry
- * @next: next entry
- * @head: list head
- */
-static void efi_pstore_scan_sysfs_enter(struct efivar_entry *pos,
-                                       struct efivar_entry *next,
-                                       struct list_head *head)
-{
-       pos->scanning = true;
-       if (&next->list != head)
-               next->scanning = true;
-}
-
-/**
- * __efi_pstore_scan_sysfs_exit
- * @entry: deleting entry
- * @turn_off_scanning: Check if a scanning flag should be turned off
- */
-static inline int __efi_pstore_scan_sysfs_exit(struct efivar_entry *entry,
-                                               bool turn_off_scanning)
-{
-       if (entry->deleting) {
-               list_del(&entry->list);
-               efivar_entry_iter_end();
-               kfree(entry);
-               if (efivar_entry_iter_begin())
-                       return -EINTR;
-       } else if (turn_off_scanning)
-               entry->scanning = false;
-
-       return 0;
-}
-
-/**
- * efi_pstore_scan_sysfs_exit
- * @pos: scanning entry
- * @next: next entry
- * @head: list head
- * @stop: a flag checking if scanning will stop
- */
-static int efi_pstore_scan_sysfs_exit(struct efivar_entry *pos,
-                                      struct efivar_entry *next,
-                                      struct list_head *head, bool stop)
-{
-       int ret = __efi_pstore_scan_sysfs_exit(pos, true);
-
-       if (ret)
-               return ret;
-
-       if (stop)
-               ret = __efi_pstore_scan_sysfs_exit(next, &next->list != head);
-       return ret;
-}
+       record->buf = kmalloc(size, GFP_KERNEL);
+       if (!record->buf)
+               return -ENOMEM;
 
-/**
- * efi_pstore_sysfs_entry_iter
- *
- * @record: pstore record to pass to callback
- *
- * You MUST call efivar_entry_iter_begin() before this function, and
- * efivar_entry_iter_end() afterwards.
- *
- */
-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 = &efi_pstore_list;
-       int size = 0;
-       int ret;
-
-       if (!*pos) {
-               list_for_each_entry_safe(entry, n, head, list) {
-                       efi_pstore_scan_sysfs_enter(entry, n, head);
-
-                       size = efi_pstore_read_func(entry, record);
-                       ret = efi_pstore_scan_sysfs_exit(entry, n, head,
-                                                        size < 0);
-                       if (ret)
-                               return ret;
-                       if (size)
-                               break;
-               }
-               *pos = n;
-               return size;
+       status = efivar_get_variable(varname, &LINUX_EFI_CRASH_GUID, NULL,
+                                    &size, record->buf);
+       if (status != EFI_SUCCESS) {
+               kfree(record->buf);
+               return -EIO;
        }
 
-       list_for_each_entry_safe_from((*pos), n, head, list) {
-               efi_pstore_scan_sysfs_enter((*pos), n, head);
-
-               size = efi_pstore_read_func((*pos), record);
-               ret = efi_pstore_scan_sysfs_exit((*pos), n, head, size < 0);
-               if (ret)
-                       return ret;
-               if (size)
-                       break;
+       /*
+        * Store the name of the variable in the pstore_record priv field, so
+        * we can reuse it later if we need to delete the EFI variable from the
+        * variable store.
+        */
+       wlen = (ucs2_strnlen(varname, DUMP_NAME_LEN) + 1) * sizeof(efi_char16_t);
+       record->priv = kmemdup(varname, wlen, GFP_KERNEL);
+       if (!record->priv) {
+               kfree(record->buf);
+               return -ENOMEM;
        }
-       *pos = n;
+
        return size;
 }
 
-/**
- * efi_pstore_read
- *
- * This function returns a size of NVRAM entry logged via efi_pstore_write().
- * The meaning and behavior of efi_pstore/pstore are as below.
- *
- * size > 0: Got data of an entry logged via efi_pstore_write() successfully,
- *           and pstore filesystem will continue reading subsequent entries.
- * size == 0: Entry was not logged via efi_pstore_write(),
- *            and efi_pstore driver will continue reading subsequent entries.
- * size < 0: Failed to get data of entry logging via efi_pstore_write(),
- *           and pstore will stop reading entry.
- */
 static ssize_t efi_pstore_read(struct pstore_record *record)
 {
-       ssize_t size;
+       efi_char16_t *varname = record->psi->data;
+       efi_guid_t guid = LINUX_EFI_CRASH_GUID;
+       unsigned long varname_size;
+       efi_status_t status;
 
-       record->buf = kzalloc(EFIVARS_DATA_SIZE_MAX, GFP_KERNEL);
-       if (!record->buf)
-               return -ENOMEM;
+       for (;;) {
+               varname_size = EFIVARS_DATA_SIZE_MAX;
 
-       if (efivar_entry_iter_begin()) {
-               size = -EINTR;
-               goto out;
-       }
-       size = efi_pstore_sysfs_entry_iter(record);
-       efivar_entry_iter_end();
+               /*
+                * If this is the first read() call in the pstore enumeration,
+                * varname will be the empty string, and the GetNextVariable()
+                * runtime service call will return the first EFI variable in
+                * its own enumeration order, ignoring the guid argument.
+                *
+                * Subsequent calls to GetNextVariable() must pass the name and
+                * guid values returned by the previous call, which is why we
+                * store varname in record->psi->data. Given that we only
+                * enumerate variables with the efi-pstore GUID, there is no
+                * need to record the guid return value.
+                */
+               status = efivar_get_next_variable(&varname_size, varname, &guid);
+               if (status == EFI_NOT_FOUND)
+                       return 0;
 
-out:
-       if (size <= 0) {
-               kfree(record->buf);
-               record->buf = NULL;
+               if (status != EFI_SUCCESS)
+                       return -EIO;
+
+               /* skip variables that don't concern us */
+               if (efi_guidcmp(guid, LINUX_EFI_CRASH_GUID))
+                       continue;
+
+               return efi_pstore_read_func(record, varname);
        }
-       return size;
 }
 
 static int efi_pstore_write(struct pstore_record *record)
 {
        char name[DUMP_NAME_LEN];
        efi_char16_t efi_name[DUMP_NAME_LEN];
-       efi_guid_t vendor = LINUX_EFI_CRASH_GUID;
-       int i, ret = 0;
+       efi_status_t status;
+       int i;
 
        record->id = generic_id(record->time.tv_sec, record->part,
                                record->count);
@@ -265,88 +183,26 @@ static int efi_pstore_write(struct pstore_record *record)
        for (i = 0; i < DUMP_NAME_LEN; i++)
                efi_name[i] = name[i];
 
-       ret = efivar_entry_set_safe(efi_name, vendor, PSTORE_EFI_ATTRIBUTES,
-                             false, record->size, record->psi->buf);
-
-       if (record->reason == KMSG_DUMP_OOPS && try_module_get(THIS_MODULE))
-               if (!schedule_work(&efivar_work))
-                       module_put(THIS_MODULE);
-
-       return ret;
+       if (efivar_trylock())
+               return -EBUSY;
+       status = efivar_set_variable_locked(efi_name, &LINUX_EFI_CRASH_GUID,
+                                           PSTORE_EFI_ATTRIBUTES,
+                                           record->size, record->psi->buf,
+                                           true);
+       efivar_unlock();
+       return status == EFI_SUCCESS ? 0 : -EIO;
 };
 
-/*
- * Clean up an entry with the same name
- */
-static int efi_pstore_erase_func(struct efivar_entry *entry, void *data)
-{
-       efi_char16_t *efi_name = data;
-       efi_guid_t vendor = LINUX_EFI_CRASH_GUID;
-       unsigned long ucs2_len = ucs2_strlen(efi_name);
-
-       if (efi_guidcmp(entry->var.VendorGuid, vendor))
-               return 0;
-
-       if (ucs2_strncmp(entry->var.VariableName, efi_name, (size_t)ucs2_len))
-               return 0;
-
-       if (entry->scanning) {
-               /*
-                * Skip deletion because this entry will be deleted
-                * after scanning is completed.
-                */
-               entry->deleting = true;
-       } else
-               list_del(&entry->list);
-
-       /* found */
-       __efivar_entry_delete(entry);
-
-       return 1;
-}
-
-static int efi_pstore_erase_name(const char *name)
-{
-       struct efivar_entry *entry = NULL;
-       efi_char16_t efi_name[DUMP_NAME_LEN];
-       int found, i;
-
-       for (i = 0; i < DUMP_NAME_LEN; i++) {
-               efi_name[i] = name[i];
-               if (name[i] == '\0')
-                       break;
-       }
-
-       if (efivar_entry_iter_begin())
-               return -EINTR;
-
-       found = __efivar_entry_iter(efi_pstore_erase_func, &efi_pstore_list,
-                                   efi_name, &entry);
-       efivar_entry_iter_end();
-
-       if (found && !entry->scanning)
-               kfree(entry);
-
-       return found ? 0 : -ENOENT;
-}
-
 static int efi_pstore_erase(struct pstore_record *record)
 {
-       char name[DUMP_NAME_LEN];
-       int ret;
-
-       snprintf(name, sizeof(name), "dump-type%u-%u-%d-%lld",
-                record->type, record->part, record->count,
-                (long long)record->time.tv_sec);
-       ret = efi_pstore_erase_name(name);
-       if (ret != -ENOENT)
-               return ret;
+       efi_status_t status;
 
-       snprintf(name, sizeof(name), "dump-type%u-%u-%lld",
-               record->type, record->part, (long long)record->time.tv_sec);
-       ret = efi_pstore_erase_name(name);
+       status = efivar_set_variable(record->priv, &LINUX_EFI_CRASH_GUID,
+                                    PSTORE_EFI_ATTRIBUTES, 0, NULL);
 
-       return ret;
+       if (status != EFI_SUCCESS && status != EFI_NOT_FOUND)
+               return -EIO;
+       return 0;
 }
 
 static struct pstore_info efi_pstore_info = {
@@ -360,77 +216,14 @@ 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())
+       if (!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;
@@ -443,8 +236,6 @@ static __init int efivars_pstore_init(void)
                efi_pstore_info.bufsize = 0;
        }
 
-       INIT_WORK(&efivar_work, efi_pstore_update_entries);
-
        return 0;
 }
 
index 860534b..7f06065 100644 (file)
@@ -202,7 +202,7 @@ static void generic_ops_unregister(void)
 }
 
 #ifdef CONFIG_EFI_CUSTOM_SSDT_OVERLAYS
-#define EFIVAR_SSDT_NAME_MAX   16
+#define EFIVAR_SSDT_NAME_MAX   16UL
 static char efivar_ssdt[EFIVAR_SSDT_NAME_MAX] __initdata;
 static int __init efivar_ssdt_setup(char *str)
 {
@@ -219,83 +219,62 @@ static int __init efivar_ssdt_setup(char *str)
 }
 __setup("efivar_ssdt=", efivar_ssdt_setup);
 
-static __init int efivar_ssdt_iter(efi_char16_t *name, efi_guid_t vendor,
-                                  unsigned long name_size, void *data)
-{
-       struct efivar_entry *entry;
-       struct list_head *list = data;
-       char utf8_name[EFIVAR_SSDT_NAME_MAX];
-       int limit = min_t(unsigned long, EFIVAR_SSDT_NAME_MAX, name_size);
-
-       ucs2_as_utf8(utf8_name, name, limit - 1);
-       if (strncmp(utf8_name, efivar_ssdt, limit) != 0)
-               return 0;
-
-       entry = kmalloc(sizeof(*entry), GFP_KERNEL);
-       if (!entry)
-               return 0;
-
-       memcpy(entry->var.VariableName, name, name_size);
-       memcpy(&entry->var.VendorGuid, &vendor, sizeof(efi_guid_t));
-
-       efivar_entry_add(entry, list);
-
-       return 0;
-}
-
 static __init int efivar_ssdt_load(void)
 {
-       LIST_HEAD(entries);
-       struct efivar_entry *entry, *aux;
-       unsigned long size;
-       void *data;
-       int ret;
+       unsigned long name_size = 256;
+       efi_char16_t *name = NULL;
+       efi_status_t status;
+       efi_guid_t guid;
 
        if (!efivar_ssdt[0])
                return 0;
 
-       ret = efivar_init(efivar_ssdt_iter, &entries, true, &entries);
-
-       list_for_each_entry_safe(entry, aux, &entries, list) {
-               pr_info("loading SSDT from variable %s-%pUl\n", efivar_ssdt,
-                       &entry->var.VendorGuid);
+       name = kzalloc(name_size, GFP_KERNEL);
+       if (!name)
+               return -ENOMEM;
 
-               list_del(&entry->list);
+       for (;;) {
+               char utf8_name[EFIVAR_SSDT_NAME_MAX];
+               unsigned long data_size = 0;
+               void *data;
+               int limit;
 
-               ret = efivar_entry_size(entry, &size);
-               if (ret) {
-                       pr_err("failed to get var size\n");
-                       goto free_entry;
+               status = efi.get_next_variable(&name_size, name, &guid);
+               if (status == EFI_NOT_FOUND) {
+                       break;
+               } else if (status == EFI_BUFFER_TOO_SMALL) {
+                       name = krealloc(name, name_size, GFP_KERNEL);
+                       if (!name)
+                               return -ENOMEM;
+                       continue;
                }
 
-               data = kmalloc(size, GFP_KERNEL);
-               if (!data) {
-                       ret = -ENOMEM;
-                       goto free_entry;
-               }
+               limit = min(EFIVAR_SSDT_NAME_MAX, name_size);
+               ucs2_as_utf8(utf8_name, name, limit - 1);
+               if (strncmp(utf8_name, efivar_ssdt, limit) != 0)
+                       continue;
 
-               ret = efivar_entry_get(entry, NULL, &size, data);
-               if (ret) {
-                       pr_err("failed to get var data\n");
-                       goto free_data;
-               }
+               pr_info("loading SSDT from variable %s-%pUl\n", efivar_ssdt, &guid);
 
-               ret = acpi_load_table(data, NULL);
-               if (ret) {
-                       pr_err("failed to load table: %d\n", ret);
-                       goto free_data;
-               }
+               status = efi.get_variable(name, &guid, NULL, &data_size, NULL);
+               if (status != EFI_BUFFER_TOO_SMALL || !data_size)
+                       return -EIO;
 
-               goto free_entry;
+               data = kmalloc(data_size, GFP_KERNEL);
+               if (!data)
+                       return -ENOMEM;
 
-free_data:
+               status = efi.get_variable(name, &guid, NULL, &data_size, data);
+               if (status == EFI_SUCCESS) {
+                       acpi_status ret = acpi_load_table(data, NULL);
+                       if (ret)
+                               pr_err("failed to load table: %u\n", ret);
+               } else {
+                       pr_err("failed to get var data: 0x%lx\n", status);
+               }
                kfree(data);
-
-free_entry:
-               kfree(entry);
        }
-
-       return ret;
+       return 0;
 }
 #else
 static inline int efivar_ssdt_load(void) { return 0; }
@@ -446,6 +425,29 @@ err_put:
 
 subsys_initcall(efisubsys_init);
 
+void __init efi_find_mirror(void)
+{
+       efi_memory_desc_t *md;
+       u64 mirror_size = 0, total_size = 0;
+
+       if (!efi_enabled(EFI_MEMMAP))
+               return;
+
+       for_each_efi_memory_desc(md) {
+               unsigned long long start = md->phys_addr;
+               unsigned long long size = md->num_pages << EFI_PAGE_SHIFT;
+
+               total_size += size;
+               if (md->attribute & EFI_MEMORY_MORE_RELIABLE) {
+                       memblock_mark_mirror(start, size);
+                       mirror_size += size;
+               }
+       }
+       if (mirror_size)
+               pr_info("Memory: %lldM/%lldM mirrored memory\n",
+                       mirror_size>>20, total_size>>20);
+}
+
 /*
  * Find the efi memory descriptor for a given physical address.  Given a
  * physical address, determine if it exists within an EFI Memory Map entry,
index 15a4753..8ced7af 100644 (file)
 #include <linux/module.h>
 #include <linux/reboot.h>
 #include <linux/slab.h>
+#include <linux/ucs2_string.h>
 
-static void efibc_str_to_str16(const char *str, efi_char16_t *str16)
-{
-       size_t i;
-
-       for (i = 0; i < strlen(str); i++)
-               str16[i] = str[i];
-
-       str16[i] = '\0';
-}
+#define MAX_DATA_LEN   512
 
-static int efibc_set_variable(const char *name, const char *value)
+static int efibc_set_variable(efi_char16_t *name, efi_char16_t *value,
+                             unsigned long len)
 {
-       int ret;
-       efi_guid_t guid = LINUX_EFI_LOADER_ENTRY_GUID;
-       struct efivar_entry *entry;
-       size_t size = (strlen(value) + 1) * sizeof(efi_char16_t);
+       efi_status_t status;
 
-       if (size > sizeof(entry->var.Data)) {
-               pr_err("value is too large (%zu bytes) for '%s' EFI variable\n", size, name);
-               return -EINVAL;
-       }
+       status = efi.set_variable(name, &LINUX_EFI_LOADER_ENTRY_GUID,
+                                 EFI_VARIABLE_NON_VOLATILE
+                                 | EFI_VARIABLE_BOOTSERVICE_ACCESS
+                                 | EFI_VARIABLE_RUNTIME_ACCESS,
+                                 len * sizeof(efi_char16_t), value);
 
-       entry = kmalloc(sizeof(*entry), GFP_KERNEL);
-       if (!entry) {
-               pr_err("failed to allocate efivar entry for '%s' EFI variable\n", name);
-               return -ENOMEM;
+       if (status != EFI_SUCCESS) {
+               pr_err("failed to set EFI variable: 0x%lx\n", status);
+               return -EIO;
        }
-
-       efibc_str_to_str16(name, entry->var.VariableName);
-       efibc_str_to_str16(value, (efi_char16_t *)entry->var.Data);
-       memcpy(&entry->var.VendorGuid, &guid, sizeof(guid));
-
-       ret = efivar_entry_set_safe(entry->var.VariableName,
-                                   entry->var.VendorGuid,
-                                   EFI_VARIABLE_NON_VOLATILE
-                                   | EFI_VARIABLE_BOOTSERVICE_ACCESS
-                                   | EFI_VARIABLE_RUNTIME_ACCESS,
-                                   false, size, entry->var.Data);
-
-       if (ret)
-               pr_err("failed to set %s EFI variable: 0x%x\n",
-                      name, ret);
-
-       kfree(entry);
-       return ret;
+       return 0;
 }
 
 static int efibc_reboot_notifier_call(struct notifier_block *notifier,
                                      unsigned long event, void *data)
 {
-       const char *reason = "shutdown";
+       efi_char16_t *reason = event == SYS_RESTART ? L"reboot"
+                                                   : L"shutdown";
+       const u8 *str = data;
+       efi_char16_t *wdata;
+       unsigned long l;
        int ret;
 
-       if (event == SYS_RESTART)
-               reason = "reboot";
-
-       ret = efibc_set_variable("LoaderEntryRebootReason", reason);
+       ret = efibc_set_variable(L"LoaderEntryRebootReason", reason,
+                                ucs2_strlen(reason));
        if (ret || !data)
                return NOTIFY_DONE;
 
-       efibc_set_variable("LoaderEntryOneShot", (char *)data);
+       wdata = kmalloc(MAX_DATA_LEN * sizeof(efi_char16_t), GFP_KERNEL);
+       for (l = 0; l < MAX_DATA_LEN - 1 && str[l] != '\0'; l++)
+               wdata[l] = str[l];
+       wdata[l] = L'\0';
+
+       efibc_set_variable(L"LoaderEntryOneShot", wdata, l);
 
+       kfree(wdata);
        return NOTIFY_DONE;
 }
 
@@ -84,7 +66,7 @@ static int __init efibc_init(void)
 {
        int ret;
 
-       if (!efivars_kobject() || !efivar_supports_writes())
+       if (!efi_rt_services_supported(EFI_RT_SUPPORTED_SET_VARIABLE))
                return -ENODEV;
 
        ret = register_reboot_notifier(&efibc_reboot_notifier);
index ea0bc39..801a655 100644 (file)
@@ -467,16 +467,12 @@ static ssize_t efivar_delete(struct file *filp, struct kobject *kobj,
        else if (__efivar_entry_delete(entry))
                err = -EIO;
 
-       if (err) {
-               efivar_entry_iter_end();
+       efivar_entry_iter_end();
+
+       if (err)
                return err;
-       }
 
-       if (!entry->scanning) {
-               efivar_entry_iter_end();
-               efivar_unregister(entry);
-       } else
-               efivar_entry_iter_end();
+       efivar_unregister(entry);
 
        /* It's dead Jim.... */
        return count;
@@ -527,10 +523,7 @@ efivar_create_sysfs_entry(struct efivar_entry *new_var)
        }
 
        kobject_uevent(&new_var->kobj, KOBJ_ADD);
-       if (efivar_entry_add(new_var, &efivar_sysfs_list)) {
-               efivar_unregister(new_var);
-               return -EINTR;
-       }
+       __efivar_entry_add(new_var, &efivar_sysfs_list);
 
        return 0;
 }
@@ -609,10 +602,7 @@ static int efivars_sysfs_callback(efi_char16_t *name, efi_guid_t vendor,
 
 static int efivar_sysfs_destroy(struct efivar_entry *entry, void *data)
 {
-       int err = efivar_entry_remove(entry);
-
-       if (err)
-               return err;
+       efivar_entry_remove(entry);
        efivar_unregister(entry);
        return 0;
 }
@@ -622,8 +612,7 @@ static void efivars_sysfs_exit(void)
        /* Remove all entries and destroy */
        int err;
 
-       err = __efivar_entry_iter(efivar_sysfs_destroy, &efivar_sysfs_list,
-                                 NULL, NULL);
+       err = efivar_entry_iter(efivar_sysfs_destroy, &efivar_sysfs_list, NULL);
        if (err) {
                pr_err("efivars: Failed to destroy sysfs entries\n");
                return;
index 4df55a5..6ec7970 100644 (file)
@@ -59,8 +59,7 @@ static void __init efi_memmap_free(void)
  * Depending on whether mm_init() has already been invoked or not,
  * either memblock or "normal" page allocation is used.
  *
- * Returns the physical address of the allocated memory map on
- * success, zero on failure.
+ * Returns zero on success, a negative error code on failure.
  */
 int __init efi_memmap_alloc(unsigned int num_entries,
                struct efi_memory_map_data *data)
@@ -245,7 +244,7 @@ int __init efi_memmap_install(struct efi_memory_map_data *data)
  * @range: Address range (start, end) to split around
  *
  * Returns the number of additional EFI memmap entries required to
- * accomodate @range.
+ * accommodate @range.
  */
 int __init efi_memmap_split_count(efi_memory_desc_t *md, struct range *range)
 {
index cae590b..9324359 100644 (file)
@@ -298,14 +298,10 @@ efivar_variable_is_removable(efi_guid_t vendor, const char *var_name,
 }
 EXPORT_SYMBOL_GPL(efivar_variable_is_removable);
 
-static efi_status_t
-check_var_size(u32 attributes, unsigned long size)
+efi_status_t check_var_size(u32 attributes, unsigned long size)
 {
        const struct efivar_operations *fops;
 
-       if (!__efivars)
-               return EFI_UNSUPPORTED;
-
        fops = __efivars->ops;
 
        if (!fops->query_variable_store)
@@ -313,15 +309,12 @@ check_var_size(u32 attributes, unsigned long size)
 
        return fops->query_variable_store(attributes, size, false);
 }
+EXPORT_SYMBOL_NS_GPL(check_var_size, EFIVAR);
 
-static efi_status_t
-check_var_size_nonblocking(u32 attributes, unsigned long size)
+efi_status_t check_var_size_nonblocking(u32 attributes, unsigned long size)
 {
        const struct efivar_operations *fops;
 
-       if (!__efivars)
-               return EFI_UNSUPPORTED;
-
        fops = __efivars->ops;
 
        if (!fops->query_variable_store)
@@ -329,6 +322,7 @@ check_var_size_nonblocking(u32 attributes, unsigned long size)
 
        return fops->query_variable_store(attributes, size, true);
 }
+EXPORT_SYMBOL_NS_GPL(check_var_size_nonblocking, EFIVAR);
 
 static bool variable_is_present(efi_char16_t *variable_name, efi_guid_t *vendor,
                                struct list_head *head)
@@ -450,9 +444,6 @@ int efivar_init(int (*func)(efi_char16_t *, efi_guid_t, unsigned long, void *),
                                                &vendor_guid);
                switch (status) {
                case EFI_SUCCESS:
-                       if (duplicates)
-                               up(&efivars_lock);
-
                        variable_name_size = var_name_strnsize(variable_name,
                                                               variable_name_size);
 
@@ -476,14 +467,6 @@ int efivar_init(int (*func)(efi_char16_t *, efi_guid_t, unsigned long, void *),
                                if (err)
                                        status = EFI_NOT_FOUND;
                        }
-
-                       if (duplicates) {
-                               if (down_interruptible(&efivars_lock)) {
-                                       err = -EINTR;
-                                       goto free;
-                               }
-                       }
-
                        break;
                case EFI_UNSUPPORTED:
                        err = -EOPNOTSUPP;
@@ -526,20 +509,24 @@ int efivar_entry_add(struct efivar_entry *entry, struct list_head *head)
 }
 EXPORT_SYMBOL_GPL(efivar_entry_add);
 
+/**
+ * __efivar_entry_add - add entry to variable list
+ * @entry: entry to add to list
+ * @head: list head
+ */
+void __efivar_entry_add(struct efivar_entry *entry, struct list_head *head)
+{
+       list_add(&entry->list, head);
+}
+EXPORT_SYMBOL_GPL(__efivar_entry_add);
+
 /**
  * efivar_entry_remove - remove entry from variable list
  * @entry: entry to remove from list
- *
- * Returns 0 on success, or a kernel error code on failure.
  */
-int efivar_entry_remove(struct efivar_entry *entry)
+void efivar_entry_remove(struct efivar_entry *entry)
 {
-       if (down_interruptible(&efivars_lock))
-               return -EINTR;
        list_del(&entry->list);
-       up(&efivars_lock);
-
-       return 0;
 }
 EXPORT_SYMBOL_GPL(efivar_entry_remove);
 
@@ -827,16 +814,8 @@ struct efivar_entry *efivar_entry_find(efi_char16_t *name, efi_guid_t guid,
        if (!found)
                return NULL;
 
-       if (remove) {
-               if (entry->scanning) {
-                       /*
-                        * The entry will be deleted
-                        * after scanning is completed.
-                        */
-                       entry->deleting = true;
-               } else
-                       list_del(&entry->list);
-       }
+       if (remove)
+               list_del(&entry->list);
 
        return entry;
 }
@@ -1055,59 +1034,6 @@ void efivar_entry_iter_end(void)
 }
 EXPORT_SYMBOL_GPL(efivar_entry_iter_end);
 
-/**
- * __efivar_entry_iter - iterate over variable list
- * @func: callback function
- * @head: head of the variable list
- * @data: function-specific data to pass to callback
- * @prev: entry to begin iterating from
- *
- * Iterate over the list of EFI variables and call @func with every
- * entry on the list. It is safe for @func to remove entries in the
- * list via efivar_entry_delete().
- *
- * You MUST call efivar_entry_iter_begin() before this function, and
- * efivar_entry_iter_end() afterwards.
- *
- * It is possible to begin iteration from an arbitrary entry within
- * the list by passing @prev. @prev is updated on return to point to
- * the last entry passed to @func. To begin iterating from the
- * beginning of the list @prev must be %NULL.
- *
- * The restrictions for @func are the same as documented for
- * efivar_entry_iter().
- */
-int __efivar_entry_iter(int (*func)(struct efivar_entry *, void *),
-                       struct list_head *head, void *data,
-                       struct efivar_entry **prev)
-{
-       struct efivar_entry *entry, *n;
-       int err = 0;
-
-       if (!prev || !*prev) {
-               list_for_each_entry_safe(entry, n, head, list) {
-                       err = func(entry, data);
-                       if (err)
-                               break;
-               }
-
-               if (prev)
-                       *prev = entry;
-
-               return err;
-       }
-
-
-       list_for_each_entry_safe_continue((*prev), n, head, list) {
-               err = func(*prev, data);
-               if (err)
-                       break;
-       }
-
-       return err;
-}
-EXPORT_SYMBOL_GPL(__efivar_entry_iter);
-
 /**
  * efivar_entry_iter - iterate over variable list
  * @func: callback function
@@ -1125,12 +1051,18 @@ EXPORT_SYMBOL_GPL(__efivar_entry_iter);
 int efivar_entry_iter(int (*func)(struct efivar_entry *, void *),
                      struct list_head *head, void *data)
 {
+       struct efivar_entry *entry, *n;
        int err = 0;
 
        err = efivar_entry_iter_begin();
        if (err)
                return err;
-       err = __efivar_entry_iter(func, head, data, NULL);
+
+       list_for_each_entry_safe(entry, n, head, list) {
+               err = func(entry, data);
+               if (err)
+                       break;
+       }
        efivar_entry_iter_end();
 
        return err;
@@ -1220,3 +1152,143 @@ int efivar_supports_writes(void)
        return __efivars && __efivars->ops->set_variable;
 }
 EXPORT_SYMBOL_GPL(efivar_supports_writes);
+
+/*
+ * efivar_lock() - obtain the efivar lock, wait for it if needed
+ * @return 0 on success, error code on failure
+ */
+int efivar_lock(void)
+{
+       if (down_interruptible(&efivars_lock))
+               return -EINTR;
+       if (!__efivars->ops) {
+               up(&efivars_lock);
+               return -ENODEV;
+       }
+       return 0;
+}
+EXPORT_SYMBOL_NS_GPL(efivar_lock, EFIVAR);
+
+/*
+ * efivar_lock() - obtain the efivar lock if it is free
+ * @return 0 on success, error code on failure
+ */
+int efivar_trylock(void)
+{
+       if (down_trylock(&efivars_lock))
+                return -EBUSY;
+       if (!__efivars->ops) {
+               up(&efivars_lock);
+               return -ENODEV;
+       }
+       return 0;
+}
+EXPORT_SYMBOL_NS_GPL(efivar_trylock, EFIVAR);
+
+/*
+ * efivar_unlock() - release the efivar lock
+ */
+void efivar_unlock(void)
+{
+       up(&efivars_lock);
+}
+EXPORT_SYMBOL_NS_GPL(efivar_unlock, EFIVAR);
+
+/*
+ * efivar_get_variable() - retrieve a variable identified by name/vendor
+ *
+ * Must be called with efivars_lock held.
+ */
+efi_status_t efivar_get_variable(efi_char16_t *name, efi_guid_t *vendor,
+                                u32 *attr, unsigned long *size, void *data)
+{
+       return __efivars->ops->get_variable(name, vendor, attr, size, data);
+}
+EXPORT_SYMBOL_NS_GPL(efivar_get_variable, EFIVAR);
+
+/*
+ * efivar_get_next_variable() - enumerate the next name/vendor pair
+ *
+ * Must be called with efivars_lock held.
+ */
+efi_status_t efivar_get_next_variable(unsigned long *name_size,
+                                     efi_char16_t *name, efi_guid_t *vendor)
+{
+       return __efivars->ops->get_next_variable(name_size, name, vendor);
+}
+EXPORT_SYMBOL_NS_GPL(efivar_get_next_variable, EFIVAR);
+
+/*
+ * efivar_set_variable_blocking() - local helper function for set_variable
+ *
+ * Must be called with efivars_lock held.
+ */
+static efi_status_t
+efivar_set_variable_blocking(efi_char16_t *name, efi_guid_t *vendor,
+                            u32 attr, unsigned long data_size, void *data)
+{
+       efi_status_t status;
+
+       if (data_size > 0) {
+               status = check_var_size(attr, data_size +
+                                             ucs2_strsize(name, 1024));
+               if (status != EFI_SUCCESS)
+                       return status;
+       }
+       return __efivars->ops->set_variable(name, vendor, attr, data_size, data);
+}
+
+/*
+ * efivar_set_variable_locked() - set a variable identified by name/vendor
+ *
+ * Must be called with efivars_lock held. If @nonblocking is set, it will use
+ * non-blocking primitives so it is guaranteed not to sleep.
+ */
+efi_status_t efivar_set_variable_locked(efi_char16_t *name, efi_guid_t *vendor,
+                                       u32 attr, unsigned long data_size,
+                                       void *data, bool nonblocking)
+{
+       efi_set_variable_t *setvar;
+       efi_status_t status;
+
+       if (!nonblocking)
+               return efivar_set_variable_blocking(name, vendor, attr,
+                                                   data_size, data);
+
+       /*
+        * If no _nonblocking variant exists, the ordinary one
+        * is assumed to be non-blocking.
+        */
+       setvar = __efivars->ops->set_variable_nonblocking ?:
+                __efivars->ops->set_variable;
+
+       if (data_size > 0) {
+               status = check_var_size_nonblocking(attr, data_size +
+                                                         ucs2_strsize(name, 1024));
+               if (status != EFI_SUCCESS)
+                       return status;
+       }
+       return setvar(name, vendor, attr, data_size, data);
+}
+EXPORT_SYMBOL_NS_GPL(efivar_set_variable_locked, EFIVAR);
+
+/*
+ * efivar_set_variable() - set a variable identified by name/vendor
+ *
+ * Can be called without holding the efivars_lock. Will sleep on obtaining the
+ * lock, or on obtaining other locks that are needed in order to complete the
+ * call.
+ */
+efi_status_t efivar_set_variable(efi_char16_t *name, efi_guid_t *vendor,
+                                u32 attr, unsigned long data_size, void *data)
+{
+       efi_status_t status;
+
+       if (efivar_lock())
+               return EFI_ABORTED;
+
+       status = efivar_set_variable_blocking(name, vendor, attr, data_size, data);
+       efivar_unlock();
+       return status;
+}
+EXPORT_SYMBOL_NS_GPL(efivar_set_variable, EFIVAR);
index d1f5354..cbc6c0d 100644 (file)
@@ -1597,52 +1597,38 @@ static u32 applespi_notify(acpi_handle gpe_device, u32 gpe, void *context)
 
 static int applespi_get_saved_bl_level(struct applespi_data *applespi)
 {
-       struct efivar_entry *efivar_entry;
+       efi_status_t sts = EFI_NOT_FOUND;
        u16 efi_data = 0;
-       unsigned long efi_data_len;
-       int sts;
-
-       efivar_entry = kmalloc(sizeof(*efivar_entry), GFP_KERNEL);
-       if (!efivar_entry)
-               return -ENOMEM;
-
-       memcpy(efivar_entry->var.VariableName, EFI_BL_LEVEL_NAME,
-              sizeof(EFI_BL_LEVEL_NAME));
-       efivar_entry->var.VendorGuid = EFI_BL_LEVEL_GUID;
-       efi_data_len = sizeof(efi_data);
+       unsigned long efi_data_len = sizeof(efi_data);
 
-       sts = efivar_entry_get(efivar_entry, NULL, &efi_data_len, &efi_data);
-       if (sts && sts != -ENOENT)
+       if (efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE))
+               sts = efi.get_variable(EFI_BL_LEVEL_NAME, &EFI_BL_LEVEL_GUID,
+                                      NULL, &efi_data_len, &efi_data);
+       if (sts != EFI_SUCCESS && sts != EFI_NOT_FOUND)
                dev_warn(&applespi->spi->dev,
-                        "Error getting backlight level from EFI vars: %d\n",
+                        "Error getting backlight level from EFI vars: 0x%lx\n",
                         sts);
 
-       kfree(efivar_entry);
-
-       return sts ? sts : efi_data;
+       return sts != EFI_SUCCESS ? -ENODEV : efi_data;
 }
 
 static void applespi_save_bl_level(struct applespi_data *applespi,
                                   unsigned int level)
 {
-       efi_guid_t efi_guid;
+       efi_status_t sts = EFI_UNSUPPORTED;
        u32 efi_attr;
-       unsigned long efi_data_len;
        u16 efi_data;
-       int sts;
 
-       /* Save keyboard backlight level */
-       efi_guid = EFI_BL_LEVEL_GUID;
        efi_data = (u16)level;
-       efi_data_len = sizeof(efi_data);
        efi_attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS |
                   EFI_VARIABLE_RUNTIME_ACCESS;
 
-       sts = efivar_entry_set_safe((efi_char16_t *)EFI_BL_LEVEL_NAME, efi_guid,
-                                   efi_attr, true, efi_data_len, &efi_data);
-       if (sts)
+       if (efi_rt_services_supported(EFI_RT_SUPPORTED_SET_VARIABLE))
+               sts = efi.set_variable(EFI_BL_LEVEL_NAME, &EFI_BL_LEVEL_GUID,
+                                      efi_attr, sizeof(efi_data), &efi_data);
+       if (sts != EFI_SUCCESS)
                dev_warn(&applespi->spi->dev,
-                        "Error saving backlight level to EFI vars: %d\n", sts);
+                        "Error saving backlight level to EFI vars: 0x%lx\n", sts);
 }
 
 static int applespi_probe(struct spi_device *spi)
index dcbe55b..b8379e4 100644 (file)
@@ -459,43 +459,34 @@ static void brcmf_fw_fix_efi_nvram_ccode(char *data, unsigned long data_len)
 
 static u8 *brcmf_fw_nvram_from_efi(size_t *data_len_ret)
 {
-       const u16 name[] = { 'n', 'v', 'r', 'a', 'm', 0 };
-       struct efivar_entry *nvram_efivar;
+       efi_guid_t guid = EFI_GUID(0x74b00bd9, 0x805a, 0x4d61, 0xb5, 0x1f,
+                                  0x43, 0x26, 0x81, 0x23, 0xd1, 0x13);
        unsigned long data_len = 0;
+       efi_status_t status;
        u8 *data = NULL;
-       int err;
 
-       nvram_efivar = kzalloc(sizeof(*nvram_efivar), GFP_KERNEL);
-       if (!nvram_efivar)
+       if (!efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE))
                return NULL;
 
-       memcpy(&nvram_efivar->var.VariableName, name, sizeof(name));
-       nvram_efivar->var.VendorGuid = EFI_GUID(0x74b00bd9, 0x805a, 0x4d61,
-                                               0xb5, 0x1f, 0x43, 0x26,
-                                               0x81, 0x23, 0xd1, 0x13);
-
-       err = efivar_entry_size(nvram_efivar, &data_len);
-       if (err)
+       status = efi.get_variable(L"nvram", &guid, NULL, &data_len, NULL);
+       if (status != EFI_BUFFER_TOO_SMALL)
                goto fail;
 
        data = kmalloc(data_len, GFP_KERNEL);
        if (!data)
                goto fail;
 
-       err = efivar_entry_get(nvram_efivar, NULL, &data_len, data);
-       if (err)
+       status = efi.get_variable(L"nvram", &guid, NULL, &data_len, data);
+       if (status != EFI_SUCCESS)
                goto fail;
 
        brcmf_fw_fix_efi_nvram_ccode(data, data_len);
        brcmf_info("Using nvram EFI variable\n");
 
-       kfree(nvram_efivar);
        *data_len_ret = data_len;
        return data;
-
 fail:
        kfree(data);
-       kfree(nvram_efivar);
        return NULL;
 }
 #else
index 23b1d68..6d408cd 100644 (file)
 
 void *iwl_uefi_get_pnvm(struct iwl_trans *trans, size_t *len)
 {
-       struct efivar_entry *pnvm_efivar;
        void *data;
        unsigned long package_size;
-       int err;
+       efi_status_t status;
 
        *len = 0;
 
-       pnvm_efivar = kzalloc(sizeof(*pnvm_efivar), GFP_KERNEL);
-       if (!pnvm_efivar)
-               return ERR_PTR(-ENOMEM);
-
-       memcpy(&pnvm_efivar->var.VariableName, IWL_UEFI_OEM_PNVM_NAME,
-              sizeof(IWL_UEFI_OEM_PNVM_NAME));
-       pnvm_efivar->var.VendorGuid = IWL_EFI_VAR_GUID;
+       if (!efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE))
+               return ERR_PTR(-ENODEV);
 
        /*
         * TODO: we hardcode a maximum length here, because reading
@@ -42,27 +36,22 @@ void *iwl_uefi_get_pnvm(struct iwl_trans *trans, size_t *len)
        package_size = IWL_HARDCODED_PNVM_SIZE;
 
        data = kmalloc(package_size, GFP_KERNEL);
-       if (!data) {
-               data = ERR_PTR(-ENOMEM);
-               goto out;
-       }
+       if (!data)
+               return ERR_PTR(-ENOMEM);
 
-       err = efivar_entry_get(pnvm_efivar, NULL, &package_size, data);
-       if (err) {
+       status = efi.get_variable(IWL_UEFI_OEM_PNVM_NAME, &IWL_EFI_VAR_GUID,
+                                 NULL, &package_size, data);
+       if (status != EFI_SUCCESS) {
                IWL_DEBUG_FW(trans,
-                            "PNVM UEFI variable not found %d (len %lu)\n",
-                            err, package_size);
+                            "PNVM UEFI variable not found 0x%lx (len %lu)\n",
+                            status, package_size);
                kfree(data);
-               data = ERR_PTR(err);
-               goto out;
+               return ERR_PTR(-ENOENT);
        }
 
        IWL_DEBUG_FW(trans, "Read PNVM from UEFI with size %lu\n", package_size);
        *len = package_size;
 
-out:
-       kfree(pnvm_efivar);
-
        return data;
 }
 
@@ -211,21 +200,15 @@ static void *iwl_uefi_reduce_power_parse(struct iwl_trans *trans,
 
 void *iwl_uefi_get_reduced_power(struct iwl_trans *trans, size_t *len)
 {
-       struct efivar_entry *reduce_power_efivar;
        struct pnvm_sku_package *package;
        void *data = NULL;
        unsigned long package_size;
-       int err;
+       efi_status_t status;
 
        *len = 0;
 
-       reduce_power_efivar = kzalloc(sizeof(*reduce_power_efivar), GFP_KERNEL);
-       if (!reduce_power_efivar)
-               return ERR_PTR(-ENOMEM);
-
-       memcpy(&reduce_power_efivar->var.VariableName, IWL_UEFI_REDUCED_POWER_NAME,
-              sizeof(IWL_UEFI_REDUCED_POWER_NAME));
-       reduce_power_efivar->var.VendorGuid = IWL_EFI_VAR_GUID;
+       if (!efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE))
+               return ERR_PTR(-ENODEV);
 
        /*
         * TODO: we hardcode a maximum length here, because reading
@@ -235,19 +218,17 @@ void *iwl_uefi_get_reduced_power(struct iwl_trans *trans, size_t *len)
        package_size = IWL_HARDCODED_REDUCE_POWER_SIZE;
 
        package = kmalloc(package_size, GFP_KERNEL);
-       if (!package) {
-               package = ERR_PTR(-ENOMEM);
-               goto out;
-       }
+       if (!package)
+               return ERR_PTR(-ENOMEM);
 
-       err = efivar_entry_get(reduce_power_efivar, NULL, &package_size, package);
-       if (err) {
+       status = efi.get_variable(IWL_UEFI_REDUCED_POWER_NAME, &IWL_EFI_VAR_GUID,
+                                 NULL, &package_size, data);
+       if (status != EFI_SUCCESS) {
                IWL_DEBUG_FW(trans,
-                            "Reduced Power UEFI variable not found %d (len %lu)\n",
-                            err, package_size);
+                            "Reduced Power UEFI variable not found 0x%lx (len %lu)\n",
+                            status, package_size);
                kfree(package);
-               data = ERR_PTR(err);
-               goto out;
+               return ERR_PTR(-ENOENT);
        }
 
        IWL_DEBUG_FW(trans, "Read reduced power from UEFI with size %lu\n",
@@ -262,9 +243,6 @@ void *iwl_uefi_get_reduced_power(struct iwl_trans *trans, size_t *len)
 
        kfree(package);
 
-out:
-       kfree(reduce_power_efivar);
-
        return data;
 }
 
@@ -304,22 +282,15 @@ static int iwl_uefi_sgom_parse(struct uefi_cnv_wlan_sgom_data *sgom_data,
 void iwl_uefi_get_sgom_table(struct iwl_trans *trans,
                             struct iwl_fw_runtime *fwrt)
 {
-       struct efivar_entry *sgom_efivar;
        struct uefi_cnv_wlan_sgom_data *data;
        unsigned long package_size;
-       int err, ret;
-
-       if (!fwrt->geo_enabled)
-               return;
+       efi_status_t status;
+       int ret;
 
-       sgom_efivar = kzalloc(sizeof(*sgom_efivar), GFP_KERNEL);
-       if (!sgom_efivar)
+       if (!fwrt->geo_enabled ||
+           !efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE))
                return;
 
-       memcpy(&sgom_efivar->var.VariableName, IWL_UEFI_SGOM_NAME,
-              sizeof(IWL_UEFI_SGOM_NAME));
-       sgom_efivar->var.VendorGuid = IWL_EFI_VAR_GUID;
-
        /* TODO: we hardcode a maximum length here, because reading
         * from the UEFI is not working.  To implement this properly,
         * we have to call efivar_entry_size().
@@ -327,15 +298,14 @@ void iwl_uefi_get_sgom_table(struct iwl_trans *trans,
        package_size = IWL_HARDCODED_SGOM_SIZE;
 
        data = kmalloc(package_size, GFP_KERNEL);
-       if (!data) {
-               data = ERR_PTR(-ENOMEM);
-               goto out;
-       }
+       if (!data)
+               return;
 
-       err = efivar_entry_get(sgom_efivar, NULL, &package_size, data);
-       if (err) {
+       status = efi.get_variable(IWL_UEFI_SGOM_NAME, &IWL_EFI_VAR_GUID,
+                                 NULL, &package_size, data);
+       if (status != EFI_SUCCESS) {
                IWL_DEBUG_FW(trans,
-                            "SGOM UEFI variable not found %d\n", err);
+                            "SGOM UEFI variable not found 0x%lx\n", status);
                goto out_free;
        }
 
@@ -349,8 +319,6 @@ void iwl_uefi_get_sgom_table(struct iwl_trans *trans,
 out_free:
        kfree(data);
 
-out:
-       kfree(sgom_efivar);
 }
 IWL_EXPORT_SYMBOL(iwl_uefi_get_sgom_table);
 #endif /* CONFIG_ACPI */
index 7e47db8..bf527b3 100644 (file)
@@ -1284,7 +1284,7 @@ static int gmin_get_config_var(struct device *maindev,
        const struct dmi_system_id *id;
        struct device *dev = maindev;
        char var8[CFG_VAR_NAME_MAX];
-       struct efivar_entry *ev;
+       efi_status_t status;
        int i, ret;
 
        /* For sensors, try first to use the _DSM table */
@@ -1326,24 +1326,11 @@ static int gmin_get_config_var(struct device *maindev,
        for (i = 0; i < sizeof(var8) && var8[i]; i++)
                var16[i] = var8[i];
 
-       /* Not sure this API usage is kosher; efivar_entry_get()'s
-        * implementation simply uses VariableName and VendorGuid from
-        * the struct and ignores the rest, but it seems like there
-        * ought to be an "official" efivar_entry registered
-        * somewhere?
-        */
-       ev = kzalloc(sizeof(*ev), GFP_KERNEL);
-       if (!ev)
-               return -ENOMEM;
-       memcpy(&ev->var.VariableName, var16, sizeof(var16));
-       ev->var.VendorGuid = GMIN_CFG_VAR_EFI_GUID;
-       ev->var.DataSize = *out_len;
-
-       ret = efivar_entry_get(ev, &ev->var.Attributes,
-                              &ev->var.DataSize, ev->var.Data);
-       if (ret == 0) {
-               memcpy(out, ev->var.Data, ev->var.DataSize);
-               *out_len = ev->var.DataSize;
+       status = EFI_UNSUPPORTED;
+       if (efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE))
+               status = efi.get_variable(var16, &GMIN_CFG_VAR_EFI_GUID, NULL,
+                                         (unsigned long *)out_len, out);
+       if (status == EFI_SUCCESS) {
                dev_info(maindev, "found EFI entry for '%s'\n", var8);
        } else if (is_gmin) {
                dev_info(maindev, "Failed to find EFI gmin variable %s\n", var8);
@@ -1351,8 +1338,6 @@ static int gmin_get_config_var(struct device *maindev,
                dev_info(maindev, "Failed to find EFI variable %s\n", var8);
        }
 
-       kfree(ev);
-
        return ret;
 }
 
index 15880a6..6780fc8 100644 (file)
@@ -155,10 +155,8 @@ static int efivarfs_callback(efi_char16_t *name16, efi_guid_t vendor,
                goto fail_inode;
        }
 
-       efivar_entry_size(entry, &size);
-       err = efivar_entry_add(entry, &efivarfs_list);
-       if (err)
-               goto fail_inode;
+       __efivar_entry_get(entry, NULL, &size, NULL);
+       __efivar_entry_add(entry, &efivarfs_list);
 
        /* copied by the above to local storage in the dentry. */
        kfree(name);
@@ -182,10 +180,7 @@ fail:
 
 static int efivarfs_destroy(struct efivar_entry *entry, void *data)
 {
-       int err = efivar_entry_remove(entry);
-
-       if (err)
-               return err;
+       efivar_entry_remove(entry);
        kfree(entry);
        return 0;
 }
@@ -221,7 +216,7 @@ static int efivarfs_fill_super(struct super_block *sb, struct fs_context *fc)
 
        err = efivar_init(efivarfs_callback, (void *)sb, true, &efivarfs_list);
        if (err)
-               __efivar_entry_iter(efivarfs_destroy, &efivarfs_list, NULL, NULL);
+               efivar_entry_iter(efivarfs_destroy, &efivarfs_list, NULL);
 
        return err;
 }
@@ -246,7 +241,7 @@ static void efivarfs_kill_sb(struct super_block *sb)
        kill_litter_super(sb);
 
        /* Remove all entries and destroy */
-       __efivar_entry_iter(efivarfs_destroy, &efivarfs_list, NULL, NULL);
+       efivar_entry_iter(efivarfs_destroy, &efivarfs_list, NULL);
 }
 
 static struct file_system_type efivarfs_type = {
index 14658b0..ffbadb8 100644 (file)
@@ -55,6 +55,7 @@ static void free_pstore_private(struct pstore_private *private)
                return;
        if (private->record) {
                kfree(private->record->buf);
+               kfree(private->record->priv);
                kfree(private->record);
        }
        kfree(private);
index 4d7fc1c..b2fd3c2 100644 (file)
@@ -808,6 +808,7 @@ void pstore_get_backend_records(struct pstore_info *psi,
                if (rc) {
                        /* pstore_mkfile() did not take record, so free it. */
                        kfree(record->buf);
+                       kfree(record->priv);
                        kfree(record);
                        if (rc != -EEXIST || !quiet)
                                failed++;
index 7d9b0bb..9ff63ac 100644 (file)
@@ -872,6 +872,7 @@ static inline bool efi_rt_services_supported(unsigned int mask)
 {
        return (efi.runtime_supported_mask & mask) == mask;
 }
+extern void efi_find_mirror(void);
 #else
 static inline bool efi_enabled(int feature)
 {
@@ -889,6 +890,8 @@ static inline bool efi_rt_services_supported(unsigned int mask)
 {
        return false;
 }
+
+static inline void efi_find_mirror(void) {}
 #endif
 
 extern int efi_status_to_err(efi_status_t status);
@@ -1040,8 +1043,6 @@ struct efivar_entry {
        struct efi_variable var;
        struct list_head list;
        struct kobject kobj;
-       bool scanning;
-       bool deleting;
 };
 
 static inline void
@@ -1061,7 +1062,8 @@ int efivar_init(int (*func)(efi_char16_t *, efi_guid_t, unsigned long, void *),
                void *data, bool duplicates, struct list_head *head);
 
 int efivar_entry_add(struct efivar_entry *entry, struct list_head *head);
-int efivar_entry_remove(struct efivar_entry *entry);
+void __efivar_entry_add(struct efivar_entry *entry, struct list_head *head);
+void efivar_entry_remove(struct efivar_entry *entry);
 
 int __efivar_entry_delete(struct efivar_entry *entry);
 int efivar_entry_delete(struct efivar_entry *entry);
@@ -1081,9 +1083,6 @@ int efivar_entry_set_safe(efi_char16_t *name, efi_guid_t vendor, u32 attributes,
 int efivar_entry_iter_begin(void);
 void efivar_entry_iter_end(void);
 
-int __efivar_entry_iter(int (*func)(struct efivar_entry *, void *),
-                       struct list_head *head, void *data,
-                       struct efivar_entry **prev);
 int efivar_entry_iter(int (*func)(struct efivar_entry *, void *),
                      struct list_head *head, void *data);
 
@@ -1095,6 +1094,26 @@ 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);
 
+int efivar_lock(void);
+int efivar_trylock(void);
+void efivar_unlock(void);
+
+efi_status_t efivar_get_variable(efi_char16_t *name, efi_guid_t *vendor,
+                                u32 *attr, unsigned long *size, void *data);
+
+efi_status_t efivar_get_next_variable(unsigned long *name_size,
+                                     efi_char16_t *name, efi_guid_t *vendor);
+
+efi_status_t efivar_set_variable_locked(efi_char16_t *name, efi_guid_t *vendor,
+                                       u32 attr, unsigned long data_size,
+                                       void *data, bool nonblocking);
+
+efi_status_t efivar_set_variable(efi_char16_t *name, efi_guid_t *vendor,
+                                u32 attr, unsigned long data_size, void *data);
+
+efi_status_t check_var_size(u32 attributes, unsigned long size);
+efi_status_t check_var_size_nonblocking(u32 attributes, unsigned long size);
+
 #if IS_ENABLED(CONFIG_EFI_CAPSULE_LOADER)
 extern bool efi_capsule_pending(int *reset_type);
 
@@ -1181,6 +1200,8 @@ static inline void efi_check_for_embedded_firmwares(void) { }
 
 efi_status_t efi_random_get_seed(void);
 
+#define arch_efi_call_virt(p, f, args...)      ((p)->f(args))
+
 /*
  * Arch code can implement the following three template macros, avoiding
  * reptition for the void/non-void return cases of {__,}efi_call_virt():
index e97a818..638507a 100644 (file)
@@ -57,6 +57,9 @@ struct pstore_info;
  * @size:      size of @buf
  * @ecc_notice_size:
  *             ECC information for @buf
+ * @priv:      pointer for backend specific use, will be
+ *             kfree()d by the pstore core if non-NULL
+ *             when the record is freed.
  *
  * Valid for PSTORE_TYPE_DMESG @type:
  *
@@ -74,6 +77,7 @@ struct pstore_record {
        char                    *buf;
        ssize_t                 size;
        ssize_t                 ecc_notice_size;
+       void                    *priv;
 
        int                     count;
        enum kmsg_dump_reason   reason;
index c0f8fbe..ddd2d6a 100644 (file)
@@ -861,4 +861,6 @@ struct folio *try_grab_folio(struct page *page, int refs, unsigned int flags);
 
 DECLARE_PER_CPU(struct per_cpu_nodestat, boot_nodestats);
 
+extern bool mirrored_kernelcore;
+
 #endif /* __MM_INTERNAL_H */
index e4f03a6..a9f18b9 100644 (file)
@@ -327,7 +327,7 @@ again:
                                            NUMA_NO_NODE, flags);
 
        if (!ret && (flags & MEMBLOCK_MIRROR)) {
-               pr_warn("Could not allocate %pap bytes of mirrored memory\n",
+               pr_warn_ratelimited("Could not allocate %pap bytes of mirrored memory\n",
                        &size);
                flags &= ~MEMBLOCK_MIRROR;
                goto again;
@@ -924,6 +924,9 @@ int __init_memblock memblock_clear_hotplug(phys_addr_t base, phys_addr_t size)
  */
 int __init_memblock memblock_mark_mirror(phys_addr_t base, phys_addr_t size)
 {
+       if (!mirrored_kernelcore)
+               return 0;
+
        system_has_some_mirror = true;
 
        return memblock_setclr_flag(base, size, 1, MEMBLOCK_MIRROR);
@@ -1384,7 +1387,7 @@ again:
 
        if (flags & MEMBLOCK_MIRROR) {
                flags &= ~MEMBLOCK_MIRROR;
-               pr_warn("Could not allocate %pap bytes of mirrored memory\n",
+               pr_warn_ratelimited("Could not allocate %pap bytes of mirrored memory\n",
                        &size);
                goto again;
        }
index b0bcab5..170bbf1 100644 (file)
@@ -356,7 +356,7 @@ static unsigned long required_kernelcore_percent __initdata;
 static unsigned long required_movablecore __initdata;
 static unsigned long required_movablecore_percent __initdata;
 static unsigned long zone_movable_pfn[MAX_NUMNODES] __initdata;
-static bool mirrored_kernelcore __meminitdata;
+bool mirrored_kernelcore __initdata_memblock;
 
 /* movable_zone is the "real" zone pages in ZONE_MOVABLE are taken from */
 int movable_zone;
index dbbd1a7..3f7e4bd 100644 (file)
@@ -536,7 +536,7 @@ void __meminit vmemmap_verify(pte_t *pte, int node,
        int actual_node = early_pfn_to_nid(pfn);
 
        if (node_distance(actual_node, node) > LOCAL_DISTANCE)
-               pr_warn("[%lx-%lx] potential offnode page_structs\n",
+               pr_warn_once("[%lx-%lx] potential offnode page_structs\n",
                        start, end - 1);
 }
 
index 0e114b3..641ef05 100755 (executable)
@@ -65,32 +65,6 @@ get_efivarfs_secureboot_mode()
        return 0;
 }
 
-get_efi_var_secureboot_mode()
-{
-       local efi_vars
-       local secure_boot_file
-       local setup_mode_file
-       local secureboot_mode
-       local setup_mode
-
-       if [ ! -d "$efi_vars" ]; then
-               log_skip "efi_vars is not enabled\n"
-       fi
-       secure_boot_file=$(find "$efi_vars" -name SecureBoot-* 2>/dev/null)
-       setup_mode_file=$(find "$efi_vars" -name SetupMode-* 2>/dev/null)
-       if [ -f "$secure_boot_file/data" ] && \
-          [ -f "$setup_mode_file/data" ]; then
-               secureboot_mode=`od -An -t u1 "$secure_boot_file/data"`
-               setup_mode=`od -An -t u1 "$setup_mode_file/data"`
-
-               if [ $secureboot_mode -eq 1 ] && [ $setup_mode -eq 0 ]; then
-                       log_info "secure boot mode enabled (CONFIG_EFI_VARS)"
-                       return 1;
-               fi
-       fi
-       return 0;
-}
-
 # On powerpc platform, check device-tree property
 # /proc/device-tree/ibm,secureboot/os-secureboot-enforcing
 # to detect secureboot state.
@@ -113,9 +87,8 @@ get_arch()
 }
 
 # Check efivar SecureBoot-$(the UUID) and SetupMode-$(the UUID).
-# The secure boot mode can be accessed either as the last integer
-# of "od -An -t u1 /sys/firmware/efi/efivars/SecureBoot-*" or from
-# "od -An -t u1 /sys/firmware/efi/vars/SecureBoot-*/data".  The efi
+# The secure boot mode can be accessed as the last integer of
+# "od -An -t u1 /sys/firmware/efi/efivars/SecureBoot-*".  The efi
 # SetupMode can be similarly accessed.
 # Return 1 for SecureBoot mode enabled and SetupMode mode disabled.
 get_secureboot_mode()
@@ -129,11 +102,6 @@ get_secureboot_mode()
        else
                get_efivarfs_secureboot_mode
                secureboot_mode=$?
-               # fallback to using the efi_var files
-               if [ $secureboot_mode -eq 0 ]; then
-                       get_efi_var_secureboot_mode
-                       secureboot_mode=$?
-               fi
        fi
 
        if [ $secureboot_mode -eq 0 ]; then