powerpc/pseries: Fix handling of PLPKS object flushing timeout
[linux-block.git] / arch / powerpc / platforms / pseries / plpks.c
CommitLineData
2454a7af
NJ
1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * POWER LPAR Platform KeyStore(PLPKS)
4 * Copyright (C) 2022 IBM Corporation
5 * Author: Nayna Jain <nayna@linux.ibm.com>
6 *
7 * Provides access to variables stored in Power LPAR Platform KeyStore(PLPKS).
8 */
9
10#define pr_fmt(fmt) "plpks: " fmt
11
12#include <linux/delay.h>
13#include <linux/errno.h>
14#include <linux/io.h>
15#include <linux/printk.h>
16#include <linux/slab.h>
17#include <linux/string.h>
18#include <linux/types.h>
19#include <asm/hvcall.h>
a66de528 20#include <asm/machdep.h>
2454a7af
NJ
21
22#include "plpks.h"
23
24#define PKS_FW_OWNER 0x1
25#define PKS_BOOTLOADER_OWNER 0x2
26#define PKS_OS_OWNER 0x3
27
28#define LABEL_VERSION 0
29#define MAX_LABEL_ATTR_SIZE 16
30#define MAX_NAME_SIZE 239
31#define MAX_DATA_SIZE 4000
32
33#define PKS_FLUSH_MAX_TIMEOUT 5000 //msec
34#define PKS_FLUSH_SLEEP 10 //msec
35#define PKS_FLUSH_SLEEP_RANGE 400
36
37static u8 *ospassword;
38static u16 ospasswordlength;
39
40// Retrieved with H_PKS_GET_CONFIG
41static u16 maxpwsize;
42static u16 maxobjsize;
43
44struct plpks_auth {
45 u8 version;
46 u8 consumer;
47 __be64 rsvd0;
48 __be32 rsvd1;
49 __be16 passwordlength;
50 u8 password[];
51} __packed __aligned(16);
52
53struct label_attr {
54 u8 prefix[8];
55 u8 version;
56 u8 os;
57 u8 length;
58 u8 reserved[5];
59};
60
61struct label {
62 struct label_attr attr;
63 u8 name[MAX_NAME_SIZE];
64 size_t size;
65};
66
67static int pseries_status_to_err(int rc)
68{
69 int err;
70
71 switch (rc) {
72 case H_SUCCESS:
73 err = 0;
74 break;
75 case H_FUNCTION:
76 err = -ENXIO;
77 break;
af223e17 78 case H_PARAMETER:
2454a7af
NJ
79 case H_P2:
80 case H_P3:
81 case H_P4:
82 case H_P5:
83 case H_P6:
84 err = -EINVAL;
85 break;
86 case H_NOT_FOUND:
87 err = -ENOENT;
88 break;
89 case H_BUSY:
90 err = -EBUSY;
91 break;
92 case H_AUTHORITY:
93 err = -EPERM;
94 break;
95 case H_NO_MEM:
96 err = -ENOMEM;
97 break;
98 case H_RESOURCE:
99 err = -EEXIST;
100 break;
101 case H_TOO_BIG:
102 err = -EFBIG;
103 break;
104 case H_STATE:
105 err = -EIO;
106 break;
107 case H_R_STATE:
108 err = -EIO;
109 break;
110 case H_IN_USE:
111 err = -EEXIST;
112 break;
113 case H_ABORTED:
bb8e4c7c 114 err = -EIO;
2454a7af
NJ
115 break;
116 default:
117 err = -EINVAL;
118 }
119
120 return err;
121}
122
123static int plpks_gen_password(void)
124{
125 unsigned long retbuf[PLPAR_HCALL_BUFSIZE] = { 0 };
126 u8 *password, consumer = PKS_OS_OWNER;
127 int rc;
128
129 password = kzalloc(maxpwsize, GFP_KERNEL);
130 if (!password)
131 return -ENOMEM;
132
133 rc = plpar_hcall(H_PKS_GEN_PASSWORD, retbuf, consumer, 0,
134 virt_to_phys(password), maxpwsize);
135
136 if (!rc) {
137 ospasswordlength = maxpwsize;
138 ospassword = kzalloc(maxpwsize, GFP_KERNEL);
139 if (!ospassword) {
140 kfree(password);
141 return -ENOMEM;
142 }
143 memcpy(ospassword, password, ospasswordlength);
144 } else {
145 if (rc == H_IN_USE) {
146 pr_warn("Password is already set for POWER LPAR Platform KeyStore\n");
147 rc = 0;
148 } else {
149 goto out;
150 }
151 }
152out:
153 kfree(password);
154
155 return pseries_status_to_err(rc);
156}
157
158static struct plpks_auth *construct_auth(u8 consumer)
159{
160 struct plpks_auth *auth;
161
162 if (consumer > PKS_OS_OWNER)
163 return ERR_PTR(-EINVAL);
164
212dd5cf 165 auth = kzalloc(struct_size(auth, password, maxpwsize), GFP_KERNEL);
2454a7af
NJ
166 if (!auth)
167 return ERR_PTR(-ENOMEM);
168
169 auth->version = 1;
170 auth->consumer = consumer;
2454a7af 171
212dd5cf 172 if (consumer == PKS_FW_OWNER || consumer == PKS_BOOTLOADER_OWNER)
2454a7af 173 return auth;
2454a7af
NJ
174
175 memcpy(auth->password, ospassword, ospasswordlength);
176
177 auth->passwordlength = cpu_to_be16(ospasswordlength);
178
179 return auth;
180}
181
182/**
183 * Label is combination of label attributes + name.
184 * Label attributes are used internally by kernel and not exposed to the user.
185 */
186static struct label *construct_label(char *component, u8 varos, u8 *name,
187 u16 namelen)
188{
189 struct label *label;
190 size_t slen;
191
192 if (!name || namelen > MAX_NAME_SIZE)
193 return ERR_PTR(-EINVAL);
194
195 slen = strlen(component);
196 if (component && slen > sizeof(label->attr.prefix))
197 return ERR_PTR(-EINVAL);
198
199 label = kzalloc(sizeof(*label), GFP_KERNEL);
200 if (!label)
201 return ERR_PTR(-ENOMEM);
202
203 if (component)
204 memcpy(&label->attr.prefix, component, slen);
205
206 label->attr.version = LABEL_VERSION;
207 label->attr.os = varos;
208 label->attr.length = MAX_LABEL_ATTR_SIZE;
209 memcpy(&label->name, name, namelen);
210
211 label->size = sizeof(struct label_attr) + namelen;
212
213 return label;
214}
215
216static int _plpks_get_config(void)
217{
218 unsigned long retbuf[PLPAR_HCALL_BUFSIZE] = { 0 };
219 struct {
220 u8 version;
221 u8 flags;
222 __be32 rsvd0;
223 __be16 maxpwsize;
224 __be16 maxobjlabelsize;
225 __be16 maxobjsize;
226 __be32 totalsize;
227 __be32 usedspace;
228 __be32 supportedpolicies;
229 __be64 rsvd1;
230 } __packed config;
231 size_t size;
232 int rc;
233
234 size = sizeof(config);
235
236 rc = plpar_hcall(H_PKS_GET_CONFIG, retbuf, virt_to_phys(&config), size);
237
238 if (rc != H_SUCCESS)
239 return pseries_status_to_err(rc);
240
241 maxpwsize = be16_to_cpu(config.maxpwsize);
242 maxobjsize = be16_to_cpu(config.maxobjsize);
243
244 return 0;
245}
246
247static int plpks_confirm_object_flushed(struct label *label,
248 struct plpks_auth *auth)
249{
250 unsigned long retbuf[PLPAR_HCALL_BUFSIZE] = { 0 };
f74dcbfd 251 bool timed_out = true;
2454a7af
NJ
252 u64 timeout = 0;
253 u8 status;
254 int rc;
255
256 do {
257 rc = plpar_hcall(H_PKS_CONFIRM_OBJECT_FLUSHED, retbuf,
258 virt_to_phys(auth), virt_to_phys(label),
259 label->size);
260
261 status = retbuf[0];
262 if (rc) {
f74dcbfd 263 timed_out = false;
2454a7af
NJ
264 if (rc == H_NOT_FOUND && status == 1)
265 rc = 0;
266 break;
267 }
268
f74dcbfd
AD
269 if (!rc && status == 1) {
270 timed_out = false;
2454a7af 271 break;
f74dcbfd 272 }
2454a7af
NJ
273
274 usleep_range(PKS_FLUSH_SLEEP,
275 PKS_FLUSH_SLEEP + PKS_FLUSH_SLEEP_RANGE);
276 timeout = timeout + PKS_FLUSH_SLEEP;
277 } while (timeout < PKS_FLUSH_MAX_TIMEOUT);
278
f74dcbfd
AD
279 if (timed_out)
280 return -ETIMEDOUT;
2454a7af 281
f74dcbfd 282 return pseries_status_to_err(rc);
2454a7af
NJ
283}
284
285int plpks_write_var(struct plpks_var var)
286{
287 unsigned long retbuf[PLPAR_HCALL_BUFSIZE] = { 0 };
288 struct plpks_auth *auth;
289 struct label *label;
290 int rc;
291
292 if (!var.component || !var.data || var.datalen <= 0 ||
293 var.namelen > MAX_NAME_SIZE || var.datalen > MAX_DATA_SIZE)
294 return -EINVAL;
295
296 if (var.policy & SIGNEDUPDATE)
297 return -EINVAL;
298
299 auth = construct_auth(PKS_OS_OWNER);
300 if (IS_ERR(auth))
301 return PTR_ERR(auth);
302
303 label = construct_label(var.component, var.os, var.name, var.namelen);
304 if (IS_ERR(label)) {
305 rc = PTR_ERR(label);
306 goto out;
307 }
308
309 rc = plpar_hcall(H_PKS_WRITE_OBJECT, retbuf, virt_to_phys(auth),
310 virt_to_phys(label), label->size, var.policy,
311 virt_to_phys(var.data), var.datalen);
312
313 if (!rc)
314 rc = plpks_confirm_object_flushed(label, auth);
315
2454a7af
NJ
316 rc = pseries_status_to_err(rc);
317 kfree(label);
318out:
319 kfree(auth);
320
321 return rc;
322}
323
324int plpks_remove_var(char *component, u8 varos, struct plpks_var_name vname)
325{
326 unsigned long retbuf[PLPAR_HCALL_BUFSIZE] = { 0 };
327 struct plpks_auth *auth;
328 struct label *label;
329 int rc;
330
331 if (!component || vname.namelen > MAX_NAME_SIZE)
332 return -EINVAL;
333
334 auth = construct_auth(PKS_OS_OWNER);
335 if (IS_ERR(auth))
336 return PTR_ERR(auth);
337
338 label = construct_label(component, varos, vname.name, vname.namelen);
339 if (IS_ERR(label)) {
340 rc = PTR_ERR(label);
341 goto out;
342 }
343
344 rc = plpar_hcall(H_PKS_REMOVE_OBJECT, retbuf, virt_to_phys(auth),
345 virt_to_phys(label), label->size);
346
347 if (!rc)
348 rc = plpks_confirm_object_flushed(label, auth);
349
2454a7af
NJ
350 rc = pseries_status_to_err(rc);
351 kfree(label);
352out:
353 kfree(auth);
354
355 return rc;
356}
357
358static int plpks_read_var(u8 consumer, struct plpks_var *var)
359{
360 unsigned long retbuf[PLPAR_HCALL_BUFSIZE] = { 0 };
361 struct plpks_auth *auth;
1f622f3f 362 struct label *label = NULL;
2454a7af
NJ
363 u8 *output;
364 int rc;
365
366 if (var->namelen > MAX_NAME_SIZE)
367 return -EINVAL;
368
1f622f3f 369 auth = construct_auth(consumer);
2454a7af
NJ
370 if (IS_ERR(auth))
371 return PTR_ERR(auth);
372
1f622f3f
NJ
373 if (consumer == PKS_OS_OWNER) {
374 label = construct_label(var->component, var->os, var->name,
375 var->namelen);
376 if (IS_ERR(label)) {
377 rc = PTR_ERR(label);
378 goto out_free_auth;
379 }
2454a7af
NJ
380 }
381
382 output = kzalloc(maxobjsize, GFP_KERNEL);
383 if (!output) {
384 rc = -ENOMEM;
385 goto out_free_label;
386 }
387
1f622f3f
NJ
388 if (consumer == PKS_OS_OWNER)
389 rc = plpar_hcall(H_PKS_READ_OBJECT, retbuf, virt_to_phys(auth),
390 virt_to_phys(label), label->size, virt_to_phys(output),
391 maxobjsize);
392 else
393 rc = plpar_hcall(H_PKS_READ_OBJECT, retbuf, virt_to_phys(auth),
394 virt_to_phys(var->name), var->namelen, virt_to_phys(output),
395 maxobjsize);
396
2454a7af
NJ
397
398 if (rc != H_SUCCESS) {
2454a7af
NJ
399 rc = pseries_status_to_err(rc);
400 goto out_free_output;
401 }
402
403 if (var->datalen == 0 || var->datalen > retbuf[0])
404 var->datalen = retbuf[0];
405
406 var->data = kzalloc(var->datalen, GFP_KERNEL);
407 if (!var->data) {
408 rc = -ENOMEM;
409 goto out_free_output;
410 }
411 var->policy = retbuf[1];
412
413 memcpy(var->data, output, var->datalen);
414 rc = 0;
415
416out_free_output:
417 kfree(output);
418out_free_label:
419 kfree(label);
420out_free_auth:
421 kfree(auth);
422
423 return rc;
424}
425
426int plpks_read_os_var(struct plpks_var *var)
427{
428 return plpks_read_var(PKS_OS_OWNER, var);
429}
430
431int plpks_read_fw_var(struct plpks_var *var)
432{
433 return plpks_read_var(PKS_FW_OWNER, var);
434}
435
436int plpks_read_bootloader_var(struct plpks_var *var)
437{
438 return plpks_read_var(PKS_BOOTLOADER_OWNER, var);
439}
440
441static __init int pseries_plpks_init(void)
442{
443 int rc;
444
445 rc = _plpks_get_config();
446
447 if (rc) {
448 pr_err("POWER LPAR Platform KeyStore is not supported or enabled\n");
449 return rc;
450 }
451
452 rc = plpks_gen_password();
453 if (rc)
454 pr_err("Failed setting POWER LPAR Platform KeyStore Password\n");
455 else
456 pr_info("POWER LPAR Platform KeyStore initialized successfully\n");
457
458 return rc;
459}
a66de528 460machine_arch_initcall(pseries, pseries_plpks_init);