AnsweredAssumed Answered

RT685 B0 MPU - Memory Alignment

Question asked by Raymond Yip on Feb 18, 2020
Latest reply on Feb 28, 2020 by Greg Steiert



I am trying to use the MPU to detect stack overflow.  The basic idea is to create two SRAM entries in the MPU: (1) from start of SRAM to base of stack minus N bytes and (2) from base of stack to the end of SRAM.  I would over allocate the stack so that the N bytes below the base of the stack would be unused normally and I can safely leave this as a hole in the memory map when programming the MPU.  If any write into this area occurs the I expect to see a mem fault.  


Looking at the CM33 MPU_RBAR register, it looks like the lower 5 bits of the memory addresses are "don't cares" (they are masked out and are used as control bits.)  This implies the MPU is able to control access to memory in increments of 32-bytes.  In order to satisfy this requirement, I have ensured (a) the base of my stack is 32-byte aligned and (b) the N byte hole in the memory map is 32 bytes.  


This doesn't seem to work for me.  If I loop through the 32-byte region (the N bytes below the base of the stack) and write each byte one by one, I am able to write the entire 32-byte region without tripping a mem fault.  I tried to increase the alignment to 64-bytes (stack base is 64-byte aligned, N byte hole is set to 64 bytes) and I see a difference in behavior.  If I started at the base of the stack and wrote byte by byte towards low memory, I get a mem fault as soon as I write the first byte below the stack base.  If I started at the low memory (i.e. first byte of the 64 byte memory hole) and worked my way up in the same fashion, I do not get a mem fault until I am exactly 32 bytes into the N byte region (and write to a 32-byte aligned address.)  What might be happening here?  I should be running without the cache at this point (CACHE64->CCR is zero).  



MPU set up in C main():



    ARM_MPU_SetMemAttr(0, ARM_MPU_ATTR(ARM_MPU_ATTR_MEMORY_(1, 0, 1, 0), ARM_MPU_ATTR_MEMORY_(1, 0, 1, 0) ) );
    ARM_MPU_SetMemAttr(1, ARM_MPU_ATTR(ARM_MPU_ATTR_MEMORY_(1, 0, 1, 0), ARM_MPU_ATTR_MEMORY_(1, 0, 1, 0) ) );
    ARM_MPU_SetMemAttr(2,                 ARM_MPU_ATTR(ARM_MPU_ATTR_DEVICE_nGnRnE, ARM_MPU_ATTR_DEVICE_nGnRnE ) );
    ARM_MPU_SetMemAttr(3,                 ARM_MPU_ATTR(ARM_MPU_ATTR_DEVICE_nGnRnE, ARM_MPU_ATTR_DEVICE_nGnRnE ) );

    ARM_MPU_SetRegion(MPU_REGION_INDEX_SRAM,         ARM_MPU_RBAR(0x00000000, ARM_MPU_SH_INNER, 0, 1, 0), ARM_MPU_RLAR(0x00001000, 0) );
    ARM_MPU_SetRegion(MPU_REGION_INDEX_FLASH_MEMORY, ARM_MPU_RBAR(0x08000000, ARM_MPU_SH_NON,   1, 1, 0), ARM_MPU_RLAR(0x08200000, 1) );
    ARM_MPU_SetRegion(MPU_REGION_INDEX_PERIPHERAL,   ARM_MPU_RBAR(0x40000000, ARM_MPU_SH_OUTER, 0, 1, 1), ARM_MPU_RLAR(0x60000000, 2) );
    ARM_MPU_SetRegion(MPU_REGION_INDEX_PERIPHERAL2,  ARM_MPU_RBAR(0xE0000000, ARM_MPU_SH_OUTER, 0, 1, 1), ARM_MPU_RLAR(0xE0100000, 3) );
    ARM_MPU_SetRegion(MPU_REGION_INDEX_SRAM2,         ARM_MPU_RBAR(0x00001040, ARM_MPU_SH_OUTER, 0, 1, 0), ARM_MPU_RLAR(0x00480000, 0) );
This code should leave a 64 byte region undefined between 0x00001000 (exclusive) and 0x00001040 (inclusive).  As explained above, writing one byte at a time from 0x00001040 to 0x00001000 causes a mem fault at address 0x0000103F.  However, when going from 0x00001000 to 0x00001040, I do not get a mem fault until I write to address 0x00001020.  
Trying this more broadly on the stacks of multiple tasks, I am unable to consistently trigger a mem fault unless I corrupt 64 bytes below the base of the stack.