opal-secvar.c (2620B)
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 21static 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 57static 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 74static 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 91static 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 104static 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 110static 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 124static const struct of_device_id opal_secvar_match[] = { 125 { .compatible = "ibm,secvar-backend",}, 126 {}, 127}; 128 129static struct platform_driver opal_secvar_driver = { 130 .driver = { 131 .name = "secvar", 132 .of_match_table = opal_secvar_match, 133 }, 134}; 135 136static int __init opal_secvar_init(void) 137{ 138 return platform_driver_probe(&opal_secvar_driver, opal_secvar_probe); 139} 140device_initcall(opal_secvar_init);