Commit 40043927 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'efi-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull EFI updates from Thomas Gleixner:
 "The EFI pile:

   - Make mixed mode UEFI runtime service invocations mutually
     exclusive, as mandated by the UEFI spec

   - Perform UEFI runtime services calls from a work queue so the calls
     into the firmware occur from a kernel thread

   - Honor the UEFI memory map attributes for live memory regions
     configured by UEFI as a framebuffer. This works around a coherency
     problem with KVM guests running on ARM.

   - Cleanups, improvements and fixes all over the place"

* 'efi-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  efivars: Call guid_parse() against guid_t type of variable
  efi/cper: Use consistent types for UUIDs
  efi/x86: Replace references to efi_early->is64 with efi_is_64bit()
  efi: Deduplicate efi_open_volume()
  efi/x86: Add missing NULL initialization in UGA draw protocol discovery
  efi/x86: Merge 32-bit and 64-bit UGA draw protocol setup routines
  efi/x86: Align efi_uga_draw_protocol typedef names to convention
  efi/x86: Merge the setup_efi_pci32() and setup_efi_pci64() routines
  efi/x86: Prevent reentrant firmware calls in mixed mode
  efi/esrt: Only call efi_mem_reserve() for boot services memory
  fbdev/efifb: Honour UEFI memory map attributes when mapping the FB
  efi: Drop type and attribute checks in efi_mem_desc_lookup()
  efi/libstub/arm: Add opt-in Kconfig option for the DTB loader
  efi: Remove the declaration of efi_late_init() as the function is unused
  efi/cper: Avoid using get_seconds()
  efi: Use a work queue to invoke EFI Runtime Services
  efi/x86: Use non-blocking SetVariable() for efi_delete_dummy_variable()
  efi/x86: Clean up the eboot code
parents 0ad6b38a c4326563
...@@ -58,6 +58,9 @@ void efi_virtmap_unload(void); ...@@ -58,6 +58,9 @@ void efi_virtmap_unload(void);
#define efi_call_runtime(f, ...) sys_table_arg->runtime->f(__VA_ARGS__) #define efi_call_runtime(f, ...) sys_table_arg->runtime->f(__VA_ARGS__)
#define efi_is_64bit() (false) #define efi_is_64bit() (false)
#define efi_table_attr(table, attr, instance) \
((table##_t *)instance)->attr
#define efi_call_proto(protocol, f, instance, ...) \ #define efi_call_proto(protocol, f, instance, ...) \
((protocol##_t *)instance)->f(instance, ##__VA_ARGS__) ((protocol##_t *)instance)->f(instance, ##__VA_ARGS__)
......
...@@ -87,6 +87,9 @@ static inline unsigned long efi_get_max_initrd_addr(unsigned long dram_base, ...@@ -87,6 +87,9 @@ static inline unsigned long efi_get_max_initrd_addr(unsigned long dram_base,
#define efi_call_runtime(f, ...) sys_table_arg->runtime->f(__VA_ARGS__) #define efi_call_runtime(f, ...) sys_table_arg->runtime->f(__VA_ARGS__)
#define efi_is_64bit() (true) #define efi_is_64bit() (true)
#define efi_table_attr(table, attr, instance) \
((table##_t *)instance)->attr
#define efi_call_proto(protocol, f, instance, ...) \ #define efi_call_proto(protocol, f, instance, ...) \
((protocol##_t *)instance)->f(instance, ##__VA_ARGS__) ((protocol##_t *)instance)->f(instance, ##__VA_ARGS__)
......
This diff is collapsed.
...@@ -12,22 +12,22 @@ ...@@ -12,22 +12,22 @@
#define DESC_TYPE_CODE_DATA (1 << 0) #define DESC_TYPE_CODE_DATA (1 << 0)
struct efi_uga_draw_protocol_32 { typedef struct {
u32 get_mode; u32 get_mode;
u32 set_mode; u32 set_mode;
u32 blt; u32 blt;
}; } efi_uga_draw_protocol_32_t;
struct efi_uga_draw_protocol_64 { typedef struct {
u64 get_mode; u64 get_mode;
u64 set_mode; u64 set_mode;
u64 blt; u64 blt;
}; } efi_uga_draw_protocol_64_t;
struct efi_uga_draw_protocol { typedef struct {
void *get_mode; void *get_mode;
void *set_mode; void *set_mode;
void *blt; void *blt;
}; } efi_uga_draw_protocol_t;
#endif /* BOOT_COMPRESSED_EBOOT_H */ #endif /* BOOT_COMPRESSED_EBOOT_H */
...@@ -636,6 +636,8 @@ void efi_switch_mm(struct mm_struct *mm) ...@@ -636,6 +636,8 @@ void efi_switch_mm(struct mm_struct *mm)
#ifdef CONFIG_EFI_MIXED #ifdef CONFIG_EFI_MIXED
extern efi_status_t efi64_thunk(u32, ...); extern efi_status_t efi64_thunk(u32, ...);
static DEFINE_SPINLOCK(efi_runtime_lock);
#define runtime_service32(func) \ #define runtime_service32(func) \
({ \ ({ \
u32 table = (u32)(unsigned long)efi.systab; \ u32 table = (u32)(unsigned long)efi.systab; \
...@@ -657,17 +659,14 @@ extern efi_status_t efi64_thunk(u32, ...); ...@@ -657,17 +659,14 @@ extern efi_status_t efi64_thunk(u32, ...);
#define efi_thunk(f, ...) \ #define efi_thunk(f, ...) \
({ \ ({ \
efi_status_t __s; \ efi_status_t __s; \
unsigned long __flags; \
u32 __func; \ u32 __func; \
\ \
local_irq_save(__flags); \
arch_efi_call_virt_setup(); \ arch_efi_call_virt_setup(); \
\ \
__func = runtime_service32(f); \ __func = runtime_service32(f); \
__s = efi64_thunk(__func, __VA_ARGS__); \ __s = efi64_thunk(__func, __VA_ARGS__); \
\ \
arch_efi_call_virt_teardown(); \ arch_efi_call_virt_teardown(); \
local_irq_restore(__flags); \
\ \
__s; \ __s; \
}) })
...@@ -702,14 +701,17 @@ static efi_status_t efi_thunk_get_time(efi_time_t *tm, efi_time_cap_t *tc) ...@@ -702,14 +701,17 @@ static efi_status_t efi_thunk_get_time(efi_time_t *tm, efi_time_cap_t *tc)
{ {
efi_status_t status; efi_status_t status;
u32 phys_tm, phys_tc; u32 phys_tm, phys_tc;
unsigned long flags;
spin_lock(&rtc_lock); spin_lock(&rtc_lock);
spin_lock_irqsave(&efi_runtime_lock, flags);
phys_tm = virt_to_phys_or_null(tm); phys_tm = virt_to_phys_or_null(tm);
phys_tc = virt_to_phys_or_null(tc); phys_tc = virt_to_phys_or_null(tc);
status = efi_thunk(get_time, phys_tm, phys_tc); status = efi_thunk(get_time, phys_tm, phys_tc);
spin_unlock_irqrestore(&efi_runtime_lock, flags);
spin_unlock(&rtc_lock); spin_unlock(&rtc_lock);
return status; return status;
...@@ -719,13 +721,16 @@ static efi_status_t efi_thunk_set_time(efi_time_t *tm) ...@@ -719,13 +721,16 @@ static efi_status_t efi_thunk_set_time(efi_time_t *tm)
{ {
efi_status_t status; efi_status_t status;
u32 phys_tm; u32 phys_tm;
unsigned long flags;
spin_lock(&rtc_lock); spin_lock(&rtc_lock);
spin_lock_irqsave(&efi_runtime_lock, flags);
phys_tm = virt_to_phys_or_null(tm); phys_tm = virt_to_phys_or_null(tm);
status = efi_thunk(set_time, phys_tm); status = efi_thunk(set_time, phys_tm);
spin_unlock_irqrestore(&efi_runtime_lock, flags);
spin_unlock(&rtc_lock); spin_unlock(&rtc_lock);
return status; return status;
...@@ -737,8 +742,10 @@ efi_thunk_get_wakeup_time(efi_bool_t *enabled, efi_bool_t *pending, ...@@ -737,8 +742,10 @@ efi_thunk_get_wakeup_time(efi_bool_t *enabled, efi_bool_t *pending,
{ {
efi_status_t status; efi_status_t status;
u32 phys_enabled, phys_pending, phys_tm; u32 phys_enabled, phys_pending, phys_tm;
unsigned long flags;
spin_lock(&rtc_lock); spin_lock(&rtc_lock);
spin_lock_irqsave(&efi_runtime_lock, flags);
phys_enabled = virt_to_phys_or_null(enabled); phys_enabled = virt_to_phys_or_null(enabled);
phys_pending = virt_to_phys_or_null(pending); phys_pending = virt_to_phys_or_null(pending);
...@@ -747,6 +754,7 @@ efi_thunk_get_wakeup_time(efi_bool_t *enabled, efi_bool_t *pending, ...@@ -747,6 +754,7 @@ efi_thunk_get_wakeup_time(efi_bool_t *enabled, efi_bool_t *pending,
status = efi_thunk(get_wakeup_time, phys_enabled, status = efi_thunk(get_wakeup_time, phys_enabled,
phys_pending, phys_tm); phys_pending, phys_tm);
spin_unlock_irqrestore(&efi_runtime_lock, flags);
spin_unlock(&rtc_lock); spin_unlock(&rtc_lock);
return status; return status;
...@@ -757,13 +765,16 @@ efi_thunk_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm) ...@@ -757,13 +765,16 @@ efi_thunk_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm)
{ {
efi_status_t status; efi_status_t status;
u32 phys_tm; u32 phys_tm;
unsigned long flags;
spin_lock(&rtc_lock); spin_lock(&rtc_lock);
spin_lock_irqsave(&efi_runtime_lock, flags);
phys_tm = virt_to_phys_or_null(tm); phys_tm = virt_to_phys_or_null(tm);
status = efi_thunk(set_wakeup_time, enabled, phys_tm); status = efi_thunk(set_wakeup_time, enabled, phys_tm);
spin_unlock_irqrestore(&efi_runtime_lock, flags);
spin_unlock(&rtc_lock); spin_unlock(&rtc_lock);
return status; return status;
...@@ -781,6 +792,9 @@ efi_thunk_get_variable(efi_char16_t *name, efi_guid_t *vendor, ...@@ -781,6 +792,9 @@ efi_thunk_get_variable(efi_char16_t *name, efi_guid_t *vendor,
efi_status_t status; efi_status_t status;
u32 phys_name, phys_vendor, phys_attr; u32 phys_name, phys_vendor, phys_attr;
u32 phys_data_size, phys_data; u32 phys_data_size, phys_data;
unsigned long flags;
spin_lock_irqsave(&efi_runtime_lock, flags);
phys_data_size = virt_to_phys_or_null(data_size); phys_data_size = virt_to_phys_or_null(data_size);
phys_vendor = virt_to_phys_or_null(vendor); phys_vendor = virt_to_phys_or_null(vendor);
...@@ -791,6 +805,8 @@ efi_thunk_get_variable(efi_char16_t *name, efi_guid_t *vendor, ...@@ -791,6 +805,8 @@ efi_thunk_get_variable(efi_char16_t *name, efi_guid_t *vendor,
status = efi_thunk(get_variable, phys_name, phys_vendor, status = efi_thunk(get_variable, phys_name, phys_vendor,
phys_attr, phys_data_size, phys_data); phys_attr, phys_data_size, phys_data);
spin_unlock_irqrestore(&efi_runtime_lock, flags);
return status; return status;
} }
...@@ -800,6 +816,9 @@ efi_thunk_set_variable(efi_char16_t *name, efi_guid_t *vendor, ...@@ -800,6 +816,9 @@ efi_thunk_set_variable(efi_char16_t *name, efi_guid_t *vendor,
{ {
u32 phys_name, phys_vendor, phys_data; u32 phys_name, phys_vendor, phys_data;
efi_status_t status; efi_status_t status;
unsigned long flags;
spin_lock_irqsave(&efi_runtime_lock, flags);
phys_name = virt_to_phys_or_null_size(name, efi_name_size(name)); phys_name = virt_to_phys_or_null_size(name, efi_name_size(name));
phys_vendor = virt_to_phys_or_null(vendor); phys_vendor = virt_to_phys_or_null(vendor);
...@@ -809,6 +828,33 @@ efi_thunk_set_variable(efi_char16_t *name, efi_guid_t *vendor, ...@@ -809,6 +828,33 @@ efi_thunk_set_variable(efi_char16_t *name, efi_guid_t *vendor,
status = efi_thunk(set_variable, phys_name, phys_vendor, status = efi_thunk(set_variable, phys_name, phys_vendor,
attr, data_size, phys_data); attr, data_size, phys_data);
spin_unlock_irqrestore(&efi_runtime_lock, flags);
return status;
}
static efi_status_t
efi_thunk_set_variable_nonblocking(efi_char16_t *name, efi_guid_t *vendor,
u32 attr, unsigned long data_size,
void *data)
{
u32 phys_name, phys_vendor, phys_data;
efi_status_t status;
unsigned long flags;
if (!spin_trylock_irqsave(&efi_runtime_lock, flags))
return EFI_NOT_READY;
phys_name = virt_to_phys_or_null_size(name, efi_name_size(name));
phys_vendor = virt_to_phys_or_null(vendor);
phys_data = virt_to_phys_or_null_size(data, data_size);
/* If data_size is > sizeof(u32) we've got problems */
status = efi_thunk(set_variable, phys_name, phys_vendor,
attr, data_size, phys_data);
spin_unlock_irqrestore(&efi_runtime_lock, flags);
return status; return status;
} }
...@@ -819,6 +865,9 @@ efi_thunk_get_next_variable(unsigned long *name_size, ...@@ -819,6 +865,9 @@ efi_thunk_get_next_variable(unsigned long *name_size,
{ {
efi_status_t status; efi_status_t status;
u32 phys_name_size, phys_name, phys_vendor; u32 phys_name_size, phys_name, phys_vendor;
unsigned long flags;
spin_lock_irqsave(&efi_runtime_lock, flags);
phys_name_size = virt_to_phys_or_null(name_size); phys_name_size = virt_to_phys_or_null(name_size);
phys_vendor = virt_to_phys_or_null(vendor); phys_vendor = virt_to_phys_or_null(vendor);
...@@ -827,6 +876,8 @@ efi_thunk_get_next_variable(unsigned long *name_size, ...@@ -827,6 +876,8 @@ efi_thunk_get_next_variable(unsigned long *name_size,
status = efi_thunk(get_next_variable, phys_name_size, status = efi_thunk(get_next_variable, phys_name_size,
phys_name, phys_vendor); phys_name, phys_vendor);
spin_unlock_irqrestore(&efi_runtime_lock, flags);
return status; return status;
} }
...@@ -835,10 +886,15 @@ efi_thunk_get_next_high_mono_count(u32 *count) ...@@ -835,10 +886,15 @@ efi_thunk_get_next_high_mono_count(u32 *count)
{ {
efi_status_t status; efi_status_t status;
u32 phys_count; u32 phys_count;
unsigned long flags;
spin_lock_irqsave(&efi_runtime_lock, flags);
phys_count = virt_to_phys_or_null(count); phys_count = virt_to_phys_or_null(count);
status = efi_thunk(get_next_high_mono_count, phys_count); status = efi_thunk(get_next_high_mono_count, phys_count);
spin_unlock_irqrestore(&efi_runtime_lock, flags);
return status; return status;
} }
...@@ -847,10 +903,15 @@ efi_thunk_reset_system(int reset_type, efi_status_t status, ...@@ -847,10 +903,15 @@ efi_thunk_reset_system(int reset_type, efi_status_t status,
unsigned long data_size, efi_char16_t *data) unsigned long data_size, efi_char16_t *data)
{ {
u32 phys_data; u32 phys_data;
unsigned long flags;
spin_lock_irqsave(&efi_runtime_lock, flags);
phys_data = virt_to_phys_or_null_size(data, data_size); phys_data = virt_to_phys_or_null_size(data, data_size);
efi_thunk(reset_system, reset_type, status, data_size, phys_data); efi_thunk(reset_system, reset_type, status, data_size, phys_data);
spin_unlock_irqrestore(&efi_runtime_lock, flags);
} }
static efi_status_t static efi_status_t
...@@ -872,10 +933,40 @@ efi_thunk_query_variable_info(u32 attr, u64 *storage_space, ...@@ -872,10 +933,40 @@ efi_thunk_query_variable_info(u32 attr, u64 *storage_space,
{ {
efi_status_t status; efi_status_t status;
u32 phys_storage, phys_remaining, phys_max; u32 phys_storage, phys_remaining, phys_max;
unsigned long flags;
if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION)
return EFI_UNSUPPORTED;
spin_lock_irqsave(&efi_runtime_lock, flags);
phys_storage = virt_to_phys_or_null(storage_space);
phys_remaining = virt_to_phys_or_null(remaining_space);
phys_max = virt_to_phys_or_null(max_variable_size);
status = efi_thunk(query_variable_info, attr, phys_storage,
phys_remaining, phys_max);
spin_unlock_irqrestore(&efi_runtime_lock, flags);
return status;
}
static efi_status_t
efi_thunk_query_variable_info_nonblocking(u32 attr, u64 *storage_space,
u64 *remaining_space,
u64 *max_variable_size)
{
efi_status_t status;
u32 phys_storage, phys_remaining, phys_max;
unsigned long flags;
if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION)
return EFI_UNSUPPORTED; return EFI_UNSUPPORTED;
if (!spin_trylock_irqsave(&efi_runtime_lock, flags))
return EFI_NOT_READY;
phys_storage = virt_to_phys_or_null(storage_space); phys_storage = virt_to_phys_or_null(storage_space);
phys_remaining = virt_to_phys_or_null(remaining_space); phys_remaining = virt_to_phys_or_null(remaining_space);
phys_max = virt_to_phys_or_null(max_variable_size); phys_max = virt_to_phys_or_null(max_variable_size);
...@@ -883,6 +974,8 @@ efi_thunk_query_variable_info(u32 attr, u64 *storage_space, ...@@ -883,6 +974,8 @@ efi_thunk_query_variable_info(u32 attr, u64 *storage_space,
status = efi_thunk(query_variable_info, attr, phys_storage, status = efi_thunk(query_variable_info, attr, phys_storage,
phys_remaining, phys_max); phys_remaining, phys_max);
spin_unlock_irqrestore(&efi_runtime_lock, flags);
return status; return status;
} }
...@@ -908,9 +1001,11 @@ void efi_thunk_runtime_setup(void) ...@@ -908,9 +1001,11 @@ void efi_thunk_runtime_setup(void)
efi.get_variable = efi_thunk_get_variable; efi.get_variable = efi_thunk_get_variable;
efi.get_next_variable = efi_thunk_get_next_variable; efi.get_next_variable = efi_thunk_get_next_variable;
efi.set_variable = efi_thunk_set_variable; efi.set_variable = efi_thunk_set_variable;
efi.set_variable_nonblocking = efi_thunk_set_variable_nonblocking;
efi.get_next_high_mono_count = efi_thunk_get_next_high_mono_count; efi.get_next_high_mono_count = efi_thunk_get_next_high_mono_count;
efi.reset_system = efi_thunk_reset_system; efi.reset_system = efi_thunk_reset_system;
efi.query_variable_info = efi_thunk_query_variable_info; efi.query_variable_info = efi_thunk_query_variable_info;
efi.query_variable_info_nonblocking = efi_thunk_query_variable_info_nonblocking;
efi.update_capsule = efi_thunk_update_capsule; efi.update_capsule = efi_thunk_update_capsule;
efi.query_capsule_caps = efi_thunk_query_capsule_caps; efi.query_capsule_caps = efi_thunk_query_capsule_caps;
} }
......
...@@ -105,12 +105,11 @@ early_param("efi_no_storage_paranoia", setup_storage_paranoia); ...@@ -105,12 +105,11 @@ early_param("efi_no_storage_paranoia", setup_storage_paranoia);
*/ */
void efi_delete_dummy_variable(void) void efi_delete_dummy_variable(void)
{ {
efi.set_variable((efi_char16_t *)efi_dummy_name, efi.set_variable_nonblocking((efi_char16_t *)efi_dummy_name,
&EFI_DUMMY_GUID, &EFI_DUMMY_GUID,
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_NON_VOLATILE |
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS |
EFI_VARIABLE_RUNTIME_ACCESS, EFI_VARIABLE_RUNTIME_ACCESS, 0, NULL);
0, NULL);
} }
/* /*
...@@ -249,7 +248,8 @@ void __init efi_arch_mem_reserve(phys_addr_t addr, u64 size) ...@@ -249,7 +248,8 @@ void __init efi_arch_mem_reserve(phys_addr_t addr, u64 size)
int num_entries; int num_entries;
void *new; void *new;
if (efi_mem_desc_lookup(addr, &md)) { if (efi_mem_desc_lookup(addr, &md) ||
md.type != EFI_BOOT_SERVICES_DATA) {
pr_err("Failed to lookup EFI memory descriptor for %pa\n", &addr); pr_err("Failed to lookup EFI memory descriptor for %pa\n", &addr);
return; return;
} }
......
...@@ -87,6 +87,18 @@ config EFI_RUNTIME_WRAPPERS ...@@ -87,6 +87,18 @@ config EFI_RUNTIME_WRAPPERS
config EFI_ARMSTUB config EFI_ARMSTUB
bool bool
config EFI_ARMSTUB_DTB_LOADER
bool "Enable the DTB loader"
depends on EFI_ARMSTUB
help
Select this config option to add support for the dtb= command
line parameter, allowing a device tree blob to be loaded into
memory from the EFI System Partition by the stub.
The device tree is typically provided by the platform or by
the bootloader, so this option is mostly for development
purposes only.
config EFI_BOOTLOADER_CONTROL config EFI_BOOTLOADER_CONTROL
tristate "EFI Bootloader Control" tristate "EFI Bootloader Control"
depends on EFI_VARS depends on EFI_VARS
......
...@@ -48,8 +48,21 @@ u64 cper_next_record_id(void) ...@@ -48,8 +48,21 @@ u64 cper_next_record_id(void)
{ {
static atomic64_t seq; static atomic64_t seq;
if (!atomic64_read(&seq)) if (!atomic64_read(&seq)) {
atomic64_set(&seq, ((u64)get_seconds()) << 32); time64_t time = ktime_get_real_seconds();
/*
* This code is unlikely to still be needed in year 2106,
* but just in case, let's use a few more bits for timestamps
* after y2038 to be sure they keep increasing monotonically
* for the next few hundred years...
*/
if (time < 0x80000000)
atomic64_set(&seq, (ktime_get_real_seconds()) << 32);
else
atomic64_set(&seq, 0x8000000000000000ull |
ktime_get_real_seconds() << 24);
}
return atomic64_inc_return(&seq); return atomic64_inc_return(&seq);
} }
...@@ -459,7 +472,7 @@ cper_estatus_print_section(const char *pfx, struct acpi_hest_generic_data *gdata ...@@ -459,7 +472,7 @@ cper_estatus_print_section(const char *pfx, struct acpi_hest_generic_data *gdata
else else
goto err_section_too_small; goto err_section_too_small;
#if defined(CONFIG_ARM64) || defined(CONFIG_ARM) #if defined(CONFIG_ARM64) || defined(CONFIG_ARM)
} else if (!uuid_le_cmp(*sec_type, CPER_SEC_PROC_ARM)) { } else if (guid_equal(sec_type, &CPER_SEC_PROC_ARM)) {
struct cper_sec_proc_arm *arm_err = acpi_hest_get_payload(gdata); struct cper_sec_proc_arm *arm_err = acpi_hest_get_payload(gdata);
printk("%ssection_type: ARM processor error\n", newpfx); printk("%ssection_type: ARM processor error\n", newpfx);
......
...@@ -84,6 +84,8 @@ struct mm_struct efi_mm = { ...@@ -84,6 +84,8 @@ struct mm_struct efi_mm = {
.mmlist = LIST_HEAD_INIT(efi_mm.mmlist), .mmlist = LIST_HEAD_INIT(efi_mm.mmlist),
}; };
struct workqueue_struct *efi_rts_wq;
static bool disable_runtime; static bool disable_runtime;
static int __init setup_noefi(char *arg) static int __init setup_noefi(char *arg)
{ {
...@@ -337,6 +339,18 @@ static int __init efisubsys_init(void) ...@@ -337,6 +339,18 @@ static int __init efisubsys_init(void)
if (!efi_enabled(EFI_BOOT)) if (!efi_enabled(EFI_BOOT))
return 0; return 0;
/*
* Since we process only one efi_runtime_service() at a time, an
* ordered workqueue (which creates only one execution context)
* should suffice all our needs.
*/
efi_rts_wq = alloc_ordered_workqueue("efi_rts_wq", 0);
if (!efi_rts_wq) {
pr_err("Creating efi_rts_wq failed, EFI runtime services disabled.\n");
clear_bit(EFI_RUNTIME_SERVICES, &efi.flags);
return 0;
}
/* We register the efi directory at /sys/firmware/efi */ /* We register the efi directory at /sys/firmware/efi */
efi_kobj = kobject_create_and_add("efi", firmware_kobj); efi_kobj = kobject_create_and_add("efi", firmware_kobj);
if (!efi_kobj) { if (!efi_kobj) {
...@@ -388,7 +402,7 @@ subsys_initcall(efisubsys_init); ...@@ -388,7 +402,7 @@ subsys_initcall(efisubsys_init);
* and if so, populate the supplied memory descriptor with the appropriate * and if so, populate the supplied memory descriptor with the appropriate
* data. * data.
*/ */
int __init efi_mem_desc_lookup(u64 phys_addr, efi_memory_desc_t *out_md) int efi_mem_desc_lookup(u64 phys_addr, efi_memory_desc_t *out_md)
{ {
efi_memory_desc_t *md; efi_memory_desc_t *md;
...@@ -406,12 +420,6 @@ int __init efi_mem_desc_lookup(u64 phys_addr, efi_memory_desc_t *out_md) ...@@ -406,12 +420,6 @@ int __init efi_mem_desc_lookup(u64 phys_addr, efi_memory_desc_t *out_md)
u64 size; u64 size;
u64 end; u64 end;
if (!(md->attribute & EFI_MEMORY_RUNTIME) &&
md->type != EFI_BOOT_SERVICES_DATA &&
md->type != EFI_RUNTIME_SERVICES_DATA) {
continue;
}
size = md->num_pages << EFI_PAGE_SHIFT; size = md->num_pages << EFI_PAGE_SHIFT;
end = md->phys_addr + size; end = md->phys_addr + size;
if (phys_addr >= md->phys_addr && phys_addr < end) { if (phys_addr >= md->phys_addr && phys_addr < end) {
......
...@@ -250,7 +250,10 @@ void __init efi_esrt_init(void) ...@@ -250,7 +250,10 @@ void __init efi_esrt_init(void)
return; return;
rc = efi_mem_desc_lookup(efi.esrt, &md); rc = efi_mem_desc_lookup(efi.esrt, &md);
if (rc < 0) { if (rc < 0 ||
(!(md.attribute & EFI_MEMORY_RUNTIME) &&
md.type != EFI_BOOT_SERVICES_DATA &&
md.type != EFI_RUNTIME_SERVICES_DATA)) {
pr_warn("ESRT header is not in the memory map.\n"); pr_warn("ESRT header is not in the memory map.\n");
return; return;
} }
...@@ -326,6 +329,7 @@ void __init efi_esrt_init(void) ...@@ -326,6 +329,7 @@ void __init efi_esrt_init(void)
end = esrt_data + size; end = esrt_data + size;
pr_info("Reserving ESRT space from %pa to %pa.\n", &esrt_data, &end); pr_info("Reserving ESRT space from %pa to %pa.\n", &esrt_data, &end);
if (md.type == EFI_BOOT_SERVICES_DATA)
efi_mem_reserve(esrt_data, esrt_data_size); efi_mem_reserve(esrt_data, esrt_data_size);
pr_debug("esrt-init: loaded.\n"); pr_debug("esrt-init: loaded.\n");
......
...@@ -40,31 +40,6 @@ ...@@ -40,31 +40,6 @@
static u64 virtmap_base = EFI_RT_VIRTUAL_BASE; static u64 virtmap_base = EFI_RT_VIRTUAL_BASE;
efi_status_t efi_open_volume(efi_system_table_t *sys_table_arg,
void *__image, void **__fh)
{
efi_file_io_interface_t *io;
efi_loaded_image_t *image = __image;
efi_file_handle_t *fh;
efi_guid_t fs_proto = EFI_FILE_SYSTEM_GUID;
efi_status_t status;
void *handle = (void *)(unsigned long)image->device_handle;
status = sys_table_arg->boottime->handle_protocol(handle,
&fs_proto, (void **)&io);
if (status != EFI_SUCCESS) {
efi_printk(sys_table_arg, "Failed to handle fs_proto\n");
return status;
}
status = io->open_volume(io, &fh);
if (status != EFI_SUCCESS)
efi_printk(sys_table_arg, "Failed to open volume\n");
*__fh = fh;
return status;
}
void efi_char16_printk(efi_system_table_t *sys_table_arg, void efi_char16_printk(efi_system_table_t *sys_table_arg,
efi_char16_t *str) efi_char16_t *str)
{ {
...@@ -202,8 +177,9 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table, ...@@ -202,8 +177,9 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table,
* 'dtb=' unless UEFI Secure Boot is disabled. We assume that secure * 'dtb=' unless UEFI Secure Boot is disabled. We assume that secure
* boot is enabled if we can't determine its state. * boot is enabled if we can't determine its state.
*/ */
if (secure_boot != efi_secureboot_mode_disabled && if (!IS_ENABLED(CONFIG_EFI_ARMSTUB_DTB_LOADER) ||
strstr(cmdline_ptr, "dtb=")) { secure_boot != efi_secureboot_mode_disabled) {
if (strstr(cmdline_ptr, "dtb="))
pr_efi(sys_table, "Ignoring DTB from command line.\n"); pr_efi(sys_table, "Ignoring DTB from command line.\n");
} else { } else {
status = handle_cmdline_files(sys_table, image, cmdline_ptr, status = handle_cmdline_files(sys_table, image, cmdline_ptr,
......
...@@ -413,6 +413,34 @@ static efi_status_t efi_file_close(void *handle) ...@@ -413,6 +413,34 @@ static efi_status_t efi_file_close(void *handle)
return efi_call_proto(efi_file_handle, close, handle); return efi_call_proto(efi_file_handle, close, handle);
} }
static efi_status_t efi_open_volume(efi_system_table_t *sys_table_arg,
efi_loaded_image_t *image,
efi_file_handle_t **__fh)
{
efi_file_io_interface_t *io;
efi_file_handle_t *fh;
efi_guid_t fs_proto = EFI_FILE_SYSTEM_GUID;
efi_status_t status;
void *handle = (void *)(unsigned long)efi_table_attr(efi_loaded_image,
device_handle,
image);
status = efi_call_early(handle_protocol, handle,
&fs_proto, (void **)&io);
if (status != EFI_SUCCESS) {
efi_printk(sys_table_arg, "Failed to handle fs_proto\n");
return status;
}
status = efi_call_proto(efi_file_io_interface, open_volume, io, &fh);
if (status != EFI_SUCCESS)
efi_printk(sys_table_arg, "Failed to open volume\n");
else
*__fh = fh;
return status;
}
/* /*
* Parse the ASCII string 'cmdline' for EFI options, denoted by the efi= * Parse the ASCII string 'cmdline' for EFI options, denoted by the efi=
* option, e.g. efi=nochunk. * option, e.g. efi=nochunk.
...@@ -563,8 +591,7 @@ efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg, ...@@ -563,8 +591,7 @@ efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg,
/* Only open the volume once. */ /* Only open the volume once. */
if (!i) { if (!i) {
status = efi_open_volume(sys_table_arg, image, status = efi_open_volume(sys_table_arg, image, &fh);
(void **)&fh);
if (status != EFI_SUCCESS) if (status != EFI_SUCCESS)
goto free_files; goto free_files;
} }
......
...@@ -36,9 +36,6 @@ extern int __pure is_quiet(void); ...@@ -36,9 +36,6 @@ extern int __pure is_quiet(void);
void efi_char16_printk(efi_system_table_t *, efi_char16_t *); void efi_char16_printk(efi_system_table_t *, efi_char16_t *);
efi_status_t efi_open_volume(efi_system_table_t *sys_table_arg, void *__image,
void **__fh);
unsigned long get_dram_base(efi_system_table_t *sys_table_arg); unsigned long get_dram_base(efi_system_table_t *sys_table_arg);
efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table, efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table,
......
/* /*
* runtime-wrappers.c - Runtime Services function call wrappers * runtime-wrappers.c - Runtime Services function call wrappers
* *
* Implementation summary:
* -----------------------
* 1. When user/kernel thread requests to execute efi_runtime_service(),
* enqueue work to efi_rts_wq.
* 2. Caller thread waits for completion until the work is finished
* because it's dependent on the return status and execution of
* efi_runtime_service().
* For instance, get_variable() and get_next_variable().
*
* Copyright (C) 2014 Linaro Ltd. <ard.biesheuvel@linaro.org> * Copyright (C) 2014 Linaro Ltd. <ard.biesheuvel@linaro.org>
* *
* Split off from arch/x86/platform/efi/efi.c * Split off from arch/x86/platform/efi/efi.c
...@@ -22,6 +31,9 @@ ...@@ -22,6 +31,9 @@
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/semaphore.h> #include <linux/semaphore.h>
#include <linux/stringify.h> #include <linux/stringify.h>
#include <linux/workqueue.h>
#include <linux/completion.h>
#include <asm/efi.h> #include <asm/efi.h>
/* /*
...@@ -33,6 +45,76 @@ ...@@ -33,6 +45,76 @@
#define __efi_call_virt(f, args...) \ #define __efi_call_virt(f, args...) \
__efi_call_virt_pointer(efi.systab->runtime, f, args) __efi_call_virt_pointer(efi.systab->runtime, f, args)
/* efi_runtime_service() function identifiers */
enum efi_rts_ids {
GET_TIME,
SET_TIME,
GET_WAKEUP_TIME,
SET_WAKEUP_TIME,
GET_VARIABLE,
GET_NEXT_VARIABLE,
SET_VARIABLE,
QUERY_VARIABLE_INFO,
GET_NEXT_HIGH_MONO_COUNT,
UPDATE_CAPSULE,
QUERY_CAPSULE_CAPS,
};
/*
* efi_runtime_work: Details of EFI Runtime Service work
* @arg<1-5>: EFI Runtime Service function arguments
* @status: Status of executing EFI Runtime Service
* @efi_rts_id: EFI Runtime Service function identifier
* @efi_rts_comp: Struct used for handling completions
*/
struct efi_runtime_work {
void *arg1;
void *arg2;
void *arg3;
void *arg4;
void *arg5;
efi_status_t status;
struct work_struct work;
enum efi_rts_ids efi_rts_id;
struct completion efi_rts_comp;
};
/*
* efi_queue_work: Queue efi_runtime_service() and wait until it's done
* @rts: efi_runtime_service() function identifier
* @rts_arg<1-5>: efi_runtime_service() function arguments
*
* Accesses to efi_runtime_services() are serialized by a binary
* semaphore (efi_runtime_lock) and caller waits until the work is
* finished, hence _only_ one work is queued at a time and the caller
* thread waits for completion.
*/
#define efi_queue_work(_rts, _arg1, _arg2, _arg3, _arg4, _arg5) \
({ \
struct efi_runtime_work efi_rts_work; \
efi_rts_work.status = EFI_ABORTED; \
\
init_completion(&efi_rts_work.efi_rts_comp); \
INIT_WORK_ONSTACK(&efi_rts_work.work, efi_call_rts); \
efi_rts_work.arg1 = _arg1; \
efi_rts_work.arg2 = _arg2; \
efi_rts_work.arg3 = _arg3; \
efi_rts_work.arg4 = _arg4; \
efi_rts_work.arg5 = _arg5; \
efi_rts_work.efi_rts_id = _rts; \
\
/* \
* queue_work() returns 0 if work was already on queue, \
* _ideally_ this should never happen. \
*/ \
if (queue_work(efi_rts_wq, &efi_rts_work.work)) \
wait_for_completion(&efi_rts_work.efi_rts_comp); \
else \
pr_err("Failed to queue work to efi_rts_wq.\n"); \
\
efi_rts_work.status; \
})
void efi_call_virt_check_flags(unsigned long flags, const char *call) void efi_call_virt_check_flags(unsigned long flags, const char *call)
{ {
unsigned long cur_flags, mismatch; unsigned long cur_flags, mismatch;
...@@ -90,13 +172,98 @@ void efi_call_virt_check_flags(unsigned long flags, const char *call) ...@@ -90,13 +172,98 @@ void efi_call_virt_check_flags(unsigned long flags, const char *call)
*/ */
static DEFINE_SEMAPHORE(efi_runtime_lock); static DEFINE_SEMAPHORE(efi_runtime_lock);
/*
* Calls the appropriate efi_runtime_service() with the appropriate
* arguments.
*
* Semantics followed by efi_call_rts() to understand efi_runtime_work:
* 1. If argument was a pointer, recast it from void pointer to original
* pointer type.
* 2. If argument was a value, recast it from void pointer to original
* pointer type and dereference it.
*/
static void efi_call_rts(struct work_struct *work)
{
struct efi_runtime_work *efi_rts_work;
void *arg1, *arg2, *arg3, *arg4, *arg5;
efi_status_t status = EFI_NOT_FOUND;
efi_rts_work = container_of(work, struct efi_runtime_work, work);
arg1 = efi_rts_work->arg1;
arg2 = efi_rts_work->arg2;
arg3 = efi_rts_work->arg3;
arg4 = efi_rts_work->arg4;
arg5 = efi_rts_work->arg5;
switch (efi_rts_work->efi_rts_id) {
case GET_TIME:
status = efi_call_virt(get_time, (efi_time_t *)arg1,
(efi_time_cap_t *)arg2);
break;
case SET_TIME:
status = efi_call_virt(set_time, (efi_time_t *)arg1);
break;
case GET_WAKEUP_TIME:
status = efi_call_virt(get_wakeup_time, (efi_bool_t *)arg1,
(efi_bool_t *)arg2, (efi_time_t *)arg3);
break;
case SET_WAKEUP_TIME:
status = efi_call_virt(set_wakeup_time, *(efi_bool_t *)arg1,
(efi_time_t *)arg2);
break;
case GET_VARIABLE:
status = efi_call_virt(get_variable, (efi_char16_t *)arg1,
(efi_guid_t *)arg2, (u32 *)arg3,
(unsigned long *)arg4, (void *)arg5);
break;
case GET_NEXT_VARIABLE:
status = efi_call_virt(get_next_variable, (unsigned long *)arg1,
(efi_char16_t *)arg2,
(efi_guid_t *)arg3);
break;
case SET_VARIABLE:
status = efi_call_virt(set_variable, (efi_char16_t *)arg1,
(efi_guid_t *)arg2, *(u32 *)arg3,
*(unsigned long *)arg4, (void *)arg5);
break;
case QUERY_VARIABLE_INFO:
status = efi_call_virt(query_variable_info, *(u32 *)arg1,
(u64 *)arg2, (u64 *)arg3, (u64 *)arg4);
break;
case GET_NEXT_HIGH_MONO_COUNT:
status = efi_call_virt(get_next_high_mono_count, (u32 *)arg1);
break;
case UPDATE_CAPSULE:
status = efi_call_virt(update_capsule,
(efi_capsule_header_t **)arg1,
*(unsigned long *)arg2,
*(unsigned long *)arg3);
break;
case QUERY_CAPSULE_CAPS:
status = efi_call_virt(query_capsule_caps,
(efi_capsule_header_t **)arg1,
*(unsigned long *)arg2, (u64 *)arg3,
(int *)arg4);
break;
default:
/*
* Ideally, we should never reach here because a caller of this
* function should have put the right efi_runtime_service()
* function identifier into efi_rts_work->efi_rts_id
*/
pr_err("Requested executing invalid EFI Runtime Service.\n");
}
efi_rts_work->status = status;
complete(&efi_rts_work->efi_rts_comp);
}
static efi_status_t virt_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc) static efi_status_t virt_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc)
{ {
efi_status_t status; efi_status_t status;
if (down_interruptible(&efi_runtime_lock)) if (down_interruptible(&efi_runtime_lock))
return EFI_ABORTED; return EFI_ABORTED;
status = efi_call_virt(get_time, tm, tc); status = efi_queue_work(GET_TIME, tm, tc, NULL, NULL, NULL);
up(&efi_runtime_lock); up(&efi_runtime_lock);
return status; return status;
} }
...@@ -107,7 +274,7 @@ static efi_status_t virt_efi_set_time(efi_time_t *tm) ...@@ -107,7 +274,7 @@ static efi_status_t virt_efi_set_time(efi_time_t *tm)
if (down_interruptible(&efi_runtime_lock)) if (down_interruptible(&efi_runtime_lock))
return EFI_ABORTED; return EFI_ABORTED;
status = efi_call_virt(set_time, tm); status = efi_queue_work(SET_TIME, tm, NULL, NULL, NULL, NULL);
up(&efi_runtime_lock); up(&efi_runtime_lock);
return status; return status;
} }
...@@ -120,7 +287,8 @@ static efi_status_t virt_efi_get_wakeup_time(efi_bool_t *enabled, ...@@ -120,7 +287,8 @@ static efi_status_t virt_efi_get_wakeup_time(efi_bool_t *enabled,
if (down_interruptible(&efi_runtime_lock)) if (down_interruptible(&efi_runtime_lock))
return EFI_ABORTED; return EFI_ABORTED;
status = efi_call_virt(get_wakeup_time, enabled, pending, tm); status = efi_queue_work(GET_WAKEUP_TIME, enabled, pending, tm, NULL,
NULL);
up(&efi_runtime_lock); up(&efi_runtime_lock);
return status; return status;
} }
...@@ -131,7 +299,8 @@ static efi_status_t virt_efi_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm) ...@@ -131,7 +299,8 @@ static efi_status_t virt_efi_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm)
if (down_interruptible(&efi_runtime_lock)) if (down_interruptible(&efi_runtime_lock))
return EFI_ABORTED; return EFI_ABORTED;
status = efi_call_virt(set_wakeup_time, enabled, tm); status = efi_queue_work(SET_WAKEUP_TIME, &enabled, tm, NULL, NULL,
NULL);
up(&efi_runtime_lock); up(&efi_runtime_lock);
return status; return status;
} }
...@@ -146,7 +315,7 @@ static efi_status_t virt_efi_get_variable(efi_char16_t *name, ...@@ -146,7 +315,7 @@ static efi_status_t virt_efi_get_variable(efi_char16_t *name,
if (down_interruptible(&efi_runtime_lock)) if (down_interruptible(&efi_runtime_lock))
return EFI_ABORTED; return EFI_ABORTED;
status = efi_call_virt(get_variable, name, vendor, attr, data_size, status = efi_queue_work(GET_VARIABLE, name, vendor, attr, data_size,
data); data);
up(&efi_runtime_lock); up(&efi_runtime_lock);
return status; return status;
...@@ -160,7 +329,8 @@ static efi_status_t virt_efi_get_next_variable(unsigned long *name_size, ...@@ -160,7 +329,8 @@ static efi_status_t virt_efi_get_next_variable(unsigned long *name_size,
if (down_interruptible(&efi_runtime_lock)) if (down_interruptible(&efi_runtime_lock))
return EFI_ABORTED; return EFI_ABORTED;
status = efi_call_virt(get_next_variable, name_size, name, vendor); status = efi_queue_work(GET_NEXT_VARIABLE, name_size, name, vendor,
NULL, NULL);
up(&efi_runtime_lock); up(&efi_runtime_lock);
return status; return status;
} }
...@@ -175,7 +345,7 @@ static efi_status_t virt_efi_set_variable(efi_char16_t *name, ...@@ -175,7 +345,7 @@ static efi_status_t virt_efi_set_variable(efi_char16_t *name,
if (down_interruptible(&efi_runtime_lock)) if (down_interruptible(&efi_runtime_lock))
return EFI_ABORTED; return EFI_ABORTED;
status = efi_call_virt(set_variable, name, vendor, attr, data_size, status = efi_queue_work(SET_VARIABLE, name, vendor, &attr, &data_size,
data); data);
up(&efi_runtime_lock); up(&efi_runtime_lock);
return status; return status;
...@@ -210,8 +380,8 @@ static efi_status_t virt_efi_query_variable_info(u32 attr, ...@@ -210,8 +380,8 @@ static efi_status_t virt_efi_query_variable_info(u32 attr,
if (down_interruptible(&efi_runtime_lock)) if (down_interruptible(&efi_runtime_lock))
return EFI_ABORTED; return EFI_ABORTED;
status = efi_call_virt(query_variable_info, attr, storage_space, status = efi_queue_work(QUERY_VARIABLE_INFO, &attr, storage_space,
remaining_space, max_variable_size); remaining_space, max_variable_size, NULL);
up(&efi_runtime_lock); up(&efi_runtime_lock);
return status; return status;
} }
...@@ -242,7 +412,8 @@ static efi_status_t virt_efi_get_next_high_mono_count(u32 *count) ...@@ -242,7 +412,8 @@ static efi_status_t virt_efi_get_next_high_mono_count(u32 *count)
if (down_interruptible(&efi_runtime_lock)) if (down_interruptible(&efi_runtime_lock))
return EFI_ABORTED; return EFI_ABORTED;
status = efi_call_virt(get_next_high_mono_count, count); status = efi_queue_work(GET_NEXT_HIGH_MONO_COUNT, count, NULL, NULL,
NULL, NULL);
up(&efi_runtime_lock); up(&efi_runtime_lock);
return status; return status;
} }
...@@ -272,7 +443,8 @@ static efi_status_t virt_efi_update_capsule(efi_capsule_header_t **capsules, ...@@ -272,7 +443,8 @@ static efi_status_t virt_efi_update_capsule(efi_capsule_header_t **capsules,
if (down_interruptible(&efi_runtime_lock)) if (down_interruptible(&efi_runtime_lock))
return EFI_ABORTED; return EFI_ABORTED;
status = efi_call_virt(update_capsule, capsules, count, sg_list); status = efi_queue_work(UPDATE_CAPSULE, capsules, &count, &sg_list,
NULL, NULL);
up(&efi_runtime_lock); up(&efi_runtime_lock);
return status; return status;
} }
...@@ -289,8 +461,8 @@ static efi_status_t virt_efi_query_capsule_caps(efi_capsule_header_t **capsules, ...@@ -289,8 +461,8 @@ static efi_status_t virt_efi_query_capsule_caps(efi_capsule_header_t **capsules,
if (down_interruptible(&efi_runtime_lock)) if (down_interruptible(&efi_runtime_lock))
return EFI_ABORTED; return EFI_ABORTED;
status = efi_call_virt(query_capsule_caps, capsules, count, max_size, status = efi_queue_work(QUERY_CAPSULE_CAPS, capsules, &count,
reset_type); max_size, reset_type, NULL);
up(&efi_runtime_lock); up(&efi_runtime_lock);
return status; return status;
} }
......
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
#include <drm/drm_connector.h> /* For DRM_MODE_PANEL_ORIENTATION_* */ #include <drm/drm_connector.h> /* For DRM_MODE_PANEL_ORIENTATION_* */
static bool request_mem_succeeded = false; static bool request_mem_succeeded = false;
static bool nowc = false; static u64 mem_flags = EFI_MEMORY_WC | EFI_MEMORY_UC;
static struct fb_var_screeninfo efifb_defined = { static struct fb_var_screeninfo efifb_defined = {
.activate = FB_ACTIVATE_NOW, .activate = FB_ACTIVATE_NOW,
...@@ -68,8 +68,12 @@ static int efifb_setcolreg(unsigned regno, unsigned red, unsigned green, ...@@ -68,8 +68,12 @@ static int efifb_setcolreg(unsigned regno, unsigned red, unsigned green,
static void efifb_destroy(struct fb_info *info) static void efifb_destroy(struct fb_info *info)
{ {
if (info->screen_base) if (info->screen_base) {
if (mem_flags & (EFI_MEMORY_UC | EFI_MEMORY_WC))
iounmap(info->screen_base); iounmap(info->screen_base);
else
memunmap(info->screen_base);
}
if (request_mem_succeeded) if (request_mem_succeeded)
release_mem_region(info->apertures->ranges[0].base, release_mem_region(info->apertures->ranges[0].base,
info->apertures->ranges[0].size); info->apertures->ranges[0].size);
...@@ -104,7 +108,7 @@ static int efifb_setup(char *options) ...@@ -104,7 +108,7 @@ static int efifb_setup(char *options)
else if (!strncmp(this_opt, "width:", 6)) else if (!strncmp(this_opt, "width:", 6))
screen_info.lfb_width = simple_strtoul(this_opt+6, NULL, 0); screen_info.lfb_width = simple_strtoul(this_opt+6, NULL, 0);
else if (!strcmp(this_opt, "nowc")) else if (!strcmp(this_opt, "nowc"))
nowc = true; mem_flags &= ~EFI_MEMORY_WC;
} }
} }
...@@ -164,6 +168,7 @@ static int efifb_probe(struct platform_device *dev) ...@@ -164,6 +168,7 @@ static int efifb_probe(struct platform_device *dev)
unsigned int size_remap; unsigned int size_remap;
unsigned int size_total; unsigned int size_total;
char *option = NULL; char *option = NULL;
efi_memory_desc_t md;
if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI || pci_dev_disabled) if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI || pci_dev_disabled)
return -ENODEV; return -ENODEV;
...@@ -272,12 +277,35 @@ static int efifb_probe(struct platform_device *dev) ...@@ -272,12 +277,35 @@ static int efifb_probe(struct platform_device *dev)
info->apertures->ranges[0].base = efifb_fix.smem_start; info->apertures->ranges[0].base = efifb_fix.smem_start;
info->apertures->ranges[0].size = size_remap; info->apertures->ranges[0].size = size_remap;
if (nowc) if (!efi_mem_desc_lookup(efifb_fix.smem_start, &md)) {
info->screen_base = ioremap(efifb_fix.smem_start, efifb_fix.smem_len); if ((efifb_fix.smem_start + efifb_fix.smem_len) >
else (md.phys_addr + (md.num_pages << EFI_PAGE_SHIFT))) {
info->screen_base = ioremap_wc(efifb_fix.smem_start, efifb_fix.smem_len); pr_err("efifb: video memory @ 0x%lx spans multiple EFI memory regions\n",
efifb_fix.smem_start);
err = -EIO;
goto err_release_fb;
}
/*
* If the UEFI memory map covers the efifb region, we may only
* remap it using the attributes the memory map prescribes.
*/
mem_flags |= EFI_MEMORY_WT | EFI_MEMORY_WB;
mem_flags &= md.attribute;
}
if (mem_flags & EFI_MEMORY_WC)
info->screen_base = ioremap_wc(efifb_fix.smem_start,
efifb_fix.smem_len);
else if (mem_flags & EFI_MEMORY_UC)
info->screen_base = ioremap(efifb_fix.smem_start,
efifb_fix.smem_len);
else if (mem_flags & EFI_MEMORY_WT)
info->screen_base = memremap(efifb_fix.smem_start,
efifb_fix.smem_len, MEMREMAP_WT);
else if (mem_flags & EFI_MEMORY_WB)
info->screen_base = memremap(efifb_fix.smem_start,
efifb_fix.smem_len, MEMREMAP_WB);
if (!info->screen_base) { if (!info->screen_base) {
pr_err("efifb: abort, cannot ioremap video memory 0x%x @ 0x%lx\n", pr_err("efifb: abort, cannot remap video memory 0x%x @ 0x%lx\n",
efifb_fix.smem_len, efifb_fix.smem_start); efifb_fix.smem_len, efifb_fix.smem_start);
err = -EIO; err = -EIO;
goto err_release_fb; goto err_release_fb;
...@@ -371,7 +399,10 @@ static int efifb_probe(struct platform_device *dev) ...@@ -371,7 +399,10 @@ static int efifb_probe(struct platform_device *dev)
err_groups: err_groups:
sysfs_remove_groups(&dev->dev.kobj, efifb_groups); sysfs_remove_groups(&dev->dev.kobj, efifb_groups);
err_unmap: err_unmap:
if (mem_flags & (EFI_MEMORY_UC | EFI_MEMORY_WC))
iounmap(info->screen_base); iounmap(info->screen_base);
else
memunmap(info->screen_base);
err_release_fb: err_release_fb:
framebuffer_release(info); framebuffer_release(info);
err_release_mem: err_release_mem:
......
...@@ -86,7 +86,9 @@ static int efivarfs_create(struct inode *dir, struct dentry *dentry, ...@@ -86,7 +86,9 @@ static int efivarfs_create(struct inode *dir, struct dentry *dentry,
/* length of the variable name itself: remove GUID and separator */ /* length of the variable name itself: remove GUID and separator */
namelen = dentry->d_name.len - EFI_VARIABLE_GUID_LEN - 1; namelen = dentry->d_name.len - EFI_VARIABLE_GUID_LEN - 1;
uuid_le_to_bin(dentry->d_name.name + namelen + 1, &var->var.VendorGuid); err = guid_parse(dentry->d_name.name + namelen + 1, &var->var.VendorGuid);
if (err)
goto out;
if (efivar_variable_is_removable(var->var.VendorGuid, if (efivar_variable_is_removable(var->var.VendorGuid,
dentry->d_name.name, namelen)) dentry->d_name.name, namelen))
......
...@@ -894,6 +894,16 @@ typedef struct _efi_file_handle { ...@@ -894,6 +894,16 @@ typedef struct _efi_file_handle {
void *flush; void *flush;
} efi_file_handle_t; } efi_file_handle_t;
typedef struct {
u64 revision;
u32 open_volume;
} efi_file_io_interface_32_t;
typedef struct {
u64 revision;
u64 open_volume;
} efi_file_io_interface_64_t;
typedef struct _efi_file_io_interface { typedef struct _efi_file_io_interface {
u64 revision; u64 revision;
int (*open_volume)(struct _efi_file_io_interface *, int (*open_volume)(struct _efi_file_io_interface *,
...@@ -988,14 +998,12 @@ extern void efi_memmap_walk (efi_freemem_callback_t callback, void *arg); ...@@ -988,14 +998,12 @@ extern void efi_memmap_walk (efi_freemem_callback_t callback, void *arg);
extern void efi_gettimeofday (struct timespec64 *ts); extern void efi_gettimeofday (struct timespec64 *ts);
extern void efi_enter_virtual_mode (void); /* switch EFI to virtual mode, if possible */ extern void efi_enter_virtual_mode (void); /* switch EFI to virtual mode, if possible */
#ifdef CONFIG_X86 #ifdef CONFIG_X86
extern void efi_late_init(void);
extern void efi_free_boot_services(void); extern void efi_free_boot_services(void);
extern efi_status_t efi_query_variable_store(u32 attributes, extern efi_status_t efi_query_variable_store(u32 attributes,
unsigned long size, unsigned long size,
bool nonblocking); bool nonblocking);
extern void efi_find_mirror(void); extern void efi_find_mirror(void);
#else #else
static inline void efi_late_init(void) {}
static inline void efi_free_boot_services(void) {} static inline void efi_free_boot_services(void) {}
static inline efi_status_t efi_query_variable_store(u32 attributes, static inline efi_status_t efi_query_variable_store(u32 attributes,
...@@ -1651,4 +1659,7 @@ struct linux_efi_tpm_eventlog { ...@@ -1651,4 +1659,7 @@ struct linux_efi_tpm_eventlog {
extern int efi_tpm_eventlog_init(void); extern int efi_tpm_eventlog_init(void);
/* Workqueue to queue EFI Runtime Services */
extern struct workqueue_struct *efi_rts_wq;
#endif /* _LINUX_EFI_H */ #endif /* _LINUX_EFI_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment