diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-05-01 15:51:46 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-05-01 15:51:46 -0700 |
commit | b9394d8a657cd3c064fa432aa0905c1b58b38fe9 (patch) | |
tree | 5a0c98370f313fa11693ab72eea0dc809fd6567d /drivers/firmware/efi/efi.c | |
parent | 126de6b20bfb82cc19012d5048f11f339ae5a021 (diff) | |
parent | 7b2dd6d2c4db3912771bfcfd7ac7264011a3c831 (diff) | |
download | talos-obmc-linux-b9394d8a657cd3c064fa432aa0905c1b58b38fe9.tar.gz talos-obmc-linux-b9394d8a657cd3c064fa432aa0905c1b58b38fe9.zip |
Merge branch 'x86-efi-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86/efi changes from Peter Anvin:
"The bulk of these changes are cleaning up the efivars handling and
breaking it up into a tree of files. There are a number of fixes as
well.
The entire changeset is pretty big, but most of it is code movement.
Several of these commits are quite new; the history got very messed up
due to a mismerge with the urgent changes for rc8 which completely
broke IA64, and so Ingo requested that we rebase it to straighten it
out."
* 'x86-efi-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
efi: remove "kfree(NULL)"
efi: locking fix in efivar_entry_set_safe()
efi, pstore: Read data from variable store before memcpy()
efi, pstore: Remove entry from list when erasing
efi, pstore: Initialise 'entry' before iterating
efi: split efisubsystem from efivars
efivarfs: Move to fs/efivarfs
efivars: Move pstore code into the new EFI directory
efivars: efivar_entry API
efivars: Keep a private global pointer to efivars
efi: move utf16 string functions to efi.h
x86, efi: Make efi_memblock_x86_reserve_range more readable
efivarfs: convert to use simple_open()
Diffstat (limited to 'drivers/firmware/efi/efi.c')
-rw-r--r-- | drivers/firmware/efi/efi.c | 134 |
1 files changed, 134 insertions, 0 deletions
diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c new file mode 100644 index 000000000000..5145fa344ad5 --- /dev/null +++ b/drivers/firmware/efi/efi.c @@ -0,0 +1,134 @@ +/* + * efi.c - EFI subsystem + * + * Copyright (C) 2001,2003,2004 Dell <Matt_Domsch@dell.com> + * Copyright (C) 2004 Intel Corporation <matthew.e.tolentino@intel.com> + * Copyright (C) 2013 Tom Gundersen <teg@jklm.no> + * + * This code registers /sys/firmware/efi{,/efivars} when EFI is supported, + * allowing the efivarfs to be mounted or the efivars module to be loaded. + * The existance of /sys/firmware/efi may also be used by userspace to + * determine that the system supports EFI. + * + * This file is released under the GPLv2. + */ + +#include <linux/kobject.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/device.h> +#include <linux/efi.h> + +static struct kobject *efi_kobj; +static struct kobject *efivars_kobj; + +/* + * Let's not leave out systab information that snuck into + * the efivars driver + */ +static ssize_t systab_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + char *str = buf; + + if (!kobj || !buf) + return -EINVAL; + + if (efi.mps != EFI_INVALID_TABLE_ADDR) + str += sprintf(str, "MPS=0x%lx\n", efi.mps); + if (efi.acpi20 != EFI_INVALID_TABLE_ADDR) + 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 (efi.hcdp != EFI_INVALID_TABLE_ADDR) + str += sprintf(str, "HCDP=0x%lx\n", efi.hcdp); + if (efi.boot_info != EFI_INVALID_TABLE_ADDR) + str += sprintf(str, "BOOTINFO=0x%lx\n", efi.boot_info); + if (efi.uga != EFI_INVALID_TABLE_ADDR) + str += sprintf(str, "UGA=0x%lx\n", efi.uga); + + return str - buf; +} + +static struct kobj_attribute efi_attr_systab = + __ATTR(systab, 0400, systab_show, NULL); + +static struct attribute *efi_subsys_attrs[] = { + &efi_attr_systab.attr, + NULL, /* maybe more in the future? */ +}; + +static struct attribute_group efi_subsys_attr_group = { + .attrs = efi_subsys_attrs, +}; + +static struct efivars generic_efivars; +static struct efivar_operations generic_ops; + +static int generic_ops_register(void) +{ + generic_ops.get_variable = efi.get_variable; + generic_ops.set_variable = efi.set_variable; + generic_ops.get_next_variable = efi.get_next_variable; + generic_ops.query_variable_store = efi_query_variable_store; + + return efivars_register(&generic_efivars, &generic_ops, efi_kobj); +} + +static void generic_ops_unregister(void) +{ + efivars_unregister(&generic_efivars); +} + +/* + * We register the efi subsystem with the firmware subsystem and the + * efivars subsystem with the efi subsystem, if the system was booted with + * EFI. + */ +static int __init efisubsys_init(void) +{ + int error; + + if (!efi_enabled(EFI_BOOT)) + return 0; + + /* We register the efi directory at /sys/firmware/efi */ + efi_kobj = kobject_create_and_add("efi", firmware_kobj); + if (!efi_kobj) { + pr_err("efi: Firmware registration failed.\n"); + return -ENOMEM; + } + + error = generic_ops_register(); + if (error) + goto err_put; + + error = sysfs_create_group(efi_kobj, &efi_subsys_attr_group); + if (error) { + pr_err("efi: Sysfs attribute export failed with error %d.\n", + error); + goto err_unregister; + } + + /* and the standard mountpoint for efivarfs */ + efivars_kobj = kobject_create_and_add("efivars", efi_kobj); + if (!efivars_kobj) { + pr_err("efivars: Subsystem registration failed.\n"); + error = -ENOMEM; + goto err_remove_group; + } + + return 0; + +err_remove_group: + sysfs_remove_group(efi_kobj, &efi_subsys_attr_group); +err_unregister: + generic_ops_unregister(); +err_put: + kobject_put(efi_kobj); + return error; +} + +subsys_initcall(efisubsys_init); |