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>
15*81d7cac4SRob Herring #include <linux/of.h>
169155e234SNayna Jain #include <linux/platform_device.h>
179155e234SNayna Jain #include <asm/opal.h>
189155e234SNayna Jain #include <asm/secvar.h>
199155e234SNayna Jain #include <asm/secure_boot.h>
209155e234SNayna Jain
opal_status_to_err(int rc)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
opal_get_variable(const char * key,u64 ksize,u8 * data,u64 * dsize)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
opal_get_next_variable(const char * key,u64 * keylen,u64 keybufsize)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
opal_set_variable(const char * key,u64 ksize,u8 * data,u64 dsize)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
opal_secvar_format(char * buf,size_t bufsize)101ec2f40bdSRussell Currey static ssize_t opal_secvar_format(char *buf, size_t bufsize)
102ec2f40bdSRussell Currey {
103ec2f40bdSRussell Currey ssize_t rc = 0;
104ec2f40bdSRussell Currey struct device_node *node;
105ec2f40bdSRussell Currey const char *format;
106ec2f40bdSRussell Currey
107ec2f40bdSRussell Currey node = of_find_compatible_node(NULL, NULL, "ibm,secvar-backend");
108ec2f40bdSRussell Currey if (!of_device_is_available(node)) {
109ec2f40bdSRussell Currey rc = -ENODEV;
110ec2f40bdSRussell Currey goto out;
111ec2f40bdSRussell Currey }
112ec2f40bdSRussell Currey
113ec2f40bdSRussell Currey rc = of_property_read_string(node, "format", &format);
114ec2f40bdSRussell Currey if (rc)
115ec2f40bdSRussell Currey goto out;
116ec2f40bdSRussell Currey
117ec2f40bdSRussell Currey rc = snprintf(buf, bufsize, "%s", format);
118ec2f40bdSRussell Currey
119ec2f40bdSRussell Currey out:
120ec2f40bdSRussell Currey of_node_put(node);
121ec2f40bdSRussell Currey
122ec2f40bdSRussell Currey return rc;
123ec2f40bdSRussell Currey }
124ec2f40bdSRussell Currey
opal_secvar_max_size(u64 * max_size)125e0240794SRussell Currey static int opal_secvar_max_size(u64 *max_size)
126e0240794SRussell Currey {
127e0240794SRussell Currey int rc;
128e0240794SRussell Currey struct device_node *node;
129e0240794SRussell Currey
130e0240794SRussell Currey node = of_find_compatible_node(NULL, NULL, "ibm,secvar-backend");
131e0240794SRussell Currey if (!node)
132e0240794SRussell Currey return -ENODEV;
133e0240794SRussell Currey
134e0240794SRussell Currey if (!of_device_is_available(node)) {
135e0240794SRussell Currey rc = -ENODEV;
136e0240794SRussell Currey goto out;
137e0240794SRussell Currey }
138e0240794SRussell Currey
139e0240794SRussell Currey rc = of_property_read_u64(node, "max-var-size", max_size);
140e0240794SRussell Currey
141e0240794SRussell Currey out:
142e0240794SRussell Currey of_node_put(node);
143e0240794SRussell Currey return rc;
144e0240794SRussell Currey }
145e0240794SRussell Currey
1469155e234SNayna Jain static const struct secvar_operations opal_secvar_ops = {
1479155e234SNayna Jain .get = opal_get_variable,
1489155e234SNayna Jain .get_next = opal_get_next_variable,
1499155e234SNayna Jain .set = opal_set_variable,
150ec2f40bdSRussell Currey .format = opal_secvar_format,
151e0240794SRussell Currey .max_size = opal_secvar_max_size,
1529155e234SNayna Jain };
1539155e234SNayna Jain
opal_secvar_probe(struct platform_device * pdev)1549155e234SNayna Jain static int opal_secvar_probe(struct platform_device *pdev)
1559155e234SNayna Jain {
1569155e234SNayna Jain if (!opal_check_token(OPAL_SECVAR_GET)
1579155e234SNayna Jain || !opal_check_token(OPAL_SECVAR_GET_NEXT)
1589155e234SNayna Jain || !opal_check_token(OPAL_SECVAR_ENQUEUE_UPDATE)) {
1599155e234SNayna Jain pr_err("OPAL doesn't support secure variables\n");
1609155e234SNayna Jain return -ENODEV;
1619155e234SNayna Jain }
1629155e234SNayna Jain
16326149b02SRussell Currey return set_secvar_ops(&opal_secvar_ops);
1649155e234SNayna Jain }
1659155e234SNayna Jain
1669155e234SNayna Jain static const struct of_device_id opal_secvar_match[] = {
1679155e234SNayna Jain { .compatible = "ibm,secvar-backend",},
1689155e234SNayna Jain {},
1699155e234SNayna Jain };
1709155e234SNayna Jain
1719155e234SNayna Jain static struct platform_driver opal_secvar_driver = {
1729155e234SNayna Jain .driver = {
1739155e234SNayna Jain .name = "secvar",
1749155e234SNayna Jain .of_match_table = opal_secvar_match,
1759155e234SNayna Jain },
1769155e234SNayna Jain };
1779155e234SNayna Jain
opal_secvar_init(void)1789155e234SNayna Jain static int __init opal_secvar_init(void)
1799155e234SNayna Jain {
1809155e234SNayna Jain return platform_driver_probe(&opal_secvar_driver, opal_secvar_probe);
1819155e234SNayna Jain }
1829155e234SNayna Jain device_initcall(opal_secvar_init);
183