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