Squashed all commits
This commit is contained in:
392
src/Modules/MMU/mmu.c
Normal file
392
src/Modules/MMU/mmu.c
Normal file
@@ -0,0 +1,392 @@
|
||||
/*
|
||||
****************************************************************************************************
|
||||
*
|
||||
* uC/OS-MMU
|
||||
*
|
||||
* (c) Copyright 2012, Micrium, FL
|
||||
* All rights reserved.
|
||||
*
|
||||
* All rights reserved. Protected by international copyright laws.
|
||||
* Knowledge of the source code may not be used to write a similar
|
||||
* product. This file may only be used in accordance with a license
|
||||
* and should not be redistributed in any way.
|
||||
*
|
||||
*
|
||||
* Version : 3.1.2pp-35237
|
||||
* File : MMU.c (#1)
|
||||
* Programmer(s) : EO
|
||||
****************************************************************************************************
|
||||
*/
|
||||
|
||||
/*!
|
||||
****************************************************************************************************
|
||||
* \defgroup PAR_CPU_MMU Target Specific MMU Implementation
|
||||
* \ingroup PAR_CORE
|
||||
*
|
||||
*
|
||||
* The memory management unit (MMU) for the ...
|
||||
*
|
||||
****************************************************************************************************
|
||||
*/
|
||||
|
||||
/*
|
||||
****************************************************************************************************
|
||||
* INCLUDES
|
||||
****************************************************************************************************
|
||||
*/
|
||||
|
||||
#include "mmu.h"
|
||||
#include "xpseudo_asm.h"
|
||||
#include "xil_cache.h"
|
||||
#include "lib_mem.h"
|
||||
#include "mmu_cfg.h"
|
||||
|
||||
/*
|
||||
****************************************************************************************************
|
||||
* GOBAL DATA
|
||||
****************************************************************************************************
|
||||
*/
|
||||
|
||||
|
||||
extern INT32U MMUTable;
|
||||
|
||||
/*
|
||||
****************************************************************************************************
|
||||
* PRIVATE FUNCTION PROTOTYPES
|
||||
****************************************************************************************************
|
||||
*/
|
||||
static MMU_ERR_T MMUTblAdd (PAR_MEM_REGION_REF_T mem, INT32U * pMMUTable);
|
||||
static MMU_ERR_T MMUTblAdd1M (PAR_MEM_REGION_REF_T mem, INT32U off, INT32U * pMMUTable);
|
||||
static void FTTSet (INT32U va, INT32U descr, INT32U * pMMUTable);
|
||||
static INT32U FTTGet (INT32U va, INT32U * pMMUTable);
|
||||
static INT32U FTTDescr (PAR_MEM_REGION_REF_T mem, INT32U offset, INT32U type, INT32U tbl);
|
||||
static void MMUEnable (INT32U * pMMUTable);
|
||||
static void MMUSwitchContext (INT32U id);
|
||||
|
||||
/*
|
||||
****************************************************************************************************
|
||||
* FUNCTIONS
|
||||
****************************************************************************************************
|
||||
*/
|
||||
|
||||
/*------------------------------------------------------------------------------------------------*/
|
||||
/*!
|
||||
* \brief INIT THE MMU
|
||||
*
|
||||
* \ingroup PAR_CPU_MMU
|
||||
*
|
||||
* This function initialize the target specific MMU
|
||||
*
|
||||
* \note The integrator must supply the contents of the PARErrLogging() function to handle
|
||||
* possible error conditions.
|
||||
*/
|
||||
/*------------------------------------------------------------------------------------------------*/
|
||||
MMU_ERR_T MMUInit (void)
|
||||
{
|
||||
INT32U n; /* Local: loop counter */
|
||||
MMU_ERR_T err = MMU_ERR_NONE;
|
||||
|
||||
Mem_Clr(&MMUTable,FTT_SIZE * sizeof(CPU_WORD_SIZE_32));
|
||||
|
||||
for(n = 0; n < sizeof(PARMemTbl_Core)/sizeof(PAR_MEM_REGION_T); n++){
|
||||
err = MMUTblAdd((PAR_MEM_REGION_REF_T)&PARMemTbl_Core[n], &MMUTable);
|
||||
if(err != MMU_ERR_NONE)
|
||||
return err;
|
||||
}
|
||||
|
||||
MMUEnable(&MMUTable); /* Enable the MMU */
|
||||
|
||||
return MMU_ERR_NONE;
|
||||
}
|
||||
|
||||
/*
|
||||
****************************************************************************************************
|
||||
* LOCAL FUNCTIONS
|
||||
****************************************************************************************************
|
||||
*/
|
||||
|
||||
/*------------------------------------------------------------------------------------------------*/
|
||||
/*!
|
||||
* \brief MMU TABLE CONSTRUCTION
|
||||
*
|
||||
* \ingroup PAR_CPU_MMU
|
||||
*
|
||||
* This function constructs the needed table entries for a single user defined memory
|
||||
* region with the following rules:
|
||||
*
|
||||
* - build user memory size with blocks of 4K, 64K and 1M portions
|
||||
*
|
||||
* - ensure that each block is aligned at size (4K Block is aligned at 4K boundary, etc.)
|
||||
*
|
||||
* \param mem Reference to memory region
|
||||
*
|
||||
* \note Memory portions below 1KB will be ignored, because the MMU granularity starts with 1kB
|
||||
*/
|
||||
/*------------------------------------------------------------------------------------------------*/
|
||||
static MMU_ERR_T MMUTblAdd(const PAR_MEM_REGION_REF_T mem, INT32U * pMMUTable)
|
||||
{
|
||||
INT32U vaddr; /* Local: virtual address */
|
||||
INT32U off; /* Local: offset in memory region */
|
||||
INT32U size; /* Local: remaining size of memory region */
|
||||
MMU_ERR_T err = MMU_ERR_NONE;
|
||||
/*------------------------------------------*/
|
||||
vaddr = mem->VA_Start; /* set virtual memory address */
|
||||
size = mem->Size; /* set size to memory region size */
|
||||
off = 0; /* set memory region offset to 0 */
|
||||
|
||||
if ((vaddr & (MMU_SIZE_1MB - 1)) != 0) { /* see, if VA is not aligned at 4k */
|
||||
return MMU_ERR_ALIGN;
|
||||
}
|
||||
if ((size % MMU_SIZE_1MB) != 0) { /* see, if size is not multiple of 4k */
|
||||
return MMU_ERR_SIZE;
|
||||
}
|
||||
|
||||
while(size >= MMU_SIZE_1MB) { /* create section for memory region */
|
||||
err = MMUTblAdd1M(mem, off, pMMUTable); /* add a 1M section */
|
||||
if(err != MMU_ERR_NONE)
|
||||
return err;
|
||||
vaddr += MMU_SIZE_1MB; /* update virtual address and */
|
||||
off += MMU_SIZE_1MB; /* offset and */
|
||||
size -= MMU_SIZE_1MB; /* remaining bytes in memory region */
|
||||
}
|
||||
|
||||
return MMU_ERR_NONE;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------------------------------*/
|
||||
/*!
|
||||
* \brief INSERT 1M SECTION IN MMU TABLE
|
||||
*
|
||||
* \ingroup PAR_CPU_MMU
|
||||
*
|
||||
* This function constructs the needed table entries for a single 1M memory block.
|
||||
*
|
||||
* \param mem Reference to memory region
|
||||
*
|
||||
* \param off Offset within the referenced memory region
|
||||
*/
|
||||
/*------------------------------------------------------------------------------------------------*/
|
||||
static MMU_ERR_T MMUTblAdd1M(PAR_MEM_REGION_REF_T mem, INT32U off, INT32U * pMMUTable)
|
||||
{
|
||||
INT32U vaddr; /* Local: virtual address */
|
||||
INT32U descr; /* Local: translation table descriptor */
|
||||
INT32U type; /* Local: descriptor type information */
|
||||
/*------------------------------------------*/
|
||||
vaddr = mem->VA_Start + off; /* calculate virtual address */
|
||||
type = FTTGet(vaddr, pMMUTable) & FTT_TYPE; /* get descriptor type */
|
||||
|
||||
if (type != FTT_TYPE_FLT) { /* see, if section is already in use */
|
||||
return MMU_ERR_ENTRY_IN_USE;
|
||||
}
|
||||
|
||||
descr = FTTDescr(mem, off, FTT_TYPE_SEC, 0); /* construct first level section descr. */
|
||||
FTTSet(vaddr, descr, pMMUTable); /* set section for virtual address */
|
||||
return MMU_ERR_NONE;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------------------------------*/
|
||||
/*!
|
||||
* \brief SET FIRST LEVEL TRANSLATION TABLE DESCRIPTOR
|
||||
*
|
||||
* \ingroup PAR_CPU_MMU
|
||||
*
|
||||
* This function sets the given descriptor in the first level translation table
|
||||
* which corresponds to the given virtual address.
|
||||
*
|
||||
* \param va Virtual Address
|
||||
*
|
||||
* \param descr First level descriptor
|
||||
*/
|
||||
/*------------------------------------------------------------------------------------------------*/
|
||||
static void FTTSet(INT32U va, INT32U descr, INT32U * pMMUTable)
|
||||
{
|
||||
volatile INT32U *tbl; /* Local: ptr to first level table entry */
|
||||
INT32U tbl_idx; /* Local: first level table index */
|
||||
/*------------------------------------------*/
|
||||
tbl_idx = (va >> 20) & 0x00000FFF; /* get table index out of virtual address */
|
||||
tbl = pMMUTable + tbl_idx; /* set first level table base address */
|
||||
/*------------------------------------------*/
|
||||
*tbl = descr; /* set descriptor in first level table */
|
||||
dsb();
|
||||
isb();
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------------------------------*/
|
||||
/*!
|
||||
* \brief GET FIRST LEVEL TRANSLATION TABLE DESCRIPTOR
|
||||
*
|
||||
* \ingroup PAR_CPU_MMU
|
||||
*
|
||||
* This function returns the first level translation table descriptor of the given
|
||||
* virtual address.
|
||||
*
|
||||
* \param va Virtual Address
|
||||
*
|
||||
* \return The current active descriptor is returned.
|
||||
*/
|
||||
/*------------------------------------------------------------------------------------------------*/
|
||||
static INT32U FTTGet(INT32U va, INT32U * pMMUTable)
|
||||
{
|
||||
volatile INT32U *tbl; /* Local: ptr to first level table entry */
|
||||
INT32U tbl_idx; /* Local: first level table index */
|
||||
/*------------------------------------------*/
|
||||
tbl_idx = (va >> 20) & 0x00000FFF; /* get table index out of virtual address */
|
||||
tbl = pMMUTable + tbl_idx; /* set first level table base address */
|
||||
/*------------------------------------------*/
|
||||
return (*tbl); /* get descriptor in first level table */
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------------------------------*/
|
||||
/*!
|
||||
* \brief CONSTRUCT FIRST LEVEL TRANSLATION TABLE DESCRIPTOR
|
||||
*
|
||||
* \ingroup PAR_CPU_MMU
|
||||
*
|
||||
* This function constructs the first level translation table descriptor of the given
|
||||
* type for the offset within the memory region.
|
||||
*
|
||||
* \param mem Reference to memory region
|
||||
*
|
||||
* \param offset Offset within the referenced memory region
|
||||
*
|
||||
* \param type Type information (section / coarse page / fine page / fault)
|
||||
*
|
||||
* \param base Base address of page table
|
||||
*
|
||||
* \return For the types FTT_TYPE_SEC, FTT_TYPE_CPT and FTT_TYPE_FPT, the
|
||||
* corresponding table descriptor is returned. For any other type, the return value is
|
||||
* the table descriptor for FTT_TYPE_FLT.
|
||||
*
|
||||
* \see FTT_TYPE_FLT, FTT_TYPE_CPT, FTT_TYPE_SEC, FTT_TYPE_FPT
|
||||
*/
|
||||
/*------------------------------------------------------------------------------------------------*/
|
||||
static INT32U FTTDescr(PAR_MEM_REGION_REF_T mem, INT32U offset, INT32U type, INT32U base)
|
||||
{
|
||||
INT32U result = 0; /* Local: function result */
|
||||
INT32U pa; /* Local: physical address */
|
||||
|
||||
switch(type){
|
||||
case FTT_TYPE_SEC:
|
||||
pa = mem->PA_Start + offset; /* yes: calculate physical address */
|
||||
result = FTT_TYPE_SEC | /* set descriptor type to section */
|
||||
((mem->HID & PAR_HID_CB_MASK) << 2u) | /* cachable & bufferable flag */
|
||||
((mem->HID & PAR_HID_F_XN) >> 6u) | /* Execute-Never Flag */
|
||||
((PAR_DOMAIN_MASTER) << 5) | /* owner = domain */
|
||||
((mem->AP & 0x3) << 10u) | /* access permissions AP0 and AP1 */
|
||||
((mem->AP & 0x4) << 13u) | /* access permissions AP2 */
|
||||
((mem->HID & PAR_HID_TEX_MASK) << 10u) | /* TEX attributes */
|
||||
((mem->HID & PAR_HID_F_S) << 8u) | /* shareable-flag */
|
||||
((mem->HID & PAR_HID_F_NG) << 8u) | /* Non-Global-Flag */
|
||||
((mem->HID & PAR_HID_F_NS) << 8u) | /* non-secure bit */
|
||||
(pa & 0xFFF00000); /* bits[31:20] of physical address */
|
||||
break;
|
||||
case FTT_TYPE_PT:
|
||||
case FTT_TYPE_FLT:
|
||||
case FTT_TYPE_RES:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------------------------------*/
|
||||
/*!
|
||||
* \brief ENABLE MMU
|
||||
*
|
||||
* \ingroup PAR_CPU_MMU
|
||||
*
|
||||
* This function enables the MMU.
|
||||
*
|
||||
* \note The first level translation table and the page tables must be initialized before
|
||||
* calling this function.
|
||||
*/
|
||||
/*------------------------------------------------------------------------------------------------*/
|
||||
static void MMUEnable(INT32U * pMMUTable)
|
||||
{
|
||||
INT32U ctrl; /* Local: control register */
|
||||
|
||||
//Invalidate data and instruction cache
|
||||
Xil_DCacheDisable();
|
||||
|
||||
__set_mmu_table(((INT32U)pMMUTable & 0xFFFFC000) | PAR_TTBR0_FLAGS); /* Set first level transl. table base addr. */
|
||||
|
||||
__set_domain_control(0x55555555u); /* set all domains to client */
|
||||
//eo verwenden noch PD1 = 1 für tlb miss in TTBR1 wird zu translation fault.
|
||||
__set_asid(0 & 0xFF);
|
||||
__set_mmu_control(0x00000000); /* Set TTBCR to 0 -> Use TTBR0 and 14Bit alignment */
|
||||
|
||||
__clr_mmu_fault();
|
||||
|
||||
__dsb();
|
||||
|
||||
__invalidate_tlb();
|
||||
__invalidate_branchpred();
|
||||
__dsb();
|
||||
__isb();
|
||||
|
||||
|
||||
|
||||
ctrl = __get_sys_control(); /* get current control register */
|
||||
ctrl |= MMU_SCTLR_FLAGS; /* set I,C,S and M to enable MMU */
|
||||
__set_sys_control(ctrl); /* write new control register */
|
||||
/*------------------------------------------*/
|
||||
__no_operation(); /* perform 2 flat fetches */
|
||||
__no_operation();
|
||||
|
||||
#if (UCOS_AMP_MASTER == DEF_ENABLED)
|
||||
// /* Enable L2 Cache */
|
||||
// This is a "mandatory" step, don't now why, see Zynq Reference manual
|
||||
*((CPU_INT32U*)0xF8000A1C) = 0x020202;
|
||||
|
||||
Xil_L2CacheEnable();
|
||||
/* set L2 Aux register */
|
||||
// CPU_INT32U dat = *((CPU_INT32U*)0xF8F02104);
|
||||
// dat = 0x72760000;
|
||||
// *((CPU_INT32U*)0xF8F02104) = dat;
|
||||
// // /* Set all latencies of tag-ram to 2 */
|
||||
// // *((CPU_INT32U*)0xF8F02108) = 0x00000111;
|
||||
// // /* set data ram write and setup latencies to 2, data ram read to 3 */
|
||||
// // *((CPU_INT32U*)0xF8F0210C) = 0x00000121;
|
||||
// // /* set prefetch conrtol register */
|
||||
// // *((CPU_INT32U*)0xF8F02F60) = 0x30000000;
|
||||
// /* enable L2 Cache */
|
||||
// *((CPU_INT32U*)0xF8F02100) = 0x1;
|
||||
#endif
|
||||
CPU_INT32U actlr = __get_actlr();
|
||||
actlr &= ~(0x00000040);
|
||||
__set_actlr(actlr);
|
||||
/*--- MMU/address translation is enabled ---*/
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------------------------------*/
|
||||
/*!
|
||||
* \brief Switch Address Space
|
||||
*
|
||||
* \ingroup PAR_CPU_MMU
|
||||
*
|
||||
* This function switches the address space and manipulates the virt->phys translation.
|
||||
*
|
||||
* \param id Partition ID
|
||||
*/
|
||||
/*------------------------------------------------------------------------------------------------*/
|
||||
|
||||
static void MMUSwitchContext(INT32U id)
|
||||
{
|
||||
|
||||
CPU_INT32U cpu_sr = 0;
|
||||
/*------------------------------------------*/
|
||||
OS_ENTER_CRITICAL(); /* Enter critical section */
|
||||
//We don't need to flush caches, when for all shared memory regions the L1 cache policy is correct write through or disabled
|
||||
// __flush_caches(); /* Flush caches */
|
||||
// MMU_DCacheClean();
|
||||
//We don't need to invalidate the tlb, beacuase we have the ASID value corresponding to a partition
|
||||
// __invalidate_tlb(); /* Invalidate TLB */
|
||||
|
||||
__dsb();
|
||||
__set_asid(id & 0xFF);
|
||||
__set_mmu_table(((INT32U)MMUTable & 0xFFFFC000) | PAR_TTBR0_FLAGS); /* Set first level transl. table base addr. */
|
||||
__dsb();
|
||||
__isb();
|
||||
OS_EXIT_CRITICAL(); /* Exit critical section */
|
||||
/*------------------------------------------*/
|
||||
}
|
||||
Reference in New Issue
Block a user