PSoC 6 Peripheral Driver Library
Prot (Protection Unit)

General Description

The Protection Unit driver provides an API to configure the Memory Protection Units (MPU), Shared Memory Protection Units (SMPU), and Peripheral Protection Units (PPU).

These are separate from the ARM Core MPUs and provide additional mechanisms for securing resource accesses. The Protection units address the following concerns in an embedded design:

The functions and other declarations used in this driver are in cy_prot.h. You can include cy_pdl.h to get access to all functions and declarations in the PDL.

Protection Types

Protection units are hardware configuration structures that control bus accesses to the resources that they protect. By combining these individual configuration structures, a system is built to allow strict restrictions on the capabilities of individual bus masters (e.g. CM0+, CM4, Crypt) and their operating modes. This architecture can then be integrated into the overall security system of the end application. To build this system, 3 main protection unit types are available; MPU, SMPU and PPU. When a resource is accessed (memory/register), it must pass the evaluation performed for each category. These access evaluations are prioritized, where MPU has the highest priority, followed by SMPU, followed by PPU. i.e. if an SMPU and a PPU protect the same resource and if access is denied by the SMPU, then the PPU access evaluation is skipped. This can lead to a denial-of-service scenario and the application should pay special attention in taking ownership of the protection unit configurations.

Memory Protection

Memory access control for a bus master is controlled using an MPU. These are most often used to distinguish user and privileged accesses from a single bus master such as task switching in an OS/kernel. For ARM cores (CM0+, CM4), the core MPUs are used to perform this task. For other non-ARM bus masters such as Crypto, MPU structs are available, which can be used in a similar manner as the ARM core MPUs. These MPUs however must be configured by the ARM cores. Other bus masters that do not have an MPU, such as DMA (DW), inherit the access control attributes of the bus master that configured the channel. Also note that unlike other protection units, MPUs do not support protection context evaluation. MPU structs have a descending priority, where larger index struct has higher priority access evaluation over lower index structs. E.g. MPU_STRUCT15 has higher priority than MPU_STRUCT14 and its access will be evaluated before MPU_STRUCT14. If both target the same memory, then the higher index (MPU_STRUCT15) will be used, and the lower index (MPU_STRUCT14) will be ignored.

Shared Memory Protection

In order to protect a region of memory from all bus masters, an SMPU is used. This protection effectively allows only those with correct bus master access settings to read/write/execute the memory region. This type of protection is used in general memory such as Flash and SRAM. Peripheral registers are best configured using the peripheral protection units instead. SMPU structs have a descending priority, where larger index struct has higher priority access evaluation over lower index structs. E.g. SMPU_STRUCT15 has higher priority than SMPU_STRUCT14 and its access will be evaluated before SMPU_STRUCT14. If both target the same memory, then the higher index (MPU_STRUCT15) will be used, and the lower index (SMPU_STRUCT14) will be ignored.

Peripheral Protection

Peripheral protection is provided by PPUs and allow control of peripheral register accesses by bus masters. Four types of PPUs are available.

Protection Context

Protection context (PC) attribute is present in all bus masters and is evaluated when accessing memory protected by an SMPU or a PPU. There are no limitations to how the PC values are allocated to the bus masters and this makes it possible for multiple bus masters to essentially share protection context values. The exception to this rule is the PC value 0.

PC=0

Protection context 0 is a hardware controlled protection context update mechanism that allows only a single entry point for transitioning into PC=0 value. This mechanism is only present for the secure CM0+ core and is a fundamental feature in defining a security solution. While all bus masters are configured to PC=0 at device boot, it is up to the security solution to transition these bus masters to PC!=0 values. Once this is done, those bus masters can no longer revert back to PC=0 and can no longer access resources protected at PC=0.

In order to enter PC=0, the CM0+ core must assign an interrupt vector or an exception handler address to the CPUSS.CM0_PC0_HANDLER register. This allows the hardware to check whether the executing code address matches the value in this register. If they match, the current PC value is saved and the CM0+ bus master automatically transitions to PC=0. It is then up to the executing code to decide if and when it will revert to a PC!=0 value. At that point, the only way to re-transition to PC=0 is through the defined exception/interrupt handler.

