arm64: dts: qcom: sm8550: add TRNG node
[linux-modified.git] / arch / powerpc / kernel / secvar-sysfs.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2019 IBM Corporation <nayna@linux.ibm.com>
4  *
5  * This code exposes secure variables to user via sysfs
6  */
7
8 #define pr_fmt(fmt) "secvar-sysfs: "fmt
9
10 #include <linux/slab.h>
11 #include <linux/compat.h>
12 #include <linux/string.h>
13 #include <linux/of.h>
14 #include <asm/secvar.h>
15
16 #define NAME_MAX_SIZE      1024
17
18 static struct kobject *secvar_kobj;
19 static struct kset *secvar_kset;
20
21 static ssize_t format_show(struct kobject *kobj, struct kobj_attribute *attr,
22                            char *buf)
23 {
24         char tmp[32];
25         ssize_t len = secvar_ops->format(tmp, sizeof(tmp));
26
27         if (len > 0)
28                 return sysfs_emit(buf, "%s\n", tmp);
29         else if (len < 0)
30                 pr_err("Error %zd reading format string\n", len);
31         else
32                 pr_err("Got empty format string from backend\n");
33
34         return -EIO;
35 }
36
37
38 static ssize_t size_show(struct kobject *kobj, struct kobj_attribute *attr,
39                          char *buf)
40 {
41         u64 dsize;
42         int rc;
43
44         rc = secvar_ops->get(kobj->name, strlen(kobj->name) + 1, NULL, &dsize);
45         if (rc) {
46                 if (rc != -ENOENT)
47                         pr_err("Error retrieving %s variable size %d\n", kobj->name, rc);
48                 return rc;
49         }
50
51         return sysfs_emit(buf, "%llu\n", dsize);
52 }
53
54 static ssize_t data_read(struct file *filep, struct kobject *kobj,
55                          struct bin_attribute *attr, char *buf, loff_t off,
56                          size_t count)
57 {
58         char *data;
59         u64 dsize;
60         int rc;
61
62         rc = secvar_ops->get(kobj->name, strlen(kobj->name) + 1, NULL, &dsize);
63         if (rc) {
64                 if (rc != -ENOENT)
65                         pr_err("Error getting %s variable size %d\n", kobj->name, rc);
66                 return rc;
67         }
68         pr_debug("dsize is %llu\n", dsize);
69
70         data = kzalloc(dsize, GFP_KERNEL);
71         if (!data)
72                 return -ENOMEM;
73
74         rc = secvar_ops->get(kobj->name, strlen(kobj->name) + 1, data, &dsize);
75         if (rc) {
76                 pr_err("Error getting %s variable %d\n", kobj->name, rc);
77                 goto data_fail;
78         }
79
80         rc = memory_read_from_buffer(buf, count, &off, data, dsize);
81
82 data_fail:
83         kfree(data);
84         return rc;
85 }
86
87 static ssize_t update_write(struct file *filep, struct kobject *kobj,
88                             struct bin_attribute *attr, char *buf, loff_t off,
89                             size_t count)
90 {
91         int rc;
92
93         pr_debug("count is %ld\n", count);
94         rc = secvar_ops->set(kobj->name, strlen(kobj->name) + 1, buf, count);
95         if (rc) {
96                 pr_err("Error setting the %s variable %d\n", kobj->name, rc);
97                 return rc;
98         }
99
100         return count;
101 }
102
103 static struct kobj_attribute format_attr = __ATTR_RO(format);
104
105 static struct kobj_attribute size_attr = __ATTR_RO(size);
106
107 static struct bin_attribute data_attr = __BIN_ATTR_RO(data, 0);
108
109 static struct bin_attribute update_attr = __BIN_ATTR_WO(update, 0);
110
111 static struct bin_attribute *secvar_bin_attrs[] = {
112         &data_attr,
113         &update_attr,
114         NULL,
115 };
116
117 static struct attribute *secvar_attrs[] = {
118         &size_attr.attr,
119         NULL,
120 };
121
122 static const struct attribute_group secvar_attr_group = {
123         .attrs = secvar_attrs,
124         .bin_attrs = secvar_bin_attrs,
125 };
126 __ATTRIBUTE_GROUPS(secvar_attr);
127
128 static struct kobj_type secvar_ktype = {
129         .sysfs_ops      = &kobj_sysfs_ops,
130         .default_groups = secvar_attr_groups,
131 };
132
133 static int update_kobj_size(void)
134 {
135
136         u64 varsize;
137         int rc = secvar_ops->max_size(&varsize);
138
139         if (rc)
140                 return rc;
141
142         data_attr.size = varsize;
143         update_attr.size = varsize;
144
145         return 0;
146 }
147
148 static int secvar_sysfs_config(struct kobject *kobj)
149 {
150         struct attribute_group config_group = {
151                 .name = "config",
152                 .attrs = (struct attribute **)secvar_ops->config_attrs,
153         };
154
155         if (secvar_ops->config_attrs)
156                 return sysfs_create_group(kobj, &config_group);
157
158         return 0;
159 }
160
161 static int add_var(const char *name)
162 {
163         struct kobject *kobj;
164         int rc;
165
166         kobj = kzalloc(sizeof(*kobj), GFP_KERNEL);
167         if (!kobj)
168                 return -ENOMEM;
169
170         kobject_init(kobj, &secvar_ktype);
171
172         rc = kobject_add(kobj, &secvar_kset->kobj, "%s", name);
173         if (rc) {
174                 pr_warn("kobject_add error %d for attribute: %s\n", rc,
175                         name);
176                 kobject_put(kobj);
177                 return rc;
178         }
179
180         kobject_uevent(kobj, KOBJ_ADD);
181         return 0;
182 }
183
184 static int secvar_sysfs_load(void)
185 {
186         u64 namesize = 0;
187         char *name;
188         int rc;
189
190         name = kzalloc(NAME_MAX_SIZE, GFP_KERNEL);
191         if (!name)
192                 return -ENOMEM;
193
194         do {
195                 rc = secvar_ops->get_next(name, &namesize, NAME_MAX_SIZE);
196                 if (rc) {
197                         if (rc != -ENOENT)
198                                 pr_err("error getting secvar from firmware %d\n", rc);
199                         else
200                                 rc = 0;
201
202                         break;
203                 }
204
205                 rc = add_var(name);
206         } while (!rc);
207
208         kfree(name);
209         return rc;
210 }
211
212 static int secvar_sysfs_load_static(void)
213 {
214         const char * const *name_ptr = secvar_ops->var_names;
215         int rc;
216
217         while (*name_ptr) {
218                 rc = add_var(*name_ptr);
219                 if (rc)
220                         return rc;
221                 name_ptr++;
222         }
223
224         return 0;
225 }
226
227 static int secvar_sysfs_init(void)
228 {
229         u64 max_size;
230         int rc;
231
232         if (!secvar_ops) {
233                 pr_warn("Failed to retrieve secvar operations\n");
234                 return -ENODEV;
235         }
236
237         secvar_kobj = kobject_create_and_add("secvar", firmware_kobj);
238         if (!secvar_kobj) {
239                 pr_err("Failed to create firmware kobj\n");
240                 return -ENOMEM;
241         }
242
243         rc = sysfs_create_file(secvar_kobj, &format_attr.attr);
244         if (rc) {
245                 pr_err("Failed to create format object\n");
246                 rc = -ENOMEM;
247                 goto err;
248         }
249
250         secvar_kset = kset_create_and_add("vars", NULL, secvar_kobj);
251         if (!secvar_kset) {
252                 pr_err("sysfs kobject registration failed\n");
253                 rc = -ENOMEM;
254                 goto err;
255         }
256
257         rc = update_kobj_size();
258         if (rc) {
259                 pr_err("Cannot read the size of the attribute\n");
260                 goto err;
261         }
262
263         rc = secvar_sysfs_config(secvar_kobj);
264         if (rc) {
265                 pr_err("Failed to create config directory\n");
266                 goto err;
267         }
268
269         if (secvar_ops->get_next)
270                 rc = secvar_sysfs_load();
271         else
272                 rc = secvar_sysfs_load_static();
273
274         if (rc) {
275                 pr_err("Failed to create variable attributes\n");
276                 goto err;
277         }
278
279         // Due to sysfs limitations, we will only ever get a write buffer of
280         // up to 1 page in size. Print a warning if this is potentially going
281         // to cause problems, so that the user is aware.
282         secvar_ops->max_size(&max_size);
283         if (max_size > PAGE_SIZE)
284                 pr_warn_ratelimited("PAGE_SIZE (%lu) is smaller than maximum object size (%llu), writes are limited to PAGE_SIZE\n",
285                                     PAGE_SIZE, max_size);
286
287         return 0;
288 err:
289         kobject_put(secvar_kobj);
290         return rc;
291 }
292
293 late_initcall(secvar_sysfs_init);