aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2015-06-22 20:10:44 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2015-06-22 20:10:44 -0400
commitcfe3eceb7a2eb91284d5605c5315249bb165e9d3 (patch)
treea18d2440ae8dac55119ef13b8b434431408ddc1b
parent5ef6ca4f24b59af7f7c2c19502a3923a4bc10e0a (diff)
parentd4f7743542f20c2b20b68bba856c281ba9c84e42 (diff)
Merge branch 'x86-efi-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 EFI updates from Ingo Molnar: "EFI changes: - 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)" * 'x86-efi-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: efi: Work around ia64 build problem with ESRT driver efi: Add 'systab' information to Documentation/ABI efi: dmi: List SMBIOS3 table before SMBIOS table efi/esrt: Fix some compiler warnings x86, doc: Remove cmdline_size from list of fields to be filled in for EFI handover efi: Add esrt support efi: efivar_create_sysfs_entry() should return negative error codes
-rw-r--r--Documentation/ABI/testing/sysfs-firmware-efi10
-rw-r--r--Documentation/ABI/testing/sysfs-firmware-efi-esrt81
-rw-r--r--Documentation/x86/boot.txt1
-rw-r--r--arch/x86/platform/efi/efi.c2
-rw-r--r--drivers/firmware/efi/Kconfig5
-rw-r--r--drivers/firmware/efi/Makefile1
-rw-r--r--drivers/firmware/efi/efi.c91
-rw-r--r--drivers/firmware/efi/efivars.c11
-rw-r--r--drivers/firmware/efi/esrt.c471
-rw-r--r--include/linux/efi.h12
10 files changed, 676 insertions, 9 deletions
diff --git a/Documentation/ABI/testing/sysfs-firmware-efi b/Documentation/ABI/testing/sysfs-firmware-efi
index 05874da7ce80..e794eac32a90 100644
--- a/Documentation/ABI/testing/sysfs-firmware-efi
+++ b/Documentation/ABI/testing/sysfs-firmware-efi
@@ -18,3 +18,13 @@ Contact: Dave Young <dyoung@redhat.com>
18Description: It shows the physical address of config table entry in the EFI 18Description: It shows the physical address of config table entry in the EFI
19 system table. 19 system table.
20Users: Kexec 20Users: Kexec
21
22What: /sys/firmware/efi/systab
23Date: April 2005
24Contact: linux-efi@vger.kernel.org
25Description: Displays the physical addresses of all EFI Configuration
26 Tables found via the EFI System Table. The order in
27 which the tables are printed forms an ABI and newer
28 versions are always printed first, i.e. ACPI20 comes
29 before ACPI.
30Users: dmidecode
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 @@
1What: /sys/firmware/efi/esrt/
2Date: February 2015
3Contact: Peter Jones <pjones@redhat.com>
4Description: Provides userland access to read the EFI System Resource Table
5 (ESRT), a catalog of firmware for which can be updated with
6 the UEFI UpdateCapsule mechanism described in section 7.5 of
7 the UEFI Standard.
8Users: fwupdate - https://github.com/rhinstaller/fwupdate
9
10What: /sys/firmware/efi/esrt/fw_resource_count
11Date: February 2015
12Contact: Peter Jones <pjones@redhat.com>
13Description: The number of entries in the ESRT
14
15What: /sys/firmware/efi/esrt/fw_resource_count_max
16Date: February 2015
17Contact: Peter Jones <pjones@redhat.com>
18Description: The maximum number of entries that /could/ be registered
19 in the allocation the table is currently in. This is
20 really only useful to the system firmware itself.
21
22What: /sys/firmware/efi/esrt/fw_resource_version
23Date: February 2015
24Contact: Peter Jones <pjones@redhat.com>
25Description: The version of the ESRT structure provided by the firmware.
26
27What: /sys/firmware/efi/esrt/entries/entry$N/
28Date: February 2015
29Contact: Peter Jones <pjones@redhat.com>
30Description: Each ESRT entry is identified by a GUID, and each gets a
31 subdirectory under entries/ .
32 example: /sys/firmware/efi/esrt/entries/entry0/
33
34What: /sys/firmware/efi/esrt/entries/entry$N/fw_type
35Date: February 2015
36Contact: Peter Jones <pjones@redhat.com>
37Description: What kind of firmware entry this is:
38 0 - Unknown
39 1 - System Firmware
40 2 - Device Firmware
41 3 - UEFI Driver
42
43What: /sys/firmware/efi/esrt/entries/entry$N/fw_class
44Date: February 2015
45Contact: Peter Jones <pjones@redhat.com>
46Description: This is the entry's guid, and will match the directory name.
47
48What: /sys/firmware/efi/esrt/entries/entry$N/fw_version
49Date: February 2015
50Contact: Peter Jones <pjones@redhat.com>
51Description: The version of the firmware currently installed. This is a
52 32-bit unsigned integer.
53
54What: /sys/firmware/efi/esrt/entries/entry$N/lowest_supported_fw_version
55Date: February 2015
56Contact: Peter Jones <pjones@redhat.com>
57Description: The lowest version of the firmware that can be installed.
58
59What: /sys/firmware/efi/esrt/entries/entry$N/capsule_flags
60Date: February 2015
61Contact: Peter Jones <pjones@redhat.com>
62Description: Flags that must be passed to UpdateCapsule()
63
64What: /sys/firmware/efi/esrt/entries/entry$N/last_attempt_version
65Date: February 2015
66Contact: Peter Jones <pjones@redhat.com>
67Description: The last firmware version for which an update was attempted.
68
69What: /sys/firmware/efi/esrt/entries/entry$N/last_attempt_status
70Date: February 2015
71Contact: Peter Jones <pjones@redhat.com>
72Description: The result of the last firmware update attempt for the
73 firmware resource entry.
74 0 - Success
75 1 - Insufficient resources
76 2 - Incorrect version
77 3 - Invalid format
78 4 - Authentication error
79 5 - AC power event
80 6 - Battery power event
81
diff --git a/Documentation/x86/boot.txt b/Documentation/x86/boot.txt
index 88b85899d309..7c1f9fad6674 100644
--- a/Documentation/x86/boot.txt
+++ b/Documentation/x86/boot.txt
@@ -1124,7 +1124,6 @@ The boot loader *must* fill out the following fields in bp,
1124 1124
1125 o hdr.code32_start 1125 o hdr.code32_start
1126 o hdr.cmd_line_ptr 1126 o hdr.cmd_line_ptr
1127 o hdr.cmdline_size
1128 o hdr.ramdisk_image (if applicable) 1127 o hdr.ramdisk_image (if applicable)
1129 o hdr.ramdisk_size (if applicable) 1128 o hdr.ramdisk_size (if applicable)
1130 1129
diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
index 02744df576d5..3b984c3aa1b0 100644
--- a/arch/x86/platform/efi/efi.c
+++ b/arch/x86/platform/efi/efi.c
@@ -501,6 +501,8 @@ void __init efi_init(void)
501 501
502 if (efi_enabled(EFI_DBG)) 502 if (efi_enabled(EFI_DBG))
503 print_efi_memmap(); 503 print_efi_memmap();
504
505 efi_esrt_init();
504} 506}
505 507
506void __init efi_late_init(void) 508void __init efi_late_init(void)
diff --git a/drivers/firmware/efi/Kconfig b/drivers/firmware/efi/Kconfig
index 8de4da5c9ab6..54071c148340 100644
--- a/drivers/firmware/efi/Kconfig
+++ b/drivers/firmware/efi/Kconfig
@@ -18,6 +18,11 @@ config EFI_VARS
18 Subsequent efibootmgr releases may be found at: 18 Subsequent efibootmgr releases may be found at:
19 <http://github.com/vathpela/efibootmgr> 19 <http://github.com/vathpela/efibootmgr>
20 20
21config EFI_ESRT
22 bool
23 depends on EFI && !IA64
24 default y
25
21config EFI_VARS_PSTORE 26config EFI_VARS_PSTORE
22 tristate "Register efivars backend for pstore" 27 tristate "Register efivars backend for pstore"
23 depends on EFI_VARS && PSTORE 28 depends on EFI_VARS && PSTORE
diff --git a/drivers/firmware/efi/Makefile b/drivers/firmware/efi/Makefile
index d8be608a9f3b..6fd3da938717 100644
--- a/drivers/firmware/efi/Makefile
+++ b/drivers/firmware/efi/Makefile
@@ -3,6 +3,7 @@
3# 3#
4obj-$(CONFIG_EFI) += efi.o vars.o reboot.o 4obj-$(CONFIG_EFI) += efi.o vars.o reboot.o
5obj-$(CONFIG_EFI_VARS) += efivars.o 5obj-$(CONFIG_EFI_VARS) += efivars.o
6obj-$(CONFIG_EFI_ESRT) += esrt.o
6obj-$(CONFIG_EFI_VARS_PSTORE) += efi-pstore.o 7obj-$(CONFIG_EFI_VARS_PSTORE) += efi-pstore.o
7obj-$(CONFIG_UEFI_CPER) += cper.o 8obj-$(CONFIG_UEFI_CPER) += cper.o
8obj-$(CONFIG_EFI_RUNTIME_MAP) += runtime-map.o 9obj-$(CONFIG_EFI_RUNTIME_MAP) += runtime-map.o
diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c
index 3061bb8629dc..ca617f40574a 100644
--- a/drivers/firmware/efi/efi.c
+++ b/drivers/firmware/efi/efi.c
@@ -39,6 +39,7 @@ struct efi __read_mostly efi = {
39 .fw_vendor = EFI_INVALID_TABLE_ADDR, 39 .fw_vendor = EFI_INVALID_TABLE_ADDR,
40 .runtime = EFI_INVALID_TABLE_ADDR, 40 .runtime = EFI_INVALID_TABLE_ADDR,
41 .config_table = EFI_INVALID_TABLE_ADDR, 41 .config_table = EFI_INVALID_TABLE_ADDR,
42 .esrt = EFI_INVALID_TABLE_ADDR,
42}; 43};
43EXPORT_SYMBOL(efi); 44EXPORT_SYMBOL(efi);
44 45
@@ -64,7 +65,7 @@ static int __init parse_efi_cmdline(char *str)
64} 65}
65early_param("efi", parse_efi_cmdline); 66early_param("efi", parse_efi_cmdline);
66 67
67static struct kobject *efi_kobj; 68struct kobject *efi_kobj;
68static struct kobject *efivars_kobj; 69static struct kobject *efivars_kobj;
69 70
70/* 71/*
@@ -85,10 +86,15 @@ static ssize_t systab_show(struct kobject *kobj,
85 str += sprintf(str, "ACPI20=0x%lx\n", efi.acpi20); 86 str += sprintf(str, "ACPI20=0x%lx\n", efi.acpi20);
86 if (efi.acpi != EFI_INVALID_TABLE_ADDR) 87 if (efi.acpi != EFI_INVALID_TABLE_ADDR)
87 str += sprintf(str, "ACPI=0x%lx\n", efi.acpi); 88 str += sprintf(str, "ACPI=0x%lx\n", efi.acpi);
88 if (efi.smbios != EFI_INVALID_TABLE_ADDR) 89 /*
89 str += sprintf(str, "SMBIOS=0x%lx\n", efi.smbios); 90 * If both SMBIOS and SMBIOS3 entry points are implemented, the
91 * SMBIOS3 entry point shall be preferred, so we list it first to
92 * let applications stop parsing after the first match.
93 */
90 if (efi.smbios3 != EFI_INVALID_TABLE_ADDR) 94 if (efi.smbios3 != EFI_INVALID_TABLE_ADDR)
91 str += sprintf(str, "SMBIOS3=0x%lx\n", efi.smbios3); 95 str += sprintf(str, "SMBIOS3=0x%lx\n", efi.smbios3);
96 if (efi.smbios != EFI_INVALID_TABLE_ADDR)
97 str += sprintf(str, "SMBIOS=0x%lx\n", efi.smbios);
92 if (efi.hcdp != EFI_INVALID_TABLE_ADDR) 98 if (efi.hcdp != EFI_INVALID_TABLE_ADDR)
93 str += sprintf(str, "HCDP=0x%lx\n", efi.hcdp); 99 str += sprintf(str, "HCDP=0x%lx\n", efi.hcdp);
94 if (efi.boot_info != EFI_INVALID_TABLE_ADDR) 100 if (efi.boot_info != EFI_INVALID_TABLE_ADDR)
@@ -232,6 +238,84 @@ err_put:
232 238
233subsys_initcall(efisubsys_init); 239subsys_initcall(efisubsys_init);
234 240
241/*
242 * Find the efi memory descriptor for a given physical address. Given a
243 * physicall address, determine if it exists within an EFI Memory Map entry,
244 * and if so, populate the supplied memory descriptor with the appropriate
245 * data.
246 */
247int __init efi_mem_desc_lookup(u64 phys_addr, efi_memory_desc_t *out_md)
248{
249 struct efi_memory_map *map = efi.memmap;
250 void *p, *e;
251
252 if (!efi_enabled(EFI_MEMMAP)) {
253 pr_err_once("EFI_MEMMAP is not enabled.\n");
254 return -EINVAL;
255 }
256
257 if (!map) {
258 pr_err_once("efi.memmap is not set.\n");
259 return -EINVAL;
260 }
261 if (!out_md) {
262 pr_err_once("out_md is null.\n");
263 return -EINVAL;
264 }
265 if (WARN_ON_ONCE(!map->phys_map))
266 return -EINVAL;
267 if (WARN_ON_ONCE(map->nr_map == 0) || WARN_ON_ONCE(map->desc_size == 0))
268 return -EINVAL;
269
270 e = map->phys_map + map->nr_map * map->desc_size;
271 for (p = map->phys_map; p < e; p += map->desc_size) {
272 efi_memory_desc_t *md;
273 u64 size;
274 u64 end;
275
276 /*
277 * If a driver calls this after efi_free_boot_services,
278 * ->map will be NULL, and the target may also not be mapped.
279 * So just always get our own virtual map on the CPU.
280 *
281 */
282 md = early_memremap((phys_addr_t)p, sizeof (*md));
283 if (!md) {
284 pr_err_once("early_memremap(%p, %zu) failed.\n",
285 p, sizeof (*md));
286 return -ENOMEM;
287 }
288
289 if (!(md->attribute & EFI_MEMORY_RUNTIME) &&
290 md->type != EFI_BOOT_SERVICES_DATA &&
291 md->type != EFI_RUNTIME_SERVICES_DATA) {
292 early_memunmap(md, sizeof (*md));
293 continue;
294 }
295
296 size = md->num_pages << EFI_PAGE_SHIFT;
297 end = md->phys_addr + size;
298 if (phys_addr >= md->phys_addr && phys_addr < end) {
299 memcpy(out_md, md, sizeof(*out_md));
300 early_memunmap(md, sizeof (*md));
301 return 0;
302 }
303
304 early_memunmap(md, sizeof (*md));
305 }
306 pr_err_once("requested map not found.\n");
307 return -ENOENT;
308}
309
310/*
311 * Calculate the highest address of an efi memory descriptor.
312 */
313u64 __init efi_mem_desc_end(efi_memory_desc_t *md)
314{
315 u64 size = md->num_pages << EFI_PAGE_SHIFT;
316 u64 end = md->phys_addr + size;
317 return end;
318}
235 319
236/* 320/*
237 * We can't ioremap data in EFI boot services RAM, because we've already mapped 321 * We can't ioremap data in EFI boot services RAM, because we've already mapped
@@ -274,6 +358,7 @@ static __initdata efi_config_table_type_t common_tables[] = {
274 {SMBIOS_TABLE_GUID, "SMBIOS", &efi.smbios}, 358 {SMBIOS_TABLE_GUID, "SMBIOS", &efi.smbios},
275 {SMBIOS3_TABLE_GUID, "SMBIOS 3.0", &efi.smbios3}, 359 {SMBIOS3_TABLE_GUID, "SMBIOS 3.0", &efi.smbios3},
276 {UGA_IO_PROTOCOL_GUID, "UGA", &efi.uga}, 360 {UGA_IO_PROTOCOL_GUID, "UGA", &efi.uga},
361 {EFI_SYSTEM_RESOURCE_TABLE_GUID, "ESRT", &efi.esrt},
277 {NULL_GUID, NULL, NULL}, 362 {NULL_GUID, NULL, NULL},
278}; 363};
279 364
diff --git a/drivers/firmware/efi/efivars.c b/drivers/firmware/efi/efivars.c
index 7b2e0496e0c0..756eca8c4cf8 100644
--- a/drivers/firmware/efi/efivars.c
+++ b/drivers/firmware/efi/efivars.c
@@ -535,7 +535,7 @@ static ssize_t efivar_delete(struct file *filp, struct kobject *kobj,
535 * efivar_create_sysfs_entry - create a new entry in sysfs 535 * efivar_create_sysfs_entry - create a new entry in sysfs
536 * @new_var: efivar entry to create 536 * @new_var: efivar entry to create
537 * 537 *
538 * Returns 1 on failure, 0 on success 538 * Returns 0 on success, negative error code on failure
539 */ 539 */
540static int 540static int
541efivar_create_sysfs_entry(struct efivar_entry *new_var) 541efivar_create_sysfs_entry(struct efivar_entry *new_var)
@@ -544,6 +544,7 @@ efivar_create_sysfs_entry(struct efivar_entry *new_var)
544 char *short_name; 544 char *short_name;
545 unsigned long variable_name_size; 545 unsigned long variable_name_size;
546 efi_char16_t *variable_name; 546 efi_char16_t *variable_name;
547 int ret;
547 548
548 variable_name = new_var->var.VariableName; 549 variable_name = new_var->var.VariableName;
549 variable_name_size = ucs2_strlen(variable_name) * sizeof(efi_char16_t); 550 variable_name_size = ucs2_strlen(variable_name) * sizeof(efi_char16_t);
@@ -558,7 +559,7 @@ efivar_create_sysfs_entry(struct efivar_entry *new_var)
558 short_name = kzalloc(short_name_size, GFP_KERNEL); 559 short_name = kzalloc(short_name_size, GFP_KERNEL);
559 560
560 if (!short_name) 561 if (!short_name)
561 return 1; 562 return -ENOMEM;
562 563
563 /* Convert Unicode to normal chars (assume top bits are 0), 564 /* Convert Unicode to normal chars (assume top bits are 0),
564 ala UTF-8 */ 565 ala UTF-8 */
@@ -574,11 +575,11 @@ efivar_create_sysfs_entry(struct efivar_entry *new_var)
574 575
575 new_var->kobj.kset = efivars_kset; 576 new_var->kobj.kset = efivars_kset;
576 577
577 i = kobject_init_and_add(&new_var->kobj, &efivar_ktype, 578 ret = kobject_init_and_add(&new_var->kobj, &efivar_ktype,
578 NULL, "%s", short_name); 579 NULL, "%s", short_name);
579 kfree(short_name); 580 kfree(short_name);
580 if (i) 581 if (ret)
581 return 1; 582 return ret;
582 583
583 kobject_uevent(&new_var->kobj, KOBJ_ADD); 584 kobject_uevent(&new_var->kobj, KOBJ_ADD);
584 efivar_entry_add(new_var, &efivar_sysfs_list); 585 efivar_entry_add(new_var, &efivar_sysfs_list);
diff --git a/drivers/firmware/efi/esrt.c b/drivers/firmware/efi/esrt.c
new file mode 100644
index 000000000000..a5b95d61ae71
--- /dev/null
+++ b/drivers/firmware/efi/esrt.c
@@ -0,0 +1,471 @@
1/*
2 * esrt.c
3 *
4 * This module exports EFI System Resource Table (ESRT) entries into userspace
5 * through the sysfs file system. The ESRT provides a read-only catalog of
6 * system components for which the system accepts firmware upgrades via UEFI's
7 * "Capsule Update" feature. This module allows userland utilities to evaluate
8 * what firmware updates can be applied to this system, and potentially arrange
9 * for those updates to occur.
10 *
11 * Data is currently found below /sys/firmware/efi/esrt/...
12 */
13#define pr_fmt(fmt) "esrt: " fmt
14
15#include <linux/capability.h>
16#include <linux/device.h>
17#include <linux/efi.h>
18#include <linux/init.h>
19#include <linux/kernel.h>
20#include <linux/kobject.h>
21#include <linux/list.h>
22#include <linux/memblock.h>
23#include <linux/module.h>
24#include <linux/slab.h>
25#include <linux/types.h>
26
27#include <asm/io.h>
28#include <asm/early_ioremap.h>
29
30struct efi_system_resource_entry_v1 {
31 efi_guid_t fw_class;
32 u32 fw_type;
33 u32 fw_version;
34 u32 lowest_supported_fw_version;
35 u32 capsule_flags;
36 u32 last_attempt_version;
37 u32 last_attempt_status;
38};
39
40/*
41 * _count and _version are what they seem like. _max is actually just
42 * accounting info for the firmware when creating the table; it should never
43 * have been exposed to us. To wit, the spec says:
44 * The maximum number of resource array entries that can be within the
45 * table without reallocating the table, must not be zero.
46 * Since there's no guidance about what that means in terms of memory layout,
47 * it means nothing to us.
48 */
49struct efi_system_resource_table {
50 u32 fw_resource_count;
51 u32 fw_resource_count_max;
52 u64 fw_resource_version;
53 u8 entries[];
54};
55
56static phys_addr_t esrt_data;
57static size_t esrt_data_size;
58
59static struct efi_system_resource_table *esrt;
60
61struct esre_entry {
62 union {
63 struct efi_system_resource_entry_v1 *esre1;
64 } esre;
65
66 struct kobject kobj;
67 struct list_head list;
68};
69
70/* global list of esre_entry. */
71static LIST_HEAD(entry_list);
72
73/* entry attribute */
74struct esre_attribute {
75 struct attribute attr;
76 ssize_t (*show)(struct esre_entry *entry, char *buf);
77 ssize_t (*store)(struct esre_entry *entry,
78 const char *buf, size_t count);
79};
80
81static struct esre_entry *to_entry(struct kobject *kobj)
82{
83 return container_of(kobj, struct esre_entry, kobj);
84}
85
86static struct esre_attribute *to_attr(struct attribute *attr)
87{
88 return container_of(attr, struct esre_attribute, attr);
89}
90
91static ssize_t esre_attr_show(struct kobject *kobj,
92 struct attribute *_attr, char *buf)
93{
94 struct esre_entry *entry = to_entry(kobj);
95 struct esre_attribute *attr = to_attr(_attr);
96
97 /* Don't tell normal users what firmware versions we've got... */
98 if (!capable(CAP_SYS_ADMIN))
99 return -EACCES;
100
101 return attr->show(entry, buf);
102}
103
104static const struct sysfs_ops esre_attr_ops = {
105 .show = esre_attr_show,
106};
107
108/* Generic ESRT Entry ("ESRE") support. */
109static ssize_t esre_fw_class_show(struct esre_entry *entry, char *buf)
110{
111 char *str = buf;
112
113 efi_guid_to_str(&entry->esre.esre1->fw_class, str);
114 str += strlen(str);
115 str += sprintf(str, "\n");
116
117 return str - buf;
118}
119
120static struct esre_attribute esre_fw_class = __ATTR(fw_class, 0400,
121 esre_fw_class_show, NULL);
122
123#define esre_attr_decl(name, size, fmt) \
124static ssize_t esre_##name##_show(struct esre_entry *entry, char *buf) \
125{ \
126 return sprintf(buf, fmt "\n", \
127 le##size##_to_cpu(entry->esre.esre1->name)); \
128} \
129\
130static struct esre_attribute esre_##name = __ATTR(name, 0400, \
131 esre_##name##_show, NULL)
132
133esre_attr_decl(fw_type, 32, "%u");
134esre_attr_decl(fw_version, 32, "%u");
135esre_attr_decl(lowest_supported_fw_version, 32, "%u");
136esre_attr_decl(capsule_flags, 32, "0x%x");
137esre_attr_decl(last_attempt_version, 32, "%u");
138esre_attr_decl(last_attempt_status, 32, "%u");
139
140static struct attribute *esre1_attrs[] = {
141 &esre_fw_class.attr,
142 &esre_fw_type.attr,
143 &esre_fw_version.attr,
144 &esre_lowest_supported_fw_version.attr,
145 &esre_capsule_flags.attr,
146 &esre_last_attempt_version.attr,
147 &esre_last_attempt_status.attr,
148 NULL
149};
150static void esre_release(struct kobject *kobj)
151{
152 struct esre_entry *entry = to_entry(kobj);
153
154 list_del(&entry->list);
155 kfree(entry);
156}
157
158static struct kobj_type esre1_ktype = {
159 .release = esre_release,
160 .sysfs_ops = &esre_attr_ops,
161 .default_attrs = esre1_attrs,
162};
163
164
165static struct kobject *esrt_kobj;
166static struct kset *esrt_kset;
167
168static int esre_create_sysfs_entry(void *esre, int entry_num)
169{
170 struct esre_entry *entry;
171 char name[20];
172
173 entry = kzalloc(sizeof(*entry), GFP_KERNEL);
174 if (!entry)
175 return -ENOMEM;
176
177 sprintf(name, "entry%d", entry_num);
178
179 entry->kobj.kset = esrt_kset;
180
181 if (esrt->fw_resource_version == 1) {
182 int rc = 0;
183
184 entry->esre.esre1 = esre;
185 rc = kobject_init_and_add(&entry->kobj, &esre1_ktype, NULL,
186 "%s", name);
187 if (rc) {
188 kfree(entry);
189 return rc;
190 }
191 }
192
193 list_add_tail(&entry->list, &entry_list);
194 return 0;
195}
196
197/* support for displaying ESRT fields at the top level */
198#define esrt_attr_decl(name, size, fmt) \
199static ssize_t esrt_##name##_show(struct kobject *kobj, \
200 struct kobj_attribute *attr, char *buf)\
201{ \
202 return sprintf(buf, fmt "\n", le##size##_to_cpu(esrt->name)); \
203} \
204\
205static struct kobj_attribute esrt_##name = __ATTR(name, 0400, \
206 esrt_##name##_show, NULL)
207
208esrt_attr_decl(fw_resource_count, 32, "%u");
209esrt_attr_decl(fw_resource_count_max, 32, "%u");
210esrt_attr_decl(fw_resource_version, 64, "%llu");
211
212static struct attribute *esrt_attrs[] = {
213 &esrt_fw_resource_count.attr,
214 &esrt_fw_resource_count_max.attr,
215 &esrt_fw_resource_version.attr,
216 NULL,
217};
218
219static inline int esrt_table_exists(void)
220{
221 if (!efi_enabled(EFI_CONFIG_TABLES))
222 return 0;
223 if (efi.esrt == EFI_INVALID_TABLE_ADDR)
224 return 0;
225 return 1;
226}
227
228static umode_t esrt_attr_is_visible(struct kobject *kobj,
229 struct attribute *attr, int n)
230{
231 if (!esrt_table_exists())
232 return 0;
233 return attr->mode;
234}
235
236static struct attribute_group esrt_attr_group = {
237 .attrs = esrt_attrs,
238 .is_visible = esrt_attr_is_visible,
239};
240
241/*
242 * remap the table, copy it to kmalloced pages, and unmap it.
243 */
244void __init efi_esrt_init(void)
245{
246 void *va;
247 struct efi_system_resource_table tmpesrt;
248 struct efi_system_resource_entry_v1 *v1_entries;
249 size_t size, max, entry_size, entries_size;
250 efi_memory_desc_t md;
251 int rc;
252 phys_addr_t end;
253
254 pr_debug("esrt-init: loading.\n");
255 if (!esrt_table_exists())
256 return;
257
258 rc = efi_mem_desc_lookup(efi.esrt, &md);
259 if (rc < 0) {
260 pr_err("ESRT header is not in the memory map.\n");
261 return;
262 }
263
264 max = efi_mem_desc_end(&md);
265 if (max < efi.esrt) {
266 pr_err("EFI memory descriptor is invalid. (esrt: %p max: %p)\n",
267 (void *)efi.esrt, (void *)max);
268 return;
269 }
270
271 size = sizeof(*esrt);
272 max -= efi.esrt;
273
274 if (max < size) {
275 pr_err("ESRT header doen't fit on single memory map entry. (size: %zu max: %zu)\n",
276 size, max);
277 return;
278 }
279
280 va = early_memremap(efi.esrt, size);
281 if (!va) {
282 pr_err("early_memremap(%p, %zu) failed.\n", (void *)efi.esrt,
283 size);
284 return;
285 }
286
287 memcpy(&tmpesrt, va, sizeof(tmpesrt));
288
289 if (tmpesrt.fw_resource_version == 1) {
290 entry_size = sizeof (*v1_entries);
291 } else {
292 pr_err("Unsupported ESRT version %lld.\n",
293 tmpesrt.fw_resource_version);
294 return;
295 }
296
297 if (tmpesrt.fw_resource_count > 0 && max - size < entry_size) {
298 pr_err("ESRT memory map entry can only hold the header. (max: %zu size: %zu)\n",
299 max - size, entry_size);
300 goto err_memunmap;
301 }
302
303 /*
304 * The format doesn't really give us any boundary to test here,
305 * so I'm making up 128 as the max number of individually updatable
306 * components we support.
307 * 128 should be pretty excessive, but there's still some chance
308 * somebody will do that someday and we'll need to raise this.
309 */
310 if (tmpesrt.fw_resource_count > 128) {
311 pr_err("ESRT says fw_resource_count has very large value %d.\n",
312 tmpesrt.fw_resource_count);
313 goto err_memunmap;
314 }
315
316 /*
317 * We know it can't be larger than N * sizeof() here, and N is limited
318 * by the previous test to a small number, so there's no overflow.
319 */
320 entries_size = tmpesrt.fw_resource_count * entry_size;
321 if (max < size + entries_size) {
322 pr_err("ESRT does not fit on single memory map entry (size: %zu max: %zu)\n",
323 size, max);
324 goto err_memunmap;
325 }
326
327 /* remap it with our (plausible) new pages */
328 early_memunmap(va, size);
329 size += entries_size;
330 va = early_memremap(efi.esrt, size);
331 if (!va) {
332 pr_err("early_memremap(%p, %zu) failed.\n", (void *)efi.esrt,
333 size);
334 return;
335 }
336
337 esrt_data = (phys_addr_t)efi.esrt;
338 esrt_data_size = size;
339
340 end = esrt_data + size;
341 pr_info("Reserving ESRT space from %pa to %pa.\n", &esrt_data, &end);
342 memblock_reserve(esrt_data, esrt_data_size);
343
344 pr_debug("esrt-init: loaded.\n");
345err_memunmap:
346 early_memunmap(va, size);
347}
348
349static int __init register_entries(void)
350{
351 struct efi_system_resource_entry_v1 *v1_entries = (void *)esrt->entries;
352 int i, rc;
353
354 if (!esrt_table_exists())
355 return 0;
356
357 for (i = 0; i < le32_to_cpu(esrt->fw_resource_count); i++) {
358 void *esre = NULL;
359 if (esrt->fw_resource_version == 1) {
360 esre = &v1_entries[i];
361 } else {
362 pr_err("Unsupported ESRT version %lld.\n",
363 esrt->fw_resource_version);
364 return -EINVAL;
365 }
366
367 rc = esre_create_sysfs_entry(esre, i);
368 if (rc < 0) {
369 pr_err("ESRT entry creation failed with error %d.\n",
370 rc);
371 return rc;
372 }
373 }
374 return 0;
375}
376
377static void cleanup_entry_list(void)
378{
379 struct esre_entry *entry, *next;
380
381 list_for_each_entry_safe(entry, next, &entry_list, list) {
382 kobject_put(&entry->kobj);
383 }
384}
385
386static int __init esrt_sysfs_init(void)
387{
388 int error;
389 struct efi_system_resource_table __iomem *ioesrt;
390
391 pr_debug("esrt-sysfs: loading.\n");
392 if (!esrt_data || !esrt_data_size)
393 return -ENOSYS;
394
395 ioesrt = ioremap(esrt_data, esrt_data_size);
396 if (!ioesrt) {
397 pr_err("ioremap(%pa, %zu) failed.\n", &esrt_data,
398 esrt_data_size);
399 return -ENOMEM;
400 }
401
402 esrt = kmalloc(esrt_data_size, GFP_KERNEL);
403 if (!esrt) {
404 pr_err("kmalloc failed. (wanted %zu bytes)\n", esrt_data_size);
405 iounmap(ioesrt);
406 return -ENOMEM;
407 }
408
409 memcpy_fromio(esrt, ioesrt, esrt_data_size);
410
411 esrt_kobj = kobject_create_and_add("esrt", efi_kobj);
412 if (!esrt_kobj) {
413 pr_err("Firmware table registration failed.\n");
414 error = -ENOMEM;
415 goto err;
416 }
417
418 error = sysfs_create_group(esrt_kobj, &esrt_attr_group);
419 if (error) {
420 pr_err("Sysfs attribute export failed with error %d.\n",
421 error);
422 goto err_remove_esrt;
423 }
424
425 esrt_kset = kset_create_and_add("entries", NULL, esrt_kobj);
426 if (!esrt_kset) {
427 pr_err("kset creation failed.\n");
428 error = -ENOMEM;
429 goto err_remove_group;
430 }
431
432 error = register_entries();
433 if (error)
434 goto err_cleanup_list;
435
436 memblock_remove(esrt_data, esrt_data_size);
437
438 pr_debug("esrt-sysfs: loaded.\n");
439
440 return 0;
441err_cleanup_list:
442 cleanup_entry_list();
443 kset_unregister(esrt_kset);
444err_remove_group:
445 sysfs_remove_group(esrt_kobj, &esrt_attr_group);
446err_remove_esrt:
447 kobject_put(esrt_kobj);
448err:
449 kfree(esrt);
450 esrt = NULL;
451 return error;
452}
453
454static void __exit esrt_sysfs_exit(void)
455{
456 pr_debug("esrt-sysfs: unloading.\n");
457 cleanup_entry_list();
458 kset_unregister(esrt_kset);
459 sysfs_remove_group(esrt_kobj, &esrt_attr_group);
460 kfree(esrt);
461 esrt = NULL;
462 kobject_del(esrt_kobj);
463 kobject_put(esrt_kobj);
464}
465
466module_init(esrt_sysfs_init);
467module_exit(esrt_sysfs_exit);
468
469MODULE_AUTHOR("Peter Jones <pjones@redhat.com>");
470MODULE_DESCRIPTION("EFI System Resource Table support");
471MODULE_LICENSE("GPL");
diff --git a/include/linux/efi.h b/include/linux/efi.h
index af5be0368dec..2092965afca3 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -583,6 +583,9 @@ void efi_native_runtime_setup(void);
583#define EFI_FILE_INFO_ID \ 583#define EFI_FILE_INFO_ID \
584 EFI_GUID( 0x9576e92, 0x6d3f, 0x11d2, 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b ) 584 EFI_GUID( 0x9576e92, 0x6d3f, 0x11d2, 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b )
585 585
586#define EFI_SYSTEM_RESOURCE_TABLE_GUID \
587 EFI_GUID( 0xb122a263, 0x3661, 0x4f68, 0x99, 0x29, 0x78, 0xf8, 0xb0, 0xd6, 0x21, 0x80 )
588
586#define EFI_FILE_SYSTEM_GUID \ 589#define EFI_FILE_SYSTEM_GUID \
587 EFI_GUID( 0x964e5b22, 0x6459, 0x11d2, 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b ) 590 EFI_GUID( 0x964e5b22, 0x6459, 0x11d2, 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b )
588 591
@@ -823,6 +826,7 @@ extern struct efi {
823 unsigned long fw_vendor; /* fw_vendor */ 826 unsigned long fw_vendor; /* fw_vendor */
824 unsigned long runtime; /* runtime table */ 827 unsigned long runtime; /* runtime table */
825 unsigned long config_table; /* config tables */ 828 unsigned long config_table; /* config tables */
829 unsigned long esrt; /* ESRT table */
826 efi_get_time_t *get_time; 830 efi_get_time_t *get_time;
827 efi_set_time_t *set_time; 831 efi_set_time_t *set_time;
828 efi_get_wakeup_time_t *get_wakeup_time; 832 efi_get_wakeup_time_t *get_wakeup_time;
@@ -875,6 +879,11 @@ static inline efi_status_t efi_query_variable_store(u32 attributes, unsigned lon
875#endif 879#endif
876extern void __iomem *efi_lookup_mapped_addr(u64 phys_addr); 880extern void __iomem *efi_lookup_mapped_addr(u64 phys_addr);
877extern int efi_config_init(efi_config_table_type_t *arch_tables); 881extern int efi_config_init(efi_config_table_type_t *arch_tables);
882#ifdef CONFIG_EFI_ESRT
883extern void __init efi_esrt_init(void);
884#else
885static inline void efi_esrt_init(void) { }
886#endif
878extern int efi_config_parse_tables(void *config_tables, int count, int sz, 887extern int efi_config_parse_tables(void *config_tables, int count, int sz,
879 efi_config_table_type_t *arch_tables); 888 efi_config_table_type_t *arch_tables);
880extern u64 efi_get_iobase (void); 889extern u64 efi_get_iobase (void);
@@ -882,12 +891,15 @@ extern u32 efi_mem_type (unsigned long phys_addr);
882extern u64 efi_mem_attributes (unsigned long phys_addr); 891extern u64 efi_mem_attributes (unsigned long phys_addr);
883extern u64 efi_mem_attribute (unsigned long phys_addr, unsigned long size); 892extern u64 efi_mem_attribute (unsigned long phys_addr, unsigned long size);
884extern int __init efi_uart_console_only (void); 893extern int __init efi_uart_console_only (void);
894extern u64 efi_mem_desc_end(efi_memory_desc_t *md);
895extern int efi_mem_desc_lookup(u64 phys_addr, efi_memory_desc_t *out_md);
885extern void efi_initialize_iomem_resources(struct resource *code_resource, 896extern void efi_initialize_iomem_resources(struct resource *code_resource,
886 struct resource *data_resource, struct resource *bss_resource); 897 struct resource *data_resource, struct resource *bss_resource);
887extern void efi_get_time(struct timespec *now); 898extern void efi_get_time(struct timespec *now);
888extern void efi_reserve_boot_services(void); 899extern void efi_reserve_boot_services(void);
889extern int efi_get_fdt_params(struct efi_fdt_params *params, int verbose); 900extern int efi_get_fdt_params(struct efi_fdt_params *params, int verbose);
890extern struct efi_memory_map memmap; 901extern struct efi_memory_map memmap;
902extern struct kobject *efi_kobj;
891 903
892extern int efi_reboot_quirk_mode; 904extern int efi_reboot_quirk_mode;
893extern bool efi_poweroff_required(void); 905extern bool efi_poweroff_required(void);