Note
Devices with CPUSS ver_2 have a hardware-controlled protection context update mechanism that allows only a single-entry point for transitioning into PC=0, 1, 2, and 3. The interrupt vector or the exception handler address can be assigned to the CPUSS.CM0_PC0_HANDLER, CPUSS.CM0_PC1_HANDLER, CPUSS.CM0_PC2_HANDLER or CPUSS.CM0_PC2_HANDLER register. Also, the control register CPUSS.CM0_PC_CTL of the CM0+ protection context must be set: bit 0 - the valid field for CM0_PC0_HANDLER, bit 1 - the valid field for CM0_PC1_HANDLER, bit 2 - the valid field for CM0_PC2_HANDLER, and bit 3 - the valid field for CM0_PC3_HANDLER.

The example of using of the single entry point mechanism is shown below.

/* The code below demonstrates the protection context update
* mechanism that allows a single entry point for transitioning
* from PC = 1 into PC=0 value.
*/
/* Note: "cy_ipc_drv.h", "cy_prot.h" and "cy_sysint.h" should be included. */
#define IPC_INTR_NR 10u
uint32_t pc; /* The active protection context of a master. */
bool isrTriggered = false; /* The ISR flag. */
/* IPC ISR handler. */
void isrPC0(void)
{
/* The protection context is 0 here. */
isrTriggered = true; /* Set flag that ISR is triggered. */
}
int main(void)
{
__enable_irq(); /* Enable global interrupts. */
#if (CY_CPU_CORTEX_M0P)
/* Enable CM4. CY_CORTEX_M4_APPL_ADDR must be updated if CM4 memory layout is changed. */
#endif
/* Assign the isrPC0 interrupt vector to the CM0_PC0_HANDLER register. */
CPUSS->CM0_PC0_HANDLER = (uint32_t)&isrPC0;
/* Configure the IPC interrupt handler. */
cy_stc_sysint_t intr = {
#if (CY_CPU_CORTEX_M0P)
.intrSrc = NvicMux5_IRQn,
.cm0pSrc = cpuss_interrupts_ipc_10_IRQn,
#else
.intrSrc = cpuss_interrupts_ipc_10_IRQn,
#endif /* (CY_CPU_CORTEX_M0P) */
.intrPriority = 2u
};
Cy_SysInt_Init(&intr, isrPC0);
NVIC_EnableIRQ(intr.intrSrc);
/* Configure the bus master to allow setting PC to PC=1 and PC=2 */
Cy_Prot_ConfigBusMaster(CPUSS_MS_ID_CM0, true, true, CY_PROT_PCMASK1 | CY_PROT_PCMASK2);
/* Set the CM0+ PC value to 1 */
{
/* Insert error handling */
}
pc = Cy_Prot_GetActivePC(CPUSS_MS_ID_CM0); /* pc should equal to 1 */
Cy_IPC_Drv_SetInterrupt(Cy_IPC_Drv_GetIntrBaseAddr(IPC_INTR_NR), 0u, 1u); /* Trigger the ISR */
while(!isrTriggered)
{
/* Wait until isrPC0 ISR entered. */
}
pc = Cy_Prot_GetActivePC(CPUSS_MS_ID_CM0); /* pc should equal to 0 */
for(;;)
{
}
}

Access Evaluation

Each protection unit is capable of evaluating several access types. These can be used to build a system of logical evaluations for different kinds of bus master modes of operations. These access types can be divided into three broad access categories.

Protection Structure

Each protection unit is comprised of a master struct and a slave struct pair. The exception to this rule is MPU structs, which only have the slave struct equivalent. The protection units apply their access evaluations in a decreasing index order. For example, if SMPU1 and SMPU2 both protect a specific memory region, the the higher index (SMPU2) will be evaluated first. In a secure system, the higher index protection structs would then provide the high level of security and the lower indexes would provide the lower level of security. Refer to the Protection Types section for more information.

Slave Struct

The slave struct is used to configure the protection settings for the resource of interest (memory/registers). Depending on the type of protection unit, the available attributes differ. However all Slave protection units have the following general format.

Slave Struct Address Definition

Slave Struct Attribute Definition

Master Struct

