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 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 125*e0240794SRussell Currey static int opal_secvar_max_size(u64 *max_size) 126*e0240794SRussell Currey { 127*e0240794SRussell Currey int rc; 128*e0240794SRussell Currey struct device_node *node; 129*e0240794SRussell Currey 130*e0240794SRussell Currey node = of_find_compatible_node(NULL, NULL, "ibm,secvar-backend"); 131*e0240794SRussell Currey if (!node) 132*e0240794SRussell Currey return -ENODEV; 133*e0240794SRussell Currey 134*e0240794SRussell Currey if (!of_device_is_available(node)) { 135*e0240794SRussell Currey rc = -ENODEV; 136*e0240794SRussell Currey goto out; 137*e0240794SRussell Currey } 138*e0240794SRussell Currey 139*e0240794SRussell Currey rc = of_property_read_u64(node, "max-var-size", max_size); 140*e0240794SRussell Currey 141*e0240794SRussell Currey out: 142*e0240794SRussell Currey of_node_put(node); 143*e0240794SRussell Currey return rc; 144*e0240794SRussell Currey } 145*e0240794SRussell 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, 151*e0240794SRussell Currey .max_size = opal_secvar_max_size, 1529155e234SNayna Jain }; 1539155e234SNayna Jain 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 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