This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TDA3XEVM: XMC access violation status

Part Number: TDA3XEVM

Hi TI!

I need some clarification to understand XMC behavior.
I'm trying to trigger an XMC read violation on a fixed, non cached buffer as a supervisor. The read violation will be triggered by reading the n:th element in the buffer.
 * The first strange behavior I see is. On first element read the exception will not be triggered but it will be triggered on the second element read.
 * The second strange behavior is. The "DSPXMCGetFaultStatus" will return only zeros so will "DSPXMCGetFaultAddr".

There seems also to be a mistake in the function "DSPXMCGetFaultStatus" where user read and write status are swapped.

I'm using PDK delivered in processor SDK vision 03_07_00_00.

Regards,
Enver

  • Enver Sultanov said:
     * The first strange behavior I see is. On first element read the exception will not be triggered but it will be triggered on the second element read.
     

    How are you testing this?  Are you using debugger to step through, or are you reading first, writing some print, then reading the second?  If you never read the second, are you confirming that it never triggers an exception?  I am just wondering if there is a timing dependency.

    Enver Sultanov said:
     * The second strange behavior is. The "DSPXMCGetFaultStatus" will return only zeros so will "DSPXMCGetFaultAddr".

    What is the baseaddress you are passing to these functions?

    Enver Sultanov said:
    There seems also to be a mistake in the function "DSPXMCGetFaultStatus" where user read and write status are swapped.

    I see what you are referring to.  Thanks for letting us know.  I will file a bug to have this looked into.  In the mean time, I assume you can make the fix locally.

    Regards,

    Jesse

  • I'm using CCS and the debugger to set a break point just before the read and stepping over first read instruction. The code looks basically like this:

    HW_RD_REG32(reinterpret_cast<uint32_t>(&dummyBuff[n]));
    n++;
    HW_RD_REG32(reinterpret_cast<uint32_t>(&dummyBuff[n]));

    But it looks like that issue is not present anymore. So the XMC interrupt will trigger on the first read. I'm not sure why.

    The base address is SOC_DSP_XMC_CTRL_BASE which is define to 0x8000000U in file pdk_01_10_03_07/packages/ti/csl/soc/tda3xx/c66x/soc.h .

    I forgot to mention that I get valid fault status and address values when a write access violation is triggered.
    Here is a printout of the XMC status and fault adress on write access violation:

    [t=0x0007d65e] xdc.runtime.Main: Invalid memory access event (110)
    [t=0x00083de2] xdc.runtime.Main: protected memory: 0x8dfc0000
    [t=0x00088a68] xdc.runtime.Main: UX:0 UW:1 UR:0
    [t=0x0008c8f0] xdc.runtime.Main: SX:0 SW:1 SR:0
    [t=0x000906d7] xdc.runtime.Main: local access: 1
    [t=0x000943ed] xdc.runtime.Main: fID: 0

    In this case all access right are set to 0 for both user and supervisor.

    Could you also explain why both user and supervisor read violation status is set even when the DSP CPU is set to supervisor mode.

    Regards,
    Enver

  • Hi Enver

    I am trying to summarize the issue you are seeing. Please confirm if this is indeed the case:

    1. Invalid read is generating an interrupt (earlier it was not on the first attempt, but now it is generating)

    2. Invalid read is not updating the fault address or status. Is that right?

    3. Invalid write is generating the interrupt and correct fault address but is setting the fault in User and Supervisor. 

    Just as a reference would be good if you have had a look at pdk_\packages\ti\csl\example\xmc_mpu\xmc_mpu_test_app\xmc_mpu_app.c example.

    Thanks and Regards

    Piyali

  • Hi Piyali!

    Yes, you summarized it correct!

    I have been mimicking that example but the function DSPXMCGetFaultStatus is not utilized in there.

    Regards,

    Enver

  • Hi Piyali!

    Any progress on this issue?

    Regards,
    Enver

  • Please refer to the below appnote for detail on XMC.


  • Does this mean that you could not find any issue with XMC functionality on your end?
    Do you think that the error I'm observing is probably due to faulty usage of XMC functionality?

    Regards,
    Enver

  • XMC works properly if it is configured and used properly.

    Using debugger with XMC protection requires special care.

    Again, please refer to the application note for details.

  • Hi Stanley Liu!

    Bellow follows code spinets where we configure the XMC module:

    se_bool setMemoryAccess(const se_uintptr_t inMemAddr,
                            const MemProtSize inLength,
                            const u32 inProtectionSlot,
                            const se_bool inAllowRead,
                            const se_bool inAllowWrite,
                            const se_bool inAllowExecute)
    {
      const u32 intSave = _disable_interrupts();
      const u32 cpuMode = DSP_getCpuMode();
      if (DSP_CPU_MODE_USR == cpuMode)
      {
        DSP_setCpuMode(DSP_CPU_MODE_SPV);
      }
    
      const s32 wbInvStatus =
          DSPICFGCacheWriteBackInvalidateAll(SOC_DSP_ICFG_BASE, static_cast<u32>(DSPICFG_MEM_L2));
    
      if (wbInvStatus != STW_SOK)
      {
        DSP_setCpuMode(cpuMode);
        _restore_interrupts(intSave);
        return false;
      }
    
      _mfence();
    // Using Prefetch function will triger XMC interrupt imidiatly pointing to DSPXMCInvalidatePrefetch.
    //  DSPXMCInvalidatePrefetch(SOC_DSP_XMC_CTRL_BASE);
    
      const u32 readPerms = inAllowRead ? XMPAXL_SR_MASK : 0U;
      const u32 writePerms = inAllowWrite ? XMPAXL_SW_MASK : 0U;
      const u32 executePerms = inAllowExecute ? XMPAXL_SX_MASK : 0U;
    
      const u32 perms = readPerms | writePerms | executePerms;
      const s32 memProtStatus =
          DSPXMCSetMPAXSegment(SOC_DSP_XMC_CTRL_BASE,
                               inProtectionSlot,
                               static_cast<u32>(memProtSizeToVendorSize(inLength)),
                               static_cast<u32>(inMemAddr),
                               static_cast<u32>(inMemAddr),
                               0U,
                               perms);
      DSP_setCpuMode(cpuMode);
      _restore_interrupts(intSave);
      return STW_SOK == memProtStatus;
    }

    It is wort mentioning that we use the exception module to catch INTH_INT_ID_MDMAERR interrupt and get the status information in a custom exception hook.

    Please take a look and and advise if any obvious configuration mistakes are made.

    Regards,
    Enver

  • Enver,

    Please also provide the permission setting for each entries.

    Regards,

    Stanley

  • Hi Stanley!

    I have been using segment 2 and setting all permissions to false both for supervisor and user in order to test the XMC functionality.

    #pragma DATA_ALIGN(256)
    #pragma DATA_SECTION(".dummySection")
    se::u8 dummyBuff[0x40000]; // 256 KB

    addMemProt(reinterpret_cast<se_uintptr_t>(&dummyBuff[0]),
    memprot::MEMPROT_SIZE_256KB,
    2,
    false,
    false,
    false);

    Regards,
    Enver

  • dummyBuff address alignment could be the problem.

    It should be at least aligned on both cache line boundary AND segment size.

    If you are not sure, just align the buffer address at 16MB address boundary in your test.

  • Hi Stanley!

    I changed my code in order to align dummyBuff to 128 which seems to be the L2 cache line size 
    found in file dsp_icfg.h, #define DSPICFG_L2_CACHE_LINE_SIZE    (128U). 

    Could you elaborate why 16MB address boundary?

    Regards,
    Enver

  • Cache line size is not good enough. Please set the alignment to at least 4KB since the minimal segment size for permission is 4KB.

    The reason I said 16MB is because cache/pre-fetch property setting in each MARx register is for every 16MB region.

  • I changed the memory chunk size to 4KB, aligned dummyBuff to 4KB and set the segment size to DSPXMC_SEGSZ_4KB.
    The behavior is the same.

    The alignment was done according the code bellow:

    #pragma DATA_ALIGN((4 * 1024))
    #pragma DATA_SECTION(".dummySection")
    se::u8 dummyBuff[0x1000]; // 4 KB

    Regards,
    Enver

  • Please verify if the registers are programmed correctly first. 

    You can refer to the application note I mentioned before for details.

    Please also describe the sequence and behavior you are seeing.

  • I'm not sure if this is needed since we do catch the memory violation. The issue is that the status information for the caught memory violation is empty or faulty depending on read or write violation.

    For sequence and behavior please see the previous posts. Let me know which sequence and behavior you need more information on.

    Regards,
    Enver

  • Do you see any issue if you run PDK mpu example as is? Did it work as expected?

  • I guess you refer to the example that Piyali suggested? pdk_\packages\ti\csl\example\xmc_mpu\xmc_mpu_test_app\xmc_mpu_app.c
    In that case no, I have not tried it. I have been mimicking that example but the function DSPXMCGetFaultStatus is not utilized in there.

    Regards,
    Enver

  • Hi Enver,

    I am sorry to overlook the bit field defined in DSPXMCGetFaultStatus().

    You are correct that there is a mistake in the implementation that user read and user write bit field are reversed indeed.

    Regards,
    Stanley

  • Regarding the question you had with the below XMC status...

    =========================

    Here is a printout of the XMC status and fault adress on write access violation:

    [t=0x0007d65e] xdc.runtime.Main: Invalid memory access event (110)
    [t=0x00083de2] xdc.runtime.Main: protected memory: 0x8dfc0000
    [t=0x00088a68] xdc.runtime.Main: UX:0 UW:1 UR:0
    [t=0x0008c8f0] xdc.runtime.Main: SX:0 SW:1 SR:0
    [t=0x000906d7] xdc.runtime.Main: local access: 1
    [t=0x000943ed] xdc.runtime.Main: fID: 0

    =========================

    It is explained in the application note I shared before in chapter 4.4.3. When you step thru the code in CCS or set breakpoint, it will trigger error like you see above because debugger is writing to memory to set breakpoint.

    4.4.3 False XMC Memory Protection Error From Debugger Access

    Debugger access is allowed regardless XMC permission setting in XMPAXL.PERM field. Debugger Write
    updates the value in External Memory as well as Cache if enabled.
    If Debugger writes to the memory location, which is also cached, the cache line will be marked dirty.
    Performing Cache WB will forward the WB request to XMC. If both Supervisor and User mode Write
    permission is disabled, XMC will record the Cache Writeback error in XMPFAR (Fault Address) and
    XMPFSR with a specific value (=0x112).
    The examples of Debugger usage that can result in XMC errors are shown as the followings:
    Software Breakpoint (SWBP) set in Program memory without Supervisor or User Write permission
    (R/X only).
    • CIO (Printf) function resides in Program memory without Supervisor or User Write permission (R/X
    only).
    • Modify value in Code Composer Studio™ (CCS) Memory window at the memory segment without
    Supervisor or User Write permission (R/X only).

    Do you have any other question regarding XMC?

    Regards,
    Stanley

  • Thanks for the answer Stanley!
    As a workaround I followed chapter "4.4.4 Workaround for Debugger Access From SWBPs", removed all prints and the values are not modified from Memory window.
    Here is the result on write violation:

      Invalid memory access event (110)
      protected memory: 0x8dfc0000
      UX:0 UW:1 UR:0
      SX:0 SW:1 SR:0
      local access: 1
      fID: 256. Only valid if localAccess set to zero

    And the result on read violation:

      Invalid memory access event (110)
      protected memory: 0x0
      UX:0 UW:0 UR:0
      SX:0 SW:0 SR:0
      local access: 0
      fID: 0. Only valid if localAccess set to zero

    Any thoughts?

    //Enver  


  • Hi Enver,

    For a valid Write violation, it would be Either a Supervisor OR User Write access violation. It will never be both.

    If both Supervisor AND User Write access violations are set, it means the error is triggered by Debugger.

    As mentioned in the application note, Setting BREAKPOINT and RUNNING/STOPPING code in debugger can trigger this kind of error if WRITE permission is disabled in program memory.

    In addition, it is better to close all memory windows in CCS since memory window can trigger read access in the background.

    For the read violation result, I don't think there is any violation captured by error status registers since the register values are all zeros.

    Did you clear the status from previous error every time? How did you determine there is violation error?

    Maybe you can run the mpu example as-is to understand how to generate and process the error correctly first.

    The C66x CorePac also provides good information about XMC in chapter 7.

    http://www.ti.com/lit/ug/sprugw0c/sprugw0c.pdf

    Regards,
    Stanley

  • During the previous test all CCS memory windows where closed.


    How is it possible that there is no read violation captured since the exception is triggered on INTH_INT_ID_MDMAERR interrupt?

    The status from previous error is cleared in a init function before memory protection setup bu calling: 
        DSPXMCClearFaultRegs(SOC_DSP_XMC_CTRL_BASE)
        DSPICFGClearMdmaErrEvt(SOC_DSP_ICFG_BASE)
    Do determine that there is a violation error I have connected INTH_INT_ID_MDMAERR to the exception module (Exception_evtExpMaskEnable(INTH_INT_ID_MDMAERR);). The status information will be extracted in a custom exception hook.

    Alright, I will try do run and recreate the error in the MPU example.

    Regards,
    Enver

  • Hi Stanley,

    I just finished modifying xmc_mpu_app.c where the goal was to simplify it in order to test only user read and write XMC violations.
    When running the code attached bellow the user read violations are not triggered. Here is the complete output from the run:

      Invalid memory access event (110)
      protected memory: 0x80030140
      UX:0 UW:1 UR:0
      SX:0 SW:0 SR:0
      local access: 1
      fID: 256. Only valid if localAccess set to zero

     

    /*
     *  Copyright (C) 2015 Texas Instruments Incorporated
     *
     *  Redistribution and use in source and binary forms, with or without
     *  modification, are permitted provided that the following conditions
     *  are met:
     *
     *    Redistributions of source code must retain the above copyright
     *    notice, this list of conditions and the following disclaimer.
     *
     *    Redistributions in binary form must reproduce the above copyright
     *    notice, this list of conditions and the following disclaimer in the
     *    documentation and/or other materials provided with the
     *    distribution.
     *
     *    Neither the name of Texas Instruments Incorporated nor the names of
     *    its contributors may be used to endorse or promote products derived
     *    from this software without specific prior written permission.
     *
     *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     *
     */
    /**
     *  \file     xmc_mpu_app.c
     *
     *  \brief    This file contains example usage for Extended Memory Controller
     *            (XMC) and Memory Protection Unit (MPU) in C66x device on TDA2x
     *            and TDA3x platform
     *
     *  \details  This will demonstrate implementation of access restrictions
     *            to different memory regions from C66x DSP.
     */
    
    /* ========================================================================== */
    /*                             Include Files                                  */
    /* ========================================================================== */
    
    #include <stdint.h>
    #include <string.h>
    #include <stdio.h>
    #include <ti/csl/csl_types.h>
    #include <ti/csl/soc.h>
    #include <c6x.h>
    #include <ti/csl/hw_types.h>
    #include <ti/csl/csl_edma.h>
    #include <ti/csl/arch/csl_arch.h>
    #include <ti/csl/example/utils/uart_console/inc/uartConfig.h>
    
    /* ========================================================================== */
    /*                                Macros                                      */
    /* ========================================================================== */
    
    #define XMC_TEST_START   (0x80030000U)
    #define XMC_TEST_END     (0x80040000U)
    
    #define DSPXMC_SPV_RWX (DSPXMC_ALLOW_SR | \
                            DSPXMC_ALLOW_SW | \
                            DSPXMC_ALLOW_SX)
    
    #define DSPXMC_USR_WO_PRV_RW (DSPXMC_ALLOW_SR | \
                                  DSPXMC_ALLOW_SW | \
                                  DSPXMC_ALLOW_SX | \
                                  DSPXMC_ALLOW_UW | \
                                  DSPXMC_ALLOW_UX)
    
    #define DSPXMC_USR_RO_PRV_RW (DSPXMC_ALLOW_SR | \
                                  DSPXMC_ALLOW_SW | \
                                  DSPXMC_ALLOW_SX | \
                                  DSPXMC_ALLOW_UR | \
                                  DSPXMC_ALLOW_UX)
    
    #define DSPXMC_USR_RW_PRV_RW (DSPXMC_USR_RO_PRV_RW | DSPXMC_ALLOW_UW)
    
    #define DSPICFG_USR_RW_PRV_RW (DSPICFG_USR_RO_PRV_RW | DSPICFG_L2MPPA_UW)
    
    /* Keys to lock/unlock MPU and XMC registers
     * Default state is unlocked. Locking is optional.
     * Keys can be changed by user.
     */
    #define MPLK_KEY0   0xABCD1234U
    #define MPLK_KEY1   0x1234ABCDU
    #define MPLK_KEY2   0xA1B2C3D4U
    #define MPLK_KEY3   0x4D3C2B1AU
    
    typedef void (*OsalIntrFuncPtr)(uint32_t arg0);
    
    /* ========================================================================== */
    /*                            Global Variables                                */
    /* ========================================================================== */
    #define MEM_CHK_BUF_SZ 0x40U
    #ifdef __cplusplus
    #pragma DATA_ALIGN(32)
    #pragma DATA_SECTION(".scratch_section");
    #else
    #pragma DATA_ALIGN(scratchBuffer, 32)
    #pragma DATA_SECTION(scratchBuffer,".scratch_section");
    #endif
    volatile uint32_t scratchBuffer[MEM_CHK_BUF_SZ >> 2U];
    #ifdef __cplusplus
    #pragma DATA_ALIGN(32)
    #pragma DATA_SECTION(".scratch_section");
    #else
    #pragma DATA_ALIGN(randomNums, 32)
    #pragma DATA_SECTION(randomNums,".scratch_section");
    #endif
    volatile uint32_t randomNums[MEM_CHK_BUF_SZ >> 2U] =
    {
        0xAAAAAAAAU,
        0x55555555U,
        0xBBBBBBBBU,
        0xCCCCCCCCU,
        0x80808080U,
        0xA0A0A0A0U,
        0x50505050U,
        0x12345678U,
        0x22222222U,
        0xDDDDDDDDU,
        0x11111111U,
        0xEEEEEEEEU,
        0x00000000U,
        0x33331111U,
        0x99997777U,
        0x05050505U
    };
    int32_t           gTestStatus = STW_SOK;
    
    uint32_t          gIntrToHandle[] =
    {
        INTH_INT_ID_MDMAERR
    };
    
    #if defined (SOC_TDA2XX) || defined (SOC_TDA2PX) || defined (SOC_TDA2EX) || defined (SOC_DRA72x) || defined (SOC_DRA75x)
    uint32_t uartBaseAddr = SOC_UART1_BASE;
    #endif
    #if defined (SOC_TDA3XX) || defined (SOC_DRA78x)
    uint32_t uartBaseAddr = SOC_UART3_BASE;
    #endif
    
    /* ========================================================================== */
    /*                 Internal Function Declarations                             */
    /* ========================================================================== */
    
    /**
     * \brief   Initialize memory region specified by startAddr and endAddr
     *
     */
    void initMem(uint32_t startAddr, uint32_t endAddr);
    
    /**
     * \brief   Initialize memory regions under test
     *
     */
    static void initAllMemory();
    
    /**
     * \brief   Sets up different regions in XMC with different access permissions
     *
     */
    static void setupXMC();
    
    /**
     * \brief   Validate CPU Read Access
     *
     * \param   startAddr       Start Address of region to check
     * \param   endAddr         End Address of region to check
     *
     * \return  errorOccured    1 if failure to read, 0 otherwise
     */
    uint32_t validateCpuReadAccess(uint32_t startAddr, uint32_t endAddr);
    
    
    /**
     * \brief   Validate CPU Write Access
     *
     * \param   startAddr       Start Address of region to check
     * \param   endAddr         End Address of region to check
     *
     * \return  errorOccured    1 if failure to read, 0 otherwise
     */
    uint32_t validateCpuWriteAccess(uint32_t startAddr, uint32_t endAddr);
    
    /**
     * \brief   Common implementation to check access permissions with specified
     *          CPU mode
     *
     * \param   none
     *
     * \return  errorOccured    >0 if unexpected failure to read/write, 0 otherwise
     */
    uint32_t validateAccessPermissions(uint32_t cpuMode);
    
    void getFaultStatus(void)
    {
        DSPICFGCacheWriteBackInvalidateAll(SOC_DSP_ICFG_BASE, DSPICFG_MEM_L2);
        // Get information on the invalid memory access.
        dspxmcFaultStatus_t faultStatus;
        const int faultStat = DSPXMCGetFaultStatus(SOC_DSP_XMC_CTRL_BASE, &faultStatus);
        
        if (STW_SOK == faultStat)
        {
          const uint32_t swap = faultStatus.userModeRead;
          faultStatus.userModeRead = faultStatus.userModeWrite;
          faultStatus.userModeWrite = swap;
        
          // Get address where the first fault was generated
          uint32_t faultAddr = DSPXMCGetFaultAddr(SOC_DSP_XMC_CTRL_BASE);
        
          printf("Invalid memory access event (%d)\n", INTH_INT_ID_MDMAERR);
          // Print the address of the memory that accessing caused the event to trigger.
          printf("  protected memory: 0x%x\n", faultAddr);
          printf("  UX:%u UW:%u UR:%u\n",
                        faultStatus.userModeExec,
                        faultStatus.userModeWrite >> XMPAXL_UW_SHIFT,
                        faultStatus.userModeRead >> XMPAXL_UR_SHIFT);
          printf("  SX:%u SW:%u SR:%u\n",
                        faultStatus.supvModeExec >> XMPAXL_SX_SHIFT,
                        faultStatus.supvModeWrite >> XMPAXL_SW_SHIFT,
                        faultStatus.supvModeRead >> XMPAXL_SR_SHIFT);
          printf("  local access: %u\n", faultStatus.localAccess >> XMPFSR_LOCAL_SHIFT);
          printf("  fID: %u. Only valid if localAccess set to zero\n", faultStatus.localAccess);    
          }
    }
    
     /**
     * \brief   Interrupt handler for XMC/MPU/MDMA errors
     *
     * \param   arg     Interrupt ID
     *
     * \retval  none.
     */
    static void dspErrHandler(void *arg)
    {
        uint32_t faultAddr = 0U;
        uint32_t errType   = (uint32_t) arg;
        switch (errType)
        {
            case INTH_INT_ID_MDMAERR:
                UARTConfigPuts(uartBaseAddr, "MDMAERR\r\n", -1);
                //faultAddr = DSPXMCGetFaultAddr(SOC_DSP_XMC_CTRL_BASE);
                getFaultStatus();
                DSPXMCClearFaultRegs(SOC_DSP_XMC_CTRL_BASE);
                DSPICFGClearMdmaErrEvt(SOC_DSP_ICFG_BASE);
                break;
            case INTH_INT_ID_L1D_PROT_CPU:
            case INTH_INT_ID_L1D_PROT_DMA:
                printf("Should not be INTH_INT_ID_L1D_PROT_DMA\n");
                UARTConfigPuts(uartBaseAddr, "L1D Memory Protection\r\n", -1);
                faultAddr = DSPICFGGetL1DMPUFaultAddr(SOC_DSP_ICFG_BASE);
                DSPICFGClearL1DMPUFaultRegs(SOC_DSP_ICFG_BASE);
                break;
            case INTH_INT_ID_L1P_PROT_CPU:
            case INTH_INT_ID_L1P_PROT_DMA:
                printf("Should not be INTH_INT_ID_L1P_PROT_DMA\n");
                UARTConfigPuts(uartBaseAddr, "L1P Memory Protection\r\n", -1);
                faultAddr = DSPICFGGetL1PMPUFaultAddr(SOC_DSP_ICFG_BASE);
                DSPICFGClearL1PMPUFaultRegs(SOC_DSP_ICFG_BASE);
                break;
            case INTH_INT_ID_L2_PROT_CPU:
            case INTH_INT_ID_L2_PROT_DMA:
                printf("Should not be INTH_INT_ID_L2_PROT_DMA\n");
                UARTConfigPuts(uartBaseAddr, "L2 Memory Protection\r\n", -1);
                faultAddr = DSPICFGGetL2MPUFaultAddr(SOC_DSP_ICFG_BASE);
                DSPICFGClearL2MPUFaultRegs(SOC_DSP_ICFG_BASE);
                break;
            case INTH_INT_ID_L3_BUS_ERR:
                printf("Should not be INTH_INT_ID_L3_BUS_ERR\n");
                UARTConfigPuts(uartBaseAddr, "L3 error\r\n", -1);
                break;
        }
    	UARTConfigPrintf(uartBaseAddr, "Fault address: 0x%08x!!!\r\n\0", faultAddr);
    }
    
    /**
     * \brief   Example NMI handler for DSP
     *
     * \param   none.
     *
     * \retval  none.
     */
    static void dspNmi(void *arg)
    {
        volatile int a = 1;
        UARTConfigPuts(uartBaseAddr, "Exception occured.. ignoring \r\n", -1);
    	ECR = 0x2;
        return;
    }
    
    void padConfig_prcmEnable()
    {
    #if defined (SOC_TDA2XX) || defined (SOC_TDA2PX) || defined (SOC_TDA2EX) || defined (SOC_DRA72x) || defined (SOC_DRA75x)
        /*Pad configurations */
        HW_WR_REG32(SOC_CORE_PAD_IO_REGISTERS_BASE+CTRL_CORE_PAD_UART1_RXD,0x00040000);
        HW_WR_REG32(SOC_CORE_PAD_IO_REGISTERS_BASE+CTRL_CORE_PAD_UART1_TXD,0x00000000);
        /* Set the UART Parameters */
        UARTConfigInit(uartBaseAddr, BAUD_RATE_115200, UART_WORD_LENGTH_8, UART_STOP_BIT_1, UART_NO_PARITY,
                        UART_16x_MODE);
    #endif
    #if defined (SOC_TDA3XX) || defined (SOC_DRA78x)
        /*Pad configurations */
        HW_WR_REG32(SOC_CORE_PAD_IO_REGISTERS_BASE+CTRL_CORE_PAD_IO_SPI1_SCLK,0x00040001);
        HW_WR_REG32(SOC_CORE_PAD_IO_REGISTERS_BASE+CTRL_CORE_PAD_IO_SPI1_CS0,0x00000001);
        /* Set the UART Parameters */
        UARTConfigInit(uartBaseAddr, BAUD_RATE_115200, UART_WORD_LENGTH_8, UART_STOP_BIT_1, UART_NO_PARITY,
                        UART_16x_MODE);
    #endif
    }
    
    /* ========================================================================== */
    /*                          Function Definitions                              */
    /* ========================================================================== */
    int32_t main(void)
    {
        uint32_t            errorOccured = 0U;
        volatile uint32_t   delay;
        int32_t             status, i, temp;
        uint32_t            errHandlerCount = sizeof (gIntrToHandle) /
                                              sizeof (uint32_t);
        OsalIntrFuncPtr         fxn;
    
        padConfig_prcmEnable();
    
    
        UARTConfigPuts(uartBaseAddr, "\r\nXMC MPU Test Application\r\n", -1);
    
        /* Initialize interrupt handlers */
        Intc_Init();
        /* Enable all interrupts */
        Intc_IntEnable(0);
        /* Register exception and NMI handler */
        Intc_IntRegister(1, (IntrFuncPtr) dspNmi, NULL);
    
        for (i = 0; i < errHandlerCount; i++)
        {
            Intc_IntRegister((uint16_t) gIntrToHandle[i],
                             (IntrFuncPtr) dspErrHandler,
                             (void *) gIntrToHandle[i]);
            Intc_IntPrioritySet((uint16_t) gIntrToHandle[i],
                                (uint16_t) 1,
                                (uint8_t) 0);
            Intc_SystemEnable((uint16_t) gIntrToHandle[i]);
        }
    
        /* Clear older error status to ensure correct interrupt generation */
        DSPICFGClearMdmaErrEvt(SOC_DSP_ICFG_BASE);
    
        /* Show interrupt due to 0x0 read access */
        temp  = *(volatile uint32_t *) 0x0U;
        delay = 1000U;
        while (delay--) ;
    
        /* Show interrupt due to 0x0 write access */
        *(volatile uint32_t *) 0x0U = temp;
        delay = 1000U;
        while (delay--) ;
    
        /* Show interrupt due to invalid memory read access at 0x100 */
        temp  = *(volatile uint32_t *) 0x100U;
        delay = 1000U;
        while (delay--) ;
    
        /* Show interrupt due to invalid memory write access at 0x100 */
        *(volatile uint32_t *) 0x100U = temp;
        delay = 1000U;
        while (delay--) ;
    
        /* Show error due to USER mode access to XMC registers */
        DSP_setCpuMode(DSP_CPU_MODE_USR);
        *(volatile uint32_t *) SOC_DSP_XMC_CTRL_BASE = 0;
        DSP_setCpuMode(DSP_CPU_MODE_SPV);
        delay = 1000U;
        while (delay--) ;
    
        DSPICFGCacheEnable(SOC_DSP_ICFG_BASE,
                           DSPICFG_MEM_L1D,
                           DSPICFG_CACHE_SIZE_L1_DISABLED);
        DSPICFGCacheEnable(SOC_DSP_ICFG_BASE,
                           DSPICFG_MEM_L1P,
                           DSPICFG_CACHE_SIZE_L1_32K);
        DSPICFGCacheEnable(SOC_DSP_ICFG_BASE,
                           DSPICFG_MEM_L2,
                           DSPICFG_CACHE_SIZE_L2_64K);
    
        /* CPU mode switch is redundant - done only to indicate dependency of
         * setupXMC() and setupL2MPU() on CPU mode */
        DSP_setCpuMode(DSP_CPU_MODE_SPV);
        setupXMC();
    
        /* CPU mode switch is redundant - done only to indicate dependency of
         * initAllMemory() on CPU mode */
        DSP_setCpuMode(DSP_CPU_MODE_SPV);
        /* Initialize all memories to allow access permissions check */
        initAllMemory();
    
        /* Verify access permissions in SUPERVISOR mode */
        errorOccured += validateAccessPermissions(DSP_CPU_MODE_SPV);
    
        /* CPU mode switch is redundant - done only to indicate dependency of
         * initAllMemory() on CPU mode */
        DSP_setCpuMode(DSP_CPU_MODE_SPV);
        /* Initialize all memories to allow access permissions check */
        initAllMemory();
    
        /* Verify access permissions in USER mode */
        errorOccured += validateAccessPermissions(DSP_CPU_MODE_USR);
    
        if (0U == errorOccured)
        {
            UARTConfigPuts(uartBaseAddr, "Testcase PASS\r\n", -1);
        }
        else
        {
            UARTConfigPuts(uartBaseAddr, "Testcase FAIL\r\n", -1);
            gTestStatus = STW_EFAIL;
        }
    
        /* Unlock all memory at the end of test-case */
        DSP_setCpuMode(DSP_CPU_MODE_SPV);
        status = DSPICFGMemoryProtectionUnlock(
            SOC_DSP_ICFG_BASE, MPLK_KEY0, MPLK_KEY1, MPLK_KEY2, MPLK_KEY3);
        if (STW_SOK != status)
        {
            UARTConfigPuts(uartBaseAddr, "Unable to unlock XMC registers\r\n", -1);
            gTestStatus = STW_EFAIL;
        }
    
        if (gTestStatus == STW_SOK)
        {
            UARTConfigPuts(uartBaseAddr, "Starting Exception Handler test.", -1);
            UARTConfigPuts(uartBaseAddr,
                           "Execution is not expected to return from the exception handler\r\n", -1);
           UARTConfigPuts(uartBaseAddr, "XMC MPU Test completed\r\n", -1);
            /* Show Exception generated due to NULL pointer usage in code */
            fxn = NULL;
            fxn(0);
            delay = 1000U;
            while (delay--) ;
        }
        else
        {
            UARTConfigPuts(uartBaseAddr, "\r\nXMC MPU Test Fail", -1);
        }
    
        return 0;
    }
    
    /* ========================================================================== */
    /*                 Internal Function Definitions                              */
    /* ========================================================================== */
    
    /**
     * \brief   Initialize memory region specified by startAddr and endAddr
     *
     */
    void initMem(uint32_t startAddr, uint32_t endAddr)
    {
        uint32_t addr;
        for (addr = startAddr; addr < endAddr; addr += 4)
        {
            HW_WR_REG32(addr, addr);
        }
    }
    
    /**
     * \brief   Initialize memory regions under test
     *
     */
    static void initAllMemory()
    {
        initMem(XMC_TEST_START, XMC_TEST_END);
        DSPICFGCacheWriteBack(SOC_DSP_ICFG_BASE,
                              XMC_TEST_START,
                              (XMC_TEST_END - XMC_TEST_START));
    }
    
    /**
     * \brief   Sets up different regions in XMC with different access permissions
     *
     */
    static void setupXMC()
    {
        int32_t status;
        /* In case you are using breakpoints for debugging, ensure that
         * code region has full access permissions
         */
        status = DSPICFGMemoryProtectionUnlock(
            SOC_DSP_ICFG_BASE, MPLK_KEY0, MPLK_KEY1, MPLK_KEY2, MPLK_KEY3);
        if (STW_SOK != status)
        {
            UARTConfigPuts(uartBaseAddr, "Unable to unlock XMC registers\r\n", -1);
        }
    
        DSPXMCSetMPAXSegment(SOC_DSP_XMC_CTRL_BASE,    /* baseAddress   */
                             0x2U,                     /* segmentId     */
                             DSPXMC_SEGSZ_64KB,        /* segmentSize   */
                             XMC_TEST_START,     /* inpBAddress   */
                             XMC_TEST_START,     /* repAddressL   */
                             0x0U,                     /* repAddressH   */
                             DSPXMC_USR_RO_PRV_RW);    /* permsFieldVal */
    
        status = DSPICFGMemoryProtectionLock(
            SOC_DSP_ICFG_BASE, MPLK_KEY0, MPLK_KEY1, MPLK_KEY2, MPLK_KEY3);
        if (STW_SOK != status)
        {
            UARTConfigPuts(uartBaseAddr, "Unable to lock XMC registers\r\n", -1);
            gTestStatus = STW_EFAIL;
        }
    }
    
    /**
     *******************************************************************************
     *
     * \brief   Validate CPU Read Access
     *
     * \param   startAddr       Start Address of region to check
     * \param   endAddr         End Address of region to check
     *
     * \return  errorOccured    1 if failure to read, 0 otherwise
     *
     *******************************************************************************
     */
    uint32_t validateCpuReadAccess(uint32_t startAddr, uint32_t endAddr)
    {
        uint32_t errorOccured = 0U, addr, val;
    
        for (addr = startAddr; addr < endAddr; addr += sizeof (uint32_t))
        {
            val = HW_RD_REG32(addr);
            if (val != addr)
            {
                errorOccured = 1U;
            }
        }
    
        if (0U != errorOccured)
        {
            UARTConfigPuts(uartBaseAddr, "Error occurred in READ\r\n", -1);
            gTestStatus = STW_EFAIL;
        }
    
        return errorOccured;
    }
    
    /**
     *******************************************************************************
     *
     * \brief   Validate CPU Write Access
     *
     * \param   startAddr       Start Address of region to check
     * \param   endAddr         End Address of region to check
     *
     * \return  errorOccured    1 if failure to read, 0 otherwise
     *
     *******************************************************************************
     */
    uint32_t validateCpuWriteAccess(uint32_t startAddr, uint32_t endAddr)
    {
        uint32_t errorOccured = 0U, addr;
    
        for (addr = startAddr; addr < endAddr; addr += MEM_CHK_BUF_SZ)
        {
            memset((void *) (&scratchBuffer[0]), 0x0, MEM_CHK_BUF_SZ);
            memcpy((void *) addr, (void *) (&randomNums[0]), MEM_CHK_BUF_SZ);
    
            DSPICFGCacheWriteBackInvalidateAll(SOC_DSP_ICFG_BASE, DSPICFG_MEM_L2);
    
            if (XMC_TEST_START == startAddr)
            {
                memcpy((void *) (&scratchBuffer[0]), (void *) addr, MEM_CHK_BUF_SZ);
            }
        }
    
        if (0U != errorOccured)
        {
            UARTConfigPuts(uartBaseAddr, "Error occurred in WRITE\r\n", -1);
        }
    
        return errorOccured;
    }
    
    /**
     *******************************************************************************
     *
     * \brief   Common implementation to check access permissions with specified
     *          CPU mode
     *
     * \return  errorOccured    >0 if unexpected failure to read/write, 0 otherwise
     *
     *******************************************************************************
     */
    uint32_t validateAccessPermissions(uint32_t cpuMode)
    {
        uint32_t errorOccured = 0U;
    
        DSP_setCpuMode(cpuMode);
    
        errorOccured += validateCpuReadAccess(XMC_TEST_START,
                                               XMC_TEST_END);
        // errorOccured += validateCpuWriteAccess(XMC_TEST_START,
        //                                        XMC_TEST_END);
    
        return errorOccured;
    }
    

  • Hi Enver,

    Please refer to AppNote chapter 4.3. Not all errors are reported by XMC when cache is enabled.

    4.3 XMC Memory Protection Error Reporting With Cache Regions
    XMC does not always report the memory protection errors from the violations in cache regions. This is
    because XMC defers the permission check to L2 cache and the permission configured for the region in
    XMC is cached in L2 cache when the cache line is allocated. If L2 cache controller identifies any violation,
    it will record the fault address and access type in L2MPFAR and L2MPFSR. In addition, L2 cache
    controller will trigger L2_CMPA error event.

    Regards,
    Stanley

  • I modified the example further more in order to catch L2_CMPA, L1D_CMPA and L1P_CMPA events. The result is promising but there is still an even triggered that I don't understand. It is the INTH_INT_ID_MDMAERR event from the log bellow with status and fault adress zero. Could you also comment if this would be a complete way setting up and catching XMC memory violations?

    Invalid memory access event INTH_INT_ID_L1D_PROT_DMA (123)
    protected memory: 0x0
    L1D fault status = 0x20
    UW:0 UR:0
    SW:0 SR:1
    local access: 0
    fID: 0x0. Only valid if localAccess set to zero
    Invalid memory access event INTH_INT_ID_L2_PROT_DMA (125)
    protected memory: 0x0
    L2 fault status = 0x10
    UW:0 UR:0
    SW:1 SR:0
    local access: 0
    fID: 0x0. Only valid if localAccess set to zero
    Invalid memory access event INTH_INT_ID_L1D_PROT_DMA (123)
    protected memory: 0x100
    L1D fault status = 0x20
    UW:0 UR:0
    SW:0 SR:1
    local access: 0
    fID: 0x0. Only valid if localAccess set to zero
    Invalid memory access event INTH_INT_ID_L2_PROT_DMA (125)
    protected memory: 0x100
    L2 fault status = 0x10
    UW:0 UR:0
    SW:1 SR:0
    local access: 0
    fID: 0x0. Only valid if localAccess set to zero
    Invalid memory access event INTH_INT_ID_MDMAERR (110)
    protected memory: 0x8000000
    UX:0 UW:1 UR:0
    SX:0 SW:0 SR:0
    local access: 1
    fID: 256. Only valid if localAccess set to zero
    Invalid memory access event INTH_INT_ID_MDMAERR (110)
    protected memory: 0x0
    UX:0 UW:0 UR:0
    SX:0 SW:0 SR:0
    local access: 0
    fID: 0. Only valid if localAccess set to zero
    Invalid memory access event INTH_INT_ID_L1D_PROT_DMA (123)
    protected memory: 0x80030000
    L1D fault status = 0x4
    UW:0 UR:1
    SW:0 SR:0
    local access: 0
    fID: 0x0. Only valid if localAccess set to zero
    Invalid memory access event INTH_INT_ID_MDMAERR (110)
    protected memory: 0x80030000
    UX:0 UW:1 UR:0
    SX:0 SW:0 SR:0
    local access: 1
    fID: 256. Only valid if localAccess set to zero

    /*
     *  Copyright (C) 2015 Texas Instruments Incorporated
     *
     *  Redistribution and use in source and binary forms, with or without
     *  modification, are permitted provided that the following conditions
     *  are met:
     *
     *    Redistributions of source code must retain the above copyright
     *    notice, this list of conditions and the following disclaimer.
     *
     *    Redistributions in binary form must reproduce the above copyright
     *    notice, this list of conditions and the following disclaimer in the
     *    documentation and/or other materials provided with the
     *    distribution.
     *
     *    Neither the name of Texas Instruments Incorporated nor the names of
     *    its contributors may be used to endorse or promote products derived
     *    from this software without specific prior written permission.
     *
     *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     *
     */
    /**
     *  \file     xmc_mpu_app.c
     *
     *  \brief    This file contains example usage for Extended Memory Controller
     *            (XMC) and Memory Protection Unit (MPU) in C66x device on TDA2x
     *            and TDA3x platform
     *
     *  \details  This will demonstrate implementation of access restrictions
     *            to different memory regions from C66x DSP.
     */
    
    /* ========================================================================== */
    /*                             Include Files                                  */
    /* ========================================================================== */
    
    #include <stdint.h>
    #include <string.h>
    #include <stdio.h>
    #include <ti/csl/csl_types.h>
    #include <ti/csl/soc.h>
    #include <c6x.h>
    #include <ti/csl/hw_types.h>
    #include <ti/csl/csl_edma.h>
    #include <ti/csl/arch/csl_arch.h>
    #include <ti/csl/example/utils/uart_console/inc/uartConfig.h>
    
    /* ========================================================================== */
    /*                                Macros                                      */
    /* ========================================================================== */
    
    #define XMC_TEST_START   (0x80030000U)
    #define XMC_TEST_END     (0x80040000U)
    
    #define DSPXMC_SPV_RWX (DSPXMC_ALLOW_SR | \
                            DSPXMC_ALLOW_SW | \
                            DSPXMC_ALLOW_SX)
    
    #define DSPXMC_USR_WO_PRV_RW (DSPXMC_ALLOW_SR | \
                                  DSPXMC_ALLOW_SW | \
                                  DSPXMC_ALLOW_SX | \
                                  DSPXMC_ALLOW_UW | \
                                  DSPXMC_ALLOW_UX)
    
    #define DSPXMC_USR_RO_PRV_RW (DSPXMC_ALLOW_SR | \
                                  DSPXMC_ALLOW_SW | \
                                  DSPXMC_ALLOW_SX | \
                                  DSPXMC_ALLOW_UR | \
                                  DSPXMC_ALLOW_UX)
    
    #define DSPXMC_USR_RW_PRV_RW (DSPXMC_USR_RO_PRV_RW | DSPXMC_ALLOW_UW)
    
    #define DSPICFG_USR_RW_PRV_RW (DSPICFG_USR_RO_PRV_RW | DSPICFG_L2MPPA_UW)
    
    /* Keys to lock/unlock MPU and XMC registers
     * Default state is unlocked. Locking is optional.
     * Keys can be changed by user.
     */
    #define MPLK_KEY0   0xABCD1234U
    #define MPLK_KEY1   0x1234ABCDU
    #define MPLK_KEY2   0xA1B2C3D4U
    #define MPLK_KEY3   0x4D3C2B1AU
    
    typedef void (*OsalIntrFuncPtr)(uint32_t arg0);
    
    /* ========================================================================== */
    /*                            Global Variables                                */
    /* ========================================================================== */
    #define MEM_CHK_BUF_SZ 0x40U
    #ifdef __cplusplus
    #pragma DATA_ALIGN(32)
    #pragma DATA_SECTION(".scratch_section");
    #else
    #pragma DATA_ALIGN(scratchBuffer, 32)
    #pragma DATA_SECTION(scratchBuffer,".scratch_section");
    #endif
    volatile uint32_t scratchBuffer[MEM_CHK_BUF_SZ >> 2U];
    #ifdef __cplusplus
    #pragma DATA_ALIGN(32)
    #pragma DATA_SECTION(".scratch_section");
    #else
    #pragma DATA_ALIGN(randomNums, 32)
    #pragma DATA_SECTION(randomNums,".scratch_section");
    #endif
    volatile uint32_t randomNums[MEM_CHK_BUF_SZ >> 2U] =
    {
        0xAAAAAAAAU,
        0x55555555U,
        0xBBBBBBBBU,
        0xCCCCCCCCU,
        0x80808080U,
        0xA0A0A0A0U,
        0x50505050U,
        0x12345678U,
        0x22222222U,
        0xDDDDDDDDU,
        0x11111111U,
        0xEEEEEEEEU,
        0x00000000U,
        0x33331111U,
        0x99997777U,
        0x05050505U
    };
    int32_t           gTestStatus = STW_SOK;
    
    uint32_t          gIntrToHandle[] =
    {
        INTH_INT_ID_MDMAERR,
        INTH_INT_ID_L1D_PROT_CPU,
        INTH_INT_ID_L1D_PROT_DMA,
        INTH_INT_ID_L1P_PROT_CPU,
        INTH_INT_ID_L1P_PROT_DMA,
        INTH_INT_ID_L2_PROT_CPU,
        INTH_INT_ID_L2_PROT_DMA,
        INTH_INT_ID_L3_BUS_ERR
    };
    
    #if defined (SOC_TDA2XX) || defined (SOC_TDA2PX) || defined (SOC_TDA2EX) || defined (SOC_DRA72x) || defined (SOC_DRA75x)
    uint32_t uartBaseAddr = SOC_UART1_BASE;
    #endif
    #if defined (SOC_TDA3XX) || defined (SOC_DRA78x)
    uint32_t uartBaseAddr = SOC_UART3_BASE;
    #endif
    
    /* ========================================================================== */
    /*                 Internal Function Declarations                             */
    /* ========================================================================== */
    
    /**
     * \brief   Initialize memory region specified by startAddr and endAddr
     *
     */
    void initMem(uint32_t startAddr, uint32_t endAddr);
    
    /**
     * \brief   Initialize memory regions under test
     *
     */
    static void initAllMemory();
    
    /**
     * \brief   Sets up different regions in XMC with different access permissions
     *
     */
    static void setupXMC();
    
    /**
     * \brief   Validate CPU Read Access
     *
     * \param   startAddr       Start Address of region to check
     * \param   endAddr         End Address of region to check
     *
     * \return  errorOccured    1 if failure to read, 0 otherwise
     */
    uint32_t validateCpuReadAccess(uint32_t startAddr, uint32_t endAddr);
    
    
    /**
     * \brief   Validate CPU Write Access
     *
     * \param   startAddr       Start Address of region to check
     * \param   endAddr         End Address of region to check
     *
     * \return  errorOccured    1 if failure to read, 0 otherwise
     */
    uint32_t validateCpuWriteAccess(uint32_t startAddr, uint32_t endAddr);
    
    /**
     * \brief   Common implementation to check access permissions with specified
     *          CPU mode
     *
     * \param   none
     *
     * \return  errorOccured    >0 if unexpected failure to read/write, 0 otherwise
     */
    uint32_t validateAccessPermissions(uint32_t cpuMode);
    
    void getFaultStatusXMC(void)
    {
        DSPICFGCacheWriteBackInvalidateAll(SOC_DSP_ICFG_BASE, DSPICFG_MEM_L2);
        // Get information on the invalid memory access.
        dspxmcFaultStatus_t faultStatus;
        const int faultStat = DSPXMCGetFaultStatus(SOC_DSP_XMC_CTRL_BASE, &faultStatus);
        
        if (STW_SOK == faultStat)
        {
          const uint32_t swap = faultStatus.userModeRead;
          faultStatus.userModeRead = faultStatus.userModeWrite;
          faultStatus.userModeWrite = swap;
        
          // Get address where the first fault was generated
          uint32_t faultAddr = DSPXMCGetFaultAddr(SOC_DSP_XMC_CTRL_BASE);
        
          printf("Invalid memory access event INTH_INT_ID_MDMAERR (%d)\n", INTH_INT_ID_MDMAERR);
          // Print the address of the memory that accessing caused the event to trigger.
          printf("  protected memory: 0x%x\n", faultAddr);
          printf("  UX:%u UW:%u UR:%u\n",
                        faultStatus.userModeExec,
                        faultStatus.userModeWrite >> XMPAXL_UW_SHIFT,
                        faultStatus.userModeRead >> XMPAXL_UR_SHIFT);
          printf("  SX:%u SW:%u SR:%u\n",
                        faultStatus.supvModeExec >> XMPAXL_SX_SHIFT,
                        faultStatus.supvModeWrite >> XMPAXL_SW_SHIFT,
                        faultStatus.supvModeRead >> XMPAXL_SR_SHIFT);
          printf("  local access: %u\n", faultStatus.localAccess >> XMPFSR_LOCAL_SHIFT);
          printf("  fID: %u. Only valid if localAccess set to zero\n", faultStatus.localAccess);
          }
    }
    
    void getFaultStatusL1D(uint32_t type)
    {
        printf("Invalid memory access event INTH_INT_ID_L1D_PROT_DMA (%d)\n", INTH_INT_ID_L1D_PROT_DMA);
        // Print the address of the memory that accessing caused the event to trigger.
        uint32_t faultAddr = DSPICFGGetL1DMPUFaultAddr(SOC_DSP_ICFG_BASE);
        printf("  protected memory: 0x%x\n", faultAddr);
    
        const uint32_t faultStatusL1D = DSPICFGGetL1DMPUFaultStatus(SOC_DSP_ICFG_BASE);
        printf("  L1D fault status = 0x%x\n", faultStatusL1D);
    
        printf("  UW:%u UR:%u\n",
                    (faultStatusL1D & DSP_L1DMPFSR_UW_MASK) >> DSP_L1DMPFSR_UW_SHIFT,
                    (faultStatusL1D & DSP_L1DMPFSR_UR_MASK) >> DSP_L1DMPFSR_UR_SHIFT);
        printf("  SW:%u SR:%u\n",
                    (faultStatusL1D & DSP_L1DMPFSR_SW_MASK) >> DSP_L1DMPFSR_SW_SHIFT,
                    (faultStatusL1D & DSP_L1DMPFSR_SR_MASK) >> DSP_L1DMPFSR_SR_SHIFT);
        printf("  local access: %u\n", (faultStatusL1D & DSP_L1DMPFSR_LOCAL_MASK) >> DSP_L1DMPFSR_LOCAL_SHIFT);
        printf("  fID: 0x%x. Only valid if localAccess set to zero\n", faultStatusL1D & DSP_L1DMPFSR_FID_MASK);
    }
    void getFaultStatusL1P(uint32_t type)
    {
        printf("Invalid memory access event INTH_INT_ID_L1P_PROT_DMA (%d)\n", INTH_INT_ID_L1P_PROT_DMA);
        // Print the address of the memory that accessing caused the event to trigger.
        uint32_t faultAddr = DSPICFGGetL1PMPUFaultAddr(SOC_DSP_ICFG_BASE);
        printf("  protected memory: 0x%x\n", faultAddr);
    
        const uint32_t faultStatusL1P = DSPICFGGetL1PMPUFaultStatus(SOC_DSP_ICFG_BASE);
        printf("  L1P fault status = 0x%x\n", faultStatusL1P);
    
        printf("  UW:%u UR:%u\n",
                    (faultStatusL1P & DSP_L1PMPFSR_UW_MASK) >> DSP_L1PMPFSR_UW_SHIFT,
                    (faultStatusL1P & DSP_L1PMPFSR_UR_MASK) >> DSP_L1PMPFSR_UR_SHIFT);
        printf("  SW:%u SR:%u\n",
                    (faultStatusL1P & DSP_L1PMPFSR_SW_MASK) >> DSP_L1PMPFSR_SW_SHIFT,
                    (faultStatusL1P & DSP_L1PMPFSR_SR_MASK) >> DSP_L1PMPFSR_SR_SHIFT);
        printf("  local access: %u\n", (faultStatusL1P & DSP_L1PMPFSR_LOCAL_MASK) >> DSP_L1PMPFSR_LOCAL_SHIFT);
        printf("  fID: 0x%x. Only valid if localAccess set to zero\n", faultStatusL1P & DSP_L1PMPFSR_FID_MASK);
    }
    void getFaultStatusL2(uint32_t type)
    {
        printf("Invalid memory access event INTH_INT_ID_L2_PROT_DMA (%d)\n", INTH_INT_ID_L2_PROT_DMA);
        // Print the address of the memory that accessing caused the event to trigger.
        uint32_t faultAddr = DSPICFGGetL2MPUFaultAddr(SOC_DSP_ICFG_BASE);
        printf("  protected memory: 0x%x\n", faultAddr);
    
        const uint32_t faultStatusL2 = DSPICFGGetL2MPUFaultStatus(SOC_DSP_ICFG_BASE);
        printf("  L2 fault status = 0x%x\n", faultStatusL2);
    
        printf("  UW:%u UR:%u\n",
                    (faultStatusL2 & DSP_L2MPFSR_UW_MASK) >> DSP_L2MPFSR_UW_SHIFT,
                    (faultStatusL2 & DSP_L2MPFSR_UR_MASK) >> DSP_L2MPFSR_UR_SHIFT);
        printf("  SW:%u SR:%u\n",
                    (faultStatusL2 & DSP_L2MPFSR_SW_MASK) >> DSP_L2MPFSR_SW_SHIFT,
                    (faultStatusL2 & DSP_L2MPFSR_SR_MASK) >> DSP_L2MPFSR_SR_SHIFT);
        printf("  local access: %u\n", (faultStatusL2 & DSP_L2MPFSR_LOCAL_MASK) >> DSP_L2MPFSR_LOCAL_SHIFT);
        printf("  fID: 0x%x. Only valid if localAccess set to zero\n", faultStatusL2 & DSP_L2MPFSR_FID_MASK);    
    }
    
     /**
     * \brief   Interrupt handler for XMC/MPU/MDMA errors
     *
     * \param   arg     Interrupt ID
     *
     * \retval  none.
     */
    static void dspErrHandler(void *arg)
    {
        uint32_t errType   = (uint32_t) arg;
        switch (errType)
        {
            case INTH_INT_ID_MDMAERR:
                UARTConfigPuts(uartBaseAddr, "MDMAERR\r\n", -1);
                getFaultStatusXMC();
                DSPXMCClearFaultRegs(SOC_DSP_XMC_CTRL_BASE);
                DSPICFGClearMdmaErrEvt(SOC_DSP_ICFG_BASE);
                break;
            case INTH_INT_ID_L1D_PROT_CPU:
            case INTH_INT_ID_L1D_PROT_DMA:
                UARTConfigPuts(uartBaseAddr, "L1D Memory Protection\r\n", -1);
                getFaultStatusL1D(INTH_INT_ID_L1D_PROT_DMA);
                DSPICFGClearL1DMPUFaultRegs(SOC_DSP_ICFG_BASE);
                break;
            case INTH_INT_ID_L1P_PROT_CPU:
            case INTH_INT_ID_L1P_PROT_DMA:
                UARTConfigPuts(uartBaseAddr, "L1P Memory Protection\r\n", -1);
                getFaultStatusL1P(INTH_INT_ID_L1P_PROT_DMA);
                DSPICFGClearL1PMPUFaultRegs(SOC_DSP_ICFG_BASE);
                break;
            case INTH_INT_ID_L2_PROT_CPU:
            case INTH_INT_ID_L2_PROT_DMA:
                UARTConfigPuts(uartBaseAddr, "L2 Memory Protection\r\n", -1);
                getFaultStatusL2(INTH_INT_ID_L2_PROT_DMA);
                DSPICFGClearL2MPUFaultRegs(SOC_DSP_ICFG_BASE);
                break;
            case INTH_INT_ID_L3_BUS_ERR:
                printf("INTH_INT_ID_L3_BUS_ERR\n");
                UARTConfigPuts(uartBaseAddr, "L3 error\r\n", -1);
                break;
        }
    }
    
    /**
     * \brief   Example NMI handler for DSP
     *
     * \param   none.
     *
     * \retval  none.
     */
    static void dspNmi(void *arg)
    {
        volatile int a = 1;
        UARTConfigPuts(uartBaseAddr, "Exception occured.. ignoring \r\n", -1);
    	ECR = 0x2;
        return;
    }
    
    void padConfig_prcmEnable()
    {
    #if defined (SOC_TDA2XX) || defined (SOC_TDA2PX) || defined (SOC_TDA2EX) || defined (SOC_DRA72x) || defined (SOC_DRA75x)
        /*Pad configurations */
        HW_WR_REG32(SOC_CORE_PAD_IO_REGISTERS_BASE+CTRL_CORE_PAD_UART1_RXD,0x00040000);
        HW_WR_REG32(SOC_CORE_PAD_IO_REGISTERS_BASE+CTRL_CORE_PAD_UART1_TXD,0x00000000);
        /* Set the UART Parameters */
        UARTConfigInit(uartBaseAddr, BAUD_RATE_115200, UART_WORD_LENGTH_8, UART_STOP_BIT_1, UART_NO_PARITY,
                        UART_16x_MODE);
    #endif
    #if defined (SOC_TDA3XX) || defined (SOC_DRA78x)
        /*Pad configurations */
        HW_WR_REG32(SOC_CORE_PAD_IO_REGISTERS_BASE+CTRL_CORE_PAD_IO_SPI1_SCLK,0x00040001);
        HW_WR_REG32(SOC_CORE_PAD_IO_REGISTERS_BASE+CTRL_CORE_PAD_IO_SPI1_CS0,0x00000001);
        /* Set the UART Parameters */
        UARTConfigInit(uartBaseAddr, BAUD_RATE_115200, UART_WORD_LENGTH_8, UART_STOP_BIT_1, UART_NO_PARITY,
                        UART_16x_MODE);
    #endif
    }
    
    /* ========================================================================== */
    /*                          Function Definitions                              */
    /* ========================================================================== */
    int32_t main(void)
    {
        uint32_t            errorOccured = 0U;
        volatile uint32_t   delay;
        int32_t             status, i, temp;
        uint32_t            errHandlerCount = sizeof (gIntrToHandle) /
                                              sizeof (uint32_t);
        OsalIntrFuncPtr         fxn;
    
        padConfig_prcmEnable();
    
    
        UARTConfigPuts(uartBaseAddr, "\r\nXMC MPU Test Application\r\n", -1);
    
        /* Initialize interrupt handlers */
        Intc_Init();
        /* Enable all interrupts */
        Intc_IntEnable(0);
        /* Register exception and NMI handler */
        Intc_IntRegister(1, (IntrFuncPtr) dspNmi, NULL);
    
        for (i = 0; i < errHandlerCount; i++)
        {
            Intc_IntRegister((uint16_t) gIntrToHandle[i],
                             (IntrFuncPtr) dspErrHandler,
                             (void *) gIntrToHandle[i]);
            Intc_IntPrioritySet((uint16_t) gIntrToHandle[i],
                                (uint16_t) 1,
                                (uint8_t) 0);
            Intc_SystemEnable((uint16_t) gIntrToHandle[i]);
        }
    
        /* Clear older error status to ensure correct interrupt generation */
        DSPICFGClearMdmaErrEvt(SOC_DSP_ICFG_BASE);
        DSPICFGClearL1DMPUFaultRegs(SOC_DSP_ICFG_BASE);
        DSPICFGClearL1PMPUFaultRegs(SOC_DSP_ICFG_BASE);
        DSPICFGClearL2MPUFaultRegs(SOC_DSP_ICFG_BASE);
    
        /* Show interrupt due to 0x0 read access */
        temp  = *(volatile uint32_t *) 0x0U;
        delay = 1000U;
        while (delay--) ;
    
        /* Show interrupt due to 0x0 write access */
        *(volatile uint32_t *) 0x0U = temp;
        delay = 1000U;
        while (delay--) ;
    
        /* Show interrupt due to invalid memory read access at 0x100 */
        temp  = *(volatile uint32_t *) 0x100U;
        delay = 1000U;
        while (delay--) ;
    
        /* Show interrupt due to invalid memory write access at 0x100 */
        *(volatile uint32_t *) 0x100U = temp;
        delay = 1000U;
        while (delay--) ;
    
        /* Show error due to USER mode access to XMC registers */
        DSP_setCpuMode(DSP_CPU_MODE_USR);
        *(volatile uint32_t *) SOC_DSP_XMC_CTRL_BASE = 0;
        DSP_setCpuMode(DSP_CPU_MODE_SPV);
        delay = 1000U;
        while (delay--) ;
    
        DSPICFGCacheEnable(SOC_DSP_ICFG_BASE,
                           DSPICFG_MEM_L1D,
                           DSPICFG_CACHE_SIZE_L1_DISABLED);
        DSPICFGCacheEnable(SOC_DSP_ICFG_BASE,
                           DSPICFG_MEM_L1P,
                           DSPICFG_CACHE_SIZE_L1_32K); //DSPICFG_CACHE_SIZE_L1_32K
        DSPICFGCacheEnable(SOC_DSP_ICFG_BASE,
                           DSPICFG_MEM_L2,
                           DSPICFG_CACHE_SIZE_L2_64K); //DSPICFG_CACHE_SIZE_L2_64K
    
        /* CPU mode switch is redundant - done only to indicate dependency of
         * setupXMC() and setupL2MPU() on CPU mode */
        DSP_setCpuMode(DSP_CPU_MODE_SPV);
        setupXMC();
    
        /* CPU mode switch is redundant - done only to indicate dependency of
         * initAllMemory() on CPU mode */
        DSP_setCpuMode(DSP_CPU_MODE_SPV);
        /* Initialize all memories to allow access permissions check */
        initAllMemory();
    
        /* Verify access permissions in SUPERVISOR mode */
        errorOccured += validateAccessPermissions(DSP_CPU_MODE_SPV);
    
        /* CPU mode switch is redundant - done only to indicate dependency of
         * initAllMemory() on CPU mode */
        DSP_setCpuMode(DSP_CPU_MODE_SPV);
        /* Initialize all memories to allow access permissions check */
        initAllMemory();
    
        /* Verify access permissions in USER mode */
        errorOccured += validateAccessPermissions(DSP_CPU_MODE_USR);
    
        if (0U == errorOccured)
        {
            UARTConfigPuts(uartBaseAddr, "Testcase PASS\r\n", -1);
        }
        else
        {
            UARTConfigPuts(uartBaseAddr, "Testcase FAIL\r\n", -1);
            gTestStatus = STW_EFAIL;
        }
    
        /* Unlock all memory at the end of test-case */
        DSP_setCpuMode(DSP_CPU_MODE_SPV);
        status = DSPICFGMemoryProtectionUnlock(
            SOC_DSP_ICFG_BASE, MPLK_KEY0, MPLK_KEY1, MPLK_KEY2, MPLK_KEY3);
        if (STW_SOK != status)
        {
            UARTConfigPuts(uartBaseAddr, "Unable to unlock XMC registers\r\n", -1);
            gTestStatus = STW_EFAIL;
        }
    
        if (gTestStatus == STW_SOK)
        {
            UARTConfigPuts(uartBaseAddr, "Starting Exception Handler test.", -1);
            UARTConfigPuts(uartBaseAddr,
                           "Execution is not expected to return from the exception handler\r\n", -1);
           UARTConfigPuts(uartBaseAddr, "XMC MPU Test completed\r\n", -1);
            /* Show Exception generated due to NULL pointer usage in code */
            fxn = NULL;
            fxn(0);
            delay = 1000U;
            while (delay--) ;
        }
        else
        {
            UARTConfigPuts(uartBaseAddr, "\r\nXMC MPU Test Fail", -1);
        }
    
        return 0;
    }
    
    /* ========================================================================== */
    /*                 Internal Function Definitions                              */
    /* ========================================================================== */
    
    /**
     * \brief   Initialize memory region specified by startAddr and endAddr
     *
     */
    void initMem(uint32_t startAddr, uint32_t endAddr)
    {
        uint32_t addr;
        for (addr = startAddr; addr < endAddr; addr += 4)
        {
            HW_WR_REG32(addr, addr);
        }
    }
    
    /**
     * \brief   Initialize memory regions under test
     *
     */
    static void initAllMemory()
    {
        initMem(XMC_TEST_START, XMC_TEST_END);
        DSPICFGCacheWriteBack(SOC_DSP_ICFG_BASE,
                              XMC_TEST_START,
                              (XMC_TEST_END - XMC_TEST_START));
    }
    
    /**
     * \brief   Sets up different regions in XMC with different access permissions
     *
     */
    static void setupXMC()
    {
        int32_t status;
        /* In case you are using breakpoints for debugging, ensure that
         * code region has full access permissions
         */
        status = DSPICFGMemoryProtectionUnlock(
            SOC_DSP_ICFG_BASE, MPLK_KEY0, MPLK_KEY1, MPLK_KEY2, MPLK_KEY3);
        if (STW_SOK != status)
        {
            UARTConfigPuts(uartBaseAddr, "Unable to unlock XMC registers\r\n", -1);
        }
    
        DSPXMCSetMPAXSegment(SOC_DSP_XMC_CTRL_BASE,    /* baseAddress   */
                             0x2U,                     /* segmentId     */
                             DSPXMC_SEGSZ_64KB,        /* segmentSize   */
                             XMC_TEST_START,           /* inpBAddress   */
                             XMC_TEST_START,           /* repAddressL   */
                             0x0U,                     /* repAddressH   */
                             DSPXMC_SPV_RWX);          /* permsFieldVal */
    
        DSPICFGSetAttribute(SOC_DSP_ICFG_BASE,
                            DSPICFG_MEM_L2,
                            XMC_TEST_START,
                            DSPXMC_SPV_RWX);
    
        status = DSPICFGMemoryProtectionLock(
            SOC_DSP_ICFG_BASE, MPLK_KEY0, MPLK_KEY1, MPLK_KEY2, MPLK_KEY3);
        if (STW_SOK != status)
        {
            UARTConfigPuts(uartBaseAddr, "Unable to lock XMC registers\r\n", -1);
            gTestStatus = STW_EFAIL;
        }
    }
    
    /**
     *******************************************************************************
     *
     * \brief   Validate CPU Read Access
     *
     * \param   startAddr       Start Address of region to check
     * \param   endAddr         End Address of region to check
     *
     * \return  errorOccured    1 if failure to read, 0 otherwise
     *
     *******************************************************************************
     */
    uint32_t validateCpuReadAccess(uint32_t startAddr, uint32_t endAddr)
    {
        // uint32_t errorOccured = 0U, addr, val;
        uint32_t errorOccured = 0U, val;
    
        val = HW_RD_REG32(startAddr);
        if (val != startAddr)
        {
        errorOccured = 1U;
        }
    
        if (0U != errorOccured)
        {
            UARTConfigPuts(uartBaseAddr, "Error occurred in READ\r\n", -1);
            gTestStatus = STW_EFAIL;
        }
    
        return errorOccured;
    }
    
    /**
     *******************************************************************************
     *
     * \brief   Validate CPU Write Access
     *
     * \param   startAddr       Start Address of region to check
     * \param   endAddr         End Address of region to check
     *
     * \return  errorOccured    1 if failure to read, 0 otherwise
     *
     *******************************************************************************
     */
    uint32_t validateCpuWriteAccess(uint32_t startAddr, uint32_t endAddr)
    {
        // uint32_t errorOccured = 0U, addr;
        uint32_t errorOccured = 0U;
    
        HW_WR_REG32(startAddr, &randomNums[0]);
    
        return errorOccured;
    }
    
    /**
     *******************************************************************************
     *
     * \brief   Common implementation to check access permissions with specified
     *          CPU mode
     *
     * \return  errorOccured    >0 if unexpected failure to read/write, 0 otherwise
     *
     *******************************************************************************
     */
    uint32_t validateAccessPermissions(uint32_t cpuMode)
    {
        uint32_t errorOccured = 0U;
    
        DSP_setCpuMode(cpuMode);
    
        errorOccured += validateCpuReadAccess(XMC_TEST_START,
                                               XMC_TEST_END);
        errorOccured += validateCpuWriteAccess(XMC_TEST_START,
                                               XMC_TEST_END);
    
        return errorOccured;
    }
    

  • It is unclear what triggered the below event. Can you find out the exact instruction triggered this error?

    Invalid memory access event INTH_INT_ID_MDMAERR (110)
    protected memory: 0x0
    UX:0 UW:0 UR:0
    SX:0 SW:0 SR:0
    local access: 0
    fID: 0. Only valid if localAccess set to zero

  • I commented out all other memory access validation tests and kept only `validateCpuReadAccess` in function `validateAccessPermissions`. Here is the output:

      Invalid memory access event INTH_INT_ID_MDMAERR (110)
      protected memory: 0x0
      UX:0 UW:0 UR:0
      SX:0 SW:0 SR:0
      local access: 0
      fID: 0. Only valid if localAccess set to zero
      Invalid memory access event INTH_INT_ID_L1D_PROT_DMA (123)
      protected memory: 0x80030000
      L1D fault status = 0x4
      UW:0 UR:1
      SW:0 SR:0
      local access: 0
      fID: 0x0. Only valid if localAccess set to zero

    It seems that a read access validation triggers both INTH_INT_ID_MDMAERR and INTH_INT_ID_L1D_PROT_DMA error.

    Regards,
    Enver

  • I think MDMAERR get triggered when L1_CPMA is triggered under some condition. This might be one of them.

  • So you mean that this according to the design?

    //Enver 

  • If it is how it behaves consistently and you are sure the status was properly cleared each time, I would think so.

    As long as L1 or L2 error register returned the fault address correctly, it should be fine.

  • The behavior is consistent and can be recreated with the previously attached example which is a copy of the xmc_mpu_test_app.

    In this case L1 does return correct error register but XMC interrupt is alsotriggered with faulty error registers. In my opinion if the

    violation is catched by both L1 or XMC then the reported information should be valid in both of them. Another way would be if the

    violation was detected in either in L1, L2 or XMC only with correct content. Otherwise this is just confusing.