📄 mmush7750lib.c
字号:
/* reset mmu (SV=1 TI=1 AT=1) * * XXX - We needed a way to customize the MMUCR init value to reserve some * TLB entries for SH7751 virtual PCI mapping. It is desirable to get * this value as an argument but here we import excMmuCrVal to keep the * function prototype of mmuSh7750LibInit(). Now the excMmuCrVal is 0 in * excArchLib, or it is modified if BSP called excPciMmuInit(). You might * want to own excMmuCrVal in mmuSh7750Lib and export it to excArchLib, * but then a bunch of MMU stuff is pulled into Boot ROM! (23oct01:hk) */ mmuCrSet (excMmuCrVal != 0 ? excMmuCrVal : 0x00000104); /* if the user has not specified a memory partition to obtain pages * from (by initializing mmuPageSource), then initialize mmuPageSource * to the system memory partition. */ if (mmuPageSource == NULL) mmuPageSource = memSysPartId; /* initialize the data objects that are shared with vmLib.c */ mmuStateTransArray = &mmuStateTransArrayLocal [0]; mmuStateTransArraySize = sizeof(mmuStateTransArrayLocal) / sizeof(STATE_TRANS_TUPLE); mmuLibFuncs = mmuLibFuncsLocal; mmuPageBlockSize = PAGE_BLOCK_SIZE; if (pageSize != 4096) { errno = S_mmuLib_INVALID_PAGE_SIZE; return ERROR; } mmuPageSize = 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 *)); /* 64 x 4 */ 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.vUpperTbl = v_page = (PTE *)mmuPageAlloc (&mmuGlobalTransTbl); if (v_page == NULL) return ERROR; for (i = 0; i < UPPER_TBL_SIZE; i++) v_page[i].pte.td.asint = -1; /* invalidate all descriptors */ /* write back the upper level table onto physical memory */ cacheClear (DATA_CACHE, v_page, UPPER_TBL_SIZE * sizeof(PTE)); return OK; }/******************************************************************************** mmuTransTblCreate - create a new translation table.** create a 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 *transTbl = (MMU_TRANS_TBL *)malloc (sizeof(MMU_TRANS_TBL)); if (transTbl == NULL) return NULL; if (mmuTransTblInit (transTbl) == ERROR) { free ((char *)transTbl); return NULL; } return transTbl; }/******************************************************************************** mmuTransTblInit - initialize a new translation table ** Initialize a new translation table. The upper level is copied from the* global translation mmuGlobalTransTbl, so that we will share the global* virtual memory with all other translation tables.** NOTE: This routine is called from mmuTransTblCreate() only.* * RETURNS: OK or ERROR if unable to allocate memory for upper level.*/LOCAL STATUS mmuTransTblInit ( MMU_TRANS_TBL *transTbl ) { PTE *v_page; /* virtual address of upper page table */ lstInit (&transTbl->memFreePageList); transTbl->memBlocksUsedArray = calloc (MMU_BLOCKS_USED_SIZE,sizeof(void *)); if (transTbl->memBlocksUsedArray == NULL) return ERROR; transTbl->memBlocksUsedIndex = 0; transTbl->memBlocksUsedSize = MMU_BLOCKS_USED_SIZE; /* allocate a page to hold the upper level descriptor array */ transTbl->vUpperTbl = v_page = (PTE *)mmuPageAlloc (transTbl); if (v_page == NULL) return ERROR; /* copy the upperlevel table from mmuGlobalTransTbl, * so we get the global virtual memory */ bcopy ((char *)mmuGlobalTransTbl.vUpperTbl, (char *)v_page, mmuPageSize); /* write back the upper table onto physical memory */ cacheClear (DATA_CACHE, v_page, 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 *)v_page, MMU_STATE_MASK_WRITABLE | MMU_STATE_MASK_CACHEABLE, MMU_STATE_WRITABLE_NOT | MMU_STATE_CACHEABLE_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 ) { int i; /* write enable the physical page containing the upper level pte */ mmuStateSet (&mmuGlobalTransTbl, transTbl->vUpperTbl, 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 ptel 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 ptel array.*/LOCAL STATUS mmuVirtualPageCreate ( MMU_TRANS_TBL *transTbl, void *v_addr /* virtual addr to create */ ) { PTE *vUpperPte; PTE *v_page; PTE *dummy; UINT i; if (mmuPteGet (transTbl, v_addr, &dummy) == OK) return OK; v_page = (PTE *)mmuPageAlloc (transTbl); /* virtual address */ if (v_page == NULL) return ERROR; /* invalidate every page in the new page block */ for (i = 0; i < LOWER_TBL_SIZE; i++) { v_page[i].pte.l.bits = 0;#if (CPU==SH7700) v_page[i].pte.l.fields.ppn = -1; v_page[i].pte.l.fields.valid = 0; v_page[i].pte.l.fields.protection = 0; v_page[i].pte.l.fields.size = 1; /* 4k bytes page */ v_page[i].pte.l.fields.cachable = 0; v_page[i].pte.l.fields.dirty = 1; v_page[i].pte.l.fields.share = 0;#elif (CPU==SH7750) v_page[i].pte.l.fields.ppn = -1; v_page[i].pte.l.fields.valid = 0; v_page[i].pte.l.fields.size1 = 0; /* 4k bytes page */ v_page[i].pte.l.fields.protection = 0; v_page[i].pte.l.fields.size2 = 1; /* 4k bytes page */ v_page[i].pte.l.fields.cachable = 0; v_page[i].pte.l.fields.dirty = 1; v_page[i].pte.l.fields.share = 0; v_page[i].pte.l.fields.wt = 0;#endif } /* write back the lower level table onto physical memory */ cacheClear (DATA_CACHE, v_page, LOWER_TBL_SIZE * sizeof(PTE)); /* write protect the new physical page containing the pte's * for this new page block */ mmuStateSet (&mmuGlobalTransTbl, v_page, MMU_STATE_MASK_WRITABLE | MMU_STATE_MASK_CACHEABLE, MMU_STATE_WRITABLE_NOT | MMU_STATE_CACHEABLE_NOT); /* unlock the physical page containing the upper level pte, * so we can modify it */ mmuStateSet (&mmuGlobalTransTbl, transTbl->vUpperTbl, MMU_STATE_MASK_WRITABLE, MMU_STATE_WRITABLE); vUpperPte = &transTbl->vUpperTbl [(UINT)v_addr / PAGE_BLOCK_SIZE]; /* modify the upperLevel pte to point to the new lowerLevel pte */ vUpperPte->pte.td.adrs = (PAGE_DESC *)(((UINT32)v_page & SH7750_PHYS_MASK) | mmuTransTblSpace); /* write back the upperLevel pte onto physical memory */ cacheClear (DATA_CACHE, vUpperPte, sizeof(PTE)); /* write protect the upper level pte table */ mmuStateSet (&mmuGlobalTransTbl, transTbl->vUpperTbl, MMU_STATE_MASK_WRITABLE | MMU_STATE_MASK_CACHEABLE, MMU_STATE_WRITABLE_NOT | MMU_STATE_CACHEABLE_NOT); mmuTLBFlush (v_addr); return OK; }/******************************************************************************** mmuEnable - turn mmu on or off* */LOCAL STATUS mmuEnable ( BOOL enable ) { int key = intLock (); /* LOCK INTERRUPTS */ mmuOn (enable); intUnlock (key); /* UNLOCK INTERRUPTS */ return OK; }/******************************************************************************** mmuStateGet - get state of virtual memory page** mmuStateGet is used to retrieve 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 notcachable/cachable* MMU_STATE_CACHEABLE_WRITETHROUGH write through(SH7750)** these are or'ed together in the returned state. Additionally, masks* are provided so that specific states may be extracted from the returned state:** MMU_STATE_MASK_VALID * MMU_STATE_MASK_WRITABLE* MMU_STATE_MASK_CACHEABLE** RETURNS: OK or ERROR if virtual page does not exist.*/LOCAL STATUS mmuStateGet ( MMU_TRANS_TBL *transTbl, void *v_addr, /* page whose state we're querying */ UINT *state /* place to return state value */ ) { PTE *pPhys; if (mmuPteGet (transTbl, v_addr, &pPhys) != OK) return ERROR; *state = pPhys->pte.l.bits; return OK; }/******************************************************************************** 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 valid/invalid* MMU_STATE_WRITABLE MMU_STATE_WRITABLE_NOT writable/writeprotected* MMU_STATE_CACHEABLE MMU_STATE_CACHEABLE_NOT notcachable/cachable* MMU_STATE_CACHEABLE_WRITETHROUGH write through (SH7750)** 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, void *v_addr, /* virtual page whose state to modify */ UINT stateMask, /* mask of which state bits to modify */ UINT state /* new state bit values */ ) { int key; PTE *pPte; /* physical address of PTE on memory */ if (mmuPteGet (transTbl, v_addr, &pPte) != OK) return ERROR; /* modify the pte with mmu turned off and interrupts locked out */ key = intLock (); mmuATTRSet (pPte, stateMask, state, v_addr); intUnlock (key); return OK; }/******************************************************************************** mmuPageMap - map physical memory page to virtual memory page** The physical page address is entered into the pte 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 mmuPageMap (
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -