Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 90 additions & 17 deletions source/transfer_list.rst
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,11 @@ This section describes the valid operations that may be performed on a TL in
more detail, in order to clarify how to use the various fields and to serve as a
guideline for implementation.

.. note::
This section assumes te.hdr_size is 0x8 for all TE entries. This is used consistently throughout the examples.
In the future, if entries with different header sizes are introduced, some operations may need to explicitly
take te.hdr_size as an argument.

Validating a TL header
^^^^^^^^^^^^^^^^^^^^^^

Expand Down Expand Up @@ -338,8 +343,7 @@ Inputs:
is smaller or equal to `tl.used_size`, otherwise abort (the TL is corrupted).

#. If `te.tag_id` (`te_base_addr + 0x0`) is a known tag, interpret the data
at `te_base_addr + te.hdr_size` accordingly. (Do not hardcode the value
for `te.hdr_size`, even for known tags!) Otherwise, ignore the tag and
at `te_base_addr + te.hdr_size` accordingly. Otherwise, ignore the tag and
proceed with the next step.

#. Add `align8(te.hdr_size + te.data_size)` to `te_base_addr`.
Expand All @@ -362,14 +366,14 @@ Inputs:

#. Use the `te_base_addr` of this tag for the rest of the operation.

#. If `has_checksum`, Subtract the sum of `align8(new_data_size + 0x8)` bytes
#. If `has_checksum`, Subtract the sum of `align8(new_data_size + te.hdr_size)` bytes
starting at `te_base_addr` from `tl.checksum`.

#. Skip the next step (step 2) with all its substeps.

#. Calculate `te_base_addr` as `tl_base_addr + tl.used_size`.

#. If `tl.total_size - tl.used_size` is smaller than `align8(new_data_size + 0x8)`,
#. If `tl.total_size - tl.used_size` is smaller than `align8(new_data_size + te.hdr_size)`,
abort (not enough room to add TE).

#. If `has_checksum`, subtract the sum of the 4 bytes from
Expand All @@ -386,29 +390,69 @@ Inputs:

#. Set `te.data_size` (`te_base_addr + 0x4`) to `new_data_size`.

#. Copy or generate the TE data into `te_base_addr + 0x8`.
#. Copy or generate the TE data into `te_base_addr + te.hdr_size`.

#. If `has_checksum`, add the sum of `align8(new_data_size + 0x8)` bytes
#. If `has_checksum`, add the sum of `align8(new_data_size + te.hdr_size)` bytes
starting at `te_base_addr` to `tl.checksum`.

#. If an existing XFERLIST_VOID TE was chosen to be overwritten in step 1, and
`old_void_data_size - new_data_size` is greater or equal to `0x8`:
`old_void_data_size - new_data_size` is greater than or equal to `te.hdr_size`, then
create a new void TE to fill the remaining space by calling `Adding a void TE`_
with the following arguments:

#. `void_te.base_addr` = `te_base_addr + align8(new_data_size + te.hdr_size)`

#. `void_te.data_size` = `old_void_data_size - align8(new_data_size + te.hdr_size)`

Removing a TE
^^^^^^^^^^^^^

Inputs:

- `te_base_addr`: Base address of the TE to be removed

#. Invoke `Adding a void TE`_ with following arguments

#. `void_te.base_addr` = `te_base_addr`

#. `void_te.size` = `te.data_size`

#. *(Optional)* Implementations may perform memory management by inspecting adjacent entries
and coalescing consecutive `XFERLIST_VOID` entries into a single larger one. This can help
reduce fragmentation and improve reuse of space in the Transfer List.

Overwriting a TE
^^^^^^^^^^^^^^^^

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be useful to define or motivate this more clearly. Why would one want to do this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overwriting a TE is a space-efficient way to update the data associated with an existing tag without changing its position in the transfer list. This is useful in scenarios where the tag ID remains valid, and only the payload needs to be refreshed. It avoids the overhead of allocating new space and modifying the TL structure unless the new data exceeds the original size, in which case a replacement strategy is triggered.

@sjg20 Do you these comments in spec or you happy with current version ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@danh-arm, could you please merge this PR? @sjg20 is happy with the patch, aside from a single minor nit.

Inputs:

- `te_base_addr`: Base address of the Transfer Entry (TE) to be overwritten
- `new_data_size`: Size in bytes of the new data to be encapsulated in the TE
- [data]: Data to be copied into the TE

#. If `te.data_size` is smaller than `new_data_size`, the overwrite operation must return an error.
The caller is then responsible for:

#. Use `te_base_addr + align8(new_data_size + 0x8)` as the new `te_base_addr`
for a new XFERLIST_VOID tag.
#. Reclaiming the existing space by calling `Adding a void TE`_ with `te_base_addr` and `te.data_size`.

#. If `has_checksum`, subtract the sum of the 8 bytes from `te_base_addr` to
`te_base_addr + 0x8` from `tl.checksum`.
#. Adding a new TE by invoking `Adding a new TE`_ with appropriate arguments.

#. Set `te.tag_id` (`te_base_addr + 0x0`) to `0x0` (XFERLIST_VOID).
#. If `has_checksum`, subtract the sum of `te.data_size` bytes starting at
`te_base_addr + te.hdr_size` from `tl.checksum`.

#. Set `te.hdr_size` (`te_base_addr + 0x3`) to `0x8`.
#. Set `te.data_size` (`te_base_addr + 0x4`) to `align8(new_data_size)`.

#. Set `te.data_size` (`te_base_addr + 0x4`) to
`old_void_data_size - align8(new_data_size) - 0x8`.
#. Copy or generate the new TE data into `te_base_addr + te.hdr_size`.

#. If `has_checksum`, add the sum of the 8 bytes from `te_base_addr` to
`te_base_addr + 0x8` to `tl.checksum`.
#. If `has_checksum`, add the sum of `align8(new_data_size)` bytes starting at
`te_base_addr + te.hdr_size` to `tl.checksum`.

#. If `te.data_size - align8(new_data_size)` is greater than or equal to `te.hdr_size`, create a new
void TE to fill the remaining space by calling `Adding a void TE`_ with the following arguments:

#. `te_base_addr` = `te_base_addr + align8(new_data_size + te.hdr_size)`

#. `data_size` = `te.data_size - align8(new_data_size - te.hdr_size)`

Adding a new TE with special data alignment requirement
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down Expand Up @@ -507,6 +551,35 @@ Inputs:
#. If `has_checksum`, add the sum of the 4 bytes from `new_tl_base + 0xc` to
`new_tl_base + 0x10` to `tl.checksum` (`new_tl_base + 0x4`).

.. note::
After relocating a TL, implementations should consider scrubbing the old TL memory if it contains
any secrets that might be accessible to later untrusted software.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor: I think this note also applies in the case of Removing a TE or Overwriting a TE. This could perhaps be duplicated or placed in a more general section?


Helper Routines
^^^^^^^^^^^^^^^

Adding a void TE
~~~~~~~~~~~~~~~~

Inputs:

- `te_base_addr`: Base address where void TE to be added
- `data_size`: Size in bytes of the data to be encapsulated in void TE

#. If `has_checksum`, subtract the sum of `te.hdr_size + data_size` bytes starting at
`te_base_addr` from `tl.checksum`.

#. Set `te.tag_id` (`te_base_addr + 0x0`) to `0x0` (XFERLIST_VOID)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm in two minds about providing the offsets explicitly (e.g. te_base_addr + 0x3). On one hand it's a useful reference for the implementer, but it may prove a bit of a burden to maintain down the line. As I understand it, the header layout is liable to change. If it does, we'd have to fix all the places in the spec where we reference hard-coded offsets. Given the structure is well defined, I think it's probably sufficient to just refer to it directly (i.e. te.tag_id).

Copy link
Contributor Author

@manish-pandey-arm manish-pandey-arm Dec 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can do this universally when migrating to appendinx ?


#. Set `te.hdr_size` (`te_base_addr + 0x3`) to `0x8`

#. Set `te.data_size` (`te_base_addr + 0x4`) to `align8(data_size)`

#. *(optional)* Set the `data_size` bytes starting at `te_base_addr + te.hdr_size` to 0x0

#. If `has_checksum`, add the sum of `te.hdr_size + data_size` bytes starting at
`te_base_addr` with `tl.checksum`


.. _sec_std_entries:

Expand Down
Loading