Skip to content

Commit

Permalink
Merge tag 'efi-next' of git://git.kernel.org/pub/scm/linux/kernel/git…
Browse files Browse the repository at this point in the history
…/mfleming/efi into x86/efi

Pull EFI changes from Matt Fleming:

  - Use idiomatic negative error values in efivar_create_sysfs_entry()
    instead of returning '1' to indicate error. (Dan Carpenter)

  - Implement new support to expose the EFI System Resource Tables in sysfs,
    which provides information for performing firmware updates. (Peter Jones)

  - Documentation cleanup in the EFI handover protocol section which
    falsely claimed that 'cmdline_size' needed to be filled out by the
    boot loader. (Alex Smith)

  - Align the order of SMBIOS tables in /sys/firmware/efi/systab to match
    the way that we do things for ACPI and add documentation to
    Documentation/ABI. (Jean Delvare)

Signed-off-by: Ingo Molnar <mingo@kernel.org>
  • Loading branch information
Ingo Molnar committed Jun 2, 2015
2 parents c46a024 + c208358 commit 6b33033
Show file tree
Hide file tree
Showing 9 changed files with 667 additions and 10 deletions.
10 changes: 10 additions & 0 deletions Documentation/ABI/testing/sysfs-firmware-efi
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,13 @@ Contact: Dave Young <dyoung@redhat.com>
Description: It shows the physical address of config table entry in the EFI
system table.
Users: Kexec

What: /sys/firmware/efi/systab
Date: April 2005
Contact: linux-efi@vger.kernel.org
Description: Displays the physical addresses of all EFI Configuration
Tables found via the EFI System Table. The order in
which the tables are printed forms an ABI and newer
versions are always printed first, i.e. ACPI20 comes
before ACPI.
Users: dmidecode
81 changes: 81 additions & 0 deletions Documentation/ABI/testing/sysfs-firmware-efi-esrt
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
What: /sys/firmware/efi/esrt/
Date: February 2015
Contact: Peter Jones <pjones@redhat.com>
Description: Provides userland access to read the EFI System Resource Table
(ESRT), a catalog of firmware for which can be updated with
the UEFI UpdateCapsule mechanism described in section 7.5 of
the UEFI Standard.
Users: fwupdate - https://github.com/rhinstaller/fwupdate

What: /sys/firmware/efi/esrt/fw_resource_count
Date: February 2015
Contact: Peter Jones <pjones@redhat.com>
Description: The number of entries in the ESRT

What: /sys/firmware/efi/esrt/fw_resource_count_max
Date: February 2015
Contact: Peter Jones <pjones@redhat.com>
Description: The maximum number of entries that /could/ be registered
in the allocation the table is currently in. This is
really only useful to the system firmware itself.

What: /sys/firmware/efi/esrt/fw_resource_version
Date: February 2015
Contact: Peter Jones <pjones@redhat.com>
Description: The version of the ESRT structure provided by the firmware.

What: /sys/firmware/efi/esrt/entries/entry$N/
Date: February 2015
Contact: Peter Jones <pjones@redhat.com>
Description: Each ESRT entry is identified by a GUID, and each gets a
subdirectory under entries/ .
example: /sys/firmware/efi/esrt/entries/entry0/

What: /sys/firmware/efi/esrt/entries/entry$N/fw_type
Date: February 2015
Contact: Peter Jones <pjones@redhat.com>
Description: What kind of firmware entry this is:
0 - Unknown
1 - System Firmware
2 - Device Firmware
3 - UEFI Driver

What: /sys/firmware/efi/esrt/entries/entry$N/fw_class
Date: February 2015
Contact: Peter Jones <pjones@redhat.com>
Description: This is the entry's guid, and will match the directory name.

What: /sys/firmware/efi/esrt/entries/entry$N/fw_version
Date: February 2015
Contact: Peter Jones <pjones@redhat.com>
Description: The version of the firmware currently installed. This is a
32-bit unsigned integer.

What: /sys/firmware/efi/esrt/entries/entry$N/lowest_supported_fw_version
Date: February 2015
Contact: Peter Jones <pjones@redhat.com>
Description: The lowest version of the firmware that can be installed.

What: /sys/firmware/efi/esrt/entries/entry$N/capsule_flags
Date: February 2015
Contact: Peter Jones <pjones@redhat.com>
Description: Flags that must be passed to UpdateCapsule()

What: /sys/firmware/efi/esrt/entries/entry$N/last_attempt_version
Date: February 2015
Contact: Peter Jones <pjones@redhat.com>
Description: The last firmware version for which an update was attempted.

What: /sys/firmware/efi/esrt/entries/entry$N/last_attempt_status
Date: February 2015
Contact: Peter Jones <pjones@redhat.com>
Description: The result of the last firmware update attempt for the
firmware resource entry.
0 - Success
1 - Insufficient resources
2 - Incorrect version
3 - Invalid format
4 - Authentication error
5 - AC power event
6 - Battery power event

1 change: 0 additions & 1 deletion Documentation/x86/boot.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1124,7 +1124,6 @@ The boot loader *must* fill out the following fields in bp,

o hdr.code32_start
o hdr.cmd_line_ptr
o hdr.cmdline_size
o hdr.ramdisk_image (if applicable)
o hdr.ramdisk_size (if applicable)

Expand Down
2 changes: 2 additions & 0 deletions arch/x86/platform/efi/efi.c
Original file line number Diff line number Diff line change
Expand Up @@ -501,6 +501,8 @@ void __init efi_init(void)

if (efi_enabled(EFI_DBG))
print_efi_memmap();

efi_esrt_init();
}

void __init efi_late_init(void)
Expand Down
2 changes: 1 addition & 1 deletion drivers/firmware/efi/Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#
# Makefile for linux kernel
#
obj-$(CONFIG_EFI) += efi.o vars.o reboot.o
obj-$(CONFIG_EFI) += efi.o esrt.o vars.o reboot.o
obj-$(CONFIG_EFI_VARS) += efivars.o
obj-$(CONFIG_EFI_VARS_PSTORE) += efi-pstore.o
obj-$(CONFIG_UEFI_CPER) += cper.o
Expand Down
91 changes: 88 additions & 3 deletions drivers/firmware/efi/efi.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand All @@ -64,7 +65,7 @@ static int __init parse_efi_cmdline(char *str)
}
early_param("efi", parse_efi_cmdline);

static struct kobject *efi_kobj;
struct kobject *efi_kobj;
static struct kobject *efivars_kobj;

/*
Expand All @@ -85,10 +86,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)
Expand Down Expand Up @@ -232,6 +238,84 @@ static int __init efisubsys_init(void)

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
Expand Down Expand Up @@ -274,6 +358,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},
};

Expand Down
11 changes: 6 additions & 5 deletions drivers/firmware/efi/efivars.c
Original file line number Diff line number Diff line change
Expand Up @@ -535,7 +535,7 @@ static ssize_t efivar_delete(struct file *filp, struct kobject *kobj,
* efivar_create_sysfs_entry - create a new entry in sysfs
* @new_var: efivar entry to create
*
* Returns 1 on failure, 0 on success
* Returns 0 on success, negative error code on failure
*/
static int
efivar_create_sysfs_entry(struct efivar_entry *new_var)
Expand All @@ -544,6 +544,7 @@ efivar_create_sysfs_entry(struct efivar_entry *new_var)
char *short_name;
unsigned long variable_name_size;
efi_char16_t *variable_name;
int ret;

variable_name = new_var->var.VariableName;
variable_name_size = ucs2_strlen(variable_name) * sizeof(efi_char16_t);
Expand All @@ -558,7 +559,7 @@ efivar_create_sysfs_entry(struct efivar_entry *new_var)
short_name = kzalloc(short_name_size, GFP_KERNEL);

if (!short_name)
return 1;
return -ENOMEM;

/* Convert Unicode to normal chars (assume top bits are 0),
ala UTF-8 */
Expand All @@ -574,11 +575,11 @@ efivar_create_sysfs_entry(struct efivar_entry *new_var)

new_var->kobj.kset = efivars_kset;

i = kobject_init_and_add(&new_var->kobj, &efivar_ktype,
ret = kobject_init_and_add(&new_var->kobj, &efivar_ktype,
NULL, "%s", short_name);
kfree(short_name);
if (i)
return 1;
if (ret)
return ret;

kobject_uevent(&new_var->kobj, KOBJ_ADD);
efivar_entry_add(new_var, &efivar_sysfs_list);
Expand Down
Loading

0 comments on commit 6b33033

Please sign in to comment.