A Closer Look at the Simple XMPU_PL Example Application

Memory and Peripheral Protection Unit for PL Isolation in Zynq UltraScale+ Devices (XAPP1353)

Document ID
XAPP1353
Release Date
2022-05-04
Revision
1.1 English

In this example the PL addresses portion of the RPU fault injection test is combined with the initialization, configuration, and management of the XMPU_PL module examples that were previously implemented in the PMU. The zupl_xmpu software drivers can be found in the following program:

<workspace>/zcu102_isolation_test/psu_cortexr5_0/standalone_psu_cortexr5_0/bsp/psu_cortexr5_0/libsrc/zupl_xmpu_v1_0/
The source file pl_xmpu_example.c includes the declarations shown in the following figure.
  • SetupInterruptSystem installs the general interrupt controller (GIC) and enables exception handling for interrupts and synchronous data aborts.
  • SAbort_DataAbortHandler clears the ArmR5 aborts exception, returns the program pointer to the next instruction, and allows the application to continue operation.
  • The readReg and writeReg memory tests use the exception detection to determine PASS/FAIL and prints the result.
  • The XMpuPl_IntrHandler responds to interrupts triggered by the zupl_xmpu core’s irq signal. It stores the violation data and clears the interrupt status register.
  • The exceptionDetected flag is set by SAbort_DataAbortHandler and indicates that exception has occurred.
  • XMpuPl_IntrHandler stores the number of interrupt occurrences in xmpu_intr and the status of the most previous interrupt in xmpu_isr.
Figure 1. pl_xmpu_example declarations

The main (A) begins with instance declarations for the general interrupt controller and XMPU_PL, followed by the SetupInterruptSystem function call to set up the interrupt controller and exception handling.

Figure 2. pl_xmpu_example Main (A)

Although this example PL design only implements a single XMPU_PL, the demonstration code declares the XmpuPl instance as an array to support any number of instances, defined by XMPU_PL_NUM_INST in pl_xmpu_example.h:

#define XMPU_PL_NUM_INST	XPAR_ZUPL_XMPU_NUM_INSTANCES
Note: The zupl_xmpu SW driver supports a maximum of 16 zupl_xmpu instances. Each instance can support a maximum of 16 regions.

The ZUPL_XMPU parameters are defined in xparameters.h:

Figure 3. xparameters.h ZUPL_XMPU Parameters

Initialization of the XMPU_PL instance(s), shown in the following figure, is carried out in a FOR loop. Each instance number represents the Device ID.

Figure 4. pl_xmpu_example Main (B)

The interrupt ID for instance 0 is defined pl_xmpu_example.h

#define XMPU_PL_INTR_ID 	XPAR_FABRIC_ZUPL_XMPU_0_IRQ_INTR

For each instance, the interrupt ID is registered to the XMpuPl_IntrHandler function which is passed the starting address of the instance array as its parameter. Since the design only contains a single instance, only instance 0 is configured.

Figure 5. pl_xmpu_example Main (C)

The CTRL register is configured with default read allowed, default write allowed, poison attribute and poison address enabled, and poisoned AXI response DECERR, by XMPU_CTLR_VAL defined in the following pl_xmpu_example.h::

#define XMPU_CTRL_VAL		( XMPU_PL_CTRL_DEFRD 		\
					| XMPU_PL_CTRL_DEFWR 		\
					| XMPU_PL_CTRL_PSNATTREN 	\
					| XMPU_PL_CTRL_PSNADDREN	\
					| XMPU_PL_CTRL_ARSP_DEC)

The defined register offsets and configuration options are found in the zupl_xmpu SW driver file zupl_xmpu_hw.h. The LOCK BYPASS register configuration allows the PMU and RPU0 to have write access after the LOCK is enabled.

#define XMPU_LOCK_MASTERS	( XMPU_PL_MID_PMU | XMPU_PL_MID_RPU0 )

Read and write violations are enabled interrupts by XMPU_INT_EN.

#define XMPU_INT_EN		(XMPU_PL_IXR_WRVIO_MSK \
| XMPU_PL_IXR_RDVIO_MSK)

Region 0 is set to a 1 KB size starting at the base of the secure (S) BRAM area, and configured with the following parameters:

#define REGION_0_ADDR 		PL_BRAM_S_BASE
#define REGION_0_MASTERS	( XMPU_PL_MID_RPU0 )
#define REGION_0_CFG		( XMPU_PL_REGION_WR_ALLOW \
					| XMPU_PL_REGION_RD_ALLOW \
					| XMPU_PL_REGION_ENABLE )

Only RPU0 has read and write privileges.

Region 1 is also set to a 1 KB size starting at the base of the non-secure (NS) BRAM area, and configured with the following parameters:

#define REGION_1_ADDR 		PL_BRAM_NS_BASE
#define REGION_1_MASTERS	( XMPU_PL_MID_APU )
#define REGION_1_CFG		( XMPU_PL_REGION_WR_ALLOW \
					| XMPU_PL_REGION_RD_ALLOW \
					| XMPU_PL_REGION_ENABLE )

Only the APU has read and write privileges. PL_BRAM_NS_SHARED is set to an address between region 0 end and region 1 start. A region miss falls to the default settings specified in the CTRL registers that gives read and write access to all masters making the memory space shared.

The rest of main () runs the read/write tests and finally prints the number of interrupts recorded by the interrupt handler, XMpuPl_IntrHandler, shown in the following figure. In this example, one interrupt handler is shared by all instances. The interrupt status register of each instance is checked until an active violation is found. The interrupt status is stored, the number of interrupts is incremented, and then the interrupt status is cleared. If there is more than one instance issuing an interrupt, the handler gets recalled until all interrupts are cleared.

Figure 6. pl_xmpu_example XMpuPl_IntrHandler

This is an example of one way a designer chooses to configure and handle the zupl_xmpu_v1_0 core. Additionally, you can add multiple instances into the PL design and add their configurations to this application. This is left for you as an exercise.