From: Daniel Axtens <dja@axtens.net>
To: nayna@linux.ibm.com, cclaudio@linux.ibm.com,
linux-fsdevel@vger.kernel.org, greg@kroah.com,
linuxppc-dev@lists.ozlabs.org
Cc: Daniel Axtens <dja@axtens.net>
Subject: [WIP RFC PATCH 4/6] powerpc/powernv: Add support for OPAL secure variables
Date: Mon, 20 May 2019 16:25:51 +1000 [thread overview]
Message-ID: <20190520062553.14947-5-dja@axtens.net> (raw)
In-Reply-To: <20190520062553.14947-1-dja@axtens.net>
From: Claudio Carvalho <cclaudio@linux.ibm.com>
[dja: this is a WIP version - a new version is coming that changes
the interface. I also had to renumber the opal calls to get this
to apply. Basically, this is an illustration of the concept: more
work would be required to get this to actually function.]
The X.509 certificates trusted by the platform and other information
required to secure boot the host OS kernel are wrapped in secure
variables, which are controlled by OPAL.
The OPAL secure variables can be handled through the following OPAL
calls.
OPAL_SECVAR_GET:
Returns the data for a given secure variable name and vendor GUID.
OPAL_SECVAR_GET_NEXT:
For a given secure variable, it returns the name and vendor GUID
of the next variable.
OPAL_SECVAR_ENQUEUE:
Enqueue the supplied secure variable update so that it can be processed
by OPAL in the next boot. Variable updates cannot be be processed right
away because the variable storage is write locked at runtime.
OPAL_SECVAR_INFO:
Returns size information about the variable.
This patch adds support for OPAL secure variables by setting up the EFI
runtime variable services to make OPAL calls.
This patch also introduces CONFIG_OPAL_SECVAR for enabling the OPAL
secure variables support in the kernel. Since CONFIG_OPAL_SECVAR selects
CONFIG_EFI, it also allow us to manage the OPAL secure variables from
userspace via efivarfs.
Signed-off-by: Claudio Carvalho <cclaudio@linux.ibm.com>
Signed-off-by: Daniel Axtens <dja@axtens.net>
---
arch/powerpc/include/asm/opal-api.h | 6 +-
arch/powerpc/include/asm/opal.h | 10 ++
arch/powerpc/platforms/Kconfig | 3 +
arch/powerpc/platforms/powernv/Kconfig | 9 +
arch/powerpc/platforms/powernv/Makefile | 1 +
arch/powerpc/platforms/powernv/opal-call.c | 4 +
arch/powerpc/platforms/powernv/opal-secvar.c | 179 +++++++++++++++++++
7 files changed, 211 insertions(+), 1 deletion(-)
create mode 100644 arch/powerpc/platforms/powernv/opal-secvar.c
diff --git a/arch/powerpc/include/asm/opal-api.h b/arch/powerpc/include/asm/opal-api.h
index e1577cfa7186..8054e1e983ff 100644
--- a/arch/powerpc/include/asm/opal-api.h
+++ b/arch/powerpc/include/asm/opal-api.h
@@ -212,7 +212,11 @@
#define OPAL_HANDLE_HMI2 166
#define OPAL_NX_COPROC_INIT 167
#define OPAL_XIVE_GET_VP_STATE 170
-#define OPAL_LAST 170
+#define OPAL_SECVAR_GET 171
+#define OPAL_SECVAR_GET_NEXT 172
+#define OPAL_SECVAR_ENQUEUE 173
+#define OPAL_SECVAR_INFO 174
+#define OPAL_LAST 174
#define QUIESCE_HOLD 1 /* Spin all calls at entry */
#define QUIESCE_REJECT 2 /* Fail all calls with OPAL_BUSY */
diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h
index 4cc37e708bc7..4b8046caaf4f 100644
--- a/arch/powerpc/include/asm/opal.h
+++ b/arch/powerpc/include/asm/opal.h
@@ -394,6 +394,16 @@ void opal_powercap_init(void);
void opal_psr_init(void);
void opal_sensor_groups_init(void);
+extern int opal_secvar_get(uint64_t name, uint64_t vendor, uint64_t attr,
+ uint64_t data_size, uint64_t data);
+extern int opal_secvar_get_next(uint64_t name_size, uint64_t name,
+ uint64_t vendor);
+extern int opal_secvar_enqueue(uint64_t name, uint64_t vendor, uint64_t attr,
+ uint64_t data_size, uint64_t data);
+extern int opal_secvar_info(uint64_t attr, uint64_t storage_space,
+ uint64_t remaining_space,
+ uint64_t max_variable_size);
+
#endif /* __ASSEMBLY__ */
#endif /* _ASM_POWERPC_OPAL_H */
diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig
index f3fb79fccc72..8e30510bc0c1 100644
--- a/arch/powerpc/platforms/Kconfig
+++ b/arch/powerpc/platforms/Kconfig
@@ -326,4 +326,7 @@ config XILINX_PCI
bool "Xilinx PCI host bridge support"
depends on PCI && XILINX_VIRTEX
+config EFI
+ bool
+
endmenu
diff --git a/arch/powerpc/platforms/powernv/Kconfig b/arch/powerpc/platforms/powernv/Kconfig
index 850eee860cf2..879f8e766098 100644
--- a/arch/powerpc/platforms/powernv/Kconfig
+++ b/arch/powerpc/platforms/powernv/Kconfig
@@ -47,3 +47,12 @@ config PPC_VAS
VAS adapters are found in POWER9 based systems.
If unsure, say N.
+
+config OPAL_SECVAR
+ bool "OPAL Secure Variables"
+ depends on PPC_POWERNV && !CPU_BIG_ENDIAN
+ select UCS2_STRING
+ select EFI
+ help
+ This enables the kernel to access OPAL secure variables via EFI
+ runtime variable services.
diff --git a/arch/powerpc/platforms/powernv/Makefile b/arch/powerpc/platforms/powernv/Makefile
index da2e99efbd04..1511d836fd19 100644
--- a/arch/powerpc/platforms/powernv/Makefile
+++ b/arch/powerpc/platforms/powernv/Makefile
@@ -16,3 +16,4 @@ obj-$(CONFIG_PERF_EVENTS) += opal-imc.o
obj-$(CONFIG_PPC_MEMTRACE) += memtrace.o
obj-$(CONFIG_PPC_VAS) += vas.o vas-window.o vas-debug.o
obj-$(CONFIG_OCXL_BASE) += ocxl.o
+obj-$(CONFIG_OPAL_SECVAR) += opal-secvar.o
diff --git a/arch/powerpc/platforms/powernv/opal-call.c b/arch/powerpc/platforms/powernv/opal-call.c
index 36c8fa3647a2..1a2e080dd027 100644
--- a/arch/powerpc/platforms/powernv/opal-call.c
+++ b/arch/powerpc/platforms/powernv/opal-call.c
@@ -288,3 +288,7 @@ OPAL_CALL(opal_pci_set_pbcq_tunnel_bar, OPAL_PCI_SET_PBCQ_TUNNEL_BAR);
OPAL_CALL(opal_sensor_read_u64, OPAL_SENSOR_READ_U64);
OPAL_CALL(opal_sensor_group_enable, OPAL_SENSOR_GROUP_ENABLE);
OPAL_CALL(opal_nx_coproc_init, OPAL_NX_COPROC_INIT);
+OPAL_CALL(opal_secvar_get, OPAL_SECVAR_GET);
+OPAL_CALL(opal_secvar_get_next, OPAL_SECVAR_GET_NEXT);
+OPAL_CALL(opal_secvar_enqueue, OPAL_SECVAR_ENQUEUE);
+OPAL_CALL(opal_secvar_info, OPAL_SECVAR_INFO)
diff --git a/arch/powerpc/platforms/powernv/opal-secvar.c b/arch/powerpc/platforms/powernv/opal-secvar.c
new file mode 100644
index 000000000000..e333828bd0bc
--- /dev/null
+++ b/arch/powerpc/platforms/powernv/opal-secvar.c
@@ -0,0 +1,179 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * PowerNV code for secure variables
+ *
+ * Copyright (C) 2019 IBM Corporation
+ * Author: Claudio Carvalho <cclaudio@linux.ibm.com>
+ *
+ */
+#define pr_fmt(fmt) "secvar: "fmt
+
+#include <linux/efi.h>
+#include <asm/machdep.h>
+#include <asm/opal.h>
+
+static bool opal_secvar_supported;
+
+static efi_status_t opal_to_efi_status_log(int rc, const char *func_name)
+{
+ efi_status_t status;
+
+ switch (rc) {
+ case OPAL_EMPTY:
+ status = EFI_NOT_FOUND;
+ break;
+ case OPAL_HARDWARE:
+ status = EFI_DEVICE_ERROR;
+ break;
+ case OPAL_NO_MEM:
+ pr_err("%s: No space in the volatile storage\n", func_name);
+ status = EFI_OUT_OF_RESOURCES;
+ break;
+ case OPAL_PARAMETER:
+ status = EFI_INVALID_PARAMETER;
+ break;
+ case OPAL_PARTIAL:
+ status = EFI_BUFFER_TOO_SMALL;
+ break;
+ case OPAL_PERMISSION:
+ status = EFI_WRITE_PROTECTED;
+ break;
+ case OPAL_RESOURCE:
+ pr_err("%s: No space in the non-volatile storage\n", func_name);
+ status = EFI_OUT_OF_RESOURCES;
+ break;
+ case OPAL_SUCCESS:
+ status = EFI_SUCCESS;
+ break;
+ default:
+ pr_err("%s: Unknown OPAL error %d\n", func_name, rc);
+ status = EFI_DEVICE_ERROR;
+ break;
+ }
+
+ return status;
+}
+
+#define opal_to_efi_status(rc) opal_to_efi_status_log(rc, __func__)
+
+static efi_status_t
+opal_get_variable(efi_char16_t *name, efi_guid_t *vendor, u32 *attr,
+ unsigned long *data_size, void *data)
+{
+ int rc;
+
+ if (!opal_secvar_supported)
+ return EFI_UNSUPPORTED;
+
+ *data_size = cpu_to_be64(*data_size);
+
+ rc = opal_secvar_get(__pa(name), __pa(vendor), __pa(attr),
+ __pa(data_size), __pa(data));
+ /*
+ * The @attr is an optional output parameter. It is returned in
+ * big-endian.
+ */
+ if (attr)
+ *attr = be32_to_cpup(attr);
+ *data_size = be64_to_cpu(*data_size);
+
+ return opal_to_efi_status(rc);
+}
+
+static efi_status_t
+opal_get_next_variable(unsigned long *name_size, efi_char16_t *name,
+ efi_guid_t *vendor)
+{
+ int rc;
+
+ if (!opal_secvar_supported)
+ return EFI_UNSUPPORTED;
+
+ *name_size = cpu_to_be64(*name_size);
+
+ rc = opal_secvar_get_next(__pa(name_size), __pa(name),
+ __pa(vendor));
+
+ *name_size = be64_to_cpu(*name_size);
+
+ return opal_to_efi_status(rc);
+}
+
+static efi_status_t
+opal_set_variable(efi_char16_t *name, efi_guid_t *vendor, u32 attr,
+ unsigned long data_size, void *data)
+{
+ int rc;
+
+ if (!opal_secvar_supported)
+ return EFI_UNSUPPORTED;
+ /*
+ * The secure variable update must be enqueued in order to be processed
+ * in the next boot by firmware. The secure variable storage is write
+ * locked at runtime.
+ */
+ rc = opal_secvar_enqueue(__pa(name), __pa(vendor), attr,
+ data_size, __pa(data));
+ return opal_to_efi_status(rc);
+}
+
+static efi_status_t
+opal_query_variable_info(u32 attr, u64 *storage_space, u64 *remaining_space,
+ u64 *max_variable_size)
+{
+ int rc;
+
+ if (!opal_secvar_supported)
+ return EFI_UNSUPPORTED;
+
+ *storage_space = cpu_to_be64p(storage_space);
+ *remaining_space = cpu_to_be64p(remaining_space);
+ *max_variable_size = cpu_to_be64p(max_variable_size);
+
+ rc = opal_secvar_info(attr, __pa(storage_space), __pa(remaining_space),
+ __pa(max_variable_size));
+
+ *storage_space = be64_to_cpup(storage_space);
+ *remaining_space = be64_to_cpup(remaining_space);
+ *max_variable_size = be64_to_cpup(max_variable_size);
+
+ return opal_to_efi_status(rc);
+}
+
+static void pnv_efi_runtime_setup(void)
+{
+ /*
+ * The opal wrappers below treat the @name, @vendor, and @data
+ * parameters as little endian blobs.
+ * @name is a ucs2 string
+ * @vendor is the vendor GUID. It is converted to LE in the kernel
+ * @data variable data, which layout may be different for each variable
+ */
+ efi.get_variable = opal_get_variable;
+ efi.get_next_variable = opal_get_next_variable;
+ efi.set_variable = opal_set_variable;
+ efi.query_variable_info = opal_query_variable_info;
+
+ if (!opal_check_token(OPAL_SECVAR_GET) ||
+ !opal_check_token(OPAL_SECVAR_GET_NEXT) ||
+ !opal_check_token(OPAL_SECVAR_ENQUEUE) ||
+ !opal_check_token(OPAL_SECVAR_INFO)) {
+ pr_err("OPAL doesn't support secure variables\n");
+ opal_secvar_supported = false;
+ } else {
+ opal_secvar_supported = true;
+ }
+}
+
+static int __init pnv_efi_init(void)
+{
+ set_bit(EFI_RUNTIME_SERVICES, &efi.flags);
+ set_bit(EFI_BOOT, &efi.flags);
+
+ if (IS_ENABLED(CONFIG_64BIT))
+ set_bit(EFI_64BIT, &efi.flags);
+
+ pnv_efi_runtime_setup();
+ return 0;
+}
+machine_arch_initcall(powernv, pnv_efi_init);
--
2.19.1
next prev parent reply other threads:[~2019-05-20 6:26 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-05-20 6:25 [WIP RFC PATCH 0/6] Generic Firmware Variable Filesystem Daniel Axtens
2019-05-20 6:25 ` [WIP RFC PATCH 1/6] kernfs: add create() and unlink() hooks Daniel Axtens
2019-05-20 6:25 ` [WIP RFC PATCH 2/6] fwvarfs: a generic firmware variable filesystem Daniel Axtens
2019-05-20 6:25 ` [WIP RFC PATCH 3/6] fwvarfs: efi backend Daniel Axtens
2019-05-20 6:25 ` Daniel Axtens [this message]
2019-05-20 6:25 ` [WIP RFC PATCH 5/6] powerpc/powernv: Remove EFI support for OPAL secure variables Daniel Axtens
2019-05-20 6:25 ` [WIP RFC PATCH 6/6] fwvarfs: Add opal_secvar backend Daniel Axtens
2019-05-31 4:04 ` [WIP RFC PATCH 0/6] Generic Firmware Variable Filesystem Nayna
2019-06-03 6:04 ` Daniel Axtens
2019-06-03 7:29 ` Greg KH
2019-06-03 23:56 ` Daniel Axtens
2019-06-04 20:01 ` Nayna
2019-06-04 20:05 ` Matthew Garrett
2019-06-05 8:13 ` Greg KH
2019-06-04 20:33 ` Nayna
2019-06-05 6:14 ` Greg KH
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=20190520062553.14947-5-dja@axtens.net \
--to=dja@axtens.net \
--cc=cclaudio@linux.ibm.com \
--cc=greg@kroah.com \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linuxppc-dev@lists.ozlabs.org \
--cc=nayna@linux.ibm.com \
/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).