嵌入式Linux經驗談(三):嵌入式Linux的硬體中斷處理

本文作者:admin       點擊: 2009-04-29 00:00
前言:
作業系統最重要的任務就是要能和各種硬體周邊溝通和通訊,而硬體周邊往往就是國內業者的主要產品,因此編寫程式來驅動和讀寫這些硬體周邊,就成了Linux工程師的主要工作了。

開機程式
  不管是哪一種作業系統(O.S.)----UNIX、Windows、RTOS、Linux……等,都是從開機(boot)程式開始的,而大多數的開機程式是可以和作業系統本身分離的。所謂「分離(separate)」是指開機程式不需要作業系統核心(kernel)就可以單獨存在和被人開發出來。以個人電腦(PC)的作業系統為例:BIOS就是PC的開機程式,它可以和Windows、Mac OS、UNIX、Linux銜接,將O.S.載入記憶體,最後呼叫O.S.的主進入程式(main entry program),並將CPU控制權交給O.S.。O.S.起來以後,照理說,開機程式便功成身退了,但它卻沒有閒著,仍然存在於記憶體中,要負責「接住」「軟重置(soft reset/warm reset)」。軟重置就是指系統不關機但重新開機的意思。而「接住」軟重置,就是指當重新開機時,開機程式必須接住「重置異常(reset exception)」訊號。順利接住之後,開機程式會重頭再被執行一次,直到O.S.再次起來。

  依照CPU、硬體周邊和O.S.的不同,開機程式也各有不同,所以,全球會有許多家不同的BIOS公司存在。傳統的BIOS(如今看來,可以算是古董了)是將硬體周邊一併初始化,所以開機時間很慢。桌上型Linux的開機程式也是如此,例如:當Red Hat不正常關機,於重開機時,可以看到一大串藍底白字的GRUB(GRand Unified Bootloader)開機訊息。為何要這樣做?為何會這麼慢?無非是因為CPU、BIOS、PC製造公司不願意改變。不過,就技術面而言,這是可以改善的,但在傳統的PC-BIOS產業裡,這種改革的腳步最近才剛開始而已。

嵌入式Linux的開機程式卻技術領先很多。打從一開始,嵌入式Linux的開機載入程式(bootloader)就不像它的「祖先」(例如:GRUB)那樣「笨重」。U-Boot和RedBoot是目前最常用的嵌入式bootloader,還有很多公司自行開發自己的bootloader。現在有許多PC-BIOS公司也仿效嵌入式Linux的bootloader,將BIOS簡化,除了必要的硬體(譬如:SDRAM記憶體)以外,其餘硬體周邊的初始化都交給O.S.或Linux核心來做。因為Linux核心允許硬體驅動程式和通訊協定堆疊(protocol stack)以動態模組的方式,於Linux起來以後,讓用戶以insmod命令將這些模組一一掛入Linux系統裡。因此,可以大幅縮減開機所需的時間。PC-BIOS公司肯這麼做,當然是經過WinTel集團同意和鼓勵的,因為在雙核心(dual cores)/多核心CPU的時代,誰還有能力去編寫和維護數以萬行的組合語言BIOS程式呢?為了順應這個趨勢,Windows作業系統的架構想必早就做好修改了。
  
中斷服務程式
  有了Linux核心,要設計一個硬體中斷服務程式(ISR),變的很容易。因為底層的異常或中斷處理全部交由Linux負責,軟體工程師只要利用request_irq( )將ISR和IRQ號碼連結在一起就可以了。當然這是很簡化的講法,要設計一個功能正常的GPIO中斷處理程式,還需要將此GPIO裝置和它的驅動程式向Linux核心註冊才行。

  對Linux而言,一個上層ISR可以簡單地被視為一個「應用程式」,雖然這種程式仍然存在於Linux核心內。那底層的異常或中斷是如何處理的呢?說來話長,但關鍵在於:traps.c和與traps相關的一個組合語言檔案----若CPU是ARM,此檔案是entry-armv.S;若用MIPS,則此檔案是genex.S。「硬體異常(hardware exception)」通常稱作trap,它不同於軟體中斷,它是真正由硬體產生的中斷。舉MIPS為例,traps.c內的trap_init( )負責將最底層的except_vec3_generic複製到「異常來源區」----位於SDRAM或ROM內,except_vec3_generic是硬體的異常處理程式(exception handler),它和其它異常處理程式全部存在於entry-armv.S或genex.S內。except_vec3_generic內有exception_handlers[ ],它是用來儲存每一個硬體中斷的lower-ISR,trap_init( )負責將所有的lower-ISR填入exception_handlers[ ]中。所有的lower-ISR都是存在於entry-armv.S或genex.S內。硬體的lower-ISR稱作handle_int,說來奇怪,所有硬體都使用這唯一的lower-ISR,這是因為CPU分配給硬體的中斷源只有一個,不管是MIPS或ARM或PPC都是這樣的。一有硬體異常或中斷發生時,程式計數器(porgam counter;PC)會跳到「異常來源區」,執行except_vec3_generic,再跳到handle_int,最後跳到plat_irq_dispatch( )----這就是high-ISR。

每一種CPU都有它們各自的plat_irq_dispatch,這是由軟體工程師按照CPU暫存器和硬體線路的不同自行設計的,MIPS、ARM或PPC的plat_irq_dispatch( )都會不一樣。縱使SoC的CPU核心都是ARM,但因為SoC是不同牌子的,它們的plat_irq_dispatch也會不一樣。這就是為何在Linux的術語裡,會有CPU和Machine兩種稱呼,前者易懂,後者簡言之,就是指特定的板子。



電子郵件:look@compotechasia.com

聯繫電話:886-2-27201789       分機請撥:11