APB Series — APB-07: Protection — PPROT and RME — VLSI Trainers
APB Series · APB-07

Protection — PPROT and RME

How PPROT[2:0] encodes privilege, security, and access type, the Realm Management Extension (PNSE) that adds Root and Realm address spaces, compatibility rules, and practical gating patterns for secure peripheral registers.

📋 Why APB Needs Protection

Modern SoCs support multiple security domains running simultaneously — a secure OS, a non-secure OS, hypervisor, and (with Arm CCA) Root and Realm worlds. Peripheral registers must be partitioned across these domains: a cryptographic key register must only be accessible from the secure world, a non-secure OS must not be able to read it even accidentally.

Without protection signals, any software running on the CPU could issue AXI/AHB transactions that propagate through the APB bridge and reach any peripheral register. PPROT (APB4) and PNSE (APB5/RME) carry the security context of the initiating transaction all the way to the peripheral, allowing register-level access control.

The protection information originates from the CPU or system bus and flows through the chain:

CPU / Initiator AxPROT[2:0] AXI / AHB Bus AxPROT propagated APB Bridge maps to PPROT[2:0] APB Peripheral checks PPROT, gates access …more
Figure 1 — Protection context flows from the CPU through AXI/AHB to the APB bridge, which maps AxPROT to PPROT and drives it alongside every APB transfer. The peripheral uses PPROT to gate access to its registers.

The AXI protection signal AxPROT[2:0] has the same bit definitions as PPROT[2:0]. The APB bridge passes it through directly — bit[0] to bit[0], bit[1] to bit[1], bit[2] to bit[2]. There is no translation needed.

📋 PPROT[2:0] — Three Independent Bits

PPROT is a 3-bit signal where each bit encodes a completely independent protection attribute. The bits are not a 3-bit encoded value — they are three separate one-bit flags. A peripheral can check any combination of bits independently.

PPROT[0]
Privilege level
0Normal (unprivileged) access
1Privileged access
PPROT[1]
Security level
0Secure access
1Non-secure access
PPROT[2]
Access type
0Data access
1Instruction access

The spec notes that PPROT[2] (data vs instruction) is provided as a hint and may not be accurate in all cases — some CPU implementations do not distinguish instruction fetches from data accesses at the bus level. Peripherals should not rely on PPROT[2] for security decisions; use only PPROT[0] and PPROT[1] for access gating.

The primary and most important use of PPROT is PPROT[1] for secure/non-secure gating. A secure peripheral rejects transfers with PPROT[1]=1 (non-secure) by asserting PSLVERR or simply ignoring the write.

PPROT[1]=0 means Secure. PPROT[1]=1 means Non-secure. This is the opposite of what many engineers expect intuitively. “Secure” is the lower value. Memorise it: LOW = Secure, HIGH = Non-secure.

📋 Encoding Table and Common Values

The full 8-value encoding space of PPROT[2:0] with the most common values highlighted:

PPROT[2:0]PPROT[2]PPROT[1]PPROT[0]Access descriptionTypical source
3'b000DataSecureNormalSecure normal data access — most common for secure driver register writesSecure OS driver, TF-A
3'b001DataSecurePrivilegedSecure privileged data access — kernel-mode secure driverSecure kernel
3'b010DataNon-secureNormalNon-secure normal data access — user-space driverLinux user-space
3'b011DataNon-securePrivilegedNon-secure privileged data access — most common for non-secure driver register writesLinux kernel driver
3'b100InstructionSecureNormalSecure normal instruction fetch (hint only)Rare — peripheral fetch
3'b101InstructionSecurePrivilegedSecure privileged instruction fetchRare
3'b110InstructionNon-secureNormalNon-secure normal instruction fetchRare
3'b111InstructionNon-securePrivilegedNon-secure privileged instruction fetchRare
In practice, only two values dominate: 3'b000 (secure privileged kernel → often promoted to privileged = 3'b001) and 3'b011 (non-secure privileged kernel). Most APB peripherals only need to check PPROT[1] — secure vs non-secure — and can ignore bits 0 and 2 entirely.

