1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * PowerNV code for secure variables 4 * 5 * Copyright (C) 2019 IBM Corporation 6 * Author: Claudio Carvalho 7 * Nayna Jain 8 * 9 * APIs to access secure variables managed by OPAL. 10 */ 11 12 #define pr_fmt(fmt) "secvar: "fmt 13 14 #include <linux/types.h> 15 #include <linux/platform_device.h> 16 #include <linux/of_platform.h> 17 #include <asm/opal.h> 18 #include <asm/secvar.h> 19 #include <asm/secure_boot.h> 20 21 static int opal_status_to_err(int rc) 22 { 23 int err; 24 25 switch (rc) { 26 case OPAL_SUCCESS: 27 err = 0; 28 break; 29 case OPAL_UNSUPPORTED: 30 err = -ENXIO; 31 break; 32 case OPAL_PARAMETER: 33 err = -EINVAL; 34 break; 35 case OPAL_RESOURCE: 36 err = -ENOSPC; 37 break; 38 case OPAL_HARDWARE: 39 err = -EIO; 40 break; 41 case OPAL_NO_MEM: 42 err = -ENOMEM; 43 break; 44 case OPAL_EMPTY: 45 err = -ENOENT; 46 break; 47 case OPAL_PARTIAL: 48 err = -EFBIG; 49 break; 50 default: 51 err = -EINVAL; 52 } 53 54 return err; 55 } 56 57 static int opal_get_variable(const char *key, uint64_t ksize, 58 u8 *data, uint64_t *dsize) 59 { 60 int rc; 61 62 if (!key || !dsize) 63 return -EINVAL; 64 65 *dsize = cpu_to_be64(*dsize); 66 67 rc = opal_secvar_get(key, ksize, data, dsize); 68 69 *dsize = be64_to_cpu(*dsize); 70 71 return opal_status_to_err(rc); 72 } 73 74 static int opal_get_next_variable(const char *key, uint64_t *keylen, 75 uint64_t keybufsize) 76 { 77 int rc; 78 79 if (!key || !keylen) 80 return -EINVAL; 81 82 *keylen = cpu_to_be64(*keylen); 83 84 rc = opal_secvar_get_next(key, keylen, keybufsize); 85 86 *keylen = be64_to_cpu(*keylen); 87 88 return opal_status_to_err(rc); 89 } 90 91 static int opal_set_variable(const char *key, uint64_t ksize, u8 *data, 92 uint64_t dsize) 93 { 94 int rc; 95 96 if (!key || !data) 97 return -EINVAL; 98 99 rc = opal_secvar_enqueue_update(key, ksize, data, dsize); 100 101 return opal_status_to_err(rc); 102 } 103 104 static const struct secvar_operations opal_secvar_ops = { 105 .get = opal_get_variable, 106 .get_next = opal_get_next_variable, 107 .set = opal_set_variable, 108 }; 109 110 static int opal_secvar_probe(struct platform_device *pdev) 111 { 112 if (!opal_check_token(OPAL_SECVAR_GET) 113 || !opal_check_token(OPAL_SECVAR_GET_NEXT) 114 || !opal_check_token(OPAL_SECVAR_ENQUEUE_UPDATE)) { 115 pr_err("OPAL doesn't support secure variables\n"); 116 return -ENODEV; 117 } 118 119 set_secvar_ops(&opal_secvar_ops); 120 121 return 0; 122 } 123 124 static const struct of_device_id opal_secvar_match[] = { 125 { .compatible = "ibm,secvar-backend",}, 126 {}, 127 }; 128 129 static struct platform_driver opal_secvar_driver = { 130 .driver = { 131 .name = "secvar", 132 .of_match_table = opal_secvar_match, 133 }, 134 }; 135 136 static int __init opal_secvar_init(void) 137 { 138 return platform_driver_probe(&opal_secvar_driver, opal_secvar_probe); 139 } 140 device_initcall(opal_secvar_init); 141