官术网_书友最值得收藏!

2.4 VxWorks內存管理——虛擬地址空間支持

內存管理并非是簡單的使物理內存可被使用。通常說到內存管理,就認為是否使能MMU,更進一步地說,即是否使用虛擬地址。一般CPU都包含MMU硬件單元,但是MMU的使用與否由操作系統決定,當然使用MMU硬件單元是需要做一系列準備工作的,如系統頁表的建立、配置CPU硬件控制寄存器等。雖然存在這些準備工作,這與使用MMU機制之后的優勢相比也是值得的。MMU可以管理物理內存非連續的應用環境,可以對單個頁面控制是否進行Cache(緩存)以及應用權限限制,可以讓一個很大的程序與其他程序一同運行,而非獨占物理內存或者無法運行。

是否使能MMU只是內存管理的一個重要方面,內存管理還包括:操作系統如何安排各組件(內核層次的和應用層次的)在物理內存中的布局;如何提供接口可讓BSP開發人員提供內存映射的關系,因為每個平臺的物理內存地址空間不同,需要根據特定平臺的特殊情況定制映射關系;是否提供某種策略可讓用戶預留一段物理內存以供私用,如專供某個驅動存儲信息等。這些都可以看做是內存管理的一部分。本節將介紹涉及內存使用以及內存管理的各個方面。

由于各處理器下內存管理的方式有些差別(如有些處理器包含MMU硬件支持,有些則不然),故下文討論中我們以ARM處理器為例進行介紹。ARM處理器內部包含MMU硬件單元,MMU的使能通過CP15控制寄存器的相關位來進行控制。系統上電執行的初始階段,MMU是禁止使用的,如果使用bootrom,那么在bootrom運行的整個過程中,MMU都是禁止的,一般只在VxWorks操作系統中才使能MMU。使用MMU之前,必須在內存中創建一張頁表,對于ARM處理器而言,這個頁表分為兩個層次(實際上,為了節省內存,基本上所有的操作系統都是通過分層次的方式建立頁表的),第一層次稱為頁目錄表,第二層次稱為頁表。

在MMU使能的情況下,系統使用兩套地址:虛擬地址和物理地址。虛擬地址是指令中使用的地址,這個地址必須經過MMU單元的轉換方能輸出到CPU外部總線上訪問實際RAM;物理地址即實際出現在地址總線上的地址,這個地址直接輸入到RAM的地址管腳,用以尋址RAM中的某個存儲單元。MMU單元的轉換必須要有頁表的配合方能完成,這個頁表一般由操作系統進行創建。具體到VxWorks下,為了適應各種平臺的地址映射關系,內核提供一個內核變量供BSP開發人員使用,用以表示該平臺上的地址映射關系,這個內核變量在sysLib.c文件中被初始化,變量名為sysPhysMemDesc,這個變量的初始化示例如下。

        PHYS_MEM_DESC sysPhysMemDesc [] =
        {
            /* adrs and length parameters must be page-aligned (multiples of 0x1000) */
            /* iram 16K */
            {
                  (void *)ARM_I_RAM_BASE,   /* virtual address */
                  (void *)ARM_I_RAM_BASE,   /* physical address */
                  ROUND_UP(ARM_I_RAM_SIZE, PAGE_SIZE), /* length, then initial state: */
                  VM_STATE_MASK_VALID | VM_STATE_MASK_WRITABLE |
                            VM_STATE_MASK_CACHEABLE,
                  VM_STATE_VALID| VM_STATE_WRITABLE | VM_STATE_CACHEABLE
            },
            …
            /* DDRAM */
            {
                  (void *) ARM_DDR2_BASE,   /* virtual address */
                  (void *) ARM_DDR2_BASE,   /* physical address */
                  ROUND_UP (ARM_DDR2_SIZE, PAGE_SIZE), /* length, then initial state: */
                  VM_STATE_MASK_VALID | VM_STATE_MASK_WRITABLE |
                            VM_STATE_MASK_CACHEABLE,
                  VM_STATE_VALID| VM_STATE_WRITABLE | VM_STATE_CACHEABLE
            }
        };

更確切地說,sysPhysMemDesc是一個結構數組,數組中每個元素都是一個PHYS_MEM_DESC結構,這個結構定義在h/vmLib.h文件中,定義如下:

        typedef struct phys_mem_desc
        {
            void *virtualAddr;
            void *physicalAddr;
            UINT len;
            UINT initialStateMask;      /* mask parameter to vmStateSet */
            UINT initialState;          /* state parameter to vmStateSet */
        } PHYS_MEM_DESC;

VxWorks內核初始化過程將依據sysPhysMemDesc變量構建系統頁表。對于一般通用操作系統(如Linux),其頁表的構建是動態的,即在操作系統初始化過程中,只對操作系統本身代碼已使用的內存空間進行頁表項的構建,而其他內存空間用做動態內存在以后使用的過程中不斷地對系統頁表項進行添加。

更進一步地說,每個用戶進程都有自己的一份頁表,這份頁表中對于內核代碼部分的映射都是相同的,只在自己的地址空間所對應的頁表項上映射到的物理頁表才有差別。在進程進行調度時,系統頁表的更換作為調度的一部分完成。所以,在Linux下所有的用戶進程可以使用完全相同的虛擬地址0x80000000,程序運行前都被鏈接到這個相同的虛擬地址處。只是在映射到物理內存時,才分配到不同的物理地址處,由于內核代碼在操作系統初始化過程中已被復制到固定的物理內存中,故所有的用戶進程對內核代碼的映射都是一致的,且提供給用戶的內核代碼一般都是可重入的(reenterable),所以各進程對于內核代碼的調用都不存在問題。

注意

通用操作系統中一個可運行的用戶程序一般都是通過鏈接的,如Linux下的.out文件、Windows下的.exe文件,這些文件中的代碼都具有實際運行時使用的絕對虛擬地址。

VxWorks下使用MMU時雖然也存在頁表表示的映射關系,但是其工作機制卻從根本上不同于通用操作系統。首先,VxWorks運行的所有任務(進程)都使用相同的頁表,換句話說,VxWorks操作系統中只有一張頁表,所有的任務都使用這張頁表;其次,也是非常關鍵的一點,VxWorks運行的文件都是未鏈接的,在程序運行之前,都需通過loadModule函數的即時動態鏈接。

Tornado環境下編譯的.out文件實際上也是一個未鏈接文件,或者更準確地說,是一個可鏈接的文件,如此不同的程序經過loadModule函數被動態鏈接到不同的物理地址處,才將各個任務的地址空間區分開來而不造成沖突。如此就引起另一個問題,即VxWorks的內存分配都是針對物理內存直接進行的,而在使能MMU的情況下,訪問內存使用的是虛擬地址,這就表示物理地址被直接用做了虛擬地址。這個關系決定了系統頁表中虛擬地址到物理地址的映射必須是相同的,即虛擬地址必須等于物理地址,否則整個系統將無法正常工作。所以,在VxWorks下使用MMU和使用系統頁表并非是實現通常操作系統下靈活的映射機制,而更多的是提供面向頁的Cache機制和權限控制機制。

實際上,VxWorks下的地址映射關系是非常固定的,在系統初始化過程中,這個系統頁表就被完全建立,在建立完成后,基本不存在改變系統頁表項的操作(雖然VxWorks支持動態添加頁表項),在這一點上完全不同于通用操作系統。

我們可以對VxWorks下內存映射機制進行總結。

① VxWorks下整個系統只有一張頁表,所有的任務都在使用這張頁表。

② VxWorks系統頁表在初始化過程中就被完全創建,其后基本不會改變該頁表,雖然VxWorks支持動態改變頁表項。這同時也表示BSP開發任務必須仔細編寫sysPhysMemDesc變量定義,對其后操作系統程序以及所有要運行的用戶程序需要訪問的地址都必須進行映射,包括主內存、所有外設的寄存器地址區域。

③ 在頁表中,所有的物理內存都被進行了映射,但并不表示對應的物理內存已被使用,內存的使用與否由VxWorks內核另外的機制表示。

④ VxWorks下雖然使用MMU和頁表,但是使用的虛擬地址實際上就是物理地址,這是由VxWorks的內存分配方式決定的。VxWorks下分配內存函數返回的地址直接就是物理內存地址,這個返回的物理內存地址被直接用于訪問物理內存,即物理地址被直接用做虛擬地址,這就從根本上決定了頁表項中的內容必須是虛擬地址等于物理地址。

⑤ VxWorks所有程序的運行都要經過VxWorks內核的重新動態鏈接操作,這個鏈接由loadModule及其同族函數完成,包括Tornado環境下編譯生成的.out文件也是要經過VxWorks內核的重新鏈接才被執行的,且生成的.out文件本身就是被設計為可被重新鏈接的。

⑥ VxWorks下使用MMU更多的是提供面向頁(一頁一般為4KB)的Cache機制和權限控制機制,而非提供虛擬地址和物理地址之間靈活的映射關系。

內存管理的另一個重要方面是如何安排VxWorks內核以及各種信息在內存中的布局。如圖2-2所示是ARM處理器平臺下物理內存的布局示意圖。注意:不同版本的VxWorks內核內存布局存在差別,圖2-2中所示為VxWorks 5.5內核在ARM系統結構下對應的布局。

圖2-2 內核布局(ARM體系結構)

圖2-2中幾點注意:

① 某些組件的包含與否也會影響內存布局,例如,如果不包含WDB組件,那么圖2-2中WDB內存池將被并入系統內存池。

② “Persistent Mem Reserved”為錯誤探測和報告組件預留的內存空間,這個空間的大小由PM_RESERVED_MEM表示。

③ 異常向量表(Vectors)和異常跳轉指針(Exception Pointers)一般都以絕對地址0為基址。ARM處理器要求系統異常向量表在絕對地址0或者高端地址處創建,ARM處理器內部絕對地址0處集成有IRAM,故一般將異常向量表創建在這個IRAM首端(地址為0)。圖2-2中沒有表示出這一點,而是以LOCAL_MEM_LOCAL_ADRS為基址進行了表示,這一點是不確切的。此時就必須要求LOCAL_MEM_LOCAL_ADRS為0。除此之外,從BootLine開始都是以LOCAL_MEM_LOCAL_ADRS進行偏移是正確的。但如前文所述,這個偏移量的值根據VxWorks內核版本的不同而有所差別,但是從總體順序上是沒有變化的。

④ “initial stack”使用在usrRoot函數執行之前,usrRoot函數執行在任務上下文中,在usrRoot函數之前運行所有的代碼都沒有任務上下文,我們將其類比于中斷上下文,“initial stack”就被這些代碼使用。每個任務都具有自己獨立的棧,故從usrRoot函數開始就在使用任務自身的棧,“initial stack”自此以后將不再被使用。“initial stack”大小在ARM平臺下設置為512B,其棧頂就是RAM_LOW_ADRS,棧底則為(RAM_LOW_ADRS-512),當然這是對于一般“向下增長型(grows down)”棧而言的。

要使VxWorks包含內存管理相關組件,必須在configAll.h或者config.h文件中包含如下宏定義。

● INCLUDE_MMU_GLOBAL_MAP:該宏定義表示根據sysLib.c文件中sysPhysMem-Desc變量定義構建系統頁表。

● INCLUDE_MMU_BASIC:該宏定義表示包含vmBaseLib API,這些API用于對系統頁表的動態管理,如添加一個新的頁表項或刪除一個已有的頁表項或改變某個頁表項的狀態位(如是否使能cache)。

注意

對于5.5版本的VxWorks內核,需要使用INCLUDE_MMU_FULL宏定義來進行MMU的初始化。

VxWorks操作系統初始化過程中,調用usrMmuInit函數完成MMU的配置,包括系統頁表的建立以及相關硬件寄存器的配置以使能MMU。注意:如果映射的內存空間較大,在usrMmuInit函數中將執行較長的時間,內核需要分配內存,創建頁表項。

內存管理是操作系統實現的一個重要方面,其決定了內存的使用效率。而內存管理的實現一般都要涉及MMU機制,不同處理器架構具有不同的MMU硬件單元,雖然從總體上說,都需要一個系統頁表配合硬件MMU單元工作,但是系統頁表的層次結構以及頁表項的定義都不相同,不同處理器都有自己的特殊要求。從BSP移植和開發角度而言,讀者只需要知道要使能MMU,必須首先在內存中創建一個系統頁表,該頁表表達了虛擬地址與物理地址之間的映射關系,VxWorks下這個映射關系由sysLib.c文件中sysPhysMemDesc[]數組表示,BSP開發人員只需要根據特定平臺的地址空間分配來初始化這個數組即可。另外為了包含MMU內核相關組件,如usrMmuInit函數的調用,用戶還必須進行相關宏的聲明,如INCLUDE_MMU_FULL、INCLUDE_MMU_BASIC,具體配置選項,請用戶參考文獻“VxWorks kernel progammer’s guide”。

VxWorks下對MMU機制以及虛擬地址和物理地址關系處理上都比較特殊,其中最為關鍵的一點是VxWorks的系統頁表在初始化的過程中基本上一次性完全創建,其后基本無須進行改變,這就決定了虛擬地址和物理地址之間的映射關系是固定的,且是一一對應的關系,雖然VxWorks內核提供了可動態修改系統頁表項的接口函數,但是很少使用。基于VxWorks對于MMU機制的特殊使用方式,VxWorks下的文件都是可鏈接的文件,需用通過VxWorks自身提供的loadModule及其同族函數進行動態鏈接后方可執行,包括Tornado環境下編譯生成的.out文件也是一個可鏈接文件。1

主站蜘蛛池模板: 涡阳县| 泗洪县| 芦溪县| 嘉义县| 淄博市| 阳谷县| 江永县| 临沭县| 锡林浩特市| 河池市| 马山县| 石景山区| 保亭| 额济纳旗| 醴陵市| 潮州市| 抚顺县| 汤原县| 苏州市| 维西| 云梦县| 托克逊县| 东丽区| 泽州县| 成武县| 云安县| 祁阳县| 舒兰市| 吉隆县| 盐山县| 浦江县| 香格里拉县| 阿合奇县| 彝良县| 张北县| 永春县| 黄龙县| 上饶县| 平昌县| 玉林市| 菏泽市|