PPROT in Timing Diagrams

PPROT is presented at the start of the Setup phase alongside PADDR and must remain stable through all wait states until transfer completion — identical stability requirement to PADDR.

T0 T1 T2 T3 T4 SETUP ACCESS PCLK PADDR PSELx PENABLE PPROT PREADY Addr 1 3’b011 (NS Priv Data)
Figure 2 — PPROT in a write transfer. PPROT=3’b011 (non-secure privileged data access, typical for a Linux kernel driver) is presented at T1 alongside PADDR and remains stable until T3 (transfer completion). PPROT has the same stability requirement as PADDR.

📋 PPROT Compatibility Rules

PPROT is optional on both Requester and Completer. The spec defines the compatibility for all four combinations:

Completer: PPROT absentCompleter: PPROT present
Requester: PPROT absent Compatible. Neither side has protection. All accesses are treated as having the default PPROT=3’b000 (secure, normal, data). Not compatible in general. The Completer expects protection attributes but none are provided. Exception: if fixed protection attributes are functionally correct for the design (e.g. the peripheral only ever needs to see secure access and the Requester is always secure), you can tie PPROT to a constant value and document it. Check Table 3-2 of the spec for the exact encoding to tie.
Requester: PPROT present Compatible. Requester drives PPROT but Completer has no access protection — PPROT signals are unconnected. The Completer accepts all transactions regardless of protection level. Compatible. Both sides have PPROT. Full protection gating works. Normal connection.
The tricky case: Completer has PPROT inputs but Requester doesn’t. You cannot simply tie PPROT to zero — zero means “secure, normal, data” which may not be the correct fixed attribute. Determine what the correct default is for your specific peripheral (is it always accessed from secure world? always non-secure?) and tie accordingly. Document the tie value in your design spec.

📋 Realm Management Extension — PNSE

The Arm Realm Management Extension (RME), introduced in the Armv9 architecture, adds two new physical address spaces — Root and Realm — alongside the existing Secure and Non-secure spaces. APB5 Issue E (2023) added PNSE (Peripheral Non-Secure Extension, also written as the NS Extension bit) to carry this additional context.

PNSE is a single additional bit that works alongside PPROT[1] to encode all four physical address spaces:

PNSE + PPROT[1] — Four Physical Address Spaces PNSE = 0 (no RME extension) PNSE = 1 (RME extension) PPROT[1] = 0 PPROT[1] = 1 Secure PNSE=0, PPROT[1]=0 Non-secure PNSE=0, PPROT[1]=1 Root PNSE=1, PPROT[1]=0 Realm PNSE=1, PPROT[1]=1
Figure 3 — PNSE extends PPROT[1] to create four physical address spaces. Without RME (PNSE absent or=0) only Secure and Non-secure exist. With RME (PNSE=1) Root and Realm spaces are added.

Key properties of PNSE:

📋 Four Physical Address Spaces

With RME, the SoC has four address spaces each with different trust levels. Peripheral access control must account for all four:

Secure
PNSE=0, PPROT[1]=0
Secure world software (TF-A, secure OS, OP-TEE). Highest trust in the pre-CCA security model. Secure peripherals are only accessible from this space.
Non-secure
PNSE=0, PPROT[1]=1
Normal world software (Linux, Android). No access to Secure peripherals. Most APB peripherals are Non-secure accessible.
Root
PNSE=1, PPROT[1]=0
Arm CCA Root world — the most privileged world, above Secure. Used by the Root monitor (e.g. TF-A EL3 with RME). Can access all other spaces.
Realm
PNSE=1, PPROT[1]=1
Arm CCA Realm world — hardware-isolated execution environment for confidential computing workloads. Separate from both Secure and Non-secure.
RME is an APB5 feature for Armv9/CCA platforms. If your design predates Armv9 or does not implement Arm CCA, you will never encounter PNSE. The most common design today still only uses PPROT[1] (Secure/Non-secure) from APB4. Only understand RME if you are working on Armv9-A platforms with Realm support.

📋 RME Compatibility

Completer: RME_Support=FalseCompleter: RME_Support=True
Requester: RME_Support=False Compatible. Neither side has PNSE. Standard PPROT[1]-based Secure/Non-secure model. Compatible. Completer has PNSE input but Requester doesn’t drive it. Tie PNSE LOW at the Completer input. PNSE=0 with PPROT[1]=0/1 gives Secure/Non-secure — the standard pre-RME behaviour.
Requester: RME_Support=True Not compatible. Requester may drive PNSE=1 (Root or Realm accesses) but Completer has no way to distinguish these from Secure/Non-secure. Cannot safely connect without access control violation risk. Compatible. Both sides support RME. Full four-space access control available.

📋 Implementation Patterns

Secure peripheral — reject non-secure access

A peripheral that should only be accessible from the secure world:

assign ns_access_violation = PSELx & PPROT[1];
assign PSLVERR = PSELx & PENABLE & PREADY & PPROT[1];
assign write_enable = PSELx & PENABLE & PREADY & PWRITE & ~PPROT[1];

When PPROT[1]=1 (non-secure), the peripheral asserts PSLVERR at completion and does not update any registers. The transfer completes as a protocol transaction but returns an error to the system bus (which returns SLVERR to the CPU).

Privileged-only peripheral — reject user-space access

assign write_enable = PSELx & PENABLE & PREADY & PWRITE & PPROT[0];
assign PSLVERR = PSELx & PENABLE & PREADY & ~PPROT[0];

Mixed secure/non-secure register file

Many peripherals have both secure and non-secure registers. A common pattern is address-based partitioning: the lower address range is non-secure accessible (status registers, debug counters), the upper range is secure-only (key registers, configuration):

wire secure_region = (PADDR[11:8] == 4'hF);
wire access_ok = ~secure_region | ~PPROT[1];
assign PSLVERR = PSELx & PENABLE & PREADY & ~access_ok;

PPROT from an AXI bridge

The AXI AxPROT signal has the same bit encoding as PPROT. An AXI-to-APB bridge simply passes ARPROT or AWPROT through to PPROT unchanged. On AXI, ARPROT is used for read transactions and AWPROT for write transactions — the bridge selects the appropriate one based on the transfer type and drives the single PPROT bus on APB.

📋 Quick Reference

ItemRule
PPROT introduced inAPB4 — not available in APB2 or APB3
Width3 bits — three independent one-bit flags
PPROT[0]0=Normal, 1=Privileged
PPROT[1]0=Secure, 1=Non-secure (LOW=Secure — counterintuitive!)
PPROT[2]0=Data, 1=Instruction (hint only — may not be accurate)
Most common value3’b011 (Non-secure Privileged Data) — Linux kernel driver
Most important bitPPROT[1] — secure vs non-secure gating
AXI mappingAxPROT[2:0] → PPROT[2:0] direct 1:1 (same encoding)
StabilityValid when PSELx asserted, stable until transfer completes — same as PADDR
Req absent, Comp presentTie PPROT to correct fixed value. Not generally compatible without analysis.
Req present, Comp absentCompatible — Completer has no access control, ignores PPROT
PNSE introduced inAPB5 Issue E (2023), RME_Support property
PNSE=0, PPROT[1]=0Secure
PNSE=0, PPROT[1]=1Non-secure
PNSE=1, PPROT[1]=0Root (Arm CCA)
PNSE=1, PPROT[1]=1Realm (Arm CCA)
Req has RME, Comp doesn’tNot compatible — tie PNSE LOW only when Requester never drives PNSE=1
Req no RME, Comp has RMECompatible — tie PNSE input LOW at Completer
PSLVERR on protection violationRecommended — assert PSLVERR when PPROT[1] violates the peripheral’s access policy
Scroll to Top