19155e234SNayna Jain // SPDX-License-Identifier: GPL-2.0
29155e234SNayna Jain /*
39155e234SNayna Jain  * PowerNV code for secure variables
49155e234SNayna Jain  *
59155e234SNayna Jain  * Copyright (C) 2019 IBM Corporation
69155e234SNayna Jain  * Author: Claudio Carvalho
79155e234SNayna Jain  *         Nayna Jain
89155e234SNayna Jain  *
99155e234SNayna Jain  * APIs to access secure variables managed by OPAL.
109155e234SNayna Jain  */
119155e234SNayna Jain 
129155e234SNayna Jain #define pr_fmt(fmt) "secvar: "fmt
139155e234SNayna Jain 
149155e234SNayna Jain #include <linux/types.h>
159155e234SNayna Jain #include <linux/platform_device.h>
169155e234SNayna Jain #include <linux/of_platform.h>
179155e234SNayna Jain #include <asm/opal.h>
189155e234SNayna Jain #include <asm/secvar.h>
199155e234SNayna Jain #include <asm/secure_boot.h>
209155e234SNayna Jain 
219155e234SNayna Jain static int opal_status_to_err(int rc)
229155e234SNayna Jain {
239155e234SNayna Jain 	int err;
249155e234SNayna Jain 
259155e234SNayna Jain 	switch (rc) {
269155e234SNayna Jain 	case OPAL_SUCCESS:
279155e234SNayna Jain 		err = 0;
289155e234SNayna Jain 		break;
299155e234SNayna Jain 	case OPAL_UNSUPPORTED:
309155e234SNayna Jain 		err = -ENXIO;
319155e234SNayna Jain 		break;
329155e234SNayna Jain 	case OPAL_PARAMETER:
339155e234SNayna Jain 		err = -EINVAL;
349155e234SNayna Jain 		break;
359155e234SNayna Jain 	case OPAL_RESOURCE:
369155e234SNayna Jain 		err = -ENOSPC;
379155e234SNayna Jain 		break;
389155e234SNayna Jain 	case OPAL_HARDWARE:
399155e234SNayna Jain 		err = -EIO;
409155e234SNayna Jain 		break;
419155e234SNayna Jain 	case OPAL_NO_MEM:
429155e234SNayna Jain 		err = -ENOMEM;
439155e234SNayna Jain 		break;
449155e234SNayna Jain 	case OPAL_EMPTY:
459155e234SNayna Jain 		err = -ENOENT;
469155e234SNayna Jain 		break;
479155e234SNayna Jain 	case OPAL_PARTIAL:
489155e234SNayna Jain 		err = -EFBIG;
499155e234SNayna Jain 		break;
509155e234SNayna Jain 	default:
519155e234SNayna Jain 		err = -EINVAL;
529155e234SNayna Jain 	}
539155e234SNayna Jain 
549155e234SNayna Jain 	return err;
559155e234SNayna Jain }
569155e234SNayna Jain 
5753cea34bSMichael Ellerman static int opal_get_variable(const char *key, u64 ksize, u8 *data, u64 *dsize)
589155e234SNayna Jain {
599155e234SNayna Jain 	int rc;
609155e234SNayna Jain 
619155e234SNayna Jain 	if (!key || !dsize)
629155e234SNayna Jain 		return -EINVAL;
639155e234SNayna Jain 
649155e234SNayna Jain 	*dsize = cpu_to_be64(*dsize);
659155e234SNayna Jain 
669155e234SNayna Jain 	rc = opal_secvar_get(key, ksize, data, dsize);
679155e234SNayna Jain 
689155e234SNayna Jain 	*dsize = be64_to_cpu(*dsize);
699155e234SNayna Jain 
709155e234SNayna Jain 	return opal_status_to_err(rc);
719155e234SNayna Jain }
729155e234SNayna Jain 
7353cea34bSMichael Ellerman static int opal_get_next_variable(const char *key, u64 *keylen, u64 keybufsize)
749155e234SNayna Jain {
759155e234SNayna Jain 	int rc;
769155e234SNayna Jain 
779155e234SNayna Jain 	if (!key || !keylen)
789155e234SNayna Jain 		return -EINVAL;
799155e234SNayna Jain 
809155e234SNayna Jain 	*keylen = cpu_to_be64(*keylen);
819155e234SNayna Jain 
829155e234SNayna Jain 	rc = opal_secvar_get_next(key, keylen, keybufsize);
839155e234SNayna Jain 
849155e234SNayna Jain 	*keylen = be64_to_cpu(*keylen);
859155e234SNayna Jain 
869155e234SNayna Jain 	return opal_status_to_err(rc);
879155e234SNayna Jain }
889155e234SNayna Jain 
8953cea34bSMichael Ellerman static int opal_set_variable(const char *key, u64 ksize, u8 *data, u64 dsize)
909155e234SNayna Jain {
919155e234SNayna Jain 	int rc;
929155e234SNayna Jain 
939155e234SNayna Jain 	if (!key || !data)
949155e234SNayna Jain 		return -EINVAL;
959155e234SNayna Jain 
969155e234SNayna Jain 	rc = opal_secvar_enqueue_update(key, ksize, data, dsize);
979155e234SNayna Jain 
989155e234SNayna Jain 	return opal_status_to_err(rc);
999155e234SNayna Jain }
1009155e234SNayna Jain 
1019155e234SNayna Jain static const struct secvar_operations opal_secvar_ops = {
1029155e234SNayna Jain 	.get = opal_get_variable,
1039155e234SNayna Jain 	.get_next = opal_get_next_variable,
1049155e234SNayna Jain 	.set = opal_set_variable,
1059155e234SNayna Jain };
1069155e234SNayna Jain 
1079155e234SNayna Jain static int opal_secvar_probe(struct platform_device *pdev)
1089155e234SNayna Jain {
1099155e234SNayna Jain 	if (!opal_check_token(OPAL_SECVAR_GET)
1109155e234SNayna Jain 			|| !opal_check_token(OPAL_SECVAR_GET_NEXT)
1119155e234SNayna Jain 			|| !opal_check_token(OPAL_SECVAR_ENQUEUE_UPDATE)) {
1129155e234SNayna Jain 		pr_err("OPAL doesn't support secure variables\n");
1139155e234SNayna Jain 		return -ENODEV;
1149155e234SNayna Jain 	}
1159155e234SNayna Jain 
116*26149b02SRussell Currey 	return set_secvar_ops(&opal_secvar_ops);
1179155e234SNayna Jain }
1189155e234SNayna Jain 
1199155e234SNayna Jain static const struct of_device_id opal_secvar_match[] = {
1209155e234SNayna Jain 	{ .compatible = "ibm,secvar-backend",},
1219155e234SNayna Jain 	{},
1229155e234SNayna Jain };
1239155e234SNayna Jain 
1249155e234SNayna Jain static struct platform_driver opal_secvar_driver = {
1259155e234SNayna Jain 	.driver = {
1269155e234SNayna Jain 		.name = "secvar",
1279155e234SNayna Jain 		.of_match_table = opal_secvar_match,
1289155e234SNayna Jain 	},
1299155e234SNayna Jain };
1309155e234SNayna Jain 
1319155e234SNayna Jain static int __init opal_secvar_init(void)
1329155e234SNayna Jain {
1339155e234SNayna Jain 	return platform_driver_probe(&opal_secvar_driver, opal_secvar_probe);
1349155e234SNayna Jain }
1359155e234SNayna Jain device_initcall(opal_secvar_init);
136