LINUX設備驅動程序是怎麼樣和硬體通信的?下面將由我帶大家來解答這個疑問吧,希望對大家有所收獲!
LINUX設備驅動程序與硬體設備之間的通信
設備驅動程序是軟體概念和硬體電路之間的一個抽象層,因此兩方面都要討論。到目前為止,我們已經討論詳細討論了軟體概念上的一些細節,現在討論另一方面,介紹驅動程序在Linux上如何在保持可移植性的前提下訪問I/O埠和I/O內存。
我們在需要示例的場合會使用簡單的數字I/O埠來講解I/O指令,並使用普通的幀緩沖區顯存來講解內存映射I/O。
I/O埠和I/O內存
計算機對每種外設都是通過讀寫它的寄存器進行控制的。大部分外設都有幾個寄存器,不管是在內存地址空間還是在I/O地址空間,這些寄存器的訪問地址都是連續的。
I/O埠就是I/O埠,設備會把寄存器映射到I/O埠,不管處理器是否具有獨立的I/O埠地址空間。即使沒有在訪問外設時也要模擬成讀寫I/O埠。
I/O內存是設備把寄存器映射到某個內存地址區段(如PCI設備)。這種I/O內存通常是首先方案,它不需要特殊的處理器指令,而且CPU核心訪問內存更有效率。
I/O寄存器和常規內存
盡管硬體寄存器和內存非常相似,但程序員在訪問I/O寄存器的時候必須注意避免由於CPU或編譯器不恰當的優化而改變預期的I/O動作。
I/O寄存器和RAM最主要的區別就是I/O操作具有邊際效應,而內存操作則沒有:由於內存沒有邊際效應,所以可以用多種 方法 進行優化,如使用高速緩存保存數值、重新排序讀/寫指令等。
編譯器能夠將數值緩存在CPU寄存器中而不寫入內存,即使儲存數據,讀寫操作也都能在高速緩存中進行而不用訪問物理RAM。無論是在編譯器一級或是硬體一級,指令的重新排序都有可能發生:一個指令序列如果以不同於程序文本中的次序運行常常能執行得更快。
在對常規內存進行這些優化的時候,優化過程是透明的,而且效果良好,但是對I/O操作來說這些優化很可能造成致命的錯誤,這是因為受到邊際效應的干擾,而這卻是驅動程序訪問I/O寄存器的主要目的。處理器無法預料某些 其它 進程(在另一個處理器上運行,或在在某個I/O控制器中發生的操作)是否會依賴於內存訪問的順序。編譯器或CPU可能會自作聰明地重新排序所要求的操作,結果會發生奇怪的錯誤,並且很難調度。因此,驅動程序必須確保不使用高速緩沖,並且在訪問寄存器時不發生讀或寫指令的重新排序。
由硬體自身引起的問題很解決:只要把底層硬體配置成(可以是自動的或是由Linux初始化代碼完成)在訪問I/O區域(不管是內存還是埠)時禁止硬體緩存即可。
由編譯器優化和硬體重新排序引起的問題的解決辦法是:對硬體(或其他處理器)必須以特定順序的操作之間設置內存屏障(memory barrier)。Linux提供了4個宏來解決所有可能的排序問題:
#include <linux/kernel.h>
void barrier(void)
這個函數通知編譯器插入一個內存屏障,但對硬體沒有影響。編譯後的代碼會把當前CPU寄存器中的所有修改過的數值保存到內存中,需要這些數據的時候再重新讀出來。對barrier的調用可避免在屏障前後的編譯器優化,但硬體完成自己的重新排序。
#include <asm/system.h>
void rmb(void);
void read_barrier_depends(void);
void wmb(void);
void mb(void);
這些函數在已編譯的指令流中插入硬體內存屏障;具體實現方法是平台相關的。rmb(讀內存屏障)保證了屏障之前的讀操作一定會在後來的讀操作之前完成。wmb保證寫操作不會亂序,mb指令保證了兩者都不會。這些函數都是barrier的超集。
void smp_rmb(void);
void smp_read_barrier_depends(void);
void smp_wmb(void);
void smp_mb(void);
上述屏障宏版本也插入硬體屏障,但僅僅在內核針對SMP系統編譯時有效;在單處理器系統上,它們均會被擴展為上面那些簡單的屏障調用。
設備驅動程序中使用內存屏障的典型形式如下:
writel(dev->registers.addr, io_destination_address);
writel(dev->registers.size, io_size);
writel(dev->registers.operation, DEV_READ);
wmb();
writel(dev->registers.control, DEV_GO);
在這個例子中,最重要的是要確保控制某種特定操作的所有設備寄存器一定要在操作開始之前已被正確設置。其中的內存屏障會強制寫操作以要求的順序完成。
因為內存屏障會影響系統性能,所以應該只用於真正需要的地方。不同類型的內存屏障對性能的影響也不盡相同,所以最好盡可能使用最符合需要的特定類型。
值得注意的是,大多數處理同步的內核原語,如自旋鎖和atomic_t操作,也能作為內存屏障使用。同時還需要注意,某些外設匯流排(比如PCI匯流排)存在自身的高速緩存問題,我們將在後面的章節中討論相關問題。
在某些體系架構上,允許把賦值語句和內存屏障進行合並以提高效率。內核提供了幾個執行這種合並的宏,在默認情況下,這些宏的定義如下:
#define set_mb(var, value) do {var = value; mb();} while 0
#define set_wmb(var, value) do {var = value; wmb();} while 0
#define set_rmb(var, value) do {var = value; rmb();} while 0
在適當的地方,<asm/system.h>中定義的這些宏可以利用體系架構特有的指令更快的完成任務。注意只有小部分體系架構定義了set_rmb宏。
使用I/O埠
I/O埠是驅動程序與許多設備之間的通信方式——至少在部分時間是這樣。本節講解了使用I/O埠的不同函數,另外也涉及到一些可移植性問題。
I/O埠分配
下面我們提供了一個注冊的介面,它允允許驅動程序聲明自己需要操作的埠:
#include <linux/ioport.h>
struct resource *request_region(unsigned long first, unsigned long n, const char *name);
它告訴內核,我們要使用起始於first的n個埠。name是設備的名稱。如果分配成功返回非NULL,如果失敗返回NULL。
所有分配的埠可從/proc/ioports中找到。如果我們無法分配到我們要的埠集合,則可以查看這個文件哪個驅動程序已經分配了這些埠。
如果不再使用這些埠,則用下面函數返回這些埠給系統:
void release_region(unsigned long start, unsigned long n);
下面函數允許驅動程序檢查給定的I/O埠是否可用:
int check_region(unsigned long first, unsigned long n);//不可用返回負的錯誤代碼
我們不贊成用這個函數,因為它返回成功並不能確保分配能夠成功,因為檢查和其後的分配並不是原子操作。我們應該始終使用request_region,因為這個函數執行了必要的鎖定,以確保分配過程以安全原子的方式完成。
操作I/O埠
當驅動程序請求了需要使用的I/O埠范圍後,必須讀取和/或寫入這些埠。為此,大多數硬體都會把8位、16位、32位區分開來。它們不能像訪問系統內存那樣混淆使用。
因此,C語言程序必須調用不同的函數訪問大小不同的埠。那些只支持映射的I/O寄存器的計算機體系架構通過把I/O埠地址重新映射到內存地址來偽裝埠I/O,並且為了易於移植,內核對驅動程序隱藏了這些細節。Linux內核頭文件中(在與體系架構相關的頭文件<asm/io.h>中)定義了如下一些訪問I/O埠的內聯函數:
unsigned inb(unsigned port);
void outb(unsigned char byte, unsigned port);
位元組讀寫埠。
unsigned inw(unsigned port);
void outw(unsigned short word, unsigned port);
訪問16位埠
unsigned inl(unsigned port);
void outl(unsigned longword, unsigned port);
訪問32位埠
在用戶空間訪問I/O埠
上面這些函數主要是提供給設備驅動程序使用的,但它們也可以用戶空間使用,至少在PC類計算機上可以使用。GNU的C庫在<sys/io.h>中定義了這些函數。如果要要用戶空間使用inb及相關函數,則必須滿足正下面這些條件:
編譯程序時必須帶有-O選項來強制內聯函數的展開。
必須用ioperm(獲取單個埠的許可權)或iopl(獲取整個I/O空間)系統調用來獲取對埠進行I/O操作的許可權。這兩個函數都是x86平台特有的。
必須以root身份運行該程序才能調用ioperm或iopl。或者進程的祖先進程之一已經以root身份獲取對埠的訪問。
如果宿主平台沒有以上兩個系統調用,則用戶空間程序仍然可以使用/dev/port設備文件訪問I/O埠。不過要注意,該設備文件的含義與平台密切相關,並且除PC平台以處,它幾乎沒有什麼用處。
串操作
以上的I/O操作都是一次傳輸一個數據,作為補充,有些處理器實現了一次傳輸一個數據序列的特殊指令,序列中的數據單位可以是位元組、字、雙字。這些指令稱為串操作指令,它們執行這些任務時比一個C語言編寫的循環語句快得多。下面列出的宏實現了串I/O:
void insb(unsigned port, void *addr, unsigned long count);
void outsb(unsigned port, void *addr, unsigned long count);從內存addr開始連續讀/寫count數目的位元組。只對單一埠port讀取或寫入數據
void insw(unsigned port, void *addr, unsigned long count);
void outsw(unsigned port, void *addr, unsigned long count);對一個16位埠讀寫16位數據
void insl(unsigned port, void *addr, unsigned long count);
void outsl(unsigned port, void *addr, unsigned long count);對一個32位埠讀寫32位數據
在使用串I/O操作函數時,需要銘記的是:它們直接將位元組流從埠中讀取或寫入。因此,當埠和主機系統具有不同的位元組序時,將導致不可預期的結果。使用inw讀取埠將在必要時交換位元組,以便確保讀入的值匹配於主機的位元組序。然而,串函數不會完成這種交換。
暫停式I/O
在處理器試圖從匯流排上快速傳輸數據時,某些平台(特別是i386)就會出現問題。當處理器時鍾比外設時鍾(如ISA)快時就會出現問題,並且在設備板上特別慢時表現出來。為了防止出現丟失數據的情況,可以使用暫停式的I/O函數來取代通常的I/O函數,這些暫停式的I/O函數很像前面介紹的那些I/O函數,不同之處是它們的名字用_p結尾,如inb_p、outb_p等等。在linux支持的大多數平台上都定義了這些函數,不過它們常常擴展為非暫停式I/O同樣的代碼,因為如果不使用過時的外設匯流排就不需要額外的暫停。
平台相關性
I/O指令是與處理器密切相關的。因為它們的工作涉及到處理器移入移出數據的細節,所以隱藏平台間的差異非常困難。因此,大部分與I/O埠相關的源代碼都與平台相關。
回顧前面函數列表可以看到有一處不兼容的地方,即數據類型。函數的參數根據各平台體系架構上的不同要相應地使用不同的數據類型。例如,port參數在x86平台上(處理器只支持64KB的I/O空間)上定義為unsigned short,但在其他平台上定義為unsigned long,在這些平台上,埠是與內存在同一地址空間內的一些特定區域。
感興趣的讀者可以從io.h文件獲得更多信息,除了本章介紹的函數,一些與體系架構相關的函數有時也由該文件定義。
值得注意的是,x86家族之外的處理器都不為埠提供獨立的地址空間。
I/O操作在各個平台上執行的細節在對應平台的編程手冊中有詳細的敘述;也可以從web上下載這些手冊的PDF文件。
I/O埠示例
演示設備驅動程序的埠I/O的示例代碼運行於通用的數字I/O埠上,這種埠在大多數計算機平台上都能找到。
數字I/O埠最常見的一種形式是一個位元組寬度的I/O區域,它或者映射到內存,或者映射到埠。當把數字寫入到輸出區域時,輸出引腳上的電平信號隨著寫入的各位而發生相應變化。從輸入區域讀取到的數據則是輸入引腳各位當前的邏輯電平值。
這類I/O埠的具體實現和軟體介面是因系統而異的。大多數情況下,I/O引腳由兩個I/O區域控制的:一個區域中可以選擇用於輸入和輸出的引腳,另一個區域中可以讀寫實際的邏輯電平。不過有時情況簡單些,每個位不是輸入就是輸出(不過這種情況下就不能稱為“通用I/O"了);在所有個人計算機上都能找到的並口就是這樣的非通用的I/O埠。
並口簡介
並口的最小配置由3個8位埠組成。第一個埠是一個雙向的數據寄存器,它直接連接到物理連接器的2~9號引腳上。第二個埠是一個只讀的狀態寄存器;當並口連接列印機時,該寄存器 報告 列印機狀態,如是否是線、缺紙、正忙等等。第三個埠是一個只用於輸出的控制寄存器,它的作用之一是控制是否啟用中斷。
如下所示:並口的引腳
示例驅動程序
while(count--) {
outb(*(ptr++), port);
wmb();
}
使用I/O內存
除了x86上普遍使的I/O埠之外,和設備通信的另一種主要機制是通過使用映射到內存的寄存器或設備內存,這兩種都稱為I/O內存,因為寄存器和內存的差別對軟體是透明的。
I/O內存僅僅是類似RAM的一個區域,在那裡處理器可以通過匯流排訪問設備。這種內存有很多用途,比如存放視頻數據或乙太網數據包,也可以用來實現類似I/O埠的設備寄存器(也就是說,對它們的讀寫也存在邊際效應)。
根據計算機平台和所使用匯流排的不同,i/o內存可能是,也可能不是通過頁表訪問的。如果訪問是經由頁表進行的,內核必須首先安排物理地址使其對設備驅動程序可見(這通常意味著在進行任何I/O之前必須先調用ioremap)。如果訪問無需頁表,那麼I/O內存區域就非常類似於I/O埠,可以使用適當形式的函數讀取它們。
不管訪問I/O內存是否需要調用ioremap,都不鼓勵直接使用指向I/O內存的指針。相反使用包裝函數訪問I/O內存,這一方面在所有平台上都是安全的,另一方面,在可以直接對指針指向的內存區域執行操作的時候,這些函數是經過優化的。並且直接使用指針會影響程序的可移植性。
I/O內存分配和映射
在使用之前,必須首先分配I/O區域。分配內存區域的介面如下(在<linux/ioport.h>中定義):
struct resource *request_mem_region(unsigned long start, unsigned long len, char *name);
該函數從start開始分配len位元組長的內存區域。如果成功返回非NULL,否則返回NULL值。所有的I/O內存分配情況可從/proc/iomem得到。
不再使用已分配的內存區域時,使用如下介面釋放:
void release_mem_region(unsigned long start, unsigned long len);
下面函數用來檢查給定的I/O內存區域是否可用的老函數:
int check_mem_region(unsigned long start, unsigned long len);//這個函數和check_region一樣不安全,應避免使用
分配內存之後我們還必須確保該I/O內存對內存而言是可訪問的。獲取I/O內存並不意味著可引用對應的指針;在許多系統上,I/O內存根本不能通過這種方式直接訪問。因此,我們必須由ioremap函數建立映射,ioremap專用於為I/O內存區域分配虛擬地址。
我們根據以下定義來調用ioremap函數:
#include <asm/io.h>
void *ioremap(unsigned long phys_addr, unsigned long size);
void *ioremap_nocache(unsigned long phys_addr, unsigned long size);在大多數計算機平台上,該函數和ioremap相同:當所有I/O內存已屬於非緩存地址時,就沒有必要實現ioremap的獨立的,非緩沖版本。
void iounmap(void *addr);
記住,由ioremap返回的地址不應該直接引用,而應該使用內核提供的accessor函數。
訪問I/O內存
在某些平台上我們可以將ioremap的返回值直接當作指針使用。但是,這種使用不具有可移植性,訪問I/O內存的正確方法是通過一組專用於些目的的函數(在<asm/io.h>中定義)。
從I/O內存中讀取,可使用以下函數之一:
unsigned int ioread8(void *addr);
unsigned int ioread16(void *addr);
unsigned int ioread32(void *addr);
其中,addr是從ioremap獲得的地址(可能包含一個整數偏移量);返回值是從給定I/O內存讀取到的值。
寫入I/O內存的函數如下:
void iowrite8(u8 value, void *addr);
void iowrite16(u16 value, void *addr);
void iowrite32(u32 value, void *addr);
如果必須在給定的I/O內存地址處讀/寫一系列值,則可使用上述函數的重復版本:
void ioread8_rep(void *addr, void *buf, unsigned long count);
void ioread16_rep(void *addr, void *buf, unsigned long count);
void ioread32_rep(void *addr, void *buf, unsigned long count);
void iowrite8_rep(void *addr, const void *buf, unsigned long count);
void iowrite16_rep(void *addr, const void *buf, unsigned long count);
void iowrite32_rep(void *addr, const void *buf, unsigned long count);
上述函數從給定的buf向給定的addr讀取或寫入count個值。count以被寫入數據的大小為單位。
上面函數均在給定的addr處執行所有的I/O操作,如果我們要在一塊I/O內存上執行操作,則可以使用下面的函數:
void memset_io(void *addr, u8 value, unsigned int count);
void memcpy_fromio(void *dest, void *source, unsigned int count);
void memcpy_toio(void *dest, void *source, unsigned int count);
上述函數和C函數庫的對應函數功能一致。
像I/O內存一樣使用I/O埠
某些硬體具有一種有趣的特性:某些版本使用I/O埠,而其他版本則使用I/O內存。導出給處理器的寄存器在兩種情況下都是一樣的,但訪問方法卻不同。為了讓處理這類硬體的驅動程序更加易於編寫,也為了最小化I/O埠和I/O內存訪問這間的表面區別,2.6內核引入了ioport_map函數:
void *ioport_map(unsigned long port, unsigned int count);
該函數重新映射count個I/O埠,使其看起來像I/O內存。此後,驅動程序可在該函數返回的地址上使用ioread8及其相關函數,這樣就不必理會I/O埠和I/O內存之間的區別了。
當不需要這種映射時使用下面函數一撤消:
void ioport_unmap(void *addr);
這些函數使得I/O埠看起來像內存。但需要注意的是,在重新映射之前,我們必須通過request_region來分配這些I/O埠。
為I/O內存重用short
前面介紹的short示例模塊訪問的是I/O埠,它也可以訪問I/O內存。為此必須在載入時通知它使用I/O內存,另外還要修改base地址以使其指向I/O區域。
下例是在MIPS開發板上點亮調試用的LED:
mips.root# ./short_load use_mem=1 base = 0xb7ffffc0
mips.root# echo -n 7 > /dev/short0
下面代碼是short寫入內存區域時使用的循環:
while(count--) {
iowrite8(*ptr++, address);
wmb();
}
1MB地址空間之下的ISA內存
最廣為人知的I/O內存區之一就是個人計算機上的ISA內存段。它的內存范圍在64KB(0xA0000)到1MB(0x100000)之間,因此它正好出現在常規系統RAM的中間。這種地址看上去有點奇怪,因為這個設計決策是20世紀80年代早期作出的,在當時看來沒有人會用到640KB以上的內存。
❷ 操作系統的主要性能指標有哪些
微型計算機的主要性能指標和基本系統配置
(1)微型計算機主要性能指標
字長:CPU能夠同時處理的比特(bit)數目。它直接關繫到計算機的計算精度、功能和速度。字長越長,計算精度越高,處理能力越強。常見的微型機字長有8位、16位、32位。
主頻(時鍾頻率):時鍾脈沖發生器所產生的時鍾信號頻率(MHz)。它在很大程度上決定了計算機的運行速度。
內存容量:內存儲器中能夠存儲信息的總位元組數,一般以KB、MB為單位,反映了內存儲器存儲數據的能力。
運算速度:計算機每秒運算的次數(MIPS
-
每秒百萬條指令)。
系統的可靠性:系統在正常條件下不發生故障或失效的概率。
外設配置:外設是指計算機的輸入、輸出設備以及外存儲器等,其中,顯示器有單色、彩色之分,也有高、中、低解析度之分,,磁碟有軟盤與硬碟之分,軟盤有高密、低密之分。
軟體配置:軟體配置包括操作系統、計算機語言、資料庫管理系統、網路通信軟體、漢字軟體及其他各種應用軟體等。
存取周期:對內存進行一次訪問(存取)操作所需的時間。
❸ linux,unix.windows三大操作系統的區別在哪
1、操作
linux區分大小寫,windows在dos界面命令下不區分大小寫;
linux所有內容均以文件形式保存包括硬體,用戶,而windows文件和硬體沒什麼關系,兩個之間沒有關聯;
windows用擴展名區分文件如.exe代表執行文件,.txt代表文本文件,而linux無擴展名的概念,當然為了管理員區分方便會有部分擴展名如.gz , .bz2 ,.tar.bz2代表壓縮包。
.html ,,php代表網頁文件,這些純粹是給管理員看的便於區分,但是linux本身是沒有擴展名的,linux是以許可權區分文件的,文件許可權總共有十位。
windows下的.exe文件不能直接在linux下安裝與運行,同時linux大部分是字元界面,大大增加了linux系統的安全性,減少了木馬攻擊的可能性,同時linux字元界面佔用的系統資源要小於windows下的圖形界面所佔的資源。
2、系統概念
UNIX操作系統:
是一個強大的多用戶、多任務操作系統,支持多種處理器架構。
整個UNIX系統可分為五層:
最底層是裸機,即硬體部分;
第二層是UNIX的核心,它直接建立在裸機的上面,實現了操作系統重要的功能,如進程管理、存儲管理、設備管理、文件管理、網路管理等。
用戶不能直接執行UNIX內核中的程序,而只能通過一種稱為」系統調用」的指令,以規定的方法訪問核心,以獲得系統服務;
第三層系統調用構成了第四層應用程序層和第二層核心層之間的介面界面;
應用層主要是UNIX系統的核外支持程序,如文本編輯處理程序、編譯程序、系統命令程序、通信軟體包和窗口圖形軟體包、各種庫函數及用戶自編程序;
UNIX系統的最外層是Shell解釋程序,它作為用戶與操作系統交互的介面,分析用戶鍵入的命令和解釋並執行命令,Shell中的一些內部命令可不經過應用層,直接通過系統調用訪問核心層。
Linux操作系統:
是基於UNIX操作系統發展而來的一種克隆系統,是一套免費使用和自由傳播的類Unix操作系統。它能運行主要的UNIX工具軟體、應用程序和網路協議。
Linux繼承了Unix以網路為核心的設計思想,是一個性能穩定的多用戶網路操作系統。其目的是建立不受任何商品化軟體的版權制約的、全世界都能自由使用的Unix兼容產品。
Windows操作系統:
Windows1.0是微軟第一次對個人電腦操作平台進行用戶圖形界面的嘗試。Windows 1.0基於MS-DOS操作系統,實際上其本身並非操作系統,至多隻是基於DOS的應用軟體。
之後的 Windows 2.x,3.x 和 95,98,ME仍是基於DOS的操作系統。 而Windows NT則宣告了DOS操作系統的終結,並成為流行至今的主流操作系統。
3、發展背景
Linux與其他操作系統的區別是,Linux是從一個比較成熟的操作系統發展而來的,而其他操作系統,如Windows NT等,都是自成體系,無對應的相依託的操作系統。這一區別使得Linux的用戶能大大地從Unix團體貢獻中獲利。
因為Unix是世界上使用最普遍、發展最成熟的操作系統之一,它是七十年代中期發展起來的微機和巨型機的多任務系統,雖然有時介面比較混亂,並缺少相對集中的標准,但還是發展壯大成為了最廣泛使用的操作系統之一。
無論是Unix的作者還是Unix的用戶,都認為只有Unix才是一個真正的操作系統,許多計算機系統(從個人計算機到超級計算機)都存在Unix版本,Unix的用戶可以從很多方面得到支持和幫助。
因此,Linux做為Unix的一個克隆,同樣會得到相應的支持和幫助,直接擁有Unix在用戶中建立的牢固的地位。
4、使用費用
從使用費用上看,Linux與其他操作系統的區別在於Linux是一種開放、免費的操作系統,而其他操作系統都是封閉的系統,需要有償使用。
這一區別使得我們能夠不用花錢就能得到很多Linux的版本以及為其開發的應用軟體。當我們訪問Internet時,會發現幾乎所有可用的自由軟體都能夠運行在Linux系統上。
有來自很多軟體商的多種Unix實現,Unix的開發、發展商以開放系統的方式推動其標准化,但卻沒有一個公司來控制這種設計。
因此,任何一個軟體商(或開拓者)都能在某種Unix實現中實現這些標准。
OS/2和WindowsNT等操作系統是具有版權的產品,其介面和設計均由某一公司控制,而且只有這些公司才有權實現其設計,它們是在封閉的環境下發展的。
❹ 基於MIPS指令集的Linux系統與基於X86指令集的Linux系統有什麼區別
MIPS和x86是兩種不同的處理器架構,屬於硬體范疇;
Linux 則是操作系統軟體,它支持包括 MIPS , x86, arm 等各種各樣的處理器架構平台。換句話說,它可以跑在依據不同處理器架構規范實作出來的各種處理器上面。
Linux 大部分的代碼都是由C語言寫成,因為C語言是一種高級別的語言,用它寫的程序可以被編譯成各種指令集中指令所構成的二進制可執行程序。C語言雖然高級別,但是有時候在沒辦法使用C語言的場合(比方為了訪問處理器內不同寄存器就需要使用匯編而非C語言),或者有時候為了追求效率的提升,我們必須得用匯編來寫程序。Linux內核為了支持不同的處理器架構,所以在其代碼中包括了少量的匯編代碼。所以我們可以認為,就內核源代碼級別來說,基於不同指令集的Linux內核是沒有太多區別的。
這是內核,對於不同應用程序來說,我們也可以認為是沒什麼區別,因為應用程序基於C函數庫導出的不同函數,以及Linux內核所提供的系統調用,這些都是C語言介面,所以應用程序都用高級語言寫成,基本上不會使用匯編語言。
如果要真說有什麼區別,那就體現在編譯後出來的二進制代碼上。我們認為那是完全不同的。因為完成同一個功能的二進制代碼,裡麵包含的是來自不同指令集內的不同指令。
就這么多了,您還需要多少詳細的解答?:)
(該解答來自JulianTec - 您在 arm 架構下學習嵌入式Linux的上佳指導。)
❺ Windows NT採用了怎樣內核結構
Windows NT 內核基本結構和特徵
盡管大部分人每天在Windows系統上工作學習娛樂,但是對於其內核結構很多人仍然是不了解的。一方面是由於其內核源代碼不開源,另一方面則是由於相關資料的奇缺。我大二基本上花了一學期來學習和探究NT內核。雖然不敢說自己對其有很深入的了解,但至少其基本結構還算是清楚的。但是我畢竟才學有限,肯定會有不完善的地方,還請各位不吝賜教。
目前微軟所有的主流操作系統均是基於NT內核,比如:
Windows 2000/XP/Server 2003(基於NT5)
Windows Vista (基於NT6)
Windows 7(基於NT6.1, 我沒裝過Win7,不過據說是這樣的)
盡管很多人責備Windows在一些方面存在很多問題,但是這並不是內核的錯,總的來說,NT的是一個成熟穩定且先進的內核,我認為在今後相當長的一段時期內,NT內核仍將是主流,且不會有很大變化(當然,局部的升級是完全毫無疑問的)
微軟早期希望把NT做成一個純微內核結構,關於微內核和單一內核的區別,各位如有不清楚的,可以去網上搜索一下。後來為了提高圖形子系統的性能,避免大量的內核態和用戶態切換,微軟便將其移入內核之中,使其成為內核一部分(類似的還有後來的DirectX技術)。由此可見,NT並不是一個完全的微內核,它也具有單一內核的某些特徵。
NT內核具有以下幾個特徵(摘自Undocumented Windows NT)
Portability (可移植性)
如你所知,Windows NT 可以運行在多種平台上,即 Intel、MIPS、Power PC 和 DEC Alpha。眾多廠商都為 Windows NT 的可移植性做出了貢獻。 其中最為重要的因素可能是其實現所使用的語言。Windows NT 大部分是用 C 語言編寫的,也有一部分用的是 C++。 平台相關的匯編語言只在必需的地方才用到。Windows NT 團隊還將操作系統中硬體相關的部分與其它部分隔離開,單獨放進了 HAL.DLL。 如此一來,Windows NT 中與硬體無關的部分的代碼就可以用 C 之類的高級語言來編寫,也因此可以很容易地移植到各種平台。
Extensibility(可擴展性)
Windows NT 具有很高的可擴展性,但因為缺少文檔,其可擴展的特性卻極少得到發掘。未公開的特性的名單中,子系統首當其沖。子系統在操作系統中提供了多種操作系統介面。只需添加新的子系統程序就可以為 Windows NT 擴展新的操作系統介面,但是對於公開添加新子系統過程的要求微軟卻一直打馬虎眼。
Windows NT 的內核是高可擴展的,因為可以將內核模塊作為驅動程序動態載入。對於 Windows NT,微軟提供了足夠的文檔來編寫硬體設備驅動——即硬碟驅動、網卡驅動、磁帶機驅動等等。在 Windows NT 下還可以編寫不控制設備的驅動程序。甚至連文件系統也是作為驅動程序載入的。
Windows NT 的可擴展性的另一個例子就是系統調用介面的實現。 開發者要修改操作系統行為,一般都需要鉤掛或添加系統調用。 Windows NT 的開發團隊實際了良好的系統調用介面以方便鉤掛和添加系統調用。但是微軟還是沒有公開這些機制。
Compatibility(兼容性)
長久以來,向下兼容性都是 Intel 處理器和微軟操作系統的一大特徵,也是這兩位巨人成功的關鍵。Windows NT 必須能運行 DOS、Win16 和 OS/2 的程序。兼容性是 Windows NT 開發團隊使用子系統概念的另一個原因。除二進制兼容之外(執行不同格式的可執行文件),Windows NT 還為符合 POSIX 的程序提供了源代碼級的兼容。增強兼容性的其他方面還表現在除自己本身的 NTFS 外,Windows NT 支持其它的文件系統,如 DOS 的 FAT 和 OS/2 的 HPFS。
Maintainability(可維護性)
Windows NT 的代碼量很大,維護著些代碼的工作量也相當大。NT 的開發團隊通過使用面向對象的設計實現了高可維護性。再有,將操作系統的功能分成各個層也提高了可維護性。最上面的一層,也就是用戶見到的操作系統層面,是子系統層。子系統提供系統調用介面來為外界提供應用程序編程介面。在系統調用介面層之下的是 NT 的 executive,executive 又建立在內核之上,而內核又依賴於硬體抽象層(HAL),硬體抽象層與硬體直接通訊。
NT 的開發團隊所選的編程語言也與 Windows NT 的可維護性有關。正如我們前面提到的,整個操作系統都是用 C 和 C++ 來編寫的,只有極少數不用不行的地方用了匯編語言。
Security(安全性)
Windows NT 是一個安全的操作系統,是因為它有以下幾點特徵:用戶在使用系統之前必須先登陸。 系統中的資源都被視為對象,而每一個對象都相應由一個安全描述符。安全描述符有一個安全列表來指示那些用戶可以訪問該對象。
盡管有這些,要是沒有一個安全的文件系統,操作系統也不能說是安全的。 DOS 時的 FAT 文件系統沒有預見到任何的安全問題,其作為一個單用戶的系統,也不用防範安全問題。
為了克服此缺陷,Windows NT 團隊推出了一種新的文件系統,這種文件系統基於 OS/2 的文件系統 HPFS。這種新的 Windows NT 的自有文件系統叫 NTFS。它支持訪問控制,用戶可以為 NTFS 下創建的文件或目錄指定訪問許可權,NTFS 只允許有訪問許可權的進程訪問該文件或目錄。
Multiprocessing(多進程)
Windows NT 支持對稱多處理,Windows NT 的工作站版本可以支持兩個處理器,伺服器版可以支持到4個。為支持多處理,操作系統需要特殊的同步機制。在單處理器系統中,通過禁用中斷,臨界區中的代碼執行時不會被打斷。這對於維護內核數據結構的完整性來說是必需的。在多處理器環境下,就不可能在所有的處理器上都禁用中斷。在多處理環境中,Windows NT 使用自旋鎖來保護內核數據結構。
註:多處理可分為對稱的和非對稱的。在非對稱多處理中,有一個處理器為主處理器,其它的處理器都為從處理器。只有主處理器運行在內核模式,其它從處理器都只運行在用戶線程。只要運行在用戶線程的從處理器一調用系統服務,主處理器就接管此線程並執行所需的內核服務。調度程序,一個內核程序,之運行在主處理器上。因此,主處理扮演者調度員的角色,將用戶模式線程分派給從處理器。很自然,與所有處理器都可在內核或用戶模式運行的對稱多處理相比,主處理器負擔很重,系統不均衡。
International Language Support(國際化語言支持)
如今眾多的 PC 用戶都使用英語之外的其它語言。與這些用戶能很好交互的關鍵就是使操作系統能支持用戶們的語言。Windows NT 通過使用 Unicode 標準的字元集實現了這一目標。Unicode 標准規定了一個16位的字元集,而ASCII 使用的是8位字元集。 Unicode 的前256個字元的編碼與 ASCII 的相同。這就為非拉丁語的語言留出了充足的空間。Win32 API 能接受 Unicode 和 ASCII 兩種字元集,而 Windows NT 的內核則只能使用 Unicode。盡管應用程序程序員可以不去了解 Unicode,但驅動程序的開發者必須熟悉 Unicode,因為內核介面函數只接受 Unicode 字元串而且驅動的入口點都用的是 Unicode。
Windows NT 從 MACH 操作系統那裡借用了核心體系,MACH 操作系統是在卡耐基梅隆大學開發的。MACH 操作系統的基本理念就是通過將復雜的操作系統功能交給用戶級進程而將內核減至最小。這種客戶機-伺服器的操作系統體系還有另外一個目的:允許在同一操作系統上使用多種 APIs。通過在伺服器進程中實現 APIs 就可以做到。
MACH 操作系統的內核提供了非常簡單的一組介面函數。伺服器進程使用這組介面函數實現出某種 API 來提供一組更復雜的介面函數。Windows NT 從 MACH 那裡借用了這個理念。Windows NT 中的伺服器進程被稱作子系統。模塊化和結構化的程序設計都是優秀軟體管理的原則,NT 選擇使用客戶機-伺服器的體系結構顯示了它對這種原則的服從。Windows NT 本可以將所需的 APIs 在內核實現,也可以在內核上加上不同的層來實現不同的 APIs。出於維護性和擴展性的目的,NT 團隊選擇了子系統的辦法。
Windows NT 中有兩種子系統: integral subsystems 和 environment subsystems。Integral subsystems,如安全管理子系統,完成基本的操作系統任務。 Environment subsystems 則使得一台 Windows NT 機器能使用不同種類的 APIs。Windows NT 的子系統能支持以下的 APIs:
Win32 子系統。Win32 子系統提供 Win32 API。使用 Win32 API 的應用程序可以運行在微軟 提供的所有平台上—
WOW 子系統。Windows on Windows (WOW) 子系統提供了對 16-bit Windows 應用程序的兼容,使得 Win16 的應用程序可以在 Windows NT 上運行。只要沒有使用 Windows NT 不支持的未公開函數,這些應用程序都可以運行。
NTVDM 子系統。NT Virtual DOS Machine (NTVDM) 提供了一個基於文本的環境,DOS 程序可以在這個環境中運行。
OS/2 子系統。OS/2 子系統能運行 OS/2 應用程序。WOW、NTVDM 和 OS/2 都只能用在 Intel 平台上,因為他們都對應用程序提供二進制兼容性。而用於一種處理器的可執行文件或二進制文件就不能用在另一種處理器上,因為處理器間的機器指令格式不同。
POSIX 子系統。POSIX 子系統提供符合 POSIX 1003.1 標準的 API。
應用程序並不知道所調用的 API 是由相應的子系統處理的。這種隱藏是通過每種子系統各自的客戶端 DLL 來實現的。這種 DLL 將 API 調用轉換為本地過程調用(local procere call,LPC)。本地過程調用類似於聯網的 UNIX 上的遠程過程調用(RPC)。使用 RPC,客戶應用程序可以調用運行在網路上另一台機器上的伺服器進程。 LPC 對運行在同一台計算機上的客戶機與伺服器進行了優化。
NT內核主要包含以下幾個重要文件:
Ntoskrnl.exe(或者Ntkrnlpa.exe)
HAL.Dll
NTDll.Dll
Win32k.Sys
NT內核的核心是NT EXECUTIVE。對應的文件是Ntoskrnl.exe。如果是機器是多處理器的,則是Ntkrnlpa.exe。非常可笑的是,這個文件可以直接刪除,其後果就是重啟後Windows無法啟動,甚至連滾動條都看不到。該文件只有2MB左右的大小,但可謂是麻雀雖小五臟俱全,它作為整個Windows中最核心的部分,向外界提供了復雜的介面。
與之相輔相成的是HAL.Dll文件,即Hardware Abstraction Layer 硬體抽象層 。它直接與機器的硬體打交道,將硬體的差異對其之上的層隱藏起來。Windows NT 是一個有高可移植性的操作系統,運行在多種平台上。HAL.DLL 包含的代碼向核心的其它部分隱藏了處理器和機器相關的細節。因此平台之間只有 HAL.DLL 不同,剩下的使用 HAL 介面的核心代碼都有很高的可移植性。
NTDll.Dll模塊。導出了大部分的Native API函數,提供了由用戶態至內核態的切換的功能。做過Windows平台開發的人都知道,Windows API主要由Kernel32.Dll, User32.Dll, GDI32.Dll構成。其實對WindowsAPI的調用最終會被轉接到NTDll。即所謂Native API,命名上基本上就是在原API前面加上Nt或者Zw(比如CreateFile就變成了NtCreateFile)。而Kernel32.Dll, User32.Dll, GDI32.Dll三個文件則組成了Win32子系統,它們本身不實現API,它導出的函數被稱為stub 函數(盡管名稱上看起來很迷惑人)
Win32K.sys模塊。實現了Windows的圖形處理部分。USER32 和 GDI32 使用系統調用介面來調用 WIN32K.SYS 中的服務。由於其工作與內核態,所以具有很高的性能,這也成就了Windows系統的強大的圖形處理能力。