EL1 Permission Fault Triggered by EL0 Memory Access Configuration
The issue revolves around a Memory Management Unit (MMU) configuration problem on the ARM Cortex-A53 processor, specifically when attempting to set up memory permissions that allow both Exception Level 1 (EL1) and Exception Level 0 (EL0) to access the same memory regions. The user has configured a two-level page table with 2MB blocks, mapping 2GB of memory with a 1:1 mapping. Initially, the Access Permission (AP) field in the block descriptors was set to 0, which restricts EL0 access. When the AP field was updated to allow EL0 access (AP[2:1] = 0b01), a synchronous permission fault occurred at EL1 immediately after setting the System Control Register (SCTLR). This fault indicates that the processor is unable to proceed due to a memory access violation, even though the configuration appears correct at first glance.
The fault is characterized by an Instruction Syndrome Register (ISS) encoding of 100001 and an Instruction Fault Status Code (IFSC) of 001110, which corresponds to a permission fault at the same exception level (EL1). The user speculated that the fault might be related to the Privileged Access Never (PAN) feature, which restricts privileged access to memory writable by EL0. However, the user confirmed that PAN is disabled (PSTATE.PAN = 0, SCTLR.SPAN = 0), and other relevant configuration registers such as SCTLR.WXN and the XN/PXN fields in the page descriptors are also cleared. This suggests that the issue lies elsewhere in the MMU configuration or the interaction between the AP field and other memory attributes.
AP Field and PXN Interaction in ARMv8 MMU Configuration
The root cause of the permission fault lies in the interaction between the Access Permission (AP) field and the Privileged Execute Never (PXN) field in the ARMv8 MMU architecture. According to the ARM Architecture Reference Manual, when the AP[2:1] bits are set to 0b01 (allowing write access from EL0), the PXN field is treated as if it has the value 1, regardless of its actual value. This means that any memory region configured with AP[2:1] = 0b01 is implicitly marked as non-executable at privileged levels (EL1 and higher), even if the PXN bit is explicitly cleared.
This behavior is a security feature designed to prevent privileged code from executing memory that can be modified by unprivileged code (EL0). In the user’s case, setting AP[2:1] to 0b01 for all page table entries caused the MMU to treat the entire memory region as non-executable at EL1, leading to the permission fault when the processor attempted to execute code from that region. This explains why the fault occurred immediately after enabling the MMU by setting the SCTLR register.
Additionally, the user’s configuration did not account for the hierarchical nature of the page tables. While the first 2MB block was correctly configured with AP[2:1] = 0b00 (restricting EL0 access), the remaining blocks were set to AP[2:1] = 0b01, which triggered the implicit PXN behavior. This oversight highlights the importance of carefully considering the interaction between different MMU attributes and their impact on memory access permissions across exception levels.
Resolving EL1 Permission Faults with Proper AP and PXN Configuration
To resolve the permission fault, the MMU configuration must be updated to ensure that memory regions accessible by EL0 are not implicitly marked as non-executable at EL1. This can be achieved by carefully setting the AP and PXN fields in the page table entries, taking into account the interaction between these fields and the security constraints of the ARMv8 architecture.
First, memory regions that need to be executable at EL1 should be configured with AP[2:1] = 0b00, which restricts write access from EL0 and avoids the implicit PXN behavior. This ensures that privileged code can execute from these regions without triggering a permission fault. For example, the kernel and hardware abstraction layer (HAL) code should be placed in memory regions with AP[2:1] = 0b00 to prevent EL0 from modifying or executing these critical sections.
Second, memory regions that need to be writable by EL0 but executable at EL1 should be split into separate pages with different permissions. For instance, data sections that require EL0 write access can be configured with AP[2:1] = 0b01, while code sections that need to be executable at EL1 should be placed in separate pages with AP[2:1] = 0b00. This approach ensures that the implicit PXN behavior does not interfere with privileged code execution.
Third, the page table hierarchy should be carefully designed to avoid unintended permission inheritance. For example, if a higher-level page table entry sets AP[2:1] = 0b01, all lower-level entries will inherit this setting unless explicitly overridden. To prevent this, higher-level entries should be configured with restrictive permissions (AP[2:1] = 0b00), and lower-level entries should be used to grant specific permissions as needed.
Finally, the MMU configuration should be validated using a debugger to ensure that the expected permissions are applied correctly. This includes checking the values of the AP, PXN, and XN fields in the page table entries, as well as verifying that the SCTLR and PSTATE registers are configured as intended. By following these steps, the permission fault can be resolved, and the MMU can be configured to support the desired memory access permissions for both EL0 and EL1.
Example MMU Configuration Table
Memory Region | AP[2:1] | PXN | XN | Description |
---|---|---|---|---|
0x00000000 – 0x001FFFFF | 0b00 | 0 | 0 | Kernel and HAL code (executable at EL1) |
0x00200000 – 0x003FFFFF | 0b01 | 1 | 0 | Data section (writable by EL0, non-executable at EL1) |
0x00400000 – 0x005FFFFF | 0b00 | 0 | 0 | Privileged code (executable at EL1) |
0x00600000 – 0x007FFFFF | 0b01 | 1 | 0 | Shared data (writable by EL0, non-executable at EL1) |
This table illustrates a sample MMU configuration that avoids the permission fault by separating memory regions with different access requirements. The kernel and privileged code are placed in regions with AP[2:1] = 0b00, ensuring that they remain executable at EL1. Data sections that need to be writable by EL0 are configured with AP[2:1] = 0b01 and PXN = 1, preventing privileged execution while allowing EL0 access. By carefully designing the page tables and validating the configuration, the MMU can be configured to support the desired memory access permissions without triggering permission faults.