Loading drivers/firmware/efi/efi.c +6 −2 Original line number Diff line number Diff line Loading @@ -273,9 +273,13 @@ static __init int efivar_ssdt_load(void) if (status == EFI_NOT_FOUND) { break; } else if (status == EFI_BUFFER_TOO_SMALL) { name = krealloc(name, name_size, GFP_KERNEL); if (!name) efi_char16_t *name_tmp = krealloc(name, name_size, GFP_KERNEL); if (!name_tmp) { kfree(name); return -ENOMEM; } name = name_tmp; continue; } Loading drivers/firmware/efi/libstub/x86-stub.c +3 −4 Original line number Diff line number Diff line Loading @@ -605,11 +605,8 @@ setup_e820(struct boot_params *params, struct setup_data *e820ext, u32 e820ext_s break; case EFI_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"); if (!IS_ENABLED(CONFIG_UNACCEPTED_MEMORY)) continue; } e820_type = E820_TYPE_RAM; process_unaccepted_memory(d->phys_addr, d->phys_addr + PAGE_SIZE * d->num_pages); Loading Loading @@ -852,6 +849,8 @@ void __noreturn efi_stub_entry(efi_handle_t handle, unsigned long kernel_entry; efi_status_t status; boot_params_pointer = boot_params; efi_system_table = sys_table_arg; /* Check if we were booted by the EFI firmware */ if (efi_system_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) Loading drivers/firmware/efi/libstub/x86-stub.h +2 −0 Original line number Diff line number Diff line Loading @@ -2,6 +2,8 @@ #include <linux/efi.h> extern struct boot_params *boot_params_pointer asm("boot_params"); extern void trampoline_32bit_src(void *, bool); extern const u16 trampoline_ljmp_imm_offset; Loading drivers/firmware/efi/unaccepted_memory.c +60 −4 Original line number Diff line number Diff line Loading @@ -5,9 +5,17 @@ #include <linux/spinlock.h> #include <asm/unaccepted_memory.h> /* Protects unaccepted memory bitmap */ /* Protects unaccepted memory bitmap and accepting_list */ 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. * Loading @@ -24,6 +32,7 @@ void accept_memory(phys_addr_t start, phys_addr_t end) { struct efi_unaccepted_memory *unaccepted; unsigned long range_start, range_end; struct accept_range range, *entry; unsigned long flags; u64 unit_size; Loading Loading @@ -78,20 +87,67 @@ void accept_memory(phys_addr_t start, phys_addr_t end) if (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); /* * 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, DIV_ROUND_UP(end, unit_size)) { range.end) { unsigned long phys_start, phys_end; unsigned long len = range_end - range_start; phys_start = range_start * 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); spin_lock(&unaccepted_memory_lock); bitmap_clear(unaccepted->bitmap, range_start, len); } list_del(&range.list); spin_unlock_irqrestore(&unaccepted_memory_lock, flags); } Loading Loading
drivers/firmware/efi/efi.c +6 −2 Original line number Diff line number Diff line Loading @@ -273,9 +273,13 @@ static __init int efivar_ssdt_load(void) if (status == EFI_NOT_FOUND) { break; } else if (status == EFI_BUFFER_TOO_SMALL) { name = krealloc(name, name_size, GFP_KERNEL); if (!name) efi_char16_t *name_tmp = krealloc(name, name_size, GFP_KERNEL); if (!name_tmp) { kfree(name); return -ENOMEM; } name = name_tmp; continue; } Loading
drivers/firmware/efi/libstub/x86-stub.c +3 −4 Original line number Diff line number Diff line Loading @@ -605,11 +605,8 @@ setup_e820(struct boot_params *params, struct setup_data *e820ext, u32 e820ext_s break; case EFI_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"); if (!IS_ENABLED(CONFIG_UNACCEPTED_MEMORY)) continue; } e820_type = E820_TYPE_RAM; process_unaccepted_memory(d->phys_addr, d->phys_addr + PAGE_SIZE * d->num_pages); Loading Loading @@ -852,6 +849,8 @@ void __noreturn efi_stub_entry(efi_handle_t handle, unsigned long kernel_entry; efi_status_t status; boot_params_pointer = boot_params; efi_system_table = sys_table_arg; /* Check if we were booted by the EFI firmware */ if (efi_system_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) Loading
drivers/firmware/efi/libstub/x86-stub.h +2 −0 Original line number Diff line number Diff line Loading @@ -2,6 +2,8 @@ #include <linux/efi.h> extern struct boot_params *boot_params_pointer asm("boot_params"); extern void trampoline_32bit_src(void *, bool); extern const u16 trampoline_ljmp_imm_offset; Loading
drivers/firmware/efi/unaccepted_memory.c +60 −4 Original line number Diff line number Diff line Loading @@ -5,9 +5,17 @@ #include <linux/spinlock.h> #include <asm/unaccepted_memory.h> /* Protects unaccepted memory bitmap */ /* Protects unaccepted memory bitmap and accepting_list */ 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. * Loading @@ -24,6 +32,7 @@ void accept_memory(phys_addr_t start, phys_addr_t end) { struct efi_unaccepted_memory *unaccepted; unsigned long range_start, range_end; struct accept_range range, *entry; unsigned long flags; u64 unit_size; Loading Loading @@ -78,20 +87,67 @@ void accept_memory(phys_addr_t start, phys_addr_t end) if (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); /* * 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, DIV_ROUND_UP(end, unit_size)) { range.end) { unsigned long phys_start, phys_end; unsigned long len = range_end - range_start; phys_start = range_start * 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); spin_lock(&unaccepted_memory_lock); bitmap_clear(unaccepted->bitmap, range_start, len); } list_del(&range.list); spin_unlock_irqrestore(&unaccepted_memory_lock, flags); } Loading