xref: /linux/arch/powerpc/platforms/powernv/opal-secvar.c (revision 26fbb4c8c7c3ee9a4c3b4de555a8587b5a19154e)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * PowerNV code for secure variables
4  *
5  * Copyright (C) 2019 IBM Corporation
6  * Author: Claudio Carvalho
7  *         Nayna Jain
8  *
9  * APIs to access secure variables managed by OPAL.
10  */
11 
12 #define pr_fmt(fmt) "secvar: "fmt
13 
14 #include <linux/types.h>
15 #include <linux/platform_device.h>
16 #include <linux/of_platform.h>
17 #include <asm/opal.h>
18 #include <asm/secvar.h>
19 #include <asm/secure_boot.h>
20 
21 static int opal_status_to_err(int rc)
22 {
23 	int err;
24 
25 	switch (rc) {
26 	case OPAL_SUCCESS:
27 		err = 0;
28 		break;
29 	case OPAL_UNSUPPORTED:
30 		err = -ENXIO;
31 		break;
32 	case OPAL_PARAMETER:
33 		err = -EINVAL;
34 		break;
35 	case OPAL_RESOURCE:
36 		err = -ENOSPC;
37 		break;
38 	case OPAL_HARDWARE:
39 		err = -EIO;
40 		break;
41 	case OPAL_NO_MEM:
42 		err = -ENOMEM;
43 		break;
44 	case OPAL_EMPTY:
45 		err = -ENOENT;
46 		break;
47 	case OPAL_PARTIAL:
48 		err = -EFBIG;
49 		break;
50 	default:
51 		err = -EINVAL;
52 	}
53 
54 	return err;
55 }
56 
57 static int opal_get_variable(const char *key, uint64_t ksize,
58 			     u8 *data, uint64_t *dsize)
59 {
60 	int rc;
61 
62 	if (!key || !dsize)
63 		return -EINVAL;
64 
65 	*dsize = cpu_to_be64(*dsize);
66 
67 	rc = opal_secvar_get(key, ksize, data, dsize);
68 
69 	*dsize = be64_to_cpu(*dsize);
70 
71 	return opal_status_to_err(rc);
72 }
73 
74 static int opal_get_next_variable(const char *key, uint64_t *keylen,
75 				  uint64_t keybufsize)
76 {
77 	int rc;
78 
79 	if (!key || !keylen)
80 		return -EINVAL;
81 
82 	*keylen = cpu_to_be64(*keylen);
83 
84 	rc = opal_secvar_get_next(key, keylen, keybufsize);
85 
86 	*keylen = be64_to_cpu(*keylen);
87 
88 	return opal_status_to_err(rc);
89 }
90 
91 static int opal_set_variable(const char *key, uint64_t ksize, u8 *data,
92 			     uint64_t dsize)
93 {
94 	int rc;
95 
96 	if (!key || !data)
97 		return -EINVAL;
98 
99 	rc = opal_secvar_enqueue_update(key, ksize, data, dsize);
100 
101 	return opal_status_to_err(rc);
102 }
103 
104 static const struct secvar_operations opal_secvar_ops = {
105 	.get = opal_get_variable,
106 	.get_next = opal_get_next_variable,
107 	.set = opal_set_variable,
108 };
109 
110 static int opal_secvar_probe(struct platform_device *pdev)
111 {
112 	if (!opal_check_token(OPAL_SECVAR_GET)
113 			|| !opal_check_token(OPAL_SECVAR_GET_NEXT)
114 			|| !opal_check_token(OPAL_SECVAR_ENQUEUE_UPDATE)) {
115 		pr_err("OPAL doesn't support secure variables\n");
116 		return -ENODEV;
117 	}
118 
119 	set_secvar_ops(&opal_secvar_ops);
120 
121 	return 0;
122 }
123 
124 static const struct of_device_id opal_secvar_match[] = {
125 	{ .compatible = "ibm,secvar-backend",},
126 	{},
127 };
128 
129 static struct platform_driver opal_secvar_driver = {
130 	.driver = {
131 		.name = "secvar",
132 		.of_match_table = opal_secvar_match,
133 	},
134 };
135 
136 static int __init opal_secvar_init(void)
137 {
138 	return platform_driver_probe(&opal_secvar_driver, opal_secvar_probe);
139 }
140 device_initcall(opal_secvar_init);
141