aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulian Hall <julian.hall@arm.com>2021-10-13 11:43:30 +0100
committerGyorgy Szing <Gyorgy.Szing@arm.com>2021-11-26 05:05:42 +0100
commit54e7a4d33e0013e85a9e418c423667bf4ef45068 (patch)
tree2d0e54d9db70a4670b1154661b607a67b9fa68f0
parent919b558abde8b042e6301a334874058d24c1d230 (diff)
downloadtrusted-services-54e7a4d33e0013e85a9e418c423667bf4ef45068.tar.gz
Add smm_variable service provider
Adds an implementation of a service provider for the smm_variable service. Accepts uefi variable requests and uses the uefi_variable_store as the backend for storage. Signed-off-by: Julian Hall <julian.hall@arm.com> Change-Id: I050fc26c03b4d0098ccc303a293b8faeab488419
-rw-r--r--components/service/smm_variable/provider/component.cmake13
-rw-r--r--components/service/smm_variable/provider/smm_variable_provider.c222
-rw-r--r--components/service/smm_variable/provider/smm_variable_provider.h63
-rw-r--r--deployments/component-test/component-test.cmake1
4 files changed, 299 insertions, 0 deletions
diff --git a/components/service/smm_variable/provider/component.cmake b/components/service/smm_variable/provider/component.cmake
new file mode 100644
index 000000000..f20d18ffc
--- /dev/null
+++ b/components/service/smm_variable/provider/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/smm_variable_provider.c"
+ )
diff --git a/components/service/smm_variable/provider/smm_variable_provider.c b/components/service/smm_variable/provider/smm_variable_provider.c
new file mode 100644
index 000000000..2de02a09b
--- /dev/null
+++ b/components/service/smm_variable/provider/smm_variable_provider.c
@@ -0,0 +1,222 @@
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+#include <string.h>
+#include <protocols/service/smm_variable/smm_variable_proto.h>
+#include <protocols/rpc/common/packed-c/status.h>
+#include "smm_variable_provider.h"
+
+/* Service request handlers */
+static rpc_status_t get_variable_handler(void *context, struct call_req *req);
+static rpc_status_t get_next_variable_name_handler(void *context, struct call_req *req);
+static rpc_status_t set_variable_handler(void *context, struct call_req *req);
+static rpc_status_t query_variable_info_handler(void *context, struct call_req *req);
+static rpc_status_t exit_boot_service_handler(void *context, struct call_req *req);
+
+/* Handler mapping table for service */
+static const struct service_handler handler_table[] = {
+ {SMM_VARIABLE_FUNCTION_GET_VARIABLE, get_variable_handler},
+ {SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME, get_next_variable_name_handler},
+ {SMM_VARIABLE_FUNCTION_SET_VARIABLE, set_variable_handler},
+ {SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO, query_variable_info_handler},
+ {SMM_VARIABLE_FUNCTION_EXIT_BOOT_SERVICE, exit_boot_service_handler}
+};
+
+struct rpc_interface *smm_variable_provider_init(
+ struct smm_variable_provider *context,
+ uint32_t owner_id,
+ size_t max_variables,
+ struct storage_backend *persistent_store,
+ struct storage_backend *volatile_store)
+{
+ struct rpc_interface *rpc_interface = NULL;
+
+ if (context) {
+
+ service_provider_init(&context->base_provider, context,
+ handler_table, sizeof(handler_table)/sizeof(struct service_handler));
+
+ if (uefi_variable_store_init(
+ &context->variable_store,
+ owner_id,
+ max_variables,
+ persistent_store,
+ volatile_store) == EFI_SUCCESS) {
+
+ rpc_interface = service_provider_get_rpc_interface(&context->base_provider);
+ }
+ }
+
+ return rpc_interface;
+}
+
+void smm_variable_provider_deinit(struct smm_variable_provider *context)
+{
+ uefi_variable_store_deinit(&context->variable_store);
+}
+
+static size_t sanitize_access_variable_param(struct call_req *req)
+{
+ size_t param_len = 0;
+ const struct call_param_buf *req_buf = call_req_get_req_buf(req);
+
+ if (req_buf->data_len >= SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE_NAME_OFFSET) {
+
+ const SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *param =
+ (const SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE*)req_buf->data;
+ size_t length_with_name =
+ SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE_DATA_OFFSET(param);
+
+ if (length_with_name <= req_buf->data_len) {
+
+ param_len = length_with_name;
+ }
+ }
+
+ return param_len;
+}
+
+static size_t sanitize_get_next_var_name_param(struct call_req *req)
+{
+ size_t param_len = 0;
+ const struct call_param_buf *req_buf = call_req_get_req_buf(req);
+
+ if (req_buf->data_len >= SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME_NAME_OFFSET) {
+
+ const SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME *param =
+ (const SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME*)req_buf->data;
+ size_t length_with_name =
+ SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME_TOTAL_SIZE(param);
+
+ if (length_with_name <= req_buf->data_len) {
+
+ param_len = length_with_name;
+ }
+ }
+
+ return param_len;
+}
+
+static rpc_status_t get_variable_handler(void *context, struct call_req *req)
+{
+ struct smm_variable_provider *this_instance = (struct smm_variable_provider*)context;
+
+ rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
+ size_t param_len = sanitize_access_variable_param(req);
+
+ if (param_len) {
+
+ /* Valid access variable header parameter */
+ rpc_status = TS_RPC_ERROR_INVALID_RESP_BODY;
+ struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
+
+ if (resp_buf->size >= param_len) {
+
+ struct call_param_buf *req_buf = call_req_get_req_buf(req);
+ size_t max_data_len = resp_buf->size - param_len;
+
+ memmove(resp_buf->data, req_buf->data, param_len);
+
+ efi_status_t efi_status = uefi_variable_store_get_variable(
+ &this_instance->variable_store,
+ (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE*)resp_buf->data,
+ max_data_len,
+ &resp_buf->data_len);
+
+ rpc_status = TS_RPC_CALL_ACCEPTED;
+ call_req_set_opstatus(req, efi_status);
+ }
+ }
+
+ return rpc_status;
+}
+
+static rpc_status_t get_next_variable_name_handler(void *context, struct call_req* req)
+{
+ struct smm_variable_provider *this_instance = (struct smm_variable_provider*)context;
+
+ rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
+ size_t param_len = sanitize_get_next_var_name_param(req);
+
+ if (param_len) {
+
+ /* Valid get next variable name header */
+ rpc_status = TS_RPC_ERROR_INVALID_RESP_BODY;
+ struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
+
+ if (resp_buf->size >= param_len) {
+
+ struct call_param_buf *req_buf = call_req_get_req_buf(req);
+ size_t max_name_len = resp_buf->size -
+ SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME_NAME_OFFSET;
+
+ memmove(resp_buf->data, req_buf->data, param_len);
+
+ efi_status_t efi_status = uefi_variable_store_get_next_variable_name(
+ &this_instance->variable_store,
+ (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME*)resp_buf->data,
+ max_name_len,
+ &resp_buf->data_len);
+
+ rpc_status = TS_RPC_CALL_ACCEPTED;
+ call_req_set_opstatus(req, efi_status);
+ }
+ }
+
+ return rpc_status;
+}
+
+static rpc_status_t set_variable_handler(void *context, struct call_req* req)
+{
+ struct smm_variable_provider *this_instance = (struct smm_variable_provider*)context;
+
+ rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
+ size_t param_len = sanitize_access_variable_param(req);
+
+ if (param_len) {
+
+ /* Access variable header is whole. Check that buffer length can
+ * accommodate the data.
+ */
+ struct call_param_buf *req_buf = call_req_get_req_buf(req);
+ const SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *access_var =
+ (const SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE*)req_buf->data;
+
+ if (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE_TOTAL_SIZE(access_var) <= req_buf->data_len) {
+
+ efi_status_t efi_status = uefi_variable_store_set_variable(
+ &this_instance->variable_store,
+ access_var);
+
+ rpc_status = TS_RPC_CALL_ACCEPTED;
+ call_req_set_opstatus(req, efi_status);
+ }
+ }
+
+ return rpc_status;
+}
+
+static rpc_status_t query_variable_info_handler(void *context, struct call_req* req)
+{
+ struct smm_variable_provider *this_instance = (struct smm_variable_provider*)context;
+ rpc_status_t rpc_status = TS_RPC_ERROR_NOT_READY;
+
+ /* todo */
+
+ return rpc_status;
+}
+
+static rpc_status_t exit_boot_service_handler(void *context, struct call_req* req)
+{
+ struct smm_variable_provider *this_instance = (struct smm_variable_provider*)context;
+ rpc_status_t rpc_status = TS_RPC_CALL_ACCEPTED;
+
+ efi_status_t efi_status = uefi_variable_store_exit_boot_service(&this_instance->variable_store);
+ call_req_set_opstatus(req, efi_status);
+
+ return rpc_status;
+}
diff --git a/components/service/smm_variable/provider/smm_variable_provider.h b/components/service/smm_variable/provider/smm_variable_provider.h
new file mode 100644
index 000000000..c6793977f
--- /dev/null
+++ b/components/service/smm_variable/provider/smm_variable_provider.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SMM_VARIABLE_PROVIDER_H
+#define SMM_VARIABLE_PROVIDER_H
+
+#include <rpc/common/endpoint/rpc_interface.h>
+#include <service/common/provider/service_provider.h>
+#include <service/smm_variable/backend/uefi_variable_store.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * The smm_variable_provider is a service provider that implements an RPC interface
+ * for an instance of the smm_variable service.
+ */
+struct smm_variable_provider
+{
+ struct service_provider base_provider;
+ struct uefi_variable_store variable_store;
+};
+
+/**
+ * \brief Initialize an instance of the smm_variable service provider
+ *
+ * Initializes an smm_variable service provider. Returns an rpc_interface that should
+ * be associated with a suitable rpc endpoint. Storage backends for NV and volatile
+ * stores are assumed to be deployment specific and are passed as initialization
+ * parameters.
+ *
+ * @param[in] context The instance to initialize
+ * @param[in] owner_id The id of the owning security domain (e.g. partition id)
+ * @param[in] max_variables The maximum number of stored variables
+ * @param[in] persistent_store The persistent storage backend to use
+ * @param[in] volatile_store The volatile storage backend to use
+ *
+ * \return An rpc_interface or NULL on failure
+ */
+struct rpc_interface *smm_variable_provider_init(
+ struct smm_variable_provider *context,
+ uint32_t owner_id,
+ size_t max_variables,
+ struct storage_backend *persistent_store,
+ struct storage_backend *volatile_store);
+
+/**
+ * \brief Cleans up when the instance is no longer needed
+ *
+ * \param[in] context The instance to de-initialize
+ */
+void smm_variable_provider_deinit(
+ struct smm_variable_provider *context);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* SMM_VARIABLE_PROVIDER_H */
diff --git a/deployments/component-test/component-test.cmake b/deployments/component-test/component-test.cmake
index 1ffcb695f..2fdc85792 100644
--- a/deployments/component-test/component-test.cmake
+++ b/deployments/component-test/component-test.cmake
@@ -118,6 +118,7 @@ add_components(
"components/service/test_runner/provider"
"components/service/test_runner/provider/serializer/packed-c"
"components/service/test_runner/provider/backend/null"
+ "components/service/smm_variable/provider"
"components/service/smm_variable/backend"
"components/service/smm_variable/backend/test"
"protocols/rpc/common/protobuf"