blob: a29f057c31386756da5c0a8c9a9df1d4bc8c03a4 [file] [log] [blame]
Block Storage Service
=====================
Overview
--------
The Block Storage service can be used to share a block-oriented storage device
such as a QSPI flash between a set of independent secure world clients. A block
storage service provider presents a block level interface for accessing an
underlying block storage device. To allow multiple higher layer filesystems to
share the same storage device, logical block addresses are partitioned, based on
configuration data provided by a system integrator. The partition configuration
data may be read from a GUID Partition Table (GPT) or from the block storage SP
manifest. The configuration data restricts access to a storage partition to a
defined owner. Each owner is allocated a maximum number of blocks and is given
exclusive access to its own blocks, based on the client ID of the calling client.
The following diagram illustrates a firmware integration that uses a single block
storage service provider to control access to a dedicated flash device. In this
example StMM, OP-TEE, Update Agent and the Protected Storage SP act as clients of
the service. Each client independently manages its own filesystem and is presented
with its own logical partition, starting with a logical block address (LBA) of zero.
.. image:: image/block-storage-example-usage.svg
Project Directories
-------------------
Components within the Trusted Services project related to the Block Storage service
are located under the following directories:
.. list-table::
:header-rows: 1
* - Directory
- Contains
* - ``components/service/block_storage``
- Service specific code components.
* - ``deployments/block-storage``
- Build files and deployment specific code for building alternative configurations
of the block storage service provider.
* - ``protocols/service/block_storage``
- Service access protocol definitions.
Service Interface
-----------------
The Block Storage service supports a conventional set of block-level operations that
can be adapted to different driver models by clients. The following table summarizes
supported operations:
.. list-table::
:header-rows: 1
* - Operation
- Description
* - Open
- Open a session - take the required *UniquePartitionGUID* as a parameter. Returns
a handle to be used as a qualifier for other requests made by a client.
* - Close
- Close a previously opened session.
* - GetInfo
- Returns information about the partition associated with an open session. Includes
the block size and the total number of blocks assigned to the partition.
* - Read
- Read data from the specified block.
* - Write
- Write data to the specified block.
* - Erase
- Erase a set of one or more blocks.
Protocol definitions live under: ``protocols/service/block_storage``.
The service interface is realized by the block storage service provider. It delegates
storage operations to a backend *block_store*. The *block_store* defines a common
interface for components that realize block storage operations. Where an underlying storage
technology does not support an explicit erase operation (e.g. RPMB), the corresponding
concrete *block_store* should return success for a call to erase but perform no actual
operation (if the partition is writable and the LBA falls within the limits of the
partition).
Service Provider Configuration
------------------------------
A platform integrator must provide a set of configuration data to configure how the block
storage service provider presents block storage to clients. Configuration data relates to
the following:
- **Storage partition configuration** - determines how storage is divided into separate partitions
- **Block device configuration** - determines how the backed storage device is configured
Storage Partition Configuration
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The block storage service allows a block storage device to be presented as a single storage
partition or as a set of smaller storage partitions. The way that storage is presented is
determined by configuration data prepared by a platform integrator. Each storage partition
presented by a block storage service provider starts at LBA zero. The number of partitions
and their size are defined by configuration data. Configuration data assigns partitions
to owners to enable access to be controlled. If no partition configuration exists for a
requesting client or if an attempt is made to access a block outside of the configured LBA
range, access is denied. The set of storage partitions used for secure block storage will
not necessarily span the entire underlying storage device. A platform integrator is free to
limit the area used for secure block storage to allow the storage device to be used for other
purposes e.g. as a boot source, read by the boot loader during early boot stages.
Two partition configuration methods will be supported; one where partition configuration data
is read from an SP manifest and the other where configuration is defined by a GUID Partition
Table. Both methods may be used in combination if necessary. Initial implementations will
use the SP manifest configuration method.
Each partition configuration entry includes an attributes bitmap that conforms to the UEFI
GPT Partition Entry attributes definition (see section 5.3 of the UEFI specification). Bits
48-63 are reserved for GUID specific use. For partitions labelled with the Secure Block Store
GUID, bits will be defined for:
- **Read-only** - write and erase operations are forbidden.
A GPT partition entry includes the PartitionName property which normally holds a human readable
name for the partition. For secure block store partitions, the PartitionName property will
hold the canonical UUID string identifying the owner. An empty string is interpreted as
'no specific owner' and any client will be granted access.
Configuration via SP Manifest
"""""""""""""""""""""""""""""
For an SP deployment, the partition configuration may be read from a device tree blob (DTB),
passed as an initialization parameter. Per-partition configuration data comprises the following:
.. list-table::
:header-rows: 1
* - Config Value
- Description
* - UniquePartitionGUID
- GUID that is unique for a partition entry.
* - StartingLBA
- The storage block address corresponding to LBA zero.
* - EndingLBA
- The last storage block in the contiguous range of blocks.
* - Attributes
- See UEFI specification
* - Owner
- Holds canonical UUID string for owner.
The partition configuration is included as a sub-node of the block-dev node that includes
configuration values related to the block device. The following is an example of how a block
device and related partitions are defined within a DT based SP manifest::
block-dev {
compatible = "tforg,ts-block-dev"
disk-guid = "af9f72de-d71f-4492-b44b-a4b4d96000bf"
partitions {
compatible = "tforg,ts-block-partitions"
fwu-meta {
guid = "a6f99e90-7a75-4384-847a-29c9a86c6279"
start-lba = <0x00000000>
end-lba = <0x00000003>
attr = <0x00000000>
owner = "afb995cd-9354-4333-9ea2-bd62ccaedb22"
};
fip {
guid = "1eccc9bc-9a5f-43d0-bcd3-466fd21c9a92"
start-lba = <0x00000004>
end-lba = <0x00040003>
attr = <0x00000000>
owner = "afb995cd-9354-4333-9ea2-bd62ccaedb22"
};
uefi-var {
guid = "1022a92b-4b4a-47b4-94cb-35faf5a45dc2"
start-lba = <0x00040004>
end-lba = <0x00080003>
attr = <0x00000000>
owner = "ed32d533-99e6-4209-9cc0-2d72cdd998a7"
};
};
};
Configuration via GUID Partition Table (GPT)
""""""""""""""""""""""""""""""""""""""""""""
The UEFI specification defines a standard layout for physical storage devices where storage
partitions are described by partition entries within the GUID Partition Table. During
initialization, the Block Storage SP will read the GPT and iterate over partition entries,
identifying those with the secure block store partition type GUID. Each entry contains the
following:
.. list-table::
:header-rows: 1
* - Offset
- Length
- contents
* - 0
- 16 bytes
- PartitionTypeGUID - Secure Block Store GUID
* - 16
- 16 bytes
- UniquePartitionGUID
* - 32
- 8 bytes
- Starting LBA
* - 40
- 8 bytes
- Ending LBA
* - 48
- 8 bytes
- Attributes (e.g. read-only)
* - 56
- 72 bytes
- PartitionName - Holds canonical UUID string for owner.
Design Description
------------------
The block storage service provider conforms to the same model as other service providers
within the TS project. Service requests from clients are received by a service provider
that is responsible for parameter deserialization/serialization and service level access
control. Block storage operations are delegated to a backend *block_store* that provides
block-level storage in some way. There is much flexibility to realize the backend block-level
storage in different ways, allowing platform integrators to use alternative *block_store*
realizations to provide storage solutions that meet specific product requirements.
The following class diagram illustrates the block storage service provider model:
.. uml:: uml/BlockStorageProvider.puml
Block Store
^^^^^^^^^^^
The *block_store* component defines a virtual interface for block IO operations. Alternative
concrete *block_store* implementations are supported. Some *block_store* components are stackable
over other *block_store* components to add features such as store partitioning or block
authentication. Separation of functionality into stackable *block_store* components gives
platform integrators the flexibility to create alternative storage solutions with different
security/cost tradeoffs. The base *block_store* interface is defined in::
components/service/block_storage/block_store/block_store.h
Components that implement the *block_store* interface are located in subdirectories beneath
``components/service/block_storage/block_store``. A *block_device* is class of *block_store*
that actually provides block-level storage. In a stack of *block_store* components, a
*block_device* will always live at the bottom. The following layer diagram illustrates a
typical block storage deployment where storage is provided by a stack of *block_store* components:
.. image:: image/block-storage-layers.svg
Some block devices supported in the TS project (located under:
``components/service/block_storage/block_store/block_device``) are:
- **ram_block_store** - stores blocks in RAM. Intended for test purposes.
- **null_block_store** - a store with no real storage. Always accepts legal writes and returns
zeros for reads.
- **fvb_block_store** - an adapter that uses a UEFI firmware volume block driver to access
storage. Can be used with drivers from the EDK2 project.
Other supported block_store components:
- **partitioned_block_store** - a stackable *block_store* that presents an underlying *block_store*
as a set of configurable storage partitions.
- **block_storage_client** - communicates with a remote block storage service provider to provide
storage.
--------------
*Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.*
SPDX-License-Identifier: BSD-3-Clause