mmuPro32Lib.c
上传用户:nvosite88
上传日期:2007-01-17
资源大小:4983k
文件大小:35k
源码类别:

VxWorks

开发平台:

C/C++

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