The master struct protects its slave struct in the protection unit. This architecture makes possible for the slave configuration to be protected from reconfiguration by an unauthorized bus master. The configuration attributes and the format are similar to that of the slave structs.

Master Struct Address Definition

Master Struct Attribute Definition

Driver Usage

Setting up and using protection units can be summed up in four stages:

For example, by configuring the CM0+ bus master configuration to allow only protection contexts 2 and 3, the bus master will be able to set its protection context only to 2 or 3. During runtime, the CM0+ core can set its protection context to 2 by calling Cy_Prot_SetActivePC() and access all regions of protected memory that allow PC=2. A fault will be triggered if a resource is protected with different protection settings.

Note that each protection unit is distinguished by its type (e.g. PROT_MPU_MPU_STRUCT_Type). The list of supported protection units can be obtained from the device definition header file. Choose a protection unit of interest, and call its corresponding Cy_Prot_Config<X>Struct() function with its software protection unit configuration structure populated. Then enable the protection unit by calling the Cy_Prot_Enable<X>Struct() function.

Note that the bus master ID (en_prot_master_t) is defined in the device config header file.

Configuration Considerations

When a resource (memory/register) is accessed, it must pass evaluation of all three protection unit categories in the following order: MPU->SMPU->PPU. The application should ensure that a denial-of-service attack cannot be made on the PPU by the SMPU. For this reason, it is recommended that the application's security policy limit the ability for the non-secure client from configuring the SMPUs.

Within each category, the priority hierarchy must be carefully considered to ensure that a higher priority protection unit cannot be configured to override the security configuration of a lower index protection unit. Therefore if a lower index protection unit is configured, relevant higher priority indexes should be configured (or protected from unwanted reconfiguration). E.g. If a PPU_SL is configured, PPU_RG and PPU_GR that overlaps with the protected registers should also be configured. SImilar to SMPUs, it is recommended that the configuration of PPU_PROG be limited. Otherwise they can be used to override the protection settings of PPU_RG and PPU_SL structs.

All bus masters are set to PC=0 value at device reset and therefore have full access to all resources. It is up to the security solution to implement what privileges each bus master has. Once transitioned to a PC!=0 value, only the CM0+ core is capable of re-entering the PC=0 via the user-defined exception entry in the CPUSS.CM0_PC0_HANDLER register.

More Information

Refer to Technical Reference Manual (TRM) and the device datasheet.

MISRA-C Compliance

The Prot driver has the following specific deviations:

MISRA Rule Rule Class (Required/Advisory) Rule Description Description of Deviation(s)
11.4 A A cast should not be performed between a pointer to object type and a different pointer to object type. This piece of code is written for DW_V2_Type only and it will be never executed for DW_V1_Type (which is a default build option for DW_Type).
19.13 A The # and ## operators should not be used. The ## preprocessor operator is used in macros to form the field mask.

Changelog

VersionChangesReason for Change
1.40 Added PSoC 64 devices support.
1.30.3 Minor documentation updates. Documentation enhancement.
1.30.2 Clarified the description of the next API functions: Cy_Prot_ConfigPpuProgMasterAtt,
Cy_Prot_ConfigPpuProgSlaveAtt, Cy_Prot_ConfigPpuFixedMasterAtt, Cy_Prot_ConfigPpuFixedSlaveAtt.
API enhancement based on usability feedback.
1.30.1 Snippet updated. Old snippet outdated.
1.30 Defect in Cy_Prot_GetPpuProgStruct() function due to faulty defines is fixed. Defect fixing.
1.20 Flattened the organization of the driver source code into the single source directory and the single include directory. Driver library directory-structure simplification.
Added functions for CPUSS ver_2: Added support for CPUSS ver_2.
Added register access layer. Use register access macros instead of direct register access using dereferenced pointers. Makes register access device-independent, so that the PDL does not need to be recompiled for each supported part number.
1.10 Added input parameter validation to the API functions.
cy_en_prot_pcmask_t, cy_en_prot_subreg_t and cy_en_prot_pc_t types are set to typedef enum
Improved debugging capability
Expanded documentation
1.0 Initial version

API Reference

 Macros
 
 Functions
 
 Data Structures
 
 Enumerated Types