1    /*
     2     * Copyright (c) 2015, 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.arm.a8;
    37    
    38    import xdc.rov.ViewInfo;
    39    
    40    import xdc.runtime.Assert;
    41    
    42    /*!
    43     *  ======== Mmu ========
    44     *  Memory Management Unit Manager.
    45     *
    46     *  This module allows the ARM processor to map a virtual address to a
    47     *  different physical address and enable/disable the MMU.  It does this
    48     *  through a translation table in memory.  The translation table is
    49     *  16KB and manages only the first level descriptor table.  Each entry
    50     *  in the table defines the properties of memory areas of size 1MB.
    51     *  These properties include memory access permissions, cacheability,
    52     *  bufferability, and domain access.
    53     *
    54     *  By default, the MMU translation table is initialized with
    55     *  cache-enabled entries for every memory segment defined in the platform.
    56     *  Cache-disabled entries are also added for the peripheral
    57     *  addresses used by SYS/BIOS (i.e. Timers, Interrupt controller).
    58     *
    59     *  The translation table is placed in
    60     *  an output section called "ti.sysbios.family.arm.a8.mmuTableSection".
    61     *  This section is placed into the platform's default dataMemory and
    62     *  in order to minimize object file size, specified to not be initialized
    63     *  via the "NOLOAD" type on GNU compilers and "NOINIT" on TI compilers.
    64     *
    65     *  This module does not manage the second level descriptor tables.
    66     *  A 'SECTION' mapped access requires only a first level fetch.  In
    67     *  this case, there is no need for a second level descriptor table.
    68     *  A 'PAGE_TABLE' mapped access requires a second level
    69     *  descriptor table which can be supplied by the user.
    70     *
    71     *  The following is an example of how to place the MMU table
    72     *  and how to enable L1 data + L2 caching for the address range
    73     *  0x80000000-0x90000000 in the *.cfg file:
    74     *
    75     *  @p(code)
    76     *
    77     *    // For Cortex-A8
    78     *    var Cache = xdc.useModule('ti.sysbios.family.arm.a8.Cache');
    79     *    // For Cortex-A9
    80     *    var Cache = xdc.useModule('ti.sysbios.family.arm.a9.Cache');
    81     *
    82     *    var Mmu = xdc.useModule('ti.sysbios.family.arm.a8.Mmu');
    83     *
    84     *    // Enable the cache
    85     *    Cache.enableCache = true;
    86     *
    87     *    // Enable the MMU (Required for L1/L2 data caching)
    88     *    Mmu.enableMMU = true;
    89     *
    90     *    // descriptor attribute structure for marking the memory region
    91     *    // as normal cacheable memory (write-back and write-allocate)
    92     *    var attrs = {
    93     *        type: Mmu.FirstLevelDesc_SECTION,  // SECTION descriptor
    94     *        tex: 0x1,
    95     *        bufferable: true,                  // bufferable
    96     *        cacheable: true,                   // cacheable
    97     *    };
    98     *
    99     *    // Set the descriptor for each entry in the address range
   100     *    for (var i=0x80000000; i < 0x90000000; i = i + 0x00100000) {
   101     *        // Each 'SECTION' descriptor entry spans a 1MB address range
   102     *        Mmu.setFirstLevelDescMeta(i, i, attrs);
   103     *    }
   104     *
   105     *    var memmap = Program.cpu.memoryMap;
   106     *    var DDR = null;
   107     *
   108     *    // Find DDR in memory map
   109     *    for (var i=0; i < memmap.length; i++) {
   110     *        if (memmap[i].name == "DDR") {
   111     *            DDR = memmap[i];
   112     *        }
   113     *    }
   114     *
   115     *    // Place the MMU table in the DDR memory segment if it exists
   116     *    if (DDR != null) {
   117     *        var sectionName = "ti.sysbios.family.arm.a8.mmuTableSection";
   118     *        Program.sectMap[sectionName] = new Program.SectionSpec();
   119     *        Program.sectMap[sectionName].type = "NOLOAD"; // NOINIT for TI Tools
   120     *        Program.sectMap[sectionName].loadSegment = "DDR";
   121     *    }
   122     *    else {
   123     *        print("No DDR memory segment was found");
   124     *    }
   125     *
   126     *  @p
   127     *
   128     *  The following example demonstrates how to add a peripheral's address
   129     *  to the MMU table so that it can be accessed by code at runtime:
   130     *
   131     *  @p(code)
   132     *    // For Cortex-A8
   133     *    var Cache = xdc.useModule('ti.sysbios.family.arm.a8.Cache');
   134     *    // For Cortex-A9
   135     *    var Cache = xdc.useModule('ti.sysbios.family.arm.a9.Cache');
   136     *
   137     *    var Mmu = xdc.useModule('ti.sysbios.family.arm.a8.Mmu');
   138     *
   139     *    // Enable the cache
   140     *    Cache.enableCache = true;
   141     *
   142     *    // Enable the MMU (Required for L1/L2 data caching)
   143     *    Mmu.enableMMU = true;
   144     *
   145     *    // Force peripheral section to be NON cacheable strongly-ordered memory
   146     *    var peripheralAttrs = {
   147     *        type : Mmu.FirstLevelDesc_SECTION, // SECTION descriptor
   148     *        tex: 0,
   149     *        bufferable : false,                // bufferable
   150     *        cacheable  : false,                // cacheable
   151     *        shareable  : false,                // shareable
   152     *        noexecute  : true,                 // not executable
   153     *    };
   154     *
   155     *    // Define the base address of the 1 Meg page
   156     *    // the peripheral resides in.
   157     *    var peripheralBaseAddr = 0xa0400000;
   158     *
   159     *    // Configure the corresponding MMU page descriptor accordingly
   160     *    Mmu.setFirstLevelDescMeta(peripheralBaseAddr,
   161     *                              peripheralBaseAddr,
   162     *                              peripheralAttrs);
   163     *  @p
   164     *
   165     *  @a(Memory region attributes)
   166     *  Memory regions can be configured as different memory types by setting
   167     *  the {@link #FirstLevelDescAttrs bufferable},
   168     *  {@link #FirstLevelDescAttrs cacheable} and {@link #FirstLevelDescAttrs tex}
   169     *  (type extension) fields of the {@link #FirstLevelDescAttrs} structure
   170     *  which is passed as an argument to {@link #setFirstLevelDesc}. The three
   171     *  memory types supported by the hardware are "Normal" (cacheable), "Device"
   172     *  and "Strongly-ordered" memory. "Device" and "Strongly-ordered" memory
   173     *  types are recommended for mapping peripheral address space like
   174     *  memory-mapped registers. These two types ensure that the memory accesses
   175     *  to the peripheral memory are not performed speculatively, are not repeated
   176     *  and are performed in order. The "Normal" memory type is recommended for
   177     *  mapping memory regions storing application code and data.
   178     *
   179     *  Here are some common settings for the
   180     *  {@link #FirstLevelDescAttrs bufferable},
   181     *  {@link #FirstLevelDescAttrs cacheable} and {@link #FirstLevelDescAttrs tex}
   182     *  fields to define different memory region types:
   183     *
   184     *  @p(code)
   185     *  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
   186     *  + Memory Type                             | bufferable | cacheable | tex +
   187     *  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
   188     *  + Shareable Strongly-ordered memory       |    false   |   false   |  0  +
   189     *  +-----------------------------------------+------------+-----------+-----+
   190     *  + Shareable Device memory                 |    true    |   false   |  0  +
   191     *  +-----------------------------------------+------------+-----------+-----+
   192     *  + Outer & Inner Non-cacheable             |    false   |   false   |  1  +
   193     *  +-----------------------------------------+------------+-----------+-----+
   194     *  + Outer & Inner Write-back Write-allocate |    true    |   true    |  1  +
   195     *  + cacheable                               |            |           |     +
   196     *  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
   197     *  @p
   198     *
   199     *  For an exhaustive list of all different memory type settings and a
   200     *  detailed explanation of the memory region attributes, please read the
   201     *  'Short-descriptor translation table format' section of the ARM v7-AR
   202     *  Architecture Reference Manual issue C.
   203     *
   204     *  Notes:
   205     *  @p(blist)
   206     *      -The 'Supersection' table descriptor is NOT supported.
   207     *      -The 'not global' page descriptor setting is NOT supported.
   208     *      -The 'non-secure' page descriptor setting is NOT supported.
   209     *      -There are size and alignment requirements on the second
   210     *       level descriptor tables depending on the page size.
   211     *      -See the ARM Architecture Reference Manual for more info.
   212     *  @p
   213     *
   214     */
   215    
   216    @Template ("./Mmu.xdt") /* generate function to init MMU page table */
   217    @ModuleStartup          /* call to initTableBuf() in startup */
   218    @DirectCall
   219    
   220    module Mmu
   221    {
   222        // -------- ROV views --------
   223    
   224        /*! @_nodoc */
   225        metaonly struct PageView {
   226            String      Type;
   227            String      Tex;
   228            Ptr         AddrVirtual;
   229            Ptr         AddrPhysical;
   230            Ptr         Level2TablePtr;
   231            Bool        Bufferable;
   232            Bool        Cacheable;
   233            Bool        Shareable;
   234            Bool        Noexecute;
   235            Bool        NotGlobal;
   236            String      L1DWritePolicy;
   237            UInt        IMP;
   238            UInt        Domain;
   239            String      Access;
   240        };
   241    
   242        @Facet
   243        metaonly config ViewInfo.Instance rovViewInfo =
   244            ViewInfo.create({
   245                viewMap: [
   246                    ['0x0-0x7FFFFFFF', {
   247                        type: ViewInfo.MODULE_DATA,
   248                        viewInitFxn: 'viewPages1',
   249                        structName: 'PageView'
   250                    }],
   251                    ['0x80000000-0x9FFFFFFF', {
   252                        type: ViewInfo.MODULE_DATA,
   253                        viewInitFxn: 'viewPages2',
   254                        structName: 'PageView'
   255                    }],
   256                    ['0xA0000000-0xBFFFFFFF', {
   257                        type: ViewInfo.MODULE_DATA,
   258                        viewInitFxn: 'viewPages3',
   259                        structName: 'PageView'
   260                    }],
   261                    ['0xC0000000-0xDFFFFFFF', {
   262                        type: ViewInfo.MODULE_DATA,
   263                        viewInitFxn: 'viewPages4',
   264                        structName: 'PageView'
   265                    }],
   266                    ['0xE0000000-0xFFFFFFFF', {
   267                        type: ViewInfo.MODULE_DATA,
   268                        viewInitFxn: 'viewPages5',
   269                        structName: 'PageView'
   270                    }]
   271               ]
   272           });
   273    
   274        /*!
   275         *  First Level descriptors
   276         *
   277         *  Different descriptor type encodings:
   278         *  0b00    ->  Invalid or Fault entry
   279         *  0b01    ->  Page table entry
   280         *  0b10    ->  Section descriptor
   281         *  0b11    ->  Reserved
   282         */
   283        enum FirstLevelDesc {
   284            FirstLevelDesc_FAULT = 0,      /*! Virtual address is unmapped     */
   285            FirstLevelDesc_PAGE_TABLE = 1, /*! Page table addr descriptor      */
   286            FirstLevelDesc_SECTION = 2,    /*! Section descriptor              */
   287            FirstLevelDesc_RESERVED = 3    /*! Reserved                        */
   288        };
   289    
   290        /*!
   291         *  Structure for setting first level descriptor entries
   292         *
   293         *  The B (Bufferable), C (Cacheable), and TEX (Type extension) bits
   294         *  in the translation table descriptor define the memory region
   295         *  attributes.
   296         *
   297         *  See the 'Short-descriptor translation table format' section of the
   298         *  ARM v7-AR Architecture Reference Manual issue C for more details.
   299         */
   300        struct FirstLevelDescAttrs {
   301            FirstLevelDesc type;    /*! first level descriptor type             */
   302            Bool  bufferable;       /*! is memory section bufferable            */
   303            Bool  cacheable;        /*! is memory section cacheable             */
   304            Bool  shareable;        /*! is memory section shareable             */
   305            Bool  noexecute;        /*! is memory section not executable        */
   306            UInt8 imp;              /*! implementation defined                  */
   307            UInt8 domain;           /*! domain access control value 0-15        */
   308            UInt8 accPerm;          /*! access permission bits value 0-7        */
   309            UInt8 tex;              /*! memory region attr type extension field */
   310            Bool  notGlobal;        /*! not global bit                          */
   311        };
   312    
   313        // Asserts
   314    
   315        /*!
   316         *  ======== A_nullPointer ========
   317         *  Assert raised when a pointer is null
   318         */
   319        config Assert.Id A_nullPointer  = {
   320            msg: "A_nullPointer: Pointer is null"
   321        };
   322    
   323        /*!
   324         *  ======== A_unknownDescType ========
   325         *  Assert raised when the descriptor type is not recognized.
   326         */
   327        config Assert.Id A_unknownDescType = {
   328            msg: "A_unknownDescType: Descriptor type is not recognized"
   329        };
   330    
   331        /*! default descriptor attributes structure */
   332        config FirstLevelDescAttrs defaultAttrs = {
   333            type: FirstLevelDesc_SECTION,   /* SECTION descriptor */
   334            bufferable: false,              /* false by default     */
   335            cacheable: false,               /* false by default     */
   336            shareable: false,               /* false by default */
   337            noexecute: false,               /* false by default     */
   338            imp: 1,                         /* set to 1 for A8/A9 devices */
   339            domain: 0,                      /* default Domain is 0 */
   340            accPerm: 3,                     /* allow read/write */
   341            tex: 1,                         /* 1 by default */
   342            notGlobal: false                /* global by default */
   343        };
   344    
   345        /*!
   346         *  ======== enableMMU ========
   347         *  Configuration parameter to enable MMU.
   348         */
   349        config Bool enableMMU = true;
   350    
   351        /*!
   352         *  ======== cachePlatformMemory ========
   353         *  Flag to automatically mark platform's code/data/stack memory as
   354         *  cacheable in MMU descriptor table
   355         *
   356         *  By default, all memory regions defined in the platform an
   357         *  application is built with are marked as cacheable.
   358         *
   359         *  @see xdc.bld.Program#platform
   360         *
   361         *  If manual configuration of memory regions is required, set
   362         *  this config parameter to 'false'.
   363         */
   364        metaonly config Bool cachePlatformMemory = true;
   365    
   366        /*!
   367         *  ======== setFirstLevelDescMeta ========
   368         *  Statically sets the descriptor for the virtual address.
   369         *
   370         *  The first level table entry for the virtual address is mapped
   371         *  to the physical address with the attributes specified. The
   372         *  descriptor table is effective when the MMU is enabled.
   373         *
   374         *  @param(virtualAddr)  The modified virtual address
   375         *  @param(phyAddr)      The physical address
   376         *  @param(attrs)        Pointer to first level descriptor attribute struct
   377         */
   378        metaonly Void setFirstLevelDescMeta(Ptr virtualAddr, Ptr phyAddr,
   379                                            FirstLevelDescAttrs attrs);
   380    
   381        /*!
   382         *  ======== disable ========
   383         *  Disables the MMU.
   384         *
   385         *  If the MMU is already disabled, then simply return.
   386         *  Otherwise this function does the following:
   387         *  If the L1 data cache is enabled, write back invalidate all
   388         *  of L1 data cache.  If the L1 program cache is enabled,
   389         *  invalidate all of L1 program cache. This function does not
   390         *  change the cache L1 data/program settings.
   391         */
   392        Void disable();
   393    
   394        /*!
   395         *  ======== enable ========
   396         *  Enables the MMU.
   397         *
   398         *  If the MMU is already enabled, then simply return.
   399         *  Otherwise this function does the following:
   400         *  If the L1 program cache is enabled, invalidate all of L1
   401         *  program cache.  This function does not change the L1
   402         *  data/program cache settings.
   403         */
   404        Void enable();
   405    
   406        /*!
   407         *  ======== initDescAttrs() ========
   408         *  Initializes the first level descriptor attribute structure
   409         *
   410         *  @param(attrs)      Pointer to first level descriptor attribute struct
   411         */
   412        Void initDescAttrs(FirstLevelDescAttrs *attrs);
   413    
   414        /*!
   415         *  ======== isEnabled ========
   416         *  Determines if the MMU is enabled
   417         */
   418        Bool isEnabled();
   419    
   420        /*!
   421         *  ======== setFirstLevelDesc ========
   422         *  Sets the descriptor for the virtual address.
   423         *
   424         *  The first level table entry for the virtual address is mapped
   425         *  to the physical address with the attributes specified. The
   426         *  descriptor table is effective when the MMU is enabled.
   427         *
   428         *  @param(virtualAddr)  The modified virtual address
   429         *  @param(phyAddr)      The physical address
   430         *  @param(attrs)        Pointer to first level descriptor attribute struct
   431         */
   432        Void setFirstLevelDesc(Ptr virtualAddr, Ptr phyAddr,
   433                               FirstLevelDescAttrs *attrs);
   434    
   435        /*!
   436         *  ======== getPhysicalAddr ========
   437         *  Returns the translated physical address for the given virtual address.
   438         *  If the virtual address cannot be translated i.e. the virtual address
   439         *  would generate a fault if translated, ~(0) is returned.
   440         *
   441         *  @param(virtualAddr)  virtual address
   442         *  @b(returns)          translated physical address
   443         */
   444        Ptr getPhysicalAddr(Ptr virtualAddr);
   445    
   446        /*!
   447         *  @_nodoc
   448         *  ======== getMmuTableAddr ========
   449         *  Returns the MMU table base address
   450         *
   451         *  @b(returns)          MMU table base address
   452         */
   453        Ptr getMmuTableAddr();
   454    
   455        /*!
   456         *  ======== getDomainAccessCtrlReg ========
   457         *  Returns the domain access control register value (DACR)
   458         *
   459         *  @b(returns)          Domain Access Ctrl Register value
   460         */
   461        UInt32 getDomainAccessCtrlReg();
   462    
   463        /*!
   464         *  ======== setDomainAccessCtrlReg ========
   465         *  Write the passed argument to domain access control register (DACR)
   466         *
   467         *  The domain access control register has 16 2-bit fields to control
   468         *  the access permissions of each domain.
   469         *
   470         *  @p(code)
   471         *         |31 30|29 28|27 26|25 24|23 22| ... |7   6|5   4|3   2|1   0|
   472         *          -----------------------------------------------------------
   473         *  Domain | D15 | D14 | D13 | D12 | D11 | ... | D3  | D2  | D1  |  D0 |
   474         *          -----------------------------------------------------------
   475         *
   476         *  Possible domain access permission value for each field:
   477         *  0b00   No access. Any domain access will generate a fault.
   478         *  0b01   Accesses are checked against translation table permission bits.
   479         *  0b11   No access permission checking is performed for this domain.
   480         *  @p
   481         *
   482         *  @param(regVal)       Contents to be written to DACR register
   483         */
   484        Void setDomainAccessCtrlReg(UInt32 regVal);
   485    
   486        /*!
   487         *  @_nodoc
   488         *  ======== switchContext ========
   489         *  Switches the ASID and changes the MMU table base address
   490         *
   491         *  Note: This function does not validate the mmuTable pointer
   492         *
   493         *  @param(asid)        ASID to switch to
   494         *  @param(mmuTable)    MMU table base address to switch to
   495         */
   496        Void switchContext(UInt8 asid, Ptr mmuTable);
   497    
   498        /*!
   499         *  @_nodoc
   500         *  ======== getAsid ========
   501         *  Returns the current ASID
   502         *
   503         *  @b(returns)         Current ASID
   504         */
   505        UInt8 getAsid();
   506    
   507        /*!
   508         *  ======== tlbInvAll ========
   509         *  Invalidate entire TLB (both data and instruction)
   510         */
   511        Void tlbInvAll();
   512    
   513    internal:
   514    
   515        /*! static array to hold first level dscriptor table */
   516        metaonly config UInt32 tableBuf[];
   517    
   518        /*!
   519         *  ======== init ========
   520         *  initialize mmu registers
   521         */
   522        Void init();
   523    
   524        /*!
   525         *  ======== enableAsm ========
   526         *  Assembly function to enable the MMU.
   527         */
   528        Void enableAsm();
   529    
   530        /*!
   531         *  ======== disableAsm ========
   532         *  Assembly function to disable the MMU.
   533         */
   534        Void disableAsm();
   535    
   536        /*! function generated to initialize first level descriptor table */
   537        Void initTableBuf(UInt32 *mmuTableBuf);
   538    
   539        /*!
   540         *  ======== getPhysicalAddrI ========
   541         *  Returns the translated physical address for the given virtual address.
   542         *  If the virtual address cannot be translated i.e. the virtual address
   543         *  would generate a fault if translated, ~(0) is returned.
   544         */
   545        Ptr getPhysicalAddrI(Ptr virtualAddr);
   546    
   547        /*! Module state */
   548        struct Module_State {
   549            UInt32 tableBuf[];      /*! 16KB array for first-level descriptors */
   550        }
   551    }