Commit c03d21f0 authored by Ard Biesheuvel's avatar Ard Biesheuvel

Merge 3rd batch of EFI fixes into efi/urgent

parents 8dbe3395 50e782a8
...@@ -273,9 +273,13 @@ static __init int efivar_ssdt_load(void) ...@@ -273,9 +273,13 @@ static __init int efivar_ssdt_load(void)
if (status == EFI_NOT_FOUND) { if (status == EFI_NOT_FOUND) {
break; break;
} else if (status == EFI_BUFFER_TOO_SMALL) { } else if (status == EFI_BUFFER_TOO_SMALL) {
name = krealloc(name, name_size, GFP_KERNEL); efi_char16_t *name_tmp =
if (!name) krealloc(name, name_size, GFP_KERNEL);
if (!name_tmp) {
kfree(name);
return -ENOMEM; return -ENOMEM;
}
name = name_tmp;
continue; continue;
} }
......
...@@ -605,11 +605,8 @@ setup_e820(struct boot_params *params, struct setup_data *e820ext, u32 e820ext_s ...@@ -605,11 +605,8 @@ setup_e820(struct boot_params *params, struct setup_data *e820ext, u32 e820ext_s
break; break;
case EFI_UNACCEPTED_MEMORY: case EFI_UNACCEPTED_MEMORY:
if (!IS_ENABLED(CONFIG_UNACCEPTED_MEMORY)) { if (!IS_ENABLED(CONFIG_UNACCEPTED_MEMORY))
efi_warn_once(
"The system has unaccepted memory, but kernel does not support it\nConsider enabling CONFIG_UNACCEPTED_MEMORY\n");
continue; continue;
}
e820_type = E820_TYPE_RAM; e820_type = E820_TYPE_RAM;
process_unaccepted_memory(d->phys_addr, process_unaccepted_memory(d->phys_addr,
d->phys_addr + PAGE_SIZE * d->num_pages); d->phys_addr + PAGE_SIZE * d->num_pages);
...@@ -852,6 +849,8 @@ void __noreturn efi_stub_entry(efi_handle_t handle, ...@@ -852,6 +849,8 @@ void __noreturn efi_stub_entry(efi_handle_t handle,
unsigned long kernel_entry; unsigned long kernel_entry;
efi_status_t status; efi_status_t status;
boot_params_pointer = boot_params;
efi_system_table = sys_table_arg; efi_system_table = sys_table_arg;
/* Check if we were booted by the EFI firmware */ /* Check if we were booted by the EFI firmware */
if (efi_system_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) if (efi_system_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
......
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
#include <linux/efi.h> #include <linux/efi.h>
extern struct boot_params *boot_params_pointer asm("boot_params");
extern void trampoline_32bit_src(void *, bool); extern void trampoline_32bit_src(void *, bool);
extern const u16 trampoline_ljmp_imm_offset; extern const u16 trampoline_ljmp_imm_offset;
......
...@@ -5,9 +5,17 @@ ...@@ -5,9 +5,17 @@
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <asm/unaccepted_memory.h> #include <asm/unaccepted_memory.h>
/* Protects unaccepted memory bitmap */ /* Protects unaccepted memory bitmap and accepting_list */
static DEFINE_SPINLOCK(unaccepted_memory_lock); static DEFINE_SPINLOCK(unaccepted_memory_lock);
struct accept_range {
struct list_head list;
unsigned long start;
unsigned long end;
};
static LIST_HEAD(accepting_list);
/* /*
* accept_memory() -- Consult bitmap and accept the memory if needed. * accept_memory() -- Consult bitmap and accept the memory if needed.
* *
...@@ -24,6 +32,7 @@ void accept_memory(phys_addr_t start, phys_addr_t end) ...@@ -24,6 +32,7 @@ void accept_memory(phys_addr_t start, phys_addr_t end)
{ {
struct efi_unaccepted_memory *unaccepted; struct efi_unaccepted_memory *unaccepted;
unsigned long range_start, range_end; unsigned long range_start, range_end;
struct accept_range range, *entry;
unsigned long flags; unsigned long flags;
u64 unit_size; u64 unit_size;
...@@ -78,20 +87,67 @@ void accept_memory(phys_addr_t start, phys_addr_t end) ...@@ -78,20 +87,67 @@ void accept_memory(phys_addr_t start, phys_addr_t end)
if (end > unaccepted->size * unit_size * BITS_PER_BYTE) if (end > unaccepted->size * unit_size * BITS_PER_BYTE)
end = unaccepted->size * unit_size * BITS_PER_BYTE; end = unaccepted->size * unit_size * BITS_PER_BYTE;
range_start = start / unit_size; range.start = start / unit_size;
range.end = DIV_ROUND_UP(end, unit_size);
retry:
spin_lock_irqsave(&unaccepted_memory_lock, flags); spin_lock_irqsave(&unaccepted_memory_lock, flags);
/*
* Check if anybody works on accepting the same range of the memory.
*
* The check is done with unit_size granularity. It is crucial to catch
* all accept requests to the same unit_size block, even if they don't
* overlap on physical address level.
*/
list_for_each_entry(entry, &accepting_list, list) {
if (entry->end < range.start)
continue;
if (entry->start >= range.end)
continue;
/*
* Somebody else accepting the range. Or at least part of it.
*
* Drop the lock and retry until it is complete.
*/
spin_unlock_irqrestore(&unaccepted_memory_lock, flags);
goto retry;
}
/*
* Register that the range is about to be accepted.
* Make sure nobody else will accept it.
*/
list_add(&range.list, &accepting_list);
range_start = range.start;
for_each_set_bitrange_from(range_start, range_end, unaccepted->bitmap, for_each_set_bitrange_from(range_start, range_end, unaccepted->bitmap,
DIV_ROUND_UP(end, unit_size)) { range.end) {
unsigned long phys_start, phys_end; unsigned long phys_start, phys_end;
unsigned long len = range_end - range_start; unsigned long len = range_end - range_start;
phys_start = range_start * unit_size + unaccepted->phys_base; phys_start = range_start * unit_size + unaccepted->phys_base;
phys_end = range_end * unit_size + unaccepted->phys_base; phys_end = range_end * unit_size + unaccepted->phys_base;
/*
* Keep interrupts disabled until the accept operation is
* complete in order to prevent deadlocks.
*
* Enabling interrupts before calling arch_accept_memory()
* creates an opportunity for an interrupt handler to request
* acceptance for the same memory. The handler will continuously
* spin with interrupts disabled, preventing other task from
* making progress with the acceptance process.
*/
spin_unlock(&unaccepted_memory_lock);
arch_accept_memory(phys_start, phys_end); arch_accept_memory(phys_start, phys_end);
spin_lock(&unaccepted_memory_lock);
bitmap_clear(unaccepted->bitmap, range_start, len); bitmap_clear(unaccepted->bitmap, range_start, len);
} }
list_del(&range.list);
spin_unlock_irqrestore(&unaccepted_memory_lock, flags); spin_unlock_irqrestore(&unaccepted_memory_lock, flags);
} }
......
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