📄 mmue500lib.c
字号:
return 0; }/********************************************************************************* mmuE500PidFree - Free (mark as invalid) the pid entry** NOTE: For MMU library internal use only**/LOCAL void mmuE500PidFree (UINT8 pid) { mmuAddrMapArray [pid] = MMU_ADDR_MAP_ARRAY_INV; }/********************************************************************************* mmuE500TlbStaticEntrySet - write a static TLB entry** This function writes one MMU TLB Entry based on the given TLB Entry* Description.** CAVEAT: If previously-enabled caching is being disabled, the caller must* pre-flush or pre-invalidate the appropriate cache lines prior to calling* this function.** NOTE: For MMU library internal use only.**/LOCAL void mmuE500TlbStaticEntrySet ( int index, /* index of TLB Entry to set */ TLB_ENTRY_DESC * pTlbDesc, /* description of TLB Entry to set */ BOOL cacheAllow /* if TRUE allow caching to be turned on */ ) { LEVEL_2_DESC lvl2Desc; /* TLB entry */ /* * fill in all fields of a LEVEL_2_DESC with data from the * TLB_ENTRY_DESC. Use that to write the TLB Entry words. */ lvl2Desc.field.epn = pTlbDesc->effAddr >> MMU_RPN_SHIFT; lvl2Desc.field.rsvd1 = 0; lvl2Desc.field.v = 1; /* valid */ lvl2Desc.field.iprot = ((pTlbDesc->attr & _MMU_TLB_IPROT) ? 1 : 0); lvl2Desc.field.ts = ((pTlbDesc->attr & _MMU_TLB_TS_1) ? 1 : 0); lvl2Desc.field.tsize = ((pTlbDesc->attr & _MMU_TLB_SZ_MASK) >> _MMU_TLB_SZ_SHIFT); lvl2Desc.field.rsvd2 = 0; lvl2Desc.field.rpn = pTlbDesc->realAddr >> MMU_RPN_SHIFT; lvl2Desc.field.rsvd3 = 0; lvl2Desc.field.tid = 0; lvl2Desc.field.rsvd4 = 0; lvl2Desc.field.u0 = 0; /* user attribute 0 unused */ lvl2Desc.field.u1 = 0; /* user attribute 1 unused */ lvl2Desc.field.u2 = 0; /* user attribute 2 unused */ lvl2Desc.field.u3 = 0; /* user attribute 3 unused */ if (cacheAllow == TRUE) { /* cache as desired */ lvl2Desc.field.w = (pTlbDesc->attr & _MMU_TLB_ATTR_W ? 1 : 0); lvl2Desc.field.i = (pTlbDesc->attr & _MMU_TLB_ATTR_I ? 1 : 0); } else { /* cache inhibited -- warning, caller must preflush if necessary */ lvl2Desc.field.w = 0; lvl2Desc.field.i = 1; } lvl2Desc.field.m = (pTlbDesc->attr & _MMU_TLB_ATTR_M ? 1 : 0); lvl2Desc.field.g = (pTlbDesc->attr & _MMU_TLB_ATTR_G ? 1 : 0); lvl2Desc.field.e = 0; /* big endian */ lvl2Desc.field.rsvd5 = 0; lvl2Desc.field.ux = 0; /* user execute off */ lvl2Desc.field.uw = 0; /* user write off */ lvl2Desc.field.ur = 0; /* user read off */ lvl2Desc.field.sx = (pTlbDesc->attr & _MMU_TLB_PERM_X ? 1 : 0); lvl2Desc.field.sw = (pTlbDesc->attr & _MMU_TLB_PERM_W ? 1 : 0); lvl2Desc.field.sr = 1; /* supervisor read on */ lvl2Desc.field.rsvd6 = 0; /* write current entry -- uses MMUCR[STID] as a side effect */ _WRS_ASM("sync"); mmuPpcTlbWriteEntryWord0 ((UINT32)lvl2Desc.words.word0); mmuPpcTlbWriteEntryWord1 ((UINT32)lvl2Desc.words.word1); mmuPpcTlbWriteEntryWord2 ((UINT32)lvl2Desc.words.word2); mmuPpcTlbWriteExecute(((index << _PPC_MAS0_ESEL_BIT) & _PPC_MAS0_ESEL_MASK) | _PPC_MAS0_TLBSEL1); }/********************************************************************************* mmuE500TlbStaticInit - initialize all static TLB entries** This function initializes MMU TLB Entries from the supplied array of* TLB Entry Descriptions.** CAVEAT: If previously-enabled caching is being disabled, the caller must* pre-flush or pre-invalidate the appropriate cache lines prior to calling* this function.** NOTE: For MMU library internal use only.**/void mmuE500TlbStaticInit ( int numDescs, /* number of TLB Entry Descriptors */ TLB_ENTRY_DESC * pTlbDesc, /* pointer to array of TLB Entries */ BOOL cacheAllow /* if TRUE, caching will be enabled */ ) { UINT32 index; /* current index being init'ed */ for (index = 0; index < numDescs; index++, pTlbDesc++) mmuE500TlbStaticEntrySet(index, pTlbDesc, cacheAllow); }/******************************************************************************** mmuE500StateSet - set state of virtual memory page*** MMU_STATE_VALID MMU_STATE_VALID_NOT valid/invalid* MMU_STATE_WRITABLE MMU_STATE_WRITABLE_NOT writable/writeprotected* MMU_STATE_CACHEABLE MMU_STATE_CACHEABLE_NOT cachable/notcachable* MMU_STATE_CACHEABLE_WRITETHROUGH* MMU_STATE_CACHEABLE_COPYBACK* MMU_STATE_GUARDED MMU_STATE_GUARDED_NOT guarded/un-guarded** RETURNS: OK, or ERROR if descriptor address does not exist.*/LOCAL STATUS mmuE500StateSet ( MMU_TRANS_TBL * pTransTbl, /* translation table */ void * effectiveAddr, /* page whose state to modify */ UINT stateMask, /* mask of which state bits to modify */ UINT state /* new state bit values */ ) { LEVEL_2_DESC * pLvl2Desc; /* level 2 descriptor address */ LEVEL_2_DESC lvl2Desc; /* level 2 descriptor */ BOOL flush = FALSE; /* page must be flushed from cache */ /* * get the level 2 descriptor address. If this descriptor address doesn't * exist then set errno and return ERROR. */ if (mmuE500Lvl2DescAddrGet (pTransTbl, effectiveAddr, &pLvl2Desc) == ERROR) { errno = S_mmuLib_NO_DESCRIPTOR; return (ERROR); } /* make a working copy of the Level 2 Descriptor */ lvl2Desc = *pLvl2Desc; if (stateMask & MMU_STATE_MASK_CACHEABLE) { /* * Check if the state to set page corresponding to <effectiveAddr> * will not set the cache inhibited and writethrough mode. This mode * is not supported by the cache. */ if ((state & MMU_STATE_CACHEABLE_NOT) && (state & MMU_STATE_CACHEABLE_WRITETHROUGH)) { return (ERROR); } /* * if the page is presently COPYBACK, and we plan to set it to * cache inhibited or writeback, flush the page before continuing. */ if (lvl2Desc.field.v && ((lvl2Desc.words.word2 & MMU_STATE_MASK_CACHEABLE) == MMU_STATE_CACHEABLE_COPYBACK) && ((state & MMU_STATE_MASK_CACHEABLE) != MMU_STATE_CACHEABLE_COPYBACK)) { flush = TRUE; } } /* * set or reset the VALID bit if requested. Since the Valid bit * in MMU_STATE is in a different bit position than in the TLB Word 0, * we use an if statement to express the logic clearly rather than * use a complicated mixture of shift, or, and and. */ if (stateMask & MMU_STATE_MASK_VALID) { if (state & stateMask & MMU_STATE_MASK_VALID) lvl2Desc.field.v = 1; else lvl2Desc.field.v = 0; } /* * set or reset write/execute bits as requested. The write/execute bits * are not in the same bit positions in MMU_STATE as in TLB Word 2. * They are shifted left by 8 bits as compared to there position in TLB word 2 */ lvl2Desc.words.word2 &= ~(((stateMask & MMU_STATE_MASK_WRITABLE_EXECUTE) >> 8)); lvl2Desc.words.word2 |= (((state & stateMask & MMU_STATE_MASK_WRITABLE_EXECUTE) >> 8)); /* * set or reset the WIMG bits as requested. WIMG are in the same bit * positions in MMU_STATE as in TLB Word 2, so we can use bitwise arithmetic */ lvl2Desc.words.word1 &= ~(stateMask & MMU_STATE_MASK_WIMG); lvl2Desc.words.word1 |= (state & stateMask & MMU_STATE_MASK_WIMG); if (stateMask & MMU_STATE_MASK_GUARDED) { if (state & MMU_STATE_GUARDED) { lvl2Desc.field.ux = 0; /* user execute off */ lvl2Desc.field.sx = 0; /* supervisor execute off */ } else { lvl2Desc.field.ux = 0; /* user execute off */ lvl2Desc.field.sx = 1; /* supervisor execute on */ } } /* flush out any copyback data before we change the attribute mapping */ if (flush == TRUE) cacheArchFlush(DATA_CACHE, effectiveAddr, MMU_PAGE_SIZE); /* update the Level 2 Descriptor */ mmuE500Lvl2DescUpdate (pLvl2Desc, lvl2Desc); /* invalidate the tlb entry for this effective address */ mmuPpcE500Tlbie (pTransTbl, effectiveAddr); return (OK); }/******************************************************************************** mmuE500StateGet - get state of virtual memory page**/LOCAL STATUS mmuE500StateGet ( MMU_TRANS_TBL * pTransTbl, /* tranlation table */ void * effectiveAddr, /* page whose state we're querying */ UINT * state /* place to return state value */ ) { LEVEL_2_DESC * pLvl2Desc; /* level 2 descriptor address */ LEVEL_2_DESC lvl2Desc; /* level 2 descriptor */ /* * get the level 2 descriptor address. If this descriptor address doesn't * exist then set errno and return ERROR. */ if (mmuE500Lvl2DescAddrGet (pTransTbl, effectiveAddr, &pLvl2Desc) == ERROR) { errno = S_mmuLib_NO_DESCRIPTOR; return (ERROR); } /* make a working copy the Level 2 Descriptor */ lvl2Desc = *pLvl2Desc; /* * extract the state of the VALID, WIMG and EX, WR bits. */ * state = (lvl2Desc.field.v ? MMU_STATE_VALID : 0); * state |= lvl2Desc.words.word1 & MMU_STATE_MASK_WIMG; /* * Note that the writable & execute bits are in a different bit position in * L2 desc than in the MMU_STATE. */ * state |= ( (lvl2Desc.words.word2 & (MMU_STATE_MASK_WRITABLE_EXECUTE>>8)) << 8); return (OK); }/******************************************************************************** mmuE500CurrentSet - change active translation table** This function changes the virtual memory context by loading the PID* register with the PID value saved in the translation* table structure pointed to by <pTransTbl>.** RETURNS: N/A**/LOCAL void mmuE500CurrentSet ( MMU_TRANS_TBL * pTransTbl /* new active tranlation table */ ) { FAST int lockKey; /* intLock lock key */ static BOOL firstTime = TRUE; /* first time call flag */ if (firstTime) { /* * write protect all the pages containing the descriptors allocated for * the global translation table. Need to do this because when this * memory is allocated, the global translation table doesn't exist yet. */ mmuE500MemPagesWriteDisable (mmuGlobalTransTbl); mmuE500MemPagesWriteDisable (pTransTbl); firstTime = FALSE; } lockKey = intLock (); /* * save the PID value in the PID register via * mmuPpcPidSet(). If one or both MMUs are turned on then disable * the MMU, set the PID register and re-enable the MMU. */ if (mmuE500IsOn (MMU_INST) || mmuE500IsOn (MMU_DATA)) { mmuE500Enable (FALSE); /* disable the MMU */ mmuPpcPidSet (pTransTbl->pid); mmuE500Enable (TRUE); /* re-enable the MMU */ } else mmuPpcPidSet (pTransTbl->pid); intUnlock (lockKey); }/******************************************************************************** mmuE500Translate - translate a virtual address to a physical address** Traverse the translation table and extract the physical address for the* given virtual address from the level 2 descriptor corresponding to the* virtual address.** RETURNS: OK, or ERROR if no level 2 descriptor found for given virtual address.*/LOCAL STATUS mmuE500Translate ( MMU_TRANS_TBL * pTransTbl, /* translation table */ void * effectiveAddr, /* effective address */ void ** physicalAddr /* where to place the result */ ) { LEVEL_2_DESC * pLvl2Desc; /* Level 2 descriptor address */ EFFECTIVE_ADDR effAddr; /* effective address */ REAL_ADDRESS realAddr; /* real address */ /* * find the level 2 descriptor corresponding to the <effectiveAddr> * in the translation table pointed to by the <pTransTbl> structure. * If this level 2 descriptor cannot be found then return ERROR. */ if (mmuE500Lvl2DescAddrGet (pTransTbl, effectiveAddr, &pLvl2Desc) != OK) { errno = S_mmuLib_NO_DESCRIPTOR; return (ERROR); } /* check if the level 2 descriptor found is valid. If not return ERROR */ if (!pLvl2Desc->field.v) { errno = S_mmuLib_NO_DESCRIPTOR; return (ERROR); } effAddr = * ((EFFECTIVE_ADDR *) &effectiveAddr); /* build the real address */ realAddr.field.rpn = pLvl2Desc->field.rpn; realAddr.field.po = effAddr.field.po; * physicalAddr = realAddr.realAddr; return (OK); }/******************************************************************************** mmuE500MemPagesWriteDisable - 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 mmuE500MemPagesWriteDisable ( MMU_TRANS_TBL * pTransTbl /* Translation table to disable */ ) { int ix; /* index of L1 entries */ int jx; /* index into L2 table pages */ LEVEL_1_DESC lvl1Desc; /* current L1 descriptor */ /* we need to disable writes on the level 1 page table and each level 2 * page table. The level 1 page table is MMU_PAGE_SIZE in size, whereas * the level 2 page table is 4 * MMU_PAGE_SIZE in size. */ /* write protect the level 1 page table */ mmuE500StateSet (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) { for (jx = 0; jx < 4; jx++) { mmuE500StateSet (pTransTbl, (void *)((lvl1Desc.field.l2ba << 2) + (jx * MMU_PAGE_SIZE)), MMU_STATE_MASK_WRITABLE, MMU_STATE_WRITABLE_NOT); } } } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -