Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/powerpc/platforms/powernv/opal-secvar.c
26481 views
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/of.h>
16
#include <linux/platform_device.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, u64 ksize, u8 *data, u64 *dsize)
58
{
59
int rc;
60
61
if (!key || !dsize)
62
return -EINVAL;
63
64
*dsize = cpu_to_be64(*dsize);
65
66
rc = opal_secvar_get(key, ksize, data, dsize);
67
68
*dsize = be64_to_cpu(*dsize);
69
70
return opal_status_to_err(rc);
71
}
72
73
static int opal_get_next_variable(const char *key, u64 *keylen, u64 keybufsize)
74
{
75
int rc;
76
77
if (!key || !keylen)
78
return -EINVAL;
79
80
*keylen = cpu_to_be64(*keylen);
81
82
rc = opal_secvar_get_next(key, keylen, keybufsize);
83
84
*keylen = be64_to_cpu(*keylen);
85
86
return opal_status_to_err(rc);
87
}
88
89
static int opal_set_variable(const char *key, u64 ksize, u8 *data, u64 dsize)
90
{
91
int rc;
92
93
if (!key || !data)
94
return -EINVAL;
95
96
rc = opal_secvar_enqueue_update(key, ksize, data, dsize);
97
98
return opal_status_to_err(rc);
99
}
100
101
static ssize_t opal_secvar_format(char *buf, size_t bufsize)
102
{
103
ssize_t rc = 0;
104
struct device_node *node;
105
const char *format;
106
107
node = of_find_compatible_node(NULL, NULL, "ibm,secvar-backend");
108
if (!of_device_is_available(node)) {
109
rc = -ENODEV;
110
goto out;
111
}
112
113
rc = of_property_read_string(node, "format", &format);
114
if (rc)
115
goto out;
116
117
rc = snprintf(buf, bufsize, "%s", format);
118
119
out:
120
of_node_put(node);
121
122
return rc;
123
}
124
125
static int opal_secvar_max_size(u64 *max_size)
126
{
127
int rc;
128
struct device_node *node;
129
130
node = of_find_compatible_node(NULL, NULL, "ibm,secvar-backend");
131
if (!node)
132
return -ENODEV;
133
134
if (!of_device_is_available(node)) {
135
rc = -ENODEV;
136
goto out;
137
}
138
139
rc = of_property_read_u64(node, "max-var-size", max_size);
140
141
out:
142
of_node_put(node);
143
return rc;
144
}
145
146
static const struct secvar_operations opal_secvar_ops = {
147
.get = opal_get_variable,
148
.get_next = opal_get_next_variable,
149
.set = opal_set_variable,
150
.format = opal_secvar_format,
151
.max_size = opal_secvar_max_size,
152
};
153
154
static int opal_secvar_probe(struct platform_device *pdev)
155
{
156
if (!opal_check_token(OPAL_SECVAR_GET)
157
|| !opal_check_token(OPAL_SECVAR_GET_NEXT)
158
|| !opal_check_token(OPAL_SECVAR_ENQUEUE_UPDATE)) {
159
pr_err("OPAL doesn't support secure variables\n");
160
return -ENODEV;
161
}
162
163
return set_secvar_ops(&opal_secvar_ops);
164
}
165
166
static const struct of_device_id opal_secvar_match[] = {
167
{ .compatible = "ibm,secvar-backend",},
168
{},
169
};
170
171
static struct platform_driver opal_secvar_driver = {
172
.driver = {
173
.name = "secvar",
174
.of_match_table = opal_secvar_match,
175
},
176
};
177
178
static int __init opal_secvar_init(void)
179
{
180
return platform_driver_probe(&opal_secvar_driver, opal_secvar_probe);
181
}
182
device_initcall(opal_secvar_init);
183
184