1 // SPDX-License-Identifier: GPL-2.0-only
3 * POWER LPAR Platform KeyStore(PLPKS)
4 * Copyright (C) 2022 IBM Corporation
5 * Author: Nayna Jain <nayna@linux.ibm.com>
7 * Provides access to variables stored in Power LPAR Platform KeyStore(PLPKS).
10 #define pr_fmt(fmt) "plpks: " fmt
12 #include <linux/delay.h>
13 #include <linux/errno.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>
23 #define PKS_FW_OWNER 0x1
24 #define PKS_BOOTLOADER_OWNER 0x2
25 #define PKS_OS_OWNER 0x3
27 #define LABEL_VERSION 0
28 #define MAX_LABEL_ATTR_SIZE 16
29 #define MAX_NAME_SIZE 239
30 #define MAX_DATA_SIZE 4000
32 #define PKS_FLUSH_MAX_TIMEOUT 5000 //msec
33 #define PKS_FLUSH_SLEEP 10 //msec
34 #define PKS_FLUSH_SLEEP_RANGE 400
36 static u8
*ospassword
;
37 static u16 ospasswordlength
;
39 // Retrieved with H_PKS_GET_CONFIG
41 static u16 maxobjsize
;
48 __be16 passwordlength
;
50 } __packed
__aligned(16);
61 struct label_attr attr
;
62 u8 name
[MAX_NAME_SIZE
];
66 static int pseries_status_to_err(int rc
)
122 static int plpks_gen_password(void)
124 unsigned long retbuf
[PLPAR_HCALL_BUFSIZE
] = { 0 };
125 u8
*password
, consumer
= PKS_OS_OWNER
;
128 password
= kzalloc(maxpwsize
, GFP_KERNEL
);
132 rc
= plpar_hcall(H_PKS_GEN_PASSWORD
, retbuf
, consumer
, 0,
133 virt_to_phys(password
), maxpwsize
);
136 ospasswordlength
= maxpwsize
;
137 ospassword
= kzalloc(maxpwsize
, GFP_KERNEL
);
142 memcpy(ospassword
, password
, ospasswordlength
);
144 if (rc
== H_IN_USE
) {
145 pr_warn("Password is already set for POWER LPAR Platform KeyStore\n");
154 return pseries_status_to_err(rc
);
157 static struct plpks_auth
*construct_auth(u8 consumer
)
159 struct plpks_auth
*auth
;
161 if (consumer
> PKS_OS_OWNER
)
162 return ERR_PTR(-EINVAL
);
164 auth
= kmalloc(struct_size(auth
, password
, maxpwsize
), GFP_KERNEL
);
166 return ERR_PTR(-ENOMEM
);
169 auth
->consumer
= consumer
;
173 if (consumer
== PKS_FW_OWNER
|| consumer
== PKS_BOOTLOADER_OWNER
) {
174 auth
->passwordlength
= 0;
178 memcpy(auth
->password
, ospassword
, ospasswordlength
);
180 auth
->passwordlength
= cpu_to_be16(ospasswordlength
);
186 * Label is combination of label attributes + name.
187 * Label attributes are used internally by kernel and not exposed to the user.
189 static struct label
*construct_label(char *component
, u8 varos
, u8
*name
,
195 if (!name
|| namelen
> MAX_NAME_SIZE
)
196 return ERR_PTR(-EINVAL
);
198 slen
= strlen(component
);
199 if (component
&& slen
> sizeof(label
->attr
.prefix
))
200 return ERR_PTR(-EINVAL
);
202 label
= kzalloc(sizeof(*label
), GFP_KERNEL
);
204 return ERR_PTR(-ENOMEM
);
207 memcpy(&label
->attr
.prefix
, component
, slen
);
209 label
->attr
.version
= LABEL_VERSION
;
210 label
->attr
.os
= varos
;
211 label
->attr
.length
= MAX_LABEL_ATTR_SIZE
;
212 memcpy(&label
->name
, name
, namelen
);
214 label
->size
= sizeof(struct label_attr
) + namelen
;
219 static int _plpks_get_config(void)
221 unsigned long retbuf
[PLPAR_HCALL_BUFSIZE
] = { 0 };
227 __be16 maxobjlabelsize
;
231 __be32 supportedpolicies
;
237 size
= sizeof(config
);
239 rc
= plpar_hcall(H_PKS_GET_CONFIG
, retbuf
, virt_to_phys(&config
), size
);
242 return pseries_status_to_err(rc
);
244 maxpwsize
= be16_to_cpu(config
.maxpwsize
);
245 maxobjsize
= be16_to_cpu(config
.maxobjsize
);
250 static int plpks_confirm_object_flushed(struct label
*label
,
251 struct plpks_auth
*auth
)
253 unsigned long retbuf
[PLPAR_HCALL_BUFSIZE
] = { 0 };
259 rc
= plpar_hcall(H_PKS_CONFIRM_OBJECT_FLUSHED
, retbuf
,
260 virt_to_phys(auth
), virt_to_phys(label
),
265 if (rc
== H_NOT_FOUND
&& status
== 1)
270 if (!rc
&& status
== 1)
273 usleep_range(PKS_FLUSH_SLEEP
,
274 PKS_FLUSH_SLEEP
+ PKS_FLUSH_SLEEP_RANGE
);
275 timeout
= timeout
+ PKS_FLUSH_SLEEP
;
276 } while (timeout
< PKS_FLUSH_MAX_TIMEOUT
);
278 rc
= pseries_status_to_err(rc
);
283 int plpks_write_var(struct plpks_var var
)
285 unsigned long retbuf
[PLPAR_HCALL_BUFSIZE
] = { 0 };
286 struct plpks_auth
*auth
;
290 if (!var
.component
|| !var
.data
|| var
.datalen
<= 0 ||
291 var
.namelen
> MAX_NAME_SIZE
|| var
.datalen
> MAX_DATA_SIZE
)
294 if (var
.policy
& SIGNEDUPDATE
)
297 auth
= construct_auth(PKS_OS_OWNER
);
299 return PTR_ERR(auth
);
301 label
= construct_label(var
.component
, var
.os
, var
.name
, var
.namelen
);
307 rc
= plpar_hcall(H_PKS_WRITE_OBJECT
, retbuf
, virt_to_phys(auth
),
308 virt_to_phys(label
), label
->size
, var
.policy
,
309 virt_to_phys(var
.data
), var
.datalen
);
312 rc
= plpks_confirm_object_flushed(label
, auth
);
315 pr_err("Failed to write variable %s for component %s with error %d\n",
316 var
.name
, var
.component
, rc
);
318 rc
= pseries_status_to_err(rc
);
326 int plpks_remove_var(char *component
, u8 varos
, struct plpks_var_name vname
)
328 unsigned long retbuf
[PLPAR_HCALL_BUFSIZE
] = { 0 };
329 struct plpks_auth
*auth
;
333 if (!component
|| vname
.namelen
> MAX_NAME_SIZE
)
336 auth
= construct_auth(PKS_OS_OWNER
);
338 return PTR_ERR(auth
);
340 label
= construct_label(component
, varos
, vname
.name
, vname
.namelen
);
346 rc
= plpar_hcall(H_PKS_REMOVE_OBJECT
, retbuf
, virt_to_phys(auth
),
347 virt_to_phys(label
), label
->size
);
350 rc
= plpks_confirm_object_flushed(label
, auth
);
353 pr_err("Failed to remove variable %s for component %s with error %d\n",
354 vname
.name
, component
, rc
);
356 rc
= pseries_status_to_err(rc
);
364 static int plpks_read_var(u8 consumer
, struct plpks_var
*var
)
366 unsigned long retbuf
[PLPAR_HCALL_BUFSIZE
] = { 0 };
367 struct plpks_auth
*auth
;
372 if (var
->namelen
> MAX_NAME_SIZE
)
375 auth
= construct_auth(PKS_OS_OWNER
);
377 return PTR_ERR(auth
);
379 label
= construct_label(var
->component
, var
->os
, var
->name
,
386 output
= kzalloc(maxobjsize
, GFP_KERNEL
);
392 rc
= plpar_hcall(H_PKS_READ_OBJECT
, retbuf
, virt_to_phys(auth
),
393 virt_to_phys(label
), label
->size
, virt_to_phys(output
),
396 if (rc
!= H_SUCCESS
) {
397 pr_err("Failed to read variable %s for component %s with error %d\n",
398 var
->name
, var
->component
, rc
);
399 rc
= pseries_status_to_err(rc
);
400 goto out_free_output
;
403 if (var
->datalen
== 0 || var
->datalen
> retbuf
[0])
404 var
->datalen
= retbuf
[0];
406 var
->data
= kzalloc(var
->datalen
, GFP_KERNEL
);
409 goto out_free_output
;
411 var
->policy
= retbuf
[1];
413 memcpy(var
->data
, output
, var
->datalen
);
426 int plpks_read_os_var(struct plpks_var
*var
)
428 return plpks_read_var(PKS_OS_OWNER
, var
);
431 int plpks_read_fw_var(struct plpks_var
*var
)
433 return plpks_read_var(PKS_FW_OWNER
, var
);
436 int plpks_read_bootloader_var(struct plpks_var
*var
)
438 return plpks_read_var(PKS_BOOTLOADER_OWNER
, var
);
441 static __init
int pseries_plpks_init(void)
445 rc
= _plpks_get_config();
448 pr_err("POWER LPAR Platform KeyStore is not supported or enabled\n");
452 rc
= plpks_gen_password();
454 pr_err("Failed setting POWER LPAR Platform KeyStore Password\n");
456 pr_info("POWER LPAR Platform KeyStore initialized successfully\n");
460 arch_initcall(pseries_plpks_init
);