0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #define pr_fmt(fmt) "secvar: "fmt
0013
0014 #include <linux/types.h>
0015 #include <linux/platform_device.h>
0016 #include <linux/of_platform.h>
0017 #include <asm/opal.h>
0018 #include <asm/secvar.h>
0019 #include <asm/secure_boot.h>
0020
0021 static int opal_status_to_err(int rc)
0022 {
0023 int err;
0024
0025 switch (rc) {
0026 case OPAL_SUCCESS:
0027 err = 0;
0028 break;
0029 case OPAL_UNSUPPORTED:
0030 err = -ENXIO;
0031 break;
0032 case OPAL_PARAMETER:
0033 err = -EINVAL;
0034 break;
0035 case OPAL_RESOURCE:
0036 err = -ENOSPC;
0037 break;
0038 case OPAL_HARDWARE:
0039 err = -EIO;
0040 break;
0041 case OPAL_NO_MEM:
0042 err = -ENOMEM;
0043 break;
0044 case OPAL_EMPTY:
0045 err = -ENOENT;
0046 break;
0047 case OPAL_PARTIAL:
0048 err = -EFBIG;
0049 break;
0050 default:
0051 err = -EINVAL;
0052 }
0053
0054 return err;
0055 }
0056
0057 static int opal_get_variable(const char *key, uint64_t ksize,
0058 u8 *data, uint64_t *dsize)
0059 {
0060 int rc;
0061
0062 if (!key || !dsize)
0063 return -EINVAL;
0064
0065 *dsize = cpu_to_be64(*dsize);
0066
0067 rc = opal_secvar_get(key, ksize, data, dsize);
0068
0069 *dsize = be64_to_cpu(*dsize);
0070
0071 return opal_status_to_err(rc);
0072 }
0073
0074 static int opal_get_next_variable(const char *key, uint64_t *keylen,
0075 uint64_t keybufsize)
0076 {
0077 int rc;
0078
0079 if (!key || !keylen)
0080 return -EINVAL;
0081
0082 *keylen = cpu_to_be64(*keylen);
0083
0084 rc = opal_secvar_get_next(key, keylen, keybufsize);
0085
0086 *keylen = be64_to_cpu(*keylen);
0087
0088 return opal_status_to_err(rc);
0089 }
0090
0091 static int opal_set_variable(const char *key, uint64_t ksize, u8 *data,
0092 uint64_t dsize)
0093 {
0094 int rc;
0095
0096 if (!key || !data)
0097 return -EINVAL;
0098
0099 rc = opal_secvar_enqueue_update(key, ksize, data, dsize);
0100
0101 return opal_status_to_err(rc);
0102 }
0103
0104 static const struct secvar_operations opal_secvar_ops = {
0105 .get = opal_get_variable,
0106 .get_next = opal_get_next_variable,
0107 .set = opal_set_variable,
0108 };
0109
0110 static int opal_secvar_probe(struct platform_device *pdev)
0111 {
0112 if (!opal_check_token(OPAL_SECVAR_GET)
0113 || !opal_check_token(OPAL_SECVAR_GET_NEXT)
0114 || !opal_check_token(OPAL_SECVAR_ENQUEUE_UPDATE)) {
0115 pr_err("OPAL doesn't support secure variables\n");
0116 return -ENODEV;
0117 }
0118
0119 set_secvar_ops(&opal_secvar_ops);
0120
0121 return 0;
0122 }
0123
0124 static const struct of_device_id opal_secvar_match[] = {
0125 { .compatible = "ibm,secvar-backend",},
0126 {},
0127 };
0128
0129 static struct platform_driver opal_secvar_driver = {
0130 .driver = {
0131 .name = "secvar",
0132 .of_match_table = opal_secvar_match,
0133 },
0134 };
0135
0136 static int __init opal_secvar_init(void)
0137 {
0138 return platform_driver_probe(&opal_secvar_driver, opal_secvar_probe);
0139 }
0140 device_initcall(opal_secvar_init);