Commit cb03dc09 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull x86 fixes from Peter Anvin:
 "Another set of fixes, the biggest bit of this is yet another tweak to
  the UEFI anti-bricking code; apparently we finally got some feedback
  from Samsung as to what makes at least their systems fail.  This set
  should actually fix the boot regressions that some other systems (e.g.
  SGI) have exhibited.

  Other than that, there is a patch to avoid a panic with particularly
  unhappy memory layouts and two minor protocol fixes which may or may
  not be manifest bugs"

* 'x86-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  x86: Fix typo in kexec register clearing
  x86, relocs: Move __vvar_page from S_ABS to S_REL
  Modify UEFI anti-bricking code
  x86: Fix adjust_range_size_mask calling position
parents cb7e9704 45df901c
...@@ -251,51 +251,6 @@ static void find_bits(unsigned long mask, u8 *pos, u8 *size) ...@@ -251,51 +251,6 @@ static void find_bits(unsigned long mask, u8 *pos, u8 *size)
*size = len; *size = len;
} }
static efi_status_t setup_efi_vars(struct boot_params *params)
{
struct setup_data *data;
struct efi_var_bootdata *efidata;
u64 store_size, remaining_size, var_size;
efi_status_t status;
if (sys_table->runtime->hdr.revision < EFI_2_00_SYSTEM_TABLE_REVISION)
return EFI_UNSUPPORTED;
data = (struct setup_data *)(unsigned long)params->hdr.setup_data;
while (data && data->next)
data = (struct setup_data *)(unsigned long)data->next;
status = efi_call_phys4((void *)sys_table->runtime->query_variable_info,
EFI_VARIABLE_NON_VOLATILE |
EFI_VARIABLE_BOOTSERVICE_ACCESS |
EFI_VARIABLE_RUNTIME_ACCESS, &store_size,
&remaining_size, &var_size);
if (status != EFI_SUCCESS)
return status;
status = efi_call_phys3(sys_table->boottime->allocate_pool,
EFI_LOADER_DATA, sizeof(*efidata), &efidata);
if (status != EFI_SUCCESS)
return status;
efidata->data.type = SETUP_EFI_VARS;
efidata->data.len = sizeof(struct efi_var_bootdata) -
sizeof(struct setup_data);
efidata->data.next = 0;
efidata->store_size = store_size;
efidata->remaining_size = remaining_size;
efidata->max_var_size = var_size;
if (data)
data->next = (unsigned long)efidata;
else
params->hdr.setup_data = (unsigned long)efidata;
}
static efi_status_t setup_efi_pci(struct boot_params *params) static efi_status_t setup_efi_pci(struct boot_params *params)
{ {
efi_pci_io_protocol *pci; efi_pci_io_protocol *pci;
...@@ -1202,8 +1157,6 @@ struct boot_params *efi_main(void *handle, efi_system_table_t *_table, ...@@ -1202,8 +1157,6 @@ struct boot_params *efi_main(void *handle, efi_system_table_t *_table,
setup_graphics(boot_params); setup_graphics(boot_params);
setup_efi_vars(boot_params);
setup_efi_pci(boot_params); setup_efi_pci(boot_params);
status = efi_call_phys3(sys_table->boottime->allocate_pool, status = efi_call_phys3(sys_table->boottime->allocate_pool,
......
...@@ -102,13 +102,6 @@ extern void efi_call_phys_epilog(void); ...@@ -102,13 +102,6 @@ extern void efi_call_phys_epilog(void);
extern void efi_unmap_memmap(void); extern void efi_unmap_memmap(void);
extern void efi_memory_uc(u64 addr, unsigned long size); extern void efi_memory_uc(u64 addr, unsigned long size);
struct efi_var_bootdata {
struct setup_data data;
u64 store_size;
u64 remaining_size;
u64 max_var_size;
};
#ifdef CONFIG_EFI #ifdef CONFIG_EFI
static inline bool efi_is_native(void) static inline bool efi_is_native(void)
......
...@@ -6,7 +6,6 @@ ...@@ -6,7 +6,6 @@
#define SETUP_E820_EXT 1 #define SETUP_E820_EXT 1
#define SETUP_DTB 2 #define SETUP_DTB 2
#define SETUP_PCI 3 #define SETUP_PCI 3
#define SETUP_EFI_VARS 4
/* ram_size flags */ /* ram_size flags */
#define RAMDISK_IMAGE_START_MASK 0x07FF #define RAMDISK_IMAGE_START_MASK 0x07FF
......
...@@ -160,7 +160,7 @@ identity_mapped: ...@@ -160,7 +160,7 @@ identity_mapped:
xorq %rbp, %rbp xorq %rbp, %rbp
xorq %r8, %r8 xorq %r8, %r8
xorq %r9, %r9 xorq %r9, %r9
xorq %r10, %r9 xorq %r10, %r10
xorq %r11, %r11 xorq %r11, %r11
xorq %r12, %r12 xorq %r12, %r12
xorq %r13, %r13 xorq %r13, %r13
......
...@@ -277,6 +277,9 @@ static int __meminit split_mem_range(struct map_range *mr, int nr_range, ...@@ -277,6 +277,9 @@ static int __meminit split_mem_range(struct map_range *mr, int nr_range,
end_pfn = limit_pfn; end_pfn = limit_pfn;
nr_range = save_mr(mr, nr_range, start_pfn, end_pfn, 0); nr_range = save_mr(mr, nr_range, start_pfn, end_pfn, 0);
if (!after_bootmem)
adjust_range_page_size_mask(mr, nr_range);
/* try to merge same page size and continuous */ /* try to merge same page size and continuous */
for (i = 0; nr_range > 1 && i < nr_range - 1; i++) { for (i = 0; nr_range > 1 && i < nr_range - 1; i++) {
unsigned long old_start; unsigned long old_start;
...@@ -291,9 +294,6 @@ static int __meminit split_mem_range(struct map_range *mr, int nr_range, ...@@ -291,9 +294,6 @@ static int __meminit split_mem_range(struct map_range *mr, int nr_range,
nr_range--; nr_range--;
} }
if (!after_bootmem)
adjust_range_page_size_mask(mr, nr_range);
for (i = 0; i < nr_range; i++) for (i = 0; i < nr_range; i++)
printk(KERN_DEBUG " [mem %#010lx-%#010lx] page %s\n", printk(KERN_DEBUG " [mem %#010lx-%#010lx] page %s\n",
mr[i].start, mr[i].end - 1, mr[i].start, mr[i].end - 1,
......
...@@ -42,7 +42,6 @@ ...@@ -42,7 +42,6 @@
#include <linux/io.h> #include <linux/io.h>
#include <linux/reboot.h> #include <linux/reboot.h>
#include <linux/bcd.h> #include <linux/bcd.h>
#include <linux/ucs2_string.h>
#include <asm/setup.h> #include <asm/setup.h>
#include <asm/efi.h> #include <asm/efi.h>
...@@ -54,12 +53,12 @@ ...@@ -54,12 +53,12 @@
#define EFI_DEBUG 1 #define EFI_DEBUG 1
/* #define EFI_MIN_RESERVE 5120
* There's some additional metadata associated with each
* variable. Intel's reference implementation is 60 bytes - bump that #define EFI_DUMMY_GUID \
* to account for potential alignment constraints EFI_GUID(0x4424ac57, 0xbe4b, 0x47dd, 0x9e, 0x97, 0xed, 0x50, 0xf0, 0x9f, 0x92, 0xa9)
*/
#define VAR_METADATA_SIZE 64 static efi_char16_t efi_dummy_name[6] = { 'D', 'U', 'M', 'M', 'Y', 0 };
struct efi __read_mostly efi = { struct efi __read_mostly efi = {
.mps = EFI_INVALID_TABLE_ADDR, .mps = EFI_INVALID_TABLE_ADDR,
...@@ -79,13 +78,6 @@ struct efi_memory_map memmap; ...@@ -79,13 +78,6 @@ struct efi_memory_map memmap;
static struct efi efi_phys __initdata; static struct efi efi_phys __initdata;
static efi_system_table_t efi_systab __initdata; static efi_system_table_t efi_systab __initdata;
static u64 efi_var_store_size;
static u64 efi_var_remaining_size;
static u64 efi_var_max_var_size;
static u64 boot_used_size;
static u64 boot_var_size;
static u64 active_size;
unsigned long x86_efi_facility; unsigned long x86_efi_facility;
/* /*
...@@ -188,53 +180,8 @@ static efi_status_t virt_efi_get_next_variable(unsigned long *name_size, ...@@ -188,53 +180,8 @@ static efi_status_t virt_efi_get_next_variable(unsigned long *name_size,
efi_char16_t *name, efi_char16_t *name,
efi_guid_t *vendor) efi_guid_t *vendor)
{ {
efi_status_t status; return efi_call_virt3(get_next_variable,
static bool finished = false; name_size, name, vendor);
static u64 var_size;
status = efi_call_virt3(get_next_variable,
name_size, name, vendor);
if (status == EFI_NOT_FOUND) {
finished = true;
if (var_size < boot_used_size) {
boot_var_size = boot_used_size - var_size;
active_size += boot_var_size;
} else {
printk(KERN_WARNING FW_BUG "efi: Inconsistent initial sizes\n");
}
}
if (boot_used_size && !finished) {
unsigned long size = 0;
u32 attr;
efi_status_t s;
void *tmp;
s = virt_efi_get_variable(name, vendor, &attr, &size, NULL);
if (s != EFI_BUFFER_TOO_SMALL || !size)
return status;
tmp = kmalloc(size, GFP_ATOMIC);
if (!tmp)
return status;
s = virt_efi_get_variable(name, vendor, &attr, &size, tmp);
if (s == EFI_SUCCESS && (attr & EFI_VARIABLE_NON_VOLATILE)) {
var_size += size;
var_size += ucs2_strsize(name, 1024);
active_size += size;
active_size += VAR_METADATA_SIZE;
active_size += ucs2_strsize(name, 1024);
}
kfree(tmp);
}
return status;
} }
static efi_status_t virt_efi_set_variable(efi_char16_t *name, static efi_status_t virt_efi_set_variable(efi_char16_t *name,
...@@ -243,34 +190,9 @@ static efi_status_t virt_efi_set_variable(efi_char16_t *name, ...@@ -243,34 +190,9 @@ static efi_status_t virt_efi_set_variable(efi_char16_t *name,
unsigned long data_size, unsigned long data_size,
void *data) void *data)
{ {
efi_status_t status; return efi_call_virt5(set_variable,
u32 orig_attr = 0; name, vendor, attr,
unsigned long orig_size = 0; data_size, data);
status = virt_efi_get_variable(name, vendor, &orig_attr, &orig_size,
NULL);
if (status != EFI_BUFFER_TOO_SMALL)
orig_size = 0;
status = efi_call_virt5(set_variable,
name, vendor, attr,
data_size, data);
if (status == EFI_SUCCESS) {
if (orig_size) {
active_size -= orig_size;
active_size -= ucs2_strsize(name, 1024);
active_size -= VAR_METADATA_SIZE;
}
if (data_size) {
active_size += data_size;
active_size += ucs2_strsize(name, 1024);
active_size += VAR_METADATA_SIZE;
}
}
return status;
} }
static efi_status_t virt_efi_query_variable_info(u32 attr, static efi_status_t virt_efi_query_variable_info(u32 attr,
...@@ -786,9 +708,6 @@ void __init efi_init(void) ...@@ -786,9 +708,6 @@ void __init efi_init(void)
char vendor[100] = "unknown"; char vendor[100] = "unknown";
int i = 0; int i = 0;
void *tmp; void *tmp;
struct setup_data *data;
struct efi_var_bootdata *efi_var_data;
u64 pa_data;
#ifdef CONFIG_X86_32 #ifdef CONFIG_X86_32
if (boot_params.efi_info.efi_systab_hi || if (boot_params.efi_info.efi_systab_hi ||
...@@ -806,22 +725,6 @@ void __init efi_init(void) ...@@ -806,22 +725,6 @@ void __init efi_init(void)
if (efi_systab_init(efi_phys.systab)) if (efi_systab_init(efi_phys.systab))
return; return;
pa_data = boot_params.hdr.setup_data;
while (pa_data) {
data = early_ioremap(pa_data, sizeof(*efi_var_data));
if (data->type == SETUP_EFI_VARS) {
efi_var_data = (struct efi_var_bootdata *)data;
efi_var_store_size = efi_var_data->store_size;
efi_var_remaining_size = efi_var_data->remaining_size;
efi_var_max_var_size = efi_var_data->max_var_size;
}
pa_data = data->next;
early_iounmap(data, sizeof(*efi_var_data));
}
boot_used_size = efi_var_store_size - efi_var_remaining_size;
set_bit(EFI_SYSTEM_TABLES, &x86_efi_facility); set_bit(EFI_SYSTEM_TABLES, &x86_efi_facility);
/* /*
...@@ -1085,6 +988,13 @@ void __init efi_enter_virtual_mode(void) ...@@ -1085,6 +988,13 @@ void __init efi_enter_virtual_mode(void)
runtime_code_page_mkexec(); runtime_code_page_mkexec();
kfree(new_memmap); kfree(new_memmap);
/* clean DUMMY object */
efi.set_variable(efi_dummy_name, &EFI_DUMMY_GUID,
EFI_VARIABLE_NON_VOLATILE |
EFI_VARIABLE_BOOTSERVICE_ACCESS |
EFI_VARIABLE_RUNTIME_ACCESS,
0, NULL);
} }
/* /*
...@@ -1136,33 +1046,65 @@ efi_status_t efi_query_variable_store(u32 attributes, unsigned long size) ...@@ -1136,33 +1046,65 @@ efi_status_t efi_query_variable_store(u32 attributes, unsigned long size)
efi_status_t status; efi_status_t status;
u64 storage_size, remaining_size, max_size; u64 storage_size, remaining_size, max_size;
if (!(attributes & EFI_VARIABLE_NON_VOLATILE))
return 0;
status = efi.query_variable_info(attributes, &storage_size, status = efi.query_variable_info(attributes, &storage_size,
&remaining_size, &max_size); &remaining_size, &max_size);
if (status != EFI_SUCCESS) if (status != EFI_SUCCESS)
return status; return status;
if (!max_size && remaining_size > size)
printk_once(KERN_ERR FW_BUG "Broken EFI implementation"
" is returning MaxVariableSize=0\n");
/* /*
* Some firmware implementations refuse to boot if there's insufficient * Some firmware implementations refuse to boot if there's insufficient
* space in the variable store. We account for that by refusing the * space in the variable store. We account for that by refusing the
* write if permitting it would reduce the available space to under * write if permitting it would reduce the available space to under
* 50%. However, some firmware won't reclaim variable space until * 5KB. This figure was provided by Samsung, so should be safe.
* after the used (not merely the actively used) space drops below
* a threshold. We can approximate that case with the value calculated
* above. If both the firmware and our calculations indicate that the
* available space would drop below 50%, refuse the write.
*/ */
if ((remaining_size - size < EFI_MIN_RESERVE) &&
!efi_no_storage_paranoia) {
/*
* Triggering garbage collection may require that the firmware
* generate a real EFI_OUT_OF_RESOURCES error. We can force
* that by attempting to use more space than is available.
*/
unsigned long dummy_size = remaining_size + 1024;
void *dummy = kmalloc(dummy_size, GFP_ATOMIC);
status = efi.set_variable(efi_dummy_name, &EFI_DUMMY_GUID,
EFI_VARIABLE_NON_VOLATILE |
EFI_VARIABLE_BOOTSERVICE_ACCESS |
EFI_VARIABLE_RUNTIME_ACCESS,
dummy_size, dummy);
if (status == EFI_SUCCESS) {
/*
* This should have failed, so if it didn't make sure
* that we delete it...
*/
efi.set_variable(efi_dummy_name, &EFI_DUMMY_GUID,
EFI_VARIABLE_NON_VOLATILE |
EFI_VARIABLE_BOOTSERVICE_ACCESS |
EFI_VARIABLE_RUNTIME_ACCESS,
0, dummy);
}
if (!storage_size || size > remaining_size || /*
(max_size && size > max_size)) * The runtime code may now have triggered a garbage collection
return EFI_OUT_OF_RESOURCES; * run, so check the variable info again
*/
status = efi.query_variable_info(attributes, &storage_size,
&remaining_size, &max_size);
if (!efi_no_storage_paranoia && if (status != EFI_SUCCESS)
((active_size + size + VAR_METADATA_SIZE > storage_size / 2) && return status;
(remaining_size - size < storage_size / 2)))
return EFI_OUT_OF_RESOURCES; /*
* There still isn't enough room, so return an error
*/
if (remaining_size - size < EFI_MIN_RESERVE)
return EFI_OUT_OF_RESOURCES;
}
return EFI_SUCCESS; return EFI_SUCCESS;
} }
......
...@@ -42,9 +42,6 @@ static const char * const sym_regex_kernel[S_NSYMTYPES] = { ...@@ -42,9 +42,6 @@ static const char * const sym_regex_kernel[S_NSYMTYPES] = {
"^(xen_irq_disable_direct_reloc$|" "^(xen_irq_disable_direct_reloc$|"
"xen_save_fl_direct_reloc$|" "xen_save_fl_direct_reloc$|"
"VDSO|" "VDSO|"
#if ELF_BITS == 64
"__vvar_page|"
#endif
"__crc_)", "__crc_)",
/* /*
...@@ -72,6 +69,7 @@ static const char * const sym_regex_kernel[S_NSYMTYPES] = { ...@@ -72,6 +69,7 @@ static const char * const sym_regex_kernel[S_NSYMTYPES] = {
"__per_cpu_load|" "__per_cpu_load|"
"init_per_cpu__.*|" "init_per_cpu__.*|"
"__end_rodata_hpage_align|" "__end_rodata_hpage_align|"
"__vvar_page|"
#endif #endif
"_end)$" "_end)$"
}; };
......
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