linux驅(qū)動基礎(chǔ)知識講解-精品課件_第1頁
linux驅(qū)動基礎(chǔ)知識講解-精品課件_第2頁
linux驅(qū)動基礎(chǔ)知識講解-精品課件_第3頁
linux驅(qū)動基礎(chǔ)知識講解-精品課件_第4頁
linux驅(qū)動基礎(chǔ)知識講解-精品課件_第5頁
已閱讀5頁,還剩67頁未讀 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

1、Linux 驅(qū)動學(xué)習(xí)總結(jié)匯報 2019年11月12日內(nèi)核模塊Bootloder并發(fā)控制中斷處理設(shè)備驅(qū)動的結(jié)構(gòu)Linux內(nèi)核重要子系統(tǒng)系統(tǒng)調(diào)用接口進(jìn)程管理內(nèi)存管理虛擬文件系統(tǒng)網(wǎng)絡(luò)堆棧設(shè)備驅(qū)動最簡單的嵌入式系統(tǒng)MTK的Bootloader在嵌入式操作系統(tǒng)中,BootLoader是在操作系統(tǒng)內(nèi)核運行之前運行。可以初始化硬件設(shè)備、建立內(nèi)存空間映射圖,從而將系統(tǒng)的軟硬件環(huán)境帶到一個合適狀態(tài),以便為最終調(diào)用操作系統(tǒng)內(nèi)核準(zhǔn)備好正確的環(huán)境。MTK的bootloader有兩部分組成:(1)第1部分bootloader,也就是MTK內(nèi)部(in-house)的pre-loader,這部分依賴平臺。(2)第2部分bo

2、otloader,也就是Little Kernel,這部分依賴操作系統(tǒng),負(fù)責(zé)引導(dǎo)linux操作系統(tǒng)和Android框架。源碼位置: vendormediatekproprietarybootablebootloaderMTK的Bootloader正常啟動的主要工作如下:(1)設(shè)備上電后,Boot ROM開始運行。(2)BootROM初始化軟件堆棧(software stack)、通信端口和可引導(dǎo)存儲設(shè)備(比如NAND/EMMC)。(3)BootROM從存儲器中加載pre-loader到內(nèi)部SRAM(ISRAM)中,因為這時候還沒有初始化外部的DRAM。(4)BootROM跳轉(zhuǎn)到pre-load

3、er的入口處并執(zhí)行。(5)Pre-loader初始化DRAM和加載LK到RAM中。(6)Pre-loader跳轉(zhuǎn)到LK中并執(zhí)行,然后LK做一些初始化,比如顯示的初始化等。(7)LK從存儲器中加載引導(dǎo)鏡像(boot image),包括linux內(nèi)核和ramdisk(Android呢?)(8)LK跳轉(zhuǎn)到linux內(nèi)核并執(zhí)行。MTK的Bootloaderpre-loaders中涉及的硬件部分(1)PLL模塊1)PLL模塊用于調(diào)整處理器和外部內(nèi)存的頻率。2)在PLL模塊初始化后,處理器和外部內(nèi)存的頻率可由26MHZ/26MHZ增加到1GHZ/192MHZ。(2)UART模塊1)UART模塊用于調(diào)試或是

4、META(Mobile Engineering Testing Architecture)模式下的握手。2)默認(rèn)情況下,UART4初始化波特率為9216000bps和用于調(diào)試信息的輸出,UART1初始化為115200bps和作為UART META端口。但也可以使用UART1作為調(diào)試或是UART META端口。(3)計時器(timer)模塊這是個基本的模塊,用來計算硬件模塊所需要的延時或是超時時間。(4)內(nèi)存模塊1)Pre-loader由boot ROM加載和在芯片組內(nèi)部的SRAM中執(zhí)行,因為外部的DRAM還沒有初始化。2)為了準(zhǔn)備軟件整個可執(zhí)行環(huán)境,pre-loader采用內(nèi)置的內(nèi)存設(shè)置來初始

