1    /*
     2     * Copyright (c) 2016-2019, 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     *  ======== Mmu.xdc ========
    34     */
    35    
    36    package ti.sysbios.family.c7x;
    37    
    38    /*!
    39     *  ======== Mmu ========
    40     *  Memory Management Unit (MMU) Manager
    41     *
    42     *  This module allows the C7x processor to map a 64-bit virtual address
    43     *  to a 48-bit physical address and enable/disable the MMU. It does this
    44     *  through translation tables in memory.
    45     *
    46     *  Every application must register a Mmu init function (see {@link #initFunc})
    47     *  that contains calls to Mmu_map() to configure the MMU.
    48     *
    49     *  *.cfg:
    50     *  @p(code)
    51     *  var Mmu = xdc.useModule('ti.sysbios.family.c7x.Mmu');
    52     *  Mmu.initFunc = "&Mmu_initFuncDefault";
    53     *  @p
    54     *
    55     *  Example {@link #initFuncDefault Mmu_initFuncDefault()} provided
    56     *  function for J7 devices:
    57     *  @p(code)
    58     *  ...
    59     *
    60     *  Void Mmu_initFuncDefault()
    61     *  {
    62     *      Bool ret;
    63     *      Mmu_MapAttrs attrs;
    64     *
    65     *      Mmu_initMapAttrs(&attrs);
    66     *
    67     *      // MAIR0 has a default memory type that is non-gathering and
    68     *      // non-reordering with no early write acknowledegement property.
    69     *      // In other words, strongly ordered memory type.
    70     *      attrs.attrIndx = Mmu_AttrIndx_MAIR0;
    71     *
    72     *      // Map GICv3 registers
    73     *      ret = Mmu_map(0x01800000, 0x01800000, 0x00100000, &attrs);
    74     *      if (!ret) {
    75     *          goto fail;
    76     *      }
    77     *
    78     *      // Map DMTimer registers
    79     *      ret = Mmu_map(0x02400000, 0x02400000, 0x000c0000, &attrs);
    80     *      if (!ret) {
    81     *          goto fail;
    82     *      }
    83     *
    84     *      // Map UART registers
    85     *      ret = Mmu_map(0x02800000, 0x02800000, 0x00001000, &attrs);
    86     *      if (!ret) {
    87     *          goto fail;
    88     *      }
    89     *
    90     *      // Map System Timer registers
    91     *      ret = Mmu_map(0x2A430000, 0x2A430000, 0x00001000, &attrs);
    92     *      if (!ret) {
    93     *          goto fail;
    94     *      }
    95     *
    96     *      // MAIR7 has a default attribute type of Inner and Outer
    97     *      // write-back cacheable
    98     *      attrs.attrIndx = Mmu_AttrIndx_MAIR7;
    99     *
   100     *      //Map MSMC SRAM
   101     *      ret = Mmu_map(0x70000000, 0x70000000, 0x00200000, &attrs);
   102     *      if (!ret) {
   103     *          goto fail;
   104     *      }
   105     *
   106     *      return;
   107     *
   108     *  fail:
   109     *      System_printf("Mmu config failed.\n");
   110     *      while (1);
   111     *  }
   112     *
   113     *  @p
   114     */
   115    
   116    @DirectCall
   117    @Template ("./Mmu.xdt")
   118    
   119    module Mmu
   120    {
   121        const UInt8 PA_MAX_WIDTH = 48;
   122    
   123        /*
   124         * Default: 48-bits, 256TB
   125         */
   126        const UInt8 PA_SIZE_ENCODING = 0x5;
   127    
   128        // -------- ROV views --------
   129    
   130        //TBD
   131    
   132        /*!
   133         *  ======== AttrIndx ========
   134         *  Memory attribute register (MAIR) index
   135         *
   136         *  SYS/BIOS defines default values for MAIR register. See {@link #MAIR0},
   137         *  {@link #MAIR1}, {@link #MAIR2}, {@link #MAIR3}, {@link #MAIR4},
   138         *  {@link #MAIR5}, {@link #MAIR6} & {@link #MAIR7} for more info on the
   139         *  memory type defined by each MAIR register.
   140         */
   141        enum AttrIndx {
   142            AttrIndx_MAIR0 = 0,
   143            AttrIndx_MAIR1,
   144            AttrIndx_MAIR2,
   145            AttrIndx_MAIR3,
   146            AttrIndx_MAIR4,
   147            AttrIndx_MAIR5,
   148            AttrIndx_MAIR6,
   149            AttrIndx_MAIR7
   150        };
   151    
   152        /*!
   153         *  @_nodoc
   154         *  ======== DescriptorType ========
   155         *  Different descriptor type encodings:
   156         *  @p(blist)
   157         *  - Invalid or Fault entry (0b00 or 0b10)
   158         *  - Block descriptor entry (0b01)
   159         *  - Table descriptor entry (0b11)
   160         *  @p
   161         */
   162        enum DescriptorType {
   163            DescriptorType_INVALID0 = 0,   /*! Virtual address is unmapped     */
   164            DescriptorType_BLOCK = 1,      /*! Block descriptor                */
   165            DescriptorType_INVALID1 = 2,   /*! Virtual address is unmapped     */
   166            DescriptorType_TABLE = 3       /*! Next-level table address        */
   167        };
   168    
   169        /*!
   170         *  ======== GranuleSize ========
   171         *  Memory translation {@link #granuleSize} granule size
   172         */
   173        enum GranuleSize {
   174            GranuleSize_4KB = 0x1000,
   175            GranuleSize_16KB = 0x4000,
   176            GranuleSize_64KB = 0x10000
   177        };
   178    
   179        /*!
   180         *  ======== Shareable ========
   181         *  Shareability attribute
   182         */
   183        enum Shareable {
   184            Shareable_NONE = 0x0,
   185            Shareable_OUTER = 0x2,
   186            Shareable_INNER = 0x3
   187        };
   188    
   189        /*!
   190         *  ======== AccessPerm ========
   191         *  Access Permissions
   192         */
   193        enum AccessPerm {
   194            AccessPerm_PRIV_RW_USER_NONE = 0x0, /* Privileged Read/write (EL1),
   195                                                   User no access (EL0) */
   196            AccessPerm_PRIV_RW_USER_RW = 0x1,   /* Privileged Read/write (EL1),
   197                                                   User Read/write (EL0) */
   198            AccessPerm_PRIV_RO_USER_NONE = 0x2, /* Privileged Read only (EL1),
   199                                                   User no access (EL0) */
   200            AccessPerm_PRIV_RO_USER_RO = 0x3    /* Privileged Read only (EL1),
   201                                                   User Read only (EL0) */
   202        };
   203    
   204        /*! Mmu init function type definition. */
   205        typedef Void (*InitFuncPtr)(void);
   206    
   207        /*!
   208         *  ======== MapAttrs ========
   209         *  Structure containing attributes for memory map entry
   210         */
   211        struct MapAttrs {
   212            AccessPerm accessPerm;      /*! privileged & user access permissions  */
   213            Bool       privExecute;     /*! privileged execute permission         */
   214            Bool       userExecute;     /*! user execute permission               */
   215            Shareable  shareable;       /*! shareability field value 0-3          */
   216            AttrIndx   attrIndx;        /*! stage 1 memory attributes index field
   217                                            for the indicated MAIRn reg value 0-7 */
   218            Bool       global;          /*! global mmu entry ? (used by kernel
   219                                            when memory protection extensions are
   220                                            enabled)                              */
   221        };
   222    
   223        // Asserts
   224    
   225        /*!
   226         *  ======== A_nullPointer ========
   227         *  Assert raised when a pointer is null
   228         */
   229        config xdc.runtime.Assert.Id A_nullPointer  = {
   230            msg: "A_nullPointer: Pointer is null"
   231        };
   232    
   233        /*!
   234         *  ======== A_vaddrOutOfRange ========
   235         *  Assert raised when virtual address passed is out of range
   236         */
   237        config xdc.runtime.Assert.Id A_vaddrOutOfRange  = {
   238            msg: "A_vaddrOutOfRange: Virtual address is out of range"
   239        };
   240    
   241        /*!
   242         *  ======== A_paddrOutOfRange ========
   243         *  Assert raised when physical address passed is out of range
   244         */
   245        config xdc.runtime.Assert.Id A_paddrOutOfRange  = {
   246            msg: "A_paddrOutOfRange: Physical address is out of range"
   247        };
   248    
   249        /*!
   250         *  ======== A_unalignedVaddr ========
   251         *  Assert raised if unaligned virtual address passed to Mmu_map().
   252         */
   253        config xdc.runtime.Assert.Id A_unalignedVaddr =
   254            {msg: "A_unalignedVaddr: Virtual address not page aligned"};
   255    
   256        /*!
   257         *  ======== A_unalignedPaddr ========
   258         *  Assert raised if unaligned physical address passed to Mmu_map().
   259         */
   260    
   261        config xdc.runtime.Assert.Id A_unalignedPaddr =
   262            {msg: "A_unalignedPaddr: Physical address not page aligned"};
   263    
   264        /*!
   265         *  ======== A_unalignedSize ========
   266         *  Assert raised if unaligned size passed to Mmu_map().
   267         */
   268        config xdc.runtime.Assert.Id A_unalignedSize =
   269            {msg: "A_unalignedSize: Mmu mapping size not page aligned"};
   270    
   271        /*!
   272         *  ======== defaultMapAttrs ========
   273         *  default descriptor attributes structure
   274         */
   275        config MapAttrs defaultMapAttrs = {
   276            accessPerm: AccessPerm_PRIV_RW_USER_NONE,
   277            privExecute: true,
   278            userExecute: false,
   279            shareable: Shareable_OUTER,
   280            attrIndx: AttrIndx_MAIR0,
   281            global: true
   282        };
   283    
   284        /*!
   285         *  ======== enableMMU ========
   286         *  Configuration parameter to enable MMU.
   287         */
   288        config Bool enableMMU = true;
   289    
   290        /*!
   291         *  ======== granuleSize ========
   292         *  Memory translation granule size. Default is 4KB.
   293         *
   294         *  The granule size determines the smallest page size that can be
   295         *  mapped with the MMU.
   296         */
   297        config GranuleSize granuleSize = GranuleSize_4KB;
   298    
   299        /*!
   300         *  ======== MAIR0 ========
   301         *  Memory attribute 0.
   302         *
   303         *  Default is memory with non-gathering, non-reordering and no early write
   304         *  acknowledegement property.
   305         */
   306        config UInt8 MAIR0 = 0x00;
   307    
   308        /*!
   309         *  ======== MAIR1 ========
   310         *  Memory attribute 1
   311         *
   312         *  Default is memory with non-gathering, non-reordering and early write
   313         *  acknowledegement property.
   314         */
   315        config UInt8 MAIR1 = 0x04;
   316    
   317        /*!
   318         *  ======== MAIR2 ========
   319         *  Memory attribute 2
   320         *
   321         *  Default is memory with non-gathering, reordering and early write
   322         *  acknowledegement property.
   323         */
   324        config UInt8 MAIR2 = 0x08;
   325    
   326        /*!
   327         *  ======== MAIR3 ========
   328         *  Memory attribute 3
   329         *
   330         *  Default is memory with gathering, reordering and early write
   331         *  acknowledegement property.
   332         */
   333        config UInt8 MAIR3 = 0x0C;
   334    
   335        /*!
   336         *  ======== MAIR4 ========
   337         *  Memory attribute 4
   338         *
   339         *  Default is normal inner & outer non-cacheable memory.
   340         */
   341        config UInt8 MAIR4 = 0x44;
   342    
   343        /*!
   344         *  ======== MAIR5 ========
   345         *  Memory attribute 5
   346         *
   347         *  Default is normal outer non-cacheable, inner write-back cacheable
   348         *  non-transient memory.
   349         */
   350        config UInt8 MAIR5 = 0x4F;
   351    
   352        /*!
   353         *  ======== MAIR6 ========
   354         *  Memory attribute 6
   355         *
   356         *  Default is normal outer & inner write-through cacheable non-transient
   357         *  memory.
   358         */
   359        config UInt8 MAIR6 = 0xBB;
   360    
   361        /*!
   362         *  ======== MAIR7 ========
   363         *  Memory attribute 7
   364         *
   365         *  Default is normal outer and inner write-back cacheable non-transient
   366         *  memory.
   367         */
   368        config UInt8 MAIR7 = 0x7D;
   369    
   370        /*!
   371         *  ======== initFunc ========
   372         *  MMU init function pointer
   373         *
   374         *  This config param is initialized to point to an init function that
   375         *  will perform MMU configuration using the {@link #map} runtime APIs
   376         *  provided by this module. The init function is called before
   377         *  C initialization i.e. before the data section is initialized.
   378         *  Therefore, care must be taken to not rely on any initialized
   379         *  data variables.
   380         *
   381         *  By default, the {@link #initFuncDefault Mmu_initFuncDefault} function
   382         *  designed for use with AM65x devices is used if the application doesn't
   383         *  provide its own implementation.
   384         */
   385        config InitFuncPtr initFunc = initFuncDefault;
   386    
   387        /*!
   388         *  ======== tableArraySection ========
   389         *  Contains a table array and some state variables.
   390         *  This section is uninitialized.
   391         *
   392         *  Note: Memory containing the table array must be marked as inner &
   393         *  and outer shareable, and inner and outer write-back write-allocate
   394         *  cacheable.
   395         */
   396        metaonly config String tableArraySection =
   397            ".data.ti_sysbios_family_c7x_Mmu_tableArray";
   398    
   399        /*!
   400         *  ======== tableArrayLen ========
   401         *  Length of array of MMU tables
   402         *
   403         *  MMU module allocates memory for MMU table from a table array.
   404         *  This config param controls number of MMU tables supported.
   405         *  Each table in the array is the size of the MMU table and aligned
   406         *  to the table's size.
   407         *
   408         *  @a(Note)
   409         *  MMU table size is same as translation granule size (see
   410         *  {@link #granuleSize})
   411         */
   412        config UInt tableArrayLen = 16;
   413    
   414        /*!
   415         *  ======== enable ========
   416         *  Enables the MMU.
   417         *
   418         *  If the MMU is already enabled, then simply return.
   419         *  Otherwise this function does the following:
   420         *  @p(blist)
   421         *  If the L1 program cache is enabled, invalidate all of L1
   422         *  program cache.
   423         *  @p
   424         *
   425         *  This function enables the MMU on the core it is called from.
   426         *
   427         *  @a(Note)
   428         *  This function does not change the L1 data/program cache settings.
   429         */
   430        Void enable();
   431    
   432        /*!
   433         *  ======== initMapAttrs() ========
   434         *  Initializes the map attribute structure
   435         *
   436         *  @param(attrs)      Pointer to map attribute struct
   437         */
   438        Void initMapAttrs(MapAttrs *descAttrs);
   439    
   440        /*!
   441         *  ======== isEnabled ========
   442         *  Determines if the MMU is enabled
   443         */
   444        Bool isEnabled();
   445    
   446        /*!
   447         *  ======== map ========
   448         *  Add a mapping to MMU table
   449         *
   450         *  This API adds a mapping for the given virtual and physical
   451         *  address to the MMU table and sets the memory attributes
   452         *  as per the attributes passed to the function.
   453         *
   454         *  This API internally disables interrupts before updating the
   455         *  MMU table. The interrupts may be disabled for a long period
   456         *  of time. It is therefore recommended to either call this
   457         *  API in the Mmu.initFunc or in main().
   458         *
   459         *  The smallest mapping size (page size) supported is determined
   460         *  by the {@link #granuleSize}. The largess mapping size supported
   461         *  is 2^{@link #PA_MAX_WIDTH}-1.
   462         *
   463         *  @param(vaddr)         Virtual address (aligned to {@link #granuleSize})
   464         *  @param(paddr)         Physical address (aligned to {@link #granuleSize})
   465         *  @param(size)          Region size (aligned to {@link #granuleSize})
   466         *  @param(attrs)         Memory region attributes
   467         *  @b(returns)           Status (True-success, False-failed)
   468         */
   469        Bool map(UInt64 vaddr, UInt64 paddr, SizeT size, MapAttrs *attrs);
   470    
   471        /*!
   472         *  ======== setMAIR ========
   473         *  Sets the memory attribute encoding in the MAIRn register.
   474         *
   475         *  MAIR provides the memory attribute encodings to the possible
   476         *  {@link #DescriptorAttrs attrIndx} values in a long-descriptor format
   477         *  translation table entry for stage 1 translations.
   478         *
   479         *  {@link #DescriptorAttrs attrIndx}[2:0] selects the ATTRn bit-field in
   480         *  the MAIR register.
   481         *
   482         *  Memory Attribute Indirection Register (MAIR) bit assignments:
   483         *  @p(code)
   484         *         --------------------------------------------------------------
   485         *        |63     |    56|55     |     48|47     |     40|39     |     32|
   486         *         --------------------------------------------------------------
   487         *  MAIR  |     ATTR7    |     ATTR6     |     ATTR5     |     ATTR4     |
   488         *         --------------------------------------------------------------
   489         *        |31     |    24|23     |     16|15     |      8|7      |      0|
   490         *         --------------------------------------------------------------
   491         *  MAIR  |     ATTR3    |     ATTR2     |     ATTR1     |     ATTR0     |
   492         *         --------------------------------------------------------------
   493         *  @p
   494         *
   495         *  SYS/BIOS has 8 MAIR config params (MAIR0, MAIR2, ...) that are
   496         *  initialized to default value. In order to have a custom memory
   497         *  attribute, a user can either change the MAIRn config param in
   498         *  the application's cfg script or call this runtime API.
   499         *
   500         *  For more details on MAIR encodings please refer
   501         *  {@link https://developer.arm.com/docs/ddi0487/latest/arm-architecture-reference-manual-armv8-for-armv8-a-architecture-profile v8A ARM Architecture Reference Manual}
   502         *
   503         *  @param(attrIndx)     Memory attribute index
   504         *  @param(attr)         Memory attribute encoding
   505         *
   506         *  @a(Note)
   507         *  This function only invalidates the TLB and does not flush the cache.
   508         *  If the cacheability attribute of a region of memory is changed by
   509         *  modifying the MAIR entry for the region, the application needs to
   510         *  flush and invalidate the region of memory from the cache.
   511         */
   512        Void setMAIR(UInt8 attrIndx, UInt8 attr);
   513    
   514        /*!
   515         *  @_nodoc
   516         *  ======== startup ========
   517         *  startup function to initialize MMU module
   518         */
   519        Void startup();
   520    
   521        /*!
   522         *  ======== tlbInvAll ========
   523         *  Invalidate entire TLB (both data and instruction)
   524         */
   525        Void tlbInvAll(UInt64 type);
   526    
   527        /*!
   528         *  ======== initFuncDefault ========
   529         *  default Mmu.initFunc implementation.
   530         *
   531         *  provides Mmu regions for the AM65x's GIC, DMTimer, UART, SYSTIMER,
   532         *  and MSMC memory.
   533         */
   534        Void initFuncDefault();
   535    
   536    internal:
   537    
   538        /*
   539         *  ======== ConfigInfo ========
   540         */
   541        struct ConfigInfo {
   542            UInt64 indexMask;
   543            UInt32 tableLength;
   544            UInt8  tableOffset[4];
   545            UInt8  granuleSizeBits;
   546            UInt8  indexBits;
   547            Bool   noLevel0Table;
   548        };
   549    
   550        /*
   551         *  ======== disable ========
   552         */
   553        Void disable();
   554    
   555        /*
   556         *  ======== disableI ========
   557         */
   558        Void disableI();
   559    
   560        /*
   561         *  ======== enableI ========
   562         */
   563        Void enableI();
   564    
   565        /*
   566         *  ======== configInfo ========
   567         *  This is a const object that contains pre-initialized config info
   568         *  about the MMU. Goal is to save some computation time at runtime
   569         *  for config info that can be pre-computed.
   570         */
   571        config ConfigInfo configInfo;
   572    
   573        /*
   574         *  ======== addBlockEntry ========
   575         */
   576        Void addBlockEntry(UInt8 level, UInt64 *tablePtr, UInt16 tableIdx,
   577            UInt64 paddr, MapAttrs *attrs);
   578    
   579        /*
   580         *  ======== addTableEntry ========
   581         */
   582        UInt64* addTableEntry(UInt64 *tablePtr, UInt16 tableIdx, MapAttrs *attrs);
   583    
   584        /*
   585         *  ======== allocTable ========
   586         */
   587        UInt64* allocTable();
   588    
   589        /*
   590         *  ======== freeTable ========
   591         */
   592        Void freeTable(UInt64 *table);
   593    
   594        /*
   595         *  ======== init ========
   596         */
   597        Void init(Ptr tableAddr);
   598    
   599        /*
   600         *  ======== readBlockEntry ========
   601         */
   602        Void readBlockEntry(UInt8 level, UInt64 *tablePtr, UInt16 tableIdx,
   603            UInt64 *paddr, MapAttrs *attrs);
   604    
   605        /*
   606         *  ======== setMAIRAsm ========
   607         */
   608        Void setMAIRAsm(UInt8 attrIndx, UInt8 attr);
   609    
   610        /*
   611         *  ======== tableWalk ========
   612         */
   613        Bool tableWalk(UInt8 level, UInt64 *tablePtr, UInt64 *vaddr, UInt64 *paddr,
   614            SizeT *size, MapAttrs *attrs);
   615    
   616        /*
   617         *  ======== setTCR ========
   618         */
   619        Void setTCR(UInt64 regVal);
   620    
   621        /*! Module state */
   622        struct Module_State {
   623        }
   624    }