歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux綜合 >> Linux資訊 >> Linux文化

OSKit包裝系統驅動程序 第一章


第一章 OSKit概述

1. OSKit簡介

通常情況下,開發一個操作系統是一件非常復雜的事情,操作系統的開發人員不僅要開發那些他們感興趣的部分,還要花費大量的時間去開發一些他們並不感興趣而不得不去開發的部分,如裝入程序、啟動程序、以及一些底層硬件的驅動程序等等。OSKit的開發者們開發它的初衷也正是為了解決這個問題。

OSKit是由美國猶它大學Flux研究小組開發的一套設計操作系統的工具包。它之所以被稱之為一個工具包而不是一個操作系統,是因為它最初的設計意圖就是要為操作系統的開發者們提供一套可重用的模塊,使操作系統的開發者們可以很快的把精力集中於實際的操作系統的問題,如作業控制、進程間通信、文件系統和安全機制等等。

對於很多種情況,OSKit本身就是一個操作系統,它提供了操作系統中所需要的幾乎所有模塊,那麼作為一個操作系統的工具包,它和真正的操作系統的差別又在哪裡呢?按照OSKit的開發人員的話說就是"在我們看來,'操作系統'和'操作系統工具包'之間的分界線是:哪些是操作系統的開發人員真正想寫的,而哪些是他們不得不寫而實際上並不想寫的。"從這一點我們也可以看出,對於不同的操作系統開發人員來說,因為他們感興趣的部分不同,他們所使用的部分自然也就不同。OSKit是一個模塊化的工具包,使用它的時候並不一定要使用它的全部,而可以僅僅去使用其中的一部分。

在這裡,有一點是需要說明一下的,通常情況下,操作系統的源碼是不能依賴於某些函數庫的,因為C語言庫(如GNU C Library)實際上是要依靠操作系統提供的某些功能才能夠正常工作的。OSKit與這些函數庫之間的一點差別就是:OSKit本身在設計時就注意到了這個問題,其中的函數在運行時都沒有對其運行環境作出任何的假設,因此,這些函數是可以在操作系統的代碼中調用的。

OSKit是一個自由軟件,也可以被稱為"開放源代碼"軟件,OSKit的主要部分是在GNU Public License(GPL)下發布的。但因為OSKit中使用了大量的其它操作系統(如Mach、FreeBSD、Linux等)的源代碼,因此OSKit中這些部分則受到它們原有的版權協議的保護。


2. OSKit構成

2.1 結構概述

OSKit從整體上可以分為三個部分,第一部分是接口,第二部分是函數庫,第三部分是部件庫。但實際上,因為這三部分之間相輔相成的關系,在源代碼中它們的劃分並不是十分的清晰,在很多情況下,劃分是非常隨意的。不過,下面我們姑且仍然按照這樣的劃分來描述一下OSKit的整體結構。

2.2 接口

OSKit的接口是面向對象的,它采用了部件對象模型(COM)來定義。COM的基礎是界面(Interfaces),所謂界面,就是一套方法,通過它們,無需知道對象的內部結構就可以訪問直接訪問對象。COM接口與部件及對象的實現無關,完全是獨立的。用C語言是如何實現COM機制的呢?由於本文的重點不在這個方面,因此這裡我只作一個簡單的介紹。

OSKit中的COM接口是一個不透明的struct結構,它的實際大小和內容對於調用者來說都是未知的。它的第一個元素必須是一個指向一個函數表格的指針,這個函數表格中是該COM對象可以使用的方法。實際上,這個函數表格也是一個struct結構,結構中的每一個元素都是一個指向函數的指針。下面是一個很簡單的例子,它定義了OSKit中塊輸入/輸出對象(blkio)的界面。

/* 這是用戶看到的COM接口 */
struct oskit_blkdev
{
  struct oskit_blkdev_ops *ops;
};
typedef struct oskit_blkdev oskit_blkdev_t;

/* 這是函數表,該COM接口所支持的方法 */
struct oskit_blkdev_ops
{
  /* COM-specified IUnknown interface operations */
  OSKIT_COMDEC* (*query)(oskit_blkdev_t *dev,
        const struct oskit_guid *iid,
        void **out_ihandle);
  OSKIT_COMDECL_U (*addref)(oskit_blkdev_t *dev);
  OSKIT_COMDECL_U (*release)(oskit_blkdev_t *dev);

  /* Base fdev device interface operations */
  OSKIT_COMDEC* (*getinfo)(oskit_blkdev_t *fdev,
        oskit_devinfo_t *out_info);
  OSKIT_COMDEC* (*getdriver)(oskit_blkdev_t *fdev,
        oskit_driver_t **out_driver);

