Skip to content

Commit 70e65af

Browse files
committed
Merge tag 'efi-fixes-for-v6.6-3' of git://git.kernel.org/pub/scm/linux/kernel/git/efi/efi
Pull EFI fixes from Ard Biesheuvel: "The boot_params pointer fix uses a somewhat ugly extern struct declaration but this will be cleaned up the next cycle. - don't try to print warnings to the console when it is no longer available - fix theoretical memory leak in SSDT override handling - make sure that the boot_params global variable is set before the KASLR code attempts to hash it for 'randomness' - avoid soft lockups in the memory acceptance code" * tag 'efi-fixes-for-v6.6-3' of git://git.kernel.org/pub/scm/linux/kernel/git/efi/efi: efi/unaccepted: Fix soft lockups caused by parallel memory acceptance x86/boot: efistub: Assign global boot_params variable efi: fix memory leak in krealloc failure handling x86/efistub: Don't try to print after ExitBootService()
2 parents 1acfd2b + c03d21f commit 70e65af

File tree

4 files changed

+71
-10
lines changed

4 files changed

+71
-10
lines changed

drivers/firmware/efi/efi.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -273,9 +273,13 @@ static __init int efivar_ssdt_load(void)
273273
if (status == EFI_NOT_FOUND) {
274274
break;
275275
} else if (status == EFI_BUFFER_TOO_SMALL) {
276-
name = krealloc(name, name_size, GFP_KERNEL);
277-
if (!name)
276+
efi_char16_t *name_tmp =
277+
krealloc(name, name_size, GFP_KERNEL);
278+
if (!name_tmp) {
279+
kfree(name);
278280
return -ENOMEM;
281+
}
282+
name = name_tmp;
279283
continue;
280284
}
281285

drivers/firmware/efi/libstub/x86-stub.c

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -605,11 +605,8 @@ setup_e820(struct boot_params *params, struct setup_data *e820ext, u32 e820ext_s
605605
break;
606606

607607
case EFI_UNACCEPTED_MEMORY:
608-
if (!IS_ENABLED(CONFIG_UNACCEPTED_MEMORY)) {
609-
efi_warn_once(
610-
"The system has unaccepted memory, but kernel does not support it\nConsider enabling CONFIG_UNACCEPTED_MEMORY\n");
608+
if (!IS_ENABLED(CONFIG_UNACCEPTED_MEMORY))
611609
continue;
612-
}
613610
e820_type = E820_TYPE_RAM;
614611
process_unaccepted_memory(d->phys_addr,
615612
d->phys_addr + PAGE_SIZE * d->num_pages);
@@ -852,6 +849,8 @@ void __noreturn efi_stub_entry(efi_handle_t handle,
852849
unsigned long kernel_entry;
853850
efi_status_t status;
854851

852+
boot_params_pointer = boot_params;
853+
855854
efi_system_table = sys_table_arg;
856855
/* Check if we were booted by the EFI firmware */
857856
if (efi_system_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)

drivers/firmware/efi/libstub/x86-stub.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
#include <linux/efi.h>
44

5+
extern struct boot_params *boot_params_pointer asm("boot_params");
6+
57
extern void trampoline_32bit_src(void *, bool);
68
extern const u16 trampoline_ljmp_imm_offset;
79

drivers/firmware/efi/unaccepted_memory.c

Lines changed: 60 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,17 @@
55
#include <linux/spinlock.h>
66
#include <asm/unaccepted_memory.h>
77

8-
/* Protects unaccepted memory bitmap */
8+
/* Protects unaccepted memory bitmap and accepting_list */
99
static DEFINE_SPINLOCK(unaccepted_memory_lock);
1010

11+
struct accept_range {
12+
struct list_head list;
13+
unsigned long start;
14+
unsigned long end;
15+
};
16+
17+
static LIST_HEAD(accepting_list);
18+
1119
/*
1220
* accept_memory() -- Consult bitmap and accept the memory if needed.
1321
*
@@ -24,6 +32,7 @@ void accept_memory(phys_addr_t start, phys_addr_t end)
2432
{
2533
struct efi_unaccepted_memory *unaccepted;
2634
unsigned long range_start, range_end;
35+
struct accept_range range, *entry;
2736
unsigned long flags;
2837
u64 unit_size;
2938

@@ -78,20 +87,67 @@ void accept_memory(phys_addr_t start, phys_addr_t end)
7887
if (end > unaccepted->size * unit_size * BITS_PER_BYTE)
7988
end = unaccepted->size * unit_size * BITS_PER_BYTE;
8089

81-
range_start = start / unit_size;
82-
90+
range.start = start / unit_size;
91+
range.end = DIV_ROUND_UP(end, unit_size);
92+
retry:
8393
spin_lock_irqsave(&unaccepted_memory_lock, flags);
94+
95+
/*
96+
* Check if anybody works on accepting the same range of the memory.
97+
*
98+
* The check is done with unit_size granularity. It is crucial to catch
99+
* all accept requests to the same unit_size block, even if they don't
100+
* overlap on physical address level.
101+
*/
102+
list_for_each_entry(entry, &accepting_list, list) {
103+
if (entry->end < range.start)
104+
continue;
105+
if (entry->start >= range.end)
106+
continue;
107+
108+
/*
109+
* Somebody else accepting the range. Or at least part of it.
110+
*
111+
* Drop the lock and retry until it is complete.
112+
*/
113+
spin_unlock_irqrestore(&unaccepted_memory_lock, flags);
114+
goto retry;
115+
}
116+
117+
/*
118+
* Register that the range is about to be accepted.
119+
* Make sure nobody else will accept it.
120+
*/
121+
list_add(&range.list, &accepting_list);
122+
123+
range_start = range.start;
84124
for_each_set_bitrange_from(range_start, range_end, unaccepted->bitmap,
85-
DIV_ROUND_UP(end, unit_size)) {
125+
range.end) {
86126
unsigned long phys_start, phys_end;
87127
unsigned long len = range_end - range_start;
88128

89129
phys_start = range_start * unit_size + unaccepted->phys_base;
90130
phys_end = range_end * unit_size + unaccepted->phys_base;
91131

132+
/*
133+
* Keep interrupts disabled until the accept operation is
134+
* complete in order to prevent deadlocks.
135+
*
136+
* Enabling interrupts before calling arch_accept_memory()
137+
* creates an opportunity for an interrupt handler to request
138+
* acceptance for the same memory. The handler will continuously
139+
* spin with interrupts disabled, preventing other task from
140+
* making progress with the acceptance process.
141+
*/
142+
spin_unlock(&unaccepted_memory_lock);
143+
92144
arch_accept_memory(phys_start, phys_end);
145+
146+
spin_lock(&unaccepted_memory_lock);
93147
bitmap_clear(unaccepted->bitmap, range_start, len);
94148
}
149+
150+
list_del(&range.list);
95151
spin_unlock_irqrestore(&unaccepted_memory_lock, flags);
96152
}
97153

0 commit comments

Comments
 (0)