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

VxWorks

开发平台:

C/C++

  1. /* mmuI86Lib.c - MMU library for i86 */
  2. /* Copyright 1984-2002 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 01h,16may02,hdn  moved the GDT reloading to sysPhysMemTop() in sysLib.c
  8. 01g,09nov01,hdn  deferred TLB flush in mmuVirtualPageCreate() at init time
  9. 01f,27aug01,hdn  made MMU_TLB_FLUSH, updated MMU_LOCK/MMU_UNLOCK macros.
  10.  deferred TLB & Cache flush at initialization time.
  11.  renamed mmuLibInit to mmuI86LibInit.
  12.  doc: cleanup.
  13. 01e,09feb99,wsl  add comment to document ERRNO value
  14. 01d,13apr98,hdn  added support for PentiumPro.
  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. mmuI86Lib.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.  mmuI86LibInit() - initialize module
  25.  mmuTransTblCreate() - create a new translation table
  26.  mmuTransTblDelete() - delete a translation table.
  27.  mmuI86Enable() - 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 mmuI86Lib.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.  mmuLib must provide a routine 
  106. mmuGlobalInfoGet(), which returns a pointer to the globalPageBlock[] array.
  107. This provides the user with enough information to be able to allocate virtual 
  108. memory space that does not conflict with the global memory space.
  109. This module supports the 80386/80486 MMU:
  110. .CS
  111.     PDBR
  112.      |
  113.      |
  114.             -------------------------------------
  115.  top level  |pde  |pde  |pde  |pde  |pde  |pde  | ... 
  116.             -------------------------------------
  117.        |     |     |     |     |     |    
  118.        |     |     |     |     |     |    
  119.       ----------     |     v     v     v     v
  120.       |         ------    NULL  NULL  NULL  NULL
  121.       |         |
  122.       v         v
  123.      ----     ----   
  124. l   |pte |   |pte |
  125. o    ----     ----
  126. w   |pte |   |pte |     
  127. e    ----     ----
  128. r   |pte |   |pte |
  129. l    ----     ----
  130. e   |pte |   |pte |
  131. v    ----     ----
  132. e     .         .
  133. l     .         .
  134.       .         .
  135. .CE
  136. where the top level consists of an array of pointers (Page Directory Entry)
  137. held within a single 4k page.  These point to arrays of Page Table Entry 
  138. arrays in the lower level.  Each of these lower level arrays is also held 
  139. within a single 4k page, and describes a virtual space of 4 MB (each Page 
  140. Table Entry is 4 bytes, so we get 1000 of these in each array, and each Page
  141. Table Entry maps a 4KB page - thus 1000 * 4096 = 4MB.)  
  142. To implement global virtual memory, a separate translation table called 
  143. mmuGlobalTransTbl is created when the module is initialized.  Calls to 
  144. mmuGlobalPageMap will augment and modify this translation table.  When new
  145. translation tables are created, memory for the top level array of sftd's is
  146. allocated and initialized by duplicating the pointers in mmuGlobalTransTbl's
  147. top level sftd array.  Thus, the new translation table will use the global
  148. translation table's state information for portions of virtual memory that are
  149. defined as global.  Here's a picture to illustrate:
  150. .CS
  151.          GLOBAL TRANS TBL       NEW TRANS TBL
  152.          PDBR    PDBR
  153.         |     |
  154.         |     |
  155.             -------------------------           -------------------------
  156.  top level  |pde  |pde  | NULL| NULL|           |pde  |pde  | NULL| NULL|
  157.             -------------------------           -------------------------
  158.        |     |     |     |                 |     |     |     |   
  159.        |     |     |     |                 |     |     |     |  
  160.       ----------     |     v     v        ----------     |     v     v
  161.       |         ------    NULL  NULL      |  |    NULL  NULL
  162.       |         |   |  |
  163.       o------------------------------------  |
  164.       | |  |
  165.       | o-----------------------------------------
  166.       | |
  167.       v         v
  168.      ----     ----   
  169. l   |pte |   |pte |
  170. o    ----     ----
  171. w   |pte |   |pte |     
  172. e    ----     ----
  173. r   |pte |   |pte |
  174. l    ----     ----
  175. e   |pte |   |pte |
  176. v    ----     ----
  177. e     .         .
  178. l     .         .
  179.       .         .
  180. .CE
  181. Note that with this scheme, the global memory granularity is 4MB.  Each time
  182. you map a section of global virtual memory, you dedicate at least 4MB of 
  183. the virtual space to global virtual memory that will be shared by all virtual
  184. memory contexts.
  185. The physical memory that holds these data structures is obtained from the
  186. system memory manager via memalign to insure that the memory is page
  187. aligned.  We want to protect this memory from being corrupted,
  188. so we invalidate the descriptors that we set up in the global translation
  189. that correspond to the memory containing the translation table data structures.
  190. This creates a "chicken and the egg" paradox, in that the only way we can
  191. modify these data structures is through virtual memory that is now invalidated,
  192. and we can't validate it because the page descriptors for that memory are
  193. in invalidated memory (confused yet?)
  194. So, you will notice that anywhere that page table descriptors (pte's)
  195. are modified, we do so by locking out interrupts, momentarily disabling the 
  196. MMU, accessing the memory with its physical address, enabling the MMU, and
  197. then re-enabling interrupts (see mmuStateSet(), for example.)
  198. The 80386 MMU does not have a write protection mechanism, since there is no
  199. WP(Write Protect) bit in CR0 unlike 80486 MMU. The 80386 has no internal
  200. cache, thus precluding control caching on a page-by-page basis. Also there 
  201. is neither a PWT(Page Write Through) bit nor PCD(Page Cache Disable) bit 
  202. in the Page Table Entry.
  203. The 80486 MMU set a PWT(Page Write Through) bit all the time and uses PCD
  204. (Page Cache Disable) bit to control caching on a page-by-page basis.
  205. The Pentium MMU set a PWT(Page Write Through) bit if the cacheDataMode is
  206. WRITE_THROUGH. If it is COPY_BACK, it doesn't set the bit.
  207. */
  208. #include "vxWorks.h"
  209. #include "string.h"
  210. #include "intLib.h"
  211. #include "stdlib.h"
  212. #include "memLib.h"
  213. #include "private/vmLibP.h"
  214. #include "arch/i86/mmuI86Lib.h"
  215. #include "mmuLib.h"
  216. #include "errno.h"
  217. #include "cacheLib.h"
  218. #include "regs.h"
  219. /* forward declarations */
  220.  
  221. LOCAL void mmuMemPagesWriteDisable (MMU_TRANS_TBL *transTbl);
  222. LOCAL STATUS mmuPteGet (MMU_TRANS_TBL *pTransTbl, void *virtAddr, PTE **result);
  223. LOCAL MMU_TRANS_TBL *mmuTransTblCreate ();
  224. LOCAL STATUS mmuTransTblInit (MMU_TRANS_TBL *newTransTbl);
  225. LOCAL STATUS mmuTransTblDelete (MMU_TRANS_TBL *transTbl);
  226. LOCAL STATUS mmuVirtualPageCreate (MMU_TRANS_TBL *thisTbl, void *virtPageAddr);
  227. LOCAL STATUS mmuStateSet (MMU_TRANS_TBL *transTbl, void *pageAddr, UINT stateMask, UINT state);
  228. LOCAL STATUS mmuStateGet (MMU_TRANS_TBL *transTbl, void *pageAddr, UINT *state);
  229. LOCAL STATUS mmuPageMap (MMU_TRANS_TBL *transTbl, void *virtualAddress, void *physPage);
  230. LOCAL STATUS mmuGlobalPageMap (void *virtualAddress, void *physPage);
  231. LOCAL STATUS mmuTranslate (MMU_TRANS_TBL *transTbl, void *virtAddress, void **physAddress);
  232. LOCAL void mmuCurrentSet (MMU_TRANS_TBL *transTbl);
  233. /* kludgey static data structure for parameters in __asm__ directives. */
  234. LOCAL int mmuPageSize;
  235. BOOL mmuI86Enabled = FALSE;
  236. /* a translation table to hold the descriptors for the global transparent
  237.  * translation of physical to virtual memory 
  238.  */
  239. LOCAL MMU_TRANS_TBL mmuGlobalTransTbl;
  240. /* initially, the current trans table is a dummy table with MMU disabled */
  241. LOCAL MMU_TRANS_TBL *mmuCurrentTransTbl = &mmuGlobalTransTbl;
  242. /* array of booleans used to keep track of sections of virtual memory defined
  243.  * as global.
  244.  */
  245. LOCAL BOOL *globalPageBlock;
  246. LOCAL STATE_TRANS_TUPLE mmuStateTransArrayLocal [] =
  247.     {
  248.     {VM_STATE_MASK_VALID, MMU_STATE_MASK_VALID, 
  249.      VM_STATE_VALID, MMU_STATE_VALID},
  250.     {VM_STATE_MASK_VALID, MMU_STATE_MASK_VALID, 
  251.      VM_STATE_VALID_NOT, MMU_STATE_VALID_NOT},
  252.     {VM_STATE_MASK_WRITABLE, MMU_STATE_MASK_WRITABLE,
  253.      VM_STATE_WRITABLE, MMU_STATE_WRITABLE},
  254.     {VM_STATE_MASK_WRITABLE, MMU_STATE_MASK_WRITABLE,
  255.      VM_STATE_WRITABLE_NOT, MMU_STATE_WRITABLE_NOT},
  256.     {VM_STATE_MASK_CACHEABLE, MMU_STATE_MASK_CACHEABLE,
  257.      VM_STATE_CACHEABLE, MMU_STATE_CACHEABLE},
  258.     {VM_STATE_MASK_CACHEABLE, MMU_STATE_MASK_CACHEABLE,
  259.      VM_STATE_CACHEABLE_NOT, MMU_STATE_CACHEABLE_NOT}
  260.     };
  261. LOCAL MMU_LIB_FUNCS mmuLibFuncsLocal =
  262.     {
  263.     mmuI86LibInit,
  264.     mmuTransTblCreate,
  265.     mmuTransTblDelete,
  266.     mmuI86Enable,   
  267.     mmuStateSet,
  268.     mmuStateGet,
  269.     mmuPageMap,
  270.     mmuGlobalPageMap,
  271.     mmuTranslate,
  272.     mmuCurrentSet
  273.     };
  274. IMPORT STATE_TRANS_TUPLE *mmuStateTransArray;
  275. IMPORT int mmuStateTransArraySize;
  276. IMPORT MMU_LIB_FUNCS mmuLibFuncs;
  277. IMPORT int mmuPageBlockSize;
  278. IMPORT int sysProcessor;
  279. LOCAL BOOL firstTime = TRUE;
  280. /* MMU_UNLOCK and MMU_LOCK are used to access page table entries that are in
  281.  * virtual memory that has been invalidated to protect it from being corrupted
  282.  * MMU_UNLOCK and MMU_LOCK makes no function call, so no worry about stack
  283.  * mismatch in virtual/physical address space, or the called out function's 
  284.  * disapearance.  It is guaranteed that this code is in physical memory.
  285.  */
  286. #define MMU_ON() 
  287.     do { int tempReg; WRS_ASM ("movl %%cr0,%0; orl $0x80010000,%0; 
  288.     movl %0,%%cr0; jmp 0f; 0:" : "=r" (tempReg) : : "memory"); } while (0)
  289. #define MMU_OFF() 
  290.     do { int tempReg; WRS_ASM ("movl %%cr0,%0; andl $0x7ffeffff,%0; 
  291.     movl %0,%%cr0; jmp 0f; 0:" : "=r" (tempReg) : : "memory"); } while (0)
  292. #define MMU_UNLOCK(wasEnabled, oldLevel) 
  293.     do { if (((wasEnabled) = mmuI86Enabled) == TRUE) 
  294. {INT_LOCK (oldLevel); MMU_OFF (); } 
  295.     } while (0)
  296. #define MMU_LOCK(wasEnabled, oldLevel) 
  297.     do { if ((wasEnabled) == TRUE) 
  298.         {MMU_ON (); INT_UNLOCK (oldLevel);} 
  299.     } while (0)
  300. /* inline version of mmuI86TLBFlush() */
  301. #define MMU_TLB_FLUSH() 
  302.     do { int tempReg; WRS_ASM ("pushfl; cli; movl %%cr3,%0; 
  303.     movl %0,%%cr3; jmp 0f; 0: popfl; " : "=r" (tempReg) : : "memory"); 
  304.     } while (0)
  305. /******************************************************************************
  306. *
  307. * mmuI86LibInit - initialize module
  308. *
  309. * Build a dummy translation table that will hold the page table entries
  310. * for the global translation table.  The MMU remains disabled upon
  311. * completion.
  312. *
  313. * RETURNS: OK if no error, ERROR otherwise
  314. *
  315. * ERRNO: S_mmuLib_INVALID_PAGE_SIZE
  316. */
  317. STATUS mmuI86LibInit 
  318.     (
  319.     int pageSize /* system pageSize (must be 4096 for i86) */
  320.     )
  321.     {
  322.     PTE *pDirectoryTable;
  323.     int i;
  324.     /* initialize the data objects that are shared with vmLib.c */
  325.     mmuStateTransArray = &mmuStateTransArrayLocal [0];
  326.     mmuStateTransArraySize =
  327.           sizeof (mmuStateTransArrayLocal) / sizeof (STATE_TRANS_TUPLE);
  328.     mmuLibFuncs = mmuLibFuncsLocal;
  329.     mmuPageBlockSize = PAGE_BLOCK_SIZE;
  330.     /* we assume a 4096 byte page size */
  331.     if (pageSize != PAGE_SIZE)
  332. {
  333. errno = S_mmuLib_INVALID_PAGE_SIZE;
  334. return (ERROR);
  335. }
  336.     mmuI86Enabled = FALSE;
  337.     mmuPageSize = pageSize;
  338.     /* allocate the global page block array to keep track of which parts
  339.      * of virtual memory are handled by the global translation tables.
  340.      * Allocate on page boundry so we can write protect it.
  341.      */
  342.     globalPageBlock = (BOOL *) memalign (pageSize, pageSize);
  343.     bzero ((char *) globalPageBlock, pageSize);
  344.     /* build a dummy translation table which will hold the pte's for
  345.      * global memory.  All real translation tables will point to this
  346.      * one for controling the state of the global virtual memory  
  347.      */
  348.     /* allocate a page to hold the directory table */
  349.     mmuGlobalTransTbl.pDirectoryTable = pDirectoryTable = 
  350. (PTE *) memalign (pageSize, pageSize);
  351.     if (pDirectoryTable == NULL)
  352. return (ERROR);
  353.     /* invalidate all the directory table entries */
  354.     for (i = 0; i < (PAGE_SIZE / sizeof(PTE)) ;i++)
  355. {
  356. pDirectoryTable[i].field.present = 0;
  357. pDirectoryTable[i].field.rw = 0;
  358. pDirectoryTable[i].field.us = 0;
  359. pDirectoryTable[i].field.pwt = 0;
  360. pDirectoryTable[i].field.pcd = 0;
  361. pDirectoryTable[i].field.access = 0;
  362. pDirectoryTable[i].field.dirty = 0;
  363. pDirectoryTable[i].field.zero = 0;
  364. pDirectoryTable[i].field.avail = 0;
  365. pDirectoryTable[i].field.page = -1;
  366. }
  367.     return (OK);
  368.     }
  369. /******************************************************************************
  370. *
  371. * mmuPteGet - get the pte for a given page
  372. *
  373. * mmuPteGet traverses a translation table and returns the (physical) address of
  374. * the pte for the given virtual address.
  375. *
  376. * RETURNS: OK or ERROR if there is no virtual space for the given address 
  377. *
  378. */
  379. LOCAL STATUS mmuPteGet 
  380.     (
  381.     MMU_TRANS_TBL *pTransTbl,  /* translation table */
  382.     void *virtAddr, /* virtual address */ 
  383.     PTE **result /* result is returned here */
  384.     )
  385.     {
  386.     PTE *pDte;
  387.     PTE *pPageTable;
  388.     pDte = &pTransTbl->pDirectoryTable [(UINT) virtAddr >> DIRECTORY_INDEX];
  389.     pPageTable = (PTE *) (pDte->bits & PTE_TO_ADDR); 
  390.     if ((UINT) pPageTable == 0xfffff000)
  391. return (ERROR);
  392.     *result = &pPageTable[((UINT) virtAddr & TABLE_BITS) >> TABLE_INDEX];
  393.     return (OK);
  394.     }
  395. /******************************************************************************
  396. *
  397. * mmuTransTblCreate - create a new translation table.
  398. *
  399. * create a i86 translation table.  Allocates space for the MMU_TRANS_TBL
  400. * data structure and calls mmuTransTblInit on that object.  
  401. *
  402. * RETURNS: address of new object or NULL if allocation failed,
  403. *          or NULL if initialization failed.
  404. */
  405. LOCAL MMU_TRANS_TBL *mmuTransTblCreate 
  406.     (
  407.     )
  408.     {
  409.     MMU_TRANS_TBL *newTransTbl;
  410.     newTransTbl = (MMU_TRANS_TBL *) malloc (sizeof (MMU_TRANS_TBL));
  411.     if (newTransTbl == NULL)
  412. return (NULL);
  413.     if (mmuTransTblInit (newTransTbl) == ERROR)
  414. {
  415. free ((char *) newTransTbl);
  416. return (NULL);
  417. }
  418.     return (newTransTbl);
  419.     }
  420. /******************************************************************************
  421. *
  422. * mmuTransTblInit - initialize a new translation table 
  423. *
  424. * Initialize a new translation table.  The directory table is copyed from the
  425. * global translation mmuGlobalTransTbl, so that we
  426. * will share the global virtual memory with all
  427. * other translation tables.
  428. * RETURNS: OK or ERROR if unable to allocate memory for directory table.
  429. */
  430. LOCAL STATUS mmuTransTblInit 
  431.     (
  432.     MMU_TRANS_TBL *newTransTbl /* translation table to be inited */
  433.     )
  434.     {
  435.     FAST PTE *pDirectoryTable;
  436.     /* allocate a page to hold the directory table */
  437.     newTransTbl->pDirectoryTable = pDirectoryTable = 
  438. (PTE *) memalign (mmuPageSize, mmuPageSize);
  439.     if (pDirectoryTable == NULL)
  440. return (ERROR);
  441.     /* copy the directory table from mmuGlobalTransTbl,
  442.      * so we get the global virtual memory 
  443.      */
  444.     bcopy ((char *) mmuGlobalTransTbl.pDirectoryTable, 
  445.    (char *) pDirectoryTable, mmuPageSize);
  446.     /* write protect virtual memory pointing to the the directory table in 
  447.      * the global translation table to insure that it can't be corrupted 
  448.      */
  449.     mmuStateSet (&mmuGlobalTransTbl, (void *) pDirectoryTable, 
  450.  MMU_STATE_MASK_WRITABLE, MMU_STATE_WRITABLE_NOT);
  451.     return (OK);
  452.     }
  453. /******************************************************************************
  454. *
  455. * mmuTransTblDelete - delete a translation table.
  456. * mmuTransTblDelete deallocates all the memory used to store the translation
  457. * table entries.  It does not deallocate physical pages mapped into the
  458. * virtual memory space.
  459. *
  460. * RETURNS: OK
  461. *
  462. */
  463. LOCAL STATUS mmuTransTblDelete 
  464.     (
  465.     MMU_TRANS_TBL *transTbl /* translation table to be deleted */
  466.     )
  467.     {
  468.     FAST int i;
  469.     FAST PTE *pDte = transTbl->pDirectoryTable;
  470.     FAST PTE *pPageTable;
  471.     /* write enable the physical page containing the directory table */
  472.     mmuStateSet (&mmuGlobalTransTbl, transTbl->pDirectoryTable, 
  473.  MMU_STATE_MASK_WRITABLE, MMU_STATE_WRITABLE);
  474.     /* deallocate only non-global page blocks */
  475.     for (i = 0; i < (PAGE_SIZE / sizeof(PTE)); i++, pDte++)
  476. if ((pDte->field.present == 1) && !globalPageBlock[i]) 
  477.     {
  478.     pPageTable = (PTE *) (pDte->bits & PTE_TO_ADDR);
  479.     mmuStateSet (&mmuGlobalTransTbl, pPageTable,
  480.  MMU_STATE_MASK_WRITABLE, MMU_STATE_WRITABLE);
  481.     free (pPageTable);
  482.     }
  483.     /* free the page holding the directory table */
  484.     free (transTbl->pDirectoryTable);
  485.     /* free the translation table data structure */
  486.     free (transTbl);
  487.     
  488.     return (OK);
  489.     }
  490. /******************************************************************************
  491. *
  492. * mmuVirtualPageCreate - set up translation tables for a virtual page
  493. *
  494. * simply check if there's already a page table that has a
  495. * pte for the given virtual page.  If there isn't, create one.
  496. *
  497. * RETURNS OK or ERROR if couldn't allocate space for a page table.
  498. */
  499. LOCAL STATUS mmuVirtualPageCreate 
  500.     (
  501.     MMU_TRANS_TBL *thisTbl,  /* translation table */
  502.     void *virtPageAddr /* virtual addr to create */
  503.     )
  504.     {
  505.     PTE *pDte;
  506.     FAST PTE *pPageTable;
  507.     FAST UINT i;
  508.     PTE *dummy;
  509.     if (mmuPteGet (thisTbl, virtPageAddr, &dummy) == OK)
  510. return (OK);
  511.     pPageTable = (PTE *) memalign (mmuPageSize, mmuPageSize);
  512.     if (pPageTable == NULL)
  513. return (ERROR);
  514.     /* invalidate every page in the new page block */
  515.     for (i = 0; i < (PAGE_SIZE / sizeof(PTE)); i++)
  516. {
  517. pPageTable[i].field.present = 0;
  518. pPageTable[i].field.rw = 0;
  519. pPageTable[i].field.us = 0;
  520. pPageTable[i].field.pwt = 0;
  521. pPageTable[i].field.pcd = 0;
  522. pPageTable[i].field.access = 0;
  523. pPageTable[i].field.dirty = 0;
  524. pPageTable[i].field.zero = 0;
  525. pPageTable[i].field.avail = 0;
  526. pPageTable[i].field.page = -1;
  527. }
  528.     /* write protect the new physical page containing the pte's
  529.        for this new page block */
  530.     mmuStateSet (&mmuGlobalTransTbl, pPageTable, 
  531.      MMU_STATE_MASK_WRITABLE, MMU_STATE_WRITABLE_NOT); 
  532.     /* unlock the physical page containing the directory table,
  533.        so we can modify it */
  534.     mmuStateSet (&mmuGlobalTransTbl, thisTbl->pDirectoryTable, 
  535.  MMU_STATE_MASK_WRITABLE, MMU_STATE_WRITABLE);
  536.     pDte = &thisTbl->pDirectoryTable [(UINT) virtPageAddr >> DIRECTORY_INDEX];    
  537.     /* modify the directory table entry to point to the new page table */
  538.     pDte->field.page = (UINT) pPageTable >> ADDR_TO_PAGE;
  539.     pDte->field.present = 1;
  540.     pDte->field.rw = 1;
  541.     /* write protect the directory table */
  542.     mmuStateSet (&mmuGlobalTransTbl, thisTbl->pDirectoryTable, 
  543.      MMU_STATE_MASK_WRITABLE, MMU_STATE_WRITABLE_NOT);
  544.     /* defer the TLB flush to the mmuCurrentSet() at init time */
  545.     if (!firstTime)
  546.         {
  547.         MMU_TLB_FLUSH ();
  548.         }
  549.     return (OK);
  550.     }
  551. /******************************************************************************
  552. *
  553. * mmuStateSet - set state of virtual memory page
  554. *
  555. * mmuStateSet is used to modify the state bits of the pte for the given
  556. * virtual page.  The following states are provided:
  557. *
  558. * MMU_STATE_VALID  MMU_STATE_VALID_NOT  vailid/invalid
  559. * MMU_STATE_WRITABLE  MMU_STATE_WRITABLE_NOT  writable/writeprotected
  560. * MMU_STATE_CACHEABLE  MMU_STATE_CACHEABLE_NOT  notcachable/cachable
  561. *
  562. * these may be or'ed together in the state parameter.  Additionally, masks
  563. * are provided so that only specific states may be set:
  564. *
  565. * MMU_STATE_MASK_VALID 
  566. * MMU_STATE_MASK_WRITABLE
  567. * MMU_STATE_MASK_CACHEABLE
  568. *
  569. * These may be or'ed together in the stateMask parameter.  
  570. *
  571. * Accesses to a virtual page marked as invalid will result in a page fault.
  572. *
  573. * RETURNS: OK or ERROR if virtual page does not exist.
  574. */
  575. LOCAL STATUS mmuStateSet 
  576.     (
  577.     MMU_TRANS_TBL *transTbl,  /* translation table */
  578.     void *pageAddr, /* page whose state to modify */ 
  579.     UINT stateMask, /* mask of which state bits to modify */
  580.     UINT state /* new state bit values */
  581.     )
  582.     {
  583.     PTE *pPte;
  584.     int oldIntLev = 0;
  585.     BOOL wasEnabled;
  586.     if (mmuPteGet (transTbl, pageAddr, &pPte) != OK)
  587. return (ERROR);
  588.     /* modify the pte with MMU turned off and interrupts locked out */
  589.     MMU_UNLOCK (wasEnabled, oldIntLev);
  590.     pPte->bits = (pPte->bits & ~stateMask) | (state & stateMask);
  591.     if ((sysProcessor != X86CPU_386) && (cacheDataMode & CACHE_COPYBACK))
  592. if ((state & MMU_STATE_MASK_CACHEABLE) == MMU_STATE_CACHEABLE)
  593.             pPte->bits &= ~MMU_STATE_CACHEABLE_WT;
  594.     MMU_LOCK (wasEnabled, oldIntLev);
  595.     /* defer the TLB and Cache flush to the mmuCurrentSet() */
  596.     if (!firstTime)
  597.         {
  598.         MMU_TLB_FLUSH ();
  599.         cacheArchClearEntry (DATA_CACHE, pPte);
  600. }
  601.     return (OK);
  602.     }
  603. /******************************************************************************
  604. *
  605. * mmuStateGet - get state of virtual memory page
  606. *
  607. * mmuStateGet is used to retrieve the state bits of the pte for the given
  608. * virtual page.  The following states are provided:
  609. *
  610. * MMU_STATE_VALID  MMU_STATE_VALID_NOT  vailid/invalid
  611. * MMU_STATE_WRITABLE  MMU_STATE_WRITABLE_NOT  writable/writeprotected
  612. * MMU_STATE_CACHEABLE  MMU_STATE_CACHEABLE_NOT  notcachable/cachable
  613. *
  614. * these are or'ed together in the returned state.  Additionally, masks
  615. * are provided so that specific states may be extracted from the returned state:
  616. *
  617. * MMU_STATE_MASK_VALID 
  618. * MMU_STATE_MASK_WRITABLE
  619. * MMU_STATE_MASK_CACHEABLE
  620. *
  621. * RETURNS: OK or ERROR if virtual page does not exist.
  622. */
  623. LOCAL STATUS mmuStateGet 
  624.     (
  625.     MMU_TRANS_TBL *transTbl,  /* tranlation table */
  626.     void *pageAddr,  /* page whose state we're querying */
  627.     UINT *state /* place to return state value */
  628.     )
  629.     {
  630.     PTE *pPte;
  631.     if (mmuPteGet (transTbl, pageAddr, &pPte) != OK)
  632. return (ERROR);
  633.     *state = pPte->bits; 
  634.     if ((sysProcessor != X86CPU_386) && (cacheDataMode & CACHE_COPYBACK))
  635. if ((*state & MMU_STATE_MASK_CACHEABLE) != MMU_STATE_CACHEABLE_NOT)
  636.             *state |= MMU_STATE_CACHEABLE_WT;
  637.     return (OK);
  638.     }
  639. /******************************************************************************
  640. *
  641. * mmuPageMap - map physical memory page to virtual memory page
  642. *
  643. * The physical page address is entered into the pte corresponding to the
  644. * given virtual page.  The state of a newly mapped page is undefined. 
  645. *
  646. * RETURNS: OK or ERROR if translation table creation failed. 
  647. */
  648. LOCAL STATUS mmuPageMap 
  649.     (
  650.     MMU_TRANS_TBL *transTbl,  /* translation table */
  651.     void *virtualAddress,  /* virtual address */
  652.     void *physPage /* physical address */
  653.     )
  654.     {
  655.     PTE *pPte;
  656.     int oldIntLev = 0;
  657.     FAST UINT page = (UINT)physPage >> ADDR_TO_PAGE; 
  658.     BOOL wasEnabled;
  659.     if (mmuPteGet (transTbl, virtualAddress, &pPte) != OK)
  660. {
  661. /* build the translation table for the virtual address */
  662. if (mmuVirtualPageCreate (transTbl, virtualAddress) != OK)
  663.     return (ERROR);
  664. if (mmuPteGet (transTbl, virtualAddress, &pPte) != OK)
  665.     return (ERROR);
  666. }
  667.     MMU_UNLOCK (wasEnabled, oldIntLev);
  668.     pPte->field.page = page; 
  669.     MMU_LOCK (wasEnabled, oldIntLev);
  670.     MMU_TLB_FLUSH ();
  671.     cacheArchClearEntry (DATA_CACHE, pPte);
  672.     return (OK);
  673.     }
  674. /******************************************************************************
  675. *
  676. * mmuGlobalPageMap - map physical memory page to global virtual memory page
  677. *
  678. * mmuGlobalPageMap is used to map physical pages into global virtual memory
  679. * that is shared by all virtual memory contexts.  The translation tables
  680. * for this section of the virtual space are shared by all virtual memory
  681. * contexts.
  682. *
  683. * RETURNS: OK or ERROR if no pte for given virtual page.
  684. */
  685. LOCAL STATUS mmuGlobalPageMap 
  686.     (
  687.     void *virtualAddress,  /* virtual address */
  688.     void *physPage /* physical address */
  689.     )
  690.     {
  691.     PTE *pPte;
  692.     int oldIntLev = 0;
  693.     FAST UINT page = (UINT)physPage >> ADDR_TO_PAGE; 
  694.     BOOL wasEnabled;
  695.     if (mmuPteGet (&mmuGlobalTransTbl, virtualAddress, &pPte) != OK)
  696. {
  697. /* build the translation table for the virtual address */
  698. if (mmuVirtualPageCreate (&mmuGlobalTransTbl, virtualAddress) != OK)
  699.     return (ERROR);
  700. if (mmuPteGet (&mmuGlobalTransTbl, virtualAddress, &pPte) != OK)
  701.     return (ERROR);
  702. /* the globalPageBlock array is write protected */
  703. mmuStateSet (&mmuGlobalTransTbl, globalPageBlock, 
  704.      MMU_STATE_MASK_WRITABLE, MMU_STATE_WRITABLE);
  705. globalPageBlock [(unsigned) virtualAddress >> DIRECTORY_INDEX] = TRUE;
  706. mmuStateSet (&mmuGlobalTransTbl, globalPageBlock, 
  707.      MMU_STATE_MASK_WRITABLE, MMU_STATE_WRITABLE_NOT);
  708. }
  709.     MMU_UNLOCK (wasEnabled, oldIntLev);
  710.     pPte->field.page = page; 
  711.     MMU_LOCK (wasEnabled, oldIntLev);
  712.     /* defer the TLB and Cache flush to the mmuCurrentSet() */
  713.     if (!firstTime)
  714.         {
  715.         MMU_TLB_FLUSH ();
  716.         cacheArchClearEntry (DATA_CACHE, pPte);
  717. }
  718.     return (OK);
  719.     }
  720. /******************************************************************************
  721. *
  722. * mmuTranslate - translate a virtual address to a physical address
  723. *
  724. * Traverse the translation table and extract the physical address for the
  725. * given virtual address from the pte corresponding to the virtual address.
  726. *
  727. * RETURNS: OK or ERROR if no pte for given virtual address.
  728. */
  729. LOCAL STATUS mmuTranslate 
  730.     (
  731.     MMU_TRANS_TBL *transTbl,  /* translation table */
  732.     void *virtAddress,  /* virtual address */
  733.     void **physAddress /* place to return result */
  734.     )
  735.     {
  736.     PTE *pPte;
  737.     if (mmuPteGet (transTbl, virtAddress, &pPte) != OK)
  738. {
  739. errno = S_mmuLib_NO_DESCRIPTOR; 
  740. return (ERROR);
  741. }
  742.     if (pPte->field.present == 0)
  743. {
  744. errno = S_mmuLib_INVALID_DESCRIPTOR; 
  745. return (ERROR);
  746. }
  747.     *physAddress = (void *)(pPte->bits & PTE_TO_ADDR); 
  748.     /* add offset into page */
  749.     *physAddress = (void *)((UINT)*physAddress + 
  750.    ((UINT)virtAddress & OFFSET_BITS));
  751.     return (OK);
  752.     }
  753. /******************************************************************************
  754. *
  755. * mmuCurrentSet - change active translation table
  756. *
  757. * mmuCurrent set is used to change the virtual memory context.
  758. * Load the CRP (root pointer) register with the given translation table.
  759. *
  760. */
  761. LOCAL void mmuCurrentSet 
  762.     (
  763.     MMU_TRANS_TBL *transTbl /* new active tranlation table */
  764.     ) 
  765.     {
  766.     FAST int oldLev;
  767.     if (firstTime)
  768. {
  769. mmuMemPagesWriteDisable (&mmuGlobalTransTbl);
  770. mmuMemPagesWriteDisable (transTbl);
  771. /* perform the deferred TLB and Cache flush */
  772.         /* MMU_TLB_FLUSH (); */ /* done by following mmuI86PdbrSet () */
  773.         if (sysProcessor != X86CPU_386)
  774.             WRS_ASM ("wbinvd"); /* flush the entire cache */
  775. firstTime = FALSE;
  776. }
  777.     oldLev = intLock ();
  778.     mmuCurrentTransTbl = transTbl;
  779.     mmuI86PdbrSet (transTbl);
  780.     intUnlock (oldLev);
  781.     }
  782. /******************************************************************************
  783. *
  784. * mmuMemPagesWriteDisable - write disable memory holding a table's descriptors
  785. *
  786. * Memory containing translation table descriptors is marked as read only
  787. * to protect the descriptors from being corrupted.  This routine write protects
  788. * all the memory used to contain a given translation table's descriptors.
  789. *
  790. */
  791. LOCAL void mmuMemPagesWriteDisable
  792.     (
  793.     MMU_TRANS_TBL *transTbl
  794.     )
  795.     {
  796.     void *thisPage;
  797.     int i;
  798.     for (i = 0; i < (PAGE_SIZE / sizeof(PTE)) ;i++)
  799. {
  800. thisPage = (void *) (transTbl->pDirectoryTable[i].bits & PTE_TO_ADDR);
  801. if ((int)thisPage != 0xfffff000)
  802.     mmuStateSet (transTbl, thisPage, MMU_STATE_MASK_WRITABLE,
  803.  MMU_STATE_WRITABLE_NOT);
  804. }
  805.     mmuStateSet (transTbl, transTbl->pDirectoryTable, MMU_STATE_MASK_WRITABLE, 
  806.  MMU_STATE_WRITABLE_NOT);
  807.     }