Add block storage service provider
Adds an implementation of the block storage service provider and
the related packed-c serializer.
Signed-off-by: Julian Hall <julian.hall@arm.com>
Change-Id: I2ce76b40311d561a17f4e245d22de02c2f6d12ec
diff --git a/components/service/block_storage/provider/block_storage_provider.c b/components/service/block_storage/provider/block_storage_provider.c
new file mode 100644
index 0000000..2369051
--- /dev/null
+++ b/components/service/block_storage/provider/block_storage_provider.c
@@ -0,0 +1,295 @@
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "protocols/service/block_storage/packed-c/opcodes.h"
+#include "protocols/rpc/common/packed-c/status.h"
+#include "block_storage_provider.h"
+
+
+/* Service request handlers */
+static rpc_status_t get_partition_info_handler(void *context, struct call_req* req);
+static rpc_status_t open_handler(void *context, struct call_req* req);
+static rpc_status_t close_handler(void *context, struct call_req* req);
+static rpc_status_t read_handler(void *context, struct call_req* req);
+static rpc_status_t write_handler(void *context, struct call_req* req);
+static rpc_status_t erase_handler(void *context, struct call_req* req);
+
+/* Handler mapping table for service */
+static const struct service_handler handler_table[] = {
+ {TS_BLOCK_STORAGE_OPCODE_GET_PARTITION_INFO, get_partition_info_handler},
+ {TS_BLOCK_STORAGE_OPCODE_OPEN, open_handler},
+ {TS_BLOCK_STORAGE_OPCODE_CLOSE, close_handler},
+ {TS_BLOCK_STORAGE_OPCODE_READ, read_handler},
+ {TS_BLOCK_STORAGE_OPCODE_WRITE, write_handler},
+ {TS_BLOCK_STORAGE_OPCODE_ERASE, erase_handler}
+};
+
+struct rpc_interface *block_storage_provider_init(
+ struct block_storage_provider *context,
+ struct block_store *block_store)
+{
+ struct rpc_interface *rpc_interface = NULL;
+
+ if (context) {
+
+ for (size_t encoding = 0; encoding < TS_RPC_ENCODING_LIMIT; ++encoding)
+ context->serializers[encoding] = NULL;
+
+ context->block_store = block_store;
+
+ service_provider_init(&context->base_provider, context,
+ handler_table, sizeof(handler_table)/sizeof(struct service_handler));
+
+ rpc_interface = service_provider_get_rpc_interface(&context->base_provider);
+ }
+
+ return rpc_interface;
+}
+
+void block_storage_provider_deinit(
+ struct block_storage_provider *context)
+{
+ (void)context;
+}
+
+void block_storage_provider_register_serializer(
+ struct block_storage_provider *context,
+ unsigned int encoding,
+ const struct block_storage_serializer *serializer)
+{
+ if (encoding < TS_RPC_ENCODING_LIMIT)
+ context->serializers[encoding] = serializer;
+}
+
+static const struct block_storage_serializer* get_block_storage_serializer(
+ struct block_storage_provider *context,
+ const struct call_req *req)
+{
+ const struct block_storage_serializer* serializer = NULL;
+ unsigned int encoding = call_req_get_encoding(req);
+
+ if (encoding < TS_RPC_ENCODING_LIMIT) serializer = context->serializers[encoding];
+
+ return serializer;
+}
+
+static rpc_status_t get_partition_info_handler(void *context, struct call_req *req)
+{
+ struct block_storage_provider *this_instance = (struct block_storage_provider*)context;
+ rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
+
+ struct call_param_buf *req_buf = call_req_get_req_buf(req);
+ const struct block_storage_serializer *serializer =
+ get_block_storage_serializer(this_instance, req);
+
+ struct uuid_octets partition_guid = {0};
+
+ if (serializer)
+ rpc_status = serializer->deserialize_get_partition_info_req(req_buf, &partition_guid);
+
+ if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+
+ struct storage_partition_info partition_info;
+
+ psa_status_t op_status = block_store_get_partition_info(
+ this_instance->block_store,
+ &partition_guid,
+ &partition_info);
+
+ call_req_set_opstatus(req, op_status);
+
+ if (op_status == PSA_SUCCESS) {
+
+ struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
+ rpc_status = serializer->serialize_get_partition_info_resp(
+ resp_buf,
+ &partition_info);
+ }
+ }
+
+ return rpc_status;
+}
+
+static rpc_status_t open_handler(void *context, struct call_req *req)
+{
+ struct block_storage_provider *this_instance = (struct block_storage_provider*)context;
+ rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
+
+ struct call_param_buf *req_buf = call_req_get_req_buf(req);
+ const struct block_storage_serializer *serializer =
+ get_block_storage_serializer(this_instance, req);
+
+ struct uuid_octets partition_guid = {0};
+
+ if (serializer)
+ rpc_status = serializer->deserialize_open_req(req_buf, &partition_guid);
+
+ if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+
+ storage_partition_handle_t handle = 0;
+
+ psa_status_t op_status = block_store_open(
+ this_instance->block_store,
+ req->caller_id,
+ &partition_guid,
+ &handle);
+
+ call_req_set_opstatus(req, op_status);
+
+ if (op_status == PSA_SUCCESS) {
+
+ struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
+ rpc_status = serializer->serialize_open_resp(resp_buf, handle);
+ }
+ }
+
+ return rpc_status;
+}
+
+static rpc_status_t close_handler(void *context, struct call_req *req)
+{
+ struct block_storage_provider *this_instance = (struct block_storage_provider*)context;
+ rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
+
+ struct call_param_buf *req_buf = call_req_get_req_buf(req);
+ const struct block_storage_serializer *serializer =
+ get_block_storage_serializer(this_instance, req);
+
+ storage_partition_handle_t handle = 0;
+
+ if (serializer)
+ rpc_status = serializer->deserialize_close_req(req_buf, &handle);
+
+ if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+
+ psa_status_t op_status = block_store_close(
+ this_instance->block_store,
+ req->caller_id,
+ handle);
+
+ call_req_set_opstatus(req, op_status);
+ }
+
+ return rpc_status;
+}
+
+static rpc_status_t read_handler(void *context, struct call_req *req)
+{
+ struct block_storage_provider *this_instance = (struct block_storage_provider*)context;
+ rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
+
+ struct call_param_buf *req_buf = call_req_get_req_buf(req);
+ const struct block_storage_serializer *serializer =
+ get_block_storage_serializer(this_instance, req);
+
+ storage_partition_handle_t handle = 0;
+ uint32_t lba = 0;
+ size_t offset = 0;
+ size_t len = 0;
+
+ if (serializer)
+ rpc_status = serializer->deserialize_read_req(req_buf, &handle, &lba, &offset, &len);
+
+ if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+
+ struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
+
+ /* Defend against oversize read length */
+ if (len > resp_buf->size)
+ len = resp_buf->size;
+
+ psa_status_t op_status = block_store_read(
+ this_instance->block_store,
+ req->caller_id,
+ handle,
+ lba,
+ offset,
+ len,
+ (uint8_t*)resp_buf->data,
+ &resp_buf->data_len);
+
+ call_req_set_opstatus(req, op_status);
+ }
+
+ return rpc_status;
+}
+
+static rpc_status_t write_handler(void *context, struct call_req *req)
+{
+ struct block_storage_provider *this_instance = (struct block_storage_provider*)context;
+ rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
+
+ struct call_param_buf *req_buf = call_req_get_req_buf(req);
+ const struct block_storage_serializer *serializer =
+ get_block_storage_serializer(this_instance, req);
+
+ storage_partition_handle_t handle = 0;
+ uint32_t lba = 0;
+ size_t offset = 0;
+ const uint8_t *data = NULL;
+ size_t data_len = 0;
+
+ if (serializer)
+ rpc_status = serializer->deserialize_write_req(req_buf, &handle, &lba,
+ &offset, &data, &data_len);
+
+ if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+
+ size_t num_written = 0;
+
+ psa_status_t op_status = block_store_write(
+ this_instance->block_store,
+ req->caller_id,
+ handle,
+ lba,
+ offset,
+ data,
+ data_len,
+ &num_written);
+
+ call_req_set_opstatus(req, op_status);
+
+ if (op_status == PSA_SUCCESS) {
+
+ struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
+ rpc_status = serializer->serialize_write_resp(resp_buf, num_written);
+ }
+ }
+
+ return rpc_status;
+}
+
+static rpc_status_t erase_handler(void *context, struct call_req *req)
+{
+ struct block_storage_provider *this_instance = (struct block_storage_provider*)context;
+ rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
+
+ struct call_param_buf *req_buf = call_req_get_req_buf(req);
+ const struct block_storage_serializer *serializer =
+ get_block_storage_serializer(this_instance, req);
+
+ storage_partition_handle_t handle = 0;
+ uint32_t begin_lba = 0;
+ size_t num_blocks = 0;
+
+ if (serializer)
+ rpc_status = serializer->deserialize_erase_req(req_buf, &handle,
+ &begin_lba, &num_blocks);
+
+ if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+
+ psa_status_t op_status = block_store_erase(
+ this_instance->block_store,
+ req->caller_id,
+ handle,
+ begin_lba,
+ num_blocks);
+
+ call_req_set_opstatus(req, op_status);
+ }
+
+ return rpc_status;
+}
diff --git a/components/service/block_storage/provider/block_storage_provider.h b/components/service/block_storage/provider/block_storage_provider.h
new file mode 100644
index 0000000..b647ac7
--- /dev/null
+++ b/components/service/block_storage/provider/block_storage_provider.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef BLOCK_STORAGE_PROVIDER_H
+#define BLOCK_STORAGE_PROVIDER_H
+
+#include "rpc/common/endpoint/rpc_interface.h"
+#include "service/common/provider/service_provider.h"
+#include "service/block_storage/block_store/block_store.h"
+#include "service/block_storage/provider/serializer/block_storage_serializer.h"
+#include "protocols/rpc/common/packed-c/encoding.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* block_storage_provider service provider structure */
+struct block_storage_provider
+{
+ struct service_provider base_provider;
+ const struct block_storage_serializer *serializers[TS_RPC_ENCODING_LIMIT];
+ struct block_store *block_store;
+};
+
+struct rpc_interface *block_storage_provider_init(
+ struct block_storage_provider *context,
+ struct block_store *block_store);
+
+void block_storage_provider_deinit(
+ struct block_storage_provider *context);
+
+void block_storage_provider_register_serializer(
+ struct block_storage_provider *context,
+ unsigned int encoding,
+ const struct block_storage_serializer *serializer);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* BLOCK_STORAGE_PROVIDER_H */
diff --git a/components/service/block_storage/provider/component.cmake b/components/service/block_storage/provider/component.cmake
new file mode 100644
index 0000000..23851f0
--- /dev/null
+++ b/components/service/block_storage/provider/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, 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}/block_storage_provider.c"
+ )
diff --git a/components/service/block_storage/provider/serializer/block_storage_serializer.h b/components/service/block_storage/provider/serializer/block_storage_serializer.h
new file mode 100644
index 0000000..65bcd1e
--- /dev/null
+++ b/components/service/block_storage/provider/serializer/block_storage_serializer.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef BLOCK_STORAGE_PROVIDER_SERIALIZER_H
+#define BLOCK_STORAGE_PROVIDER_SERIALIZER_H
+
+#include <stddef.h>
+#include <stdint.h>
+#include "common/uuid/uuid.h"
+#include "rpc/common/endpoint/rpc_interface.h"
+#include "service/block_storage/block_store/block_store.h"
+
+/* Provides a common interface for parameter serialization operations
+ * for the block storage service provider. Allows alternative serialization
+ * protocols to be used without hard-wiring a particular protocol
+ * into the service provider code. A concrete serializer must
+ * implement this interface.
+ */
+struct block_storage_serializer {
+
+ /* Operation: get_partition_info */
+ rpc_status_t (*deserialize_get_partition_info_req)(const struct call_param_buf *req_buf,
+ struct uuid_octets *partition_guid);
+
+ rpc_status_t (*serialize_get_partition_info_resp)(struct call_param_buf *resp_buf,
+ struct storage_partition_info *info);
+
+ /* Operation: open */
+ rpc_status_t (*deserialize_open_req)(const struct call_param_buf *req_buf,
+ struct uuid_octets *partition_guid);
+
+ rpc_status_t (*serialize_open_resp)(struct call_param_buf *resp_buf,
+ storage_partition_handle_t handle);
+
+ /* Operation: close */
+ rpc_status_t (*deserialize_close_req)(const struct call_param_buf *req_buf,
+ storage_partition_handle_t *handle);
+
+ /* Operation: read */
+ rpc_status_t (*deserialize_read_req)(const struct call_param_buf *req_buf,
+ storage_partition_handle_t *handle,
+ uint32_t *lba,
+ size_t *offset,
+ size_t *len);
+
+ /* Operation: write */
+ rpc_status_t (*deserialize_write_req)(const struct call_param_buf *req_buf,
+ storage_partition_handle_t *handle,
+ uint32_t *lba,
+ size_t *offset,
+ const uint8_t **data,
+ size_t *data_len);
+
+ rpc_status_t (*serialize_write_resp)(struct call_param_buf *resp_buf,
+ size_t num_written);
+
+ /* Operation: erase */
+ rpc_status_t (*deserialize_erase_req)(const struct call_param_buf *req_buf,
+ storage_partition_handle_t *handle,
+ uint32_t *begin_lba,
+ size_t *num_blocks);
+};
+
+#endif /* BLOCK_STORAGE_PROVIDER_SERIALIZER_H */
diff --git a/components/service/block_storage/provider/serializer/packed-c/component.cmake b/components/service/block_storage/provider/serializer/packed-c/component.cmake
new file mode 100644
index 0000000..e5887a4
--- /dev/null
+++ b/components/service/block_storage/provider/serializer/packed-c/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, 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}/packedc_block_storage_serializer.c"
+ )
diff --git a/components/service/block_storage/provider/serializer/packed-c/packedc_block_storage_serializer.c b/components/service/block_storage/provider/serializer/packed-c/packedc_block_storage_serializer.c
new file mode 100644
index 0000000..cb5fd7a
--- /dev/null
+++ b/components/service/block_storage/provider/serializer/packed-c/packedc_block_storage_serializer.c
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <string.h>
+#include "common/tlv/tlv.h"
+#include "common/endian/le.h"
+#include "protocols/rpc/common/packed-c/status.h"
+#include "protocols/service/block_storage/packed-c/messages.h"
+#include "packedc_block_storage_serializer.h"
+
+
+/* Operation: get_partition_info */
+rpc_status_t deserialize_get_partition_info_req(const struct call_param_buf *req_buf,
+ struct uuid_octets *partition_guid)
+{
+ rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
+ struct ts_block_storage_get_partition_info_in recv_msg;
+ size_t expected_fixed_len = sizeof(struct ts_block_storage_get_partition_info_in);
+
+ if (expected_fixed_len <= req_buf->data_len) {
+
+ memcpy(&recv_msg, req_buf->data, expected_fixed_len);
+ memcpy(&partition_guid->octets, recv_msg.partition_guid, sizeof(partition_guid->octets));
+ rpc_status = TS_RPC_CALL_ACCEPTED;
+ }
+
+ return rpc_status;
+}
+
+rpc_status_t serialize_get_partition_info_resp(struct call_param_buf *resp_buf,
+ struct storage_partition_info *info)
+{
+ rpc_status_t rpc_status = TS_RPC_ERROR_INTERNAL;
+ struct ts_block_storage_get_partition_info_out resp_msg;
+ size_t fixed_len = sizeof(struct ts_block_storage_get_partition_info_out);
+
+ resp_msg.num_blocks = info->num_blocks;
+ resp_msg.block_size = info->block_size;
+
+ if (fixed_len <= resp_buf->size) {
+
+ memcpy(resp_buf->data, &resp_msg, fixed_len);
+ resp_buf->data_len = fixed_len;
+ rpc_status = TS_RPC_CALL_ACCEPTED;
+ }
+
+ return rpc_status;
+}
+
+/* Operation: open */
+rpc_status_t deserialize_open_req(const struct call_param_buf *req_buf,
+ struct uuid_octets *partition_guid)
+{
+ rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
+ struct ts_block_storage_open_in recv_msg;
+ size_t expected_fixed_len = sizeof(struct ts_block_storage_open_in);
+
+ if (expected_fixed_len <= req_buf->data_len) {
+
+ memcpy(&recv_msg, req_buf->data, expected_fixed_len);
+ memcpy(&partition_guid->octets, recv_msg.partition_guid, sizeof(partition_guid->octets));
+ rpc_status = TS_RPC_CALL_ACCEPTED;
+ }
+
+ return rpc_status;
+}
+
+rpc_status_t serialize_open_resp(struct call_param_buf *resp_buf,
+ storage_partition_handle_t handle)
+{
+ rpc_status_t rpc_status = TS_RPC_ERROR_INTERNAL;
+ struct ts_block_storage_open_out resp_msg;
+ size_t fixed_len = sizeof(struct ts_block_storage_open_out);
+
+ resp_msg.handle = handle;
+
+ if (fixed_len <= resp_buf->size) {
+
+ memcpy(resp_buf->data, &resp_msg, fixed_len);
+ resp_buf->data_len = fixed_len;
+ rpc_status = TS_RPC_CALL_ACCEPTED;
+ }
+
+ return rpc_status;
+}
+
+/* Operation: close */
+rpc_status_t deserialize_close_req(const struct call_param_buf *req_buf,
+ storage_partition_handle_t *handle)
+{
+ rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
+ struct ts_block_storage_close_in recv_msg;
+ size_t expected_fixed_len = sizeof(struct ts_block_storage_close_in);
+
+ if (expected_fixed_len <= req_buf->data_len) {
+
+ memcpy(&recv_msg, req_buf->data, expected_fixed_len);
+ *handle = recv_msg.handle;
+ rpc_status = TS_RPC_CALL_ACCEPTED;
+ }
+
+ return rpc_status;
+}
+
+/* Operation: read */
+rpc_status_t deserialize_read_req(const struct call_param_buf *req_buf,
+ storage_partition_handle_t *handle,
+ uint32_t *lba,
+ size_t *offset,
+ size_t *len)
+{
+ rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
+ struct ts_block_storage_read_in recv_msg;
+ size_t expected_fixed_len = sizeof(struct ts_block_storage_read_in);
+
+ if (expected_fixed_len <= req_buf->data_len) {
+
+ memcpy(&recv_msg, req_buf->data, expected_fixed_len);
+ *handle = recv_msg.handle;
+ *lba = recv_msg.lba;
+ *offset = recv_msg.offset;
+ *len = recv_msg.len;
+ rpc_status = TS_RPC_CALL_ACCEPTED;
+ }
+
+ return rpc_status;
+}
+
+/* Operation: write */
+rpc_status_t deserialize_write_req(const struct call_param_buf *req_buf,
+ storage_partition_handle_t *handle,
+ uint32_t *lba,
+ size_t *offset,
+ const uint8_t **data,
+ size_t *data_len)
+{
+ rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
+ struct ts_block_storage_write_in recv_msg;
+ size_t expected_fixed_len = sizeof(struct ts_block_storage_write_in);
+
+ if (expected_fixed_len <= req_buf->data_len) {
+
+ memcpy(&recv_msg, req_buf->data, expected_fixed_len);
+
+ *handle = recv_msg.handle;
+ *lba = recv_msg.lba;
+ *offset = recv_msg.offset;
+
+ *data = (const uint8_t*)req_buf->data + expected_fixed_len;
+ *data_len = req_buf->data_len - expected_fixed_len;
+
+ rpc_status = TS_RPC_CALL_ACCEPTED;
+ }
+
+ return rpc_status;
+}
+
+rpc_status_t serialize_write_resp(struct call_param_buf *resp_buf,
+ size_t num_written)
+{
+ rpc_status_t rpc_status = TS_RPC_ERROR_INTERNAL;
+ struct ts_block_storage_write_out resp_msg;
+ size_t fixed_len = sizeof(struct ts_block_storage_write_out);
+
+ resp_msg.num_written = num_written;
+
+ if (fixed_len <= resp_buf->size) {
+
+ memcpy(resp_buf->data, &resp_msg, fixed_len);
+ resp_buf->data_len = fixed_len;
+ rpc_status = TS_RPC_CALL_ACCEPTED;
+ }
+
+ return rpc_status;
+}
+
+/* Operation: erase */
+rpc_status_t deserialize_erase_req(const struct call_param_buf *req_buf,
+ storage_partition_handle_t *handle,
+ uint32_t *begin_lba,
+ size_t *num_blocks)
+{
+ rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
+ struct ts_block_storage_erase_in recv_msg;
+ size_t expected_fixed_len = sizeof(struct ts_block_storage_erase_in);
+
+ if (expected_fixed_len <= req_buf->data_len) {
+
+ memcpy(&recv_msg, req_buf->data, expected_fixed_len);
+
+ *handle = recv_msg.handle;
+ *begin_lba = recv_msg.begin_lba;
+ *num_blocks = (size_t)recv_msg.num_blocks;
+
+ rpc_status = TS_RPC_CALL_ACCEPTED;
+ }
+
+ return rpc_status;
+}
+
+/* Singleton method to provide access to the serializer instance */
+const struct block_storage_serializer *packedc_block_storage_serializer_instance(void)
+{
+ static const struct block_storage_serializer instance =
+ {
+ deserialize_get_partition_info_req,
+ serialize_get_partition_info_resp,
+ deserialize_open_req,
+ serialize_open_resp,
+ deserialize_close_req,
+ deserialize_read_req,
+ deserialize_write_req,
+ serialize_write_resp,
+ deserialize_erase_req
+ };
+
+ return &instance;
+}
diff --git a/components/service/block_storage/provider/serializer/packed-c/packedc_block_storage_serializer.h b/components/service/block_storage/provider/serializer/packed-c/packedc_block_storage_serializer.h
new file mode 100644
index 0000000..86c7807
--- /dev/null
+++ b/components/service/block_storage/provider/serializer/packed-c/packedc_block_storage_serializer.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PACKEDC_BLOCK_STORAGE_PROVIDER_SERIALIZER_H
+#define PACKEDC_BLOCK_STORAGE_PROVIDER_SERIALIZER_H
+
+#include <service/block_storage/provider/serializer/block_storage_serializer.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Singleton method to provide access to the packed-c serializer
+ * for the block storage service provider.
+ */
+const struct block_storage_serializer *packedc_block_storage_serializer_instance(void);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* PACKEDC_BLOCK_STORAGE_PROVIDER_SERIALIZER_H */
diff --git a/deployments/component-test/component-test.cmake b/deployments/component-test/component-test.cmake
index a1be1dd..532ae21 100644
--- a/deployments/component-test/component-test.cmake
+++ b/deployments/component-test/component-test.cmake
@@ -83,6 +83,8 @@
"components/service/block_storage/block_store/device/null"
"components/service/block_storage/block_store/partitioned"
"components/service/block_storage/block_store/partitioned/test"
+ "components/service/block_storage/provider"
+ "components/service/block_storage/provider/serializer/packed-c"
"components/service/crypto/client/cpp"
"components/service/crypto/client/cpp/protocol/protobuf"
"components/service/crypto/client/cpp/protocol/packed-c"