| // Copyright 2019 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| library fuchsia.sysmem; |
| |
| using zx; |
| |
| /// SecureMem |
| /// |
| /// The client is sysmem. The server is securemem driver. |
| /// |
| /// TEE - Trusted Execution Environment. |
| /// |
| /// REE - Rich Execution Environment. |
| /// |
| /// Enables sysmem to call the securemem driver to get any secure heaps |
| /// configured via the TEE (or via the securemem driver), and set any physical |
| /// secure heaps configured via sysmem. |
| /// |
| /// Presently, dynamically-allocated secure heaps are configured via sysmem, as |
| /// it starts quite early during boot and can successfully reserve contiguous |
| /// physical memory. Presently, fixed-location secure heaps are configured via |
| /// TEE, as the plumbing goes from the bootloader to the TEE. However, this |
| /// protocol intentionally doesn't care which heaps are dynamically-allocated |
| /// and which are fixed-location. |
| protocol SecureMem { |
| /// Gets the physical address and length of any secure heap whose physical |
| /// range is configured via the TEE. |
| /// |
| /// Presently, these will be fixed physical addresses and lengths, with the |
| /// location plumbed via the TEE. |
| /// |
| /// This is preferred over RegisterHeap() when there isn't any special |
| /// heap-specific per-VMO setup or teardown required. |
| /// |
| /// The physical range must be secured/protected by the TEE before the |
| /// securemem driver responds to this request with success. |
| /// |
| /// Sysmem should only call this once. Returning zero heaps is not a |
| /// failure. |
| /// |
| /// Errors: |
| /// * ZX_ERR_BAD_STATE - called more than once. |
| /// * ZX_ERR_INTERNAL - generic internal error (such as in communication |
| /// with TEE which doesn't generate zx_status_t errors). |
| /// * other errors are possible, such as from communication failures or |
| /// server propagation of zx_status_t failures |
| GetPhysicalSecureHeaps() -> (struct { |
| heaps SecureHeapsAndRanges; |
| }) error zx.status; |
| |
| /// This request from sysmem to the securemem driver gets the properties of |
| /// a protected/secure heap. |
| GetPhysicalSecureHeapProperties(struct { |
| heap HeapType; |
| }) -> (struct { |
| properties SecureHeapProperties; |
| }) error zx.status; |
| |
| /// This request from sysmem to the securemem driver conveys a physical |
| /// range to add, for a heap whose physical range(s) are set up via |
| /// sysmem. |
| /// |
| /// Only sysmem can call this because only sysmem is handed the client end |
| /// of a FIDL channel serving this protocol, via RegisterSecureMem(). The |
| /// securemem driver is the server end of this protocol. |
| /// |
| /// The securemem driver must configure all the covered offsets as protected |
| /// before responding to this message with success. |
| /// |
| /// On failure, the securemem driver must ensure the protected range was not |
| /// created. |
| /// |
| /// Sysmem must only call this up to once if dynamic_protection_ranges |
| /// false. |
| /// |
| /// If dynamic_protection_ranges is true, sysmem can call this multiple |
| /// times as long as the current number of ranges never exceeds |
| /// max_protected_range_count. |
| /// |
| /// The caller must not attempt to add a range that matches an |
| /// already-existing range. Added ranges can overlap each other as long as |
| /// no two ranges match exactly. |
| /// |
| /// Errors: |
| /// * ZX_ERR_BAD_STATE - called more than once when |
| /// !dynamic_protection_ranges. Adding a heap that would cause overall |
| /// heap count to exceed max_protected_range_count. |
| /// * ZX_ERR_INVALID_ARGS - unexpected heap, or range that doesn't conform |
| /// to protected_range_granularity. |
| /// * ZX_ERR_INTERNAL - generic internal error (such as in communication |
| /// with TEE which doesn't generate zx_status_t errors). |
| /// * other errors are possible, such as from communication failures or |
| /// server propagation of zx_status_t failures. |
| AddSecureHeapPhysicalRange(struct { |
| heap_range SecureHeapAndRange; |
| }) -> (struct {}) error zx.status; |
| |
| /// This request from sysmem to the securemem driver conveys a physical |
| /// range to delete, for a heap whose physical range(s) are set up via |
| /// sysmem. |
| /// |
| /// Only sysmem can call this because only sysmem is handed the client end |
| /// of a FIDL channel serving this protocol, via RegisterSecureMem(). The |
| /// securemem driver is the server end of this protocol. |
| /// |
| /// The securemem driver must configure all the covered offsets as not |
| /// protected before responding to this message with success. |
| /// |
| /// On failure, the securemem driver must ensure the protected range was not |
| /// deleted. |
| /// |
| /// Sysmem must not call this if dynamic_protection_ranges false. |
| /// |
| /// If dynamic_protection_ranges is true, sysmem can call this repeatedly, |
| /// on various ranges that exist at the time of the call. |
| /// |
| /// If any portion of the range being deleted is not also covered by another |
| /// protected range, then any ongoing DMA to any part of the entire range |
| /// may be interrupted / may fail, potentially in a way that's disruptive to |
| /// the entire system (bus lockup or similar, depending on device details). |
| /// Therefore, the caller must ensure that no ongoing DMA is occurring to |
| /// any portion of the range being deleted, unless the caller has other |
| /// active ranges covering every block of the range being deleted. Ongoing |
| /// DMA to/from blocks outside the range being deleted is never impacted by |
| /// the deletion. |
| /// |
| /// Errors: |
| /// * ZX_ERR_BAD_STATE - called when !dynamic_protection_ranges. |
| /// * ZX_ERR_INVALID_ARGS - unexpected heap, or range that doesn't conform |
| /// to protected_range_granularity. |
| /// * ZX_ERR_INTERNAL - generic internal error (such as in communication |
| /// with TEE which doesn't generate zx_status_t errors). |
| /// * ZX_ERR_NOT_FOUND - the specified range is not found. |
| /// * other errors are possible, such as from communication failures or |
| /// server propagation of zx_status_t failures. |
| DeleteSecureHeapPhysicalRange(struct { |
| heap_range SecureHeapAndRange; |
| }) -> (struct {}) error zx.status; |
| |
| /// This request from sysmem to the securemem driver conveys a physical |
| /// range to modify and its new base and length, for a heap whose physical |
| /// range(s) are set up via sysmem. |
| /// |
| /// Only sysmem can call this because only sysmem is handed the client end |
| /// of a FIDL channel serving this protocol, via RegisterSecureMem(). The |
| /// securemem driver is the server end of this protocol. |
| /// |
| /// The securemem driver must configure the range to cover only the new |
| /// offsets before responding to this message with success. |
| /// |
| /// On failure, the securemem driver must ensure the range was not changed. |
| /// |
| /// Sysmem must not call this if dynamic_protection_ranges false. Sysmem |
| /// must not call this if !is_mod_protected_range_available. |
| /// |
| /// If dynamic_protection_ranges is true, sysmem can call this repeatedly, |
| /// on various ranges that exist at the time of the call. |
| /// |
| /// The range must only be modified at one end or the other, but not both. |
| /// If the range is getting shorter, and the un-covered blocks are not |
| /// covered by other active ranges, any ongoing DMA to the entire range |
| /// that's geting shorter may fail in a way that disrupts the entire system |
| /// (bus lockup or similar), so the caller must ensure that no DMA is |
| /// ongoing to any portion of a range that is getting shorter, unless the |
| /// blocks being un-covered by the modification to this range are all |
| /// covered by other active ranges, in which case no disruption to ongoing |
| /// DMA will occur. |
| /// |
| /// If a range is modified to become <= zero length, the range is deleted. |
| /// |
| /// Errors: |
| /// * ZX_ERR_BAD_STATE - called when !dynamic_protection_ranges. |
| /// * ZX_ERR_INVALID_ARGS - unexpected heap, or old_range or new_range |
| /// that doesn't conform to protected_range_granularity, or old_range |
| /// and new_range differ in both begin and end (disallowed). |
| /// * ZX_ERR_INTERNAL - generic internal error (such as in communication |
| /// with TEE which doesn't generate zx_status_t errors). |
| /// * ZX_ERR_NOT_FOUND - the specified range is not found. |
| /// * other errors are possible, such as from communication failures or |
| /// server propagation of zx_status_t failures. |
| ModifySecureHeapPhysicalRange(struct { |
| range_modification SecureHeapAndRangeModification; |
| }) -> (struct {}) error zx.status; |
| |
| /// Zero a sub-range of a currently-existing physical range added via |
| /// AddSecureHeapPhysicalRange(). The sub-range must be fully covered by |
| /// exactly one physical range, and must not overlap with any other |
| /// physical range. |
| /// |
| /// is_covering_range_explicit - When true, the covering range must be one |
| /// of the ranges explicitly created via AddSecureHeapPhysicalRange(), |
| /// possibly modified since. When false, the covering range must not |
| /// be one of the ranges explicitly created via |
| /// AddSecureHeapPhysicalRange(), but the covering range must exist as |
| /// a covering range not created via AddSecureHeapPhysicalRange(). The |
| /// covering range is typically the entire physical range (or a range |
| /// which covers even more) of a heap configured by the TEE and whose |
| /// configuration is conveyed to sysmem via GetPhysicalSecureHeaps(). |
| /// |
| /// Ongoing DMA is not disrupted by this request. |
| ZeroSubRange(struct { |
| is_covering_range_explicit bool; |
| heap_range SecureHeapAndRange; |
| }) -> (struct {}) error zx.status; |
| }; |
| |
| type SecureHeapProperties = table { |
| /// The HeapType is repeated here for convenience. |
| 1: heap HeapType; |
| |
| /// If true, more than one call to SetPhysicalSecureHeap() for the same |
| /// heap is allowed. If false, only one SetPhyscialSecureHeap() call is |
| /// allowed, and no calls to DeleteSecureHeapPhysicalRange() or |
| /// ModifySecureHeapPhysicalRange() are allowed. Even when this is false, |
| /// the SecureMem server (driver) is still responsible for de-protecting |
| /// just before warm reboot if protected ranges would not otherwise be |
| /// cleaned up during a warm reboot. |
| 2: dynamic_protection_ranges bool; |
| |
| /// The granularity of protection ranges. If the granularity of start is |
| /// different than granularity of end or length, then this is the max |
| /// granularity value among those values. |
| /// |
| /// This must be a power of 2. The client must not request ranges that |
| /// specify smaller granularity. |
| /// |
| /// This must be at least zx_system_page_size() even if the HW can do |
| /// smaller granularity. |
| 3: protected_range_granularity uint32; |
| |
| /// The SecureMem server should not count reserved ranges that the SecureMem |
| /// server uses internally to get from range set A to range set B, if the |
| /// SecureMem server needs to do any emulation of that sort. Normally such |
| /// emulation by the SecureMem server is unnecessary. If any ranges are |
| /// reserved by the SecureMem server, those reserved ranges are not |
| /// available for use by the SecureMem client. |
| /// |
| /// If the number of ranges is limited only by available memory, it's ok for |
| /// the SecureMem server to report 0xFFFFFFFFFFFFFFFF for this value. The |
| /// field must still be set. As usual, the SecureMem server should ensure |
| /// that SetPhysicalSecureHeapRanges() succeeds or fails atomically (either |
| /// fully updates or rolls back before completing). |
| 4: max_protected_range_count uint64; |
| |
| /// Iff true, ModifySecureHeapPhysicalRange() is implemented. Calling |
| /// ModifySecureHeapPhysicalRange() when is_mod_protected_range_available |
| /// is false is prohibited. Don't attempt to detect availability of |
| /// ModifySecureHeapPhysicalRange() by calling it to see if it fails; it |
| /// may ZX_PANIC(). |
| 5: is_mod_protected_range_available bool; |
| }; |
| |
| const MAX_HEAPS_COUNT uint32 = 32; |
| const MAX_RANGES_COUNT uint32 = 128; |
| |
| type SecureHeapRange = table { |
| /// Must be aligned to at least heap_range_granularity. |
| 1: physical_address uint64; |
| |
| /// Must be aligned to at least heap_range_granularity. |
| 2: size_bytes uint64; |
| }; |
| |
| type SecureHeapAndRanges = table { |
| /// This is which secure/protected heap. |
| 1: heap HeapType; |
| |
| /// The list of physical ranges. This list must be sorted by |
| /// physical_address (lower first), and must not have any overlapping |
| /// ranges. Ranges that are directly adjacent are allowed (not |
| /// overlapping). |
| 2: ranges vector<SecureHeapRange>:MAX_RANGES_COUNT; |
| }; |
| |
| type SecureHeapsAndRanges = table { |
| 1: heaps vector<SecureHeapAndRanges>:MAX_HEAPS_COUNT; |
| }; |
| |
| type SecureHeapAndRange = table { |
| 1: heap HeapType; |
| 2: range SecureHeapRange; |
| }; |
| |
| type SecureHeapAndRangeModification = table { |
| 1: heap HeapType; |
| 2: old_range SecureHeapRange; |
| 3: new_range SecureHeapRange; |
| }; |