12

Virtual Memory Interface

Basic Support and Optional Component VxVMI



12.1    Introduction

VxWorks provides two levels of virtual memory support. The basic level is bundled with VxWorks and provides caching on a per-page basis. The full level is unbundled, and requires the optional component VxVMI. VxVMI provides write protection of text segments and the VxWorks exception vector table, and an architecture-independent interface to the CPU's memory management unit (MMU). For information on how to install VxVMI, see the Tornado Getting Started Guide.

This chapter contains the following sections:

  • A description of the basic level of support.

  • Configuration guidelines applicable to both levels of support.

  • Two sections that apply only to the optional component VxVMI:

  • One for general use, discussing the write protection implemented by VxVMI.

  • One that describes a set of routines for manipulating the MMU. VxVMI provides low-level routines for interfacing with the MMU in an architecture-independent manner, allowing you to implement your own virtual memory systems.



12.2    Basic Virtual Memory Support

For systems with an MMU, VxWorks allows you to perform DMA and interprocessor communication more efficiently by rendering related buffers noncacheable. This is necessary to ensure that data is not being buffered locally when other processors or DMA devices are accessing the same memory location. Without the ability to make portions of memory noncacheable, caching must be turned off globally (resulting in performance degradation) or buffers must be flushed/invalidated manually.

Basic virtual memory support is included by selecting INCLUDE_MMU_BASIC in the project facility VxWorks view; see 12.3 Virtual Memory Configuration. It is also possible to allocate noncacheable buffers using cacheDmaMalloc( ); see the reference entry for cacheLib.



12.3    Virtual Memory Configuration

The following discussion of configuration applies to both bundled and unbundled virtual memory support. In the project facility, define the constants in Table 12-1 to reflect your system configuration.

Table 12-1:   MMU Configuration Constants


Constant
Description

INCLUDE_MMU_BASIC
Basic MMU support without VxVMI option.
INCLUDE_MMU_FULL
Full MMU support with the VxVMI option.
INCLUDE_PROTECT_TEXT
Text segment protection (requires full MMU support).
INCLUDE_PROTECT_VEC_TABLE
Exception vector table protection (requires full MMU support).

The appropriate default page size for your processor (4 KB or 8KB) is defined by VM_PAGE_SIZE in your BSP. If you must change this value for some reason, redefine VM_PAGE_SIZE in config.h. (See the Tornado User's Guide: Configuration and Build.)

To make memory noncacheable, it must have a virtual-to-physical mapping. The data structure PHYS_MEM_DESC in vmLib.h defines the parameters used for mapping physical memory. Each board's memory map is defined in sysLib.c using sysPhysMemDesc (which is declared as an array of PHYS_MEM_DESC). In addition to defining the initial state of the memory pages, the sysPhysMemDesc structure defines the virtual addresses used for mapping virtual-to-physical memory. For a discussion of page states, see Page States.

Modify the sysPhysMemDesc structure to reflect your system configuration. For example, you may need to add the addresses of interprocessor communication buffers not already included in the structure. Or, you may need to map and make noncacheable the VMEbus addresses of the shared-memory data structures. Most board support packages have a section of VME space defined in sysPhysMemDesc; however, this may not include all the space required by your system configuration.

I/O devices and memory not already included in the structure must also be mapped and made noncacheable. In general, off-board memory regions are specified as noncacheable; see VxWorks Network Programmer's Guide: Data Link Layer Network Components.


*      
CAUTION: The regions of memory defined in sysPhysMemDesc must be page-aligned, and must span complete pages. In other words, the first three fields (virtual address, physical address, and length) of a PHYS_MEM_DESC structure must all be even multiples of VM_PAGE_SIZE. Specifying elements of sysPhysMemDesc that are not page-aligned leads to crashes during VxWorks initialization.

The following example configuration consists of multiple CPUs using the shared-memory network. A separate memory board is used for the shared-memory pool. Because this memory is not already mapped, it must be added to sysPhysMemDesc for all the boards on the network. The memory starts at 0x4000000 and must be made noncacheable, as shown in the following code excerpt:

/* shared memory */ 
{ 
(void *) 0x4000000,         /* virtual address */ 
(void *) 0x4000000,         /* physical address */ 
0x20000,              /* length */ 
/* initial state mask */ 
VM_STATE_MASK_VALID | VM_STATE_MASK_WRITABLE |VM_STATE_MASK_CACHEABLE, 
/* initial state */ 
VM_STATE_VALID | VM_STATE_WRITABLE | VM_STATE_CACHEABLE_NOT 
}

For MC680x0 boards, the virtual address must be the same as the physical address. For other boards, the virtual and physical addresses are the same as a matter of convention.



12.4    General Use

This section describes VxVMI's general use and configuration for write-protecting text segments and the exception vector table.

VxVMI uses the MMU to prevent portions of memory from being overwritten. This is done by write-protecting pages of memory. Not all target hardware supports write protection; see the architecture appendices in this manual for further information. For most architectures, the page size is 8KB. An attempt to write to a memory location that is write-protected causes a bus error.

When VxWorks is loaded, all text segments are write-protected; see 12.3 Virtual Memory Configuration. The text segments of additional object modules loaded using ld( ) are automatically marked as read-only. When object modules are loaded, memory to be write-protected is allocated in page-size increments. No additional steps are required to write-protect application code.

During system initialization, VxWorks write-protects the exception vector table. The only way to modify the interrupt vector table is to use the routine intConnect( ), which write-enables the exception vector table for the duration of the call.

To include write protection, select the following in the project facility VxWorks view:

INCLUDE_MMU_FULL
INCLUDE_PROTECT_TEXT
INCLUDE_PROTECT_VEC_TABLE



12.5    Using the MMU Programmatically

This section describes the facilities provided for manipulating the MMU programmatically using low-level routines in vmLib. You can make data private to a task or code segment, make portions of memory noncacheable, or write-protect portions of memory. The fundamental structure used to implement virtual memory is the virtual memory context (VMC).

For a summary of the VxVMI routines, see the reference entry for vmLib.

12.5.1   Virtual Memory Contexts

A virtual memory context (VM_CONTEXT, defined in vmLib) is made up of a translation table and other information used for mapping a virtual address to a physical address. Multiple virtual memory contexts can be created and swapped in and out as desired.

Global Virtual Memory

Some system objects, such as text segments and semaphores, must be accessible to all tasks in the system regardless of which virtual memory context is made current. These objects are made accessible by means of global virtual memory. Global virtual memory is created by mapping all the physical memory in the system (the mapping is defined in sysPhysMemDesc) to the identical address in the virtual memory space. In the default system configuration, this initially gives a one-to-one relationship between physical memory and global virtual memory; for example, virtual address 0x5000 maps to physical address 0x5000. On some architectures, it is possible to use sysPhysMemDesc to set up virtual memory so that the mapping of virtual-to-physical addresses is not one-to-one; see 12.3 Virtual Memory Configuration for additional information.

Global virtual memory is accessible from all virtual memory contexts. Modifications made to the global mapping in one virtual memory context appear in all virtual memory contexts. Before virtual memory contexts are created, add all global memory with vmGlobalMap( ). Global memory that is added after virtual memory contexts are created may not be available to existing contexts.

Initialization

Global virtual memory is initialized by vmGlobalMapInit( ) in usrMmuInit( ), which is called from usrRoot( ). The routine usrMmuInit( ) is in installDir/target/src/config/usrMmuInit.c, and creates global virtual memory using sysPhysMemDesc. It then creates a default virtual memory context and makes the default context current. Optionally, it also enables the MMU.

Page States

Each virtual memory page (typically 8KB) has a state associated with it. A page can be valid/invalid, writable/nonwritable, or cacheable/noncacheable. See Table 12-2 for the associated constants.

Table 12-2:   State Flags


Constant
Description

VM_STATE_VALID
Valid translation
VM_STATE_VALID_NOT
Invalid translation
VM_STATE_WRITABLE
Writable memory
VM_STATE_WRITABLE_NOT
Read-only memory
VM_STATE_CACHEABLE
Cacheable memory
VM_STATE_CACHEABLE_NOT
Noncacheable memory

Validity
A valid state indicates the virtual-to-physical translation is true. When the translation tables are initialized, global virtual memory is marked as valid. All other virtual memory is initialized as invalid.

Writability
Pages can be made read-only by setting the state to nonwritable. This is used by VxWorks to write-protect all text segments.

Cacheability
The caching of memory pages can be prevented by setting the state flags to noncacheable. This is useful for memory that is shared between processors (including DMA devices).

Change the state of a page with the routine vmStateSet( ). In addition to specifying the state flags, a state mask must describe which flags are being changed; see Table 12-3. Additional architecture-dependent states are specified in vmLib.h.

Table 12-3:   State Masks


Constant
Description

VM_STATE_MASK_VALID
Modifies valid flag.
VM_STATE_MASK_WRITABLE
Modifies write flag.
VM_STATE_MASK_CACHEABLE
Modifies cache flag.

12.5.2   Private Virtual Memory

Private virtual memory can be created by creating a new virtual memory context. This is useful for protecting data by making it inaccessible to other tasks or by limiting access to specific routines. Virtual memory contexts are not automatically created for tasks, but can be created and swapped in and out in an application-specific manner.

At system initialization, a default context is created. All tasks use this default context. To create private virtual memory, a task must create a new virtual memory context using vmContextCreate( ), and make it current. All virtual memory contexts share the global mappings that are created at system initialization; see Figure 12-1. Only the valid virtual memory in the current virtual memory context (including global virtual memory) is accessible. Virtual memory defined in other virtual memory contexts is not accessible. To make another memory context current, use vmCurrentSet( ).

Figure 12-1:   Global Mappings of Virtual Memory

To create a new virtual-to-physical mapping, use vmMap( ); both the physical and virtual address must be determined in advance. The physical memory (which must be page aligned) can be obtained using valloc( ). The easiest way to determine the virtual address is to use vmGlobalInfoGet( ) to find a virtual page that is not a global mapping. With this scheme, if multiple mappings are required, a task must keep track of its own private virtual memory pages to guarantee it does not map the same non-global address twice.

When physical pages are mapped into new sections of the virtual space, the physical page is accessible from two different virtual addresses (a condition known as aliasing): the newly mapped virtual address and the virtual address equal to the physical address in the global virtual memory. This can cause problems for some architectures, because the cache may hold two different values for the same underlying memory location. To avoid this, invalidate the virtual page (using vmStateSet( )) in the global virtual memory. This also ensures that the data is accessible only when the virtual memory context containing the new mapping is current.

Figure 12-2 depicts two private virtual memory contexts. The new context (pvmc2) maps virtual address 0x6000000 to physical address 0x10000. To prevent access to this address from outside of this virtual context (pvmc1), the corresponding physical address (0x10000) must be set to invalid. If access to the memory is made using address 0x10000, a bus error occurs because that address is now invalid.

Figure 12-2:   Mapping Private Virtual Memory

Example 12-1:   Private Virtual Memory Contexts

In the following code example, private virtual memory contexts are used for allocating memory from a task's private memory partition. The setup routine, contextSetup( ), creates a private virtual memory context that is made current during a context switch. The virtual memory context is stored in the field spare1 in the task's TCB. Switch hooks are used to save the old context and install the task's private context. Note that the use of switch hooks increases the context switch time. A user-defined memory partition is created using the private virtual memory context. The partition ID is stored in spare2 in the tasks TCB. Any task wanting a private virtual memory context must call contextSetup( ). A sample task to test the code is included.

/* contextExample.h - header file for vm contexts used by switch hooks */ 
 
#define NUM_PAGES (3)
/* context.c - use context switch hooks to make task private context current */  
 
#include "vxWorks.h" 
#include "vmLib.h" 
#include "semLib.h" 
#include "taskLib.h" 
#include "taskHookLib.h" 
#include "memLib.h" 
#include "contextExample.h" 
 
void privContextSwitch (WIND_TCB *pOldTask, WIND_TCB *pNewTask); 
 
/* 
 * initContextSetup - install context switch hook 
 */ 
 
STATUS initContextSetup ( ) 
    { 
    /* Install switch hook */ 
 
    if (taskSwitchHookAdd ((FUNCPTR) privContextSwitch) == ERROR) 
        return (ERROR); 
 
    return (OK); 
    } 
 
/* 
 * contextSetup - initialize context and create separate memory partition 
 * 
 * Call only once for each task that wants a private context. 
 * 
 * This could be made into a create-hook routine if every task on the  
 * system needs a private context. To use as a create hook, the code for 
 * installing the new virtual memory context should be replaced by simply 
 * saving the new context in spare1 of the task's TCB. 
 */
STATUS contextSetup (void) 
    { 
    VM_CONTEXT_ID pNewContext; 
    int pageSize; 
    int pageBlkSize; 
    char * pPhysAddr; 
    char * pVirtAddr; 
    UINT8 * globalPgBlkArray; 
    int newMemSize; 
    int index; 
    WIND_TCB * pTcb; 
 
    /* create context */ 
 
    pNewContext = vmContextCreate(); 
 
    /* get page and page block size */ 
 
    pageSize = vmPageSizeGet (); 
    pageBlkSize = vmPageBlockSizeGet (); 
    newMemSize = pageSize * NUM_PAGES; 
 
    /* allocate physical memory that is page aligned */ 
 
    if ((pPhysAddr = (char *) valloc (newMemSize)) == NULL) 
        return (ERROR); 
 
    /* Select virtual address to map. For this example, since only one page 
     * block is used per task, simply use the first address that is not a  
     * global mapping. vmGlobalInfoGet( ) returns a boolean array where each  
     * element corresponds to a block of virtual memory. 
     */ 
 
    globalPgBlkArray = vmGlobalInfoGet(); 
    for (index = 0; globalPgBlkArray[index] == TRUE; index++) 
        ; 
    pVirtAddr = (char *) (index * pageBlkSize); 
 
    /* map physical memory to new context */ 
 
    if (vmMap (pNewContext, pVirtAddr, pPhysAddr, newMemSize) == ERROR) 
        { 
        free (pPhysAddr); 
        return (ERROR); 
        } 
 
    /*  
     * Set state in global virtual memory to be invalid - any access to 
     * this memory must be done through new context.  
     */
    if (vmStateSet(pNewContext, pPhysAddr, newMemSize, VM_STATE_MASK_VALID, 
                    VM_STATE_VALID_NOT) == ERROR) 
        return (ERROR); 
 
    /* get tasks TCB */ 
 
    pTcb = taskTcb (taskIdSelf()); 
 
    /* change virtual memory contexts */ 
 
    /*  
     * Stash the current vm context in the spare TCB field -- the switch 
     * hook will install this when this task gets swapped out. 
     */ 
 
    pTcb->spare1 = (int) vmCurrentGet(); 
 
    /* install new tasks context */ 
 
    vmCurrentSet (pNewContext); 
 
    /* create new memory partition and store id in task's TCB */ 
 
    if ((pTcb->spare2 = (int) memPartCreate (pVirtAddr,newMemSize)) == NULL) 
        return (ERROR); 
 
    return (OK); 
    }
/* 
 * privContextSwitch - routine to be executed on a context switch 
 * 
 * If old task had private context, save it. If new task has private 
 * context, install it. 
 */ 
 
void privContextSwitch  
    ( 
    WIND_TCB *pOldTcb, 
    WIND_TCB *pNewTcb 
    ) 
 
    { 
    VM_CONTEXT_ID pContext = NULL; 
 
    /* If previous task had private context, save it--reset previous context. */
    if (pOldTcb->spare1) 
        { 
        pContext = (VM_CONTEXT_ID) pOldTcb->spare1; 
        pOldTcb->spare1 = (int) vmCurrentGet (); 
 
        /* restore old context */ 
 
        vmCurrentSet (pContext); 
        } 
 
    /*  
     * If next task has private context, map new context and save previous 
     * context in task's TCB. 
     */  
 
    if (pNewTcb->spare1) 
        { 
        pContext = (VM_CONTEXT_ID) pNewTcb->spare1; 
    pNewTcb->spare1 = (int) vmCurrentGet(); 
 
        /* install new tasks context */ 
 
        vmCurrentSet (pContext); 
        } 
    }
/* taskExample.h - header file for testing VM contexts used by switch hook */  
 
/* This code is used by the sample task. */ 
 
#define MAX (10000000) 
 
typedef struct myStuff { 
    int stuff; 
    int myStuff; 
    } MY_DATA;
/* testTask.c - task code to test switch hooks */ 
 
#include "vxWorks.h" 
#include "memLib.h" 
#include "taskLib.h" 
#include "stdio.h" 
#include "vmLib.h" 
#include "taskExample.h"
IMPORT char *string = "test\n"; 
 
MY_DATA *pMem; 
 
/* 
 * testTask - allocate private memory and use it 
 * 
 * Loop forever, modifying memory and printing out a global string. Use this 
 * in conjunction with testing from the shell. Since pMem points to private 
 * memory, the shell should generate a bus error when it tries to read it. 
 * For example: 
 *     -> sp testTask 
 *     -> d pMem 
 */ 
 
STATUS testTask (void) 
    { 
    int val; 
    WIND_TCB *myTcb; 
 
    /* install private context */ 
 
    if (contextSetup () == ERROR) 
        return (ERROR); 
 
    /* get TCB */ 
 
    myTcb = taskTcb (taskIdSelf ()); 
 
    /* allocate private memory */ 
 
    if ((pMem = (MY_DATA *) memPartAlloc((PART_ID) myTcb->spare2,  
         sizeof (MY_DATA))) == NULL) 
        return (ERROR); 
 
    /*  
     * Forever, modify data in private memory and display string in 
     * global memory. 
     */ 
 
    FOREVER 
    { 
        for (val = 0; val <= MAX; val++) 
            { 
            /* modify structure */ 
 
            pMem->stuff = val; 
            pMem->myStuff = val / 2;
            /* make sure can access global virtual memory */ 
 
            printf (string); 
 
            taskDelay (sysClkRateGet() * 10); 
            } 
        } 
    return (OK); 
    } 
 
/* 
 * testVmContextGet - return a task's virtual memory context stored in TCB 
 * 
 * Used with vmContextShow()1
 to display a task's virtual memory context.  
 * For example, from the shell, type: 
 *   -> tid = sp (testTask) 
 *   -> vmContextShow (testVmContextGet (tid)) 
 */ 
 
VM_CONTEXT_ID testVmContextGet 
    ( 
    UINT tid 
    ) 
    { 
    return ((VM_CONTEXT_ID) ((taskTcb (tid))->spare1)); 
    }

12.5.3   Noncacheable Memory

Architectures that do not support bus snooping must disable the memory caching that is used for interprocessor communication (or by DMA devices). If multiple processors are reading from and writing to a memory location, you must guarantee that when the CPU accesses the data, it is using the most recent value. If caching is used in one or more CPUs in the system, there can be a local copy of the data in one of the CPUs' data caches.

In the example in Figure 12-3, a system with multiple CPUs share data, and one CPU on the system (CPU 0) caches the shared data. A task on CPU 0 reads the data [1] and then modifies the value [2]; however, the new value may still be in the cache and not flushed to memory when a task on another CPU (CPU 1) accesses it [3]. Thus the value of the data used by the task on CPU 1 is the old value and does not reflect the modifications done by the task on CPU 0; that value is still in CPU 0's data cache [2].

Figure 12-3:   Example of Possible Problems with Data Caching

To disable caching on a page basis, use vmStateSet( ); for example:

vmStateSet (pContext, pSData, len, VM_STATE_MASK_CACHEABLE, VM_STATE_CACHEABLE_NOT) 

To allocate noncacheable memory, see the reference entry for cacheDmaMalloc( ).

12.5.4   Nonwritable Memory

Memory can be marked as nonwritable. Sections of memory can be write-protected using vmStateSet( ) to prevent inadvertent access.

One use of this is to restrict modification of a data object to a particular routine. If a data object is global but read-only, tasks can read the object but not modify it. Any task that must modify this object must call the associated routine. Inside the routine, the data is made writable for the duration of the routine, and on exit, the memory is set to VM_STATE_WRITABLE_NOT.

Example 12-2:   Nonwritable Memory

In this code example, to modify the data structure pointed to by pData, a task must call dataModify( ). This routine makes the memory writable, modifies the data, and sets the memory back to nonwritable. If a task tries to read the memory, it is successful; however, if it tries to modify the data outside of dataModify( ), a bus error occurs.

/* privateCode.h - header file to make data writable from routine only */ 
 
#define MAX 1024 
 
typedef struct myData 
    { 
    char stuff[MAX]; 
    int moreStuff; 
    } MY_DATA;
/* privateCode.c - uses VM contexts to make data private to a code segment */  
 
#include "vxWorks.h" 
#include "vmLib.h" 
#include "semLib.h" 
#include "privateCode.h" 
 
MY_DATA * pData; 
SEM_ID dataSemId; 
int pageSize; 
 
/* 
 * initData - allocate memory and make it nonwritable 
 * 
 * This routine initializes data and should be called only once. 
 * 
 */ 
 
STATUS initData (void) 
    { 
    pageSize = vmPageSizeGet(); 
 
    /* create semaphore to protect data */ 
 
    dataSemId = semBCreate (SEM_Q_PRIORITY, SEM_EMPTY);
    /* allocate memory = to a page */ 
 
    pData = (MY_DATA *) valloc (pageSize); 
 
    /* initialize data and make it read-only */ 
 
    bzero (pData, pageSize); 
    if (vmStateSet (NULL, pData, pageSize, VM_STATE_MASK_WRITABLE,  
            VM_STATE_WRITABLE_NOT) == ERROR) 
                { 
                semGive (dataSemId); 
                return (ERROR); 
                } 
 
    /* release semaphore */ 
 
    semGive (dataSemId); 
    return (OK); 
    } 
 
/* 
 * dataModify - modify data 
 * 
 * To modify data, tasks must call this routine, passing a pointer to 
 * the new data. 
 * To test from the shell use: 
 *     -> initData 
 *     -> sp dataModify 
 *     -> d pData 
 *     -> bfill (pdata, 1024, 'X') 
 */ 
 
STATUS dataModify  
    (  
    MY_DATA * pNewData 
    ) 
    { 
 
    /* take semaphore for exclusive access to data */ 
 
    semTake (dataSemId, WAIT_FOREVER); 
 
    /* make memory writable */ 
 
    if (vmStateSet (NULL, pData, pageSize, VM_STATE_MASK_WRITABLE,  
            VM_STATE_WRITABLE) == ERROR) 
                { 
                semGive (dataSemId); 
                return (ERROR); 
                } 
 
    /* update data*/ 
 
    bcopy (pNewData, pData, sizeof(MY_DATA)); 
 
    /* make memory not writable */ 
 
    if (vmStateSet (NULL, pData, pageSize, VM_STATE_MASK_WRITABLE,  
            VM_STATE_WRITABLE_NOT) == ERROR) 
                { 
                semGive (dataSemId); 
                return (ERROR); 
                } 
 
    semGive (dataSemId); 
 
    return (OK); 
    }

12.5.5   Troubleshooting

If INCLUDE_MMU_FULL_SHOW is included in the project facility VxWorks view, you can use vmContextShow( ) to display a virtual memory context on the standard output device. In the following example, the current virtual memory context is displayed. Virtual addresses between 0x0 and 0x59fff are write-protected; 0xff800000 through 0xffbfffff are noncacheable; and 0x2000000 through 0x2005fff are private. All valid entries are listed and marked with a V+. Invalid entries are not listed.

-> vmContextShow 0  
value = 0 = 0x0 

The output is sent to the standard output device, and looks like the following:

VIRTUAL ADDR   BLOCK LENGTH   PHYSICAL ADDR   STATE 
0x0            0x5a000        0x0             W- C+ V+ (global) 
0x5a000        0x1f3c000      0x5a000         W+ C+ V+ (global) 
0x1f9c000      0x2000         0x1f9c000       W+ C+ V+ (global) 
0x1f9e000      0x2000         0x1f9e000       W- C+ V+ (global) 
0x1fa0000      0x2000         0x1fa0000       W+ C+ V+ (global) 
0x1fa2000      0x2000         0x1fa2000       W- C+ V+ (global) 
0x1fa4000      0x6000         0x1fa4000       W+ C+ V+ (global) 
0x1faa000      0x2000         0x1faa000       W- C+ V+ (global) 
0x1fac000      0xa000         0x1fac000       W+ C+ V+ (global) 
0x1fb6000      0x2000         0x1fb6000       W- C+ V+ (global) 
0x1fb8000      0x36000        0x1fb8000       W+ C+ V+ (global) 
0x1fee000      0x2000         0x1fee000       W- C+ V+ (global) 
0x1ff0000      0x2000         0x1ff0000       W+ C+ V+ (global) 
0x1ff2000      0x2000         0x1ff2000       W- C+ V+ (global) 
0x1ff4000      0x2000         0x1ff4000       W+ C+ V+ (global) 
0x1ff6000      0x2000         0x1ff6000       W- C+ V+ (global) 
0x1ff8000      0x2000         0x1ff8000       W+ C+ V+ (global) 
0x1ffa000      0x2000         0x1ffa000       W- C+ V+ (global) 
0x1ffc000      0x4000         0x1ffc000       W+ C+ V+ (global) 
0x2000000      0x6000         0x1f96000       W+ C+ V+  
0xff800000     0x400000       0xff800000      W- C- V+ (global) 
0xffe00000     0x20000        0xffe00000      W+ C+ V+ (global) 
0xfff00000     0xf0000        0xfff00000      W+ C- V+ (global) 

12.5.6   Precautions

Memory that is marked as global cannot be remapped using vmMap( ). To add to global virtual memory, use vmGlobalMap( ). For further information on adding global virtual memory, see 12.5.2 Private Virtual Memory.

Performances of MMUs vary across architectures; in fact, some architectures may cause the system to become non-deterministic. For additional information, see the architecture-specific documentation for your hardware.


1:  This routine is not built in to the Tornado shell. To use it from the Tornado shell, you must define INCLUDE_MMU_FULL_SHOW in your VxWorks configuration; see the Tornado User's Guide: Projects. When invoked this routine's output is sent to the standard output device.