5、化DRAM(DRAM is initialized upon pre-loader built-inmemory settigns)。這樣,LK就能夠被加載到DRAM中并執(zhí)行。(5)GPIO模塊(6)PMIC模塊為了提供一些基本的硬件功能,比如控制外設(shè)電源,pre-loader初始化上層模塊(upper modules)。(7)RTC模塊1)當(dāng)通過power按鍵開機(jī)后,pre-loader拉高RTC的PWBB來保持設(shè)備一直有電(keep the device alive)和繼續(xù)引導(dǎo)LK。2)RTC鬧鐘(alarm)有可能是設(shè)備開機(jī)的啟動源,對于這種情況,設(shè)備部需要按power按鍵就可自動啟動。

6、(8)USB模塊當(dāng)USB線插入時,它初始化來和外部工具通信,比如用于升級系統(tǒng)的下載工具或是META模式觸發(fā)器的META工具。(9)NAND模塊(10) MSDC模塊Pre-loader可以從NAND flash或是EMMC中加載LK,這兩者只能選擇其中一種來啟動。LK中涉及的硬件部分LK是第2個loader,它由pre-loader引導(dǎo)并執(zhí)行。從根本上來說(basically),pre-loader已經(jīng)初始化了相關(guān)的硬件模塊,而不需要在LK中重新配置這些模塊了。但一些模塊在LK中被重新復(fù)位來配置硬件寄存器,這樣可創(chuàng)造一個干凈的環(huán)境。比如計時器模塊,在LK中,計時器重新復(fù)位清零硬件計數(shù)來對計時進(jìn)

7、行復(fù)位。所有在LK中需要初始化的列在下面:(1)計時器模塊通過復(fù)位硬件寄存器來復(fù)位計時。(2)串口模塊LK采用串口模塊來配置它的輸入/輸出系統(tǒng),在這個模塊初始化后,我們可以使用LK提供的“printf()”等函數(shù)來使用串口功能。(3)I2C模塊(4)PWM模塊(5)PMIC模塊(6)RTC模塊和計時器模塊一樣,在U-Boot中,I2C/PMIC/RTC重新復(fù)位寄存器來復(fù)位這些模塊。(7)LED模塊通過這power off charging個模塊,設(shè)備能夠通知用戶當(dāng)前的充電狀態(tài)。(8)充電模塊這個模塊負(fù)責(zé)關(guān)機(jī)充電(power off charging)、低電壓充電(lower charging

8、in the system)。(9)LCD模塊使用這個模塊,設(shè)備能夠顯示logo或是任何通知的消息。(10) NAND模塊因為U-Boot也需要從flash讀取鏡像(比如內(nèi)核或是ramdisk),所以有必要在U-Boot中初始化NAND相關(guān)的功能。(11) MSDC模塊支持MSDC啟動一些重要的數(shù)據(jù)結(jié)構(gòu)大部分驅(qū)動程序涉及三個重要的內(nèi)核數(shù)據(jù)結(jié)構(gòu):文件操作file_operations結(jié)構(gòu)體文件對象file結(jié)構(gòu)體索引節(jié)點inode結(jié)構(gòu)體Linux設(shè)備驅(qū)動Linux下設(shè)備的屬性設(shè)備的類型:字符設(shè)備、塊設(shè)備、網(wǎng)絡(luò)設(shè)備主設(shè)備號:標(biāo)識設(shè)備對應(yīng)的驅(qū)動程序。一般“一個主設(shè)備號對應(yīng)一個驅(qū)動程序”次設(shè)備號:每個驅(qū)

9、動程序負(fù)責(zé)管理它所驅(qū)動的幾個硬件實例,這些硬件實例則由次設(shè)備號來表示。同一驅(qū)動下的實例編號,用于確定設(shè)備文件所指的設(shè)備??赏ㄟ^ls l “設(shè)備文件名”命令查看設(shè)備的主次設(shè)備號,以及設(shè)備的類型。18分配和釋放字符設(shè)備號編寫驅(qū)動程序要做的第一件事,為字符設(shè)備獲取一個設(shè)備號。事先知道所需要的設(shè)備編號(主設(shè)備號)的情況:int register_chrdev_region(dev_t first, unsigned count, const char *name)first是要分配的起始設(shè)備編號值。 first的次設(shè)備號通常設(shè)置為0。Count 所請求的連續(xù)設(shè)備編號的個數(shù)。Name設(shè)備名稱,指和該編號

10、范圍建立關(guān)系的設(shè)備。分配成功返回0。19分配和釋放字符設(shè)備號動態(tài)分配設(shè)備編號(主要是主設(shè)備號)int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,const char *name)dev 是一個僅用于輸出的參數(shù), 它在函數(shù)成功完成時保存已分配范圍的第一個編號。baseminor 應(yīng)當(dāng)是請求的第一個要用的次設(shè)備號,它常常是 0. count 和 name 參數(shù)跟request_chrdev_region 的一樣.20分配和釋放字符設(shè)備號不再使用時,釋放這些設(shè)備編號。使用以下函數(shù):void unregiste

11、r_chrdev_region(dev_t from, unsigned count)在模塊的卸載函數(shù)中調(diào)用該函數(shù)。21字符設(shè)備的注冊內(nèi)核內(nèi)部使用struct cdev結(jié)構(gòu)表示字符設(shè)備。編寫設(shè)備驅(qū)動的第二步就是注冊該設(shè)備。包含頭文件。獲取一個獨立的cdev結(jié)構(gòu):struct cdev *my_cdev = cdev_alloc();調(diào)用cdev_init初始化cdev結(jié)構(gòu)體void cdev_init(struct cdev *cdev, struct file_operations *fops);初始化該設(shè)備的所有者字段:dev-cdev.owner = THIS_MODULE;初始化該設(shè)備

12、的可用操作集:dev-cdev.ops = &device_fops;22字符設(shè)備的注冊編寫設(shè)備驅(qū)動的第二步就是注冊該設(shè)備。cdev 結(jié)構(gòu)已建立和初始化, 最后通過cdev_add函數(shù)把它告訴內(nèi)核:int cdev_add(struct cdev *dev, dev_t num, unsigned int count);dev 是要添加的設(shè)備的 cdev 結(jié)構(gòu), num 是這個設(shè)備對應(yīng)的第一個設(shè)備編號,count 是應(yīng)當(dāng)關(guān)聯(lián)到設(shè)備的設(shè)備號的數(shù)目. 卸載字符設(shè)備時,調(diào)用相反的動作函數(shù):void cdev_del(struct cdev *dev);23Linux設(shè)備驅(qū)動的并發(fā)控制24設(shè)備驅(qū)動的并

13、發(fā)控制 在驅(qū)動程序中,當(dāng)多個線程同時訪問相同的資源時,可能會引發(fā)“競態(tài)”,必須對共享資源進(jìn)行并發(fā)控制。并發(fā)和競態(tài)廣泛存在。并發(fā)控制的目的:使得線程訪問共享資源的操作是原子操作。原子操作:在執(zhí)行過程中不會被別的代碼路徑所中斷的操作。 驅(qū)動程序中的全局變量是一種典型的共享資源。25考慮一個非常簡單的共享資源的例子:一個全局整型變量和一個簡單的臨界區(qū),其中的操作僅僅是將整型變量的值增加1: i+ 該操作可以轉(zhuǎn)化成下面三條機(jī)器指令序列:得到當(dāng)前變量i的值并拷貝到一個寄存器中將寄存器中的值加1把i的新值寫回到內(nèi)存中 原子操作26Linux內(nèi)核的并發(fā)控制 在內(nèi)核空間的內(nèi)核任務(wù)需要考慮同步內(nèi)核空間中的共享數(shù)

14、據(jù)對內(nèi)核中的所有任務(wù)可見,所以當(dāng)在內(nèi)核中訪問數(shù)據(jù)時,就必須考慮是否會有其他內(nèi)核任務(wù)并發(fā)訪問的可能、是否會產(chǎn)生競爭條件、是否需要對數(shù)據(jù)同步。27確定保護(hù)對象 找出哪些數(shù)據(jù)需要保護(hù)是關(guān)鍵所在內(nèi)核任務(wù)的局部數(shù)據(jù)僅僅被它本身訪問,顯然不需要保護(hù)。如果數(shù)據(jù)只會被特定的進(jìn)程訪問,也不需加鎖 大多數(shù)內(nèi)核數(shù)據(jù)結(jié)構(gòu)都需要加鎖:若有其它內(nèi)核任務(wù)可以訪問這些數(shù)據(jù),那么就給這些數(shù)據(jù)加上某種形式的鎖;若任何其它東西能看到它,那么就要鎖住它。 Linux內(nèi)核的并發(fā)控制28Linux內(nèi)核的并發(fā)控制并發(fā)控制的機(jī)制中斷屏蔽,原子數(shù)操作,自旋鎖和信號量都是解決并發(fā)問題的機(jī)制。中斷屏蔽很少被單獨使用,原子操作只能針對整數(shù)來進(jìn)行。因

15、此自旋鎖和信號量應(yīng)用最為廣泛。 29鎖機(jī)制可以避免競爭狀態(tài)正如門鎖和門一樣,門后的房間可想象成一個臨界區(qū)。在一段時間內(nèi),房間里只能有一個內(nèi)核任務(wù)存在,當(dāng)一個任務(wù)進(jìn)入房間后,它會鎖住身后的房門;當(dāng)它結(jié)束對共享數(shù)據(jù)的操作后,就會走出房間,打開門鎖。如果另一個任務(wù)在房門上鎖時來了,那么它就必須等待房間內(nèi)的任務(wù)出來并打開門鎖后,才能進(jìn)入房間。 加鎖機(jī)制 30任何要訪問臨界資源的代碼首先都需要占住相應(yīng)的鎖,這樣該鎖就能阻止來自其它內(nèi)核任務(wù)的并發(fā)訪問: 任務(wù) 1 試圖鎖定隊列 成功:獲得鎖 訪問隊列 為隊列解除鎖 任務(wù)2 試圖鎖定隊列失?。旱却?等待 等待 成功:獲得鎖 訪問隊列 為隊列解除鎖加鎖機(jī)制 3

16、1原子數(shù)操作整型原子數(shù)操作原子變量初始化atomic_t test = ATOMIC_INIT(i);設(shè)置原子變量的值void atomic_set(atomic_t *v, int i)獲得原子變量的值atomic_read(v)原子變量加void atomic_add(int i, atomic_t *v)原子變量減void atomic_sub(int i, atomic_t *v)32原子數(shù)操作整型原子數(shù)操作原子變量的自增操作void atomic_inc(atomic_t *v)原子變量的自減操作void atomic_dec(atomic_t *v)操作并測試 (測試其是否為0,0

17、為true,否為false)atomic_inc_and_test(atomic_t *v)atomic_dec_and_test(atomic_t *v)int atomic_sub_and_test(int i, atomic_t *v)操作并返回 (返回新值)int atomic_add_return(int i, atomic_t *v)int atomic_sub_return(int i, atomic_t *v)33原子數(shù)操作原子位操作設(shè)置位void set_bit(int nr, volatile unsigned long * addr)清除位void clear_bit(i

18、nt nr, volatile unsigned long * addr)改變位change_bit(nr,p)測試位test_bit(int nr, const volatile unsigned long * p)測試并操作位test_and_set_bit(nr,p)34自旋鎖自旋鎖是專為防止多處理器并發(fā)而引入的一種鎖,它在內(nèi)核中大量應(yīng)用于中斷處理等部分。而對于單處理器來說,防止中斷處理中的并發(fā)可簡單采用關(guān)閉中斷的方式,不需要自旋鎖。 自旋鎖最多只能被一個內(nèi)核任務(wù)持有,若一個內(nèi)核任務(wù)試圖請求一個已被持有的自旋鎖,那么這個任務(wù)就會一直進(jìn)行忙循環(huán),也就是旋轉(zhuǎn),等待鎖重新可用。 自旋鎖可以在任

19、何時刻防止多于一個的內(nèi)核任務(wù)同時進(jìn)入臨界區(qū),因此這種鎖可有效地避免多處理器上并發(fā)運行的內(nèi)核任務(wù)競爭共享資源。 35自旋鎖自旋鎖的初衷就是:在短期間內(nèi)進(jìn)行輕量級的鎖定。一個被爭用的自旋鎖使得請求它的線程在等待鎖重新可用的期間進(jìn)行自旋(特別浪費處理器時間),所以自旋鎖不應(yīng)該被持有時間過長。如果需要長時間鎖定的話, 最好使用信號量。 36自旋鎖自旋鎖防止在不同CPU上的執(zhí)行單元對共享資源的同時訪問,以及不同進(jìn)程上下文互相搶占導(dǎo)致的對共享資源的非同步訪問。在單CPU且不可搶占的內(nèi)核下,自旋鎖的所有操作都是空操作。 自旋鎖不允許任務(wù)睡眠。37自旋鎖自旋鎖的基本形式如下:spin_lock(&mr_loc

20、k);/*臨界區(qū)*/spin_unlock(&mr_lock);38自旋鎖自旋鎖原語要求包含文件是 . 鎖的類型是 spinlock_t.鎖的兩種初始化方法:spinlock_t my_lock = SPIN_LOCK_UNLOCKED;void spin_lock_init(spinlock_t *lock);進(jìn)入一個臨界區(qū)前, 必須獲得需要的 lock。void spin_lock(spinlock_t *lock);自旋鎖等待是不可中斷的。一旦你調(diào)用spin_lock, 將自旋直到鎖變?yōu)榭捎?。釋放一個鎖:void spin_unlock(spinlock_t *lock);39自旋鎖關(guān)中

21、斷的自旋鎖Spin_lock_irq( )Spin_unlock_irq( )Spin_lock_irqsave ( )Spin_unlock_irqrestore ( )40信號量Linux中的信號量是一種睡眠鎖。如果有一個任務(wù)試圖獲得一個已被持有的信號量時,信號量會將其推入等待隊列,然后讓其睡眠。當(dāng)持有信號量的進(jìn)程將信號量釋放后,在等待隊列中的一個任務(wù)將被喚醒,從而便可以獲得這個信號量。信號量的睡眠特性,使得信號量適用于鎖會被長時間持有的情況;信號量的操作信號量支持兩個原子操作P()和V(),前者做測試操作,后者叫做增加操作。Linux中分別叫做down()和up()。 41信號量42信號

22、量43Linux信號量的實現(xiàn)內(nèi)核代碼必須包含 ,才能使用信號量。相關(guān)的類型是 struct semaphore信號量的定義struct semaphore atomic_t count; int sleepers; wait_queue_head_t wait; 44Linux信號量的實現(xiàn)信號量的聲明和初始化直接創(chuàng)建一個信號量 struct semaphore * sem;接著使用 sema_init 來初始化這個信號量:void sema_init(struct semaphore *sem, int val);互斥模式的信號量聲明,內(nèi)核提供宏定義.DECLARE_MUTEX(name);信

23、號量初始化為 1DECLARE_MUTEX_LOCKED(name);信號量初始化為045自旋鎖忙等待,無調(diào)度開銷;進(jìn)程搶占被禁止;鎖定期間不能休眠;信號量拿不到就切換進(jìn)程,有調(diào)度開銷;鎖定期間可以休眠;46Linux 的中斷處理 47為什么會有中斷中斷最初是為克服對I/O接口控制采用程序查詢所帶來的處理器低效率而產(chǎn)生的。處理器速度一般比外設(shè)快很多用輪詢的方式來查詢設(shè)備的狀態(tài),CPU效率不高,CPU和外設(shè)不能并行工作。中斷機(jī)制讓CPU啟動設(shè)備后,就去處理其他任務(wù),只有當(dāng)外設(shè)真正完成數(shù)據(jù)傳輸?shù)臏?zhǔn)備,請求CPU服務(wù)的時候,CPU才轉(zhuǎn)過來處理外設(shè)的請求。48中斷和異常外部中斷:外部設(shè)備所發(fā)出的I/O

24、請求。隨著計算機(jī)系統(tǒng)結(jié)構(gòu)的不斷改進(jìn)以及應(yīng)用技術(shù)的日益提高,中斷的適用范圍也隨之?dāng)U大,出現(xiàn)了所謂的內(nèi)部中斷(或叫異常)。異常:為解決機(jī)器運行時所出現(xiàn)的某些隨機(jī)事件及編程方便而出現(xiàn)的。49I/O中斷處理為了保證系統(tǒng)對外部的響應(yīng),一個中斷處理程序必須被盡快的完成。因此,把所有的操作都放在中斷處理程序中并不合適Linux中把緊隨中斷要執(zhí)行的操作分為三類緊急的(critical)一般關(guān)中斷運行。諸如對PIC應(yīng)答中斷,對PIC或是硬件控制器重新編程,或者修改由設(shè)備和處理器同時訪問的數(shù)據(jù)非緊急的(noncritical)如修改那些只有處理器才會訪問的數(shù)據(jù)結(jié)構(gòu)(例如按下一個鍵后讀掃描碼),這些也要很快完成,因

25、此由中斷處理程序立即執(zhí)行,不過一般在開中斷的情況下50I/O中斷處理Linux中把緊隨中斷要執(zhí)行的操作分為三類非緊急可延遲的(noncritical deferrable)這些操作可以被延遲較長的時間間隔而不影響內(nèi)核操作,有興趣的進(jìn)程將會等待數(shù)據(jù)。內(nèi)核用下半部分這樣一個機(jī)制來在一個更為合適的時機(jī)用獨立的函數(shù)來執(zhí)行這些操作。如把緩沖區(qū)內(nèi)容拷貝到某個進(jìn)程的地址空間(例如把鍵盤緩沖區(qū)內(nèi)容發(fā)送到終端處理程序進(jìn)程)。51注冊中斷服務(wù)例程 中斷號是一個寶貴且常常有限的資源。內(nèi)核維護(hù)一個中斷號的注冊表。要使用中斷,就要進(jìn)行中斷號的申請,也就是IRQ(Interrupt ReQuirement)。只有當(dāng)設(shè)備需

26、要中斷的時候才申請占用一個IRQ,或者是在申請IRQ時采用共享中斷的方式,讓更多的設(shè)備使用中斷。52注冊中斷服務(wù)例程 在 實現(xiàn)中斷注冊接口:int request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_regs *),unsigned long flags,const char *dev_name, void *dev_id);void free_irq(unsigned int irq, void *dev_id);request_irq 的返回值是 0 指示申請成功,為負(fù)值時表示錯誤碼。函數(shù)返

27、回 -EBUSY 表示已經(jīng)有另一個驅(qū)動占用了所要申請的中斷線。53注冊中斷服務(wù)例程 request_irq的參數(shù)說明:unsigned int irq, 要申請的中斷號。irqreturn_t (*handler)(int, void *, struct pt_regs *),要安裝的中斷處理函數(shù)指針。const char *dev_name, 用在 /proc/interrupts 中顯示中斷的擁有者。54注冊中斷服務(wù)例程 request_irq的參數(shù)說明:unsigned long flags,與中斷管理相關(guān)的位掩碼選項。Flags的每個位有不同含義SA_INTERRUPT 當(dāng)該位被設(shè)置時

28、, 表示這是一個“快速”中斷。快速中斷處理例程運行時,屏蔽中斷。SA_SHIRQ 這個位表示中斷可以在設(shè)備間共享。void *dev_id這個指針用于共享的中斷號。做為驅(qū)動程序的私有數(shù)據(jù)區(qū)(可用來識別那個設(shè)備產(chǎn)生的中斷)。不使用共享中斷線方式時,可設(shè)置為NULL。55實現(xiàn)中斷處理例程中斷處理例程特別之處:在中斷時間內(nèi)運行,不能向用戶空間發(fā)送或者接收數(shù)據(jù)。不能做任何導(dǎo)致休眠的操作。不能調(diào)用schedule函數(shù)。無論快速還是慢速中斷處理例程,都應(yīng)該設(shè)計成執(zhí)行時間盡可能短。56實現(xiàn)中斷處理例程中斷處理函數(shù)的參數(shù)和返回值irqreturn_t (*handler)(int irq, void *dev

29、_id, struct pt_regs *regs)Irq 中斷號Dev_id 驅(qū)動程序可用的數(shù)據(jù)區(qū),通??蓚鬟f指向描述設(shè)備的數(shù)據(jù)結(jié)構(gòu)指針。struct pt_regs *regs,保存了處理器進(jìn)入中斷代碼之前的cpu寄存器的值。一般驅(qū)動可不要。57實現(xiàn)中斷處理例程啟動和禁用中斷驅(qū)動禁止特定中斷線的中斷:#include .void disable_irq(int irq);void enable_irq(int irq);禁止所有中斷void local_irq_save(unsigned long flags);local_irq_save 在當(dāng)前處理器上禁止中斷遞交, 在保存當(dāng)前中斷狀態(tài)

30、到 flags。void local_irq_disable(void);local_irq_disable 關(guān)閉本地中斷遞交而不保存狀態(tài);58實現(xiàn)中斷處理例程打開中斷:void local_irq_restore(unsigned long flags);恢復(fù)由 local_irq_save 存儲于 flags 的狀態(tài), 而 local_irq_enable 無條件打開中斷.void local_irq_enable(void);59頂半部和底半部中斷處理的一個主要問題是如何在處理中進(jìn)行長時間的任務(wù)。響應(yīng)一次設(shè)備中斷需要完成一定數(shù)量的工作,但是中斷處理需要很快完成并且不使中斷阻塞太長。Lin

31、ux把中斷處理例程分兩部分:頂部分:實際響應(yīng)中斷的例程。底部分:被頂部分調(diào)用,通過開中斷的方式進(jìn)行。兩種機(jī)制實現(xiàn):Tasklet工作隊列work queue60頂半部和底半部頂半部頂半部的功能是“登記中斷”,當(dāng)一個中斷發(fā)生時,它進(jìn)行相應(yīng)地硬件讀寫后就把中斷例程的下半部掛到該設(shè)備的底半部執(zhí)行隊列中去。頂半部執(zhí)行的速度就會很快,可以服務(wù)更多的中斷請求。底半部僅有“登記中斷”是遠(yuǎn)遠(yuǎn)不夠的,因為中斷的事件可能很復(fù)雜。Linux引入了一個底半部,來完成中斷事件的絕大多數(shù)使命。底半部和頂半部最大的不同是底半部是可中斷的,而頂半部是不可中斷的,底半部幾乎做了中斷處理程序所有的事情,而且可以被新的中斷打斷!底

32、半部則相對來說并不是非常緊急的,通常還是比較耗時的,因此由系統(tǒng)自行安排運行時機(jī),不在中斷服務(wù)上下文中執(zhí)行。 61軟中斷和 tasklet 的關(guān)系如下圖: 小任務(wù)機(jī)制tasklet62小任務(wù)機(jī)制taskletksoftirqd是一個后臺運行的內(nèi)核線程,它會周期的遍歷軟中斷的向量列表,如果發(fā)現(xiàn)哪個軟中斷向量被掛起了( pend ),就執(zhí)行對應(yīng)的處理函數(shù)。tasklet 所對應(yīng)的處理函數(shù)就是tasklet_action,這個處理函數(shù)在系統(tǒng)啟動時初始化軟中斷時,就在軟中斷向量表中注冊。 63小任務(wù)以數(shù)據(jù)結(jié)構(gòu)的形式存在:struct tasklet_structstruct tasklet_struct

33、 *next;unsigned long state;atomic_t count;void (*func)(unsigned long);unsigned long data;每個結(jié)構(gòu)一個函數(shù)指針func,指向自定義的函數(shù)。這就是我們要執(zhí)行的小任務(wù)函數(shù)。小任務(wù)機(jī)制tasklet64tasklet 的接口DECLARE_TASKLET(name,function,data) 此接口初始化一個 tasklet ;name 是 tasklet 的名字, function 是執(zhí)行 tasklet 的函數(shù); data 是 unsigned long 類型的 function 參數(shù)。 static in

34、line void tasklet_schedule(struct tasklet_struct *t) 調(diào)度執(zhí)行指定的tasklet。將定義后的 tasklet 掛接到 cpu 的 tasklet_vec 鏈表。而且會引起一個軟 tasklet 的軟中斷 , 既把 tasklet 對應(yīng)的中斷向量掛起 (pend) 。 小任務(wù)機(jī)制tasklet65工作隊列 工作隊列類似 taskets,允許內(nèi)核代碼請求在將來某個時間調(diào)用一個函數(shù),不同在于:tasklet 在軟件中斷上下文中運行,所以 tasklet 代碼必須是原子的。而工作隊列函數(shù)在一個特殊內(nèi)核進(jìn)程上下文運行,有更多的靈活性,且能夠休眠。tasklet 只能在最初被提交的處理器上運行,這只是工作隊列

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論