1    /*
     2     * Copyright (c) 2017, Texas Instruments Incorporated
     3     * All rights reserved.
     4     *
     5     * Redistribution and use in source and binary forms, with or without
     6     * modification, are permitted provided that the following conditions
     7     * are met:
     8     *
     9     * *  Redistributions of source code must retain the above copyright
    10     *    notice, this list of conditions and the following disclaimer.
    11     *
    12     * *  Redistributions in binary form must reproduce the above copyright
    13     *    notice, this list of conditions and the following disclaimer in the
    14     *    documentation and/or other materials provided with the distribution.
    15     *
    16     * *  Neither the name of Texas Instruments Incorporated nor the names of
    17     *    its contributors may be used to endorse or promote products derived
    18     *    from this software without specific prior written permission.
    19     *
    20     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    21     * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
    22     * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
    23     * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
    24     * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
    25     * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
    26     * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
    27     * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
    28     * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
    29     * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
    30     * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    31     */
    32    /*
    33     *  ======== MPU.xdc ========
    34     */
    35    
    36    package ti.sysbios.family.arm.v8;
    37    
    38    import xdc.rov.ViewInfo;
    39    
    40    /*!
    41     *  ======== MPU ========
    42     *  Memory Protection Unit (MPU) Manager.
    43     *
    44     *  This module manages the Memory Protect Unit (MPU) present in ARMv8
    45     *  Cortex-M devices. It enables the application to partition the memory
    46     *  into different regions and set protection attributes for each region.
    47     *
    48     *  The number of memory regions supported is device specific and may vary
    49     *  on different devices.
    50     *
    51     *  Programming a memory region requires specifying the base address and
    52     *  ending address of the region, and the region's protection attributes.
    53     *  The protection attributes for each region include attributes such as
    54     *  memory type (device or normal), shareability, cacheability and
    55     *  read-write access permission.
    56     *
    57     *  @a(Memory region attributes)
    58     *  Memory regions can be configured as different memory types by setting
    59     *  the {@link #RegionAttrs shareable}, {@link #RegionAttrs accessPerm},
    60     *  {@link #RegionAttrs executable} and {@link #RegionAttrs attrIndx}
    61     *  fields of the {@link #RegionAttrs} structure which is passed as an
    62     *  argument to {@link #setRegion MPU_setRegion()} function.
    63     *
    64     *  The two memory types supported by the hardware are "Normal" (cacheable or
    65     *  non-cacheable) and "Device" memory (gathering, reordering and/or early
    66     *  acknowledgement). "Device" memory type is recommended for mapping
    67     *  peripheral address space like memory-mapped registers. This type ensures
    68     *  that the memory accesses to the peripheral memory are not performed
    69     *  speculatively, are not repeated, and are always performed in order. The
    70     *  "Normal" memory type is recommended for mapping memory regions storing
    71     *  application code and data. The memory type is encoded in a Memory Attribute
    72     *  Indirection Register (MAIR) and an index to it (see
    73     *  {@link #RegionAttrs attrIndx}) is passed to
    74     *  {@link #setRegion MPU_setRegion()} function.
    75     *
    76     *  SYS/BIOS has 8 MAIR config params (MAIR0, MAIR2, ...) that are
    77     *  initialized to default value. In order to have a custom memory
    78     *  attribute, a user can either change the MAIRn config param in
    79     *  the application's cfg script or call the {@link #setMAIR MPU_setMAIR()}
    80     *  runtime API.
    81     *
    82     *  For more details on MAIR encodings please refer v8M ARM Architecture
    83     *  Reference Manual.
    84     *
    85     *  @a(Changing shareability attributes of a cacheable memory region)
    86     *  If changing the shareability attribute of a cacheable memory region,
    87     *  it is possible for coherency problems to arise. In order to avoid possible
    88     *  coherency errors, the below sequence should be followed to change the
    89     *  shareability attributes of the memory region:
    90     *  - Make the memory region Non-cacheable and outer-shareable
    91     *  - Clean and invalidate the memory region from the cache
    92     *  - Change the shareability attribute to the desired value
    93     *
    94     *  @a(Examples)
    95     *  Example showing how to set attributes for a given memory region using
    96     *  *.cfg script:
    97     *
    98     *  @p(code)
    99     *  var MPU = xdc.useModule('ti.sysbios.family.arm.v8.MPU');
   100     *  MPU.enableMPU = true;
   101     *
   102     *  // Mark memory region as normal outer and inner write-back
   103     *  // cacheable
   104     *  var attrs = new MPU.RegionAttrs();
   105     *  MPU.initRegionAttrsMeta(attrs);
   106     *  attrs.enable = true;
   107     *  attrs.shareable = MPU.Shareable_NONE;
   108     *  attrs.executable = false;
   109     *  attrs.accessPerm = MPU.AccessPerm_RW_ANY;
   110     *  attrs.attrIndx = 7; // Use MAIR 7 which has a default of outer and inner
   111     *                      // write-back cacheable
   112     *
   113     *  // Set attributes for memory region of size 32KB starting at
   114     *  // address 0x20000000 using MPU region Id 0 to store the attributes.
   115     *  MPU.setRegionMeta(0, 0x20000000, 32768, attrs);
   116     *  @p
   117     *
   118     *  @p(html)
   119     *  <h3> Calling Context </h3>
   120     *  <table border="1" cellpadding="3">
   121     *    <colgroup span="1"></colgroup> <colgroup span="5" align="center">
   122     *    </colgroup>
   123     *
   124     *    <tr><th> Function                 </th><th>  Hwi   </th><th>  Swi   </th>
   125     *    <th>  Task  </th><th>  Main  </th><th>  Startup  </th></tr>
   126     *    <!--                               -->
   127     *    <tr><td> {@link #disable}     </td><td>   Y    </td><td>   Y    </td>
   128     *    <td>   Y    </td><td>   Y    </td><td>   Y    </td></tr>
   129     *    <tr><td> {@link #enable}      </td><td>   Y    </td><td>   Y    </td>
   130     *    <td>   Y    </td><td>   Y    </td><td>   Y    </td></tr>
   131     *    <tr><td> {@link #initRegionAttrs}  </td><td>   Y    </td><td>   Y    </td>
   132     *    <td>   Y    </td><td>   Y    </td><td>   Y    </td></tr>
   133     *    <tr><td> {@link #isEnabled}  </td><td>   Y    </td><td>   Y    </td>
   134     *    <td>   Y    </td><td>   Y    </td><td>   Y    </td></tr>
   135     *    <tr><td> {@link #setMAIR}  </td><td>   Y    </td><td>   Y    </td>
   136     *    <td>   Y    </td><td>   Y    </td><td>   Y    </td></tr>
   137     *    <tr><td> {@link #setRegion}  </td><td>   Y    </td><td>   Y    </td>
   138     *    <td>   Y    </td><td>   Y    </td><td>   Y    </td></tr>
   139     *    <tr><td colspan="6"> Definitions: <br />
   140     *       <ul>
   141     *         <li> <b>Hwi</b>: API is callable from a Hwi thread. </li>
   142     *         <li> <b>Swi</b>: API is callable from a Swi thread. </li>
   143     *         <li> <b>Task</b>: API is callable from a Task thread. </li>
   144     *         <li> <b>Main</b>: API is callable during any of these phases: </li>
   145     *           <ul>
   146     *             <li> In your module startup. </li>
   147     *             <li> During xdc.runtime.Startup.lastFxns. </li>
   148     *             <li> During main().</li>
   149     *             <li> During BIOS.startupFxns.</li>
   150     *           </ul>
   151     *         <li> <b>Startup</b>: API is callable during any of these phases:</li>
   152     *           <ul>
   153     *             <li> During xdc.runtime.Startup.firstFxns.</li>
   154     *             <li> In your module startup.</li>
   155     *           </ul>
   156     *       </ul>
   157     *    </td></tr>
   158     *
   159     *  </table>
   160     *  @p
   161     */
   162    
   163    @DirectCall
   164    module MPU
   165    {
   166        // -------- ROV views --------
   167    
   168        /*! @_nodoc */
   169        metaonly struct RegionAttrsView {
   170            UInt8       RegionId;
   171            Bool        Enabled;
   172            String      BaseAddress;
   173            String      EndAddress;
   174            String      Shareable;
   175            Bool        Executable;
   176            String      AccessPerm;
   177        };
   178    
   179        @Facet
   180        metaonly config ViewInfo.Instance rovViewInfo =
   181            ViewInfo.create({
   182                viewMap: [
   183                    ['MpuRegionAttrsView', {
   184                        type: ViewInfo.MODULE_DATA,
   185                        viewInitFxn: 'viewMpuRegionAttrs',
   186                        structName: 'RegionAttrsView'
   187                    }],
   188               ]
   189           });
   190    
   191        /*!
   192         *  Memory Protection Unit (MPU) registers. Symbol "MPU_deviceRegs" is
   193         *  a physical device
   194         */
   195        struct DeviceRegs {
   196            UInt32 TYPE;            /*! 0xD90 Type Register                      */
   197            UInt32 CTRL;            /*! 0xD94 Control Register                   */
   198            UInt32 RNR;             /*! 0xD98 Region Register                    */
   199            UInt32 RBAR;            /*! 0xD9C Region Base Address Register       */
   200            UInt32 RLAR;            /*! 0xDA0 Region Base Limit Register         */
   201            UInt32 RBAR_A1;         /*! 0xDA4 MPU RBAR Alias 1                   */
   202            UInt32 RLAR_A1;         /*! 0xDA8 MPU RLAR Alias 1                   */
   203            UInt32 RBAR_A2;         /*! 0xDAC MPU RBAR Alias 2                   */
   204            UInt32 RLAR_A2;         /*! 0xDB0 MPU RLAR Alias 2                   */
   205            UInt32 RBAR_A3;         /*! 0xDB4 MPU RBAR Alias 3                   */
   206            UInt32 RLAR_A3;         /*! 0xDB8 MPU RLAR Alias 3                   */
   207            UInt32 res0;            /*! 0xDBC Reserved                           */
   208            UInt32 MAIR0;           /*! 0xDC0 MAIR0                              */
   209            UInt32 MAIR1;           /*! 0xDC4 MAIR1                              */
   210        };
   211    
   212        extern volatile DeviceRegs deviceRegs;
   213    
   214        /*!
   215         *  ======== AccessPerm ========
   216         *  Access Permissions
   217         */
   218        enum AccessPerm {
   219            AccessPerm_RW_PRIV = 0x0,   /*! Read/write by privileged code only */
   220            AccessPerm_RW_ANY = 0x1,    /*! Read/write by any privilege level  */
   221            AccessPerm_RO_PRIV = 0x2,   /*! Read only by privileged code only  */
   222            AccessPerm_RO_ANY = 0x3     /*! Read only by any privilege level   */
   223        };
   224    
   225        /*!
   226         *  ======== Shareable ========
   227         *  Shareability attribute
   228         */
   229        enum Shareable {
   230            Shareable_NONE = 0x0,
   231            Shareable_OUTER = 0x2,
   232            Shareable_INNER = 0x3
   233        };
   234    
   235        /*!
   236         *  ======== RegionAttrs ========
   237         *  Structure for setting protection attributes of a MPU region
   238         */
   239        struct RegionAttrs {
   240            Bool       enable;           /*! Is MPU region enabled              */
   241            Shareable  shareable;        /*! Memory region shareability         */
   242            Bool       executable;       /*! Is memory region executable        */
   243            AccessPerm accessPerm;       /*! Access permission                  */
   244            UInt8      attrIndx;         /*! Memory attributes index field 0-7  */
   245        };
   246    
   247        /*!
   248         *  ======== defaultAttrs ========
   249         *  Default region attributes structure
   250         *
   251         *  The default attributes structure marks the memory region as outer and
   252         *  inner non-cacheable and non-shareable, with read-write access from
   253         *  privileged code only.
   254         */
   255        config RegionAttrs defaultAttrs = {
   256            enable: true,                   /* true by default                  */
   257            shareable: Shareable_NONE,      /* Shareable_NONE by default        */
   258            executable: true,               /* true by default                  */
   259            accessPerm: AccessPerm_RW_PRIV, /* allow read/write access from
   260                                               privileged code only             */
   261            attrIndx: 0                     /* MAIR 0 by default (MAIR 0 is set
   262                                               to attribute for strongly ordered
   263                                               device memory)                   */
   264        };
   265    
   266        /*!
   267         *  ======== A_nullPointer ========
   268         *  Assert raised when a pointer is null
   269         */
   270        config xdc.runtime.Assert.Id A_nullPointer  = {
   271            msg: "A_nullPointer: Pointer is null"
   272        };
   273    
   274        /*!
   275         *  ======== A_invalidRegionId ========
   276         *  Assert raised when an invalid region number is passed to MPU_setRegion()
   277         */
   278        config xdc.runtime.Assert.Id A_invalidRegionId  = {
   279            msg: "A_invalidRegionId: MPU Region number passed is invalid."
   280        };
   281    
   282        /*!
   283         *  ======== A_unalignedBaseAddr ========
   284         *  Assert raised when region's base address is not aligned.
   285         */
   286        config xdc.runtime.Assert.Id A_unalignedBaseAddr  = {
   287            msg: "A_unalignedBaseAddr: MPU region base address not aligned."
   288        };
   289    
   290        /*!
   291         *  ======== A_unalignedEndAddr ========
   292         *  Assert raised when region's end address is not aligned.
   293         */
   294        config xdc.runtime.Assert.Id A_unalignedEndAddr  = {
   295            msg: "A_unalignedEndAddr: MPU region end address not aligned."
   296        };
   297    
   298        /*!
   299         *  ======== enableMPU ========
   300         *  Configuration parameter to enable MPU. Disabled by default.
   301         */
   302        config Bool enableMPU = false;
   303    
   304        /*!
   305         *  ======== enableBackgroundRegion ========
   306         *  Configuration parameter to enable background region.
   307         *
   308         *  If the MPU is enabled and background region is also enabled, any
   309         *  privileged access that does not map to any MPU memory region is
   310         *  handled using the default memory map.
   311         *
   312         *  @p(blist)
   313         *      -See the "Protected Memory System Architecture (PMSA)" chapter
   314         *       in the ARM v8M Architecture Reference Manual for more info on
   315         *       the default memory map.
   316         *  @p
   317         */
   318        config Bool enableBackgroundRegion = true;
   319    
   320        /*!
   321         *  ======== MAIR0 ========
   322         *  Memory attribute 0.
   323         *
   324         *  Default is memory with non-gathering, non-reordering and no early write
   325         *  acknowledegement property.
   326         */
   327        config UInt8 MAIR0 = 0x00;
   328    
   329        /*!
   330         *  ======== MAIR1 ========
   331         *  Memory attribute 1
   332         *
   333         *  Default is memory with non-gathering, non-reordering and early write
   334         *  acknowledegement property.
   335         */
   336        config UInt8 MAIR1 = 0x04;
   337    
   338        /*!
   339         *  ======== MAIR2 ========
   340         *  Memory attribute 2
   341         *
   342         *  Default is memory with non-gathering, reordering and early write
   343         *  acknowledegement property.
   344         */
   345        config UInt8 MAIR2 = 0x08;
   346    
   347        /*!
   348         *  ======== MAIR3 ========
   349         *  Memory attribute 3
   350         *
   351         *  Default is memory with gathering, reordering and early write
   352         *  acknowledegement property.
   353         */
   354        config UInt8 MAIR3 = 0x0C;
   355    
   356        /*!
   357         *  ======== MAIR4 ========
   358         *  Memory attribute 4
   359         *
   360         *  Default is normal outer & inner non-cacheable memory.
   361         */
   362        config UInt8 MAIR4 = 0x44;
   363    
   364        /*!
   365         *  ======== MAIR5 ========
   366         *  Memory attribute 5
   367         *
   368         *  Default is normal outer non-cacheable, inner write-back cacheable
   369         *  non-transient memory.
   370         */
   371        config UInt8 MAIR5 = 0x4F;
   372    
   373        /*!
   374         *  ======== MAIR6 ========
   375         *  Memory attribute 6
   376         *
   377         *  Default is normal outer & inner write-through cacheable non-transient
   378         *  memory.
   379         */
   380        config UInt8 MAIR6 = 0xBB;
   381    
   382        /*!
   383         *  ======== MAIR7 ========
   384         *  Memory attribute 7
   385         *
   386         *  Default is normal outer and inner write-back cacheable non-transient
   387         *  memory.
   388         */
   389        config UInt8 MAIR7 = 0xFF;
   390    
   391        /*!
   392         *  @_nodoc
   393         *  ======== numRegions ========
   394         *  Number of MPU regions. Default is determined based on device type.
   395         */
   396        config UInt8 numRegions;
   397    
   398        /*!
   399         *  ======== initRegionAttrsMeta ========
   400         *  Initializes the region attribute structure
   401         *
   402         *   @param(attrs)          Pointer to region attribute struct
   403         */
   404        metaonly Void initRegionAttrsMeta(RegionAttrs *regionAttrs);
   405    
   406        /*!
   407         *  ======== setRegionMeta ========
   408         *  Statically sets the MPU region attributes
   409         *
   410         *  @see ti.sysbios.family.arm.r5.MPU
   411         *
   412         *  @param(regionId)        MPU region number
   413         *  @param(regionBaseAddr)  MPU region base address
   414         *  @param(regionEndAddr)   MPU region end address
   415         *  @param(attrs)           Protection attributes
   416         */
   417        metaonly Void setRegionMeta(UInt8 regionId, Ptr regionBaseAddr,
   418            Ptr regionEndAddr, RegionAttrs attrs);
   419    
   420        /*!
   421         *  ======== disable ========
   422         *  Disables the MPU.
   423         *
   424         *  If the MPU is already disabled, then simply return.
   425         */
   426        Void disable();
   427    
   428        /*!
   429         *  ======== enable ========
   430         *  Enables the MPU.
   431         *
   432         *  If the MPU is already enabled, then simply return.
   433         */
   434        Void enable();
   435    
   436        /*!
   437         *  ======== initRegionAttrs() ========
   438         *  Initializes the region attribute structure
   439         *
   440         *  @param(attrs)           Pointer to region attribute struct
   441         */
   442        Void initRegionAttrs(RegionAttrs *regionAttrs);
   443    
   444        /*!
   445         *  ======== isEnabled ========
   446         *  Determines if the MPU is enabled
   447         */
   448        Bool isEnabled();
   449    
   450        /*!
   451         *  ======== setMAIR ========
   452         *  Sets the memory attribute encoding in the MAIRn register.
   453         *
   454         *  MAIR provides the memory attribute encodings to the possible
   455         *  {@link #RegionAttrs attrIndx} values in a MPU region entry.
   456         *
   457         *  {@link #RegionAttrs attrIndx}[2:0] selects the ATTRn bit-field in
   458         *  the MAIR register.
   459         *
   460         *  Memory Attribute Indirection Register (MAIR) bit assignments:
   461         *  @p(code)
   462         *        |31     |    24|23     |     16|15     |      8|7      |      0|
   463         *         --------------------------------------------------------------
   464         *  MAIR0 |     ATTR3    |     ATTR2     |     ATTR1     |     ATTR0     |
   465         *         --------------------------------------------------------------
   466         *  MAIR1 |     ATTR7    |     ATTR6     |     ATTR5     |     ATTR4     |
   467         *         --------------------------------------------------------------
   468         *  @p
   469         *
   470         *  SYS/BIOS has 8 MAIR config params (MAIR0, MAIR2, ...) that are
   471         *  initialized to default value. In order to have a custom memory
   472         *  attribute, a user can either change the MAIRn config param in
   473         *  the application's cfg script or call this runtime API.
   474         *
   475         *  For more details on MAIR encodings please refer v8M ARM Architecture
   476         *  Reference Manual.
   477         *
   478         *  @param(attrIndx)     Memory attribute index
   479         *  @param(attr)         Memory attribute encoding
   480         */
   481        Void setMAIR(UInt8 attrIndx, UInt8 attr);
   482    
   483        /*!
   484         *  ======== setRegion ========
   485         *  Sets the MPU region attributes
   486         *
   487         *  @see ti.sysbios.family.arm.v8.MPU
   488         *
   489         *  @param(regionId)        MPU region number
   490         *  @param(regionBaseAddr)  MPU region base address
   491         *  @param(regionEndAddr)   MPU region end address
   492         *  @param(attrs)           Protection attributes
   493         */
   494        Void setRegion(UInt8 regionId, Ptr regionBaseAddr,
   495            Ptr regionEndAddr, RegionAttrs *attrs);
   496    
   497    internal:
   498    
   499        /*
   500         *  ======== RegionEntry ========
   501         */
   502        struct RegionEntry {
   503            UInt32 rbar;
   504            UInt32 rlar;
   505        };
   506    
   507        /*
   508         *  ======== regionEntry ========
   509         *  Array to hold statically configured MPU region entries
   510         */
   511        config RegionEntry regionEntry[];
   512    
   513        /*
   514         *  ======== startup ========
   515         *  startup function to initialize MPU module
   516         */
   517        Void startup();
   518    
   519        /*! Module state */
   520        struct Module_State {
   521            RegionEntry regionEntry[];  // Array to hold a copy of MPU region
   522                                        // settings
   523        }
   524    }