1. gzyueqian
      13352868059
      首頁 > 新聞中心 > > 正文

      RTOS設備驅動向嵌人式Linux的移植

      更新時間: 2007-09-06 13:11:26來源: 粵嵌教育瀏覽量:1287

        Linux暴風雨般占領了嵌入式系統市場。分析家指出,大約有1/3到1/2的32/64位新的嵌入式系統設計采用了Linux。嵌入式 Linux 已經在很多應用領域顯示出優勢,比如SOHO家庭網絡和成像/多功能外設。在(NAS/SAN)存儲,家庭數字娛樂(HDTV/PVR/DVR/STB),和手持設備/無線設備,特別是數字移動電話更獲得大幅度發展。

        嵌入式Linux新應用不會憑空從開發者的頭腦中冒出來,大部分項目都是由成千上萬行,甚至數百萬行的代碼組成。成千上百的嵌入式項目已經成功地把現有的其它平臺的代碼移植到Linux下,比如Wind River VxWorks 和 pSOS, VRTX, Nucleus 和其它RTOS。這些移植工作有著重要的價值和現實意義。

        到目前為止,大多數關于移植已有的RTOS應用到嵌入式Linux的文獻,關注RTOS 接口(API)、任務、調度模式以及如何把他們映射到相應得用戶空間去。同樣重要的是,在I/O調用密集的嵌入式程序中怎么樣把RTOS的硬件接口代碼移植到更加規范的Linux設備驅動程序中去。

        本文把概述幾種常用的經常出現于現有嵌入式應用中的內存映射I/O方法。它們涵蓋的范圍從對中斷服務例程的特殊使用及用戶線程對硬件訪問到出現于有些ROTS中的半規范化驅動程序模型。這對于移植RTOS 代碼到規范化的Linux設備啟動程序具有一定啟發作用,并且介紹了一些移植方法。特別地,本文會重點討論RTOS和Linux中的內存映射,基于I/O調度隊列的移植,把RTOS I/O重定義到Linux下的驅動程序和守護進程里。

        RTOS I/O 概念

        “不規范”是描述大多數RTOS系統I/O的詞語。多數RTOS是針對較早的無MMU的CPU而設計,所以忽略了內存管理部分,即使當MMU問世后也是這樣:不區分物理地址和邏輯地址。大多數 RTOS還全部運行在特權模式,雖然表面上看來是增強了性能。全部的RTOS 應用和系統代碼都能夠訪問整個地址空間、內存映射過的設備、以及其他I/O操作。這樣,即使存在差別,也是很難把RTOS應用程序代碼同驅動程序代碼區分開來。

        不規范的結構導致了I/O實現的特殊性。在很多情況下,缺乏設備驅動程序模型的認同。根據這種無層次的特性,回顧一下基于RTOS軟件中使用的一些重要概念和習慣用法非常有指導意義。

        內嵌的內存訪問

        上個世紀八十年代中期商業化的RTOS產品中,多數嵌入式軟件都有一個對執行時間有嚴格需求的,采用I/O查詢和中斷服務例程的大循環。開發人員在項目采用RTOS和執行程序,主要為了加強并行性和多任務同步,繞開其它有礙實現該目標的程序結構。這樣,即使RTOS提供了I/O 調用形式化方法,嵌入式程序員繼續使用直接的I/O操作:  

        #define DATA_REGISTER 0xF00000F5
        char getchar(void) {
        return (*((char *) DATA_REGISTER)); /* read from port */
        }
        void putchar(char c) {
        *((char *) DATA_REGISTER) = c; /* write to port */
        }
         
        多數受過訓練的開發者常會把這樣的直接I/O代碼從硬件代碼中分離開來。但是我還是經??吹街T如此類的I/O調用代碼。

        當開始使用直接內存映射I/O的時候,新接觸Linux的嵌入式開發人員總是想把這類代碼移到用戶空間,通過mmap()調用來替代定義寄存器地址的#define 語句。這種處理方法對于一些原型是可以的,但不能支持中斷處理,限制了實時響應,特別不安全,不適合商業化產品的發布。

        RTOS 中斷服務例程

        在 Linux里, 中斷服務屬于內核層; 在一個 RTOS里, 中斷服務例程代碼沒有特殊規定且常與應用程序代碼沒什么區別(不外乎返回序列異同)。很多 RTOS提供系統調用或者宏來讓代碼自己檢測它自己的切換狀態(比如 Wind River VxWorks的 intContext())。中斷服務例程通常也使用標準的庫函數,隨之而來也有可重入性和移植性等問題。

        大多數RTOS支持注冊中斷服務例程代碼、中斷判斷和中斷服務調用。一些簡單的嵌入式程序,僅僅支持在硬件矢量表里插入中斷服務例程的起始地址。

        如果試圖直接在用戶程序空間執行讀和寫操作,你不得不把Linux中斷服務例程放入內核程序空間。

        RTOS I/O 子系統

        大多數RTOS會提供一個定制的標準C運行庫 (比如 pSOS 的pREPC),或者修改編譯器提供商的C庫(libc)或修改glibc。在盡量小化情況下,多數的 RTOS支持標準C的I/O子集(open/close/read/write/ioctl). 大多數情況下,這些調用和從衍生出來的調用轉化為基本I/O簡單封裝.有趣的是,因為大多數的 RTOS不支持文件系統,這些平臺不提供針對flash和其他存儲介質的文件存儲,常采用完全不同的代碼實現或者其他應用程序接口(API) (比如 pSOS 的pHILE).

        Wind River VxWorks 在這方面比其它RTOS做得好些,它提供功能豐富的I/O子集,有效廣泛集成網絡接口及網絡媒體。

        延時處理

        很多RTOS也支持一種叫”下半部 “("bottom half" )的機制, 把I/O處理放到可中斷或者可搶占切換上下文中執行。其他RTOS提供類似機制比如中斷嵌套來獲得同樣的效果.

        典型RTOS應用的I/O架構

        下面描述一個典型的I/O圖解(僅輸入)和它向主應用程序傳遞數據的路徑,處理過程如下:

        · 一個硬件中斷觸發一個中斷服務例程執行。
        · 中斷服務例程做基本處理,完成本地輸入操作,或者讓RTOS調度延時處理。在一些情況下,延時處理過程由Linux里的用戶進程來處理,在這里就是普通的RTOS任務。
        · 當獲取到數據(中斷服務例程或者延時切換),準備好的數據被放進隊列(RTOS中斷服務例程能夠訪問應用程序隊列通過應用程序接口(API)和其它進程間通信 ( IPC),請看下面的API表)。
        · 一個或者多個應用任務從隊列讀消息取出數據

        傳統的RTOS和Linux的典型I/O比較

        輸出常常由類似的機制來完成-代替write()或者相似的系統調用,一個或者多個RTOS任務,把數據放進隊列.隊列中的數據由以下幾種過程取出:一個I/O程序或者響應“準備好發送”中斷的中斷服務例程,一個系統時鐘,或者其它阻塞在取數據隊列中的應用任務,然后執行I/O操作(可以是輪詢,也可以是通過 DMA).

        把RTOS I/O 映射到 Linux中

        上面描述的基于隊列的生產者/消費者I/O模型,僅僅是傳統多種設計中所采用的特別方法的一種。讓我們繼續用這個直接的例子,來討論幾種在嵌入式Linux下的實現方法:

        大規模移植到用戶空間

        對于只是初步了解Linux設備驅動設計,或者沒有經驗的開發者,可能把大多數這種基于隊列的程序原封不動地移植到用戶空間。在這種驅動程序映射中,內存映射通過函數mmap()提供的指針可以在用戶空間操作物理I/O接口。

        #include <sys/mman.h>
        #define REG_SIZE 0x4 /* device register size */
        #define REG_OFFSET 0xFA400000
        /* physical address of device */
        void *mem_ptr; /* de-reference for memory-mapped access */
        int fd;
        fd=open("/dev/mem",O_RDWR); /* open physical memory (must be root) */
        mem_ptr = mmap((void *)0x0, REG_AREA_SIZE, PROT_READ+PROT_WRITE,
        MAP_SHARED, fd, REG_OFFSET);
        /* actual call to mmap() */
       
        一個進程下的用戶線程運行類似RTOS的中斷服務例程或延時任務一樣的操作,然后使用SVR4進程間通信函數msgsnd()把消息放進隊列,等待被另一個本地線程或者另一個進程利用函數msgrcv()獲取。

        這種快速缺乏技巧的處理方法是一種較好的原型,但同時給代碼模型建立帶來了巨大的挑戰。首先重要的是要在用戶空間掃描中斷.象DOSEMU項目提供基于信號 的I/O中斷方式,但用戶空間的中斷處理過程非常慢(一般毫秒級中斷延時相較內核中斷服務例程數十微秒中斷延時).進一步講,即使采用可搶占Linux內核,和實時調度策略,用戶空間的切換調度不能保證I/O 線程的及時得到執行。

        為使用Linux驅動程序重新設計

        較可取的是應該至少寫一個簡單Linux驅動程序在內核層處理中斷。一個基本的字符或者塊驅動程序,能夠在“上半部”直接處理中斷數據,或者延時到任務隊列或2.6內核新工作隊列中作后續處理。一個或者多個應用線程/進程能夠打開設備然后執行同步讀操作,正像RTOS用隊列實現同時調用一樣。需注意的是,這種方法需要重寫I/O線程讀取,代替隊列接收操作。

        保留一個RTOS基于隊列的I/O架構

        為了減小移植到嵌入式Linux 后的影響,可以在保留基于隊列的方案,添加額外的線程或者守護進程,在新創建的設備上等待I/O操作.當數據準備好以后,這些線程或者守護進程被喚醒 , 按隊列重排由應用線程或進程讀取的數據。

        移植方法
       
        把RTOS移植到嵌入式Linux 與商業應用程序移植概念上并無區別。當準備好移植的基礎性工作:(創建make/build腳本和工具,編譯器兼容性,指定所用的頭文件等)之后,移植任務面臨的是應用程序的結構和(API)使用問題。 為了便于下面的討論,我們假設“應用”部分(除針對I/O以外的所有代碼)會被從RTOS系統中移植到單獨的一個Linux進程;RTOS任務映射到Linux線程,而任務的進程間通信(IPC)映射到Linux進程和線程相應通訊。 .

        

        映射RTOS任務到Linux基于進程的線程 Process-based Threads

        移植的基本概念容易理解,問題主要出現在細節上。常見的是RTOS中的應用程序接口以及怎么樣把它們保留到linux結構中繼續使用。

        整體分析―重構

        假如項目時間要求不是很緊,并且為了把來項目的可重用和代碼可移植性,你會化時間分析當前RTOS應用程序結構以及如何把他們映射到Linux中去。對于RTOS應用,需要考慮把任務對應一一映射到Linux基于進程的線程中去,或者考慮把RTOS應用重分配到多個Linux進程中去。基于這些考慮,應該重新考慮把RTOS進程間通信(IPC)用合適的進程間或者進程內通訊來替代。

        在驅動程序上,肯定要把不規范的內嵌式RTOS代碼轉化成相應的驅動程序。如果已有的應用程序已經很好劃分,或者使用RTOS I/O應用程序接口,或者分隔在不同的層面,轉化工作把非常容易進行。如果這類I/O代碼分散于整個應用程序中,把面臨巨大工作量。

        基于API的方法

        對于急于擺脫舊RTOS,或者嘗試把原型綜合在一起的開發者, 更傾向于把很多RTOS映射或者轉化為相當Linux API。程序的接口幾乎是透明的(兼容的API,IPC,系統數據類型等)。其余部分可以通過用#define 重新定義和使用宏來解決。剩下的部分需要重新編碼,作為完整抽象層的一部分。

        通過使用仿真庫-很多商業嵌入式Linux都帶有(比如我們公司的針對Wind River VxWorks 和 pSOS的仿真庫),或者使用第三方公司提供的API映射包,比如MapuSoft,能夠使你在移植基于API的程序時有良好的開端。

       

        移植RTOS代碼和API 到Linux的多叉方法

        大多數項目采用混合的方法,映射所有兼容的或者容易轉化的API,重新配置那些對運行速度有要求的部分,重新編寫剩余的部分代碼直到編譯通過和可以運行為止。

        在內核和用戶空間適用的API

        對于需要重新編寫和其他API實現方法,你得重新分配RTOS應用程序和I/O代碼和Linux內核/用戶空間相對應。

        有兩個非常重要的區別:

        · RTOS平等地讓應用程序和I/O代碼能夠訪問任何地址,幾乎可以進行任意操作, Linux則更講究應用級別和權限。
        · 舊的RTOS代碼能夠(至少在鏈接時)“看見”每一個符號和系統的入口點,Linux 用戶代碼是分離的,內核程序和用戶程序完全分開。

        Linux分層權限訪問的結果是,僅內核代碼(驅動程序)能夠訪問物理內存,其它用戶代碼必須有根用戶權限才能訪問。

        一般情況下,用戶空間代碼與Linux內核相隔離,只有當內核的信息出現在/proc/ksyms 時才能被直接“看見”。進一步講,不能直接調用對于內核可見的系統調用,只能通過用戶庫函數調用。Linux這種分隔是有意用來加強穩定性和安全性。

        相反的當寫驅動程序的時,靜態鏈接的驅動程序專屬于整個內核名字空間(不是出口),但是對于基于進程的用戶空間,符號和入口點完全不可見。并且,當驅動程序封裝成可動態加載的模塊時,程序在內核里面通過EXPORT_SYMBOL 宏來使用顯示的接口。

        網絡驅動程序移植

        如上面指出的,字符和塊驅動程序移植到Linux下較為明了。而移植網絡驅動程序則要困難得多。

        Linux伴隨TCP/IP一起成長,而大多數的RTOS 到90年代晚期才把添加網絡支持。這些網絡常常僅支持基本功能,比如只能處理單個會話或者同時只能訪問一個端口,或者只能支持單一網絡媒質的物理接口。在某些情況下網絡結構,在允許多重接口和物理類型連接后,才能實現(比如Wind River VxWorks MUX代碼)。

        糟糕的是,你不得不重寫大部分或者全部的RTOS中現有網絡接口。好消息是,對于Linux網絡重新劃分不是太困難,而且有大量的開源網絡設備驅動例子程序可供參考。

        你的移植任務會是如何用合適的封裝格式和接口代碼組裝下圖表中底部區域:


      Linux 網絡驅動程序框圖

        寫網絡驅動程序不是初學者的事。許多RTOS網絡驅動程序實際上是從GPL的Linux接口演變而來,因此,你也許通過代碼本身可以發現程序易用性。更進一步的,有大量、并且一直在增長的系統集成和咨詢社區以合理的收費幫助嵌入式開發者把他們的應用移植到Linux中去。

        總結

        本文深入分析了把軟件從原有的RTOS移植到Linux時,嵌入式開發者面臨的挑戰和得到的好處。寥寥幾千字對于深入研究許多驅動程序移植的細節來說過于簡單(總線接口的驅動API,地址轉換等),但是現有的眾多開源GPL驅動程序代碼,可以作為移植的文檔參考和模板。本文肯定對你的團隊在移植RTOS到Linux的時候有所幫助,對重新規劃代碼、更好移入嵌入式Linux有所啟發。

      免費預約試聽課

      亚洲另类欧美综合久久图片区_亚洲中文字幕日产无码2020_欧美日本一区二区三区桃色视频_亚洲AⅤ天堂一区二区三区

      
      

      1. 午夜福利免费区久久 | 最新国产Av最新国产在钱 | 人成国产h视频在线观看 | 伊久香蕉在线视频网站 | 亚洲伊人久久成综合人影院 | 人人狠狠久久亚洲区 |