blob: 8875930dd25d4254232db499b70501a18e5acf61 [file] [log] [blame]
Joel Stanleya1fccbf2020-06-23 17:25:56 +09301From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
2From: Nayna Jain <nayna@linux.ibm.com>
3Date: Sun, 10 Nov 2019 21:10:33 -0600
Joel Stanleycb9bf572020-09-29 16:18:12 +09304Subject: [PATCH 10/19] powerpc/powernv: Add OPAL API interface to access
Joel Stanleya1fccbf2020-06-23 17:25:56 +09305 secure variable
6
7The X.509 certificates trusted by the platform and required to secure
8boot the OS kernel are wrapped in secure variables, which are
9controlled by OPAL.
10
11This patch adds firmware/kernel interface to read and write OPAL
12secure variables based on the unique key.
13
14This support can be enabled using CONFIG_OPAL_SECVAR.
15
16Signed-off-by: Claudio Carvalho <cclaudio@linux.ibm.com>
17Signed-off-by: Nayna Jain <nayna@linux.ibm.com>
18Signed-off-by: Eric Richter <erichte@linux.ibm.com>
19[mpe: Make secvar_ops __ro_after_init, only build opal-secvar.c if PPC_SECURE_BOOT=y]
20Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
21Link: https://lore.kernel.org/r/1573441836-3632-2-git-send-email-nayna@linux.ibm.com
22(cherry picked from commit 9155e2341aa8b5df057dc1c77633b33d1a4f17d2)
23Signed-off-by: Joel Stanley <joel@jms.id.au>
24---
25 arch/powerpc/include/asm/opal-api.h | 5 +-
26 arch/powerpc/include/asm/opal.h | 7 +
27 arch/powerpc/include/asm/secvar.h | 35 +++++
28 arch/powerpc/kernel/Makefile | 2 +-
29 arch/powerpc/kernel/secvar-ops.c | 17 +++
30 arch/powerpc/platforms/powernv/Makefile | 1 +
31 arch/powerpc/platforms/powernv/opal-call.c | 3 +
32 arch/powerpc/platforms/powernv/opal-secvar.c | 140 +++++++++++++++++++
33 arch/powerpc/platforms/powernv/opal.c | 3 +
34 9 files changed, 211 insertions(+), 2 deletions(-)
35 create mode 100644 arch/powerpc/include/asm/secvar.h
36 create mode 100644 arch/powerpc/kernel/secvar-ops.c
37 create mode 100644 arch/powerpc/platforms/powernv/opal-secvar.c
38
39diff --git a/arch/powerpc/include/asm/opal-api.h b/arch/powerpc/include/asm/opal-api.h
40index 378e3997845a..c1f25a760eb1 100644
41--- a/arch/powerpc/include/asm/opal-api.h
42+++ b/arch/powerpc/include/asm/opal-api.h
43@@ -211,7 +211,10 @@
44 #define OPAL_MPIPL_UPDATE 173
45 #define OPAL_MPIPL_REGISTER_TAG 174
46 #define OPAL_MPIPL_QUERY_TAG 175
47-#define OPAL_LAST 175
48+#define OPAL_SECVAR_GET 176
49+#define OPAL_SECVAR_GET_NEXT 177
50+#define OPAL_SECVAR_ENQUEUE_UPDATE 178
51+#define OPAL_LAST 178
52
53 #define QUIESCE_HOLD 1 /* Spin all calls at entry */
54 #define QUIESCE_REJECT 2 /* Fail all calls with OPAL_BUSY */
55diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h
56index a0cf8fba4d12..9986ac34b8e2 100644
57--- a/arch/powerpc/include/asm/opal.h
58+++ b/arch/powerpc/include/asm/opal.h
59@@ -298,6 +298,13 @@ int opal_sensor_group_clear(u32 group_hndl, int token);
60 int opal_sensor_group_enable(u32 group_hndl, int token, bool enable);
61 int opal_nx_coproc_init(uint32_t chip_id, uint32_t ct);
62
63+int opal_secvar_get(const char *key, uint64_t key_len, u8 *data,
64+ uint64_t *data_size);
65+int opal_secvar_get_next(const char *key, uint64_t *key_len,
66+ uint64_t key_buf_size);
67+int opal_secvar_enqueue_update(const char *key, uint64_t key_len, u8 *data,
68+ uint64_t data_size);
69+
70 s64 opal_mpipl_update(enum opal_mpipl_ops op, u64 src, u64 dest, u64 size);
71 s64 opal_mpipl_register_tag(enum opal_mpipl_tags tag, u64 addr);
72 s64 opal_mpipl_query_tag(enum opal_mpipl_tags tag, u64 *addr);
73diff --git a/arch/powerpc/include/asm/secvar.h b/arch/powerpc/include/asm/secvar.h
74new file mode 100644
75index 000000000000..4cc35b58b986
76--- /dev/null
77+++ b/arch/powerpc/include/asm/secvar.h
78@@ -0,0 +1,35 @@
79+/* SPDX-License-Identifier: GPL-2.0 */
80+/*
81+ * Copyright (C) 2019 IBM Corporation
82+ * Author: Nayna Jain
83+ *
84+ * PowerPC secure variable operations.
85+ */
86+#ifndef SECVAR_OPS_H
87+#define SECVAR_OPS_H
88+
89+#include <linux/types.h>
90+#include <linux/errno.h>
91+
92+extern const struct secvar_operations *secvar_ops;
93+
94+struct secvar_operations {
95+ int (*get)(const char *key, uint64_t key_len, u8 *data,
96+ uint64_t *data_size);
97+ int (*get_next)(const char *key, uint64_t *key_len,
98+ uint64_t keybufsize);
99+ int (*set)(const char *key, uint64_t key_len, u8 *data,
100+ uint64_t data_size);
101+};
102+
103+#ifdef CONFIG_PPC_SECURE_BOOT
104+
105+extern void set_secvar_ops(const struct secvar_operations *ops);
106+
107+#else
108+
109+static inline void set_secvar_ops(const struct secvar_operations *ops) { }
110+
111+#endif
112+
113+#endif
114diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
115index b82f7f5e5121..93b0336090f2 100644
116--- a/arch/powerpc/kernel/Makefile
117+++ b/arch/powerpc/kernel/Makefile
118@@ -158,7 +158,7 @@ ifneq ($(CONFIG_PPC_POWERNV)$(CONFIG_PPC_SVM),)
119 obj-y += ucall.o
120 endif
121
122-obj-$(CONFIG_PPC_SECURE_BOOT) += secure_boot.o ima_arch.o
123+obj-$(CONFIG_PPC_SECURE_BOOT) += secure_boot.o ima_arch.o secvar-ops.o
124
125 # Disable GCOV, KCOV & sanitizers in odd or sensitive code
126 GCOV_PROFILE_prom_init.o := n
127diff --git a/arch/powerpc/kernel/secvar-ops.c b/arch/powerpc/kernel/secvar-ops.c
128new file mode 100644
129index 000000000000..6a29777d6a2d
130--- /dev/null
131+++ b/arch/powerpc/kernel/secvar-ops.c
132@@ -0,0 +1,17 @@
133+// SPDX-License-Identifier: GPL-2.0
134+/*
135+ * Copyright (C) 2019 IBM Corporation
136+ * Author: Nayna Jain
137+ *
138+ * This file initializes secvar operations for PowerPC Secureboot
139+ */
140+
141+#include <linux/cache.h>
142+#include <asm/secvar.h>
143+
144+const struct secvar_operations *secvar_ops __ro_after_init;
145+
146+void set_secvar_ops(const struct secvar_operations *ops)
147+{
148+ secvar_ops = ops;
149+}
150diff --git a/arch/powerpc/platforms/powernv/Makefile b/arch/powerpc/platforms/powernv/Makefile
151index a3ac9646119d..c0f8120045c3 100644
152--- a/arch/powerpc/platforms/powernv/Makefile
153+++ b/arch/powerpc/platforms/powernv/Makefile
154@@ -20,3 +20,4 @@ obj-$(CONFIG_PPC_MEMTRACE) += memtrace.o
155 obj-$(CONFIG_PPC_VAS) += vas.o vas-window.o vas-debug.o
156 obj-$(CONFIG_OCXL_BASE) += ocxl.o
157 obj-$(CONFIG_SCOM_DEBUGFS) += opal-xscom.o
158+obj-$(CONFIG_PPC_SECURE_BOOT) += opal-secvar.o
159diff --git a/arch/powerpc/platforms/powernv/opal-call.c b/arch/powerpc/platforms/powernv/opal-call.c
160index a2aa5e433ac8..5cd0f52d258f 100644
161--- a/arch/powerpc/platforms/powernv/opal-call.c
162+++ b/arch/powerpc/platforms/powernv/opal-call.c
163@@ -290,3 +290,6 @@ OPAL_CALL(opal_nx_coproc_init, OPAL_NX_COPROC_INIT);
164 OPAL_CALL(opal_mpipl_update, OPAL_MPIPL_UPDATE);
165 OPAL_CALL(opal_mpipl_register_tag, OPAL_MPIPL_REGISTER_TAG);
166 OPAL_CALL(opal_mpipl_query_tag, OPAL_MPIPL_QUERY_TAG);
167+OPAL_CALL(opal_secvar_get, OPAL_SECVAR_GET);
168+OPAL_CALL(opal_secvar_get_next, OPAL_SECVAR_GET_NEXT);
169+OPAL_CALL(opal_secvar_enqueue_update, OPAL_SECVAR_ENQUEUE_UPDATE);
170diff --git a/arch/powerpc/platforms/powernv/opal-secvar.c b/arch/powerpc/platforms/powernv/opal-secvar.c
171new file mode 100644
172index 000000000000..14133e120bdd
173--- /dev/null
174+++ b/arch/powerpc/platforms/powernv/opal-secvar.c
175@@ -0,0 +1,140 @@
176+// SPDX-License-Identifier: GPL-2.0
177+/*
178+ * PowerNV code for secure variables
179+ *
180+ * Copyright (C) 2019 IBM Corporation
181+ * Author: Claudio Carvalho
182+ * Nayna Jain
183+ *
184+ * APIs to access secure variables managed by OPAL.
185+ */
186+
187+#define pr_fmt(fmt) "secvar: "fmt
188+
189+#include <linux/types.h>
190+#include <linux/platform_device.h>
191+#include <linux/of_platform.h>
192+#include <asm/opal.h>
193+#include <asm/secvar.h>
194+#include <asm/secure_boot.h>
195+
196+static int opal_status_to_err(int rc)
197+{
198+ int err;
199+
200+ switch (rc) {
201+ case OPAL_SUCCESS:
202+ err = 0;
203+ break;
204+ case OPAL_UNSUPPORTED:
205+ err = -ENXIO;
206+ break;
207+ case OPAL_PARAMETER:
208+ err = -EINVAL;
209+ break;
210+ case OPAL_RESOURCE:
211+ err = -ENOSPC;
212+ break;
213+ case OPAL_HARDWARE:
214+ err = -EIO;
215+ break;
216+ case OPAL_NO_MEM:
217+ err = -ENOMEM;
218+ break;
219+ case OPAL_EMPTY:
220+ err = -ENOENT;
221+ break;
222+ case OPAL_PARTIAL:
223+ err = -EFBIG;
224+ break;
225+ default:
226+ err = -EINVAL;
227+ }
228+
229+ return err;
230+}
231+
232+static int opal_get_variable(const char *key, uint64_t ksize,
233+ u8 *data, uint64_t *dsize)
234+{
235+ int rc;
236+
237+ if (!key || !dsize)
238+ return -EINVAL;
239+
240+ *dsize = cpu_to_be64(*dsize);
241+
242+ rc = opal_secvar_get(key, ksize, data, dsize);
243+
244+ *dsize = be64_to_cpu(*dsize);
245+
246+ return opal_status_to_err(rc);
247+}
248+
249+static int opal_get_next_variable(const char *key, uint64_t *keylen,
250+ uint64_t keybufsize)
251+{
252+ int rc;
253+
254+ if (!key || !keylen)
255+ return -EINVAL;
256+
257+ *keylen = cpu_to_be64(*keylen);
258+
259+ rc = opal_secvar_get_next(key, keylen, keybufsize);
260+
261+ *keylen = be64_to_cpu(*keylen);
262+
263+ return opal_status_to_err(rc);
264+}
265+
266+static int opal_set_variable(const char *key, uint64_t ksize, u8 *data,
267+ uint64_t dsize)
268+{
269+ int rc;
270+
271+ if (!key || !data)
272+ return -EINVAL;
273+
274+ rc = opal_secvar_enqueue_update(key, ksize, data, dsize);
275+
276+ return opal_status_to_err(rc);
277+}
278+
279+static const struct secvar_operations opal_secvar_ops = {
280+ .get = opal_get_variable,
281+ .get_next = opal_get_next_variable,
282+ .set = opal_set_variable,
283+};
284+
285+static int opal_secvar_probe(struct platform_device *pdev)
286+{
287+ if (!opal_check_token(OPAL_SECVAR_GET)
288+ || !opal_check_token(OPAL_SECVAR_GET_NEXT)
289+ || !opal_check_token(OPAL_SECVAR_ENQUEUE_UPDATE)) {
290+ pr_err("OPAL doesn't support secure variables\n");
291+ return -ENODEV;
292+ }
293+
294+ set_secvar_ops(&opal_secvar_ops);
295+
296+ return 0;
297+}
298+
299+static const struct of_device_id opal_secvar_match[] = {
300+ { .compatible = "ibm,secvar-backend",},
301+ {},
302+};
303+
304+static struct platform_driver opal_secvar_driver = {
305+ .driver = {
306+ .name = "secvar",
307+ .of_match_table = opal_secvar_match,
308+ },
309+};
310+
311+static int __init opal_secvar_init(void)
312+{
313+ return platform_driver_probe(&opal_secvar_driver, opal_secvar_probe);
314+}
315+device_initcall(opal_secvar_init);
316diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c
317index 38e90270280b..8355bcd00f93 100644
318--- a/arch/powerpc/platforms/powernv/opal.c
319+++ b/arch/powerpc/platforms/powernv/opal.c
320@@ -1002,6 +1002,9 @@ static int __init opal_init(void)
321 /* Initialise OPAL Power control interface */
322 opal_power_control_init();
323
324+ /* Initialize OPAL secure variables */
325+ opal_pdev_init("ibm,secvar-backend");
326+
327 return 0;
328 }
329 machine_subsys_initcall(powernv, opal_init);