久久精品精选,精品九九视频,www久久只有这里有精品,亚洲熟女乱色综合一区
    分享

    IA32上Linux內(nèi)核中斷機(jī)制分析

     Liucw2012 2012-03-30
    IA32上Linux內(nèi)核中斷機(jī)制分析

    Author:  albcamus
    Email:   albcamus@
    Homepage:http://www.
    Date:    2005-11-21

    IA32Linux內(nèi)核中斷機(jī)制分析



    中斷是計(jì)算機(jī)與外界聯(lián)系的唯一途徑。本文將分析在IA-32體系結(jié)構(gòu)上的Linux內(nèi)核對待中斷系統(tǒng)的處理,針對的是2.6內(nèi)核,引用的代碼則具體則是2.6.14的。

    一。幾個(gè)相關(guān)概念的澄清

    1, 中斷信號:

    在電路級別來說,中斷就是輸送到CPUINTR引腳上的電平信號。

    2, 可編程中斷控制器(PICProgrammable Interrupt Controller):

    PIC是在計(jì)算機(jī)外部設(shè)備與CPU之間的芯片,它負(fù)責(zé)把自己接收到的外部中斷信號,提交給CPU。在80386中,PIC是兩片i8259A芯片級聯(lián);在Pentium以及后來的CPU中,集成了一個(gè)叫做高級可編程中斷控制器(Advanced Programmable Interrupt Controller)的PIC。如果你想用IA32處理器搭建SMP系統(tǒng),則APIC是必不可少的。

    3, 中斷向量與中斷號:

    中斷向量是IntelIA-32 CPU角度看到的中斷信號劃分;中斷號則是Linux系統(tǒng)對外部中斷的號碼分配。當(dāng)外設(shè)把中斷信號遞送給PIC時(shí),與之關(guān)聯(lián)的是一個(gè)“中斷號”(每個(gè)中斷號對應(yīng)一條中斷線,從軟件的角度來看,這兩個(gè)術(shù)語可以混用);當(dāng)PIC把這個(gè)中斷信號發(fā)送給CPU時(shí),與之關(guān)聯(lián)的是一個(gè)“中斷向量”。

    IA-32體系結(jié)構(gòu)中,所有的異常和不可屏蔽中斷(Non-Maskable Interrupt)的中斷向量都是Intel預(yù)先定義的,軟件無法更改;可屏蔽中斷的中斷向量可以通過編程來更改。在Linux上,0號中斷(也就是時(shí)鐘中斷)對應(yīng)的中斷向量是0x20,也就是十進(jìn)制的32

    4, 異常(Exception

    顧名思義,異常是指CPU檢測到了某種不正常的情形出現(xiàn)。CPU產(chǎn)生的異常是不可屏蔽的(eflags寄存器的IF位對異常不起作用),根據(jù)異常處理程序返回時(shí),是否需要重新執(zhí)行引發(fā)異常的那條指令,又可以把異常分為3種:

    1)故障(Fault)。故障是比較輕微的異常,返回時(shí)重新執(zhí)行引發(fā)故障的那條指令。

    2)陷阱(Trap)。陷阱處理返回時(shí),不重新執(zhí)行引發(fā)陷阱的那條指令。

    3)中止(Abort)。中止是嚴(yán)重的異常,將導(dǎo)致任務(wù)的中止而不會(huì)返回。

    還有一種是程序產(chǎn)生的異常,如INT3指令、BOUND指令等。CPU把這種異常當(dāng)作是陷阱來處理。

    5, 中斷描述表IDT

    異常與中斷發(fā)生時(shí),都需要到IDT中查找相關(guān)信息,以找到對應(yīng)的處理程序以及其他動(dòng)作。需要注意的是,保護(hù)模式下發(fā)生權(quán)限提升時(shí),中斷穿越的是中斷門,而異常穿越的是陷阱門。二者的區(qū)別是:當(dāng)CPU穿越中斷門時(shí),是自動(dòng)關(guān)中斷的;而穿越異常門則不會(huì)。


    二。重要數(shù)據(jù)結(jié)構(gòu)與函數(shù)

    在系統(tǒng)引導(dǎo)期間,需要初試化中斷處理(asm/i386/kernel/entry.S):

    422 #define BUILD_INTERRUPT(name, nr) \

    423 ENTRY(name) \

    424 pushl $nr-256; \ #這里得到一個(gè)負(fù)數(shù),因?yàn)檎龜?shù)留給系統(tǒng)調(diào)用

    425 SAVE_ALL \ #保存寄存器

    426 movl %esp,%eax; \

    427 call smp_/**/name; \

    428 jmp ret_from_intr;


    其中,SAVE_ALL宏就是用來保存寄存器的。


    內(nèi)核書籍中經(jīng)常提到的中斷上下文,指的是內(nèi)核正在運(yùn)行中斷服務(wù)程序或softirq,無法代表當(dāng)前進(jìn)程的情形。中斷上下文沒有自己專有的堆棧,相反,它借用被中斷進(jìn)程的內(nèi)核堆棧──IA-32上的Linux默認(rèn)這個(gè)堆棧只有8k大小,而且很可能在處理中斷的過程中又被另一個(gè)中斷源中斷。因此如果你自己編寫中斷處理程序,遞歸層次太深或者函數(shù)局部變量太大,都有可能導(dǎo)致棧溢出。(i386有一個(gè)4KStacks補(bǔ)丁,如果編譯時(shí)打開該選項(xiàng),則中斷上下文使用獨(dú)立的棧,而不占用被中斷進(jìn)程的。)


    include/linux/irq.h文件中,定義了一個(gè)中斷描述數(shù)組iqr_desc[NR_IRQS],每一個(gè)中斷向量都與它的一個(gè)元素相關(guān)聯(lián):


    70 typedef struct irq_desc {

    71 hw_irq_controller *handler;

    72 void *handler_data;

    73 struct irqaction *action; /* IRQ action list */

    74 unsigned int status; /* IRQ status */

    75 unsigned int depth; /* nested irq disables */

    76 unsigned int irq_count; /* For detecting broken interrupts */

    77 unsigned int irqs_unhandled;

    78 spinlock_t lock;

    79 #if defined (CONFIG_GENERIC_PENDING_IRQ) || defined (CONFIG_IRQBALANCE)

    80 unsigned int move_irq; /* Flag need to re-target intr dest*/

    81 #endif

    82 } ____cacheline_aligned irq_desc_t; /*告訴GCCCPUL1告訴緩存對齊*/

    83

    84 extern irq_desc_t irq_desc [NR_IRQS];


    當(dāng)一個(gè)中斷發(fā)生時(shí),內(nèi)核的處理是這樣的(arch/i386/kernel/entry.S):


    416 common_interrupt:

    417 SAVE_ALL

    418 movl %esp,%eax

    419 call do_IRQ

    420 jmp ret_from_intr


    SAVE_ALL宏定義在entry.S中,負(fù)責(zé)保存寄存器,再將%esp寄存器移送到%eax中,調(diào)用do_IRQ()函數(shù)(arch/i386/kernel/irq.c:


    /*

    * do_IRQ()函數(shù)負(fù)責(zé)處理所有的外部設(shè)備中斷(處理器間中斷由它們各自

    * 的處理函數(shù)來處理

    */

    fastcall unsigned int do_IRQ(struct pt_regs *regs)

    {

    /* high bits used in ret_from_ code */

    int irq = regs->orig_eax & 0xff;

    /* i386上如果定義了CONFIG_4KSTAKS,就申請獨(dú)立的棧,而不占用被中斷進(jìn)程的*/

    #ifdef CONFIG_4KSTACKS

    union irq_ctx *curctx, *irqctx;

    u32 *isp;

    #endif


    irq_enter();

    #ifdef CONFIG_DEBUG_STACKOVERFLOW

    /* 檢查堆棧溢出的代碼,此處省去。 */

    #endif


    #ifdef CONFIG_4KSTACKS


    curctx = (union irq_ctx *) current_thread_info();

    irqctx = hardirq_ctx[smp_processor_id()];


    /*

    * 這是我們切換到中斷棧的地方。然而,如果我們已經(jīng)在使用中斷棧(也

    * 就是說,我們這次是中斷了一個(gè)中斷處理程序),我們就不切換棧,而

    * 是繼續(xù)使用當(dāng)前的棧(此時(shí),“當(dāng)前的棧”是一個(gè)中斷棧)

    */

    if (curctx != irqctx) {

    int arg1, arg2, ebx;


    /* build the stack frame on the IRQ stack */

    isp = (u32*) ((char*)irqctx + sizeof(*irqctx));

    irqctx->tinfo.task = curctx->tinfo.task;

    irqctx->tinfo.previous_esp = current_stack_pointer;


    asm volatile(

    " xchgl %%ebx,%%esp \n"

    " call __do_IRQ \n"

    " movl %%ebx,%%esp \n"

    : "=a" (arg1), "=d" (arg2), "=b" (ebx)

    : "0" (irq), "1" (regs), "2" (isp)

    : "memory", "cc", "ecx"

    );

    } else

    #endif

    __do_IRQ(irq, regs); //真正的中斷處理


    irq_exit(); /* 如果需要,處理softirq。注意,這里有兩種可能不需要處理softirq1, local_softirq_pending為假;2,我們剛剛是中斷了一個(gè)中斷,嵌套中斷沒有最終返回之前,softirq是不能處理的。 */


    return 1;

    }

    注意,fastcall是在include/asm-i386/linkage.h中定義的宏,它指導(dǎo)GCC連接時(shí)把fastcall修飾的函數(shù)的前三個(gè)參數(shù)用寄存器傳遞。另外一個(gè)類似的宏asmlinkage則告訴GCC不要用寄存器傳遞參數(shù),asmlinkagefastcall不能共存。




    上面的do_IRQ()函數(shù)調(diào)用的__do_IRQ()代碼如下(arch/i386/kernel/irq.c


    fastcall unsigned int __do_IRQ(unsigned int irq, struct pt_regs *regs)

    {

    irq_desc_t *desc = irq_desc + irq; /* 找到在irq_desc數(shù)組中的位置 */

    struct irqaction * action; /* 取得相應(yīng)的irqaction結(jié)構(gòu) */

    unsigned int status;


    kstat_this_cpu.irqs[irq]++;

    if (CHECK_IRQ_PER_CPU(desc->status)) {

    irqreturn_t action_ret;


    /*

    * 因?yàn)?FONT face=SimSun>irq_desc[]數(shù)組中,每個(gè)CPU占一個(gè)元素,這里的desc就是本CPU

    * 數(shù)據(jù),所以此處不需要加鎖。

    */

    desc->handler->ack(irq);

    action_ret = handle_IRQ_event(irq, regs, desc->action);

    desc->handler->end(irq);

    return 1;

    }


    spin_lock(&desc->lock);

    desc->handler->ack(irq); /* i8259AAPIC應(yīng)答信號 */

    /*

    * REPLAY is when Linux resends an IRQ that was dropped earlier

    * WAITING is used by probe to mark irqs that are being tested

    */

    status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING);

    status |= IRQ_PENDING; /* we _want_ to handle it */


    /*

    * If the IRQ is disabled for whatever reason, we cannot

    * use the action we have.

    */

    action = NULL;

    if (likely(!(status & (IRQ_DISABLED | IRQ_INPROGRESS)))) { /* 判斷該IRQ是否是被禁止的,或者是已經(jīng)在其他CPU上被處理 */

    action = desc->action;

    status &= ~IRQ_PENDING; /* 我們將處理它 */

    status |= IRQ_INPROGRESS; /* 置位IRQ_INPROGRESS,以便其他CPU注意 */

    }

    desc->status = status;


    /*

    * 如果該IRQ沒有處理函數(shù),或者被禁止了,及早離開。

    * 因?yàn)槲覀冎梦涣?FONT face=SimSun>PENDING,如果別的CPU正在處理該IRQ

    * 另一個(gè)實(shí)例,它就會(huì)小心些。

    */

    if (unlikely(!action))

    goto out;


    /*

    * Edge triggered interrupts need to remember

    * pending events.

    * This applies to any hw interrupts that allow a second

    * instance of the same irq to arrive while we are in do_IRQ

    * or in the handler. But the code here only handles the _second_

    * instance of the irq, not the third or fourth. So it is mostly

    * useful for irq hardware that does not mask cleanly in an

    * SMP environment.

    */


    for (;;) {

    irqreturn_t action_ret;


    spin_unlock(&desc->lock);


    action_ret = handle_IRQ_event(irq, regs, action);


    spin_lock(&desc->lock);

    if (!noirqdebug)

    note_interrupt(irq, desc, action_ret, regs);

    if (likely(!(desc->status & IRQ_PENDING)))

    break;

    desc->status &= ~IRQ_PENDING;

    }

    desc->status &= ~IRQ_INPROGRESS;


    out:

    /*

    * ->end()用來處理那些由于別的CPU正在運(yùn)行其處理程序而被禁止的中斷

    */

    desc->handler->end(irq);

    spin_unlock(&desc->lock);


    return 1;

    }


    三。中斷機(jī)制在SMP系統(tǒng)上的變化


    當(dāng)intel考慮如何在IA-32上架構(gòu)SMP時(shí),原來的中斷控制器i8259A就顯得力不從心了。在SMP上,必須考慮外部設(shè)備來的中斷信號如何傳遞給某個(gè)合適的CPU問題,必須考慮IPIInter-Percossor Interrupt,處理器間中斷)問題。IntelPentium之后,在CPU中集成了APIC,在SMP上,主板上有一個(gè)(至少一個(gè),有的主板有多個(gè)IO-APIC,用來更好的分發(fā)中斷信號)全局的APIC,它負(fù)責(zé)從外設(shè)接收中斷信號,再分發(fā)到CPU上,這個(gè)全局的APIC被稱作IO-APIC

    SMP的中斷機(jī)制如下圖所示:




    1SMP系統(tǒng)中的中斷分發(fā)示意圖


    在系統(tǒng)引導(dǎo)的時(shí)候,通過setup_IO_APIC()函數(shù)(arch/i386/kernel/io_apic.c)對IO-APIC進(jìn)行初試化;每個(gè)CPU被激活成為online狀態(tài)的時(shí)候,通過setup_local_APIC()函數(shù)(arch/kernel/i386/apic.c)對本地APIC進(jìn)行初試化。


    SMP系統(tǒng)上,Linux除了處理CPU異常、外部設(shè)備中斷之外,還要處理處理器間中斷。當(dāng)一個(gè)CPU想對另一個(gè)CPU發(fā)送中斷信號時(shí),就在自己的本地APICICR寄存器(Interrupt Command Register,中斷命令寄存器)中存放其中斷向量,和目標(biāo)CPU擁有的本地APIC的標(biāo)識,觸發(fā)中斷。IPI中斷信號經(jīng)由APIC總線傳遞到目標(biāo)APIC,那個(gè)收到中斷的APIC就向自己所屬的CPU發(fā)送一個(gè)中斷。

    Linux針對IA32SMP系統(tǒng)定義了五種IPI

    1, CALL_FUNCTION_VECTOR。發(fā)往自己除外的所有CPU,強(qiáng)制它們執(zhí)行指定的函數(shù);

    2, RESCHEDULE_VECTOR。使被中斷的CPU重新調(diào)度;

    3, INVLIDATE_TLB_VECTOR。使被中斷的CPU廢棄自己的TLB緩存內(nèi)容。

    4, ERROR_APIC_VECTOR

    5, SPUROUS_APIC_VECTOR

    IA-32體系結(jié)構(gòu)中,SMP的高速緩存一致性(Cache Coherence)問題是通過一種叫做總線監(jiān)視(Bus watching,也叫Snoopying)的硬件技術(shù)來解決的。每當(dāng)某個(gè)CPUDMA控制器改寫了某塊內(nèi)存區(qū)域的內(nèi)容(這總是要通過總線來進(jìn)行的,所以逃不過總線監(jiān)視),別的CPU就會(huì)自動(dòng)廢棄緩存了該內(nèi)存區(qū)域的Cache。然而對TLB的情況則有所不同(為什么不同?Intel的手冊說TLB也可以對軟件透明,這里有點(diǎn)疑惑),Linux內(nèi)核中,每個(gè)CPU在改變了頁表的時(shí)候,都需要給其它所有運(yùn)行著與該頁表有關(guān)的任務(wù)的CPU發(fā)送IPI,使它們廢棄自己的TLB內(nèi)容。





    參考:

    Understanding the Linux Kernel2nd

    IA-32 Intel Architecture Software Developer’s Manual, Volume 3: System Programming Guide

      本站是提供個(gè)人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報(bào)。
      轉(zhuǎn)藏 分享 獻(xiàn)花(0

      0條評論

      發(fā)表

      請遵守用戶 評論公約

      類似文章 更多

      主站蜘蛛池模板: 丰满爆乳在线播放| 国产AV无码专区亚洲AV潘金链 | 香蕉久久久久久久AV网站| 久久精品国产亚洲AV麻豆网站 | 亚洲精品综合网二三区| 国产美女MM131爽爽爽| 波多野结衣乳巨码无在线观看| 精品国产精品午夜福利| 三上悠亚久久精品| 日韩中文字幕人妻一区| 亚洲欧美成人综合久久久| 亚洲免费成人av一区| 亚洲国产精品久久久久久无码| 26uuu另类亚洲欧美日本| 丁香婷婷激情俺也去俺来也| 国产在线精品无码二区二区| 国产福利萌白酱在线观看视频| 亚洲国产精品无码中文LV| 卡一卡2卡3卡精品网站| 亚洲夂夂婷婷色拍ww47| 99九九视频高清在线| 国产一区二区四区不卡| 精品人妻无码专区在中文字幕| 亚洲国产精品久久久天堂麻豆宅男| 亚洲国产成人久久精品APP| 亚洲av免费成人在线| 婷婷综合久久中文字幕蜜桃三电影 | 欧美韩中文精品有码视频在线| 五月天婷婷激情无码专区| 美乳丰满人妻无码视频| 大地资源免费视频观看| 免费又黄又爽又猛的毛片| 久久月本道色综合久久| 中文有无人妻VS无码人妻激烈| 无遮挡免费高清羞羞视频| 人妻中文字幕精品系列| 中文成人无码精品久久久| 国产成人午夜福利在线观看| 国产片AV国语在线观看手机版| 性一交一乱一伦一| 亚洲AV伊人久久综合密臀性色|