Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fabb37c7 authored by Borislav Petkov's avatar Borislav Petkov Committed by Matt Fleming
Browse files

x86/efi: Split efi_enter_virtual_mode



... into a kexec flavor for better code readability and simplicity. The
original one was getting ugly with ifdeffery.

Signed-off-by: default avatarBorislav Petkov <bp@suse.de>
Tested-by: default avatarToshi Kani <toshi.kani@hp.com>
Signed-off-by: default avatarMatt Fleming <matt.fleming@intel.com>
parent b7b898ae
Loading
Loading
Loading
Loading
+98 −50
Original line number Diff line number Diff line
@@ -879,8 +879,9 @@ static void __init get_systab_virt_addr(efi_memory_desc_t *md)
	}
}

static int __init save_runtime_map(void)
static void __init save_runtime_map(void)
{
#ifdef CONFIG_KEXEC
	efi_memory_desc_t *md;
	void *tmp, *p, *q = NULL;
	int count = 0;
@@ -902,28 +903,12 @@ static int __init save_runtime_map(void)
	}

	efi_runtime_map_setup(q, count, memmap.desc_size);
	return;

	return 0;
out:
	kfree(q);
	return -ENOMEM;
}

/*
 * Map efi regions which were passed via setup_data. The virt_addr is a fixed
 * addr which was used in first kernel of a kexec boot.
 */
static void __init efi_map_regions_fixed(void)
{
	void *p;
	efi_memory_desc_t *md;

	for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
		md = p;
		efi_map_region_fixed(md); /* FIXME: add error handling */
		get_systab_virt_addr(md);
	}

	pr_err("Error saving runtime map, efi runtime on kexec non-functional!!\n");
#endif
}

static void *realloc_pages(void *old_memmap, int old_shift)
@@ -989,6 +974,72 @@ static void * __init efi_map_regions(int *count, int *pg_shift)
	return new_memmap;
}

static void __init kexec_enter_virtual_mode(void)
{
#ifdef CONFIG_KEXEC
	efi_memory_desc_t *md;
	void *p;

	efi.systab = NULL;

	/*
	 * We don't do virtual mode, since we don't do runtime services, on
	 * non-native EFI
	 */
	if (!efi_is_native()) {
		efi_unmap_memmap();
		return;
	}

	/*
	* Map efi regions which were passed via setup_data. The virt_addr is a
	* fixed addr which was used in first kernel of a kexec boot.
	*/
	for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
		md = p;
		efi_map_region_fixed(md); /* FIXME: add error handling */
		get_systab_virt_addr(md);
	}

	save_runtime_map();

	BUG_ON(!efi.systab);

	efi_sync_low_kernel_mappings();

	/*
	 * Now that EFI is in virtual mode, update the function
	 * pointers in the runtime service table to the new virtual addresses.
	 *
	 * Call EFI services through wrapper functions.
	 */
	efi.runtime_version = efi_systab.hdr.revision;
	efi.get_time = virt_efi_get_time;
	efi.set_time = virt_efi_set_time;
	efi.get_wakeup_time = virt_efi_get_wakeup_time;
	efi.set_wakeup_time = virt_efi_set_wakeup_time;
	efi.get_variable = virt_efi_get_variable;
	efi.get_next_variable = virt_efi_get_next_variable;
	efi.set_variable = virt_efi_set_variable;
	efi.get_next_high_mono_count = virt_efi_get_next_high_mono_count;
	efi.reset_system = virt_efi_reset_system;
	efi.set_virtual_address_map = NULL;
	efi.query_variable_info = virt_efi_query_variable_info;
	efi.update_capsule = virt_efi_update_capsule;
	efi.query_capsule_caps = virt_efi_query_capsule_caps;

	if (efi_enabled(EFI_OLD_MEMMAP) && (__supported_pte_mask & _PAGE_NX))
		runtime_code_page_mkexec();

	/* 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);
#endif
}

/*
 * This function will switch the EFI runtime services to virtual mode.
 * Essentially, we look through the EFI memmap and map every region that
@@ -1008,11 +1059,12 @@ static void * __init efi_map_regions(int *count, int *pg_shift)
 *
 * Specially for kexec boot, efi runtime maps in previous kernel should
 * be passed in via setup_data. In that case runtime ranges will be mapped
 * to the same virtual addresses as the first kernel.
 * to the same virtual addresses as the first kernel, see
 * kexec_enter_virtual_mode().
 */
void __init efi_enter_virtual_mode(void)
static void __init __efi_enter_virtual_mode(void)
{
	int err, count = 0, pg_shift = 0;
	int count = 0, pg_shift = 0;
	void *new_memmap = NULL;
	efi_status_t status;

@@ -1027,9 +1079,6 @@ void __init efi_enter_virtual_mode(void)
		return;
	}

	if (efi_setup) {
		efi_map_regions_fixed();
	} else {
	efi_merge_regions();
	new_memmap = efi_map_regions(&count, &pg_shift);
	if (!new_memmap) {
@@ -1037,22 +1086,16 @@ void __init efi_enter_virtual_mode(void)
		return;
	}

		err = save_runtime_map();
		if (err)
			pr_err("Error saving runtime map, efi runtime on kexec non-functional!!\n");
	}
	save_runtime_map();

	BUG_ON(!efi.systab);

	if (!efi_setup) {
	if (efi_setup_page_tables(__pa(new_memmap), 1 << pg_shift))
		return;
	}

	efi_sync_low_kernel_mappings();
	efi_dump_pagetable();

	if (!efi_setup) {
	status = phys_efi_set_virtual_address_map(
			memmap.desc_size * count,
			memmap.desc_size,
@@ -1064,7 +1107,6 @@ void __init efi_enter_virtual_mode(void)
			 status);
		panic("EFI call to SetVirtualAddressMap() failed!");
	}
	}

	/*
	 * Now that EFI is in virtual mode, update the function
@@ -1089,7 +1131,6 @@ void __init efi_enter_virtual_mode(void)

	efi_runtime_mkexec();


	/*
	 * We mapped the descriptor array into the EFI pagetable above but we're
	 * not unmapping it here. Here's why:
@@ -1116,7 +1157,6 @@ void __init efi_enter_virtual_mode(void)
	 *
	 * efi_cleanup_page_tables(__pa(new_memmap), 1 << pg_shift);
	 */
	if (!efi_setup)
	free_pages((unsigned long)new_memmap, pg_shift);

	/* clean DUMMY object */
@@ -1127,6 +1167,14 @@ void __init efi_enter_virtual_mode(void)
			 0, NULL);
}

void __init efi_enter_virtual_mode(void)
{
	if (efi_setup)
		kexec_enter_virtual_mode();
	else
		__efi_enter_virtual_mode();
}

/*
 * Convenience functions to obtain memory types and attributes
 */