1. 程式人生 > >嵌入式常見面試題總結(6)

嵌入式常見面試題總結(6)

50,如何編寫一個LINUX驅動?  答:一.在系統的資原始檔程式碼中定義platform_device,裡面填寫對應裝置的外設IO起始地址,地址長度,中斷,DMA資源等資訊資源資訊,並把資源資訊新增到系統啟動初始化流程裡面;

二. 通過module_init(xxx_init)和moule_exit(xxx_init)定義驅動入口和出口函式; 三.寫出模組載入xxx_init()和退出的實際處理函式xxx_exit(),這裡以xxx_init()為例: 在裡面呼叫platform_driver_resigter()註冊一個platform_driver結構體,實現其中的probe()和remove()函式以及driver成員結構體中name和owner成員。

51,簡述LINUX驅動中字元裝置和塊裝置的區別?

答:字元裝置的特點是資料以字元流的方式進行訪問,資料的順序不能錯序,亂序和隨機讀寫,字元裝置核心中不需要讀寫的緩衝,其驅動不支援lseek()函式 塊裝置的特點是資料是固定塊大小(典型值有512位元組,2KB,4KB)進行讀寫,塊裝置可以隨機讀寫,讀寫的時候核心中需要緩衝,驅動支援lseek()函式,塊裝置中資料的訪問需要先mount到LINUX的目錄檔案後才能訪問裡面的資料 LINUX中字元裝置架構相對簡單,應用程式設計的系統呼叫open,close,read,write和ioctl等函式驅動裡面有相應的file_operations結構體裡面的函式與之對應。

LINUX中塊裝置架構相對複雜,應用程式的讀寫會通過塊裝置裡面的檔案系統轉化為讀寫的IO請求,塊裝置驅動裡面通過gendisk結構體抽象塊裝置,並通過對請求佇列的處理來實現對塊裝置的讀寫。

52,試總結微控制器底層開發與LINUX驅動開發有哪些異同?

答:底層的程式包括,核心,bootloader和驅動。基本開發Android硬體產品公司主要需要這一類人。而不同產品中,核心和bootloader變化較小,主要的工作量是在驅動之上。驅動相當於 微控制器程式+linux核心介面。

但是從微控制器轉型為Linux驅動開發的,幾個主要問題的,是程式碼量急劇增加,在微控制器中有一些習慣在驅動開發裡變成致命的陷阱。比如不喜歡用巨集,在驅動大量用到核心複雜結構而微控制器往往自寫,還有一個併發處理,也是一個難點。

相同點: 微控制器開發和LINUX的驅動開發都有對硬體的操作,最底層對硬體的暫存器操作,對時序的理解是一致的。 不同點: 1.微控制器是對外設的IO實地址進行直接操作,而LINUX裡面,由於使能了MMU,所以對外設IO地址的操作必須先通過ioremap()或者通過靜態對映,把外設IO地址對映到核心的虛擬地址空間後才能正確操作。 2.在微控制器編寫對應裝置的驅動不用考慮系統太多的系統分層問題,重用其他的程式碼量比較小,而LINUX採用分層抽象的思想,在LINUX中編寫裝置驅動,要按照LINUX已經搭建好的層次結構進行驅動編寫,經常呼叫LINUX提供的函式和機制,程式碼重用性大。 3.由於LINUX是一個多工的系統,即使在單核CPU上也存在資源競爭的情況(思考一下,LINUX裡面那些地方可能導致資源競爭),所以在對驅動的編寫的時候,對競爭資源需要採用一定的資源保護機制,比如原子變數,自旋鎖等 4.微控制器中斷處理時,一般直接在產生中斷的進入到中斷處理函式裡面在關中斷的情況下處理完中斷就可以。而LINUX裡面把中斷分為2部分,上半部分和下班部分,在上半部分中,是在關中斷情況下,只做最基本和最核心的部分,然後在下半部分在開中斷情況下,通過LINUX提供的各種機制來處理(思考: LINUX中斷的底半部分有哪些模式)。

53.請從網絡卡、USB HOST、LCD驅動器、NAND FLASH、WIFI 、音訊晶片中選擇一個或者2個(可以以具體的晶片為例),對下面的問題做答:  1)如果是外部擴充套件晶片,請說出你用的晶片的型號  2)畫出上題中你選定相應硬體模組與CPU的主要引腳連線 

3) 編寫上題中你選定相應硬體模組相應LINUX驅動的流程? 

54,linux驅動分類?

答:Linux裝置驅動的分類   (1)字元裝置。   (2) 塊裝置。   (3) 網路裝置。   字元裝置指那些必須以序列順序依次進行訪問的裝置,如觸控式螢幕、磁帶驅動器、滑鼠等。塊裝置可以用任意順序進行訪問,以塊為單位進行操作,如硬碟、軟碟機等。字元裝置不經過系統的快速緩衝,而塊裝置經過系統的快速緩衝。但是,字元裝置和塊裝置並沒有明顯的界限,如對於Flash裝置,符合塊裝置的特點,但是我們仍然可以把它作為一個字元裝置來訪問。網路裝置在Linux裡做專門的處理。Linux的網路系統主要是基於BSD unix的socket 機制。在系統和驅動程式之間定義有專門的資料結構(sk_buff)進行資料的傳遞。系統裡支援對傳送資料和接收資料的快取,提供流量控制機制,提供對多協議的支援。55,訊號量與自旋鎖?

