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

Commit 926172d4 authored by Dave Young's avatar Dave Young Committed by Matt Fleming
Browse files

efi: Export EFI runtime memory mapping to sysfs



kexec kernel will need exactly same mapping for EFI runtime memory
ranges. Thus here export the runtime ranges mapping to sysfs,
kexec-tools will assemble them and pass to 2nd kernel via setup_data.

Introducing a new directory /sys/firmware/efi/runtime-map just like
/sys/firmware/memmap. Containing below attribute in each file of that
directory:

attribute  num_pages  phys_addr  type  virt_addr

Signed-off-by: default avatarDave Young <dyoung@redhat.com>
Tested-by: default avatarToshi Kani <toshi.kani@hp.com>
Signed-off-by: default avatarMatt Fleming <matt.fleming@intel.com>
parent a0998eb1
Loading
Loading
Loading
Loading
+34 −0
Original line number Original line Diff line number Diff line
What:		/sys/firmware/efi/runtime-map/
Date:		December 2013
Contact:	Dave Young <dyoung@redhat.com>
Description:	Switching efi runtime services to virtual mode requires
		that all efi memory ranges which have the runtime attribute
		bit set to be mapped to virtual addresses.

		The efi runtime services can only be switched to virtual
		mode once without rebooting. The kexec kernel must maintain
		the same physical to virtual address mappings as the first
		kernel. The mappings are exported to sysfs so userspace tools
		can reassemble them and pass them into the kexec kernel.

		/sys/firmware/efi/runtime-map/ is the directory the kernel
		exports that information in.

		subdirectories are named with the number of the memory range:

			/sys/firmware/efi/runtime-map/0
			/sys/firmware/efi/runtime-map/1
			/sys/firmware/efi/runtime-map/2
			/sys/firmware/efi/runtime-map/3
			...

		Each subdirectory contains five files:

		attribute : The attributes of the memory range.
		num_pages : The size of the memory range in pages.
		phys_addr : The physical address of the memory range.
		type      : The type of the memory range.
		virt_addr : The virtual address of the memory range.

		Above values are all hexadecimal numbers with the '0x' prefix.
Users:		Kexec
+43 −3
Original line number Original line Diff line number Diff line
@@ -76,6 +76,9 @@ static __initdata efi_config_table_type_t arch_tables[] = {
	{NULL_GUID, NULL, NULL},
	{NULL_GUID, NULL, NULL},
};
};


static void *efi_runtime_map;
static int nr_efi_runtime_map;

/*
/*
 * Returns 1 if 'facility' is enabled, 0 otherwise.
 * Returns 1 if 'facility' is enabled, 0 otherwise.
 */
 */
@@ -824,6 +827,39 @@ static void __init get_systab_virt_addr(efi_memory_desc_t *md)
	}
	}
}
}


static int __init save_runtime_map(void)
{
	efi_memory_desc_t *md;
	void *tmp, *p, *q = NULL;
	int count = 0;

	for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
		md = p;

		if (!(md->attribute & EFI_MEMORY_RUNTIME) ||
		    (md->type == EFI_BOOT_SERVICES_CODE) ||
		    (md->type == EFI_BOOT_SERVICES_DATA))
			continue;
		tmp = krealloc(q, (count + 1) * memmap.desc_size, GFP_KERNEL);
		if (!tmp)
			goto out;
		q = tmp;

		memcpy(q + count * memmap.desc_size, md, memmap.desc_size);
		count++;
	}

	efi_runtime_map = q;
	nr_efi_runtime_map = count;
	efi_runtime_map_setup(efi_runtime_map, nr_efi_runtime_map,
			      boot_params.efi_info.efi_memdesc_size);

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

/*
/*
 * Map efi memory ranges for runtime serivce and update new_memmap with virtual
 * Map efi memory ranges for runtime serivce and update new_memmap with virtual
 * addresses.
 * addresses.
@@ -849,7 +885,7 @@ static void * __init efi_map_regions(int *count)
		tmp = krealloc(new_memmap, (*count + 1) * memmap.desc_size,
		tmp = krealloc(new_memmap, (*count + 1) * memmap.desc_size,
			       GFP_KERNEL);
			       GFP_KERNEL);
		if (!tmp)
		if (!tmp)
			goto out_krealloc;
			goto out;
		new_memmap = tmp;
		new_memmap = tmp;
		memcpy(new_memmap + (*count * memmap.desc_size), md,
		memcpy(new_memmap + (*count * memmap.desc_size), md,
		       memmap.desc_size);
		       memmap.desc_size);
@@ -857,7 +893,7 @@ static void * __init efi_map_regions(int *count)
	}
	}


	return new_memmap;
	return new_memmap;
out_krealloc:
out:
	kfree(new_memmap);
	kfree(new_memmap);
	return NULL;
	return NULL;
}
}
@@ -883,7 +919,7 @@ void __init efi_enter_virtual_mode(void)
{
{
	efi_status_t status;
	efi_status_t status;
	void *new_memmap = NULL;
	void *new_memmap = NULL;
	int count = 0;
	int err, count = 0;


	efi.systab = NULL;
	efi.systab = NULL;


@@ -904,6 +940,10 @@ void __init efi_enter_virtual_mode(void)
		return;
		return;
	}
	}


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

	BUG_ON(!efi.systab);
	BUG_ON(!efi.systab);


	efi_setup_page_tables();
	efi_setup_page_tables();
+11 −0
Original line number Original line Diff line number Diff line
@@ -39,4 +39,15 @@ config EFI_VARS_PSTORE_DEFAULT_DISABLE
config UEFI_CPER
config UEFI_CPER
	def_bool n
	def_bool n


config EFI_RUNTIME_MAP
	bool "Export efi runtime maps to sysfs"
	depends on X86 && EFI && KEXEC
	default y
	help
	  Export efi runtime memory maps to /sys/firmware/efi/runtime-map.
	  That memory map is used for example by kexec to set up efi virtual
	  mapping the 2nd kernel, but can also be used for debugging purposes.

	  See also Documentation/ABI/testing/sysfs-firmware-efi-runtime-map.

endmenu
endmenu
+1 −0
Original line number Original line Diff line number Diff line
@@ -5,3 +5,4 @@ obj-y += efi.o vars.o
obj-$(CONFIG_EFI_VARS)			+= efivars.o
obj-$(CONFIG_EFI_VARS)			+= efivars.o
obj-$(CONFIG_EFI_VARS_PSTORE)		+= efi-pstore.o
obj-$(CONFIG_EFI_VARS_PSTORE)		+= efi-pstore.o
obj-$(CONFIG_UEFI_CPER)			+= cper.o
obj-$(CONFIG_UEFI_CPER)			+= cper.o
obj-$(CONFIG_EFI_RUNTIME_MAP)		+= runtime-map.o
+4 −0
Original line number Original line Diff line number Diff line
@@ -167,6 +167,10 @@ static int __init efisubsys_init(void)
		goto err_unregister;
		goto err_unregister;
	}
	}


	error = efi_runtime_map_init(efi_kobj);
	if (error)
		goto err_remove_group;

	/* and the standard mountpoint for efivarfs */
	/* and the standard mountpoint for efivarfs */
	efivars_kobj = kobject_create_and_add("efivars", efi_kobj);
	efivars_kobj = kobject_create_and_add("efivars", efi_kobj);
	if (!efivars_kobj) {
	if (!efivars_kobj) {
Loading