  /* Block device interface operations */
  OSKIT_COMDEC(*open)(oskit_blkdev_t *dev, unsigned mode,
        struct oskit_blkio **out_blkio);
};

/* OS Environment中塊設備接口的GUID */
extern const struct oskit_guid oskit_blkdev_iid;
#define OSKIT_BLKDEV_IID OSKIT_GUID(0x4aa7df82, 0x7c74,\
    0x11cf, 0xb5, 0x00, 0x08, 0x00, 0x09, 0x53, 0xad, 0xc2)

/* 以下定義的是較為友好的訪問上述接口的方法 */
#define oskit_blkdev_query(dev, iid, out_ihandle) \
    ((dev)->ops->query((oskit_blkdev_t *)(dev), \
    (iid), (out_ihandle)))
#define oskit_blkdev_addref(dev) \
    ((dev)->ops->addref((oskit_blkdev_t *)(dev)))
#define oskit_blkdev_release(dev) \
    ((dev)->ops->release((oskit_blkdev_t *)(dev)))
#define oskit_blkdev_getinfo(fdev, out_info) \
    ((fdev)->ops->getinfo((oskit_blkdev_t *)(fdev), \
    (out_info)))
#define oskit_blkdev_getdriver(fdev, out_driver) \
    ((fdev)->ops->getdriver((oskit_blkdev_t *)(fdev), \
    (out_driver)))
#define oskit_blkdev_open(dev, mode, out_blkio) \
    ((dev)->ops->open((oskit_blkdev_t *)(dev), (mode), \
    (out_blkio)))

OSKit中定義的接口非常多,本文將要詳細描述的,也正是OSKit中的一套非常重要的接口OS Environment(osenv)。它實際上是系統內核與驅動程序之間的接口,通過OS Environment,系統內核為驅動程序的運行提供了必要的支持。同時,系統也通過驅動程序所提供的COM接口來訪問設備。

2.3 函數庫

OSKit的函數庫為操作系統提供最基本的低級服務。在OSKit的函數庫中,很少使用OSKit的COM接口,而是用普通的C語言的函數實現的。這樣操作系統的設計者只要直接調用這些函數就可以了。OSKit的函數庫在設計上盡量公開,可以讓使用者很容易的看到這些函數的設計細節。

OSKit中的函數庫主要有一下幾個:
liboskit_c:這是一個非常小的C語言庫,它在受限制的OS環境中提供了一些通用的C函數,比如基本的字符串、內存和格式化的輸入、輸出工具等。如果需要更強大的C庫,OSKit中還提供了FreeBSD的C庫liboskit_freebsd_c。
liboskit_kern:這個函數庫中包括建立一個基本的操作系統內核運行環境,為陷入、中斷等提供了缺省的處理程序。這個庫包括了很多在寫核心代碼時非常有用的通用函數,如訪問某個特殊的處理器寄存器的函數,建立並維護頁表,在不同的處理器模式之間轉換(如x86的實模式和保護模式)等。此外它還提供了便於的在開發時使用的源碼級內核調試機制。
liboskit_smp:更多的內 核支持代碼,用於多處理器的系統環境。
liboskit_com:處理COM 接口的工具函數和一套通用的包裝部件。
liboskit_dev:這個庫提供了驅動程序和由其它操作系統引入的部件(如網絡、文件系統)所需要的"glue code"中的函數的缺省實現。在OSKit的文檔中,把這一部分放在了函數中,但通過對OSKit的源代碼的分析,這一部分實際上使用了大量的COM接口。這一部分中的函數的實現是為了使用liboskit_kern函數庫的簡單內核所設計的,當需要精心制作的內核時,目標系統必須要重寫此函數庫中的部分或全部代碼。

2.4 部件庫

OSKit的部件庫提供了比較高層的功能,這些高層的功能以標准的、面向對象的"黑盒"方式設計。部件庫通常只向使用者公開一些相關的公共調用接口。例如,在Linux和BSD驅動程序部件庫中,每一個完整的驅動程序僅僅實現為一個單獨的函數調用,這個函數調用用來初始化並注冊驅動程序。目標系統將通過OSKit的面向對象的COM 接口來與這些部件進行交互。

OSKit部件庫的這種設計策略,可以有效的將大量已經存在的系統(如Linux和BSD)中的已經寫好的代碼合並進來,並隱藏原有環境的細節,使操作系統的設計者們方便的使用它們。

