📄 mmu405lib.c
字号:
/* mmu405Lib.c - mmu library for PowerPC 405 series *//* Copyright 1984-2002 Wind River Systems, Inc. */#include "copyright_wrs.h"/*modification history--------------------01e,25apr02,pch SPR 74926: don't connect to unused vector01d,17apr02,jtp use common identifier names with PPC44001c,07dec01,jtp SPR #67973 add exception message for MMU config failure01b,22nov00,s_m changes due to changed prototype of mmuPpcTlbSearch01a,17jul00,sm written.*//*DESCRIPTION:mmu405Lib.c provides the architecture dependent routines that directlycontrol the memory management unit for the PowerPC 405 series. It provides routines that are called by the higher level architecture independent routines in vmLib.c or vmBaseLib.c.*//* includes */#include "vxWorks.h"#include "cacheLib.h"#include "errno.h"#include "intLib.h"#include "stdlib.h"#include "stdio.h"#include "string.h"#include "vmLib.h"#include "sysLib.h"#include "private/memPartLibP.h"#include "private/vmLibP.h"#include "arch/ppc/excPpcLib.h"#include "arch/ppc/vxPpcLib.h"#include "arch/ppc/mmu405Lib.h"/* defines */#define PAGE_SIZE 4096 /* page size of 4K *//* locals */LOCAL STATE_TRANS_TUPLE mmuStateTransArrayLocal [] = { {VM_STATE_MASK_VALID, MMU_STATE_MASK_VALID, VM_STATE_VALID, MMU_STATE_VALID}, {VM_STATE_MASK_VALID, MMU_STATE_MASK_VALID, VM_STATE_VALID_NOT, MMU_STATE_VALID_NOT}, {VM_STATE_MASK_WRITABLE, MMU_STATE_MASK_WRITABLE, VM_STATE_WRITABLE, MMU_STATE_WRITABLE}, {VM_STATE_MASK_WRITABLE, MMU_STATE_MASK_WRITABLE, VM_STATE_WRITABLE_NOT, MMU_STATE_WRITABLE_NOT}, {VM_STATE_MASK_CACHEABLE, MMU_STATE_MASK_CACHEABLE, VM_STATE_CACHEABLE, MMU_STATE_CACHEABLE}, {VM_STATE_MASK_CACHEABLE, MMU_STATE_MASK_CACHEABLE, VM_STATE_CACHEABLE_NOT, MMU_STATE_CACHEABLE_NOT}, {VM_STATE_MASK_CACHEABLE, MMU_STATE_MASK_CACHEABLE, VM_STATE_CACHEABLE_WRITETHROUGH, MMU_STATE_CACHEABLE_WRITETHROUGH}, {VM_STATE_MASK_GUARDED, MMU_STATE_MASK_GUARDED, VM_STATE_GUARDED, MMU_STATE_GUARDED}, {VM_STATE_MASK_GUARDED, MMU_STATE_MASK_GUARDED, VM_STATE_GUARDED_NOT, MMU_STATE_GUARDED_NOT} };LOCAL MMU_TRANS_TBL * mmu405TransTblCreate ();LOCAL STATUS mmu405TransTblDelete (MMU_TRANS_TBL *transTbl);LOCAL STATUS mmu405Enable (BOOL enable);LOCAL STATUS mmu405StateSet (MMU_TRANS_TBL *transTbl, void *pageAddr, UINT stateMask, UINT state);LOCAL STATUS mmu405StateGet (MMU_TRANS_TBL *transTbl, void *pageAddr, UINT *state);LOCAL STATUS mmu405PageMap (MMU_TRANS_TBL *transTbl, void * virtualAddress, void *physPage);LOCAL STATUS mmu405GlobalPageMap (void * virtualAddress, void * physPage);LOCAL STATUS mmu405Translate (MMU_TRANS_TBL * transTbl, void * virtAddress, void ** physAddress);LOCAL void mmu405CurrentSet (MMU_TRANS_TBL * transTbl);LOCAL STATUS mmu405TransTblInit (MMU_TRANS_TBL * pNewTransTbl);LOCAL LEVEL_1_DESC * mmu405Lvl1DescAddrGet (MMU_TRANS_TBL * pTransTbl, void * effectiveAddr);LOCAL STATUS mmu405Lvl2DescAddrGet (MMU_TRANS_TBL * pTransTbl, void * effectiveAddr, LEVEL_2_DESC ** ppLvl2Desc);LOCAL void mmu405Lvl1DescUpdate (LEVEL_1_DESC * pLvl1Desc, LEVEL_1_DESC lvl1Desc);LOCAL void mmu405Lvl2DescUpdate (LEVEL_2_DESC * pLvl2Desc, LEVEL_2_DESC lvl2Desc);LOCAL BOOL mmu405IsOn (int mmuType);LOCAL UINT8 mmu405GetNewPid (MMU_TRANS_TBL *transTbl);LOCAL void mmu405FreePid (UINT8 pid);LOCAL void mmu405Tlbie (MMU_TRANS_TBL *pTransTbl, void * effAddr);IMPORT void mmuPpcPidSet (UINT8 pid);IMPORT UINT32 mmuPpcPidGet (void);IMPORT void mmuPpcTlbInvalidateAll (void);IMPORT void mmuPpcZprSet (UINT32 zprVal);IMPORT UINT32 mmuPpcTlbReadEntryHi (UINT32 index);IMPORT UINT32 mmuPpcTlbReadEntryLo (UINT32 index);IMPORT int mmuPpcTlbSearch (void * effAddr);IMPORT void mmuPpcTlbWriteEntryHi (UINT32 index, UINT32 tlbhi);IMPORT void mmuPpcTlbWriteEntryLo (UINT32 index, UINT32 tlblo);IMPORT void mmuPpcAEnable ();IMPORT void mmuPpcADisable ();IMPORT void mmuPpcInstTlbMissHandler();IMPORT void mmuPpcDataTlbMissHandler();IMPORT STATE_TRANS_TUPLE * mmuStateTransArray;IMPORT int mmuStateTransArraySize;IMPORT MMU_LIB_FUNCS mmuLibFuncs;IMPORT int mmuPageBlockSize;/* * a translation table to hold the descriptors for the global transparent * translation of physical to virtual memory */MMU_TRANS_TBL mmuGlobalTransTbl; /* global translation table */ /* * An array 256 translation table pointers is allocated to store upto * 255 (entry 0 unused) unique address maps * This array is indexed by the PID value. A value of -1 denotes an * unused entry. */MMU_TRANS_TBL * mmuAddrMapArray [MMU_ADDR_MAP_ARRAY_SIZE];/* the global map's PID index into above array (should be equal to 1) */UINT8 mmuGlobalMapPid;/* tlb replacement counter: we use a round-robin strategy to determine * which tlb entry to replace. The following variable is used by the * TLB miss handlers to determine which TLB (0..63) to replace in the * event of a TLB miss. */UINT32 mmuPpcTlbNext;#ifdef DEBUG_MISS_HANDLERUINT32 mmuPpcITlbMisses;UINT32 mmuPpcITlbMissArray[256];UINT32 mmuPpcDTlbMisses;UINT32 mmuPpcDTlbMissArray[256];UINT32 mmuPpcITlbErrors;UINT32 mmuPpcDTlbErrors;#endif /* DEBUG_MISS_HANDLER */LOCAL UINT32 mmu405Selected; /* mmu type selected */LOCAL MMU_LIB_FUNCS mmuLibFuncsLocal = { mmu405LibInit, mmu405TransTblCreate, mmu405TransTblDelete, mmu405Enable, mmu405StateSet, mmu405StateGet, mmu405PageMap, mmu405GlobalPageMap, mmu405Translate, mmu405CurrentSet };/******************************************************************************** mmu405LibInit - MMU library initialization** RETURNS: OK, or ERROR if <mmuType> is incorrect or memory allocation failed. */STATUS mmu405LibInit ( int mmuType /* data and/or instruction MMU to initialize */ ) { /* check if the MMU type to initialize is coherent */ if (!(mmuType & MMU_INST) && !(mmuType & MMU_DATA)) { /* * too soon in boot process to print a string, so store one in the * exception message area. */ strcpy(sysExcMsg, "405 MMU config failed: either enable I or D MMU, " "or remove MMU support\n"); return (ERROR); } /* save the Data and/or Instruction MMU selected */ mmu405Selected = mmuType; /* initialize the exception table: * At the exception offset, we put a branch instruction (0x48000002) * OR'ed with the address of the TLB miss handler. */ if (mmuType & MMU_INST) { if ((UINT32)mmuPpcInstTlbMissHandler > 0x03fffffc) { strcpy(sysExcMsg, "405 MMU config failed: TLB miss handler " "is too far from the vector table\n"); return (ERROR); } * (int *) _EXC_OFF_INST_MISS = 0x48000002 | (((int) mmuPpcInstTlbMissHandler) & 0x03fffffc); CACHE_TEXT_UPDATE((void *)_EXC_OFF_INST_MISS, sizeof(int)); } if (mmuType & MMU_DATA) { if ((UINT32)mmuPpcDataTlbMissHandler > 0x03fffffc) { strcpy(sysExcMsg, "405 MMU config failed: TLB miss handler " "is too far from the vector table\n"); return (ERROR); } * (int *) _EXC_OFF_DATA_MISS = 0x48000002 | (((int) mmuPpcDataTlbMissHandler) & 0x03fffffc); CACHE_TEXT_UPDATE((void *)_EXC_OFF_DATA_MISS, sizeof(int)); } /* initialize the address map array: a value of -1 denotes an unused element. */ memset ((void *) mmuAddrMapArray, (int)MMU_ADDR_MAP_ARRAY_INV, sizeof (mmuAddrMapArray)); /* get a PID element for the global map */ mmuGlobalMapPid = mmu405GetNewPid (&mmuGlobalTransTbl); if (mmuGlobalMapPid == 0) /* no free PIDs ! */ return (ERROR); mmuGlobalTransTbl.pid = mmuGlobalMapPid; /* allocate a piece of memory to handle the level 1 Table. This memory * needs to be page aligned because, we write protect all the page * tables later, and we don't want other variables sharing a page with * the page table itself. */ mmuGlobalTransTbl.l1TblPtr.pL1Desc = (LEVEL_1_DESC *) memalign (PAGE_SIZE, PAGE_SIZE); /* check the memory allocation */ if (mmuGlobalTransTbl.l1TblPtr.pL1Desc == NULL) { mmu405FreePid (mmuGlobalMapPid); return (ERROR); } /* invalidate all entries in the table */ memset ((void *) mmuGlobalTransTbl.l1TblPtr.pL1Desc, 0x00, PAGE_SIZE); /* initialize the PID register , and invalidate all TLB entries */ mmuPpcPidSet (mmuGlobalMapPid); mmuPpcTlbInvalidateAll(); /* initialize the Zone protection register so that for all zones * access is controlled by EX and WR for both user and supervisor * states. */ mmuPpcZprSet (MMU_ZPR_INIT_VAL); /* initialize the data objects that are shared with vmLib.c */ mmuStateTransArray = &mmuStateTransArrayLocal [0]; mmuStateTransArraySize = sizeof (mmuStateTransArrayLocal) / sizeof (STATE_TRANS_TUPLE); mmuLibFuncs = mmuLibFuncsLocal; /* initialize the TLB replacement counter to zero. */ mmuPpcTlbNext = 0; mmuPageBlockSize = PAGE_SIZE; return (OK); }#if FALSE/******************************************************************************** mmu405MemPagesWriteEnable - write enable the memory holding PTEs** Each translation table has a linked list of physical pages that contain its* table and page descriptors. Before you can write into any descriptor, you* must write enable the page it is contained in. This routine enables all* the pages used by a given translation table.**/LOCAL STATUS mmu405MemPagesWriteEnable ( MMU_TRANS_TBL * pTransTbl ) { int ix; LEVEL_1_DESC lvl1Desc; /* we need to enable writes on the level 1 page table and each level 2 * page table. The level 1 page table is PAGE_SIZE in size, whereas * the level 2 page table is 2 * PAGE_SIZE in size. */ /* write enable the level 1 page table */ mmu405StateSet (pTransTbl, (void *)pTransTbl->l1TblPtr.pL1Desc, MMU_STATE_MASK_WRITABLE, MMU_STATE_WRITABLE); /* go thru the L 1 table and write enable each L 2 table */ for (ix = 0 ; ix < MMU_LVL_2_DESC_NB; ix++) { lvl1Desc = * (pTransTbl->l1TblPtr.pL1Desc + ix); if (lvl1Desc.field.v) { mmu405StateSet (pTransTbl, (void *)(lvl1Desc.field.l2ba << 2), MMU_STATE_MASK_WRITABLE, MMU_STATE_WRITABLE); mmu405StateSet (pTransTbl, (void *)((lvl1Desc.field.l2ba << 2) + PAGE_SIZE), MMU_STATE_MASK_WRITABLE, MMU_STATE_WRITABLE); } } return (OK); }#endif/******************************************************************************** mmu405MemPagesWriteDisable - write disable memory holding PTEs** Memory containing translation table descriptors is marked as read only* to protect the descriptors from being corrupted. This routine write protects* all the memory used to contain a given translation table's descriptors.** RETURNS: N/A*/LOCAL void mmu405MemPagesWriteDisable ( MMU_TRANS_TBL * pTransTbl ) { int ix; LEVEL_1_DESC lvl1Desc; /* we need to disable writes on the level 1 page table and each level 2 * page table. The level 1 page table is PAGE_SIZE in size, whereas * the level 2 page table is 2 * PAGE_SIZE in size. */ /* write protect the level 1 page table */ mmu405StateSet (pTransTbl, (void *)pTransTbl->l1TblPtr.pL1Desc, MMU_STATE_MASK_WRITABLE, MMU_STATE_WRITABLE_NOT); /* go thru the L 1 table and write protect each L 2 table */ for (ix = 0 ; ix < MMU_LVL_2_DESC_NB; ix++) { lvl1Desc = * (pTransTbl->l1TblPtr.pL1Desc + ix); if (lvl1Desc.field.v) { mmu405StateSet (pTransTbl, (void *)(lvl1Desc.field.l2ba << 2), MMU_STATE_MASK_WRITABLE, MMU_STATE_WRITABLE_NOT); } } }/******************************************************************************** mmu405TransTblCreate - create a new translation table.** RETURNS: address of new object or NULL if allocation failed.*/LOCAL MMU_TRANS_TBL * mmu405TransTblCreate ( ) { MMU_TRANS_TBL * pNewTransTbl; /* allocate a piece of memory to save the new translation table */ pNewTransTbl = (MMU_TRANS_TBL *) malloc (sizeof (MMU_TRANS_TBL)); /* if the memory can not allocated then return the NULL pointer */ if (pNewTransTbl == NULL) return (NULL); /* get a free PID for the new translation table */ pNewTransTbl->pid = mmu405GetNewPid (pNewTransTbl); if (pNewTransTbl->pid == 0) /* no free PIDs ! */ { free ((char *) pNewTransTbl); return (NULL); } /* * initialize the new translation table. * If the initialization fails then free the memory and return the NULL * pointer. */ if (mmu405TransTblInit (pNewTransTbl) == ERROR) { free ((char *) pNewTransTbl); return (NULL); } /* return the new translation table created */ return (pNewTransTbl); }/******************************************************************************
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -