?? mmu440lib.c
字號:
int ix; /* index of L1 entries */ int jx; /* index into L2 table pages */ LEVEL_1_DESC lvl1Desc; /* current L1 descriptor */ /* we need to enable 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 enable the level 1 page table */ mmu440StateSet (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) { for (jx = 0; jx < 4; jx++) { mmu440StateSet (pTransTbl, (void *)(lvl1Desc.field.l2ba << 2) + (jx * MMU_PAGE_SIZE), MMU_STATE_MASK_WRITABLE, MMU_STATE_WRITABLE); } } } return (OK); }#endif /* FALSE *//******************************************************************************** mmu440MemPagesWriteDisable - 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 mmu440MemPagesWriteDisable ( 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 */ mmu440StateSet (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++) { mmu440StateSet (pTransTbl, (void *)(lvl1Desc.field.l2ba << 2) + (jx * MMU_PAGE_SIZE), MMU_STATE_MASK_WRITABLE, MMU_STATE_WRITABLE_NOT); } } } }/******************************************************************************** mmu440TransTblCreate - create a new translation table.** RETURNS: address of new object or NULL if allocation failed.*/LOCAL MMU_TRANS_TBL * mmu440TransTblCreate (void) { MMU_TRANS_TBL * pNewTransTbl; /* new translation table */ /* 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 = mmu440PidAlloc (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 (mmu440TransTblInit (pNewTransTbl) == ERROR) { free ((char *) pNewTransTbl); return (NULL); } /* return the new translation table created */ return (pNewTransTbl); }/******************************************************************************** mmu440TransTblInit - initialize a new translation table** Initialize a new translation table. The level 1 table is copied 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.*/LOCAL STATUS mmu440TransTblInit ( MMU_TRANS_TBL * pNewTransTbl /* translation table to initialize */ ) { /* * Allocate memory space for a new Level 1 descriptor 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. */ pNewTransTbl->l1TblPtr.pL1Desc = (LEVEL_1_DESC *) memalign (MMU_PAGE_SIZE, MMU_PAGE_SIZE); /* if the memory cannot be allocated then return ERROR */ if (pNewTransTbl->l1TblPtr.pL1Desc == NULL) return (ERROR); /* invalidate all entries in the table */ memset ((void *) pNewTransTbl->l1TblPtr.pL1Desc, 0x00, MMU_PAGE_SIZE); if (mmuGlobalTransTbl != NULL) { /* copy the global level 1 descriptor table to the new table */ memcpy ((void *) pNewTransTbl->l1TblPtr.pL1Desc, (void *) mmuGlobalTransTbl->l1TblPtr.pL1Desc, MMU_PAGE_SIZE); } /* In AE, would page protect the new L1 descriptor table here */ return (OK); }/******************************************************************************** mmu440TransTblDelete - delete a translation table.** This routine deletes a translation table.** RETURNS: OK always.*/LOCAL STATUS mmu440TransTblDelete ( MMU_TRANS_TBL * pTransTbl /* translation table to be deleted */ ) { LEVEL_1_DESC lvl1Desc; /* level 1 descriptor */ UINT32 ix; /* free the PID element for this translation table */ mmu440PidFree (pTransTbl->pid); /* free level 2 page tables */ for (ix = 0 ; ix < MMU_LVL_2_DESC_NB; ix++) { lvl1Desc = * (pTransTbl->l1TblPtr.pL1Desc + ix); if (lvl1Desc.field.v) free ((void *) (lvl1Desc.l1desc & MMU_LVL_1_L2BA_MSK)); } /* free the level 1 table */ free ((void *) pTransTbl->l1TblPtr.pL1Desc); return (OK); }/******************************************************************************** mmu440Enable - turn mmu on or off** On the PPC440, the MMU is always on, so turning it off is a misnomer.* Instead, this function changes the MSR[IS,DS] values, which change which TLB* entries match -- either the static ones that emulate 'real mode', or the ones* that provide dynamic mmu page mapping.** RETURNS: OK*/LOCAL STATUS mmu440Enable ( BOOL enable /* TRUE to enable, FALSE to disable MMU */ ) { int lockKey; /* lock key for intUnlock() */ if (mmuPpcSelected == 0) return (OK); /* lock the interrupt */ lockKey = intLock (); if (enable) { if (mmuPpcSelected & MMU_INST) mmuPpcAEnable (MMU_I_ADDR_TRANS); /* enable instruction MMU */ if (mmuPpcSelected & MMU_DATA) mmuPpcAEnable (MMU_D_ADDR_TRANS); /* enable data MMU */ } else { if (mmuPpcSelected & MMU_INST) mmuPpcADisable (MMU_I_ADDR_TRANS); /* disable instruction MMU */ if (mmuPpcSelected & MMU_DATA) mmuPpcADisable (MMU_D_ADDR_TRANS); /* disable data MMU */ } /* AE would unmap EA 0x0 - 0x2fff here, but only for user mode tasks */ intUnlock (lockKey); /* unlock the interrupt */ return (OK); }/******************************************************************************** mmu440StateSet - 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 mmu440StateSet ( 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 (mmu440Lvl2DescAddrGet (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 the WIMG bits as requested. WIMG and write/execute bits * are in the same bit positions in MMU_STATE as in TLB Word 2, so we * can use bitwise arithmetic */ lvl2Desc.words.word2 &= ~(stateMask & MMU_STATE_MASK_WIMG_WRITABLE_EXECUTE); lvl2Desc.words.word2 |= (state & stateMask & MMU_STATE_MASK_WIMG_WRITABLE_EXECUTE); /* 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 */ mmu440Lvl2DescUpdate (pLvl2Desc, lvl2Desc); /* invalidate the tlb entry for this effective address */ mmu440Tlbie (pTransTbl, effectiveAddr); return (OK); }/******************************************************************************** mmu440StateGet - get state of virtual memory page**/LOCAL STATUS mmu440StateGet ( 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 (mmu440Lvl2DescAddrGet (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. * Note that the valid bit is in a different bit position in L2 desc * than in the MMU_STATE_VALID. */ * state = (lvl2Desc.field.v ? MMU_STATE_VALID : 0); * state |= lvl2Desc.words.word2 & MMU_STATE_MASK_WIMG_WRITABLE_EXECUTE; return (OK); }/******************************************************************************** mmu440PageMap - map physical memory page to virtual memory page** The physical page address is entered into the level 2 descriptor* 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 mmu440PageMap ( MMU_TRANS_TBL * pTransTbl, /* translation table */ void * effectiveAddr, /* effective address */ void * physicalAddr /* physical address */ ) { LEVEL_1_DESC * pLvl1Desc; /* level 1 descriptor address */ LEVEL_1_DESC lvl1Desc; /* level 1 descriptor */ LEVEL_2_DESC * pLvl2Desc; /* level 2 descriptor address */ LEVEL_2_DESC lvl2Desc; /* level 2 descriptor */ /* get the level 1 descriptor address */ pLvl1Desc = mmu440Lvl1DescAddrGet (pTransTbl, effectiveAddr);
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -