MMU在VxWorks中的實現……摘抄

MMU在VxWorks中的實現
1.內存管理單元MMU
VxWorks提供兩級虛內存支持:與VxWorks捆綁在一起的基本級和需要可選產品VxVMI的完全級。

1.1指令和數據MMU
PowerPC MMU允許指令和數據MMU被分別允許或禁止。在SELECT_MMU下的屬性窗口的參數表中的參數USER_I_MMU_ENABLE和 USER_D_MMU_ENABLE缺省是被允許的。爲了允許/禁止一個或兩個MMU,選擇合適的參數並設置/刪除TRUE。

1.2 60X內存映射
PowerPC 603和604的MMU兩種模式的內存映射。第一種是BAT模式,它允許在大小從128KB到256MB的內存塊映射進一個BAT寄存器。第二種是段模式,它可以將內存映射爲4KB的頁。Tornado支持這兩種內存模式。

1.2.1 603/604的塊地址變換模式
一個BAT寄存器的大小是兩個32位的值。對於PowerPC 603和604,有八個BAT寄存器實現:四個用於指令MMU,四個用於數據MMU。

在sysLib.c中定義的sysBatDesc[]處理BAT寄存器配置。寄存器由MMU庫中的初始化軟件設置。缺省這些寄存器被清零。

用於填充數組sysBatDesc[]的所有配置常量在適合於PowerPC 603和604的目錄installDir/target/h/arch/ppc/mmu603Lib.h中被定義。

1.2.2 603/604的段模式
這種模式指定每一內存頁的配置。整個物理內存由sysLib.c中定義的數據結構數組sysPhysMemDesc[]描敘。這個數組由每一頁或每一組頁的配置常量組成。所有的配置常量在表7-1中定義。虛內存接口對PowerPC虛內存頁是有用的。

使用在表7-1中列出的用於每一頁或每一組頁的常量VM_STATE_CACHEABLE來設置cache爲copy-back模式。

除VM_STATE_CACHEABLE之外,還支持以下常量:

VM_STATE_CACHEABLE_WRITETHROUGH
VM_STATE_MEM_COHERENCY
VM_STATE_MEM_COHERENCY_NOT
VM_STATE_GUARDED
VM_STATE_GUARDED_NOT
第一個常量設置頁描敘符cache模式域爲可cache的write-through模式。Cache的一致性和保護模式由其他常量控制。

頁表大小依賴被映射的總的內存。被映射的內存越大,頁表越大。在MMU庫初始化期間,被映射的內存的總大小被計算,這允許動態決定頁表大小。下表顯示待映射的內存的總數和頁表大小之間的對應關係。

表 9-4: 待映射的內存的總數和頁表大小之間的對應關係

8 MB or less 64 KB
16 MB 128 KB
32 MB 56 KB
64 MB 512 KB
128 MB 1 MB
256 MB 2 MB
512 MB 4 MB
1 GB 8 MB
2 GB 16 MB
4 GB 32 MB
--------------------------------------------------------------------------------


2.虛擬內存(包括VxVMI選項)
對於帶有MMU的板子,VxWorks提供虛擬內存的支持。捆綁虛擬內存支持提供標記不可cache的緩衝區的能力。這對內存在處理器間共享或發生DMA傳送的多處理器環境是有用的。關於捆綁虛擬內存支持的信息,參考第三節:虛擬內存接口和vmBaseLib和cacheLib的引用入口(庫函數)。

非捆綁虛擬內存支持可用作可選的組件VxVMI 。VxVMI 提供了設置文本段text和中斷向量表爲只讀的能力,並且包括一組用於開發人員管理他們自己的虛擬內存上下文的子程序。關於VxVMI 的信息,參考第三節:虛擬內存接口和vmLib的引用入口(庫函數)。


3.虛擬內存接口
3.1介紹
VxWorks 提供兩級虛內存支持:基本級被與VxWorks捆綁在一起並且提供基於每一頁的cache。完全級是非捆綁的,並且需要可選組件VxVMI。VxVMI提供文本段text和VxWorks中斷向量表的寫保護,並且提供一種體系結構無關的接口給CPU的內存管理單元MMU。關於怎樣安裝VxVMI的信息,參考Tornado入門(Tornado Getting Started)。

3.2基本虛內存支持
對於帶有MMU的系統。 VxWorks允許你通過設置相關緩衝區不可cache來更有效的執行DMA及處理器間通信。當其他處理器或DMA設備正訪問同一內存位置時,確保數據沒有進行局部的緩衝是必要的。如果沒有能力將內存的各部分設置爲不可cache的,那麼cache必須從全局上被關閉(導致性能下降)或緩衝區必須被手工地刷新/使無效。

通過在項目工具(project facility)VxWorks視圖中選擇INCLUDE_MMU_BASIC包含基本虛內存支持,參考3.3節:虛內存配製;也可以用 cacheDmaMalloc( )分配不可cache的緩衝區,參考cacheLib 的引用入口(庫函數)。

3.3虛內存配置
以下討論的配置適用於捆綁和非捆綁的虛內存支持。

在項目工具(project facility)中定義表7-1中的常量來反映你的系統配置。

表7-1: MMU配置常量

--------------------------------------------------------------------------------
常量描敘
--------------------------------------------------------------------------------
INCLUDE_MMU_BASIC 不帶VxVMI選項的基本MMU支持。
INCLUDE_MMU_FULL 帶VxVMI選項的完全MMU支持。
INCLUDE_PROTECT_TEXT 文本段保護(要求完全的MMU支持)。
INCLUDE_PROTECT_VEC_TABLE 中斷向量表保護(要求完全的MMU支持)。
--------------------------------------------------------------------------------

對於你的處理器,合適的缺省頁大小(4 KB或8KB)由你的BSP的VM_PAGE_SIZE定義。如果你因爲某種原因必須改變這個值,重定義config.h中的VM_PAGE_SIZE。參考VxWorks程序員指南第八章配置和編譯。

爲設置內存爲不可cache,必須有一種虛-到-物理的映射。在vmLib.h中的數據結構PHYS_MEM_DESC定義用於映射物理內存的參數。每塊板的內存映射用sysPhysMemDesc(被聲明爲一個PHYS_MEM_DESC的數組)在sysLib.c中定義。除了定義內存頁的初始狀態之外, sysPhysMemDesc還定義用於映射虛-到-物理內存的虛地址。

修改sysPhysMemDesc以反映你的系統配置。比如,你可能需要增加沒有包含在結構數組sysPhysMemDesc中的處理器間通信緩衝區的地址。

不包含在結構數組中的I/O設備和內存必須被映射和設置爲不可cache。通常, devices and memory not already included in the structure must also be mapped and made noncacheable. In general, 板外內存區域被指定爲不可cache。參考VxWorks網絡程序員指南:數據連路層網絡組件。

警告:在 sysPhysMemDesc中定義的內存區,必須是頁對齊的,並且必須跨越完整的頁。換句話說,結構PHYS_MEM_DESC 的最初三個域都必須恰好是VM_PAGE_SIZE 的倍數。如果指定的sysPhysMemDesc的元素不是頁對齊的,則在VxWorks初始化期間將導致崩潰。

以下例子配置由使用共享內存的網絡的多個CPU 組成。一塊單獨的內存板被用於這個共享內存池。因爲這塊內存不總是被映射,對於所有在網絡上的板子,它必須被增加到sysPhysMemDesc中。內存起始於0x4000000,並且必須被設置爲不可cache。

/* 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
}

3.4通常的用法
這一節描敘VxVMI的通常用法和用於寫保護文本段和中斷向量表的配置。

VxVMI用MMU來保護內存區以免被重寫,這由內存的寫保護頁完成。並不是所有的目標硬件支持寫保護。對於大多體系結構,頁大小是8K。嘗試寫一塊被寫保護的內存位置會導致一個總線出錯。

當VxWorks被裝入是時,所有text段是寫保護的。其他用ld()裝入的目標模塊的text段被自動標記爲只讀的。當目標模塊被裝入時,被寫保護的內存按頁大小遞增被分配。沒有其他的步驟對於寫保護應用程序代碼是必須的。

在系統初始化期間,VxWorks寫保護中斷向量表。修改中斷向量表的唯一辦法是使用程序intConnect( ),在整個調用期間intConnect( )寫允許中斷向量表。

爲包含寫保護,在項目工具VxWorks視圖中選擇如下:

INCLUDE_MMU_FULL
INCLUDE_PROTECT_TEXT
INCLUDE_PROTECT_VEC_TABLE

3.5使用可編程的MMU
本章描敘了爲了使用vmLib中的低級程序處理(manipulate)可編程的MMU所提供的工具(facility)。你可以設置數據爲任務或代碼段的私有數據,設置內存爲不可cahe,設置內存的各部分爲寫保護的。用於實現虛內存的基本結構是虛內存上下文(VMC)。

對於VxVMI程序的彙總,參考vmLib的引用入口(庫函數)。

3.5.1虛內存上下文(VMC)
虛內存上下文 (VM_CONTEXT, 在vmLib中定義)由一張轉換表和其他用於映射虛地址到實地址的信息組成。多個虛地址上下文可以被創建和隨意的被換入/換出。

Ø 全局虛內存

一些系統對象,諸如text段和信號量,必須是對所有在系統中的任務是可訪問的,不管虛內存上下文是否是當前的。這些對象依靠全局虛內存被設置爲可訪問的。全局虛內存通過映射所有系統內的物理內存到虛內存空間中的相同地址被創建(這個映射被定義在sysPhysMemDesc中)。在缺省系統配置中,這最先在物理內存和全局虛內存之間給出一對一的關係。比如,虛地址0x5000映射到實地址0x5000。在某些體系結構中,可能使用 sysPhysMemDesc 來建立虛擬內存,以便虛到實地址的映射是一對一的。

全局虛內存可以根據所有虛內存上下文訪問。對一個虛內存上下文中的全局映象所做的修改會出現在所有虛內存上下文中。在虛內存上下文被創建之前,用vmGlobalMap()增加所有全局內存。在虛內存上下文被創建之後增加的全局內存可能對已存在的上下文是不可用的。

Ø 初始化

全局虛內存被從usrRoot 調用的usrMmuInit()中的vmGlobalMapInit()初始化。程序usrMmuInit()在 installDir/target/src/config/usrMmuInit.c中,並且用sysPhysMemDesc創建全局虛內存,接着它創建一個缺省虛內存上下文,並設置該缺省上下文爲當前的。它也可以隨時隨地使能MMU。

Ø 頁狀態

每一虛內存頁(通常是8K)有一種與之關聯的狀態。一頁可以是有效/的無效的,可寫的/不可寫的,或可cahe/不可cahe。對於相關的常量請看錶7-2。

表7-2: 狀態標誌

--------------------------------------------------------------------------------
常量描敘
--------------------------------------------------------------------------------
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
--------------------------------------------------------------------------------

l 有效性

有效狀態指示虛到實轉換是正確的。當轉換表被初始化時,全局虛內存被標記爲有效的。所有其他虛內存被初始化爲無效的。

l 可寫性

通過設置狀態爲不可寫,頁可以被設置爲只讀。這被VxWorks用於寫保護所有text段。

l 可cache

內存頁的cache可以通過設置狀態標誌爲不可cache被禁止。這對處理器間共享的內存(包括DMA設備)是有用的。
可用程序vmStateSet()改變一頁的狀態。除了指定狀態標誌外,一個狀態屏蔽必須描敘哪一標誌需要被改變。在vmLib.h中指定的其他體系結構相關的狀態請看錶7-3。

表7-3: 狀態屏蔽

--------------------------------------------------------------------------------
常量描敘
--------------------------------------------------------------------------------
VM_STATE_MASK_VALID Modify valid flag
VM_STATE_MASK_WRITABLE Modify write flag
VM_STATE_MASK_CACHEABLE Modify cache flag
--------------------------------------------------------------------------------

3.5.2私有虛內存
私有虛內存可以通過創建一個新的虛內存上下文。這對於通過使數據對於其他任務不可訪問或通過限制對特定程序的訪問來保護數據是有用的。虛內存上下文不會被自動地爲任務創建,但可以被創建並按應用程序特定的方式被換入和換出。

在系統初始化時,一個缺省上下文被創建。所有任務使用這個缺省上下文。爲了創建私有虛內存,一個任務必須用vmContextCreate ()創建一個新的虛內存上下文,並設置它爲當前的。所有虛內存上下文共享在系統初始化時創建的全局映象。參考圖7-1。在當前虛內存上下文中(包括全局虛內存)僅僅有效的虛內存被訪問。在其他虛內存上下文中定義的虛內存不可訪問。爲設置其他內存上下文爲當前的,使用vmCurrentSet()。

圖7-1: 虛內存的全局映像



爲創建一個新的虛到實的映像,使用vmMap();物理和虛地址都必須被預先決定。物理內存(它必須按頁對齊)可以使用valloc ()獲得。決定虛地址最容易的辦法是使用vmGlobalInfoGet()來查找不是一個全局映像的虛頁。關於這種方案,如果多個映像被要求,一個任務必須明確它自己的私有虛內存頁以確保它不映射同一非全局地址兩次。

當物理頁被映射進虛空間的新區域時,該物理頁可從兩個不同的虛地址(一個被稱爲別名的條件)訪問:最近映射的虛地址和以前的虛地址等價於全局虛內存中的一個物理地址。對於某些體系結構,這可能導致問題,因爲這個 cache對於同一內存位置可能保持兩個不同的值。爲避免這種情況,可以用vmStateSet ()使在全局虛內存中的虛擬頁無效。這也確保僅僅當包含新映像的虛內存上下文是當前的時,這些數據纔可以訪問。

圖7-2描述兩個私有虛內存上下文。新上下文(pvmc2)映射虛地址0x6000000到物理地址0x10000。爲了避免從這個虛上下文的外界(pvmc1)訪問這個地址,相應的物理地址(0x10000)必須被設置爲無效的。如果使用地址0x10000來訪問這塊內存,一個總線出錯發生,因爲這個地址現在是無效的。

圖7-2: 映射私有虛內存



事例7-1: 私有虛內存上下文
在以下代碼事例中,私有虛內存上下文被用於從一個任務的私有內存區分配內存。程序contextSetup()創建一塊私有虛內存上下文,它在一個上下文切換期間被設置爲當前的。該虛內存上下文被保存在這個任務的TCB的域spare1中。切換異常分支(hook)被用於保存舊的上下文和安裝該任務的私有上下文。注意:切換異常分支(hook)的使用增加了上下文切換的時間。一塊用戶定義的內存區被使用私有虛內存上下文創建。該內存區ID被保存於該任務TCB的域spare2中。任何沒有私有虛內存上下文的任務必須調用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));
}

3.5.3非cache的內存
不支持總線動態監視的體系結構必須禁止用於處理器之間通信(或通過DMA設備)的內存cache。如果多處理器讀取和寫入一內存位置,你必須保證當CPU訪問數據時,它正在使用最新的數據。如果cache被用於一個或多個CPU的系統中,在CPU的一個數據cache中可能有一個該數據的本地備份。在圖7- 3的事例中,一個有多個CPU的系統共享數據,並且在系統上的一個CPU(CPU 0)高速緩存(cache)該共享數據。在CPU 0上的一個任務讀數據[1],並且接着修改值[2];然而,當在另一個CPU(CPU 1)上的一個任務訪問它[3]時,該新值可能還在cache中並且沒有更新到內存。因此由CPU 1上的任務使用的值是舊值,並且沒有反映由CPU 0上的任務所做的修改;那個值還在CPU 0的數據cache[2]中。

圖7-3: 與數據cache相關的(with Data Caching)可能的問題的事例



爲了禁止基於頁的高速緩存(caching),使用vmStateSet();比如:

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

爲分配不可cache的內存,參看cacheDmaMalloc()的引用入口。

3.5.4不可寫的內存
內存可以被標記爲不可寫的。內存區可以使用vmStateSet ()被寫保護來避免無意中做的訪問。

這樣做的一種用處是將數據模塊的修改限制到一個具體的程序。如果一個數據模塊是全局的但只讀,任務可以讀該模塊但不能修改它。任何必須修改這個模塊的任務必須調用相關的程序。在該程序內,該數據在整個程序調用期間被修改爲可寫的,這塊內存被設置爲VM_STATE_WRITABLE_NOT 。

事例7-2: 不可寫內存
在這段代碼事例中,爲了修改由pData所指向數據結構,一個任務必須調用dataModify()。這個程序使內存可寫,修改數據,並且設置內存返回到不可寫。如果一個任務試圖讀該內存,它是成功的;然而,如果它試圖在dataModify()之外修改數據,那麼一個總線出錯就會發生。


--------------------------------------------------------------------------------

/* 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);
}

3.5.5疑難解答
如果INCLUDE_MMU_FULL_SHOW被包含在項目工具VxWorks視圖中,你可以使用vmContextShow()來在標準輸出設備上顯示一個虛內存上下文。在以下的事例中,當前虛內存上下文被顯示。在0x0和0x59fff之間的虛地址是寫保護的;從0xff800000到 0xffbfffff是不可cache的;並且從0x2000000到0x2005fff是私有的。所有有效的項被列出並被用一個V+標記,無效的項沒有被列出。

-> vmContextShow 0
value = 0 = 0x0
這個輸出被送到標準輸出設備,如下所示:

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)

3.5.6預防方法
被標記爲全局的內存不能使用vmMap ()被重新映射。爲增加到全局虛內存中,使用vmGlobalMap ()。關於增加全局虛內存的更多信息,參看章節3.52:私有虛內存。

在不同體系結構中,MMU的性能各不相同。實際上,某些體系結構可能導致系統變得不確定。更多的信息,參看適合你的硬件的體系結構特定的文檔。


1: 這個程序(vmContextShow())沒有被編譯進Tornado shell。爲了從Tornado shell中使用它,你必須在VxWorks的配置文件中定義INCLUDE_MMU_FULL_SHOW。參看Tornado用戶指南:項目。當調用這個程序時,它的輸出被送到標準輸出設備。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章