Versal Secure Register Access with IOCTL - 2023.2 English

Versal Adaptive SoC System Software Developers Guide (UG1304)

Document ID
Release Date
2023.2 English

For most secure usecases, enforces XPPU and XMPU protection scheme allows only a set of "firmware masters" to access system resources directly. Protections are enforced in the hardware by configuring the XPPUs/XMPUs appropriately. If a non-firmware master requires an access to such protected address space, then it should request PLM to perform the access on behalf of it. A direct access from any non-firmware master to this protected address space will be blocked by hardware. Such non-firmware masters can use EEMI IOCTL APIs (IOCTL_READ_REG and IOCTL_MASK_WRITE_REG) to perform desired accesses which ensures that only firmware is directly accessing these resources and access is kept "secure". To use this feature, define an access policy for one or more apertures per resource through SET_NODE_ACCESS command in the PMC data CDO.

To read the secure/protected registers via IOCTL (for example, SYSMON registers), set the Node Access, add this as part of PMC CDO:

This command allows you to define address apertures accessible using EEMI IOCTL command. This unit describes one or more apertures associated with a node and defines different “access permissions” for each such aperture. This information is used by the firmware to build a "Node Access Table" which is used to evaluate client read/write access requests. A "Node Access Table" will contain several entries, where each entry will contain:

  • Node ID
  • Base Address
  • Total Size
  • List of:
    • <offset1, size1, access-permission1>,
    • <offset2, size2, access-permission2>,
Table 1. Node Access
Command: Set Node Access
Reserved[31:24] Length[23:16] XILPM = 2 CMD_PM_SET_NODE_ACCESS
NodeID 1
size1[31:24]2 reserved[23:20] offset1[19:0]
reserved[31:4] access1[3:0]
size2[31:24] 2 reserved[23:20] offset2[19:0]
reserved[31:4] access2[3:0]
  1. RNodeID can be of two types:
    • Device ID: These are PLM aware devices and have unique node IDs defined in the xpm_nodeid.h file.
    • RegNode ID: These are non-PLM aware nodes and node IDs must be created for these. Each SET_NODE_ACCESS is accompanied by a PM_ADD_NODE command for adding the given RegNode to the PM database.
  2. Size is 1-based and not 0-based, which means that the minimum size is 1).
    • Offset[19:0] defines the permitted aperture's start address as offset from the base address of the node
    • Size[31:24] (in 32-bit words - MAX 255 words) defines the size of the permitted aperture (chunk of address space starting from offset)
    • Access[0:3] defines the access permission for primary SLRs issuing the IOCTL command
      • 0 - reserved
      • 1 - all read only
      • 2 - all read and write
      • 3 - secure read only
      • 4 - secure read and write
      • 5 - subsystem read only (S or NS)
      • 6 - subsystem read/write (S or NS)
      • 7 - subsystem read only (S only)
      • 8 - subsystem read/write (S only)
      Note: If access is set to 5, 6, 7 or 8, the node must be assigned to a subsystem using the PM_ADD_REQ command. Only having a requirement for the call subsystem is enough and there is no need for device policy checking. This means that even though the add requirement is used, the XPPU / FPD_XMPU setting only allows access by firmware.

0x18224055 is the NodeID of PMC_SYSMON resource (taken from xpm_nodeid.h in PLM sources).

# Add default subsystem
# subsystem_default
pm_add_subsystem 0x1c000000
# Define node access permissions for PMC SYSMON Block Chunks
# Allow Sysmon access for any sec/non-secure masters for following ranges:
# 0xf1270000 - 0xf12703fb (0xff: 255 32-bit words)
# 0xf12703fc - 0xf12707f7 (0xff: 255 32-bit words)
# 0xf12707f8 - 0xf1270bf3 (0xff: 255 32-bit words)
# 0xf1270bf4 - 0xf1270fef (0xff: 255 32-bit words)
# 0xf1270ff0 - 0xf12713eb (0xff: 255 32-bit words)
# 0xf12713ec - 0xf12717e7 (0xff: 255 32-bit words)
# 0xf12717e8 - 0xf1271be3 (0xff: 255 32-bit words)
# 0xf1271be4 - 0xf1271fdf (0xff: 255 32-bit words)
# 0xf1271fe0 - 0xf12723db (0xff: 255 32-bit words)
# 0xf12723dc - 0xf12727d7 (0xff: 255 32-bit words)
# 0xf12727d8 - 0xf1272bd3 (0xff: 255 32-bit words)
# 0xf1272bd4 - 0xf1272fcf (0xff: 255 32-bit words)
# 0xf1272fd0 - 0xf12733cb (0xff: 255 32-bit words)
# 0xf12733cc - 0xf12737c7 (0xff: 255 32-bit words)
# 0xf12737c8 - 0xf1273bc3 (0xff: 255 32-bit words)
# 0xf1273bc4 - 0xf1273fbf (0xff: 255 32-bit words)
# 0xf1273fc0 - 0xf1274003 (0x11: 17 32-bit words)
pm_set_node_access 0x18224055 0xff000000 0x2 0xff0003fc 0x2 0xff0007f8 0x2 0xff000bf4 0x2 0xff000ff0 0x2 0xff0013ec 0x2 0xff0017e8 0x2 0xff001be4 0x2 0xff001fe0 0x2 0xff0023dc 0x2 0xff0027d8 0x2 0xff002bd4 0x2 0xff002fd0 0x2 0xff0033cc 0x2 0xff0037c8 0x2 0xff003bc4 0x2 0x11003fc0 0x2

An example to read SYSMON registers from Linux OS:

root@xilinx-vc-p-a2197-00-reva-x-prc-01-reva-2021_2:~$ echo pm_ioctl 0x18224055 0x1c 0x0 > /sys/kernel/debug/zynqmp-firmware/pm
root@xilinx-vc-p-a2197-00-reva-x-prc-01-reva-2021_2:~$ cat /sys/kernel/debug/zynqmp-firmware/pm
root@xilinx-vc-p-a2197-00-reva-x-prc-01-reva-2021_2:~$ echo pm_ioctl 0x18224055 0x1c 0x4 > /sys/kernel/debug/zynqmp-firmware/pm
root@xilinx-vc-p-a2197-00-reva-x-prc-01-reva-2021_2:~$ cat /sys/kernel/debug/zynqmp-firmware/pm
root@xilinx-vc-p-a2197-00-reva-x-prc-01-reva-2021_2:~$ echo pm_ioctl 0x18224055 0x1c 0x1fc > /sys/kernel/debug/zynqmp-firmware/pm
root@xilinx-vc-p-a2197-00-reva-x-prc-01-reva-2021_2:~$ cat /sys/kernel/debug/zynqmp-firmware/pm