diff options
Diffstat (limited to 'drivers/firmware/efi/efi.c')
| -rw-r--r-- | drivers/firmware/efi/efi.c | 97 | 
1 files changed, 90 insertions, 7 deletions
diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index 3061bb8629dc..9fa8084a7c8d 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c @@ -39,6 +39,7 @@ struct efi __read_mostly efi = {  	.fw_vendor  = EFI_INVALID_TABLE_ADDR,  	.runtime    = EFI_INVALID_TABLE_ADDR,  	.config_table  = EFI_INVALID_TABLE_ADDR, +	.esrt       = EFI_INVALID_TABLE_ADDR,  };  EXPORT_SYMBOL(efi); @@ -64,8 +65,7 @@ static int __init parse_efi_cmdline(char *str)  }  early_param("efi", parse_efi_cmdline); -static struct kobject *efi_kobj; -static struct kobject *efivars_kobj; +struct kobject *efi_kobj;  /*   * Let's not leave out systab information that snuck into @@ -85,10 +85,15 @@ static ssize_t systab_show(struct kobject *kobj,  		str += sprintf(str, "ACPI20=0x%lx\n", efi.acpi20);  	if (efi.acpi != EFI_INVALID_TABLE_ADDR)  		str += sprintf(str, "ACPI=0x%lx\n", efi.acpi); -	if (efi.smbios != EFI_INVALID_TABLE_ADDR) -		str += sprintf(str, "SMBIOS=0x%lx\n", efi.smbios); +	/* +	 * If both SMBIOS and SMBIOS3 entry points are implemented, the +	 * SMBIOS3 entry point shall be preferred, so we list it first to +	 * let applications stop parsing after the first match. +	 */  	if (efi.smbios3 != EFI_INVALID_TABLE_ADDR)  		str += sprintf(str, "SMBIOS3=0x%lx\n", efi.smbios3); +	if (efi.smbios != EFI_INVALID_TABLE_ADDR) +		str += sprintf(str, "SMBIOS=0x%lx\n", efi.smbios);  	if (efi.hcdp != EFI_INVALID_TABLE_ADDR)  		str += sprintf(str, "HCDP=0x%lx\n", efi.hcdp);  	if (efi.boot_info != EFI_INVALID_TABLE_ADDR) @@ -212,10 +217,9 @@ static int __init efisubsys_init(void)  		goto err_remove_group;  	/* and the standard mountpoint for efivarfs */ -	efivars_kobj = kobject_create_and_add("efivars", efi_kobj); -	if (!efivars_kobj) { +	error = sysfs_create_mount_point(efi_kobj, "efivars"); +	if (error) {  		pr_err("efivars: Subsystem registration failed.\n"); -		error = -ENOMEM;  		goto err_remove_group;  	} @@ -232,6 +236,84 @@ err_put:  subsys_initcall(efisubsys_init); +/* + * Find the efi memory descriptor for a given physical address.  Given a + * physicall address, determine if it exists within an EFI Memory Map entry, + * and if so, populate the supplied memory descriptor with the appropriate + * data. + */ +int __init efi_mem_desc_lookup(u64 phys_addr, efi_memory_desc_t *out_md) +{ +	struct efi_memory_map *map = efi.memmap; +	void *p, *e; + +	if (!efi_enabled(EFI_MEMMAP)) { +		pr_err_once("EFI_MEMMAP is not enabled.\n"); +		return -EINVAL; +	} + +	if (!map) { +		pr_err_once("efi.memmap is not set.\n"); +		return -EINVAL; +	} +	if (!out_md) { +		pr_err_once("out_md is null.\n"); +		return -EINVAL; +        } +	if (WARN_ON_ONCE(!map->phys_map)) +		return -EINVAL; +	if (WARN_ON_ONCE(map->nr_map == 0) || WARN_ON_ONCE(map->desc_size == 0)) +		return -EINVAL; + +	e = map->phys_map + map->nr_map * map->desc_size; +	for (p = map->phys_map; p < e; p += map->desc_size) { +		efi_memory_desc_t *md; +		u64 size; +		u64 end; + +		/* +		 * If a driver calls this after efi_free_boot_services, +		 * ->map will be NULL, and the target may also not be mapped. +		 * So just always get our own virtual map on the CPU. +		 * +		 */ +		md = early_memremap((phys_addr_t)p, sizeof (*md)); +		if (!md) { +			pr_err_once("early_memremap(%p, %zu) failed.\n", +				    p, sizeof (*md)); +			return -ENOMEM; +		} + +		if (!(md->attribute & EFI_MEMORY_RUNTIME) && +		    md->type != EFI_BOOT_SERVICES_DATA && +		    md->type != EFI_RUNTIME_SERVICES_DATA) { +			early_memunmap(md, sizeof (*md)); +			continue; +		} + +		size = md->num_pages << EFI_PAGE_SHIFT; +		end = md->phys_addr + size; +		if (phys_addr >= md->phys_addr && phys_addr < end) { +			memcpy(out_md, md, sizeof(*out_md)); +			early_memunmap(md, sizeof (*md)); +			return 0; +		} + +		early_memunmap(md, sizeof (*md)); +	} +	pr_err_once("requested map not found.\n"); +	return -ENOENT; +} + +/* + * Calculate the highest address of an efi memory descriptor. + */ +u64 __init efi_mem_desc_end(efi_memory_desc_t *md) +{ +	u64 size = md->num_pages << EFI_PAGE_SHIFT; +	u64 end = md->phys_addr + size; +	return end; +}  /*   * We can't ioremap data in EFI boot services RAM, because we've already mapped @@ -274,6 +356,7 @@ static __initdata efi_config_table_type_t common_tables[] = {  	{SMBIOS_TABLE_GUID, "SMBIOS", &efi.smbios},  	{SMBIOS3_TABLE_GUID, "SMBIOS 3.0", &efi.smbios3},  	{UGA_IO_PROTOCOL_GUID, "UGA", &efi.uga}, +	{EFI_SYSTEM_RESOURCE_TABLE_GUID, "ESRT", &efi.esrt},  	{NULL_GUID, NULL, NULL},  };  |