mmuPro36Lib.c
上传用户:baixin
上传日期:2008-03-13
资源大小:4795k
文件大小:43k
开发平台:

MultiPlatform

  1. /* mmuPro36Lib.c - MMU library for PentiumPro/2/3/4 36 bit mode */
  2. /* Copyright 1984-2002 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 01i,23may02,hdn  aligned PT/DT at mmuPageSize boundary for 4K/2MB page size
  8.  imported updates from mmuPro32Lib.c
  9. 01h,16may02,hdn  moved the GDT reloading to sysPhysMemTop() in sysLib.c
  10. 01g,27aug01,hdn  made MMU_TLB_FLUSH, updated MMU_LOCK/MMU_UNLOCK macros.
  11.  initialized oldIntLev to shut off warnings.
  12. 01f,09feb99,wsl  add comment to document ERRNO value
  13. 01e,17sep98,hdn  renamed mmuEnabled to mmuPro36Enabled.
  14. 01d,13apr98,hdn  added support for 4KB/2MB page for PentiumPro w PAE.
  15. 01c,07jan95,hdn  re-initialized the GDT in mmuLibInit().
  16. 01b,01nov94,hdn  added a support for COPY_BACK cache mode for Pentium.
  17. 01a,26jul93,hdn  written based on mc68k's version.
  18. */
  19. /*
  20. DESCRIPTION:
  21. mmuPro36Lib.c provides the architecture dependent routines that directly control
  22. the memory management unit.  It provides 10 routines that are called by the
  23. higher level architecture independent routines in vmLib.c: 
  24.  mmuPro36LibInit() - initialize module
  25.  mmuTransTblCreate() - create a new translation table
  26.  mmuTransTblDelete() - delete a translation table.
  27.  mmuPro36Enable() - turn MMU on or off
  28.  mmuStateSet() - set state of virtual memory page
  29.  mmuStateGet() - get state of virtual memory page
  30.  mmuPageMap() - map physical memory page to virtual memory page
  31.  mmuGlobalPageMap() - map physical memory page to global virtual memory page
  32.  mmuTranslate() - translate a virtual address to a physical address
  33.  mmuCurrentSet() - change active translation table
  34. Applications using the MMU will never call these routines directly; 
  35. the visible interface is supported in vmLib.c.
  36. mmuLib supports the creation and maintenance of multiple translation tables,
  37. one of which is the active translation table when the MMU is enabled.  
  38. Note that VxWorks does not include a translation table as part of the task
  39. context;  individual tasks do not reside in private virtual memory.  However,
  40. we include the facilities to create multiple translation tables so that
  41. the user may create "private" virtual memory contexts and switch them in an
  42. application specific manner.  New
  43. translation tables are created with a call to mmuTransTblCreate(), and installed
  44. as the active translation table with mmuCurrentSet().  Translation tables
  45. are modified and potentially augmented with calls to mmuPageMap() and 
  46. mmuStateSet().
  47. The state of portions of the translation table can be read with calls to 
  48. mmuStateGet() and mmuTranslate().
  49. The traditional VxWorks architecture and design philosophy requires that all
  50. objects and operating systems resources be visible and accessible to all agents
  51. (tasks, isrs, watchdog timers, etc) in the system.  This has traditionally been
  52. insured by the fact that all objects and data structures reside in physical 
  53. memory; thus, a data structure created by one agent may be accessed by any
  54. other agent using the same pointer (object identifiers in VxWorks are often
  55. pointers to data structures.) This creates a potential 
  56. problem if you have multiple virtual memory contexts.  For example, if a
  57. semaphore is created in one virtual memory context, you must guarantee that
  58. that semaphore will be visible in all virtual memory contexts if the semaphore
  59. is to be accessed at interrupt level, when a virtual memory context other than
  60. the one in which it was created may be active. Another example is that
  61. code loaded using the incremental loader from the shell must be accessible
  62. in all virtual memory contexts, since code is shared by all agents in the
  63. system.
  64. This problem is resolved by maintaining a global "transparent" mapping
  65. of virtual to physical memory for all the contiguous segments of physical 
  66. memory (on board memory, i/o space, sections of vme space, etc) that is shared
  67. by all translation tables;  all available  physical memory appears at the same 
  68. address in virtual memory in all virtual memory contexts. This technique 
  69. provides an environment that allows
  70. resources that rely on a globally accessible physical address to run without
  71. modification in a system with multiple virtual memory contexts.
  72. An additional requirement is that modifications made to the state of global 
  73. virtual memory in one translation table appear in all translation tables.  For
  74. example, memory containing the text segment is made read only (to avoid
  75. accidental corruption) by setting the appropriate writable bits in the 
  76. translation table entries corresponding to the virtual memory containing the 
  77. text segment.  This state information must be shared by all virtual memory 
  78. contexts, so that no matter what translation table is active, the text segment
  79. is protected from corruption.  The mechanism that implements this feature is
  80. architecture dependent, but usually entails building a section of a 
  81. translation table that corresponds to the global memory, that is shared by
  82. all other translation tables.  Thus, when changes to the state of the global
  83. memory are made in one translation table, the changes are reflected in all
  84. other translation tables.
  85. mmuLib provides a separate call for constructing global virtual memory -
  86. mmuGlobalPageMap() - which creates translation table entries that are shared
  87. by all translation tables.  Initialization code in usrConfig makes calls
  88. to vmGlobalMap() (which in turn calls mmuGlobalPageMap()) to set up global 
  89. transparent virtual memory for all
  90. available physical memory.  All calls made to mmuGlobalPageMap() must occur 
  91. before any virtual memory contexts are created;  changes made to global virtual
  92. memory after virtual memory contexts are created are not guaranteed to be 
  93. reflected in all virtual memory contexts.
  94. Most MMU architectures will dedicate some fixed amount of virtual memory to 
  95. a minimal section of the translation table (a "segment", or "block").  This 
  96. creates a problem in that the user may map a small section of virtual memory
  97. into the global translation tables, and then attempt to use the virtual memory
  98. after this section as private virtual memory.  The problem is that the 
  99. translation table entries for this virtual memory are contained in the global 
  100. translation tables, and are thus shared by all translation tables.  This 
  101. condition is detected by vmMap, and an error is returned, thus, the lower
  102. level routines in mmuPro36Lib.c (mmuPageMap(), mmuGlobalPageMap()) need not 
  103. perform any error checking.
  104. A global variable `mmuPageBlockSize' should be defined which is equal to 
  105. the minimum virtual segment size.  
  106. This module supports the PentiumPro/2/3/4 MMU:
  107. .CS
  108.     PDBR
  109.      |
  110.      |
  111.             -------------------------
  112.             |pdp  |pdp  |pdp  |pdp  |
  113.             -------------------------
  114.      |
  115.              v
  116.             -------------------------------------
  117.  top level  |pde  |pde  |pde  |pde  |pde  |pde  | ... 
  118.             -------------------------------------
  119.        |     |     |     |     |     |    
  120.        |     |     |     |     |     |    
  121.       ----------     |     v     v     v     v
  122.       |         ------    NULL  NULL  NULL  NULL
  123.       |         |
  124.       v         v
  125.      ----     ----   
  126. l   |pte |   |pte |
  127. o    ----     ----
  128. w   |pte |   |pte |     
  129. e    ----     ----
  130. r   |pte |   |pte |
  131. l    ----     ----
  132. e   |pte |   |pte |
  133. v    ----     ----
  134. e     .         .
  135. l     .         .
  136.       .         .
  137. .CE
  138. where the top level consists of two tables that are the page directory
  139. pointer table and the page directory table which is an array of pointers 
  140. (Page Directory Entry) held within a single 4k page.  These point to 
  141. arrays of Page Table Entry arrays in the lower level.  Each of these 
  142. lower level arrays is also held within a single 4k page, and describes 
  143. a virtual space of 2 MB (each Page Table Entry is 8 bytes, so we get 
  144. 512 of these in each array, and each Page Table Entry maps a 4KB page - 
  145. thus 512 * 4096 = 2MB.)  
  146. To implement global virtual memory, a separate translation table called 
  147. mmuGlobalTransTbl is created when the module is initialized.  Calls to 
  148. mmuGlobalPageMap will augment and modify this translation table.  When new
  149. translation tables are created, memory for the top level array of sftd's is
  150. allocated and initialized by duplicating the pointers in mmuGlobalTransTbl's
  151. top level sftd array.  Thus, the new translation table will use the global
  152. translation table's state information for portions of virtual memory that are
  153. defined as global.  Here's a picture to illustrate:
  154. .CS
  155.          GLOBAL TRANS TBL       NEW TRANS TBL
  156.          PDBR    PDBR
  157.         |     |
  158.         |     |
  159.             -------------------------           -------------------------
  160.             |pdp  |pdp  |pdp  |pdp  |           |pdp  |pdp  |pdp  |pdp  |
  161.             -------------------------           -------------------------
  162.      |                                   |
  163.              v                                   v
  164.             -------------------------           -------------------------
  165.  top level  |pde  |pde  | NULL| NULL|           |pde  |pde  | NULL| NULL|
  166.             -------------------------           -------------------------
  167.        |     |     |     |                 |     |     |     |   
  168.        |     |     |     |                 |     |     |     |  
  169.       ----------     |     v     v        ----------     |     v     v
  170.       |         ------    NULL  NULL      |  |    NULL  NULL
  171.       |         |   |  |
  172.       o------------------------------------  |
  173.       | |  |
  174.       | o-----------------------------------------
  175.       | |
  176.       v         v
  177.      ----     ----   
  178. l   |pte |   |pte |
  179. o    ----     ----
  180. w   |pte |   |pte |     
  181. e    ----     ----
  182. r   |pte |   |pte |
  183. l    ----     ----
  184. e   |pte |   |pte |
  185. v    ----     ----
  186. e     .         .
  187. l     .         .
  188.       .         .
  189. .CE
  190. Note that with this scheme, the global memory granularity is 4MB.  Each time
  191. you map a section of global virtual memory, you dedicate at least 4MB of 
  192. the virtual space to global virtual memory that will be shared by all virtual
  193. memory contexts.
  194. The physical memory that holds these data structures is obtained from the
  195. system memory manager via memalign to insure that the memory is page
  196. aligned.  We want to protect this memory from being corrupted,
  197. so we invalidate the descriptors that we set up in the global translation
  198. that correspond to the memory containing the translation table data structures.
  199. This creates a "chicken and the egg" paradox, in that the only way we can
  200. modify these data structures is through virtual memory that is now invalidated,
  201. and we can't validate it because the page descriptors for that memory are
  202. in invalidated memory (confused yet?)
  203. So, you will notice that anywhere that page table descriptors (PTE's)
  204. are modified, we do so by locking out interrupts, momentarily disabling the 
  205. MMU, accessing the memory with its physical address, enabling the MMU, and
  206. then re-enabling interrupts (see mmuStateSet(), for example.)
  207. Support for two new page attribute bits are added for PentiumPro's enhanced
  208. MMU.  They are Global bit (G) and Page-level write-through/back bit (PWT).
  209. Global bit indicates a global page when set.  When a page is marked global and
  210. the page global enable (PGE) bit in register CR4 is set, the page-table or
  211. page-directory entry for the page is not invalidated in the TLB when register
  212. CR3 is loaded or a task switch occurs.  This bit is provided to prevent
  213. frequently used pages (such as pages that contain kernel or other operating
  214. system or executive code) from being flushed from the TLB.
  215. Page-level write-through/back bit (PWT) controls the write-through or write-
  216. back caching policy of individual pages or page tables.  When the PWT bit is
  217. set, write-through caching is enabled for the associated page or page table.
  218. When the bit is clear, write-back caching is enabled for the associated page
  219. and page table.
  220. Following macros are used to describe these attribute bits in the physical
  221. memory descriptor table sysPhysMemDesc[] in sysLib.c.
  222.  VM_STATE_WBACK - use write-back cache policy for the page 
  223.  VM_STATE_WBACK_NOT - use write-through cache policy for the page 
  224.  VM_STATE_GLOBAL - set page global bit
  225.  VM_STATE_GLOBAL_NOT - not set page global bit
  226. Support for two page size (4KB and 2MB) are added also.
  227. The linear address for 4KB pages is divided into four sections:
  228.  Page directory pointer - bits 30 through 31.
  229.  Page directory entry - bits 21 through 29.
  230.  Page table entry - Bits 12 through 20.
  231.  Page offset - Bits  0 through 11.
  232. The linear address for 2MB pages is divided into three sections:
  233.  Page directory pointer - bits 30 through 31.
  234.  Page directory entry - Bits 21 through 29.
  235.  Page offset - Bits  0 through 20.
  236. These two page size is configurable by VM_PAGE_SIZE macro in config.h.
  237. */
  238. /* includes */
  239. #include "vxWorks.h"
  240. #include "string.h"
  241. #include "intLib.h"
  242. #include "stdlib.h"
  243. #include "memLib.h"
  244. #include "private/vmLibP.h"
  245. #include "arch/i86/mmuPro36Lib.h"
  246. #include "arch/i86/vxI86Lib.h"
  247. #include "mmuLib.h"
  248. #include "errno.h"
  249. #include "cacheLib.h"
  250. #include "regs.h"
  251. #include "sysLib.h"
  252. /* defines */
  253. /*
  254.  * MMU_WP_UNLOCK and MMU_WP_LOCK are used to access page table entries that
  255.  * are in virtual memory that has been invalidated to protect it from being
  256.  * corrupted.  The write protection bit is toggled to stay in the virtual
  257.  * address space.
  258.  * MMU_UNLOCK and MMU_LOCK are used to allocate memory for Directory/Page
  259.  * Table from the initial system memory in the 1st 32 bit physical address
  260.  * space. Thus, for all the Directory/Page Tables', the upper 4 bits of 
  261.  * 36 bit physical address becomes zero.  This makes this library simple.
  262.  * Allocated memory can be freed from the virtual address space
  263.  * assuming the transparent mapping of the initial system memory.
  264.  * These four macros do not invoke function calls. Therefore, we do not 
  265.  * need to worry about stack mismatch in the virtual/physical address 
  266.  * space, or the called out function's disappearance.  It is guaranteed 
  267.  * that this code is in physical memory.
  268.  */
  269. #define MMU_ON() 
  270.     do { int tempReg; WRS_ASM ("movl %%cr0,%0; orl $0x80010000,%0; 
  271.     movl %0,%%cr0; jmp 0f; 0:" : "=r" (tempReg) : : "memory"); } while (0)
  272. #define MMU_OFF() 
  273.     do { int tempReg; WRS_ASM ("movl %%cr0,%0; andl $0x7ffeffff,%0; 
  274.     movl %0,%%cr0; jmp 0f; 0:" : "=r" (tempReg) : : "memory"); } while (0)
  275. #define MMU_UNLOCK(wasEnabled, oldLevel) 
  276.     do { if (((wasEnabled) = mmuPro36Enabled) == TRUE) 
  277. {INT_LOCK (oldLevel); MMU_OFF (); } 
  278.     } while (0)
  279. #define MMU_LOCK(wasEnabled, oldLevel) 
  280.     do { if ((wasEnabled) == TRUE) 
  281.         {MMU_ON (); INT_UNLOCK (oldLevel);} 
  282.     } while (0)
  283. #define WP_ON() 
  284.     do { int tempReg; WRS_ASM ("movl %%cr0,%0; orl $0x00010000,%0; 
  285.     movl %0,%%cr0; jmp 0f; 0:" : "=r" (tempReg) : : "memory"); } while (0)
  286. #define WP_OFF() 
  287.     do { int tempReg; WRS_ASM ("movl %%cr0,%0; andl $0xfffeffff,%0; 
  288.     movl %0,%%cr0; jmp 0f; 0:" : "=r" (tempReg) : : "memory"); } while (0)
  289. #define MMU_WP_UNLOCK(wasEnabled, oldLevel) 
  290.     do { if (((wasEnabled) = mmuPro36Enabled) == TRUE) 
  291. {INT_LOCK (oldLevel); WP_OFF (); } 
  292.     } while (0)
  293. #define MMU_WP_LOCK(wasEnabled, oldLevel) 
  294.     do { if ((wasEnabled) == TRUE) 
  295.         {WP_ON (); INT_UNLOCK (oldLevel);} 
  296.     } while (0)
  297. /* inline version of mmuI86TLBFlush() */
  298. #define MMU_TLB_FLUSH() 
  299.     do { int tempReg; WRS_ASM ("pushfl; cli; movl %%cr3,%0; 
  300.     movl %0,%%cr3; jmp 0f; 0: popfl; " : "=r" (tempReg) : : "memory"); 
  301.     } while (0)
  302. /* imports */
  303. IMPORT STATE_TRANS_TUPLE * mmuStateTransArray;
  304. IMPORT int mmuStateTransArraySize;
  305. IMPORT MMU_LIB_FUNCS mmuLibFuncs;
  306. IMPORT int mmuPageBlockSize;
  307. IMPORT int sysProcessor;
  308. IMPORT CPUID sysCpuId;
  309. /* globals */
  310. BOOL mmuPro36Enabled = FALSE;
  311. /* locals */
  312. LOCAL UINT32 mmuPageSize;
  313. LOCAL UINT32 mmuPdpTableNumEnt = 4;
  314. LOCAL BOOL firstTime = TRUE;
  315. LOCAL UINT32 nDirPages = 0; /* number of pages for Directory Table */
  316. /* 
  317.  * a translation table to hold the descriptors for the global transparent
  318.  * translation of physical to virtual memory 
  319.  */
  320. LOCAL MMU_TRANS_TBL mmuGlobalTransTbl;
  321. /* initially, the current trans table is a dummy table with mmu disabled */
  322. LOCAL MMU_TRANS_TBL * mmuCurrentTransTbl = &mmuGlobalTransTbl;
  323. /* 
  324.  * array of booleans used to keep track of sections of virtual memory 
  325.  * defined as global.
  326.  */
  327. LOCAL UINT8 * globalPageBlock;
  328. LOCAL STATE_TRANS_TUPLE mmuStateTransArrayLocal [] =
  329.     {
  330.     {VM_STATE_MASK_VALID, MMU_STATE_MASK_VALID, 
  331.      VM_STATE_VALID, MMU_STATE_VALID},
  332.     {VM_STATE_MASK_VALID, MMU_STATE_MASK_VALID, 
  333.      VM_STATE_VALID_NOT, MMU_STATE_VALID_NOT},
  334.     {VM_STATE_MASK_WRITABLE, MMU_STATE_MASK_WRITABLE,
  335.      VM_STATE_WRITABLE, MMU_STATE_WRITABLE},
  336.     {VM_STATE_MASK_WRITABLE, MMU_STATE_MASK_WRITABLE,
  337.      VM_STATE_WRITABLE_NOT, MMU_STATE_WRITABLE_NOT},
  338.     {VM_STATE_MASK_CACHEABLE, MMU_STATE_MASK_CACHEABLE,
  339.      VM_STATE_CACHEABLE, MMU_STATE_CACHEABLE},
  340.     {VM_STATE_MASK_CACHEABLE, MMU_STATE_MASK_CACHEABLE,
  341.      VM_STATE_CACHEABLE_NOT, MMU_STATE_CACHEABLE_NOT},
  342.     {VM_STATE_MASK_WBACK, MMU_STATE_MASK_WBACK,
  343.      VM_STATE_WBACK, MMU_STATE_WBACK},
  344.     {VM_STATE_MASK_WBACK, MMU_STATE_MASK_WBACK,
  345.      VM_STATE_WBACK_NOT, MMU_STATE_WBACK_NOT},
  346.     {VM_STATE_MASK_GLOBAL, MMU_STATE_MASK_GLOBAL,
  347.      VM_STATE_GLOBAL, MMU_STATE_GLOBAL},
  348.     {VM_STATE_MASK_GLOBAL, MMU_STATE_MASK_GLOBAL,
  349.      VM_STATE_GLOBAL_NOT, MMU_STATE_GLOBAL_NOT}
  350.     };
  351. /* forward declarations */
  352.  
  353. LOCAL void mmuMemPagesWriteDisable (MMU_TRANS_TBL * transTbl);
  354. LOCAL STATUS mmuPteGet (MMU_TRANS_TBL * pTransTbl, void * virtAddr,
  355.    PTE ** result);
  356. LOCAL MMU_TRANS_TBL * mmuTransTblCreate ();
  357. LOCAL STATUS mmuTransTblInit (MMU_TRANS_TBL * newTransTbl);
  358. LOCAL STATUS mmuTransTblDelete (MMU_TRANS_TBL * transTbl);
  359. LOCAL STATUS mmuVirtualPageCreate (MMU_TRANS_TBL * thisTbl,
  360.       void * virtPageAddr);
  361. LOCAL STATUS mmuStateSet (MMU_TRANS_TBL * transTbl, void * pageAddr,
  362.      UINT stateMask, UINT state);
  363. LOCAL STATUS mmuStateGet (MMU_TRANS_TBL * transTbl, void * pageAddr,
  364.      UINT * state);
  365. LOCAL STATUS mmuPageMap (MMU_TRANS_TBL * transTbl, void * virtAddr,
  366.     void * physPage);
  367. LOCAL STATUS mmuGlobalPageMap (void * virtAddr, void * physPage);
  368. LOCAL STATUS mmuTranslate (MMU_TRANS_TBL * transTbl, void * virtAddr,
  369.       void ** physAddr);
  370. LOCAL void mmuCurrentSet (MMU_TRANS_TBL * transTbl);
  371. LOCAL MMU_LIB_FUNCS mmuLibFuncsLocal =
  372.     {
  373.     mmuPro36LibInit,
  374.     mmuTransTblCreate,
  375.     mmuTransTblDelete,
  376.     mmuPro36Enable,   
  377.     mmuStateSet,
  378.     mmuStateGet,
  379.     mmuPageMap,
  380.     mmuGlobalPageMap,
  381.     mmuTranslate,
  382.     mmuCurrentSet
  383.     };
  384. /******************************************************************************
  385. *
  386. * mmuPro36LibInit - initialize module
  387. *
  388. * Build a dummy translation table that will hold the page table entries
  389. * for the global translation table.  The mmu remains disabled upon
  390. * completion.
  391. *
  392. * RETURNS: OK if no error, ERROR otherwise
  393. *
  394. * ERRNO: S_mmuLib_INVALID_PAGE_SIZE
  395. */
  396. STATUS mmuPro36LibInit 
  397.     (
  398.     int pageSize /* system pageSize (must be 4KB or 2MB) */
  399.     )
  400.     {
  401.     PTE * pDirectoryPtrTable;
  402.     PTE * pDirectoryTable;
  403.     INT32 ix;
  404.     /* check if the PSE and PAE are supported */
  405.     if ((sysCpuId.featuresEdx & (CPUID_PAE | CPUID_PSE)) !=
  406.         (CPUID_PAE | CPUID_PSE))
  407.         return (ERROR);
  408.     /* initialize the data objects that are shared with vmLib.c */
  409.     mmuStateTransArray = &mmuStateTransArrayLocal [0];
  410.     mmuStateTransArraySize =
  411.           sizeof (mmuStateTransArrayLocal) / sizeof (STATE_TRANS_TUPLE);
  412.     mmuLibFuncs = mmuLibFuncsLocal;
  413.     mmuPageBlockSize = PAGE_BLOCK_SIZE;
  414.     /* we assume a 4KB or 2MB page size */
  415.     if ((pageSize != PAGE_SIZE_4KB) && (pageSize != PAGE_SIZE_2MB))
  416. {
  417. errno = S_mmuLib_INVALID_PAGE_SIZE;
  418. return (ERROR);
  419. }
  420.     mmuPro36Enabled = FALSE;
  421.     mmuPageSize = pageSize;
  422.     /* 
  423.      * set number of pages for the page directory table
  424.      * 2048 (4 * 512) PDEs * 8 byte = 16384 byte
  425.      */
  426.     nDirPages = (mmuPageSize == PAGE_SIZE_4KB) ? 4 : 1;
  427.     /* 
  428.      * allocate the global page block array to keep track of which parts
  429.      * of virtual memory are handled by the global translation tables.
  430.      * Allocate on page boundary so we can write protect it.
  431.      */
  432.     globalPageBlock = (UINT8 *) memalign (mmuPageSize, mmuPageSize);
  433.     if (globalPageBlock == NULL)
  434. return (ERROR);
  435.     bzero ((char *) globalPageBlock, mmuPageSize);
  436.     /*
  437.      * build a dummy translation table which will hold the PTE's for
  438.      * global memory.  All real translation tables will point to this
  439.      * one for controlling the state of the global virtual memory  
  440.      */
  441.     /* allocate pages to hold the directory table */
  442.     pDirectoryTable = (PTE *) memalign (mmuPageSize, mmuPageSize * nDirPages);
  443.     if (pDirectoryTable == NULL)
  444. {
  445. free (globalPageBlock);
  446. return (ERROR);
  447. }
  448.     /* allocate a page to hold the directory pointer table */
  449.     mmuGlobalTransTbl.pDirectoryTable = pDirectoryPtrTable = 
  450.         (PTE *) memalign (mmuPageSize, mmuPageSize);
  451.     if (pDirectoryPtrTable == NULL)
  452. {
  453. free (globalPageBlock);
  454. free (pDirectoryTable);
  455. return (ERROR);
  456. }
  457.     bzero ((char *) pDirectoryPtrTable, mmuPageSize);
  458.     /* validate all the directory pointer table entries */
  459.     for (ix = 0; ix < mmuPdpTableNumEnt; ix++)
  460. {
  461.         pDirectoryPtrTable[ix].bits[0] = (UINT)pDirectoryTable + 
  462.   (PD_SIZE * ix);
  463.         pDirectoryPtrTable[ix].bits[1] = 0;
  464.         pDirectoryPtrTable[ix].field.present = 1;
  465.         pDirectoryPtrTable[ix].field.pwt = 0;
  466.         pDirectoryPtrTable[ix].field.pcd = 0;
  467. }
  468.     /* invalidate all the directory table entries */
  469.     for (ix = 0; ix < ((PD_SIZE * 4) / sizeof(PTE)); ix++)
  470. {
  471. pDirectoryTable[ix].field.present = 0;
  472. pDirectoryTable[ix].field.rw = 0;
  473. pDirectoryTable[ix].field.us = 0;
  474. pDirectoryTable[ix].field.pwt = 0;
  475. pDirectoryTable[ix].field.pcd = 0;
  476. pDirectoryTable[ix].field.access = 0;
  477. pDirectoryTable[ix].field.dirty = 0;
  478. if (pageSize == PAGE_SIZE_4KB)
  479.     pDirectoryTable[ix].field.pagesize = 0;
  480. else
  481.     pDirectoryTable[ix].field.pagesize = 1;
  482. pDirectoryTable[ix].field.global = 0;
  483. pDirectoryTable[ix].field.avail = 0;
  484. pDirectoryTable[ix].field.page = -1;
  485. pDirectoryTable[ix].field.page36 = 0;
  486. pDirectoryTable[ix].field.reserved = 0;
  487. }
  488.     /* set CR4 register: PAE=1 PSE=0/1 PGE=1 */
  489.     if (pageSize == PAGE_SIZE_4KB)
  490.         vxCr4Set ((vxCr4Get() & ~CR4_PSE) | (CR4_PAE | CR4_PGE));
  491.     else
  492.         vxCr4Set (vxCr4Get() | (CR4_PSE | CR4_PAE | CR4_PGE));
  493.     return (OK);
  494.     }
  495. /******************************************************************************
  496. *
  497. * mmuPteGet - get the PTE for a given page
  498. *
  499. * mmuPteGet traverses a translation table and returns the (physical) address of
  500. * the PTE for the given virtual address.
  501. *
  502. * RETURNS: OK or ERROR if there is no virtual space for the given address 
  503. *
  504. */
  505. LOCAL STATUS mmuPteGet 
  506.     (
  507.     MMU_TRANS_TBL *pTransTbl,  /* translation table */
  508.     void *virtAddr, /* virtual address */ 
  509.     PTE **result /* result is returned here */
  510.     )
  511.     {
  512.     PTE * pDte; /* directory table entry */
  513.     PTE * pDirectoryTable; /* directory table */
  514.     PTE * pPageTable; /* page table */
  515.     pDirectoryTable = (PTE *) (pTransTbl->pDirectoryTable->bits[0] & PDP_TO_ADDR);
  516.     pDte = &pDirectoryTable 
  517.    [((UINT) virtAddr & (DIR_PTR_BITS | DIR_BITS)) >> DIR_INDEX];
  518.     if (mmuPageSize == PAGE_SIZE_4KB)
  519. {
  520.         pPageTable = (PTE *) (pDte->bits[0] & PTE_TO_ADDR_4KB); 
  521.         if ((UINT) pPageTable == (0xffffffff & PTE_TO_ADDR_4KB))
  522.     return (ERROR);
  523.         *result = &pPageTable [((UINT) virtAddr & TBL_BITS) >> TBL_INDEX];
  524. }
  525.     else
  526. {
  527.         if ((UINT) pDte == (0xffffffff & PTE_TO_ADDR_2MB))
  528.     return (ERROR);
  529.         *result = pDte;
  530. }
  531.     return (OK);
  532.     }
  533. /******************************************************************************
  534. *
  535. * mmuTransTblCreate - create a new translation table.
  536. *
  537. * create a i86 translation table.  Allocates space for the MMU_TRANS_TBL
  538. * data structure and calls mmuTransTblInit on that object.  
  539. *
  540. * RETURNS: address of new object or NULL if allocation failed,
  541. *          or NULL if initialization failed.
  542. */
  543. LOCAL MMU_TRANS_TBL *mmuTransTblCreate 
  544.     (
  545.     )
  546.     {
  547.     MMU_TRANS_TBL * newTransTbl;
  548.     INT32 oldIntLev = 0;
  549.     BOOL wasEnabled;
  550.     MMU_UNLOCK (wasEnabled, oldIntLev);
  551.     newTransTbl = (MMU_TRANS_TBL *) malloc (sizeof (MMU_TRANS_TBL));
  552.     MMU_LOCK (wasEnabled, oldIntLev);
  553.     if (newTransTbl == NULL)
  554. return (NULL);
  555.     if (mmuTransTblInit (newTransTbl) == ERROR)
  556. {
  557. free ((char *) newTransTbl);
  558. return (NULL);
  559. }
  560.     return (newTransTbl);
  561.     }
  562. /******************************************************************************
  563. *
  564. * mmuTransTblInit - initialize a new translation table 
  565. *
  566. * Initialize a new translation table.  The directory table is copied from the
  567. * global translation mmuGlobalTransTbl, so that we will share the global 
  568. * virtual memory with all other translation tables.
  569. * RETURNS: OK or ERROR if unable to allocate memory for directory table.
  570. */
  571. LOCAL STATUS mmuTransTblInit 
  572.     (
  573.     MMU_TRANS_TBL *newTransTbl /* translation table to be inited */
  574.     )
  575.     {
  576.     PTE * pDirectoryPtrTable; /* directory pointer table */
  577.     PTE * pDirectoryTable; /* directory table */
  578.     INT32 oldIntLev = 0;
  579.     BOOL wasEnabled;
  580.     INT32 ix;
  581.     /* allocate a page to hold the directory pointer table */
  582.     MMU_UNLOCK (wasEnabled, oldIntLev);
  583.     newTransTbl->pDirectoryTable = pDirectoryPtrTable = 
  584. (PTE *) memalign (mmuPageSize, mmuPageSize);
  585.     MMU_LOCK (wasEnabled, oldIntLev);
  586.     if (pDirectoryPtrTable == NULL)
  587. return (ERROR);
  588.     /* allocate pages to hold the directory table */
  589.     MMU_UNLOCK (wasEnabled, oldIntLev);
  590.     pDirectoryTable = (PTE *) memalign (mmuPageSize, mmuPageSize * nDirPages);
  591.     MMU_LOCK (wasEnabled, oldIntLev);
  592.     if (pDirectoryTable == NULL)
  593. {
  594. free (pDirectoryPtrTable);
  595. return (ERROR);
  596. }
  597.     /* setup the directory pointer table */
  598.     for (ix = 0; ix < mmuPdpTableNumEnt; ix++)
  599. {
  600.         pDirectoryPtrTable[ix].bits[0] = (UINT)pDirectoryTable +
  601.     (PD_SIZE * ix);
  602.         pDirectoryPtrTable[ix].bits[1] = 0;
  603.         pDirectoryPtrTable[ix].field.present = 1;
  604.         pDirectoryPtrTable[ix].field.pwt = 0;
  605.         pDirectoryPtrTable[ix].field.pcd = 0;
  606. }
  607.     /* 
  608.      * copy the directory table from the mmuGlobalTransTbl, 
  609.      * so we get the global virtual memory 
  610.      */
  611.     bcopy ((char *) (mmuGlobalTransTbl.pDirectoryTable->bits[0] & PDP_TO_ADDR), 
  612.    (char *) pDirectoryTable, PD_SIZE * 4);
  613.     /* 
  614.      * write protect virtual memory pointing to the directory pointer table 
  615.      * and the directory table in the global translation table to insure 
  616.      * that it can't be corrupted 
  617.      */
  618.     for (ix = 0; ix < nDirPages; ix++)
  619. {
  620.         mmuStateSet (&mmuGlobalTransTbl, 
  621.      (void *) ((UINT)pDirectoryTable + (mmuPageSize * ix)),
  622.      MMU_STATE_MASK_WRITABLE, MMU_STATE_WRITABLE_NOT);
  623. }
  624.     mmuStateSet (&mmuGlobalTransTbl, (void *) pDirectoryPtrTable, 
  625.  MMU_STATE_MASK_WRITABLE, MMU_STATE_WRITABLE_NOT);
  626.     return (OK);
  627.     }
  628. /******************************************************************************
  629. *
  630. * mmuTransTblDelete - delete a translation table.
  631. * mmuTransTblDelete deallocates all the memory used to store the translation
  632. * table entries.  It does not deallocate physical pages mapped into the
  633. * virtual memory space.
  634. *
  635. * RETURNS: OK
  636. *
  637. */
  638. LOCAL STATUS mmuTransTblDelete 
  639.     (
  640.     MMU_TRANS_TBL *transTbl /* translation table to be deleted */
  641.     )
  642.     {
  643.     PTE * pDte;
  644.     PTE * pDirectoryTable; /* directory table */
  645.     PTE * pPageTable;
  646.     INT32 ix;
  647.     /* write enable the physical page containing the directory ptr table */
  648.     mmuStateSet (&mmuGlobalTransTbl, transTbl->pDirectoryTable,
  649.  MMU_STATE_MASK_WRITABLE, MMU_STATE_WRITABLE);
  650.     /* write enable the physical page containing the directory table */
  651.     pDirectoryTable = (PTE *)(transTbl->pDirectoryTable->bits[0] & PDP_TO_ADDR);
  652.     for (ix = 0; ix < nDirPages; ix++)
  653. {
  654. pDte = (PTE *)((UINT)pDirectoryTable + (mmuPageSize * ix));
  655.         mmuStateSet (&mmuGlobalTransTbl, pDte, 
  656.       MMU_STATE_MASK_WRITABLE, MMU_STATE_WRITABLE);
  657. }
  658.     /* deallocate only non-global page blocks */
  659.     pDte = pDirectoryTable;
  660.     if (mmuPageSize == PAGE_SIZE_4KB)
  661.         for (ix = 0; ix < ((PD_SIZE * 4) / sizeof(PTE)); ix++, pDte++)
  662.     if ((pDte->field.present == 1) && !globalPageBlock[ix]) 
  663.         {
  664.         pPageTable = (PTE *) (pDte->bits[0] & PTE_TO_ADDR_4KB);
  665.         mmuStateSet (&mmuGlobalTransTbl, pPageTable,
  666.              MMU_STATE_MASK_WRITABLE, MMU_STATE_WRITABLE);
  667.         free (pPageTable);
  668.         }
  669.     /* free the pages holding the directory table */
  670.     free ((void *) (transTbl->pDirectoryTable->bits[0] & PDP_TO_ADDR));
  671.     /* free the page holding the directory pointer table */
  672.     free (transTbl->pDirectoryTable);
  673.     /* free the translation table data structure */
  674.     free (transTbl);
  675.     
  676.     return (OK);
  677.     }
  678. /******************************************************************************
  679. *
  680. * mmuVirtualPageCreate - set up translation tables for a virtual page
  681. *
  682. * simply check if there's already a page table that has a
  683. * PTE for the given virtual page.  If there isn't, create one.
  684. * this routine is called only if the page size is 4KB, since a page table
  685. * is not necessary for 2MB or 4MB page sizes.
  686. *
  687. * RETURNS OK or ERROR if couldn't allocate space for a page table.
  688. */
  689. LOCAL STATUS mmuVirtualPageCreate 
  690.     (
  691.     MMU_TRANS_TBL *thisTbl,  /* translation table */
  692.     void *virtPageAddr /* virtual addr to create */
  693.     )
  694.     {
  695.     PTE * pDirectoryTable; /* directory table */
  696.     PTE * pPageTable; /* page table */
  697.     PTE * pDte; /* directory table entry */
  698.     PTE * dummy;
  699.     INT32 oldIntLev = 0;
  700.     BOOL wasEnabled;
  701.     UINT ix;
  702.     if (mmuPteGet (thisTbl, virtPageAddr, &dummy) == OK)
  703. return (OK);
  704.     MMU_UNLOCK (wasEnabled, oldIntLev);
  705.     pPageTable = (PTE *) memalign (mmuPageSize, mmuPageSize);
  706.     MMU_LOCK (wasEnabled, oldIntLev);
  707.     if (pPageTable == NULL)
  708. return (ERROR);
  709.     /* invalidate every page in the new page block */
  710.     for (ix = 0; ix < (PT_SIZE / sizeof(PTE)); ix++)
  711. {
  712. pPageTable[ix].field.present = 0;
  713. pPageTable[ix].field.rw = 0;
  714. pPageTable[ix].field.us = 0;
  715. pPageTable[ix].field.pwt = 0;
  716. pPageTable[ix].field.pcd = 0;
  717. pPageTable[ix].field.access = 0;
  718. pPageTable[ix].field.dirty = 0;
  719. pPageTable[ix].field.pagesize = 0;
  720. pPageTable[ix].field.global = 0;
  721. pPageTable[ix].field.avail = 0;
  722. pPageTable[ix].field.page = -1;
  723. pPageTable[ix].field.page36 = 0;
  724. pPageTable[ix].field.reserved = 0;
  725. }
  726.     /* 
  727.      * write protect the new physical page containing the PTE's
  728.      * for this new page block 
  729.      */
  730.     mmuStateSet (&mmuGlobalTransTbl, pPageTable, 
  731.          MMU_STATE_MASK_WRITABLE, MMU_STATE_WRITABLE_NOT); 
  732.     /* 
  733.      * unlock the physical page containing the directory pointer table
  734.      * and the directory table, so we can modify it 
  735.      */
  736.     pDirectoryTable = (PTE *) (thisTbl->pDirectoryTable->bits[0] & PDP_TO_ADDR);
  737.     for (ix = 0; ix < nDirPages; ix++)
  738. {
  739.         mmuStateSet (&mmuGlobalTransTbl, 
  740.      (void *) ((UINT32)pDirectoryTable + (mmuPageSize * ix)),
  741.      MMU_STATE_MASK_WRITABLE, MMU_STATE_WRITABLE);
  742. }
  743.     /* modify the directory table entry to point to the new page table */
  744.     pDte = &pDirectoryTable 
  745.    [((UINT) virtPageAddr & (DIR_PTR_BITS | DIR_BITS)) >> DIR_INDEX];    
  746.     pDte->field.page = (UINT) pPageTable >> ADDR_TO_PAGE;
  747.     pDte->field.present = 1;
  748.     pDte->field.rw = 1;
  749.     /* write protect the directory pointer table and the directory table */
  750.     for (ix = 0; ix < nDirPages; ix++)
  751. {
  752.         mmuStateSet (&mmuGlobalTransTbl, 
  753.      (void *) ((UINT32)pDirectoryTable + (mmuPageSize * ix)),
  754.      MMU_STATE_MASK_WRITABLE, MMU_STATE_WRITABLE_NOT);
  755. }
  756.     /* defer the TLB flush to the mmuCurrentSet() at init time */
  757.     if (!firstTime)
  758.         {
  759.         MMU_TLB_FLUSH ();
  760.         }
  761.     return (OK);
  762.     }
  763. /******************************************************************************
  764. *
  765. * mmuStateSet - set state of virtual memory page
  766. *
  767. * mmuStateSet is used to modify the state bits of the PTE for the given
  768. * virtual page.  The following states are provided:
  769. *
  770. * MMU_STATE_VALID  MMU_STATE_VALID_NOT  valid/invalid
  771. * MMU_STATE_WRITABLE  MMU_STATE_WRITABLE_NOT  writable/write_protected
  772. * MMU_STATE_CACHEABLE  MMU_STATE_CACHEABLE_NOT  notcachable/cachable
  773. * MMU_STATE_WBACK  MMU_STATE_WBACK_NOT      write_back/write_through
  774. * MMU_STATE_GLOBAL     MMU_STATE_GLOBAL_NOT     global/not_global
  775. *
  776. * these may be or'ed together in the state parameter.  Additionally, masks
  777. * are provided so that only specific states may be set:
  778. *
  779. * MMU_STATE_MASK_VALID 
  780. * MMU_STATE_MASK_WRITABLE
  781. * MMU_STATE_MASK_CACHEABLE
  782. * MMU_STATE_MASK_WBACK
  783. * MMU_STATE_MASK_GLOBAL
  784. *
  785. * These may be or'ed together in the stateMask parameter.  
  786. *
  787. * Accesses to a virtual page marked as invalid will result in a page fault.
  788. *
  789. * RETURNS: OK or ERROR if virtual page does not exist.
  790. */
  791. LOCAL STATUS mmuStateSet 
  792.     (
  793.     MMU_TRANS_TBL *transTbl,  /* translation table */
  794.     void *pageAddr, /* page whose state to modify */ 
  795.     UINT stateMask, /* mask of which state bits to modify */
  796.     UINT state /* new state bit values */
  797.     )
  798.     {
  799.     PTE * pPte;
  800.     INT32 oldIntLev = 0;
  801.     BOOL wasEnabled;
  802.     if (mmuPteGet (transTbl, pageAddr, &pPte) != OK)
  803. return (ERROR);
  804.     /* modify the PTE with mmu turned off and interrupts locked out */
  805.     MMU_WP_UNLOCK (wasEnabled, oldIntLev);
  806.     pPte->bits[0] = (pPte->bits[0] & ~stateMask) | (state & stateMask);
  807.     MMU_WP_LOCK (wasEnabled, oldIntLev);
  808.     /* defer the TLB and Cache flush to the mmuCurrentSet() */
  809.     if (!firstTime)
  810. {
  811.         MMU_TLB_FLUSH ();
  812.         cacheArchClearEntry (DATA_CACHE, pPte);
  813. }
  814.     return (OK);
  815.     }
  816. /******************************************************************************
  817. *
  818. * mmuStateGet - get state of virtual memory page
  819. *
  820. * mmuStateGet is used to retrieve the state bits of the PTE for the given
  821. * virtual page.  The following states are provided:
  822. *
  823. * MMU_STATE_VALID  MMU_STATE_VALID_NOT  valid/invalid
  824. * MMU_STATE_WRITABLE  MMU_STATE_WRITABLE_NOT  writable/write_protected
  825. * MMU_STATE_CACHEABLE  MMU_STATE_CACHEABLE_NOT  notcachable/cachable
  826. * MMU_STATE_WBACK  MMU_STATE_WBACK_NOT      write_back/write_through
  827. * MMU_STATE_GLOBAL     MMU_STATE_GLOBAL_NOT     global/not_global
  828. *
  829. * these are or'ed together in the returned state.  Additionally, masks
  830. * are provided so that specific states may be extracted from the returned state:
  831. *
  832. * MMU_STATE_MASK_VALID 
  833. * MMU_STATE_MASK_WRITABLE
  834. * MMU_STATE_MASK_CACHEABLE
  835. * MMU_STATE_MASK_WBACK
  836. * MMU_STATE_MASK_GLOBAL
  837. *
  838. * RETURNS: OK or ERROR if virtual page does not exist.
  839. */
  840. LOCAL STATUS mmuStateGet 
  841.     (
  842.     MMU_TRANS_TBL *transTbl,  /* tranlation table */
  843.     void *pageAddr,  /* page whose state we're querying */
  844.     UINT *state /* place to return state value */
  845.     )
  846.     {
  847.     PTE *pPte;
  848.     if (mmuPteGet (transTbl, pageAddr, &pPte) != OK)
  849. return (ERROR);
  850.     *state = pPte->bits[0]; 
  851.     return (OK);
  852.     }
  853. /******************************************************************************
  854. *
  855. * mmuPageMap - map physical memory page to virtual memory page
  856. *
  857. * The physical page address is entered into the PTE corresponding to the
  858. * given virtual page.  The state of a newly mapped page is undefined. 
  859. *
  860. * RETURNS: OK or ERROR if translation table creation failed. 
  861. */
  862. LOCAL STATUS mmuPageMap 
  863.     (
  864.     MMU_TRANS_TBL *transTbl,  /* translation table */
  865.     void *virtualAddress,  /* virtual address */
  866.     void *physPage /* physical address */
  867.     )
  868.     {
  869.     PTE * pPte;
  870.     INT32 oldIntLev = 0;
  871.     BOOL wasEnabled;
  872.     BOOL status = mmuPteGet (transTbl, virtualAddress, &pPte);
  873.     if ((mmuPageSize == PAGE_SIZE_4KB) && (status != OK))
  874. {
  875. /* build the translation table for the virtual address */
  876. if (mmuVirtualPageCreate (transTbl, virtualAddress) != OK)
  877.     return (ERROR);
  878. if (mmuPteGet (transTbl, virtualAddress, &pPte) != OK)
  879.     return (ERROR);
  880. }
  881.     if (mmuPageSize != PAGE_SIZE_4KB)
  882.         (UINT)physPage &= ADDR_TO_PAGEBASE; 
  883.     MMU_WP_UNLOCK (wasEnabled, oldIntLev);
  884.     pPte->field.page   = (UINT)physPage >> ADDR_TO_PAGE;
  885.     MMU_WP_LOCK (wasEnabled, oldIntLev);
  886.     MMU_TLB_FLUSH ();
  887.     cacheArchClearEntry (DATA_CACHE, pPte);
  888.     return (OK);
  889.     }
  890. /******************************************************************************
  891. *
  892. * mmuGlobalPageMap - map physical memory page to global virtual memory page
  893. *
  894. * mmuGlobalPageMap is used to map physical pages into global virtual memory
  895. * that is shared by all virtual memory contexts.  The translation tables
  896. * for this section of the virtual space are shared by all virtual memory
  897. * contexts.
  898. *
  899. * RETURNS: OK or ERROR if no PTE for given virtual page.
  900. */
  901. LOCAL STATUS mmuGlobalPageMap 
  902.     (
  903.     void *virtualAddress,  /* virtual address */
  904.     void *physPage /* physical address */
  905.     )
  906.     {
  907.     PTE * pPte;
  908.     INT32 oldIntLev = 0;
  909.     BOOL wasEnabled;
  910.     BOOL status = mmuPteGet (&mmuGlobalTransTbl, virtualAddress, &pPte);
  911.     int ix;
  912.     if ((mmuPageSize == PAGE_SIZE_4KB) && (status != OK))
  913. {
  914. /* build the translation table for the virtual address */
  915. if (mmuVirtualPageCreate (&mmuGlobalTransTbl, virtualAddress) != OK)
  916.     return (ERROR);
  917. if (mmuPteGet (&mmuGlobalTransTbl, virtualAddress, &pPte) != OK)
  918.     return (ERROR);
  919.         /* the globalPageBlock array is write protected */
  920.         mmuStateSet (&mmuGlobalTransTbl, globalPageBlock,
  921.      MMU_STATE_MASK_WRITABLE, MMU_STATE_WRITABLE);
  922.         ix = ((UINT) virtualAddress & (DIR_PTR_BITS | DIR_BITS)) >> DIR_INDEX;
  923.         globalPageBlock [ix] = (UINT8) TRUE;
  924.         mmuStateSet (&mmuGlobalTransTbl, globalPageBlock,
  925.                   MMU_STATE_MASK_WRITABLE, MMU_STATE_WRITABLE_NOT);
  926. }
  927.     if (mmuPageSize != PAGE_SIZE_4KB)
  928. (UINT)physPage &= ADDR_TO_PAGEBASE;
  929.     MMU_WP_UNLOCK (wasEnabled, oldIntLev);
  930.     pPte->field.page = (UINT)physPage >> ADDR_TO_PAGE;
  931.     MMU_WP_LOCK (wasEnabled, oldIntLev);
  932.     /* defer the TLB and Cache flush to the mmuCurrentSet() */
  933.     if (!firstTime)
  934. {
  935.         MMU_TLB_FLUSH ();
  936.         cacheArchClearEntry (DATA_CACHE, pPte);
  937. }
  938.     return (OK);
  939.     }
  940. /******************************************************************************
  941. *
  942. * mmuTranslate - translate a virtual address to a physical address
  943. *
  944. * Traverse the translation table and extract the physical address for the
  945. * given virtual address from the PTE corresponding to the virtual address.
  946. *
  947. * RETURNS: OK or ERROR if no PTE for given virtual address.
  948. */
  949. LOCAL STATUS mmuTranslate 
  950.     (
  951.     MMU_TRANS_TBL *transTbl,  /* translation table */
  952.     void *virtAddress,  /* virtual address */
  953.     void **physAddress /* place to return result */
  954.     )
  955.     {
  956.     PTE *pPte;
  957.     if (mmuPteGet (transTbl, virtAddress, &pPte) != OK)
  958. {
  959. errno = S_mmuLib_NO_DESCRIPTOR; 
  960. return (ERROR);
  961. }
  962.     if (pPte->field.present == 0)
  963. {
  964. errno = S_mmuLib_INVALID_DESCRIPTOR; 
  965. return (ERROR);
  966. }
  967.     /* add offset into page */
  968.     if (mmuPageSize == PAGE_SIZE_4KB)
  969.         *physAddress = (void *)((UINT)(pPte->bits[0] & PTE_TO_ADDR_4KB) + 
  970.         ((UINT)virtAddress & OFFSET_BITS_4KB));
  971.     else
  972.         *physAddress = (void *)((UINT)(pPte->bits[0] & PTE_TO_ADDR_2MB) + 
  973.         ((UINT)virtAddress & OFFSET_BITS_2MB));
  974.     return (OK);
  975.     }
  976. /******************************************************************************
  977. *
  978. * mmuCurrentSet - change active translation table
  979. *
  980. * mmuCurrent set is used to change the virtual memory context.
  981. * Load the CRP (root pointer) register with the given translation table.
  982. *
  983. */
  984. LOCAL void mmuCurrentSet 
  985.     (
  986.     MMU_TRANS_TBL *transTbl /* new active tranlation table */
  987.     ) 
  988.     {
  989.     INT32 oldLev;
  990.     if (firstTime)
  991. {
  992. mmuMemPagesWriteDisable (&mmuGlobalTransTbl);
  993. mmuMemPagesWriteDisable (transTbl);
  994. /* perform the deferred TLB and Cache flush */
  995.         /* MMU_TLB_FLUSH (); */ /* done by following mmuPro32PdbrSet () */
  996.         if (sysProcessor != X86CPU_386)
  997.             WRS_ASM ("wbinvd"); /* flush the entire cache */
  998. firstTime = FALSE;
  999. }
  1000.     oldLev = intLock (); /* LOCK INTERRUPTS */
  1001.     mmuCurrentTransTbl = transTbl;
  1002.     mmuPro36PdbrSet (transTbl);
  1003.     intUnlock (oldLev); /* UNLOCK INTERRUPTS */
  1004.     }
  1005. /******************************************************************************
  1006. *
  1007. * mmuMemPagesWriteDisable - write disable memory holding a table's descriptors
  1008. *
  1009. * Memory containing translation table descriptors is marked as read only
  1010. * to protect the descriptors from being corrupted.  This routine write protects
  1011. * all the memory used to contain a given translation table's descriptors.
  1012. *
  1013. */
  1014. LOCAL void mmuMemPagesWriteDisable
  1015.     (
  1016.     MMU_TRANS_TBL *transTbl
  1017.     )
  1018.     {
  1019.     PTE * pDirectoryTable;
  1020.     void * thisPage;
  1021.     INT32 ix;
  1022.     pDirectoryTable = (PTE *)(transTbl->pDirectoryTable->bits[0] & PDP_TO_ADDR);
  1023.     if (mmuPageSize == PAGE_SIZE_4KB)
  1024.         for (ix = 0; ix < ((PD_SIZE * 4) / sizeof(PTE)); ix++)
  1025.     {
  1026.     thisPage = (void *)(pDirectoryTable[ix].bits[0] & PTE_TO_ADDR_4KB);
  1027.     if ((int)thisPage != (0xffffffff & PTE_TO_ADDR_4KB))
  1028.         mmuStateSet (transTbl, thisPage, MMU_STATE_MASK_WRITABLE,
  1029.      MMU_STATE_WRITABLE_NOT);
  1030.     }
  1031.     for (ix = 0; ix < nDirPages; ix++)
  1032. {
  1033. thisPage = (void *)((UINT)pDirectoryTable + (mmuPageSize * ix));
  1034.         mmuStateSet (transTbl, thisPage, MMU_STATE_MASK_WRITABLE, 
  1035.      MMU_STATE_WRITABLE_NOT);
  1036. }
  1037.     mmuStateSet (transTbl, transTbl->pDirectoryTable, MMU_STATE_MASK_WRITABLE, 
  1038.  MMU_STATE_WRITABLE_NOT);
  1039.     }
  1040. /******************************************************************************
  1041. *
  1042. * mmuPro36PageMap - map 36bit physical memory page to virtual memory page
  1043. *
  1044. * The 36bit physical page address is entered into the PTE corresponding to 
  1045. * the given virtual page.  The state of a newly mapped page is undefined. 
  1046. *
  1047. * RETURNS: OK or ERROR if translation table creation failed. 
  1048. */
  1049. STATUS mmuPro36PageMap 
  1050.     (
  1051.     MMU_TRANS_TBL * transTbl,  /* translation table */
  1052.     void * virtualAddress,  /* 32bit virtual address */
  1053.     LL_INT physPage /* 36bit physical address */
  1054.     )
  1055.     {
  1056.     PTE *    pPte;
  1057.     BOOL     wasEnabled;
  1058.     INT32    oldIntLev = 0;
  1059.     UINT32 * pPhysPage = (UINT32 *)&physPage;
  1060.     BOOL     status    = mmuPteGet (transTbl, virtualAddress, &pPte);
  1061.     if ((mmuPageSize == PAGE_SIZE_4KB) && (status != OK))
  1062. {
  1063. /* build the translation table for the virtual address */
  1064. if (mmuVirtualPageCreate (transTbl, virtualAddress) != OK)
  1065.     return (ERROR);
  1066. if (mmuPteGet (transTbl, virtualAddress, &pPte) != OK)
  1067.     return (ERROR);
  1068. }
  1069.     if (mmuPageSize != PAGE_SIZE_4KB)
  1070.         pPhysPage[0] &= ADDR_TO_PAGEBASE; 
  1071.     MMU_WP_UNLOCK (wasEnabled, oldIntLev);
  1072.     pPte->field.page   = pPhysPage[0] >> ADDR_TO_PAGE;
  1073.     pPte->field.page36 = pPhysPage[1] & 0x0000000f;
  1074.     MMU_WP_LOCK (wasEnabled, oldIntLev);
  1075.     MMU_TLB_FLUSH ();
  1076.     cacheArchClearEntry (DATA_CACHE, pPte);
  1077.     return (OK);
  1078.     }
  1079. /******************************************************************************
  1080. *
  1081. * mmuPro36Translate - translate a virtual address to a 36bit physical address
  1082. *
  1083. * Traverse the translation table and extract the 36bit physical address for 
  1084. * the given virtual address from the PTE corresponding to the virtual address.
  1085. *
  1086. * RETURNS: OK or ERROR if no PTE for given virtual address.
  1087. */
  1088. STATUS mmuPro36Translate 
  1089.     (
  1090.     MMU_TRANS_TBL * transTbl,  /* translation table */
  1091.     void * virtAddress, /* 32bit virtual address */
  1092.     LL_INT * physAddress /* place to return 36bit result */
  1093.     )
  1094.     {
  1095.     PTE *    pPte;
  1096.     UINT32 * pPhysAddr = (UINT32 *) physAddress;
  1097.     if (mmuPteGet (transTbl, virtAddress, &pPte) != OK)
  1098. {
  1099. errno = S_mmuLib_NO_DESCRIPTOR; 
  1100. return (ERROR);
  1101. }
  1102.     if (pPte->field.present == 0)
  1103. {
  1104. errno = S_mmuLib_INVALID_DESCRIPTOR; 
  1105. return (ERROR);
  1106. }
  1107.     /* add offset into page */
  1108.     if (mmuPageSize == PAGE_SIZE_4KB)
  1109.         pPhysAddr[0] = (UINT32)(pPte->bits[0] & PTE_TO_ADDR_4KB) + 
  1110.        ((UINT32)virtAddress & OFFSET_BITS_4KB);
  1111.     else
  1112.         pPhysAddr[0] = (UINT32)(pPte->bits[0] & PTE_TO_ADDR_2MB) + 
  1113.        ((UINT32)virtAddress & OFFSET_BITS_2MB);
  1114.     pPhysAddr[1] = pPte->bits[1];
  1115.     return (OK);
  1116.     }