📄 mmu800lib.c
字号:
*/LOCAL STATUS mmu800TransTblInit ( 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 */ mmu800MemPagesWriteDisable (pNewTransTbl); return (OK); }/******************************************************************************** mmu800TransTblDelete - delete a translation table.* * This routine deletes a translation table.** RETURNS: OK always.*/LOCAL STATUS mmu800TransTblDelete ( MMU_TRANS_TBL * pTransTbl /* translation table to be deleted */ ) { LEVEL_1_DESC lvl1Desc; /* level 1 descriptor */ LEVEL_1_DESC globalLvl1Desc; /* level 1 descriptor */ u_int ix; int key; for (ix = 0 ; ix < MMU_LVL_2_DESC_NB; ix++) { /* Move through L1 descriptor table */ pTransTbl->l1TblPtr.l1index = ix; /* Grab global version of same L1 descriptor. Careful not to allow other * tasks access to the global descriptor table. */ key=intLock(); mmuGlobalTransTbl.l1TblPtr.l1index=ix; globalLvl1Desc=*mmuGlobalTransTbl.l1TblPtr.pL1Desc; mmuGlobalTransTbl.l1TblPtr.l1index=0; intUnlock(key); lvl1Desc = *pTransTbl->l1TblPtr.pL1Desc; if (lvl1Desc.v) { /* Check to see if L2 descriptor actually created * in global translation table. If so do not free memory, in use. */ if ((lvl1Desc.l1desc & MMU_LVL_1_L2BA_MSK) != (globalLvl1Desc.l1desc & MMU_LVL_1_L2BA_MSK)) free ((void *) (lvl1Desc.l1desc & MMU_LVL_1_L2BA_MSK)); } } /* Reset index so free is done a base of L1 descriptor table */ pTransTbl->l1TblPtr.l1index = 0; /* free the PTEG table */ free ((void *) pTransTbl->l1TblPtr.pL1Desc); free ((void *) pTransTbl); return (OK); }/******************************************************************************** mmu800Enable - turn mmu on or off** RETURNS: OK*/LOCAL STATUS mmu800Enable ( BOOL enable /* TRUE to enable, FALSE to disable MMU */ ) { int lockKey; /* lock key for intUnlock() */ /* lock the interrupt */ lockKey = intLock (); if (enable) { if (mmu800Selected & MMU_INST) mmuPpcAEnable (MMU_I_ADDR_TRANS); /* enable instruction MMU */ if (mmu800Selected & MMU_DATA) mmuPpcAEnable (MMU_D_ADDR_TRANS); /* enable data MMU */ } else { if (mmu800Selected & MMU_INST) mmuPpcADisable (MMU_I_ADDR_TRANS); /* disable instruction MMU */ if (mmu800Selected & MMU_DATA) mmuPpcADisable (MMU_D_ADDR_TRANS); /* disable data MMU */ } intUnlock (lockKey); /* unlock the interrupt */ return (OK); }/******************************************************************************** mmu800StateSet - set state of virtual memory page** Note : Exercise extreme caution when changing a page from copyback to* writethrough. The 860 architecture handles the writethrough/copyback* attribute at the 4MB Level 1 segment level, not the 4KB Level 2 page* level. This function does not attempt to automatically flush cache* lines belonging to the entire 4MB segment. It does, however, invalidate* all TLB entries mapping any part of the 4MB segment.** The application must handle the flush implications explicitly. In order* to change a 4MB segment from copyback to writethrough, first use* cacheFlush on the entire 4MB segment to flush any dirty cache lines,* then use mmuStateSet on the first page of the segment to change the* caching attributes from copyback to writethrough.* * 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** RETURNS: OK, or ERROR if descriptor address does not exist.*/LOCAL STATUS mmu800StateSet ( 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_1_DESC * pLvl1Desc; /* level 1 descriptor address */ LEVEL_1_DESC lvl1Desc,oldLvl1Desc; /* level 1 descriptor */ LEVEL_2_DESC * pLvl2Desc; /* level 2 descriptor address */ LEVEL_2_DESC lvl2Desc,oldLvl2Desc; /* level 2 descriptor */ /* get the level 1 descriptor address */ pLvl1Desc = mmu800Lvl1DescAddrGet (pTransTbl, effectiveAddr); /* * get the level 2 descriptor address. If this descriptor address doesn't * exist then set errno and return ERROR. */ if (mmu800Lvl2DescAddrGet (pTransTbl, effectiveAddr, &pLvl2Desc) == ERROR) { errno = S_mmuLib_NO_DESCRIPTOR; return (ERROR); } /* get the Level 1 Descriptor */ lvl1Desc.l1desc = pLvl1Desc->l1desc; oldLvl1Desc.l1desc = pLvl1Desc->l1desc; /* get the Level 2 Descriptor */ lvl2Desc.l2desc = pLvl2Desc->l2desc; oldLvl2Desc.l2desc = pLvl2Desc->l2desc; /* Any change of state in the cache requires the page in question to be flushed but not done until just before the tlb invalidate entry */ /* set the VALID bit if requested */ if (stateMask & MMU_STATE_MASK_VALID) { if ((state & MMU_STATE_MASK_VALID) == MMU_STATE_VALID) lvl2Desc.v = 1; /* set the Valid bit */ else lvl2Desc.v = 0; /* clear the Valid bit */ } /* set the CACHE state if requested */ if (stateMask & MMU_STATE_MASK_CACHEABLE) { if ((state & MMU_STATE_MASK_CACHEABLE) == MMU_STATE_CACHEABLE_NOT) lvl2Desc.ci = 1; /* set the Cache Inhibit bit */ else { lvl2Desc.ci = 0; /* clear the Cache Inhibit bit*/ if ((state & MMU_STATE_MASK_CACHEABLE) == MMU_STATE_CACHEABLE_WRITETHROUGH) lvl1Desc.wt = 1; /* set the writethrough cache */ else lvl1Desc.wt = 0; /* set the copyback cache */ } } /* set the GUARDED bit if requested */ if (stateMask & MMU_STATE_MASK_GUARDED) { if ((state & MMU_STATE_MASK_GUARDED) == MMU_STATE_GUARDED) lvl1Desc.g = 1; /* set the Guarded bit */ else lvl1Desc.g = 0; /* clear the Guarded bit */ } /* set/unset the WRITABLE BIT if requested */ if (stateMask & MMU_STATE_MASK_WRITABLE) { if ((state & MMU_STATE_MASK_WRITABLE) == MMU_STATE_WRITABLE) lvl2Desc.pp = 2; /* set to R/W */ else lvl2Desc.pp = 3; /* set to R/O */ } /* Flush page if cache inhibit is going to be set */ if ( (lvl2Desc.ci!=oldLvl2Desc.ci) && /* Have cache inhibit changed */ (lvl2Desc.ci==1) && /* Is it about to be marked cache inhibit */ (oldLvl1Desc.wt==0) && /* Only need to do this if in copyback mode */ (oldLvl2Desc.v==1) ) /* Make sure old page is valid */ cacheArchFlush(DATA_CACHE,effectiveAddr,PAGE_SIZE); mmu800Lvl1DescUpdate (pLvl1Desc, lvl1Desc); mmu800Lvl2DescUpdate (pLvl2Desc, lvl2Desc); /* Check to see if L1 descriptor has changed */ if ((lvl1Desc.g!=oldLvl1Desc.g) || (lvl1Desc.wt != oldLvl1Desc.wt)) /* L1 attribute so invalidate SEGMENT * Quicker than invalidating each page for 4MB * The number of TLB misses resulting in this command is assumed * to be inconsequential for system initialisation. */ mmuPpcTlbInvalidateAll(); else mmuPpcTlbie (effectiveAddr); /* invalidate page so new descriptor is loaded */ return (OK); }/******************************************************************************** mmu800StateGet - get state of virtual memory page**/LOCAL STATUS mmu800StateGet ( MMU_TRANS_TBL * pTransTbl, /* tranlation table */ void * effectiveAddr, /* page whose state we're querying */ UINT * state /* place to return state value */ ) { 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 = mmu800Lvl1DescAddrGet (pTransTbl, effectiveAddr); /* * get the level 2 descriptor address. If this descriptor address doesn't * exist then set errno and return ERROR. */ if (mmu800Lvl2DescAddrGet (pTransTbl, effectiveAddr, &pLvl2Desc) == ERROR) { errno = S_mmuLib_NO_DESCRIPTOR; return (ERROR); } /* get the Level 1 Descriptor */ lvl1Desc.l1desc = pLvl1Desc->l1desc; /* get the Level 2 Descriptor */ lvl2Desc.l2desc = pLvl2Desc->l2desc; *state=0; /* Get the various supported MMU states */ if (lvl1Desc.wt==1) *state |= MMU_STATE_CACHEABLE_WRITETHROUGH; if (lvl1Desc.g==1) *state |= MMU_STATE_GUARDED; if (lvl2Desc.v==1) *state |= MMU_STATE_VALID; if (lvl2Desc.ci==0) *state |= MMU_STATE_CACHEABLE; if (lvl2Desc.pp==2) *state |= MMU_STATE_WRITABLE; return (OK); }/******************************************************************************** mmu800PageMap - 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 mmu800PageMap ( 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 */ u_int ix; /* counter */ /* get the level 1 descriptor address */ pLvl1Desc = mmu800Lvl1DescAddrGet (pTransTbl, effectiveAddr); /* get the level 1 descriptor */ lvl1Desc.l1desc = pLvl1Desc->l1desc; if (!lvl1Desc.v) { /* * the level 2 desciptor is not valid (doesn't exit) then * allocate a piece of memory to save the level 2 desciptor table */ pLvl2Desc = (LEVEL_2_DESC *) memalign (PAGE_SIZE, PAGE_SIZE); /* * 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.rpn = 0; /* Real page Number */ lvl2Desc.pp = 2; /* Executable Read/Write page */ lvl2Desc.ppe = 0; /* PowerPC encoding */ lvl2Desc.c = 0; /* Not changed page */ lvl2Desc.spv = 0xf; /* All sub-page valid */ lvl2Desc.sps = 0; /* 4 K Bytes page */ lvl2Desc.sh = 1; /* ASID comparaison disabled */ lvl2Desc.v = 0; /* Page Not Valid */ for (ix = 0; ix < MMU_LVL_2_DESC_NB; ix ++) pLvl2Desc[ix] = lvl2Desc; /* * set the Level 1 Descriptor with default option for the * new level 2 descriptor table created. */ lvl1Desc.l1desc = ((u_int) pLvl2Desc) & MMU_LVL_1_L2BA_MSK; lvl1Desc.apg = 0; /* use the Access Protection Group Number 0 */ lvl1Desc.g = 0; /* not guarded */ lvl1Desc.ps = 0; /* small page size (4k or 16k) */ lvl1Desc.wt = 0; /* cache copyback mode */ lvl1Desc.v = 1; /* segment valid */ /* update the Level 1 descriptor in table */ mmu800Lvl1DescUpdate (pLvl1Desc, lvl1Desc); } /* * Get the level 2 descriptor address. If the level 2 descriptor doesn't * exist then return ERROR. */ if (mmu800Lvl2DescAddrGet (pTransTbl, effectiveAddr, &pLvl2Desc) == ERROR) return (ERROR); /* get the level 1 descriptor */ lvl2Desc.l2desc = pLvl2Desc->l2desc; /* save the real address in the level 2 descriptors */ lvl2Desc.rpn = (u_int) physicalAddr >> MMU_RPN_SHIFT;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -