summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Jones <pjones@redhat.com>2015-03-13 08:09:29 -0400
committerJosh Boyer <jwboyer@fedoraproject.org>2015-03-13 08:31:07 -0400
commitbbf3f54706912de331ed2b7642263b58a18e0d6e (patch)
tree8aba486912aff65bb796241e375fd4ba20cb73d0
parent283bd0665fa547cf17fcf1ba09ec14eae9091749 (diff)
downloadkernel-bbf3f54706912de331ed2b7642263b58a18e0d6e.tar.gz
kernel-bbf3f54706912de331ed2b7642263b58a18e0d6e.tar.xz
kernel-bbf3f54706912de331ed2b7642263b58a18e0d6e.zip
Add ESRT patch here.
Signed-off-by: Peter Jones <pjones@redhat.com>
-rw-r--r--efi-Add-esrt-support.patch764
-rw-r--r--kernel.spec5
2 files changed, 769 insertions, 0 deletions
diff --git a/efi-Add-esrt-support.patch b/efi-Add-esrt-support.patch
new file mode 100644
index 000000000..2b157529c
--- /dev/null
+++ b/efi-Add-esrt-support.patch
@@ -0,0 +1,764 @@
+From: Peter Jones <pjones@redhat.com>
+Date: Tue, 18 Nov 2014 10:18:22 -0500
+Subject: [PATCH] efi: Add esrt support.
+
+Add sysfs files for the EFI System Resource Table (ESRT) under
+/sys/firmware/efi/esrt and for each EFI System Resource Entry under
+entries/ as a subdir.
+
+The EFI System Resource Table (ESRT) provides a read-only catalog of
+system components for which the system accepts firmware upgrades via
+UEFI's "Capsule Update" feature. This module allows userland utilities
+to evaluate what firmware updates can be applied to this system, and
+potentially arrange for those updates to occur.
+
+The ESRT is described as part of the UEFI specification, in version 2.5
+which should be available from http://uefi.org/specifications in early
+2015. If you're a member of the UEFI Forum, information about its
+addition to the standard is available as UEFI Mantis 1090.
+
+For some hardware platforms, additional restrictions may be found at
+http://msdn.microsoft.com/en-us/library/windows/hardware/jj128256.aspx ,
+and additional documentation may be found at
+http://download.microsoft.com/download/5/F/5/5F5D16CD-2530-4289-8019-94C6A20BED3C/windows-uefi-firmware-update-platform.docx
+.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ Documentation/ABI/testing/sysfs-firmware-efi-esrt | 81 ++++
+ arch/x86/platform/efi/efi.c | 2 +
+ drivers/firmware/efi/Makefile | 2 +-
+ drivers/firmware/efi/efi.c | 66 +++-
+ drivers/firmware/efi/esrt.c | 461 ++++++++++++++++++++++
+ include/linux/efi.h | 8 +
+ 6 files changed, 618 insertions(+), 2 deletions(-)
+ create mode 100644 Documentation/ABI/testing/sysfs-firmware-efi-esrt
+ create mode 100644 drivers/firmware/efi/esrt.c
+
+diff --git a/Documentation/ABI/testing/sysfs-firmware-efi-esrt b/Documentation/ABI/testing/sysfs-firmware-efi-esrt
+new file mode 100644
+index 000000000000..6e431d1a4e79
+--- /dev/null
++++ b/Documentation/ABI/testing/sysfs-firmware-efi-esrt
+@@ -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
++
+diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
+index dbc8627a5cdf..b4c9fbbc9270 100644
+--- a/arch/x86/platform/efi/efi.c
++++ b/arch/x86/platform/efi/efi.c
+@@ -492,6 +492,8 @@ void __init efi_init(void)
+ return;
+
+ print_efi_memmap();
++
++ efi_esrt_init();
+ }
+
+ void __init efi_late_init(void)
+diff --git a/drivers/firmware/efi/Makefile b/drivers/firmware/efi/Makefile
+index d8be608a9f3b..26eabbc55341 100644
+--- a/drivers/firmware/efi/Makefile
++++ b/drivers/firmware/efi/Makefile
+@@ -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
+diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c
+index 3061bb8629dc..e54ea20dfb42 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,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;
+
+ /*
+@@ -232,6 +233,68 @@ 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) {
++ /*
++ * If a driver calls this after efi_free_boot_services,
++ * ->map will be NULL.
++ * So just always get our own virtual map on the CPU.
++ */
++ efi_memory_desc_t *md = phys_to_virt((phys_addr_t)p);
++ u64 size = md->num_pages << EFI_PAGE_SHIFT;
++ u64 end = md->phys_addr + size;
++
++ if (!(md->attribute & EFI_MEMORY_RUNTIME) &&
++ md->type != EFI_BOOT_SERVICES_DATA &&
++ md->type != EFI_RUNTIME_SERVICES_DATA)
++ continue;
++ if (phys_addr >= md->phys_addr && phys_addr < end) {
++ memcpy(out_md, md, sizeof(*out_md));
++ return 0;
++ }
++ }
++ 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 +337,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},
+ };
+
+diff --git a/drivers/firmware/efi/esrt.c b/drivers/firmware/efi/esrt.c
+new file mode 100644
+index 000000000000..1053b38f7e46
+--- /dev/null
++++ b/drivers/firmware/efi/esrt.c
+@@ -0,0 +1,461 @@
++/*
++ * esrt.c
++ *
++ * This module exports EFI System Resource Table (ESRT) entries into userspace
++ * through the sysfs file system. The ESRT provides a read-only catalog of
++ * system components for which the system accepts firmware upgrades via UEFI's
++ * "Capsule Update" feature. This module allows userland utilities to evaluate
++ * what firmware updates can be applied to this system, and potentially arrange
++ * for those updates to occur.
++ *
++ * Data is currently found below /sys/firmware/efi/esrt/...
++ */
++#define pr_fmt(fmt) "esrt: " fmt
++
++#include <linux/capability.h>
++#include <linux/device.h>
++#include <linux/efi.h>
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/kobject.h>
++#include <linux/list.h>
++#include <linux/memblock.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/types.h>
++
++struct efi_system_resource_entry_v1 {
++ efi_guid_t fw_class;
++ u32 fw_type;
++ u32 fw_version;
++ u32 lowest_supported_fw_version;
++ u32 capsule_flags;
++ u32 last_attempt_version;
++ u32 last_attempt_status;
++};
++
++/*
++ * _count and _version are what they seem like. _max is actually just
++ * accounting info for the firmware when creating the table; it should never
++ * have been exposed to us. To wit, the spec says:
++ * The maximum number of resource array entries that can be within the
++ * table without reallocating the table, must not be zero.
++ * Since there's no guidance about what that means in terms of memory layout,
++ * it means nothing to us.
++ */
++struct efi_system_resource_table {
++ u32 fw_resource_count;
++ u32 fw_resource_count_max;
++ u64 fw_resource_version;
++ u8 entries[];
++};
++
++static phys_addr_t esrt_data;
++static size_t esrt_data_size;
++
++static struct efi_system_resource_table *esrt;
++
++struct esre_entry {
++ union {
++ struct efi_system_resource_entry_v1 *esre1;
++ } esre;
++
++ struct kobject kobj;
++ struct list_head list;
++};
++
++/* global list of esre_entry. */
++static LIST_HEAD(entry_list);
++
++/* entry attribute */
++struct esre_attribute {
++ struct attribute attr;
++ ssize_t (*show)(struct esre_entry *entry, char *buf);
++ ssize_t (*store)(struct esre_entry *entry,
++ const char *buf, size_t count);
++};
++
++static struct esre_entry *to_entry(struct kobject *kobj)
++{
++ return container_of(kobj, struct esre_entry, kobj);
++}
++
++static struct esre_attribute *to_attr(struct attribute *attr)
++{
++ return container_of(attr, struct esre_attribute, attr);
++}
++
++static ssize_t esre_attr_show(struct kobject *kobj,
++ struct attribute *_attr, char *buf)
++{
++ struct esre_entry *entry = to_entry(kobj);
++ struct esre_attribute *attr = to_attr(_attr);
++
++ /* Don't tell normal users what firmware versions we've got... */
++ if (!capable(CAP_SYS_ADMIN))
++ return -EACCES;
++
++ return attr->show(entry, buf);
++}
++
++static const struct sysfs_ops esre_attr_ops = {
++ .show = esre_attr_show,
++};
++
++/* Generic ESRT Entry ("ESRE") support. */
++static ssize_t esre_fw_class_show(struct esre_entry *entry, char *buf)
++{
++ char *str = buf;
++
++ efi_guid_to_str(&entry->esre.esre1->fw_class, str);
++ str += strlen(str);
++ str += sprintf(str, "\n");
++
++ return str - buf;
++}
++
++static struct esre_attribute esre_fw_class = __ATTR(fw_class, 0400,
++ esre_fw_class_show, NULL);
++
++#define esre_attr_decl(name, size, fmt) \
++static ssize_t esre_##name##_show(struct esre_entry *entry, char *buf) \
++{ \
++ return sprintf(buf, fmt "\n", \
++ le##size##_to_cpu(entry->esre.esre1->name)); \
++} \
++\
++static struct esre_attribute esre_##name = __ATTR(name, 0400, \
++ esre_##name##_show, NULL)
++
++esre_attr_decl(fw_type, 32, "%u");
++esre_attr_decl(fw_version, 32, "%u");
++esre_attr_decl(lowest_supported_fw_version, 32, "%u");
++esre_attr_decl(capsule_flags, 32, "0x%x");
++esre_attr_decl(last_attempt_version, 32, "%u");
++esre_attr_decl(last_attempt_status, 32, "%u");
++
++static struct attribute *esre1_attrs[] = {
++ &esre_fw_class.attr,
++ &esre_fw_type.attr,
++ &esre_fw_version.attr,
++ &esre_lowest_supported_fw_version.attr,
++ &esre_capsule_flags.attr,
++ &esre_last_attempt_version.attr,
++ &esre_last_attempt_status.attr,
++ NULL
++};
++static void esre_release(struct kobject *kobj)
++{
++ struct esre_entry *entry = to_entry(kobj);
++
++ list_del(&entry->list);
++ kfree(entry);
++}
++
++static struct kobj_type esre1_ktype = {
++ .release = esre_release,
++ .sysfs_ops = &esre_attr_ops,
++ .default_attrs = esre1_attrs,
++};
++
++
++static struct kobject *esrt_kobj;
++static struct kset *esrt_kset;
++
++static int esre_create_sysfs_entry(void *esre, int entry_num)
++{
++ int rc = 0;
++ struct esre_entry *entry;
++ char name[20];
++
++ entry = kzalloc(sizeof(*entry), GFP_KERNEL);
++ if (!entry)
++ return -ENOMEM;
++
++ sprintf(name, "entry%d", entry_num);
++
++ entry->kobj.kset = esrt_kset;
++
++ if (esrt->fw_resource_version == 1) {
++ entry->esre.esre1 = esre;
++ rc = kobject_init_and_add(&entry->kobj, &esre1_ktype, NULL,
++ "%s", name);
++ }
++ if (rc) {
++ kfree(entry);
++ return rc;
++ }
++
++ list_add_tail(&entry->list, &entry_list);
++ return 0;
++}
++
++/* support for displaying ESRT fields at the top level */
++#define esrt_attr_decl(name, size, fmt) \
++static ssize_t esrt_##name##_show(struct kobject *kobj, \
++ struct kobj_attribute *attr, char *buf)\
++{ \
++ return sprintf(buf, fmt "\n", le##size##_to_cpu(esrt->name)); \
++} \
++\
++static struct kobj_attribute esrt_##name = __ATTR(name, 0400, \
++ esrt_##name##_show, NULL)
++
++esrt_attr_decl(fw_resource_count, 32, "%u");
++esrt_attr_decl(fw_resource_count_max, 32, "%u");
++esrt_attr_decl(fw_resource_version, 64, "%llu");
++
++static struct attribute *esrt_attrs[] = {
++ &esrt_fw_resource_count.attr,
++ &esrt_fw_resource_count_max.attr,
++ &esrt_fw_resource_version.attr,
++ NULL,
++};
++
++static inline int esrt_table_exists(void)
++{
++ if (!efi_enabled(EFI_CONFIG_TABLES))
++ return 0;
++ if (efi.esrt == EFI_INVALID_TABLE_ADDR)
++ return 0;
++ return 1;
++}
++
++static umode_t esrt_attr_is_visible(struct kobject *kobj,
++ struct attribute *attr, int n)
++{
++ if (!esrt_table_exists())
++ return 0;
++ return attr->mode;
++}
++
++static struct attribute_group esrt_attr_group = {
++ .attrs = esrt_attrs,
++ .is_visible = esrt_attr_is_visible,
++};
++
++/*
++ * remap the table, copy it to kmalloced pages, and unmap it.
++ */
++void __init efi_esrt_init(void)
++{
++ void *va;
++ struct efi_system_resource_table tmpesrt;
++ struct efi_system_resource_entry_v1 *v1_entries;
++ size_t size, max, entry_size, entries_size;
++ efi_memory_desc_t md;
++ int rc;
++
++ pr_debug("esrt-init: loading.\n");
++ if (!esrt_table_exists())
++ return;
++
++ rc = efi_mem_desc_lookup(efi.esrt, &md);
++ if (rc < 0) {
++ pr_err("ESRT header is not in the memory map.\n");
++ return;
++ }
++
++ max = efi_mem_desc_end(&md);
++ if (max < efi.esrt) {
++ pr_err("EFI memory descriptor is invalid. (esrt: %p max: %p)\n",
++ (void *)efi.esrt, (void *)max);
++ return;
++ }
++
++ size = sizeof(*esrt);
++ max -= efi.esrt;
++
++ if (max < size) {
++ pr_err("ESRT header doen't fit on single memory map entry. (size: %zu max: %zu)\n",
++ size, max);
++ return;
++ }
++
++ va = early_memremap(efi.esrt, size);
++ if (!va) {
++ pr_err("early_memremap(%p, %zu) failed.\n", (void *)efi.esrt,
++ size);
++ return;
++ }
++
++ memcpy(&tmpesrt, va, sizeof(tmpesrt));
++
++ if (tmpesrt.fw_resource_version == 1) {
++ entry_size = sizeof (*v1_entries);
++ } else {
++ pr_err("Unsupported ESRT version %lld.\n",
++ tmpesrt.fw_resource_version);
++ return;
++ }
++
++ if (tmpesrt.fw_resource_count > 0 && max - size < entry_size) {
++ pr_err("ESRT memory map entry can only hold the header. (max: %zu size: %zu)\n",
++ max - size, entry_size);
++ goto err_memunmap;
++ }
++
++ /*
++ * The format doesn't really give us any boundary to test here,
++ * so I'm making up 128 as the max number of individually updatable
++ * components we support.
++ * 128 should be pretty excessive, but there's still some chance
++ * somebody will do that someday and we'll need to raise this.
++ */
++ if (tmpesrt.fw_resource_count > 128) {
++ pr_err("ESRT says fw_resource_count has very large value %d.\n",
++ tmpesrt.fw_resource_count);
++ goto err_memunmap;
++ }
++
++ /*
++ * We know it can't be larger than N * sizeof() here, and N is limited
++ * by the previous test to a small number, so there's no overflow.
++ */
++ entries_size = tmpesrt.fw_resource_count * entry_size;
++ if (max < size + entries_size) {
++ pr_err("ESRT does not fit on single memory map entry (size: %zu max: %zu)\n",
++ size, max);
++ goto err_memunmap;
++ }
++
++ /* remap it with our (plausible) new pages */
++ early_memunmap(va, size);
++ size += entries_size;
++ va = early_memremap(efi.esrt, size);
++ if (!va) {
++ pr_err("early_memremap(%p, %zu) failed.\n", (void *)efi.esrt,
++ size);
++ return;
++ }
++
++ esrt_data = (phys_addr_t)efi.esrt;
++ esrt_data_size = size;
++
++ pr_info("Reserving ESRT space from %p to %p.\n", (void *)esrt_data,
++ (char *)esrt_data + size);
++ memblock_reserve(esrt_data, esrt_data_size);
++
++ pr_debug("esrt-init: loaded.\n");
++err_memunmap:
++ early_memunmap(va, size);
++}
++
++static int __init register_entries(void)
++{
++ struct efi_system_resource_entry_v1 *v1_entries = (void *)esrt->entries;
++ int i, rc;
++
++ if (!esrt_table_exists())
++ return 0;
++
++ for (i = 0; i < le32_to_cpu(esrt->fw_resource_count); i++) {
++ void *entry;
++ if (esrt->fw_resource_version == 1) {
++ entry = &v1_entries[i];
++ }
++ rc = esre_create_sysfs_entry(entry, i);
++ if (rc < 0) {
++ pr_err("ESRT entry creation failed with error %d.\n",
++ rc);
++ return rc;
++ }
++ }
++ return 0;
++}
++
++static void cleanup_entry_list(void)
++{
++ struct esre_entry *entry, *next;
++
++ list_for_each_entry_safe(entry, next, &entry_list, list) {
++ kobject_put(&entry->kobj);
++ }
++}
++
++static int __init esrt_sysfs_init(void)
++{
++ int error;
++ struct efi_system_resource_table __iomem *ioesrt;
++
++ pr_debug("esrt-sysfs: loading.\n");
++ if (!esrt_data || !esrt_data_size)
++ return -ENOSYS;
++
++ ioesrt = ioremap(esrt_data, esrt_data_size);
++ if (!ioesrt) {
++ pr_err("ioremap(%p, %zu) failed.\n", (void *)esrt_data,
++ esrt_data_size);
++ return -ENOMEM;
++ }
++
++ esrt = kmalloc(esrt_data_size, GFP_KERNEL);
++ if (!esrt) {
++ pr_err("kmalloc failed. (wanted %zu bytes)\n", esrt_data_size);
++ iounmap(ioesrt);
++ return -ENOMEM;
++ }
++
++ memcpy_fromio(esrt, ioesrt, esrt_data_size);
++
++ esrt_kobj = kobject_create_and_add("esrt", efi_kobj);
++ if (!esrt_kobj) {
++ pr_err("Firmware table registration failed.\n");
++ error = -ENOMEM;
++ goto err;
++ }
++
++ error = sysfs_create_group(esrt_kobj, &esrt_attr_group);
++ if (error) {
++ pr_err("Sysfs attribute export failed with error %d.\n",
++ error);
++ goto err_remove_esrt;
++ }
++
++ esrt_kset = kset_create_and_add("entries", NULL, esrt_kobj);
++ if (!esrt_kset) {
++ pr_err("kset creation failed.\n");
++ error = -ENOMEM;
++ goto err_remove_group;
++ }
++
++ error = register_entries();
++ if (error)
++ goto err_cleanup_list;
++
++ memblock_remove(esrt_data, esrt_data_size);
++
++ pr_debug("esrt-sysfs: loaded.\n");
++
++ return 0;
++err_cleanup_list:
++ cleanup_entry_list();
++ kset_unregister(esrt_kset);
++err_remove_group:
++ sysfs_remove_group(esrt_kobj, &esrt_attr_group);
++err_remove_esrt:
++ kobject_put(esrt_kobj);
++err:
++ kfree(esrt);
++ esrt = NULL;
++ return error;
++}
++
++static void __exit esrt_sysfs_exit(void)
++{
++ pr_debug("esrt-sysfs: unloading.\n");
++ cleanup_entry_list();
++ kset_unregister(esrt_kset);
++ sysfs_remove_group(esrt_kobj, &esrt_attr_group);
++ kfree(esrt);
++ esrt = NULL;
++ kobject_del(esrt_kobj);
++ kobject_put(esrt_kobj);
++}
++
++module_init(esrt_sysfs_init);
++module_exit(esrt_sysfs_exit);
++
++MODULE_AUTHOR("Peter Jones <pjones@redhat.com>");
++MODULE_DESCRIPTION("EFI System Resource Table support");
++MODULE_LICENSE("GPL");
+diff --git a/include/linux/efi.h b/include/linux/efi.h
+index 470e8dfcb517..ed0d0c09d45c 100644
+--- a/include/linux/efi.h
++++ b/include/linux/efi.h
+@@ -589,6 +589,9 @@ void efi_native_runtime_setup(void);
+ #define DEVICE_TREE_GUID \
+ EFI_GUID( 0xb1b621d5, 0xf19c, 0x41a5, 0x83, 0x0b, 0xd9, 0x15, 0x2c, 0x69, 0xaa, 0xe0 )
+
++#define EFI_SYSTEM_RESOURCE_TABLE_GUID \
++ EFI_GUID( 0xb122a263, 0x3661, 0x4f68, 0x99, 0x29, 0x78, 0xf8, 0xb0, 0xd6, 0x21, 0x80 )
++
+ #define EFI_CERT_SHA256_GUID \
+ EFI_GUID( 0xc1c41626, 0x504c, 0x4092, 0xac, 0xa9, 0x41, 0xf9, 0x36, 0x93, 0x43, 0x28 )
+
+@@ -849,6 +852,7 @@ extern struct efi {
+ unsigned long fw_vendor; /* fw_vendor */
+ unsigned long runtime; /* runtime table */
+ unsigned long config_table; /* config tables */
++ unsigned long esrt; /* ESRT table */
+ efi_get_time_t *get_time;
+ efi_set_time_t *set_time;
+ efi_get_wakeup_time_t *get_wakeup_time;
+@@ -901,6 +905,7 @@ static inline efi_status_t efi_query_variable_store(u32 attributes, unsigned lon
+ #endif
+ extern void __iomem *efi_lookup_mapped_addr(u64 phys_addr);
+ extern int efi_config_init(efi_config_table_type_t *arch_tables);
++extern void __init efi_esrt_init(void);
+ extern int efi_config_parse_tables(void *config_tables, int count, int sz,
+ efi_config_table_type_t *arch_tables);
+ extern u64 efi_get_iobase (void);
+@@ -908,12 +913,15 @@ extern u32 efi_mem_type (unsigned long phys_addr);
+ extern u64 efi_mem_attributes (unsigned long phys_addr);
+ extern u64 efi_mem_attribute (unsigned long phys_addr, unsigned long size);
+ extern int __init efi_uart_console_only (void);
++extern u64 efi_mem_desc_end(efi_memory_desc_t *md);
++extern int efi_mem_desc_lookup(u64 phys_addr, efi_memory_desc_t *out_md);
+ extern void efi_initialize_iomem_resources(struct resource *code_resource,
+ struct resource *data_resource, struct resource *bss_resource);
+ extern void efi_get_time(struct timespec *now);
+ extern void efi_reserve_boot_services(void);
+ extern int efi_get_fdt_params(struct efi_fdt_params *params, int verbose);
+ extern struct efi_memory_map memmap;
++extern struct kobject *efi_kobj;
+
+ extern int efi_reboot_quirk_mode;
+ extern bool efi_poweroff_required(void);
+--
+2.1.0
+
diff --git a/kernel.spec b/kernel.spec
index 20cf22ce5..106bcd904 100644
--- a/kernel.spec
+++ b/kernel.spec
@@ -554,6 +554,9 @@ Patch1018: MODSIGN-Support-not-importing-certs-from-db.patch
Patch1019: Add-sysrq-option-to-disable-secure-boot-mode.patch
+# esrt
+Patch1020: efi-Add-esrt-support.patch
+
# virt + ksm patches
# DRM
@@ -1329,6 +1332,8 @@ ApplyPatch MODSIGN-Support-not-importing-certs-from-db.patch
ApplyPatch Add-sysrq-option-to-disable-secure-boot-mode.patch
+ApplyPatch efi-Add-esrt-support.patch
+
# Assorted Virt Fixes
# DRM core