答:自旋鎖是專為防止多處理器併發而引入的一種鎖,它應用於中斷處理等部分。對於單處理器來說,防止中斷處理中的併發可簡單採用關閉中斷的方式,不需要自旋鎖。自旋鎖最多隻能被一個核心任務持有,如果一個核心任務試圖請求一個已被爭用(已經被持有)的自旋鎖,那麼這個任務就會一直進行忙迴圈——旋轉——等待鎖重新可用。要是鎖未被爭用,請求它的核心任務便能立刻得到它並且繼續進行。自旋鎖可以在任何時刻防止多於一個的核心任務同時進入臨界區,因此這種鎖可有效地避免多處理器上併發執行的核心任務競爭共享資源。事實上,自旋鎖的初衷就是:在短期間內進行輕量級的鎖定。一個被爭用的自旋鎖使得請求它的執行緒在等待鎖重新可用的期間進行自旋(特別浪費處理器時間),所以自旋鎖不應該被持有時間過長。如果需要長時間鎖定的話, 最好使用訊號量。但是自旋鎖節省了上下文切換的開銷。 自旋鎖的基本形式如下:   spin_lock(&mr_lock);   //臨界區   spin_unlock(&mr_lock); 因為自旋鎖在同一時刻只能被最多一個核心任務持有,所以一個時刻只有一個執行緒允許存在於臨界區中。這點很好地滿足了對稱多處理機器需要的鎖定服務。在單處理器上,自旋鎖僅僅當作一個設定核心搶佔的開關。如果核心搶佔也不存在,那麼自旋鎖會在編譯時被完全剔除出核心。簡單的說,自旋鎖在核心中主要用來防止多處理器中併發訪問臨界區,防止核心搶佔造成的競爭。另外自旋鎖不允許任務睡眠(持有自旋鎖的任務睡眠會造成自死鎖——因為睡眠有可能造成持有鎖的核心任務被重新排程,而再次申請自己已持有的鎖),它能夠在中斷上下文中使用。

死鎖:假設有一個或多個核心任務和一個或多個資源,每個核心都在等待其中的一個資源,但所有的資源都已經被佔用了。這便會發生所有核心任務都在相互等待,但它們永遠不會釋放已經佔有的資源,於是任何核心任務都無法獲得所需要的資源,無法繼續執行,這便意味著死鎖發生了。自死瑣是說自己佔有了某個資源,然後自己又申請自己已佔有的資源,顯然不可能再獲得該資源,因此就自縛手腳了。遞迴使用一個自旋鎖就會出現這種情況。

訊號量是一種睡眠鎖。如果有一個任務試圖獲得一個已被持有的訊號量時,訊號量會將其推入等待佇列,然後讓其睡眠。這時處理器獲得自由去執行其它程式碼。當持有訊號量的程序將訊號量釋放後,在等待佇列中的一個任務將被喚醒,從而便可以獲得這個訊號量。   訊號量的睡眠特性,使得訊號量適用於鎖會被長時間持有的情況;只能在程序上下文中使用,因為中斷上下文中是不能被排程的;另外當代碼持有訊號量時,不可以再持有自旋鎖。 訊號量基本使用形式為:   static DECLARE_MUTEX(mr_sem);//宣告互斥訊號量   if(down_interruptible(&mr_sem))            //可被中斷的睡眠,當訊號來到,睡眠的任務被喚醒            //臨界區        up(&mr_sem); 訊號量和自旋鎖區別   從嚴格意義上講,訊號量和自旋鎖屬於不同層次的互斥手段,前者的實現有賴於後者。 注意以下原則:    如果程式碼需要睡眠——這往往是發生在和使用者空間同步時——使用訊號量是唯一的選擇。由於不受睡眠的限制,使用訊號量通常來說更加簡單一些。如果需要在自旋鎖和訊號量中作選擇,應該取決於鎖被持有的時間長短。理想情況是所有的鎖都應該儘可能短的被持有,但是如果鎖的持有時間較長的話,使用訊號量是更好的選擇。另外,訊號量不同於自旋鎖,它不會關閉核心搶佔,所以持有訊號量的程式碼可以被搶佔。這意味者訊號量不會對影響排程反應時間帶來負面影響。 自旋鎖對訊號量 需求              建議的加鎖方法 低開銷加鎖           優先使用自旋鎖 短期鎖定            優先使用自旋鎖 長期加鎖            優先使用訊號量 中斷上下文中加鎖        使用自旋鎖 持有鎖是需要睡眠、排程     使用訊號量