From: Octavian Purdila <octavian.purdila-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
To: "Rafael J. Wysocki" <rjw-LthD3rsA81gm4RdzfppkhA@public.gmane.org>,
Len Brown <lenb-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>,
Matt Fleming
<matt-mF/unelCI9GS6iBeEJttW/XRex20P6io@public.gmane.org>,
Mark Brown <broonie-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>,
Wolfram Sang <wsa-z923LK4zBo2bacvFa/9K2g@public.gmane.org>
Cc: Joel Becker <jlbec-aKy9MeLSZ9dg9hUCZPvPmw@public.gmane.org>,
Christoph Hellwig <hch-jcswGhMUV9g@public.gmane.org>,
linux-acpi-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-efi-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-i2c-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-spi-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
irina.tirdea-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org,
Octavian Purdila
<octavian.purdila-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
Subject: [RFC PATCH 07/10] efi: load SSTDs from EFI variables
Date: Thu, 31 Mar 2016 12:37:03 +0300 [thread overview]
Message-ID: <1459417026-6697-8-git-send-email-octavian.purdila@intel.com> (raw)
In-Reply-To: <1459417026-6697-1-git-send-email-octavian.purdila-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
This patch allows SSDTs to be loaded from EFI variables. It works by
specifying the EFI variable name containing the SSDT to be loaded. All
variables with the same name (regardless of the vendor GUID) will be
loaded.
Note that we can't use acpi_install_table and we must rely on the
dynamic ACPI table loading and bus re-scanning mechanisms. That is
because I2C/SPI controllers are initialized earlier then the EFI
subsystems and all I2C/SPI ACPI devices are enumerated when the
I2C/SPI controllers are initialized.
Signed-off-by: Octavian Purdila <octavian.purdila-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
---
Documentation/acpi/ssdt-overlays.txt | 66 +++++++++++++++++++++
Documentation/kernel-parameters.txt | 7 +++
drivers/firmware/efi/efi.c | 107 +++++++++++++++++++++++++++++++++++
3 files changed, 180 insertions(+)
diff --git a/Documentation/acpi/ssdt-overlays.txt b/Documentation/acpi/ssdt-overlays.txt
index a94c3f9..7c588be 100644
--- a/Documentation/acpi/ssdt-overlays.txt
+++ b/Documentation/acpi/ssdt-overlays.txt
@@ -92,3 +92,69 @@ cp ssdt.aml kernel/firmware/acpi
find kernel | cpio -H newc --create > /boot/instrumented_initrd
cat /boot/initrd >>/boot/instrumented_initrd
+== Loading ACPI SSDTs from EFI variables ==
+
+This is the preferred method, when EFI is supported on the platform, because it
+allows a persistent, OS independent way of storing the user defined SSDTs. There
+is also work underway to implement EFI support for loading user defined SSDTs
+and using this method will make it easier to convert to the EFI loading
+mechanism when that will arrive.
+
+In order to load SSDTs from an EFI variable the efivar_ssdt kernel command line
+parameter can be used. The argument for the option is the variable name to
+use. If there are multiple variables with the same name but with different
+vendor GUIDs, all of them will be loaded.
+
+In order to store the AML code in an EFI variable the efivarfs filesystem can be
+used. It is enabled and mounted by default in /sys/firmware/efi/efivars in all
+recent distribution.
+
+Creating a new file in /sys/firmware/efi/efivars will automatically create a new
+EFI variable. Updating a file in /sys/firmware/efi/efivars will update the EFI
+variable. Please note that the file name needs to be specially formatted as
+"Name-GUID" and that the first 4 bytes in the file (little-endian format)
+represent the attributes of the EFI variable (see EFI_VARIABLE_MASK in
+include/linux/efi.h). Writing to the file must also be done with one write
+operation.
+
+For example, you can use the following bash script to create/update an EFI
+variable with the content from a given file:
+
+#!/bin/sh -e
+
+while ! [ -z "$1" ]; do
+ case "$1" in
+ "-f") filename="$2"; shift;;
+ "-g") guid="$2"; shift;;
+ *) name="$1";;
+ esac
+ shift
+done
+
+if [ -z "$name" ] || [ -z "$filename" ]; then
+ echo "Syntax: ${0##*/} -f filename [ -g guid ] name"
+ exit 1
+fi
+
+EFIVARFS='/sys/firmware/efi/efivars'
+
+[ -d "$EFIVARFS" ] || exit 2
+
+if stat -tf $EFIVARFS | grep -q -v de5e81e4; then
+ mount -t efivarfs none $EFIVARFS
+fi
+
+# try to pick up an existing GUID
+if [ -z "$guid" ]; then
+ guid=$(find "$EFIVARFS" -name "$name-*" | head -n1 | cut -f2- -d-)
+fi
+
+# use a randomly generated GUID
+if [ -z "$guid" ]; then
+ guid="$(cat /proc/sys/kernel/random/uuid)"
+fi
+
+tmp=$(mktemp)
+/bin/echo -ne "\007\000\000\000" | cat - $filename > $tmp
+dd if=$tmp of="$EFIVARFS/$name-$guid" bs=$(stat -c %s $tmp)
+rm $tmp
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 9a53c92..fe89cda 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -1144,6 +1144,13 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
Address Range Mirroring feature even if your box
doesn't support it.
+ efivar_ssdt= [EFI; X86] Name of an EFI variable that contains an SSDT
+ that is to be dynamically loaded by Linux. If there are
+ multiple variables with the same name but with different
+ vendor GUIDs, all of them will be loaded. See
+ Documentation/acpi/ssdt-overlays.txt for details.
+
+
eisa_irq_edge= [PARISC,HW]
See header of drivers/parisc/eisa.c.
diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c
index 2cd37da..dda4778 100644
--- a/drivers/firmware/efi/efi.c
+++ b/drivers/firmware/efi/efi.c
@@ -24,6 +24,8 @@
#include <linux/of_fdt.h>
#include <linux/io.h>
#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/acpi.h>
#include <asm/early_ioremap.h>
@@ -193,6 +195,108 @@ static void generic_ops_unregister(void)
efivars_unregister(&generic_efivars);
}
+#if IS_ENABLED(CONFIG_ACPI)
+#define EFIVAR_SSDT_NAME_MAX 16
+static char efivar_ssdt[EFIVAR_SSDT_NAME_MAX];
+static int __init efivar_ssdt_setup(char *str)
+{
+ if (strlen(str) < sizeof(efivar_ssdt))
+ memcpy(efivar_ssdt, str, strlen(str));
+ else
+ pr_warn("efivar_ssdt: name too long: %s\n", str);
+ return 0;
+}
+__setup("efivar_ssdt=", efivar_ssdt_setup);
+
+static LIST_HEAD(efivar_ssdts);
+
+static inline void pr_efivar_name(efi_char16_t *name16)
+{
+ char name[EFIVAR_SSDT_NAME_MAX];
+ int i;
+
+ for (i = 0; i < EFIVAR_SSDT_NAME_MAX - 1; i++)
+ name[i] = name16[i] & 0xFF;
+ name[i] = 0;
+ pr_cont("%s", name);
+}
+
+static __init int efivar_acpi_iter(efi_char16_t *name, efi_guid_t vendor,
+ unsigned long name_size, void *data)
+{
+ int i;
+ int str_len = name_size / sizeof(efi_char16_t);
+ struct efivar_entry *entry;
+
+ if (str_len != strlen(efivar_ssdt) + 1)
+ return 0;
+
+ for (i = 0; i < str_len; i++)
+ if ((name[i] & 0xFF) != efivar_ssdt[i])
+ return 0;
+
+ entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+ if (!entry)
+ return -ENOMEM;
+
+ memcpy(entry->var.VariableName, name, name_size);
+ memcpy(&entry->var.VendorGuid, &vendor, sizeof(efi_guid_t));
+
+ efivar_entry_add(entry, &efivar_ssdts);
+
+ return 0;
+}
+
+static __init int efivar_ssdt_load(void)
+{
+ struct efivar_entry *i;
+ int err;
+
+ err = efivar_init(efivar_acpi_iter, NULL, false, false,
+ &efivar_ssdts);
+ if (err) {
+ pr_err("%s: efivar_init failed: %d\n", __func__, err);
+ return err;
+ }
+
+ list_for_each_entry(i, &efivar_ssdts, list) {
+ void *data;
+ unsigned long size;
+
+ pr_info("loading SSDT from EFI variable ");
+ pr_efivar_name(i->var.VariableName); pr_cont("\n");
+
+ err = efivar_entry_size(i, &size);
+ if (err) {
+ pr_err("failed to get size\n");
+ continue;
+ }
+
+ data = kmalloc(size, GFP_KERNEL);
+ if (!data)
+ continue;
+
+ err = efivar_entry_get(i, NULL, &size, data);
+ if (err) {
+ pr_err("failed to get data\n");
+ kfree(data);
+ continue;
+ }
+
+ err = acpi_load_table(data);
+ if (err) {
+ pr_err("failed to load table: %d\n", err);
+ kfree(data);
+ continue;
+ }
+
+ add_taint(TAINT_OVERLAY_ACPI_TABLE, LOCKDEP_STILL_OK);
+ }
+
+ return 0;
+}
+#endif
+
/*
* We register the efi subsystem with the firmware subsystem and the
* efivars subsystem with the efi subsystem, if the system was booted with
@@ -216,6 +320,9 @@ static int __init efisubsys_init(void)
if (error)
goto err_put;
+ if (IS_ENABLED(CONFIG_ACPI))
+ efivar_ssdt_load();
+
error = sysfs_create_group(efi_kobj, &efi_subsys_attr_group);
if (error) {
pr_err("efi: Sysfs attribute export failed with error %d.\n",
--
1.9.1
--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
next prev parent reply other threads:[~2016-03-31 9:37 UTC|newest]
Thread overview: 39+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-03-31 9:36 [RFC PATCH 00/10] ACPI overlays Octavian Purdila
2016-03-31 9:36 ` [RFC PATCH 01/10] kernel: add TAINT_OVERLAY_ACPI_TABLE Octavian Purdila
2016-03-31 9:36 ` [RFC PATCH 02/10] acpi: install SSDT tables from initrd Octavian Purdila
2016-04-01 5:05 ` Zheng, Lv
2016-04-01 10:11 ` Octavian Purdila
[not found] ` <CAE1zotJ1fa4m-_FO3PUQK8_p0vHcfWD5TmuMdxOSHDjku421pA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2016-04-04 13:07 ` Octavian Purdila
2016-04-05 0:49 ` Zheng, Lv
2016-04-05 7:23 ` Octavian Purdila
2016-04-06 6:15 ` Zheng, Lv
2016-04-05 0:57 ` Zheng, Lv
2016-03-31 9:36 ` [RFC PATCH 03/10] acpi: add support for ACPI reconfiguration notifiers Octavian Purdila
2016-03-31 9:37 ` [RFC PATCH 04/10] acpi: fix enumeration (visited) flags for bus rescans Octavian Purdila
2016-03-31 9:37 ` [RFC PATCH 05/10] i2c: add support for ACPI reconfigure notifications Octavian Purdila
2016-03-31 9:37 ` [RFC PATCH 06/10] spi: " Octavian Purdila
[not found] ` <1459417026-6697-7-git-send-email-octavian.purdila-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
2016-03-31 17:29 ` Mark Brown
2016-04-01 10:54 ` Octavian Purdila
2016-04-01 14:08 ` Mark Brown
2016-04-01 19:26 ` Rafael J. Wysocki
2016-04-02 16:24 ` Mark Brown
2016-04-04 10:25 ` Octavian Purdila
2016-04-04 16:03 ` Mark Brown
2016-04-04 19:34 ` Octavian Purdila
[not found] ` <CAE1zot+ESGBEYeUbLTreKfkc-6B45uQq3PWhhRfBo1AWd-7Vxw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2016-04-04 21:18 ` Rafael J. Wysocki
[not found] ` <CAJZ5v0gV8N6zgVrwtRFaY98Wv1HsoKs+4=U-s_V29FSpCdFW3g-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2016-04-05 11:49 ` Octavian Purdila
2016-04-05 18:32 ` Mark Brown
[not found] ` <20160405183255.GH1924-GFdadSzt00ze9xe1eoZjHA@public.gmane.org>
2016-04-05 19:16 ` Octavian Purdila
[not found] ` <CAE1zotL7X+di4rHecRW_G-45wUPbbNb9jvn3C_zjD4XttZ4v3w-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2016-04-05 21:20 ` Mark Brown
2016-04-05 18:24 ` Mark Brown
[not found] ` <1459417026-6697-1-git-send-email-octavian.purdila-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
2016-03-31 9:37 ` Octavian Purdila [this message]
2016-03-31 9:37 ` [RFC PATCH 08/10] configfs: fix CONFIGFS_BIN_ATTR_[RW]O definitions Octavian Purdila
2016-03-31 9:37 ` [RFC PATCH 09/10] acpi: add support for configfs Octavian Purdila
2016-03-31 9:37 ` [RFC PATCH 10/10] acpi: add support for loading SSDTs via configfs Octavian Purdila
[not found] ` <1459417026-6697-11-git-send-email-octavian.purdila-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
2016-04-01 4:55 ` Zheng, Lv
[not found] ` <1AE640813FDE7649BE1B193DEA596E883BB66233-0J0gbvR4kThpB2pF5aRoyrfspsVTdybXVpNB7YpNyf8@public.gmane.org>
2016-04-01 10:01 ` Octavian Purdila
2016-04-05 3:11 ` Zheng, Lv
[not found] ` <1AE640813FDE7649BE1B193DEA596E883BB6677B-0J0gbvR4kThpB2pF5aRoyrfspsVTdybXVpNB7YpNyf8@public.gmane.org>
2016-04-05 8:21 ` Octavian Purdila
2016-04-06 6:05 ` Zheng, Lv
[not found] ` <1AE640813FDE7649BE1B193DEA596E883BB66B8C-0J0gbvR4kThpB2pF5aRoyrfspsVTdybXVpNB7YpNyf8@public.gmane.org>
2016-04-06 18:46 ` Octavian Purdila
[not found] ` <CAE1zotKa+t5cxznWfPyQ599k9ZB=akOuEDZusWcJgzux8wqp5A-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2016-04-07 2:42 ` Zheng, Lv
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1459417026-6697-8-git-send-email-octavian.purdila@intel.com \
--to=octavian.purdila-ral2jqcrhueavxtiumwx3w@public.gmane.org \
--cc=broonie-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org \
--cc=hch-jcswGhMUV9g@public.gmane.org \
--cc=irina.tirdea-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org \
--cc=jlbec-aKy9MeLSZ9dg9hUCZPvPmw@public.gmane.org \
--cc=lenb-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org \
--cc=linux-acpi-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
--cc=linux-efi-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
--cc=linux-i2c-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
--cc=linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
--cc=linux-spi-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
--cc=matt-mF/unelCI9GS6iBeEJttW/XRex20P6io@public.gmane.org \
--cc=rjw-LthD3rsA81gm4RdzfppkhA@public.gmane.org \
--cc=wsa-z923LK4zBo2bacvFa/9K2g@public.gmane.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).