📄 mmu30lib.c
字号:
{ PTE *pagePte; volatile int oldIntLev; /* volatile hushes warnings */ BOOL wasEnabled; if (mmuPteGet (transTbl, pageAddr, &pagePte) != OK) return (ERROR); /* modify the pte with mmu turned off and interrupts locked out */ /* XXX can't dynamically turn mmu on and off if virtual stack */ /* only way is if you make mmuEnable inline and guarantee that this code is in physical memory */ MMU_UNLOCK (wasEnabled, oldIntLev); pagePte->pte.sfpd.bits = (pagePte->pte.sfpd.bits & ~stateMask) | (state & stateMask); MMU_LOCK (wasEnabled, oldIntLev); mmuATCFlush (pageAddr); cacheArchClearEntry (DATA_CACHE, pagePte); return (OK); }/******************************************************************************** mmuStateGet - get state of virtual memory page** mmuStateGet is used to retrieve the state bits of the pte for the given* virtual page. The following states are provided:** MMU_STATE_VALID MMU_STATE_VALID_NOT vailid/invalid* MMU_STATE_WRITABLE MMU_STATE_WRITABLE_NOT writable/writeprotected* MMU_STATE_CACHEABLE MMU_STATE_CACHEABLE_NOT notcachable/cachable** these are or'ed together in the returned state. Additionally, masks* are provided so that specific states may be extracted from the returned state:** MMU_STATE_MASK_VALID * MMU_STATE_MASK_WRITABLE* MMU_STATE_MASK_CACHEABLE** RETURNS: OK or ERROR if virtual page does not exist.*/LOCAL STATUS mmuStateGet ( MMU_TRANS_TBL *transTbl, /* tranlation table */ void *pageAddr, /* page whose state we're querying */ UINT *state /* place to return state value */ ) { PTE *pagePte; if (mmuPteGet (transTbl, pageAddr, &pagePte) != OK) return (ERROR); *state = pagePte->pte.sfpd.bits; return (OK); }/******************************************************************************** mmuPageMap - map physical memory page to virtual memory page** The physical page address is entered into the pte corresponding to the* given virtual page. The state of a newly mapped page is undefined. ** RETURNS: OK or ERROR if translation table creation failed. */LOCAL STATUS mmuPageMap ( MMU_TRANS_TBL *transTbl, /* translation table */ void *virtualAddress, /* virtual address */ void *physPage /* physical address */ ) { PTE *pagePte; volatile int oldIntLev; /* volatile hushes warnings */ FAST UINT addr = (UINT)physPage >> 8; BOOL wasEnabled; if (mmuPteGet (transTbl, virtualAddress, &pagePte) != OK) { /* build the translation table for the virtual address */ if (mmuVirtualPageCreate (transTbl, virtualAddress) != OK) return (ERROR); if (mmuPteGet (transTbl, virtualAddress, &pagePte) != OK) return (ERROR); } MMU_UNLOCK (wasEnabled, oldIntLev); pagePte->pte.sfpd.fields.addr = addr; MMU_LOCK (wasEnabled, oldIntLev); mmuATCFlush (virtualAddress); cacheArchClearEntry (DATA_CACHE, pagePte); return (OK); }/******************************************************************************** mmuGlobalPageMap - map physical memory page to global virtual memory page** mmuGlobalPageMap is used to map physical pages into global virtual memory* that is shared by all virtual memory contexts. The translation tables* for this section of the virtual space are shared by all virtual memory* contexts.** RETURNS: OK or ERROR if no pte for given virtual page.*/LOCAL STATUS mmuGlobalPageMap ( void *virtualAddress, /* virtual address */ void *physPage /* physical address */ ) { PTE *pagePte; volatile int oldIntLev; /* volatile hushes warnings */ FAST UINT addr = (UINT)physPage >> 8; BOOL wasEnabled; if (mmuPteGet (&mmuGlobalTransTbl, virtualAddress, &pagePte) != OK) { /* build the translation table for the virtual address */ if (mmuVirtualPageCreate (&mmuGlobalTransTbl, virtualAddress) != OK) return (ERROR); if (mmuPteGet (&mmuGlobalTransTbl, virtualAddress, &pagePte) != OK) return (ERROR); /* the globalPageBlock array is write protected */ mmuStateSet (&mmuGlobalTransTbl, globalPageBlock, MMU_STATE_MASK_WRITABLE, MMU_STATE_WRITABLE); globalPageBlock [(unsigned) virtualAddress / PAGE_BLOCK_SIZE] = TRUE; mmuStateSet (&mmuGlobalTransTbl, globalPageBlock, MMU_STATE_MASK_WRITABLE, MMU_STATE_WRITABLE_NOT); } MMU_UNLOCK (wasEnabled, oldIntLev); pagePte->pte.sfpd.fields.addr = addr; MMU_LOCK (wasEnabled, oldIntLev); mmuATCFlush (virtualAddress); cacheArchClearEntry (DATA_CACHE, pagePte); return (OK); }/******************************************************************************** mmuTranslate - translate a virtual address to a physical address** Traverse the translation table and extract the physical address for the* given virtual address from the pte corresponding to the virtual address.** RETURNS: OK or ERROR if no pte for given virtual address.*/LOCAL STATUS mmuTranslate ( MMU_TRANS_TBL *transTbl, /* translation table */ void *virtAddress, /* virtual address */ void **physAddress /* place to return result */ ) { PTE *pagePte; UINT dt; if (mmuPteGet (transTbl, virtAddress, &pagePte) != OK) { errno = S_mmuLib_NO_DESCRIPTOR; return (ERROR); } *physAddress = (PTE *) pagePte->pte.sfpd.fields.addr; dt = pagePte->pte.sfpd.fields.dt; if (dt == DT_INVALID) { errno = S_mmuLib_INVALID_DESCRIPTOR; return (ERROR); } *physAddress = (void *) ((UINT) *physAddress << 8); /* add offset into page */ *physAddress += (unsigned) virtAddress & ((1 << NUM_PAGE_OFFSET_BITS) - 1); return (OK); }/******************************************************************************** mmuCurrentSet - change active translation table** mmuCurrent set is used to change the virtual memory context.* Load the CRP (root pointer) register with the given translation table.**/LOCAL void mmuCurrentSet ( MMU_TRANS_TBL *transTbl /* new active tranlation table */ ) { FAST int oldLev; static BOOL firstTime = TRUE; if (firstTime) { mmuMemPagesWriteDisable (&mmuGlobalTransTbl); mmuMemPagesWriteDisable (transTbl); firstTime = FALSE; } oldLev = intLock (); localCrp.ta = ((unsigned int) transTbl->pUpperLevelTable) >> 4 ; __asm__("pmove _localCrp, crp"); mmuCurrentTransTbl = transTbl; /* the address translation cache is automatically flushed when the * crp register is loaded by the pmove instruction ONLY if the fd bit * of the opcode is zero. Thus, this is dependent on the assembler * implementation, so we flush the atc explicitly. */ /* flush the address translation cache cause we're in a new context */ __asm__("pflusha"); intUnlock (oldLev); }/******************************************************************************** mmuATCFlush - flush an entry from the address translation cache**/LOCAL void mmuATCFlush ( void *addr ) { __asm__ ("movel a6@(8) ,a0"); /* pflush 0,#0, a0 */ __asm__ (".word 0xf010"); __asm__ (".word 0x3810"); }/******************************************************************************** mmuMemPagesWriteDisable - write disable memory holding a table's descriptors** 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.**/LOCAL void mmuMemPagesWriteDisable ( MMU_TRANS_TBL *transTbl ) { void *thisPage; int i; for (i = 0; i < (1 << NUM_TIA_BITS) ;i++) { thisPage = (void *) (transTbl->pUpperLevelTable[i].pte.sftd.addr << 4); if (thisPage != (void *) 0xfffffff0) mmuStateSet (transTbl, thisPage, MMU_STATE_MASK_WRITABLE, MMU_STATE_WRITABLE_NOT); } mmuStateSet (transTbl, transTbl->pUpperLevelTable, MMU_STATE_MASK_WRITABLE, MMU_STATE_MASK_WRITABLE); }/******************************************************************************** mmuPageAlloc - allocate a page of physical memory**/LOCAL char *mmuPageAlloc ( MMU_TRANS_TBL *thisTbl ) { char *pPage; int i; if ((pPage = (char *) lstGet (&thisTbl->memFreePageList)) == NULL) { pPage = memPartAlignedAlloc (mmuPageSource, mmuPageSize * mmuNumPagesInFreeList, mmuPageSize); if (pPage == NULL) return (NULL); if (thisTbl->memBlocksUsedIndex >= thisTbl->memBlocksUsedSize) { void *newArray; /* realloc the array */ thisTbl->memBlocksUsedSize *= 2; newArray = realloc (thisTbl->memBlocksUsedArray, sizeof (void *) * thisTbl->memBlocksUsedSize); if (newArray == NULL) { thisTbl->memBlocksUsedSize /= 2; return (NULL); } thisTbl->memBlocksUsedArray = (void **) newArray; } thisTbl->memBlocksUsedArray [thisTbl->memBlocksUsedIndex++] = (void *) pPage; for (i = 0; i < mmuNumPagesInFreeList; i++, pPage += mmuPageSize) lstAdd (&thisTbl->memFreePageList, (NODE *) pPage); pPage = (char *) lstGet (&thisTbl->memFreePageList); } return (pPage); }#if FALSE// left here for debugging only/* EXPERIMENTAL STUFF */LOCAL char *addrBuf;LOCAL PTE *ptestResult;LOCAL MMU_SR copyOfSr;/******************************************************************************** mmuPtest - use the ptest instruction to traverse the translation table**/LOCAL void mmuPtest ( char *addr, int level ) { addrBuf = addr; if (level == 0) { __asm__ ("movel _addrBuf, a0"); __asm__ ("ptestr #1,a0@,#7,a1"); __asm__ ("movel a1, _ptestResult"); __asm__ ("pmove psr, _copyOfSr"); } else { __asm__ ("movel _addrBuf, a0"); __asm__ ("ptestr #1,a0@,#1,a1"); __asm__ ("movel a1, _ptestResult"); __asm__ ("pmove psr, _copyOfSr"); } printf ("mmu status register:\n"); printf (" bus error = %d\n", copyOfSr.b); printf (" limit violation = %d\n", copyOfSr.l); printf (" supervisor only = %d\n", copyOfSr.s); printf (" write protected = %d\n", copyOfSr.w); printf (" invalid = %d\n", copyOfSr.i); printf (" modified = %d\n", copyOfSr.m); printf (" transparent = %d\n", copyOfSr.t); printf (" num levels = %d\n", copyOfSr.n); printf ("descriptor address = %x\n", ptestResult); printf (" addr = %x\n", ptestResult->pte.sfpd.fields.addr); printf (" cache inhibit = %x\n", ptestResult->pte.sfpd.fields.ci); printf (" modified = %x\n", ptestResult->pte.sfpd.fields.m); printf (" u/l = %x\n", ptestResult->pte.sfpd.fields.u); printf (" write protect = %x\n", ptestResult->pte.sfpd.fields.wp); printf (" desc type = %x\n", ptestResult->pte.sfpd.fields.dt); }#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -