1    /*
     2     * Copyright (c) 2013, 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     */
    37    
    38    package ti.sysbios.family.arm.a8;
    39    
    40    import xdc.rov.ViewInfo;
    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,
    63     *  specified to not be initialized via the "NOLOAD" type on GNU compilers
    64     *  and "NOINIT" on TI compilers.
    65     *
    66     *  This module does not manage the second level descriptor tables.
    67     *  A 'SECTION' mapped access requires only a first level fetch.  In
    68     *  this case, there is no need for a second level descriptor table.
    69     *  A 'PAGE_TABLE' mapped access requires a second level
    70     *  descriptor table which can be supplied by the user.
    71     *
    72     *  The following is an example of how to place the MMU table
    73     *  and how to enable L1 data caching for the address range
    74     *  0x80000000-0x90000000 in the *.cfg file:
    75     *
    76     *  @p(code)
    77     *
    78     *    var Cache = xdc.useModule('ti.sysbios.family.arm.a8.Cache');
    79     *    var Mmu = xdc.useModule('ti.sysbios.family.arm.a8.Mmu');
    80     *
    81     *    // Enable the cache
    82     *    Cache.enableCache = true;
    83     *
    84     *    // Enable the MMU (Required for L1/L2 data caching)
    85     *    Mmu.enableMMU = true;
    86     *
    87     *    // descriptor attribute structure
    88     *    var attrs = {
    89     *        type: Mmu.FirstLevelDesc_SECTION,  // SECTION descriptor
    90     *        bufferable: true,                  // bufferable
    91     *        cacheable: true,                   // cacheable
    92     *    };
    93     *
    94     *    // Set the descriptor for each entry in the address range
    95     *    for (var i=0x80000000; i < 0x90000000; i = i + 0x00100000) {
    96     *        // Each 'SECTION' descriptor entry spans a 1MB address range
    97     *        Mmu.setFirstLevelDescMeta(i, i, attrs);
    98     *    }
    99     *
   100     *    var memmap = Program.cpu.memoryMap;
   101     *    var DDR = null;
   102     *
   103     *    // Find DDR in memory map
   104     *    for (var i=0; i < memmap.length; i++) {
   105     *        if (memmap[i].name == "DDR") {
   106     *            DDR = memmap[i];
   107     *        }
   108     *    }
   109     *
   110     *    // Place the MMU table in the DDR memory segment if it exists
   111     *    if (DDR != null) {
   112     *        var sectionName = "ti.sysbios.family.arm.a8.mmuTableSection";
   113     *        Program.sectMap[sectionName] = new Program.SectionSpec();
   114     *        Program.sectMap[sectionName].type = "NOINIT";
   115     *        Program.sectMap[sectionName].loadSegment = "DDR";
   116     *    }
   117     *    else {
   118     *        print("No DDR memory segment was found");
   119     *    }
   120     *
   121     *  @p
   122     *
   123     *  The following example demonstrates how to add a peripheral's address
   124     *  to the MMU table so that it can be accessed by code at runtime:
   125     *
   126     *  @p(code)
   127     *    var Cache = xdc.useModule('ti.sysbios.family.arm.a8.Cache');
   128     *    var Mmu = xdc.useModule('ti.sysbios.family.arm.a8.Mmu');
   129     *
   130     *    // Enable the cache
   131     *    Cache.enableCache = true;
   132     *
   133     *    // Enable the MMU (Required for L1/L2 data caching)
   134     *    Mmu.enableMMU = true;
   135     *
   136     *    // Force peripheral section to be NON cacheable
   137     *    var peripheralAttrs = {
   138     *        type : Mmu.FirstLevelDesc_SECTION, // SECTION descriptor
   139     *        bufferable : false,                // bufferable
   140     *        cacheable  : false,                // cacheable
   141     *        shareable  : false,                // shareable
   142     *        noexecute  : true,                 // not executable
   143     *    };
   144     *
   145     *    // Define the base address of the 1 Meg page
   146     *    // the peripheral resides in.
   147     *    var peripheralBaseAddr = 0xa0400000;
   148     *
   149     *    // Configure the corresponding MMU page descriptor accordingly
   150     *    Mmu.setFirstLevelDescMeta(peripheralBaseAddr,
   151     *                              peripheralBaseAddr,
   152     *                              peripheralAttrs);
   153     *  @p
   154     *
   155     *  Notes:
   156     *  @p(blist)
   157     *      -The 'Supersection' table descriptor is NOT supported.
   158     *      -The 'not global' page descriptor setting is NOT supported.
   159     *      -The 'non-secure' page descriptor setting is NOT supported.
   160     *      -There are size and alignment requirements on the second
   161     *       level descriptor tables depending on the page size.
   162     *      -See the ARM Architecture Reference Manual for more info.
   163     *  @p
   164     *
   165     */
   166    
   167    @Template ("./Mmu.xdt") /* generate function to init MMU page table */
   168    @ModuleStartup          /* call to initTableBuf() in startup */
   169    
   170    module Mmu
   171    {
   172        // -------- ROV views --------
   173    
   174        /*! @_nodoc */
   175        metaonly struct PageView {
   176            String      Type;
   177            Ptr         AddrVirtual;
   178            Ptr         AddrPhysical;
   179            Ptr         Level2TablePtr;
   180            Bool        Bufferable;
   181            Bool        Cacheable;
   182            Bool        Shareable;
   183            Bool        Noexecute;
   184            String      L1DWritePolicy;
   185            UInt        IMP;
   186            UInt        Domain;
   187            String      Access;
   188        };
   189    
   190        @Facet
   191        metaonly config ViewInfo.Instance rovViewInfo =
   192            ViewInfo.create({
   193                viewMap: [
   194                    ['PageView', {
   195                        type: ViewInfo.MODULE_DATA,
   196                        viewInitFxn: 'viewPages',
   197                        structName: 'PageView'
   198                    }]
   199               ]
   200           });
   201    
   202       /*! First Level descriptors */
   203        enum FirstLevelDesc {
   204            FirstLevelDesc_FAULT = 0,       /*! Virtual address is unmapped */
   205            FirstLevelDesc_PAGE_TABLE = 1,  /*! Page table addr descriptor  */
   206            FirstLevelDesc_SECTION = 2      /*! Section descriptor          */
   207        };
   208    
   209        /*!
   210         *  Structure for setting first level descriptor entries
   211         *
   212         *  If the 'cacheable' attribute is true and 'bufferable' is true,
   213         *  L1 data cache operates as a write-back cache.
   214         *  If 'cacheable' is true but 'bufferable' is false,
   215         *  L1 data cache operates as a write-through cache.
   216         *
   217         *  See the 'Translation Tables' section of the ARM v7 Architecture
   218         *  Reference Manual for more details.
   219         */
   220        struct FirstLevelDescAttrs {
   221            FirstLevelDesc type;    /*! first level descriptor type         */
   222            Bool  bufferable;       /*! is memory section bufferable        */
   223            Bool  cacheable;        /*! is memory section cacheable         */
   224            Bool  shareable;        /*! is memory section shareable         */
   225            Bool  noexecute;        /*! is memory section not executable    */
   226            UInt8 imp;              /*! implementation defined              */
   227            UInt8 domain;           /*! domain access control value 0-15    */
   228            UInt8 accPerm;          /*! access permission bits value 0-3    */
   229        };
   230    
   231        /*!
   232         *  ======== A_nullPointer ========
   233         *  Assert raised when a pointer is null
   234         */
   235        config xdc.runtime.Assert.Id A_nullPointer  = {
   236            msg: "A_nullPointer: Pointer is null"
   237        };
   238    
   239        /*!
   240         *  ======== A_unknownDescType ========
   241         *  Assert raised when the descriptor type is not recognized.
   242         */
   243        config xdc.runtime.Assert.Id A_unknownDescType =
   244            {msg: "A_unknownDescType: Descriptor type is not recognized"};
   245    
   246        /*! default descriptor attributes structure */
   247        config FirstLevelDescAttrs defaultAttrs = {
   248            type: FirstLevelDesc_SECTION,   /* SECTION descriptor           */
   249            bufferable: false,              /* false by default             */
   250            cacheable: false,               /* false by default             */
   251            shareable: false,               /* false by default             */
   252            noexecute: false,               /* false by default             */
   253            imp: 1,                         /* set to 1 for A8 devices      */
   254            domain: 0,                      /* default Domain is 0          */
   255            accPerm: 3,                     /* allow read/write             */
   256        };
   257    
   258        /*!
   259         *  ======== enableMMU ========
   260         *  Configuration parameter to enable MMU.
   261         */
   262        config Bool enableMMU = true;
   263    
   264        /*!
   265         *  ======== cachePlatformMemory ========
   266         *  Flag to automatically mark platform's code/data/stack memory as
   267         *  cacheable in MMU descriptor table
   268         *
   269         *  By default, all memory regions defined in the platform an
   270         *  application is built with are marked as cacheable.
   271         *
   272         *  @see xdc.bld.Program#platform
   273         *
   274         *  If manual configuration of memory regions is required, set
   275         *  this config parameter to 'false'.
   276         */
   277        metaonly config Bool cachePlatformMemory = true;
   278    
   279        /*!
   280         *  ======== setFirstLevelDescMeta ========
   281         *  Statically sets the descriptor for the virtual address.
   282         *
   283         *  The first level table entry for the virtual address is mapped
   284         *  to the physical address with the attributes specified. The
   285         *  descriptor table is effective when the MMU is enabled.
   286         *
   287         *  @param(virtualAddr)  The modified virtual address
   288         *  @param(phyAddr)      The physical address
   289         *  @param(attrs)        Pointer to first level descriptor attribute struct
   290         */
   291        metaonly Void setFirstLevelDescMeta(Ptr virtualAddr, Ptr phyAddr,
   292                                            FirstLevelDescAttrs attrs);
   293    
   294        /*!
   295         *  ======== disable ========
   296         *  Disables the MMU.
   297         *
   298         *  If the MMU is already disabled, then simply return.
   299         *  Otherwise this function does the following:
   300         *  If the L1 data cache is enabled, write back invalidate all
   301         *  of L1 data cache.  If the L1 program cache is enabled,
   302         *  invalidate all of L1 program cache. This function does not
   303         *  change the cache L1 data/program settings.
   304         */
   305        @DirectCall
   306        Void disable();
   307    
   308        /*!
   309         *  ======== enable ========
   310         *  Enables the MMU.
   311         *
   312         *  If the MMU is already enabled, then simply return.
   313         *  Otherwise this function does the following:
   314         *  If the L1 program cache is enabled, invalidate all of L1
   315         *  program cache.  This function does not change the L1
   316         *  data/program cache settings.
   317         */
   318        @DirectCall
   319        Void enable();
   320    
   321        /*!
   322         *  ======== initDescAttrs() ========
   323         *  Initializes the first level descriptor attribute structure
   324         *
   325         *  @param(attrs)      Pointer to first level descriptor attribute struct
   326         */
   327        @DirectCall
   328        Void initDescAttrs(FirstLevelDescAttrs *attrs);
   329    
   330        /*!
   331         *  ======== isEnabled ========
   332         *  Determines if the MMU is enabled
   333         */
   334        @DirectCall
   335        Bool isEnabled();
   336    
   337        /*!
   338         *  ======== setFirstLevelDesc ========
   339         *  Sets the descriptor for the virtual address.
   340         *
   341         *  The first level table entry for the virtual address is mapped
   342         *  to the physical address with the attributes specified. The
   343         *  descriptor table is effective when the MMU is enabled.
   344         *
   345         *  @param(virtualAddr)  The modified virtual address
   346         *  @param(phyAddr)      The physical address
   347         *  @param(attrs)        Pointer to first level descriptor attribute struct
   348         */
   349        @DirectCall
   350        Void setFirstLevelDesc(Ptr virtualAddr, Ptr phyAddr,
   351                               FirstLevelDescAttrs *attrs);
   352    
   353    
   354    internal:
   355    
   356        /*! static array to hold first level dscriptor table */
   357        metaonly config UInt32 tableBuf[];
   358    
   359        /*!
   360         *  ======== enableAsm ========
   361         *  Assembly function to enable the MMU.
   362         */
   363        Void enableAsm();
   364    
   365        /*!
   366         *  ======== disableAsm ========
   367         *  Assembly function to disable the MMU.
   368         */
   369        Void disableAsm();
   370    
   371        /*! function generated to initialize first level descriptor table */
   372        Void initTableBuf(Module_State *mod);
   373    
   374        /*! Module state */
   375        struct Module_State {
   376            UInt32 tableBuf[];      /*! 16KB array for first-level descriptors */
   377        }
   378    }