📄 mmu405lib.c
字号:
** mmu405TransTblInit - initialize a new translation table ** Initialize a new translation table. The level 1 table 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. */LOCAL STATUS mmu405TransTblInit ( MMU_TRANS_TBL * pNewTransTbl /* translation table to initialize */ ) { /* allocat memory space for a new Level 1 descriptor table */ pNewTransTbl->l1TblPtr.pL1Desc = (LEVEL_1_DESC *) memalign (PAGE_SIZE, PAGE_SIZE); /* if the memory cannot be allocated then return ERROR */ if (pNewTransTbl->l1TblPtr.pL1Desc == NULL) return (ERROR); /* copy the global level 1 descriptor table to the new table */ memcpy ((void *) pNewTransTbl->l1TblPtr.pL1Desc, (void *) mmuGlobalTransTbl.l1TblPtr.pL1Desc, PAGE_SIZE); /* lock the new level 1 descriptor table modification */ mmu405MemPagesWriteDisable (pNewTransTbl); return (OK); }/******************************************************************************** mmu405TransTblDelete - delete a translation table.* * This routine deletes a translation table.** RETURNS: OK always.*/LOCAL STATUS mmu405TransTblDelete ( 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 */ mmu405FreePid (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); }/******************************************************************************** mmu405Enable - turn mmu on or off** RETURNS: OK*/LOCAL STATUS mmu405Enable ( BOOL enable /* TRUE to enable, FALSE to disable MMU */ ) { int lockKey; /* lock key for intUnlock() */ /* lock the interrupt */ lockKey = intLock (); if (enable) { if (mmu405Selected & MMU_INST) mmuPpcAEnable (MMU_I_ADDR_TRANS); /* enable instruction MMU */ if (mmu405Selected & MMU_DATA) mmuPpcAEnable (MMU_D_ADDR_TRANS); /* enable data MMU */ } else { if (mmu405Selected & MMU_INST) mmuPpcADisable (MMU_I_ADDR_TRANS); /* disable instruction MMU */ if (mmu405Selected & MMU_DATA) mmuPpcADisable (MMU_D_ADDR_TRANS); /* disable data MMU */ } intUnlock (lockKey); /* unlock the interrupt */ return (OK); }/******************************************************************************** mmu405StateSet - 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 mmu405StateSet ( 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 */ /* * get the level 2 descriptor address. If this descriptor address doesn't * exist then set errno and return ERROR. */ if (mmu405Lvl2DescAddrGet (pTransTbl, effectiveAddr, &pLvl2Desc) == ERROR) { errno = S_mmuLib_NO_DESCRIPTOR; return (ERROR); } /* get the Level 2 Descriptor */ lvl2Desc = *pLvl2Desc; /* * 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 ((stateMask & MMU_STATE_MASK_CACHEABLE) && (state & MMU_STATE_CACHEABLE_NOT) && (state & MMU_STATE_CACHEABLE_WRITETHROUGH)) { return (ERROR); } /* set or reset the VALID bit if requested */ lvl2Desc.words.word0 = (lvl2Desc.words.word0 & ~(stateMask & MMU_STATE_MASK_VALID)) | (state & stateMask & MMU_STATE_MASK_VALID); /* set or reset the WIMG bit if requested */ lvl2Desc.words.word1 = (lvl2Desc.words.word1 & ~(stateMask & MMU_STATE_MASK_WIMG_WRITABLE_EXECUTE)) | (state & stateMask & MMU_STATE_MASK_WIMG_WRITABLE_EXECUTE); /* update the Level 2 Descriptor */ mmu405Lvl2DescUpdate (pLvl2Desc, lvl2Desc); /* invalidate the tlb entry for this effective address */ mmu405Tlbie (pTransTbl, effectiveAddr); return (OK); }/******************************************************************************** mmu405StateGet - get state of virtual memory page**/LOCAL STATUS mmu405StateGet ( 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 (mmu405Lvl2DescAddrGet (pTransTbl, effectiveAddr, &pLvl2Desc) == ERROR) { errno = S_mmuLib_NO_DESCRIPTOR; return (ERROR); } /* get the Level 2 Descriptor */ lvl2Desc = *pLvl2Desc; /* extract the state of the VALID and WIMG bit */ * state = lvl2Desc.words.word0 & MMU_STATE_MASK_VALID; * state |= lvl2Desc.words.word1 & MMU_STATE_MASK_WIMG_WRITABLE_EXECUTE; return (OK); }/******************************************************************************** mmu405PageMap - 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 mmu405PageMap ( 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 */ UINT32 ix; /* counter */ /* get the level 1 descriptor address */ pLvl1Desc = mmu405Lvl1DescAddrGet (pTransTbl, effectiveAddr); /* get the level 1 descriptor */ lvl1Desc.l1desc = pLvl1Desc->l1desc; if (!lvl1Desc.field.v) { /* * the level 2 desciptor table is not valid (doesn't exist) then * allocate a piece of memory to save the level 2 desciptor table * The level 2 table needs to be aligned on a 4byte boundary * and has a size of 1024 entries * 8 bytes/entry = 8K. */ pLvl2Desc = (LEVEL_2_DESC *) memalign (PAGE_SIZE, MMU_LVL_2_DESC_NB * sizeof(LEVEL_2_DESC)); /* * check if the level 2 desciptor table was created properly. If * not then return ERROR. */ if (pLvl2Desc == NULL) return (ERROR); /* * invalid all level 2 descriptors by clearing the new level * 2 descriptor table created. */ lvl2Desc.field.epn = 0; /* effective page number */ lvl2Desc.field.rsvd1 = 0; lvl2Desc.field.size = 1; /* default 4KB page */ lvl2Desc.field.v = 0; /* initially invalid */ lvl2Desc.field.e = 0; /* big endian */ lvl2Desc.field.u0 = 0; /* no user defined attribute */ lvl2Desc.field.rsvd2 = 0; lvl2Desc.field.rpn = 0; /* real page number */ lvl2Desc.field.rsvd3 = 0; lvl2Desc.field.ex = 1; /* no execute protection */ lvl2Desc.field.wr = 0; /* no write protection */ lvl2Desc.field.zsel = 0; /* select zone 0 */ lvl2Desc.field.w = 0; /* no write thru */ lvl2Desc.field.i = 0; /* no cache inhibit */ lvl2Desc.field.m = 0; /* memory coherent: no effect */ lvl2Desc.field.g = 0; /* memory unguarded */ for (ix = 0; ix < MMU_LVL_2_DESC_NB; ix ++) pLvl2Desc[ix] = lvl2Desc; /* * set the Level 1 Descriptor with the * new level 2 descriptor table created. */ lvl1Desc.l1desc = ((UINT32) pLvl2Desc) & MMU_LVL_1_L2BA_MSK; lvl1Desc.field.v = 1; /* segment valid */ /* update the Level 1 descriptor in table */ mmu405Lvl1DescUpdate (pLvl1Desc, lvl1Desc); } /* * Get the level 2 descriptor address. If the level 2 descriptor doesn't * exist then return ERROR. */ if (mmu405Lvl2DescAddrGet (pTransTbl, effectiveAddr, &pLvl2Desc) == ERROR) return (ERROR); /* get the level 2 descriptor */ lvl2Desc = *pLvl2Desc; /* save the real address & effective addr in the level 2 descriptors */ lvl2Desc.field.rpn = (UINT32) physicalAddr >> MMU_RPN_SHIFT; lvl2Desc.field.epn = (UINT32) effectiveAddr >> MMU_RPN_SHIFT; /* set the valid bit in the level 2 descriptor */ lvl2Desc.field.v = 1; /* update the Level 2 descriptor in table */ mmu405Lvl2DescUpdate (pLvl2Desc, lvl2Desc); /* invalidate the tlb entry for this effective addr */ mmu405Tlbie (pTransTbl, effectiveAddr); return (OK); }/******************************************************************************** mmu405GlobalPageMap - map physical memory page to global virtual memory page** mmuPpcGlobalPageMap 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 mmu405GlobalPageMap ( void * effectiveAddr, /* effective address */ void * physicalAddr /* physical address */ ) { return (mmu405PageMap (&mmuGlobalTransTbl, effectiveAddr, physicalAddr)); }/******************************************************************************** mmu405Translate - 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 mmu405Translate ( 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 (mmu405Lvl2DescAddrGet (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); }/******************************************************************************** mmu405CurrentSet - 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**/void mmu405CurrentSet (
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -