diff options
Diffstat (limited to 'roms/skiboot/libstb/secvar/secvar_api.c')
-rw-r--r-- | roms/skiboot/libstb/secvar/secvar_api.c | 157 |
1 files changed, 157 insertions, 0 deletions
diff --git a/roms/skiboot/libstb/secvar/secvar_api.c b/roms/skiboot/libstb/secvar/secvar_api.c new file mode 100644 index 000000000..7245e8590 --- /dev/null +++ b/roms/skiboot/libstb/secvar/secvar_api.c @@ -0,0 +1,157 @@ +// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later +/* Copyright 2019 IBM Corp. */ + +#ifndef pr_fmt +#define pr_fmt(fmt) "SECVAR_API: " fmt +#endif + +#include <opal.h> +#include "secvar.h" + + +static int64_t opal_secvar_get(const char *key, uint64_t key_len, void *data, uint64_t *data_size) +{ + struct secvar *var; + int64_t rc = OPAL_SUCCESS; + + if (!secvar_enabled) + return OPAL_UNSUPPORTED; + if (!secvar_ready) + return OPAL_RESOURCE; + if (!key) + return OPAL_PARAMETER; + if (key_len == 0) + return OPAL_PARAMETER; + // Data size must be set, data is optional for size query + if (!data_size) + return OPAL_PARAMETER; + + var = find_secvar(key, key_len, &variable_bank); + if (!var) + return OPAL_EMPTY; // Variable not found, bail early + + if (!data) + rc = OPAL_SUCCESS; + else if (*data_size < var->data_size) + rc = OPAL_PARTIAL; + else + memcpy(data, var->data, var->data_size); + + *data_size = var->data_size; + + return rc; +} +opal_call(OPAL_SECVAR_GET, opal_secvar_get, 4); + + +static int64_t opal_secvar_get_next(char *key, uint64_t *key_len, uint64_t key_buf_size) +{ + struct secvar *var; + + if (!secvar_enabled) + return OPAL_UNSUPPORTED; + if (!secvar_ready) + return OPAL_RESOURCE; + if (!key_len) + return OPAL_PARAMETER; + if (key_buf_size == 0) + return OPAL_PARAMETER; + if (*key_len > SECVAR_MAX_KEY_LEN) + return OPAL_PARAMETER; + if (*key_len > key_buf_size) + return OPAL_PARAMETER; + if (!key) + return OPAL_PARAMETER; + + if (!is_key_empty(key, *key_len)) { + var = find_secvar(key, *key_len, &variable_bank); + if (!var) + return OPAL_PARAMETER; + + var = list_next(&variable_bank, var, link); + } else { + var = list_top(&variable_bank, struct secvar, link); + } + + if (!var) + return OPAL_EMPTY; + + if (key_buf_size < var->key_len) { + *key_len = var->key_len; + return OPAL_PARTIAL; + } + + *key_len = var->key_len; + memcpy(key, var->key, var->key_len); + + return OPAL_SUCCESS; +} +opal_call(OPAL_SECVAR_GET_NEXT, opal_secvar_get_next, 3); + + +static int64_t opal_secvar_enqueue_update(const char *key, uint64_t key_len, void *data, uint64_t data_size) +{ + struct secvar *var; + + if (!secvar_enabled) + return OPAL_UNSUPPORTED; + if (!secvar_ready) + return OPAL_RESOURCE; + if (!secvar_storage.write_bank) + return OPAL_HARDWARE; + if (!key) + return OPAL_PARAMETER; + if (key_len == 0) + return OPAL_PARAMETER; + if (key_len > SECVAR_MAX_KEY_LEN) + return OPAL_PARAMETER; + if ((!data) && (data_size != 0)) + return OPAL_PARAMETER; + if (data_size > secvar_storage.max_var_size) + return OPAL_PARAMETER; + + // Key should not be empty + if (is_key_empty(key, key_len)) + return OPAL_PARAMETER; + + var = find_secvar(key, key_len, &update_bank); + + // Unstage an update + if (data_size == 0) { + if (!var) + return OPAL_EMPTY; + + list_del(&var->link); + dealloc_secvar(var); + goto out; + } + + if (var) { + list_del(&var->link); + // Realloc var if too small + if (var->data_size < data_size) { + if (realloc_secvar(var, data_size)) + return OPAL_NO_MEM; + } else { + memset(var->data, 0x00, var->data_size); + } + } else { + var = alloc_secvar(key_len, data_size); + if (!var) + return OPAL_NO_MEM; + } + + memcpy(var->key, key, key_len); + var->key_len = key_len; + memcpy(var->data, data, data_size); + var->data_size = data_size; + + list_add_tail(&update_bank, &var->link); + +out: + if (secvar_storage.write_bank(&update_bank, SECVAR_UPDATE_BANK)) + return OPAL_HARDWARE; + else + return OPAL_SUCCESS; +} +opal_call(OPAL_SECVAR_ENQUEUE_UPDATE, opal_secvar_enqueue_update, 4); |