国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
linux中斷源碼分析1/4--概述
http://blog.chinaunix.net/uid-26772321-id-4992230.html
2015

可編程中斷控制器(PIC、APIC)

  為了方便說明,這里我們將PIC和APIC統(tǒng)稱為中斷控制器。中斷控制器是作為中斷(IRQ)和CPU核之間的一個橋梁而存在的,每個CPU內(nèi)部都有一個自己的中斷控制器,中斷線并不是直接與CPU核相連,而是與CPU內(nèi)部或外部的中斷控制器相連。而為什么叫做可編程中斷控制器,是因為其本身有一定的寄存器,CPU可以通過操作設置中斷控制器屏蔽某個中斷引腳的信號,實現(xiàn)硬件上的中斷屏蔽。中斷控制器也可以級聯(lián)提供更多的中斷線,具體如下:


  如上圖,CPU的INTR與中斷控制器的INT相連,INTA與ACK相連,當一個外部中斷發(fā)生時(比如鍵盤中斷IRQ1),中斷控制器與CPU交互操作如下:

  1. IRQ1發(fā)生中斷,主中斷控制器接收到中斷信號,檢查中斷屏蔽寄存器IRQ1是否被屏蔽,如果屏蔽則忽略此中斷信號。
  2. 將中斷控制器中的中斷請求寄存器對應的IRQ1位置位,表示收到IRQ1中斷。
  3. 中斷控制器拉高INT引腳電平,告知CPU有中斷發(fā)生。
  4. CPU每執(zhí)行完一條指令時,都會檢查INTR引腳是否被拉高,這里已被拉高。
  5. CPU檢查EFLAGS寄存器的中斷運行標志位IF是否為1,若為1,表明允許中斷,通過INTA向中斷控制器發(fā)出應答。
  6. 中斷控制器接收到應答信號,將IRQ1的中斷向量號發(fā)到數(shù)據(jù)總線上,此時CPU會通過數(shù)據(jù)總線讀取IRQ1的中斷向量號。
  7. 最后,如果中斷控制器需要EOI(End of Interrupt)信號,CPU則會發(fā)送,否則中斷控制器自動將INT拉低,并清除IRQ1對應的中斷請求寄存器位。

 

  在linux內(nèi)核中,用struct irq_chip結構體描述一個可編程中斷控制器,它的整個結構和調(diào)度器中的調(diào)度類類似,里面定義了中斷控制器的一些操作,如下:

  1. struct irq_chip {
  2.     /* 中斷控制器的名字 */
  3.     const char *name;
  4.     /* 控制器初始化函數(shù) */
  5.     unsigned int (*irq_startup)(struct irq_data *data);
  6.     /* 控制器關閉函數(shù) */
  7.     void (*irq_shutdown)(struct irq_data *data);
  8.     /* 使能irq操作,通常是直接調(diào)用irq_unmask(),通過data參數(shù)指明irq */
  9.     void (*irq_enable)(struct irq_data *data);
  10.     /* 禁止irq操作,通常是直接調(diào)用irq_mask,嚴格意義上,他倆其實代表不同的意義,disable表示中斷控制器根本就不響應該irq,而mask時,中斷控制器可能響應該irq,只是不通知CPU */
  11.     void (*irq_disable)(struct irq_data *data);
  12.     /* 用于CPU對該irq的回應,通常表示cpu希望要清除該irq的pending狀態(tài),準備接受下一個irq請求 */
  13.     void (*irq_ack)(struct irq_data *data);
  14.     /* 屏蔽irq操作,通過data參數(shù)表明指定irq */
  15.     void (*irq_mask)(struct irq_data *data);
  16.     /* 相當于irq_mask() + irq_ack() */
  17.     void (*irq_mask_ack)(struct irq_data *data);
  18.     /* 取消屏蔽指定irq操作 */
  19.     void (*irq_unmask)(struct irq_data *data);
  20.     /* 某些中斷控制器需要在cpu處理完該irq后發(fā)出eoi信號 */
  21.     void (*irq_eoi)(struct irq_data *data);
  22.     /* 用于設置該irq和cpu之間的親和力,就是通知中斷控制器,該irq發(fā)生時,那些cpu有權響應該irq */
  23.     int (*irq_set_affinity)(struct irq_data *data, const struct cpumask *dest, bool force);
  24.     int (*irq_retrigger)(struct irq_data *data);
  25.     /* 設置irq的電氣觸發(fā)條件,例如 IRQ_TYPE_LEVEL_HIGH(電平觸發(fā)) 或 IRQ_TYPE_EDGE_RISING(邊緣觸發(fā)) */
  26.     int (*irq_set_type)(struct irq_data *data, unsigned int flow_type);
  27.     /* 通知電源管理子系統(tǒng),該irq是否可以用作系統(tǒng)的喚醒源 */
  28.     int (*irq_set_wake)(struct irq_data *data, unsigned int on);

  29.     void (*irq_bus_lock)(struct irq_data *data);
  30.     void (*irq_bus_sync_unlock)(struct irq_data *data);

  31.     void (*irq_cpu_online)(struct irq_data *data);
  32.     void (*irq_cpu_offline)(struct irq_data *data);

  33.     void (*irq_suspend)(struct irq_data *data);
  34.     void (*irq_resume)(struct irq_data *data);
  35.     void (*irq_pm_shutdown)(struct irq_data *data);

  36.     void (*irq_calc_mask)(struct irq_data *data);

  37.     void (*irq_print_chip)(struct irq_data *data, struct seq_file *p);
  38.     int (*irq_request_resources)(struct irq_data *data);
  39.     void (*irq_release_resources)(struct irq_data *data);

  40.     unsigned long flags;
  41. };


中斷描述符表(IDT)

  在中斷系統(tǒng)中有兩個名字很相像的結構,就是中斷描述符表中斷描述符數(shù)組。這里我們先說說中斷描述符表。  一個系統(tǒng)中的中斷和異常加起來一共是256個,它們以向量的形式保存在中斷描述符表中,每一個向量是8字節(jié)(整個表大小就是8 x 256=2048字節(jié)),其主要保存著權限位和向量對應的中斷或異常處理程序的入口地址。而一般的,linux會將中斷描述符表中的0~31用于非屏蔽中斷和異常,其他的中斷用于32~255之間。CPU把中斷描述符表的向量類型分為三種類型:任務門、中斷門、陷阱門。CPU為了防止惡意程序訪問中斷,限制了中斷門的權限,而在某些時候,用戶程序又必須使用中斷,所以Linux把中斷描述符的中斷向量類型改為了5種:中斷門,系統(tǒng)門,系統(tǒng)中斷門,陷阱門,任務門。

中斷門

        用戶程序不能訪問的CPU中斷門(權限字段為0),所有的中斷處理程序都是這個,被限定在內(nèi)核態(tài)執(zhí)行。會清除IF標志,屏蔽可屏蔽中斷。

系統(tǒng)門

        用戶程序可以訪問的CPU陷阱門(權限字段為3)。我們的系統(tǒng)調(diào)用就是通過向量128系統(tǒng)門進入的。

系統(tǒng)中斷門

        能夠被用戶進程訪問的CPU陷阱門(權限字段為3),作為一個特別的異常處理所用。

陷阱門

        用戶進程不能訪問的CPU陷阱門(權限字段為0),大部分異常處理程序入口都為陷阱門。

任務門

        用戶進程不能訪問的CPU任務門(權限字段為0),''Double fault"異常處理程序入口。

 

  當我們發(fā)生異常或中斷時,系統(tǒng)首先會判斷權限字段(安全處理),權限通過則進入指定的處理函數(shù),而所有的中斷門的中斷處理函數(shù)都是同一個,它首先是一段匯編代碼,匯編代碼操作如下:

  • 執(zhí)行SAVE_ALL宏,保存中斷向量號寄存器上下文至當前運行進程的內(nèi)核棧或者硬中斷請求棧(當內(nèi)核棧大小為8K時保存在內(nèi)核棧,若為4K,則保存在硬中斷請求棧)。
  • 調(diào)用do_IRQ()函數(shù)。
  • 跳轉(zhuǎn)到ret_from_intr,這是一段匯編代碼,主要用于判斷是否需要進行調(diào)度。

 

 

中斷處理

  每個能夠產(chǎn)生中斷的設備或者模塊都會在內(nèi)核中注冊一個中斷服務例程(ISR),當產(chǎn)生中斷時,中斷處理程序會被執(zhí)行,在中斷處理程序中,首先會保存中斷向量號和上下文,之后執(zhí)行中斷線對應的中斷服務例程。對于CPU來說,中斷線是非常寶貴的資源,而由于計算機的發(fā)展,外部設備數(shù)量和種類越來越多,導致了中斷線資源不足的情況,linux為了應對這種情況,實現(xiàn)了兩種中斷線分配方式,分別是:共享中斷線,中斷線動態(tài)分配。

共享中斷線

  多個設備共用一條中斷線,當此條中斷線發(fā)生中斷時,因為不可能預先知道哪個特定的設備產(chǎn)生了中斷,因此,這條中斷線上的每個中斷服務例程都會被執(zhí)行,以驗證是哪個設備產(chǎn)生的中斷(一般的,設備產(chǎn)生中斷時,會標記自己的狀態(tài)寄存器,中斷服務例程通過檢查每個設備的狀態(tài)寄存器來查找產(chǎn)生中斷的設備)。

中斷線動態(tài)分配

  一條中斷線在可能使用的時刻才與一個設備驅(qū)動程序關聯(lián)起來,這樣一來,即使幾個硬件設備并不共享中斷線,同一個中斷向量也可以由這幾個設備在不同時刻運行。

 

  共享中斷線的分配方式是比較常見的,一次典型的基于共享中斷線的中斷處理流程如下:


  由于中斷處于中斷上下文中,所以在中斷處理過程中,會有以下幾個特性:

  • 中斷處理程序正在運行時,CPU會通知中斷控制器屏蔽產(chǎn)生此中斷的中斷線。此中斷線發(fā)出的信號被暫時忽略,當中斷處理程序結束時恢復此中斷線。
  • 在中斷服務例程的設計中,原則上是立即處理緊急的操作,將非緊急的操作延后處理(交給軟中斷進行處理)。
  • 中斷處理程序是運行在中斷上下文,但是其是代表進程運行的,因此它所代表的進行必須處于TASK_RUNNING狀態(tài),否則可能出現(xiàn)僵死情況,因此在中斷處理程序中不能執(zhí)行任何阻塞過程。

 

 

中斷描述符

  中斷描述符用于描述IRQ線的屬性與狀態(tài),每個IRQ都有它自己的中斷描述符,這些中斷描述符用一個數(shù)組保存, 這個數(shù)組就是中斷描述符數(shù)組,整個中斷描述符數(shù)組長度為NR_IRQS(通常為224)項。當產(chǎn)生一個中斷或者異常時,首先會從中斷描述符表中獲取到一個中斷向量號時(此中斷向量號有可能表示中斷,也可能表示的是一個異常),如果是一個中斷導致的,會執(zhí)行do_IRQ()函數(shù),而在do_IRQ()函數(shù)中,會根據(jù)中斷向量號,從中斷描述符數(shù)組中獲取對應的中斷描述符,如下圖:


  整個中斷描述符結構如下:

  1. struct irq_desc {
  2.     struct irq_data irq_data;
  3.     /* irq的統(tǒng)計信息,在proc中可查到 */
  4.     unsigned int __percpu *kstat_irqs;
  5.     
  6.     /* 回調(diào)函數(shù),當此中斷產(chǎn)生中斷時,會調(diào)用handle_irq,在handle_irq中進行遍歷irqaction鏈表
  7.      * handle_simple_irq 用于簡單處理;
  8.      * handle_level_irq 用于電平觸發(fā)中斷的流控處理;
  9.      * handle_edge_irq 用于邊沿觸發(fā)中斷的流控處理;
  10.      * handle_fasteoi_irq 用于需要響應eoi的中斷控制器;
  11.      * handle_percpu_irq 用于只在單一cpu響應的中斷;
  12.      * handle_nested_irq 用于處理使用線程的嵌套中斷;
  13.      */
  14.     irq_flow_handler_t handle_irq;
  15. #ifdef CONFIG_IRQ_PREFLOW_FASTEOI
  16.     irq_preflow_handler_t preflow_handler;
  17. #endif
  18.     /* 中斷服務例程鏈表 */
  19.     struct irqaction *action; /* IRQ action list */
  20.     /* 狀態(tài) */
  21.     unsigned int status_use_accessors;
  22.     /* 函數(shù)調(diào)用中使用,另一個名稱為istate */
  23.     unsigned int core_internal_state__do_not_mess_with_it;
  24.     /* 嵌套深度,中斷線被激活顯示0,如果為正數(shù),表示被禁止次數(shù) */
  25.     unsigned int depth; /* nested irq disables */
  26.     unsigned int wake_depth; /* nested wake enables */
  27.     /* 此中斷線上發(fā)生的中斷次數(shù) */
  28.     unsigned int irq_count; /* For detecting broken IRQs */
  29.     /* 上次發(fā)生未處理中斷時的jiffies值 */
  30.     unsigned long last_unhandled; /* Aging timer for unhandled count */
  31.     /* 中斷線上無法處理的中斷次數(shù),如果當?shù)?00000次中斷發(fā)生時,有超過99900次是意外中斷,系統(tǒng)會禁止這條中斷線 */
  32.     unsigned int irqs_unhandled;
  33.     atomic_t threads_handled;
  34.     int threads_handled_last;
  35.     /**/
  36.     raw_spinlock_t lock;
  37.     struct cpumask *percpu_enabled;
  38. #ifdef CONFIG_SMP
  39.     /* CPU親和力關系,其實就是每個CPU是占一個bit長度,某CPU上置為1表明該CPU可以進行這個中斷的處理 */
  40.     const struct cpumask *affinity_hint;
  41.     struct irq_affinity_notify *affinity_notify;
  42. #ifdef CONFIG_GENERIC_PENDING_IRQ
  43.     /* 用于調(diào)整irq在各個cpu之間的平衡 */
  44.     cpumask_var_t pending_mask;
  45. #endif
  46. #endif
  47.     unsigned long threads_oneshot;
  48.     atomic_t threads_active;
  49.     /* 用于synchronize_irq(),等待該irq所有線程完成 */
  50.     wait_queue_head_t wait_for_threads;
  51. #ifdef CONFIG_PM_SLEEP
  52.     /* irqaction數(shù)量 */
  53.     unsigned int nr_actions;
  54.     unsigned int no_suspend_depth;
  55.     unsigned int force_resume_depth;
  56. #endif
  57. #ifdef CONFIG_PROC_FS
  58.     /* 指向與IRQn相關的/proc/irq/n目錄的描述符 */
  59.     struct proc_dir_entry *dir;
  60. #endif
  61.     int parent_irq;
  62.     struct module *owner;
  63.     /*/proc/interrupts所顯示名稱 */
  64.     const char *name;
  65. } ____cacheline_internodealigned_in_smp;
  core_internal_state__do_not_mes_with_it成員是用于記錄此中斷線狀態(tài)的,中斷線狀態(tài)有如下幾種形式:

  1. IRQS_AUTODETECT     /* 該IRQ線用來進行硬件設備探測 */
  2.     IRQS_SPURIOUS_DISABLED /* 該IRQ線被禁止,是由于產(chǎn)生了欺騙性中斷 */
  3.     IRQS_POLL_INPROGRESS /* 該IRQ進行輪詢檢查是否發(fā)生中斷 */
  4.     IRQS_ONESHOT        /* 此IRQ沒有在主處理函數(shù)中進行unmasked處理 */
  5.     IRQS_REPLAY         /* IRQ線已被禁止,但前一個出現(xiàn)的中斷還沒有被應答 */
  6.     IRQS_WAITING        /* 進行硬件設備探測時,會將所有沒有掛載中斷服務程序的IRQ線狀態(tài)設置為IRQS_WAITING,如果該IRQ上有中斷產(chǎn)生,就清除這個狀態(tài),可以推斷哪些引腳產(chǎn)生過中斷 */
  7.     IRQS_PENDING        /* IRQ已經(jīng)被應答(掛起),但是內(nèi)核還沒有進行處理 */
  8.     IRQS_SUSPENDED       /* 此IRQ被延遲 */


中斷服務例程(ISR)

  中斷服務例程用于描述一個設備的中斷處理(區(qū)別與中斷處理函數(shù)),每個申請了中斷的外部設備都會有一個中斷服務例程,其作用就是執(zhí)行對應設備的中斷處理。當多個設備共享IRQ線時,內(nèi)核會將此IRQ線上所有設備的中斷服務例程組織成一個鏈表并保存在中斷描述符中,當此IRQ線產(chǎn)生中斷時,中斷處理函數(shù)會依次執(zhí)行此IRQ線上的中斷服務例程。內(nèi)核使用struct irqaction描述一個中斷服務例程:

  1. struct irqaction {
  2.     /* 此中斷服務例程的中斷處理函數(shù) */
  3.     irq_handler_t handler;
  4.     /* 設備ID,一般用于指向中斷處理時需要的數(shù)據(jù)結構傳入handler */
  5.     void *dev_id;
  6.     /* 此中斷服務例程在CPU上所對應的設備ID */
  7.     void __percpu *percpu_dev_id;
  8.     /* 鏈表中下一個中斷服務例程 */
  9.     struct irqaction *next;
  10.     /* 進行中斷處理的內(nèi)核線程執(zhí)行函數(shù) */
  11.     irq_handler_t thread_fn;
  12.     /* 一個內(nèi)核線程,用于執(zhí)行中斷處理 */
  13.     struct task_struct *thread;
  14.     /* IRQ線,IRQ號 */
  15.     unsigned int irq;
  16.     unsigned int flags;
  17.     unsigned long thread_flags;
  18.     unsigned long thread_mask;
  19.     const char *name;
  20.     /* 指向/proc/irq/n目錄的描述符 */
  21.     struct proc_dir_entry *dir;
  22. } ____cacheline_internodealigned_in_smp;


irq_stat數(shù)組

  此數(shù)組包含NR_CPUS個元素,系統(tǒng)中每個CPU對應數(shù)組中的一個元素。每個元素的類型為irq_cpustat_t,其包含幾個計數(shù)器和內(nèi)核記錄CPU正在做什么的標志。


  1. typedef struct {
  2.     unsigned int __softirq_pending; /* 表示掛起的軟中斷,每一位表示一個軟中斷,為1表示掛起 */
  3.     long idle_timestamp; /* CPU變?yōu)榭臻e的時間點 */

  4.     /* 硬中斷統(tǒng)計. */
  5.     unsigned int irq_timer_count; /* 定時器中斷統(tǒng)計 */
  6.     unsigned int irq_syscall_count; /* 系統(tǒng)調(diào)用中斷統(tǒng)計 */
  7.     unsigned int irq_resched_count;
  8.     unsigned int irq_hv_flush_count;
  9.     unsigned int irq_call_count;
  10.     unsigned int irq_hv_msg_count;
  11.     unsigned int irq_dev_intr_count;

  12. } ____cacheline_aligned irq_cpustat_t;

數(shù)據(jù)結構總結

  到此,在中斷處理中所涉及的幾個重要的數(shù)據(jù)結構已經(jīng)說明,其最主要的數(shù)據(jù)結構為:中斷描述符(struct irq_desc),中斷控制器描述符(struct irq_chip),中斷服務例程(struct irqaction)。它們的組織形式如下:




本站僅提供存儲服務,所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權內(nèi)容,請點擊舉報
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
Linux中斷實現(xiàn)淺析
request
內(nèi)核隨記(一)——理解中斷(3)
Linux中斷基礎構架
linux kernel的中斷子系統(tǒng)之(四):High level irq event handler
Linux 系統(tǒng)內(nèi)核初始化過程 | Tek
更多類似文章 >>
生活服務
分享 收藏 導長圖 關注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服