18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * PowerNV code for secure variables 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2019 IBM Corporation 68c2ecf20Sopenharmony_ci * Author: Claudio Carvalho 78c2ecf20Sopenharmony_ci * Nayna Jain 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * APIs to access secure variables managed by OPAL. 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#define pr_fmt(fmt) "secvar: "fmt 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <linux/types.h> 158c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 168c2ecf20Sopenharmony_ci#include <linux/of_platform.h> 178c2ecf20Sopenharmony_ci#include <asm/opal.h> 188c2ecf20Sopenharmony_ci#include <asm/secvar.h> 198c2ecf20Sopenharmony_ci#include <asm/secure_boot.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_cistatic int opal_status_to_err(int rc) 228c2ecf20Sopenharmony_ci{ 238c2ecf20Sopenharmony_ci int err; 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci switch (rc) { 268c2ecf20Sopenharmony_ci case OPAL_SUCCESS: 278c2ecf20Sopenharmony_ci err = 0; 288c2ecf20Sopenharmony_ci break; 298c2ecf20Sopenharmony_ci case OPAL_UNSUPPORTED: 308c2ecf20Sopenharmony_ci err = -ENXIO; 318c2ecf20Sopenharmony_ci break; 328c2ecf20Sopenharmony_ci case OPAL_PARAMETER: 338c2ecf20Sopenharmony_ci err = -EINVAL; 348c2ecf20Sopenharmony_ci break; 358c2ecf20Sopenharmony_ci case OPAL_RESOURCE: 368c2ecf20Sopenharmony_ci err = -ENOSPC; 378c2ecf20Sopenharmony_ci break; 388c2ecf20Sopenharmony_ci case OPAL_HARDWARE: 398c2ecf20Sopenharmony_ci err = -EIO; 408c2ecf20Sopenharmony_ci break; 418c2ecf20Sopenharmony_ci case OPAL_NO_MEM: 428c2ecf20Sopenharmony_ci err = -ENOMEM; 438c2ecf20Sopenharmony_ci break; 448c2ecf20Sopenharmony_ci case OPAL_EMPTY: 458c2ecf20Sopenharmony_ci err = -ENOENT; 468c2ecf20Sopenharmony_ci break; 478c2ecf20Sopenharmony_ci case OPAL_PARTIAL: 488c2ecf20Sopenharmony_ci err = -EFBIG; 498c2ecf20Sopenharmony_ci break; 508c2ecf20Sopenharmony_ci default: 518c2ecf20Sopenharmony_ci err = -EINVAL; 528c2ecf20Sopenharmony_ci } 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci return err; 558c2ecf20Sopenharmony_ci} 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistatic int opal_get_variable(const char *key, uint64_t ksize, 588c2ecf20Sopenharmony_ci u8 *data, uint64_t *dsize) 598c2ecf20Sopenharmony_ci{ 608c2ecf20Sopenharmony_ci int rc; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci if (!key || !dsize) 638c2ecf20Sopenharmony_ci return -EINVAL; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci *dsize = cpu_to_be64(*dsize); 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci rc = opal_secvar_get(key, ksize, data, dsize); 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci *dsize = be64_to_cpu(*dsize); 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci return opal_status_to_err(rc); 728c2ecf20Sopenharmony_ci} 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_cistatic int opal_get_next_variable(const char *key, uint64_t *keylen, 758c2ecf20Sopenharmony_ci uint64_t keybufsize) 768c2ecf20Sopenharmony_ci{ 778c2ecf20Sopenharmony_ci int rc; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci if (!key || !keylen) 808c2ecf20Sopenharmony_ci return -EINVAL; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci *keylen = cpu_to_be64(*keylen); 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci rc = opal_secvar_get_next(key, keylen, keybufsize); 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci *keylen = be64_to_cpu(*keylen); 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci return opal_status_to_err(rc); 898c2ecf20Sopenharmony_ci} 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_cistatic int opal_set_variable(const char *key, uint64_t ksize, u8 *data, 928c2ecf20Sopenharmony_ci uint64_t dsize) 938c2ecf20Sopenharmony_ci{ 948c2ecf20Sopenharmony_ci int rc; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci if (!key || !data) 978c2ecf20Sopenharmony_ci return -EINVAL; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci rc = opal_secvar_enqueue_update(key, ksize, data, dsize); 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci return opal_status_to_err(rc); 1028c2ecf20Sopenharmony_ci} 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_cistatic const struct secvar_operations opal_secvar_ops = { 1058c2ecf20Sopenharmony_ci .get = opal_get_variable, 1068c2ecf20Sopenharmony_ci .get_next = opal_get_next_variable, 1078c2ecf20Sopenharmony_ci .set = opal_set_variable, 1088c2ecf20Sopenharmony_ci}; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_cistatic int opal_secvar_probe(struct platform_device *pdev) 1118c2ecf20Sopenharmony_ci{ 1128c2ecf20Sopenharmony_ci if (!opal_check_token(OPAL_SECVAR_GET) 1138c2ecf20Sopenharmony_ci || !opal_check_token(OPAL_SECVAR_GET_NEXT) 1148c2ecf20Sopenharmony_ci || !opal_check_token(OPAL_SECVAR_ENQUEUE_UPDATE)) { 1158c2ecf20Sopenharmony_ci pr_err("OPAL doesn't support secure variables\n"); 1168c2ecf20Sopenharmony_ci return -ENODEV; 1178c2ecf20Sopenharmony_ci } 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci set_secvar_ops(&opal_secvar_ops); 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci return 0; 1228c2ecf20Sopenharmony_ci} 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_cistatic const struct of_device_id opal_secvar_match[] = { 1258c2ecf20Sopenharmony_ci { .compatible = "ibm,secvar-backend",}, 1268c2ecf20Sopenharmony_ci {}, 1278c2ecf20Sopenharmony_ci}; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_cistatic struct platform_driver opal_secvar_driver = { 1308c2ecf20Sopenharmony_ci .driver = { 1318c2ecf20Sopenharmony_ci .name = "secvar", 1328c2ecf20Sopenharmony_ci .of_match_table = opal_secvar_match, 1338c2ecf20Sopenharmony_ci }, 1348c2ecf20Sopenharmony_ci}; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_cistatic int __init opal_secvar_init(void) 1378c2ecf20Sopenharmony_ci{ 1388c2ecf20Sopenharmony_ci return platform_driver_probe(&opal_secvar_driver, opal_secvar_probe); 1398c2ecf20Sopenharmony_ci} 1408c2ecf20Sopenharmony_cidevice_initcall(opal_secvar_init); 141