📄 mmulib.c
字号:
return OK;#else /* !ARM_HAS_MPU */ return ERROR;#endif /* !ARM_HAS_MPU */ } /* mmuTransTblDelete() */ #if (!ARM_HAS_MPU)/******************************************************************************** mmuVirtualPageCreate - set up translation tables for a virtual page (ARM)** Simply check if there's already a lower level page table that has a page* table entry for the given virtual page. If there isn't, create one.** RETURNS: OK or ERROR if couldn't allocate space for lower level page table.*/LOCAL STATUS mmuVirtualPageCreate ( MMU_TRANS_TBL * thisTbl, /* translation table */ void * virtPageAddr /* virtual addr to create */ ) { LEVEL_1_DESC * pL1; /* Level 1 descriptor entry */ PTE * pPte; /* page table entry */ /* If the virtual address already has a page table, then we've finished */ if (mmuPteGet (thisTbl, virtPageAddr, &pPte) == OK) return OK; /* * The PTE doesn't exist, so create one. Allocate a "mini-heap" * on a page aligned boundary and parcel out the 1k chunks needed by * second level page table entries until they are exhausted. Then allocate * and parcel the next "mini-heap". In this way, memory waste is * significantly decreased. */ if ( mmuSecondLevelMiniHeap == NULL || mmuSecondLevelMiniHeap_Index >= mmuSecondLevelMiniHeap_Max ) { mmuSecondLevelMiniHeap = (UINT8 *) memPartAlignedAlloc (mmuPageSource, mmuSecondLevelMiniHeap_Size, mmuPageSize); if (mmuSecondLevelMiniHeap == NULL) return ERROR; mmuSecondLevelMiniHeap_Index = 0; /* * Invalidate every page table entry in the new Page Table. All will be * fault Level 2 descriptors. */ memset ((char *) mmuSecondLevelMiniHeap, 0, mmuSecondLevelMiniHeap_Size); } /* * Assign a PTE from the mini-heap. */ pPte = (PTE *)(mmuSecondLevelMiniHeap + (mmuSecondLevelMiniHeap_Index++ * L2_PTE_SIZE)) ; /* * If this pPte is on a page boundary, then set the cacheable * state. */ if ( ( ((int)pPte) & (mmuPageSize - 1 )) == 0) { /* * mmuStateSet() will flush the cache for this page before changing * its state */#if (ARMMMU == ARMMMU_XSCALE) /* * We use the current page instead of the current pPte */ mmuStateSet (&mmuGlobalTransTbl, pPte, MMU_STATE_MASK_WRITABLE | MMU_STATE_MASK_CACHEABLE | \ MMU_STATE_MASK_EX_CACHEABLE, MMU_STATE_WRITABLE_NOT | MMU_STATE_CACHEABLE_NOT | \ MMU_STATE_EX_CACHEABLE_NOT);#else /* * We use the current page instead of the current pPte */ mmuStateSet (&mmuGlobalTransTbl, pPte, MMU_STATE_MASK_WRITABLE | MMU_STATE_MASK_CACHEABLE, MMU_STATE_WRITABLE_NOT | MMU_STATE_CACHEABLE_NOT);#endif } /* * Unlock the physical pages containing the Level 1 Descriptor table, * so we can modify them. */ mmuStateSetMultiple (&mmuGlobalTransTbl, thisTbl->pLevel1Table, MMU_STATE_MASK_WRITABLE, MMU_STATE_WRITABLE, L1_DESC_PAGES); pL1 = &thisTbl->pLevel1Table [(UINT) virtPageAddr/PAGE_BLOCK_SIZE]; /* modify the Level 1 Descriptor to point to the new page table */ pL1->bits = DEF_L1_PAGE; /* Page Table descriptor, domain 0 */ pPte = _func_armVirtToPhys (pPte); /* conv Virtual to Physical Address*/ pL1->fields.addr = ((UINT) pPte) >> L1D_TO_BASE_SHIFT; /* (Re)write-protect the Level 1 Descriptor table */ mmuStateSetMultiple (&mmuGlobalTransTbl, thisTbl->pLevel1Table, MMU_STATE_MASK_WRITABLE, MMU_STATE_WRITABLE_NOT, L1_DESC_PAGES); return OK; } /* mmuVirtualPageCreate() */ #endif (!ARM_HAS_MPU)/******************************************************************************** mmuEnable - turn MMU on or off (ARM)** SEE ALSO:* .I "ARM Architecture Reference"** RETURNS: OK*/LOCAL STATUS mmuEnable ( BOOL enable /* TRUE to enable, FALSE to disable MMU */ ) { FAST int oldIntLev; LOCAL BOOL firstTime = TRUE; /* * We cannot unilaterally protect against FIQ as the cacheClear * operation may take too long. */ oldIntLev = cacheArchIntLock (); if (enable) { /* * Invalidate all TLBs. If MMU is not currently on, then we * could be about to start using whatever has been left * behind in them. */#if (!ARM_HAS_MPU) /* MPUs don't have TLBs */ mmuTLBIDFlushAll ();#endif if (firstTime) {#if (!ARM_HAS_MPU) /* * Set Access Control for domain zero to 01: client i.e. * all accesses are checked against the Access Permissions in * the page table entry. We only use domain zero, Access * control for the other domains is set to 00: any access * will cause a domain fault. */ mmuDacrSet (0x1);#endif /* (!ARM_HAS_MPU) */ /* * Initialize MMU Control Register. Some should have been done, in * order to get us here at all. However, here we will set: * * M 1 Enable MMU * A 0 Enable address alignment fault * C X (D-)Cache Enable) Controlled by cacheLib * W X (Write Buffer) Controlled by cacheLib * P X (PROG32) should have been set before here. * D X (DATA32) should have been set before here. * L X (Late abort on earlier CPUs) ignore * B X (Big/Little-endian) should have been set before here. * S 0 (System) } SBZ on MPUs * R 1 (ROM) } * F 0 (Should be Zero) * Z X (Branch prediction enable on 810) Controlled by cacheLib * I X (I-cache enable) Controlled by cacheLib */ /* set the above and any bits needed by cacheArchLib */ mmuModifyCr (MMU_ENABLE_VALUE | cacheArchState, MMU_ENABLE_MASK | cacheArchState); firstTime = FALSE; } else /* not first time */ mmuAEnable (cacheArchState); /* * Clear (flush and invalidate) the data cache (some pages may not be * cacheable). */ cacheClear (DATA_CACHE, 0, ENTIRE_CACHE); /* * cacheEnable() may have been called before this, when the MMU was off * so set cacheDataEnabled accordingly, then call cacheFuncsSet() to * set up the appropriate function pointers. */ cacheDataEnabled = ((cacheArchState & MMUCR_C_ENABLE) != 0); } else /* disable */ { /* * Clear (flush and invalidate) the data cache. Leave nothing * behind in the cache, which might either be dirty, or might * continue to be used. */ cacheClear (DATA_CACHE, 0, ENTIRE_CACHE); mmuADisable ();#if (!ARM_HAS_MPU) /* Invalidate all TLB entries: tidiness really, leave nothing behind */ mmuTLBIDFlushAll ();#endif /* (!ARM_HAS_MPU) */ cacheDataEnabled = FALSE; } /* Set up function pointers appropriate to actual cache enabled state */ cacheFuncsSet (); /* Invalidate the instruction cache */ cacheInvalidate (INSTRUCTION_CACHE, 0, ENTIRE_CACHE); mmuEnabled = enable; intIFUnlock (oldIntLev); return OK; } /* mmuEnable() */ #if (!ARM_HAS_MPU)/******************************************************************************** mmuStateSet - set state of virtual memory page (ARM)** 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 valid/invalid* MMU_STATE_WRITABLE MMU_STATE_WRITABLE_NOT writable/writeprotected* MMU_STATE_CACHEABLE MMU_STATE_CACHEABLE_NOT cacheable/not cacheable** These may be OR'd 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_CACEHABLE** These may be OR'd 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 */ ) { PTE * pPte; int oldIntLev; if (mmuPteGet (transTbl, pageAddr, &pPte) != OK) return ERROR; /* * We are about to change the state of a page. We may be about to change * the page from cached to uncached, or mark it invalid, so we must clear * (write out to memory and invalidate from the cache) the whole page. */ cacheClear (DATA_CACHE, pageAddr, mmuPageSize);#if ARMCACHE_NOT_COHERENT /* On 810, this will just do an IMB */ cacheClear (INSTRUCTION_CACHE, pageAddr, mmuPageSize);#endif /* modify the PTE with MMU protection turned off and ints locked out */ MMU_UNLOCK (oldIntLev); pPte->bits = (pPte->bits & ~stateMask) | (state & stateMask); MMU_LOCK (oldIntLev); /* * Page entry has been updated in memory so flush the entry in the TLB * to be sure that the TLB will be updated during the next access to this * address. */ mmuTLBIDFlushEntry (pageAddr); return OK; } /* mmuStateSet() */ #else /* ARM_HAS_MPU *//******************************************************************************** mmuDeleteRegion - delete memory region (ARM)** This routine deletes an address region definition, shuffling the* other (higher priority) regions down, if necessary, in an MPU.** The MPU must be disabled while this routine is called.** RETURNS: N/A.*/LOCAL void mmuDeleteRegion ( MPU_REGION_REG * regs, /* the Protection Region Registers */ int region /* the region number */ ) { int i; UINT32 ccr, wbcr, cpr, mask1, mask2; /* * We already have the protection region registers. Get the cache * control register, the write-buffer control register and the cache * protection registers. */ ccr = mmuCcrGet(); wbcr = mmuWbcrGet(); cpr = mmuPrGet(); /* shuffle the regions down from above this region */ for (i = region; i < (MPU_NUM_REGIONS - 1); i++) regs[i].bits = regs[i+1].bits; /* shuffle down the contents of the other registers */ mask1 = 0xFFFFFFFF << region; mask2 = 0xFFFFFFFF << (region + 1); ccr &= (ccr & ~mask1); ccr |= ((ccr & mask2) >> 1); wbcr &= (wbcr & ~mask1); wbcr |= ((wbcr & mask2) >> 1); mask1 = 0xFFFFFFFF << (region * 2);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -