📄 mmu30lib.c
字号:
localTc.tia = NUM_TIA_BITS; localTc.tib = NUM_TIB_BITS; localTc.tic = 0; localTc.tid = 0; /* initialize the static data structure that mmuCurrentSet uses to load * the crp. */ localCrp.lu = 1; localCrp.limit = 0; localCrp.zero = 0; localCrp.dt = DT_VALID_4_BYTE; /* we assume a 8192 byte page size */ if (pageSize != 8192) { errno = S_mmuLib_INVALID_PAGE_SIZE; return (ERROR); } mmuEnabled = FALSE; mmuPageSize = pageSize; /* allocate the global page block array to keep track of which parts * of virtual memory are handled by the global translation tables. * Allocate on page boundry so we can write protect it. */ globalPageBlock = (BOOL *) memPartAlignedAlloc (mmuPageSource, pageSize, pageSize); bzero ((char *) globalPageBlock, pageSize); /* build a dummy translation table which will hold the pte's for * global memory. All real translation tables will point to this * one for controling the state of the global virtual memory */ lstInit (&mmuGlobalTransTbl.memFreePageList); mmuGlobalTransTbl.memBlocksUsedArray = calloc (MMU_BLOCKS_USED_SIZE, sizeof (void *)); if (mmuGlobalTransTbl.memBlocksUsedArray == NULL) return (ERROR); mmuGlobalTransTbl.memBlocksUsedIndex = 0; mmuGlobalTransTbl.memBlocksUsedSize = MMU_BLOCKS_USED_SIZE; /* allocate a page to hold the upper level descriptor array */ mmuGlobalTransTbl.pUpperLevelTable = pUpperLevelTable = (PTE *) mmuPageAlloc (&mmuGlobalTransTbl); if (pUpperLevelTable == NULL) return (ERROR); /* invalidate all the upper level descriptors */ for (i = 0; i < (1 << NUM_TIA_BITS) ;i++) { pUpperLevelTable[i].pte.sftd.addr = -1; pUpperLevelTable[i].pte.sftd.u = 0; pUpperLevelTable[i].pte.sftd.wp = 0; pUpperLevelTable[i].pte.sftd.dt = DT_INVALID; } return (OK); }/******************************************************************************** mmuPteGet - get the pte for a given page** mmuPteGet traverses a translation table and returns the (physical) address of* the pte for the given virtual address.** RETURNS: OK or ERROR if there is no virtual space for the given address **/LOCAL STATUS mmuPteGet ( MMU_TRANS_TBL *pTransTbl, /* translation table */ void *virtAddr, /* virtual address */ PTE **result /* result is returned here */ ) { PTE *upperLevelPte; PTE *lowerLevelPteTable; int lowerLevelPteTableIndex; upperLevelPte = &pTransTbl->pUpperLevelTable [(UINT) virtAddr / PAGE_BLOCK_SIZE]; lowerLevelPteTable = (PTE *) upperLevelPte->pte.sftd.addr; if ((UINT) lowerLevelPteTable == 0xfffffff) /* -1 in 28 bits */ return (ERROR); lowerLevelPteTable = (PTE *)((UINT)lowerLevelPteTable << 4); lowerLevelPteTableIndex = ((UINT) virtAddr >> NUM_PAGE_OFFSET_BITS) & ((1 << NUM_TIB_BITS) - 1); *result = &lowerLevelPteTable[lowerLevelPteTableIndex]; return (OK); }/******************************************************************************** mmuTransTblCreate - create a new translation table.** create a 68k translation table. Allocates space for the MMU_TRANS_TBL* data structure and calls mmuTransTblInit on that object. ** RETURNS: address of new object or NULL if allocation failed,* or NULL if initialization failed.*/LOCAL MMU_TRANS_TBL *mmuTransTblCreate ( ) { MMU_TRANS_TBL *newTransTbl; newTransTbl = (MMU_TRANS_TBL *) malloc (sizeof (MMU_TRANS_TBL)); if (newTransTbl == NULL) return (NULL); if (mmuTransTblInit (newTransTbl) == ERROR) { free ((char *) newTransTbl); return (NULL); } return (newTransTbl); }/******************************************************************************** mmuTransTblInit - initialize a new translation table ** Initialize a new translation table. The upper level is copyed from the* global translation mmuGlobalTransTbl, so that we* will share the global virtual memory with all* other translation tables.* * RETURNS: OK or ERROR if unable to allocate memory for upper level.*/LOCAL STATUS mmuTransTblInit ( MMU_TRANS_TBL *newTransTbl /* translation table to be inited */ ) { FAST PTE *pUpperLevelTable; lstInit (&newTransTbl->memFreePageList); newTransTbl->memBlocksUsedArray = calloc (MMU_BLOCKS_USED_SIZE, sizeof (void *)); if (newTransTbl->memBlocksUsedArray == NULL) return (ERROR); newTransTbl->memBlocksUsedIndex = 0; newTransTbl->memBlocksUsedSize = MMU_BLOCKS_USED_SIZE; /* allocate a page to hold the upper level descriptor array */ newTransTbl->pUpperLevelTable = pUpperLevelTable = (PTE *) mmuPageAlloc (newTransTbl); if (pUpperLevelTable == NULL) return (ERROR); /* copy the upperlevel table from mmuGlobalTransTbl, * so we get the global virtual memory */ bcopy ((char *) mmuGlobalTransTbl.pUpperLevelTable, (char *) pUpperLevelTable, mmuPageSize); /* write protect virtual memory pointing to the the upper level table in * the global translation table to insure that it can't be corrupted */ mmuStateSet (&mmuGlobalTransTbl, (void *) pUpperLevelTable, MMU_STATE_MASK_WRITABLE, MMU_STATE_WRITABLE_NOT); return (OK); }/******************************************************************************** mmuTransTblDelete - delete a translation table.* * mmuTransTblDelete deallocates all the memory used to store the translation* table entries. It does not deallocate physical pages mapped into the* virtual memory space.** RETURNS: OK**/LOCAL STATUS mmuTransTblDelete ( MMU_TRANS_TBL *transTbl /* translation table to be deleted */ ) { FAST int i; /* write enable the physical page containing the upper level pte */ mmuStateSet (&mmuGlobalTransTbl, transTbl->pUpperLevelTable, MMU_STATE_MASK_WRITABLE, MMU_STATE_WRITABLE); /* free all the blocks of pages in memBlocksUsedArray */ for (i = 0; i < transTbl->memBlocksUsedIndex; i++) free (transTbl->memBlocksUsedArray[i]); free (transTbl->memBlocksUsedArray); /* free the translation table data structure */ free (transTbl); return (OK); }/******************************************************************************** mmuVirtualPageCreate - set up translation tables for a virtual page** simply check if there's already a lower level sfpd array that has a* pte for the given virtual page. If there isn't, create one.** RETURNS OK or ERROR if couldn't allocate space for lower level sfpd array.*/LOCAL STATUS mmuVirtualPageCreate ( MMU_TRANS_TBL *thisTbl, /* translation table */ void *virtPageAddr /* virtual addr to create */ ) { PTE *upperLevelPte; FAST PTE *lowerLevelPteTable; FAST UINT i; PTE *dummy; if (mmuPteGet (thisTbl, virtPageAddr, &dummy) == OK) return (OK); lowerLevelPteTable = (PTE *) mmuPageAlloc (thisTbl); if (lowerLevelPteTable == NULL) return (ERROR); /* invalidate every page in the new page block */ for (i = 0; i < (1 << NUM_TIB_BITS); i++) { lowerLevelPteTable[i].pte.sfpd.fields.addr = -1; lowerLevelPteTable[i].pte.sfpd.fields.ci = 0; lowerLevelPteTable[i].pte.sfpd.fields.m = 0; lowerLevelPteTable[i].pte.sfpd.fields.u = 0; lowerLevelPteTable[i].pte.sfpd.fields.wp = 0; lowerLevelPteTable[i].pte.sfpd.fields.dt = DT_INVALID; } /* write protect the new physical page containing the pte's for this new page block */ mmuStateSet (&mmuGlobalTransTbl, lowerLevelPteTable, MMU_STATE_MASK_WRITABLE, MMU_STATE_WRITABLE_NOT); /* unlock the physical page containing the upper level pte, so we can modify it */ mmuStateSet (&mmuGlobalTransTbl, thisTbl->pUpperLevelTable, MMU_STATE_MASK_WRITABLE, MMU_STATE_WRITABLE); upperLevelPte = &thisTbl->pUpperLevelTable [(UINT) virtPageAddr / PAGE_BLOCK_SIZE]; /* modify the upperLevel pte to point to the new lowerLevel pte */ upperLevelPte->pte.sftd.addr = (UINT) lowerLevelPteTable >> 4; upperLevelPte->pte.sftd.dt = DT_VALID_4_BYTE; /* write protect the upper level pte table */ mmuStateSet (&mmuGlobalTransTbl, thisTbl->pUpperLevelTable, MMU_STATE_MASK_WRITABLE, MMU_STATE_WRITABLE_NOT); mmuATCFlush (virtPageAddr); return (OK); }/******************************************************************************** mmuEnable - turn mmu on or off** RETURNS: OK*/LOCAL STATUS mmuEnable ( BOOL enable /* TRUE to enable, FALSE to disable MMU */ ) { FAST int oldIntLev; /* lock out interrupts to protect kludgey static data structure */ oldIntLev = intLock (); localTc.enable = enable; __asm__ ("pmove _localTc, tc"); mmuEnabled = enable; intUnlock (oldIntLev); return (OK); }/******************************************************************************** mmuOn - turn mmu on ** This routine assumes that interrupts are locked out. It is called internally* to enable the mmu after it has been disabled for a short period of time* to access internal data structs.** RETURNS: OK*/LOCAL void mmuOn ( ) { localTc.enable = TRUE; __asm__ ("pmove _localTc, tc"); }/******************************************************************************** mmuOff - turn mmu off ** This routine assumes that interrupts are locked out. It is called internally* to disable the mmu for a short period of time* to access internal data structs.** RETURNS: OK*/LOCAL void mmuOff ( ) { localTc.enable = FALSE; __asm__ ("pmove _localTc, tc"); }/******************************************************************************** mmuStateSet - set state of virtual memory page** mmuStateSet is used to modify 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 may be or'ed together in the state parameter. Additionally, masks* are provided so that only specific states may be set:** MMU_STATE_MASK_VALID * MMU_STATE_MASK_WRITABLE* MMU_STATE_MASK_CACHEABLE** These may be or'ed together in the stateMask parameter. ** Accesses to a virtual page marked as invalid will result in a bus error.** RETURNS: OK or ERROR if virtual page does not exist.*/LOCAL STATUS mmuStateSet ( MMU_TRANS_TBL *transTbl, /* translation table */ void *pageAddr, /* page whose state to modify */ UINT stateMask, /* mask of which state bits to modify */ UINT state /* new state bit values */ )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -