diff options
Diffstat (limited to 'src/cmse.rs')
-rw-r--r-- | src/cmse.rs | 238 |
1 files changed, 0 insertions, 238 deletions
diff --git a/src/cmse.rs b/src/cmse.rs deleted file mode 100644 index 7826bb8..0000000 --- a/src/cmse.rs +++ /dev/null @@ -1,238 +0,0 @@ -//! Cortex-M Security Extensions -//! -//! This module provides several helper functions to support Armv8-M and Armv8.1-M Security -//! Extensions. -//! Most of this implementation is directly inspired by the "Armv8-M Security Extensions: -//! Requirements on Development Tools" document available here: -//! https://developer.arm.com/docs/ecm0359818/latest -//! -//! Please note that the TT instructions support as described part 4 of the document linked above is -//! not part of CMSE but is still present in this module. The TT instructions return the -//! configuration of the Memory Protection Unit at an address. -//! -//! # Notes -//! -//! * Non-Secure Unprivileged code will always read zeroes from TestTarget and should not use it. -//! * Non-Secure Privileged code can check current (AccessType::Current) and Non-Secure Unprivileged -//! accesses (AccessType::Unprivileged). -//! * Secure Unprivileged code can check Non-Secure Unprivileged accesses (AccessType::NonSecure). -//! * Secure Privileged code can check all access types. -//! -//! # Example -//! -//! ``` -//! use cortex_m::cmse::{TestTarget, AccessType}; -//! -//! // suspect_address was given by Non-Secure to a Secure function to write at it. -//! // But is it allowed to? -//! let suspect_address_test = TestTarget::check(0xDEADBEEF as *mut u32, -//! AccessType::NonSecureUnprivileged); -//! if suspect_address_test.ns_read_and_writable() { -//! // Non-Secure can not read or write this address! -//! } -//! ``` - -use crate::asm::{tt, tta, ttat, ttt}; -use bitfield::bitfield; - -/// Memory access behaviour: determine which privilege execution mode is used and which Memory -/// Protection Unit (MPU) is used. -#[derive(PartialEq, Copy, Clone, Debug)] -pub enum AccessType { - /// Access using current privilege level and reading from current security state MPU. - /// Uses the TT instruction. - Current, - /// Unprivileged access reading from current security state MPU. Uses the TTT instruction. - Unprivileged, - /// Access using current privilege level reading from Non-Secure MPU. Uses the TTA instruction. - /// Undefined if used from Non-Secure state. - NonSecure, - /// Unprivilege access reading from Non-Secure MPU. Uses the TTAT instruction. - /// Undefined if used from Non-Secure state. - NonSecureUnprivileged, -} - -/// Abstraction of TT instructions and helper functions to determine the security and privilege -/// attribute of a target address, accessed in different ways. -#[derive(PartialEq, Copy, Clone, Debug)] -pub struct TestTarget { - tt_resp: TtResp, - access_type: AccessType, -} - -bitfield! { - /// Test Target Response Payload - /// - /// Provides the response payload from a TT, TTA, TTT or TTAT instruction. - #[derive(PartialEq, Copy, Clone)] - struct TtResp(u32); - impl Debug; - mregion, _: 7, 0; - sregion, _: 15, 8; - mrvalid, _: 16; - srvalid, _: 17; - r, _: 18; - rw, _: 19; - nsr, _: 20; - nsrw, _: 21; - s, _: 22; - irvalid, _: 23; - iregion, _: 31, 24; -} - -impl TestTarget { - /// Creates a Test Target Response Payload by testing addr using access_type. - #[inline] - pub fn check(addr: *mut u32, access_type: AccessType) -> Self { - let tt_resp = match access_type { - AccessType::Current => TtResp(tt(addr)), - AccessType::Unprivileged => TtResp(ttt(addr)), - AccessType::NonSecure => TtResp(tta(addr)), - AccessType::NonSecureUnprivileged => TtResp(ttat(addr)), - }; - - TestTarget { - tt_resp, - access_type, - } - } - - /// Creates a Test Target Response Payload by testing the zone from addr to addr + size - 1 - /// using access_type. - /// Returns None if: - /// * the address zone overlaps SAU, IDAU or MPU region boundaries - /// * size is 0 - /// * addr + size - 1 overflows - #[inline] - pub fn check_range(addr: *mut u32, size: usize, access_type: AccessType) -> Option<Self> { - let begin: usize = addr as usize; - // Last address of the range (addr + size - 1). This also checks if size is 0. - let end: usize = begin.checked_add(size.checked_sub(1)?)?; - - // Regions are aligned at 32-byte boundaries. If the address range fits in one 32-byte - // address line, a single TT instruction suffices. This is the case when the following - // constraint holds. - let single_check: bool = (begin % 32).checked_add(size)? <= 32usize; - - let test_start = TestTarget::check(addr, access_type); - - if single_check { - Some(test_start) - } else { - let test_end = TestTarget::check(end as *mut u32, access_type); - // Check that the range does not cross SAU, IDAU or MPU region boundaries. - if test_start != test_end { - None - } else { - Some(test_start) - } - } - } - - /// Access type that was used for this test target. - #[inline] - pub fn access_type(self) -> AccessType { - self.access_type - } - - /// Get the raw u32 value returned by the TT instruction used. - #[inline] - pub fn as_u32(self) -> u32 { - self.tt_resp.0 - } - - /// Read accessibility of the target address. Only returns the MPU settings without checking - /// the Security state of the target. - /// For Unprivileged and NonSecureUnprivileged access types, returns the permissions for - /// unprivileged access, regardless of whether the current mode is privileged or unprivileged. - /// Returns false if the TT instruction was executed from an unprivileged mode - /// and the NonSecure access type was not specified. - /// Returns false if the address matches multiple MPU regions. - #[inline] - pub fn readable(self) -> bool { - self.tt_resp.r() - } - - /// Read and write accessibility of the target address. Only returns the MPU settings without - /// checking the Security state of the target. - /// For Unprivileged and NonSecureUnprivileged access types, returns the permissions for - /// unprivileged access, regardless of whether the current mode is privileged or unprivileged. - /// Returns false if the TT instruction was executed from an unprivileged mode - /// and the NonSecure access type was not specified. - /// Returns false if the address matches multiple MPU regions. - #[inline] - pub fn read_and_writable(self) -> bool { - self.tt_resp.rw() - } - - /// Indicate the MPU region number containing the target address. - /// Returns None if the value is not valid: - /// * the MPU is not implemented or MPU_CTRL.ENABLE is set to zero - /// * the register argument specified by the MREGION field does not match any enabled MPU regions - /// * the address matched multiple MPU regions - /// * the address specified by the SREGION field is exempt from the secure memory attribution - /// * the TT instruction was executed from an unprivileged mode and the A flag was not specified. - #[inline] - pub fn mpu_region(self) -> Option<u8> { - if self.tt_resp.mrvalid() { - // Cast is safe as MREGION field is defined on 8 bits. - Some(self.tt_resp.mregion() as u8) - } else { - None - } - } - - /// Indicates the Security attribute of the target address. Independent of AccessType. - /// Always zero when the test target is done in the Non-Secure state. - #[inline] - pub fn secure(self) -> bool { - self.tt_resp.s() - } - - /// Non-Secure Read accessibility of the target address. - /// Same as readable() && !secure() - #[inline] - pub fn ns_readable(self) -> bool { - self.tt_resp.nsr() - } - - /// Non-Secure Read and Write accessibility of the target address. - /// Same as read_and_writable() && !secure() - #[inline] - pub fn ns_read_and_writable(self) -> bool { - self.tt_resp.nsrw() - } - - /// Indicate the IDAU region number containing the target address. Independent of AccessType. - /// Returns None if the value is not valid: - /// * the IDAU cannot provide a region number - /// * the address is exempt from security attribution - /// * the test target is done from Non-Secure state - #[inline] - pub fn idau_region(self) -> Option<u8> { - if self.tt_resp.irvalid() { - // Cast is safe as IREGION field is defined on 8 bits. - Some(self.tt_resp.iregion() as u8) - } else { - None - } - } - - /// Indicate the SAU region number containing the target address. Independent of AccessType. - /// Returns None if the value is not valid: - /// * SAU_CTRL.ENABLE is set to zero - /// * the register argument specified in the SREGION field does not match any enabled SAU regions - /// * the address specified matches multiple enabled SAU regions - /// * the address specified by the SREGION field is exempt from the secure memory attribution - /// * the TT instruction was executed from the Non-secure state or the Security Extension is not - /// implemented - #[inline] - pub fn sau_region(self) -> Option<u8> { - if self.tt_resp.srvalid() { - // Cast is safe as SREGION field is defined on 8 bits. - Some(self.tt_resp.sregion() as u8) - } else { - None - } - } -} |