OSKit中的主要的部件庫有:
liboskit_posix:增加對一個POSIX構造的系統會實現的系統調用的支持。例如:open、read和write等。這些POSIX操作被映射到相應的OSKit COM接口上。最小化的C庫和FreeBSD C庫都依賴POSIX庫來提供所需要的系統級操作。
liboskit_freebsd_c:起源於FreeBSD的完整的類POSIX C庫,提供了單線程和多線程的配置。在需要支持那些調用了類POSIX的函數或需要線程安全時,這個庫可以用來替換最小化的C庫liboskit_c。FreeBSD的"系統調用"層由POSIX庫liboskit_posix提供,而高層的代碼則沒有作改動。
liboskit_freebsd_m:完整的標准數學庫(從FreeBSD的libm中取得)。通常那些使用了浮點數的程序都需要這個庫中的函數的支持。
liboskit_fsnamespace:文件系統名字空間庫,為應用程序提供了"namei"風格的轉換,如高層的mount 和unmount兼容。多種部件的絕對和相對路徑名(有斜線的)被轉換成為oskit_file和oskit_dir COM對象。
liboskit_rtld:運行時鏈接、裝入庫,允許ELF格式的OSKit內核裝入共享庫(.so文件)。
liboskit_lmm:一個靈活的存儲管理庫,它可以管理物理內存或虛擬內存。這個庫支持很多OS級代碼需要的功能,例如多種內存類型、分配優先權、和隨意的放置已經分配的塊的約束。
liboskit_amm:地址映射管理庫用於管理收集到的資源,通常收集的每一個元素都有一個名字(地址)和一些屬性。有可能被地址映射管理的資源的例子有交換空間和進程虛擬地址空間。
liboskit_svm:簡單虛存庫。使用AMM 庫定義了一個簡單的用於單獨地址空間的虛存接口,它提供內存保護和為塊設備如一個硬盤分區進行分頁。(不被支持的redzone.c為單線程的內核提供了一個棧redzone,不需要SVM。)
liboskit_threads:這個庫提供了多線程的內核支持,包括POSIX線程、同步、調度和棧保護。調度使用了標准的POSIX Round-Robin和FIFO。試驗性地支持CPU遺傳調度(CPU inheritance scheduling),這是一種用於隨意的調度策略的分層架構,但它還不是很完整很強壯的。
liboskit_memdebug:這個庫提供了一個用於調試的malloc,它可以檢測多種與內存分配有關的錯誤(如overruns、使用已經釋放的內存塊等)。
liboskit_gprof:使OSKit的內核可以收集關於它自己的剖析數據並在運行結束時報告的的運行期支持代碼。當編譯內核時使用"-pg"選項就可以收集剖析數據。
liboskit_diskpart:一個能夠識別多種常見的磁盤分區方案並生成一個完整的映射的通用庫。這個庫提供了一個簡單的方法讓操作系統可以找到相關的或者是"感興趣的"磁盤分區,就如提供簡單的高級方法使用不同的命名策略去訪問任何磁盤分區,BSD和Linux兼容的名字策略在缺省的情況下是被支持的。
liboskit_fsread:一個簡單只讀文件系統解釋庫,它不同的常見的文件系統,包括BSD FFS、Linux ext2fs和MINIX的文件系統。這個庫典型地被用於和分區庫一起使用,為操作系統提供一種簡單的方法從硬盤或軟盤上讀取程序和數據。此外,即使是在一些不需要它的操作系統裡,這個功能經常在啟動時需要。這部分代碼在構造boot loader時也是很有用的。
liboskit_exec:一個通用的可執行程序解釋器和裝入器,它支持流行的可執行程序格式,如a.out和ELF。(即使是通常不需要裝入可執行程序的微內核系統,通常也必須有一種方法裝入第一個用戶態的程序,OSKit的小巧、簡單的可執行程序解釋器很適合於這個目的。)
liboskit_linux_fs:包裝了Linux 2.0.29的文件系統部分的代碼。包括Linux VFS層支持的ext2fs(一個Linux系統上主要使用的文件系統)和其它很多PC上的被Linux支持的文件系統。
liboskit_netbsd_fs:包裝了NetBSD 1.2的文件系統部分的代碼,包括BSD VFS層支持的本地的FFS文件系統。
liboskit_memfs:一個基於內存的文件系統。
liboskit_freebsd_net:包裝了FreeBSD 2.1.7.1的網絡代碼。包括套接字層和協議。
liboskit_bootp:這個庫提供了一個簡單的接口執行BOOTP協議(RFC 1048/1533),以客戶的以太網卡的硬件地址為基礎,從服務器取回一套規范的參數。
liboskit_linux_dev:包裝了Linux 2.0.29的設備驅動程序代碼。當前包括超過50種塊設備(SCSI、IDE)和網絡驅動,它被包裝成使用OSKit的設備驅動架構。。
liboskit_freebsd_dev:包裝了FreeBSD 2.1.7.1的設備驅動程序代碼。當前包括8各TTY(虛擬控制台和串口線,包括鼠標)驅動。
liboskit_wimpi:基於MGR的簡單的分層窗口系統,只用簡單的畫圖和窗口管理操作。
liboskit_*video*:基本的視頻支持,有兩種實現:一種包裝了全部SVGALIB 1.3.0,另一種基於XFree86 3.3.1,但只支持S3的驅動程序。

2.5 OSKit的整體結構圖

上面我們介紹了OSKit的構成,那麼OSKit的整體結構圖是什麼樣的呢?這裡我們給出一個OSKit的整體結構圖,這個整體結構圖並沒有包括OSKit的全部部件,而只是其中一些比較主要的部分,但是從中我們仍然可以加深對於OSKit的了解。

本文要詳細說明的就是上圖中左下角用黑線框住的部分。


3. OSKit的運行環境

OSkit中的許多部件在核心和用戶方式下都可以使用,這就需要對部件的執行環境作出定義,例如部件什麼時候可以嵌套進入等。此外,OSKit使用了許多其它操作系統的代碼,例如設備驅動程序和網絡協議棧,都是原封不動的從原有的核心如BSD和Linux中借用來的,OSKit通過附加代碼模擬原始執行環境使得這些執行模塊比它們原始執行環境更簡單,用戶也不需要詳細了解原執行環境的細節。下面對OSKIT的每種執行模塊進行簡單的介紹。

純執行模塊。這是OSKIT執行環境中最簡單的模塊。這些部件或函數中沒有全局變量或靜態變量,只使用和處理目標環境傳遞的數據。例如函數strlen,它只通過目標環境傳遞給它的字符串指針求出字符串的長度,並將其返回,它只接觸參數數據域而不影響目標環境。當這些函數使用的數據集是分離的,它們可以安全地同時被調用,而不需要同步,反之則不行。例如對重疊的目標緩沖區並發使用memcpy調用是不安全的。

非純執行模塊。這些模塊中使用了全局變量或有可能改變全局共享狀態,例如liboskit_kern(核心支持庫)中的許多函數建立和訪問全局處理器寄存器和數據結構,因此它們是非純執行模塊。非純執行模塊有以下特點:

非純函數和部件可能依賴於全局狀態,如全局變量、靜態變量、處理器中特殊寄存器等。
除非有明確的聲明,非純函數和部件是不可重入的,並且運用在多線程系統中也是不安全的。為了在一個多線程/多處理器環境中使用這些函數和部件,目標操作系統必須提供適當的同步代碼。

阻塞模塊。它擴展了非純模塊以支持非搶占的多線程,這些模塊中有一類可重入的函數稱為阻塞函數,在這模塊中,除非明確聲明為非阻塞函數,否則函數是阻塞的。為了在一個可搶占的、可中斷的或者多處理器的環境中使用阻塞模塊,必須在進入模塊前加鎖,在退出模塊時將鎖釋放。

可中斷阻塞模塊。在它之中每個部件都是一個單線程的執行域,在一個給定的時刻,只有一個(虛擬的或者物理的)CPU可以執行部件中的代碼。例如:在一個多處理器系統中,在進程級,任意時刻在一個部件集內只有一個CPU被允許執行;這能夠通過在部件前後放置全局鎖來實現。

此外,OSKit的執行環境還有以下特點:

在一段時間內,部件中可以存在多個活動進程,但在某時刻只有一個進程被執行。

目標操作系統給每個活動進程提供一個獨立堆棧,這個堆棧在阻塞函數運行時被保留。只有在操作完成後,對部件的調用返回時才放棄該堆棧。

部件中的代碼總是運行在兩個級別中之一,進程級或中斷級。有意思的是一些部件的函數和方法只能在進程級被調用,而另一些只能在中斷級被調用,還有的能在任何級別被調用。調用的細節屬於接口描述的一部分。

部件中無論進程級或中斷級的操作都能被部件中的中斷處理程序中斷,除非代碼調用osenv_intr_disable屏蔽了中斷。

當部件在進程級運行時,OSKit假定中斷開放,部件在處理過程中可能臨時屏蔽掉中斷,但必須在返回到目標操作系統前重新激活。同樣,當部件在中斷級運行時,OSKIT假定中斷被屏蔽,但是部件可以在目標操作系統允許其它中斷級別的活動中斷該部件時重新激活中斷。

當目標操作系統在一個部件內中斷一個進程級的活動時,在繼續這個活動前,操作系統必須執行完這個中斷級別的活動。同理,若一個中斷級的活動被中斷,那麼最近的中斷級別的活動必須在繼續前一個中斷級別的活動之前完成。

部件中運行在中斷級別的代碼不能調用目標操作系統提供的阻塞回調函數;只有非阻塞的回調函數能夠在中斷級別被調用。


Copyright © Linux教程網 All Rights Reserved