Skip to content
Commit 6642c58e authored by Marek Bykowski's avatar Marek Bykowski Committed by Tom Rini
Browse files

armv8: MMU: Mark code memory Executable, any other Non-Executable



If the location the ARM CPU is accessing is executable (translation
table descriptor Execute-Never attribute bit cleared) then the ARM CPU
fetches a number of instructions from that location all at the same time.
For example, Cortex-A57 can source up to 128 bits per fetch depending on
alignment.

If the CPU mispredicts to the Execute-Never region, it creates the
memory fault but it actually never uses the instructions mispredicted.
The CPU branches away elsewhere. So, as long as we program the MMU
correctly these mispredictions will only affect the performance.

However if we fail programming so and the instruction fetch logic goes
mispredict to non-instruction memory it may eventually perturb it, eg.
corrupt the FIFO, or the control registers, load the unified cache
the data side memory system hits into subsequently.

U-Boot adheres into attributing the device regions to Execute-Never but
it actually fails doing so for data regions. Data as well as Device Regions
should be Execute-Never.

This patch enables attributing data memory regions to Non-Executable,
and code region to Executable, additionally to Read-Only. Read-Only ensures
the code region is only Readable resulting in Instruction Abort, Permission
Fault exception on a write.

To use the updated attributes the DDR memory of interest should be
Non-Executable, it is by default Read-Write Access Permission as well
with an example as follows:

static struct mm_region axxia_mem_map[] = {
  {
     .virt = 0x0UL, /* DDR */
     .phys = 0x0UL,
     .size = 0x400000000ULL,
     .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
              PTE_BLOCK_INNER_SHARE |
              PTE_BLOCK_PXN | PTE_BLOCK_UXN
  }, {
     .virt = AXXIA_CCN_512_BASE,
     .phys = AXXIA_CCN_512_BASE,
     .size = AXXIA_CCN_512_SIZE,
     .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
              PTE_BLOCK_NON_SHARE |
              PTE_BLOCK_PXN | PTE_BLOCK_UXN
  }, {
     .virt = AXI_MMAP_BASE,
     .phys = AXI_MMAP_BASE,
     .size = AXI_MMAP_SIZE,
     .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
              PTE_BLOCK_NON_SHARE |
              PTE_BLOCK_PXN | PTE_BLOCK_UXN
  }, {
     .virt = AXI_PERIPH_BASE,
     .phys = AXI_PERIPH_BASE,
     .size = AXI_PERIPH_SIZE,
     .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
              PTE_BLOCK_NON_SHARE |
              PTE_BLOCK_PXN | PTE_BLOCK_UXN
  }, {
     /* List terminator */
     0,
  }
};

add_text_map() routine in cache_v8.c locates then the code region in it and
modifies its attributes to Executable, Read-Only. The HW Debugger views
the Memory Map set then as:

EL2N:0x00000000-0x3FD35FFF NP:0x00000000-0x3FD35FFF Normal RW C S XN
EL2N:0x3FD36000-0x3FD86FFF NP:0x3FD36000-0x3FD86FFF Normal RO C S
EL2N:0x3FD87000-0x3FFFFFFFF NP:0x3FD87000-0x3FFFFFFFF Normal RW C S XN
EL2N:0x400000000-0x3FFFFFFFFF <unmapped>
EL2N:0x4000000000-0x403FFFFFFF NP:0x4000000000-0x403FFFFFFF Device-nGnRnE RW NC XN
EL2N:0x4040000000-0x7FFFFFFFFF <unmapped>
EL2N:0x8000000000-0x803FFFFFFF NP:0x8000000000-0x803FFFFFFF Device-nGnRnE RW NC XN
EL2N:0x8040000000-0x807FFFFFFF <unmapped>
EL2N:0x8080000000-0x80BFFFFFFF NP:0x8080000000-0x80BFFFFFFF Device-nGnRnE RW NC XN
EL2N:0x80C0000000-0xFFFFFFFFFF <unmapped>

where:
C, NC is Cacheable, Non-Cacheable respectively,
S, NS - Shareable and Non-Shareable,
XN - Execute-Never, if XN isn't present it is Executable.

Shareability of the Device is always treated as Outer Shareable,
regardless of the attributes, therefore the Shareability for the Device
Regions is not mentioned here.

Signed-off-by: default avatarMarek Bykowski <marek.bykowski@gmail.com>
parent 1c4b5038
Loading
Loading
Loading
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment