You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge branch 'next' into efi-next-merge
Conflicts: arch/x86/boot/compressed/eboot.c
This commit is contained in:
@@ -41,6 +41,28 @@ struct efi __read_mostly efi = {
|
||||
};
|
||||
EXPORT_SYMBOL(efi);
|
||||
|
||||
static bool disable_runtime;
|
||||
static int __init setup_noefi(char *arg)
|
||||
{
|
||||
disable_runtime = true;
|
||||
return 0;
|
||||
}
|
||||
early_param("noefi", setup_noefi);
|
||||
|
||||
bool efi_runtime_disabled(void)
|
||||
{
|
||||
return disable_runtime;
|
||||
}
|
||||
|
||||
static int __init parse_efi_cmdline(char *str)
|
||||
{
|
||||
if (parse_option_str(str, "noruntime"))
|
||||
disable_runtime = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
early_param("efi", parse_efi_cmdline);
|
||||
|
||||
static struct kobject *efi_kobj;
|
||||
static struct kobject *efivars_kobj;
|
||||
|
||||
@@ -423,3 +445,60 @@ int __init efi_get_fdt_params(struct efi_fdt_params *params, int verbose)
|
||||
return ret;
|
||||
}
|
||||
#endif /* CONFIG_EFI_PARAMS_FROM_FDT */
|
||||
|
||||
static __initdata char memory_type_name[][20] = {
|
||||
"Reserved",
|
||||
"Loader Code",
|
||||
"Loader Data",
|
||||
"Boot Code",
|
||||
"Boot Data",
|
||||
"Runtime Code",
|
||||
"Runtime Data",
|
||||
"Conventional Memory",
|
||||
"Unusable Memory",
|
||||
"ACPI Reclaim Memory",
|
||||
"ACPI Memory NVS",
|
||||
"Memory Mapped I/O",
|
||||
"MMIO Port Space",
|
||||
"PAL Code"
|
||||
};
|
||||
|
||||
char * __init efi_md_typeattr_format(char *buf, size_t size,
|
||||
const efi_memory_desc_t *md)
|
||||
{
|
||||
char *pos;
|
||||
int type_len;
|
||||
u64 attr;
|
||||
|
||||
pos = buf;
|
||||
if (md->type >= ARRAY_SIZE(memory_type_name))
|
||||
type_len = snprintf(pos, size, "[type=%u", md->type);
|
||||
else
|
||||
type_len = snprintf(pos, size, "[%-*s",
|
||||
(int)(sizeof(memory_type_name[0]) - 1),
|
||||
memory_type_name[md->type]);
|
||||
if (type_len >= size)
|
||||
return buf;
|
||||
|
||||
pos += type_len;
|
||||
size -= type_len;
|
||||
|
||||
attr = md->attribute;
|
||||
if (attr & ~(EFI_MEMORY_UC | EFI_MEMORY_WC | EFI_MEMORY_WT |
|
||||
EFI_MEMORY_WB | EFI_MEMORY_UCE | EFI_MEMORY_WP |
|
||||
EFI_MEMORY_RP | EFI_MEMORY_XP | EFI_MEMORY_RUNTIME))
|
||||
snprintf(pos, size, "|attr=0x%016llx]",
|
||||
(unsigned long long)attr);
|
||||
else
|
||||
snprintf(pos, size, "|%3s|%2s|%2s|%2s|%3s|%2s|%2s|%2s|%2s]",
|
||||
attr & EFI_MEMORY_RUNTIME ? "RUN" : "",
|
||||
attr & EFI_MEMORY_XP ? "XP" : "",
|
||||
attr & EFI_MEMORY_RP ? "RP" : "",
|
||||
attr & EFI_MEMORY_WP ? "WP" : "",
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -226,6 +226,10 @@ unsigned long __init efi_entry(void *handle, efi_system_table_t *sys_table,
|
||||
goto fail_free_image;
|
||||
}
|
||||
|
||||
status = efi_parse_options(cmdline_ptr);
|
||||
if (status != EFI_SUCCESS)
|
||||
pr_efi_err(sys_table, "Failed to parse EFI cmdline options\n");
|
||||
|
||||
/*
|
||||
* Unauthenticated device tree data is a security hazard, so
|
||||
* ignore 'dtb=' unless UEFI Secure Boot is disabled.
|
||||
|
||||
@@ -15,8 +15,23 @@
|
||||
|
||||
#include "efistub.h"
|
||||
|
||||
/*
|
||||
* Some firmware implementations have problems reading files in one go.
|
||||
* A read chunk size of 1MB seems to work for most platforms.
|
||||
*
|
||||
* Unfortunately, reading files in chunks triggers *other* bugs on some
|
||||
* platforms, so we provide a way to disable this workaround, which can
|
||||
* be done by passing "efi=nochunk" on the EFI boot stub command line.
|
||||
*
|
||||
* If you experience issues with initrd images being corrupt it's worth
|
||||
* trying efi=nochunk, but chunking is enabled by default because there
|
||||
* are far more machines that require the workaround than those that
|
||||
* break with it enabled.
|
||||
*/
|
||||
#define EFI_READ_CHUNK_SIZE (1024 * 1024)
|
||||
|
||||
static unsigned long __chunk_size = EFI_READ_CHUNK_SIZE;
|
||||
|
||||
struct file_info {
|
||||
efi_file_handle_t *handle;
|
||||
u64 size;
|
||||
@@ -281,6 +296,49 @@ void efi_free(efi_system_table_t *sys_table_arg, unsigned long size,
|
||||
efi_call_early(free_pages, addr, nr_pages);
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse the ASCII string 'cmdline' for EFI options, denoted by the efi=
|
||||
* option, e.g. efi=nochunk.
|
||||
*
|
||||
* It should be noted that efi= is parsed in two very different
|
||||
* environments, first in the early boot environment of the EFI boot
|
||||
* stub, and subsequently during the kernel boot.
|
||||
*/
|
||||
efi_status_t efi_parse_options(char *cmdline)
|
||||
{
|
||||
char *str;
|
||||
|
||||
/*
|
||||
* If no EFI parameters were specified on the cmdline we've got
|
||||
* nothing to do.
|
||||
*/
|
||||
str = strstr(cmdline, "efi=");
|
||||
if (!str)
|
||||
return EFI_SUCCESS;
|
||||
|
||||
/* Skip ahead to first argument */
|
||||
str += strlen("efi=");
|
||||
|
||||
/*
|
||||
* Remember, because efi= is also used by the kernel we need to
|
||||
* skip over arguments we don't understand.
|
||||
*/
|
||||
while (*str) {
|
||||
if (!strncmp(str, "nochunk", 7)) {
|
||||
str += strlen("nochunk");
|
||||
__chunk_size = -1UL;
|
||||
}
|
||||
|
||||
/* Group words together, delimited by "," */
|
||||
while (*str && *str != ',')
|
||||
str++;
|
||||
|
||||
if (*str == ',')
|
||||
str++;
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check the cmdline for a LILO-style file= arguments.
|
||||
@@ -423,8 +481,8 @@ efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg,
|
||||
size = files[j].size;
|
||||
while (size) {
|
||||
unsigned long chunksize;
|
||||
if (size > EFI_READ_CHUNK_SIZE)
|
||||
chunksize = EFI_READ_CHUNK_SIZE;
|
||||
if (size > __chunk_size)
|
||||
chunksize = __chunk_size;
|
||||
else
|
||||
chunksize = size;
|
||||
|
||||
|
||||
@@ -14,10 +14,79 @@
|
||||
* This file is released under the GPLv2.
|
||||
*/
|
||||
|
||||
#include <linux/bug.h>
|
||||
#include <linux/efi.h>
|
||||
#include <linux/spinlock.h> /* spinlock_t */
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <asm/efi.h>
|
||||
|
||||
/*
|
||||
* According to section 7.1 of the UEFI spec, Runtime Services are not fully
|
||||
* reentrant, and there are particular combinations of calls that need to be
|
||||
* serialized. (source: UEFI Specification v2.4A)
|
||||
*
|
||||
* Table 31. Rules for Reentry Into Runtime Services
|
||||
* +------------------------------------+-------------------------------+
|
||||
* | If previous call is busy in | Forbidden to call |
|
||||
* +------------------------------------+-------------------------------+
|
||||
* | Any | SetVirtualAddressMap() |
|
||||
* +------------------------------------+-------------------------------+
|
||||
* | ConvertPointer() | ConvertPointer() |
|
||||
* +------------------------------------+-------------------------------+
|
||||
* | SetVariable() | ResetSystem() |
|
||||
* | UpdateCapsule() | |
|
||||
* | SetTime() | |
|
||||
* | SetWakeupTime() | |
|
||||
* | GetNextHighMonotonicCount() | |
|
||||
* +------------------------------------+-------------------------------+
|
||||
* | GetVariable() | GetVariable() |
|
||||
* | GetNextVariableName() | GetNextVariableName() |
|
||||
* | SetVariable() | SetVariable() |
|
||||
* | QueryVariableInfo() | QueryVariableInfo() |
|
||||
* | UpdateCapsule() | UpdateCapsule() |
|
||||
* | QueryCapsuleCapabilities() | QueryCapsuleCapabilities() |
|
||||
* | GetNextHighMonotonicCount() | GetNextHighMonotonicCount() |
|
||||
* +------------------------------------+-------------------------------+
|
||||
* | GetTime() | GetTime() |
|
||||
* | SetTime() | SetTime() |
|
||||
* | GetWakeupTime() | GetWakeupTime() |
|
||||
* | SetWakeupTime() | SetWakeupTime() |
|
||||
* +------------------------------------+-------------------------------+
|
||||
*
|
||||
* Due to the fact that the EFI pstore may write to the variable store in
|
||||
* interrupt context, we need to use a spinlock for at least the groups that
|
||||
* contain SetVariable() and QueryVariableInfo(). That leaves little else, as
|
||||
* none of the remaining functions are actually ever called at runtime.
|
||||
* So let's just use a single spinlock to serialize all Runtime Services calls.
|
||||
*/
|
||||
static DEFINE_SPINLOCK(efi_runtime_lock);
|
||||
|
||||
/*
|
||||
* Some runtime services calls can be reentrant under NMI, even if the table
|
||||
* above says they are not. (source: UEFI Specification v2.4A)
|
||||
*
|
||||
* Table 32. Functions that may be called after Machine Check, INIT and NMI
|
||||
* +----------------------------+------------------------------------------+
|
||||
* | Function | Called after Machine Check, INIT and NMI |
|
||||
* +----------------------------+------------------------------------------+
|
||||
* | GetTime() | Yes, even if previously busy. |
|
||||
* | GetVariable() | Yes, even if previously busy |
|
||||
* | GetNextVariableName() | Yes, even if previously busy |
|
||||
* | QueryVariableInfo() | Yes, even if previously busy |
|
||||
* | SetVariable() | Yes, even if previously busy |
|
||||
* | UpdateCapsule() | Yes, even if previously busy |
|
||||
* | QueryCapsuleCapabilities() | Yes, even if previously busy |
|
||||
* | ResetSystem() | Yes, even if previously busy |
|
||||
* +----------------------------+------------------------------------------+
|
||||
*
|
||||
* In order to prevent deadlocks under NMI, the wrappers for these functions
|
||||
* may only grab the efi_runtime_lock or rtc_lock spinlocks if !efi_in_nmi().
|
||||
* However, not all of the services listed are reachable through NMI code paths,
|
||||
* so the the special handling as suggested by the UEFI spec is only implemented
|
||||
* for QueryVariableInfo() and SetVariable(), as these can be reached in NMI
|
||||
* context through efi_pstore_write().
|
||||
*/
|
||||
|
||||
/*
|
||||
* As per commit ef68c8f87ed1 ("x86: Serialize EFI time accesses on rtc_lock"),
|
||||
* the EFI specification requires that callers of the time related runtime
|
||||
@@ -32,7 +101,9 @@ static efi_status_t virt_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc)
|
||||
efi_status_t status;
|
||||
|
||||
spin_lock_irqsave(&rtc_lock, flags);
|
||||
spin_lock(&efi_runtime_lock);
|
||||
status = efi_call_virt(get_time, tm, tc);
|
||||
spin_unlock(&efi_runtime_lock);
|
||||
spin_unlock_irqrestore(&rtc_lock, flags);
|
||||
return status;
|
||||
}
|
||||
@@ -43,7 +114,9 @@ static efi_status_t virt_efi_set_time(efi_time_t *tm)
|
||||
efi_status_t status;
|
||||
|
||||
spin_lock_irqsave(&rtc_lock, flags);
|
||||
spin_lock(&efi_runtime_lock);
|
||||
status = efi_call_virt(set_time, tm);
|
||||
spin_unlock(&efi_runtime_lock);
|
||||
spin_unlock_irqrestore(&rtc_lock, flags);
|
||||
return status;
|
||||
}
|
||||
@@ -56,7 +129,9 @@ static efi_status_t virt_efi_get_wakeup_time(efi_bool_t *enabled,
|
||||
efi_status_t status;
|
||||
|
||||
spin_lock_irqsave(&rtc_lock, flags);
|
||||
spin_lock(&efi_runtime_lock);
|
||||
status = efi_call_virt(get_wakeup_time, enabled, pending, tm);
|
||||
spin_unlock(&efi_runtime_lock);
|
||||
spin_unlock_irqrestore(&rtc_lock, flags);
|
||||
return status;
|
||||
}
|
||||
@@ -67,7 +142,9 @@ static efi_status_t virt_efi_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm)
|
||||
efi_status_t status;
|
||||
|
||||
spin_lock_irqsave(&rtc_lock, flags);
|
||||
spin_lock(&efi_runtime_lock);
|
||||
status = efi_call_virt(set_wakeup_time, enabled, tm);
|
||||
spin_unlock(&efi_runtime_lock);
|
||||
spin_unlock_irqrestore(&rtc_lock, flags);
|
||||
return status;
|
||||
}
|
||||
@@ -78,14 +155,27 @@ static efi_status_t virt_efi_get_variable(efi_char16_t *name,
|
||||
unsigned long *data_size,
|
||||
void *data)
|
||||
{
|
||||
return efi_call_virt(get_variable, name, vendor, attr, data_size, data);
|
||||
unsigned long flags;
|
||||
efi_status_t status;
|
||||
|
||||
spin_lock_irqsave(&efi_runtime_lock, flags);
|
||||
status = efi_call_virt(get_variable, name, vendor, attr, data_size,
|
||||
data);
|
||||
spin_unlock_irqrestore(&efi_runtime_lock, flags);
|
||||
return status;
|
||||
}
|
||||
|
||||
static efi_status_t virt_efi_get_next_variable(unsigned long *name_size,
|
||||
efi_char16_t *name,
|
||||
efi_guid_t *vendor)
|
||||
{
|
||||
return efi_call_virt(get_next_variable, name_size, name, vendor);
|
||||
unsigned long flags;
|
||||
efi_status_t status;
|
||||
|
||||
spin_lock_irqsave(&efi_runtime_lock, flags);
|
||||
status = efi_call_virt(get_next_variable, name_size, name, vendor);
|
||||
spin_unlock_irqrestore(&efi_runtime_lock, flags);
|
||||
return status;
|
||||
}
|
||||
|
||||
static efi_status_t virt_efi_set_variable(efi_char16_t *name,
|
||||
@@ -94,24 +184,61 @@ static efi_status_t virt_efi_set_variable(efi_char16_t *name,
|
||||
unsigned long data_size,
|
||||
void *data)
|
||||
{
|
||||
return efi_call_virt(set_variable, name, vendor, attr, data_size, data);
|
||||
unsigned long flags;
|
||||
efi_status_t status;
|
||||
|
||||
spin_lock_irqsave(&efi_runtime_lock, flags);
|
||||
status = efi_call_virt(set_variable, name, vendor, attr, data_size,
|
||||
data);
|
||||
spin_unlock_irqrestore(&efi_runtime_lock, flags);
|
||||
return status;
|
||||
}
|
||||
|
||||
static efi_status_t
|
||||
virt_efi_set_variable_nonblocking(efi_char16_t *name, efi_guid_t *vendor,
|
||||
u32 attr, unsigned long data_size,
|
||||
void *data)
|
||||
{
|
||||
unsigned long flags;
|
||||
efi_status_t status;
|
||||
|
||||
if (!spin_trylock_irqsave(&efi_runtime_lock, flags))
|
||||
return EFI_NOT_READY;
|
||||
|
||||
status = efi_call_virt(set_variable, name, vendor, attr, data_size,
|
||||
data);
|
||||
spin_unlock_irqrestore(&efi_runtime_lock, flags);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
static efi_status_t virt_efi_query_variable_info(u32 attr,
|
||||
u64 *storage_space,
|
||||
u64 *remaining_space,
|
||||
u64 *max_variable_size)
|
||||
{
|
||||
unsigned long flags;
|
||||
efi_status_t status;
|
||||
|
||||
if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION)
|
||||
return EFI_UNSUPPORTED;
|
||||
|
||||
return efi_call_virt(query_variable_info, attr, storage_space,
|
||||
remaining_space, max_variable_size);
|
||||
spin_lock_irqsave(&efi_runtime_lock, flags);
|
||||
status = efi_call_virt(query_variable_info, attr, storage_space,
|
||||
remaining_space, max_variable_size);
|
||||
spin_unlock_irqrestore(&efi_runtime_lock, flags);
|
||||
return status;
|
||||
}
|
||||
|
||||
static efi_status_t virt_efi_get_next_high_mono_count(u32 *count)
|
||||
{
|
||||
return efi_call_virt(get_next_high_mono_count, count);
|
||||
unsigned long flags;
|
||||
efi_status_t status;
|
||||
|
||||
spin_lock_irqsave(&efi_runtime_lock, flags);
|
||||
status = efi_call_virt(get_next_high_mono_count, count);
|
||||
spin_unlock_irqrestore(&efi_runtime_lock, flags);
|
||||
return status;
|
||||
}
|
||||
|
||||
static void virt_efi_reset_system(int reset_type,
|
||||
@@ -119,17 +246,27 @@ static void virt_efi_reset_system(int reset_type,
|
||||
unsigned long data_size,
|
||||
efi_char16_t *data)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&efi_runtime_lock, flags);
|
||||
__efi_call_virt(reset_system, reset_type, status, data_size, data);
|
||||
spin_unlock_irqrestore(&efi_runtime_lock, flags);
|
||||
}
|
||||
|
||||
static efi_status_t virt_efi_update_capsule(efi_capsule_header_t **capsules,
|
||||
unsigned long count,
|
||||
unsigned long sg_list)
|
||||
{
|
||||
unsigned long flags;
|
||||
efi_status_t status;
|
||||
|
||||
if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION)
|
||||
return EFI_UNSUPPORTED;
|
||||
|
||||
return efi_call_virt(update_capsule, capsules, count, sg_list);
|
||||
spin_lock_irqsave(&efi_runtime_lock, flags);
|
||||
status = efi_call_virt(update_capsule, capsules, count, sg_list);
|
||||
spin_unlock_irqrestore(&efi_runtime_lock, flags);
|
||||
return status;
|
||||
}
|
||||
|
||||
static efi_status_t virt_efi_query_capsule_caps(efi_capsule_header_t **capsules,
|
||||
@@ -137,11 +274,17 @@ static efi_status_t virt_efi_query_capsule_caps(efi_capsule_header_t **capsules,
|
||||
u64 *max_size,
|
||||
int *reset_type)
|
||||
{
|
||||
unsigned long flags;
|
||||
efi_status_t status;
|
||||
|
||||
if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION)
|
||||
return EFI_UNSUPPORTED;
|
||||
|
||||
return efi_call_virt(query_capsule_caps, capsules, count, max_size,
|
||||
reset_type);
|
||||
spin_lock_irqsave(&efi_runtime_lock, flags);
|
||||
status = efi_call_virt(query_capsule_caps, capsules, count, max_size,
|
||||
reset_type);
|
||||
spin_unlock_irqrestore(&efi_runtime_lock, flags);
|
||||
return status;
|
||||
}
|
||||
|
||||
void efi_native_runtime_setup(void)
|
||||
@@ -153,6 +296,7 @@ void efi_native_runtime_setup(void)
|
||||
efi.get_variable = virt_efi_get_variable;
|
||||
efi.get_next_variable = virt_efi_get_next_variable;
|
||||
efi.set_variable = virt_efi_set_variable;
|
||||
efi.set_variable_nonblocking = virt_efi_set_variable_nonblocking;
|
||||
efi.get_next_high_mono_count = virt_efi_get_next_high_mono_count;
|
||||
efi.reset_system = virt_efi_reset_system;
|
||||
efi.query_variable_info = virt_efi_query_variable_info;
|
||||
|
||||
@@ -321,11 +321,11 @@ static unsigned long var_name_strnsize(efi_char16_t *variable_name,
|
||||
* Print a warning when duplicate EFI variables are encountered and
|
||||
* disable the sysfs workqueue since the firmware is buggy.
|
||||
*/
|
||||
static void dup_variable_bug(efi_char16_t *s16, efi_guid_t *vendor_guid,
|
||||
static void dup_variable_bug(efi_char16_t *str16, efi_guid_t *vendor_guid,
|
||||
unsigned long len16)
|
||||
{
|
||||
size_t i, len8 = len16 / sizeof(efi_char16_t);
|
||||
char *s8;
|
||||
char *str8;
|
||||
|
||||
/*
|
||||
* Disable the workqueue since the algorithm it uses for
|
||||
@@ -334,16 +334,16 @@ static void dup_variable_bug(efi_char16_t *s16, efi_guid_t *vendor_guid,
|
||||
*/
|
||||
efivar_wq_enabled = false;
|
||||
|
||||
s8 = kzalloc(len8, GFP_KERNEL);
|
||||
if (!s8)
|
||||
str8 = kzalloc(len8, GFP_KERNEL);
|
||||
if (!str8)
|
||||
return;
|
||||
|
||||
for (i = 0; i < len8; i++)
|
||||
s8[i] = s16[i];
|
||||
str8[i] = str16[i];
|
||||
|
||||
printk(KERN_WARNING "efivars: duplicate variable: %s-%pUl\n",
|
||||
s8, vendor_guid);
|
||||
kfree(s8);
|
||||
str8, vendor_guid);
|
||||
kfree(str8);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -595,6 +595,39 @@ int efivar_entry_set(struct efivar_entry *entry, u32 attributes,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(efivar_entry_set);
|
||||
|
||||
/*
|
||||
* efivar_entry_set_nonblocking - call set_variable_nonblocking()
|
||||
*
|
||||
* This function is guaranteed to not block and is suitable for calling
|
||||
* from crash/panic handlers.
|
||||
*
|
||||
* Crucially, this function will not block if it cannot acquire
|
||||
* __efivars->lock. Instead, it returns -EBUSY.
|
||||
*/
|
||||
static int
|
||||
efivar_entry_set_nonblocking(efi_char16_t *name, efi_guid_t vendor,
|
||||
u32 attributes, unsigned long size, void *data)
|
||||
{
|
||||
const struct efivar_operations *ops = __efivars->ops;
|
||||
unsigned long flags;
|
||||
efi_status_t status;
|
||||
|
||||
if (!spin_trylock_irqsave(&__efivars->lock, flags))
|
||||
return -EBUSY;
|
||||
|
||||
status = check_var_size(attributes, size + ucs2_strsize(name, 1024));
|
||||
if (status != EFI_SUCCESS) {
|
||||
spin_unlock_irqrestore(&__efivars->lock, flags);
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
status = ops->set_variable_nonblocking(name, &vendor, attributes,
|
||||
size, data);
|
||||
|
||||
spin_unlock_irqrestore(&__efivars->lock, flags);
|
||||
return efi_status_to_err(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* efivar_entry_set_safe - call set_variable() if enough space in firmware
|
||||
* @name: buffer containing the variable name
|
||||
@@ -622,6 +655,20 @@ int efivar_entry_set_safe(efi_char16_t *name, efi_guid_t vendor, u32 attributes,
|
||||
if (!ops->query_variable_store)
|
||||
return -ENOSYS;
|
||||
|
||||
/*
|
||||
* If the EFI variable backend provides a non-blocking
|
||||
* ->set_variable() operation and we're in a context where we
|
||||
* cannot block, then we need to use it to avoid live-locks,
|
||||
* since the implication is that the regular ->set_variable()
|
||||
* will block.
|
||||
*
|
||||
* If no ->set_variable_nonblocking() is provided then
|
||||
* ->set_variable() is assumed to be non-blocking.
|
||||
*/
|
||||
if (!block && ops->set_variable_nonblocking)
|
||||
return efivar_entry_set_nonblocking(name, vendor, attributes,
|
||||
size, data);
|
||||
|
||||
if (!block) {
|
||||
if (!spin_trylock_irqsave(&__efivars->lock, flags))
|
||||
return -EBUSY;
|
||||
|
||||
Reference in New Issue
Block a user