📄 mmupro36lib.c
字号:
mmuCurrentSet };/******************************************************************************** mmuPro36LibInit - initialize module** Build a dummy translation table that will hold the page table entries* for the global translation table. The mmu remains disabled upon* completion.** RETURNS: OK if no error, ERROR otherwise** ERRNO: S_mmuLib_INVALID_PAGE_SIZE*/STATUS mmuPro36LibInit ( int pageSize /* system pageSize (must be 4KB or 2MB) */ ) { PTE * pDirectoryPtrTable; PTE * pDirectoryTable; INT32 ix; /* check if the PSE and PAE are supported */ if ((sysCpuId.featuresEdx & (CPUID_PAE | CPUID_PSE)) != (CPUID_PAE | CPUID_PSE)) return (ERROR); /* 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; /* we assume a 4KB or 2MB page size */ if ((pageSize != PAGE_SIZE_4KB) && (pageSize != PAGE_SIZE_2MB)) { errno = S_mmuLib_INVALID_PAGE_SIZE; return (ERROR); } mmuPro36Enabled = FALSE; mmuPageSize = pageSize; /* * set number of pages for the page directory table * 2048 (4 * 512) PDEs * 8 byte = 16384 byte */ nDirPages = (mmuPageSize == PAGE_SIZE_4KB) ? 4 : 1; /* * allocate the global page block array to keep track of which parts * of virtual memory are handled by the global translation tables. * Allocate on page boundary so we can write protect it. */ globalPageBlock = (UINT8 *) memalign (mmuPageSize, mmuPageSize); if (globalPageBlock == NULL) return (ERROR); bzero ((char *) globalPageBlock, mmuPageSize); /* * build a dummy translation table which will hold the PTE's for * global memory. All real translation tables will point to this * one for controlling the state of the global virtual memory */ /* allocate pages to hold the directory table */ pDirectoryTable = (PTE *) memalign (mmuPageSize, mmuPageSize * nDirPages); if (pDirectoryTable == NULL) { free (globalPageBlock); return (ERROR); } /* allocate a page to hold the directory pointer table */ mmuGlobalTransTbl.pDirectoryTable = pDirectoryPtrTable = (PTE *) memalign (mmuPageSize, mmuPageSize); if (pDirectoryPtrTable == NULL) { free (globalPageBlock); free (pDirectoryTable); return (ERROR); } bzero ((char *) pDirectoryPtrTable, mmuPageSize); /* validate all the directory pointer table entries */ for (ix = 0; ix < mmuPdpTableNumEnt; ix++) { pDirectoryPtrTable[ix].bits[0] = (UINT)pDirectoryTable + (PD_SIZE * ix); pDirectoryPtrTable[ix].bits[1] = 0; pDirectoryPtrTable[ix].field.present = 1; pDirectoryPtrTable[ix].field.pwt = 0; pDirectoryPtrTable[ix].field.pcd = 0; } /* invalidate all the directory table entries */ for (ix = 0; ix < ((PD_SIZE * 4) / sizeof(PTE)); ix++) { pDirectoryTable[ix].field.present = 0; pDirectoryTable[ix].field.rw = 0; pDirectoryTable[ix].field.us = 0; pDirectoryTable[ix].field.pwt = 0; pDirectoryTable[ix].field.pcd = 0; pDirectoryTable[ix].field.access = 0; pDirectoryTable[ix].field.dirty = 0; if (pageSize == PAGE_SIZE_4KB) pDirectoryTable[ix].field.pagesize = 0; else pDirectoryTable[ix].field.pagesize = 1; pDirectoryTable[ix].field.global = 0; pDirectoryTable[ix].field.avail = 0; pDirectoryTable[ix].field.page = -1; pDirectoryTable[ix].field.page36 = 0; pDirectoryTable[ix].field.reserved = 0; } /* set CR4 register: PAE=1 PSE=0/1 PGE=1 */ if (pageSize == PAGE_SIZE_4KB) vxCr4Set ((vxCr4Get() & ~CR4_PSE) | (CR4_PAE | CR4_PGE)); else vxCr4Set (vxCr4Get() | (CR4_PSE | CR4_PAE | CR4_PGE)); return (OK); }/******************************************************************************** mmuPteGet - get the PTE for a given page** mmuPteGet traverses a translation table and returns the (physical) address of* the PTE for the given virtual address.** RETURNS: OK or ERROR if there is no virtual space for the given address **/LOCAL STATUS mmuPteGet ( MMU_TRANS_TBL *pTransTbl, /* translation table */ void *virtAddr, /* virtual address */ PTE **result /* result is returned here */ ) { PTE * pDte; /* directory table entry */ PTE * pDirectoryTable; /* directory table */ PTE * pPageTable; /* page table */ pDirectoryTable = (PTE *) (pTransTbl->pDirectoryTable->bits[0] & PDP_TO_ADDR); pDte = &pDirectoryTable [((UINT) virtAddr & (DIR_PTR_BITS | DIR_BITS)) >> DIR_INDEX]; if (mmuPageSize == PAGE_SIZE_4KB) { pPageTable = (PTE *) (pDte->bits[0] & PTE_TO_ADDR_4KB); if ((UINT) pPageTable == (0xffffffff & PTE_TO_ADDR_4KB)) return (ERROR); *result = &pPageTable [((UINT) virtAddr & TBL_BITS) >> TBL_INDEX]; } else { if ((UINT) pDte == (0xffffffff & PTE_TO_ADDR_2MB)) return (ERROR); *result = pDte; } return (OK); }/******************************************************************************** mmuTransTblCreate - create a new translation table.** create a i86 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 * newTransTbl; INT32 oldIntLev = 0; BOOL wasEnabled; MMU_UNLOCK (wasEnabled, oldIntLev); newTransTbl = (MMU_TRANS_TBL *) malloc (sizeof (MMU_TRANS_TBL)); MMU_LOCK (wasEnabled, oldIntLev); if (newTransTbl == NULL) return (NULL); if (mmuTransTblInit (newTransTbl) == ERROR) { free ((char *) newTransTbl); return (NULL); } return (newTransTbl); }/******************************************************************************** mmuTransTblInit - initialize a new translation table ** Initialize a new translation table. The directory 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 for directory table.*/LOCAL STATUS mmuTransTblInit ( MMU_TRANS_TBL *newTransTbl /* translation table to be inited */ ) { PTE * pDirectoryPtrTable; /* directory pointer table */ PTE * pDirectoryTable; /* directory table */ INT32 oldIntLev = 0; BOOL wasEnabled; INT32 ix; /* allocate a page to hold the directory pointer table */ MMU_UNLOCK (wasEnabled, oldIntLev); newTransTbl->pDirectoryTable = pDirectoryPtrTable = (PTE *) memalign (mmuPageSize, mmuPageSize); MMU_LOCK (wasEnabled, oldIntLev); if (pDirectoryPtrTable == NULL) return (ERROR); /* allocate pages to hold the directory table */ MMU_UNLOCK (wasEnabled, oldIntLev); pDirectoryTable = (PTE *) memalign (mmuPageSize, mmuPageSize * nDirPages); MMU_LOCK (wasEnabled, oldIntLev); if (pDirectoryTable == NULL) { free (pDirectoryPtrTable); return (ERROR); } /* setup the directory pointer table */ for (ix = 0; ix < mmuPdpTableNumEnt; ix++) { pDirectoryPtrTable[ix].bits[0] = (UINT)pDirectoryTable + (PD_SIZE * ix); pDirectoryPtrTable[ix].bits[1] = 0; pDirectoryPtrTable[ix].field.present = 1; pDirectoryPtrTable[ix].field.pwt = 0; pDirectoryPtrTable[ix].field.pcd = 0; } /* * copy the directory table from the mmuGlobalTransTbl, * so we get the global virtual memory */ bcopy ((char *) (mmuGlobalTransTbl.pDirectoryTable->bits[0] & PDP_TO_ADDR), (char *) pDirectoryTable, PD_SIZE * 4); /* * write protect virtual memory pointing to the directory pointer table * and the directory table in the global translation table to insure * that it can't be corrupted */ for (ix = 0; ix < nDirPages; ix++) { mmuStateSet (&mmuGlobalTransTbl, (void *) ((UINT)pDirectoryTable + (mmuPageSize * ix)), MMU_STATE_MASK_WRITABLE, MMU_STATE_WRITABLE_NOT); } mmuStateSet (&mmuGlobalTransTbl, (void *) pDirectoryPtrTable, MMU_STATE_MASK_WRITABLE, MMU_STATE_WRITABLE_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 /* translation table to be deleted */ ) { PTE * pDte; PTE * pDirectoryTable; /* directory table */ PTE * pPageTable; INT32 ix; /* write enable the physical page containing the directory ptr table */ mmuStateSet (&mmuGlobalTransTbl, transTbl->pDirectoryTable, MMU_STATE_MASK_WRITABLE, MMU_STATE_WRITABLE); /* write enable the physical page containing the directory table */ pDirectoryTable = (PTE *)(transTbl->pDirectoryTable->bits[0] & PDP_TO_ADDR); for (ix = 0; ix < nDirPages; ix++) { pDte = (PTE *)((UINT)pDirectoryTable + (mmuPageSize * ix)); mmuStateSet (&mmuGlobalTransTbl, pDte, MMU_STATE_MASK_WRITABLE, MMU_STATE_WRITABLE); } /* deallocate only non-global page blocks */ pDte = pDirectoryTable; if (mmuPageSize == PAGE_SIZE_4KB) for (ix = 0; ix < ((PD_SIZE * 4) / sizeof(PTE)); ix++, pDte++) if ((pDte->field.present == 1) && !globalPageBlock[ix]) { pPageTable = (PTE *) (pDte->bits[0] & PTE_TO_ADDR_4KB); mmuStateSet (&mmuGlobalTransTbl, pPageTable, MMU_STATE_MASK_WRITABLE, MMU_STATE_WRITABLE); free (pPageTable); } /* free the pages holding the directory table */ free ((void *) (transTbl->pDirectoryTable->bits[0] & PDP_TO_ADDR)); /* free the page holding the directory pointer table */ free (transTbl->pDirectoryTable); /* 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 page table that has a* PTE for the given virtual page. If there isn't, create one.* this routine is called only if the page size is 4KB, since a page table* is not necessary for 2MB or 4MB page sizes.** RETURNS OK or ERROR if couldn't allocate space for a page table.*/LOCAL STATUS mmuVirtualPageCreate ( MMU_TRANS_TBL *thisTbl, /* translation table */ void *virtPageAddr /* virtual addr to create */ ) { PTE * pDirectoryTable; /* directory table */ PTE * pPageTable; /* page table */ PTE * pDte; /* directory table entry */ PTE * dummy; INT32 oldIntLev = 0; BOOL wasEnabled; UINT ix; if (mmuPteGet (thisTbl, virtPageAddr, &dummy) == OK) return (OK); MMU_UNLOCK (wasEnabled, oldIntLev); pPageTable = (PTE *) memalign (mmuPageSize, mmuPageSize); MMU_LOCK (wasEnabled, oldIntLev); if (pPageTable == NULL) return (ERROR); /* invalidate every page in the new page block */ for (ix = 0; ix < (PT_SIZE / sizeof(PTE)); ix++) { pPageTable[ix].field.present = 0; pPageTable[ix].field.rw = 0; pPageTable[ix].field.us = 0; pPageTable[ix].field.pwt = 0; pPageTable[ix].field.pcd = 0; pPageTable[ix].field.access = 0; pPageTable[ix].field.dirty = 0; pPageTable[ix].field.pagesize = 0; pPageTable[ix].field.global = 0; pPageTable[ix].field.avail = 0; pPageTable[ix].field.page = -1; pPageTable[ix].field.page36 = 0; pPageTable[ix].field.reserved = 0; } /* * write protect the new physical page containing the PTE's * for this new page block */ mmuStateSet (&mmuGlobalTransTbl, pPageTable, MMU_STATE_MASK_WRITABLE, MMU_STATE_WRITABLE_NOT); /* * unlock the physical page containing the directory pointer table * and the directory table, so we can modify it */ pDirectoryTable = (PTE *) (thisTbl->pDirectoryTable->bits[0] & PDP_TO_ADDR); for (ix = 0; ix < nDirPages; ix++) { mmuStateSet (&mmuGlobalTransTbl, (void *) ((UINT32)pDirectoryTable + (mmuPageSize * ix)), MMU_STATE_MASK_WRITABLE, MMU_STATE_WRITABLE); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -