一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

Linux內(nèi)核中的中斷棧與內(nèi)核棧的補(bǔ)充說(shuō)明

 Liucw2012 2012-04-10

http://www./forum.php/forum.php?mod=viewthread&tid=499&extra=page%3D1

中斷棧與內(nèi)核棧的話題更多地屬于內(nèi)核的范疇,所以在《深入Linux設(shè)備驅(qū)動(dòng)程序內(nèi)核機(jī)制》第5章“中斷處理”當(dāng)中,基本上沒(méi)怎么涉及到上述內(nèi)容,只是在5.4節(jié)有些許的文字討論中斷棧在中斷嵌套情形下可能的溢出問(wèn)題。

本貼在這個(gè)基礎(chǔ)上對(duì)內(nèi)核棧與中斷棧的話題做些補(bǔ)充,討論基于x86 32位系統(tǒng),因?yàn)?4位系統(tǒng)下Linux內(nèi)核關(guān)于棧的支持原理上是相同的,不過(guò)也有些特性屬于64位特有的,比如IST(Interrupt Stack Table),如果可能將來(lái)會(huì)在processor版塊發(fā)個(gè)帖子專門討論。

1. x86下內(nèi)核棧與中斷棧是否共享的問(wèn)題

我們知道Linux系統(tǒng)下每個(gè)用戶進(jìn)程都有個(gè)task_struct對(duì)象來(lái)表示,同時(shí)在處理器層面還對(duì)應(yīng)一個(gè)TSS(Task State Segment),當(dāng)中斷發(fā)生時(shí),用戶進(jìn)程或者處于用戶態(tài)(特權(quán)級(jí)3)或者處于內(nèi)核態(tài)(特權(quán)級(jí)0),如果是在用戶態(tài),那么會(huì)發(fā)生棧的切換問(wèn)題,也就是會(huì)切換到內(nèi)核態(tài)的棧,如果是在內(nèi)核態(tài),那么就沒(méi)有棧切換的問(wèn)題。但是x86處理器在特權(quán)級(jí)0上只有一個(gè)ESP,這意味著中斷發(fā)生后,只能使用一個(gè)棧,這個(gè)棧就是內(nèi)核棧(kernel stack)。處理器的硬件邏輯會(huì)將被中斷進(jìn)程的下條指令(CS,EIP)以及EFLAG壓入棧,當(dāng)然如果發(fā)生用戶態(tài)棧向內(nèi)核態(tài)棧的切換,處理器還會(huì)把用戶態(tài)的(SS, ESP)也壓入棧,此時(shí)使用的就是內(nèi)核棧。這個(gè)行為屬于處理器的硬件邏輯范疇,不是系統(tǒng)軟件的行為。

至于x86下內(nèi)核棧與中斷棧是否共享的問(wèn)題,其實(shí)是個(gè)內(nèi)核設(shè)計(jì)的問(wèn)題,換言之,中斷??膳c內(nèi)核棧共享,也可重新分配一個(gè)獨(dú)立的中斷棧。2.4的內(nèi)核版本似乎采用中斷棧與內(nèi)核棧共享的設(shè)計(jì),因?yàn)檫@種設(shè)計(jì)的好處是代碼相對(duì)簡(jiǎn)單,如前所述,直接使用ESP0就可以了,但是負(fù)面因素是中斷棧如果發(fā)生嵌套,可能破壞內(nèi)核棧的一些數(shù)據(jù),因?yàn)楫吘构蚕?,所以??臻g有時(shí)候難免會(huì)捉襟見(jiàn)肘。所以在2.5內(nèi)核版本開(kāi)發(fā)中,來(lái)自IBM的一位大俠曾提交過(guò)一個(gè)補(bǔ)丁,試圖在中斷發(fā)生時(shí),從內(nèi)核棧switch到一個(gè)獨(dú)立的中斷棧中,后來(lái)也不知道被內(nèi)核社區(qū)采納了沒(méi)有,總之我現(xiàn)在在3.2的內(nèi)核源碼中沒(méi)有看到那位仁兄的補(bǔ)丁代碼了,當(dāng)然也可能是那個(gè)補(bǔ)丁已經(jīng)長(zhǎng)成現(xiàn)在的代碼樣子了。

現(xiàn)在的Linux內(nèi)核中采用的是內(nèi)核棧與中斷棧分離的設(shè)計(jì),下面我們從源碼層面來(lái)看一看這種分離是如何完成的。

內(nèi)核棧與中斷棧分離的核心代碼發(fā)生在do_IRQ() --> handle_irq() --> execute_on_irq_stack()
最后一個(gè)函數(shù)字面上的意思大約是在中斷棧中執(zhí)行中斷處理例程,也就是說(shuō)中斷的處理函數(shù)會(huì)在獨(dú)立于被中斷進(jìn)程的上下文中執(zhí)行。execute_on_irq_stack的函數(shù)實(shí)現(xiàn)為:

<arch/x86/kernel/irq_32.c>

  1. static inline int
  2. execute_on_irq_stack(int overflow, struct irq_desc *desc, int irq)
  3. {
  4. union irq_ctx *curctx, *irqctx;
  5. u32 *isp, arg1, arg2;

  6. curctx = (union irq_ctx *) current_thread_info();
  7. irqctx = __this_cpu_read(hardirq_ctx);

  8. /*
  9. * this is where we switch to the IRQ stack. However, if we are
  10. * already using the IRQ stack (because we interrupted a hardirq
  11. * handler) we can't do that and just have to keep using the
  12. * current stack (which is the irq stack already after all)
  13. */
  14. if (unlikely(curctx == irqctx))
  15. return 0;

  16. /* build the stack frame on the IRQ stack */
  17. isp = (u32 *) ((char *)irqctx + sizeof(*irqctx));
  18. irqctx->tinfo.task = curctx->tinfo.task;
  19. irqctx->tinfo.previous_esp = current_stack_pointer;

  20. /*
  21. * Copy the softirq bits in preempt_count so that the
  22. * softirq checks work in the hardirq context.
  23. */
  24. irqctx->tinfo.preempt_count =
  25. (irqctx->tinfo.preempt_count & ~SOFTIRQ_MASK) |
  26. (curctx->tinfo.preempt_count & SOFTIRQ_MASK);

  27. if (unlikely(overflow))
  28. call_on_stack(print_stack_overflow, isp);

  29. asm volatile("xchgl %%ebx,%%esp \n"
  30. "call *%%edi \n"
  31. "movl %%ebx,%%esp \n"
  32. : "=a" (arg1), "=d" (arg2), "=b" (isp)
  33. : "0" (irq), "1" (desc), "2" (isp),
  34. "D" (desc->handle_irq)
  35. : "memory", "cc", "ecx");
  36. return 1;
  37. }
復(fù)制代碼
代碼中的curctx=(union irq_ctx *) current_thread_info()用來(lái)獲得當(dāng)前被中斷進(jìn)程的上下文,irqctx = __this_cpu_read(hardirq_ctx)用來(lái)獲得hardirq的上下文,其實(shí)就是獲得獨(dú)立的中斷棧起始地址。中斷棧的大小與layout與內(nèi)核棧是完全一樣的。接下來(lái)isp指向中斷棧棧頂,最后的堆棧切換發(fā)生在那段匯編代碼中:當(dāng)前進(jìn)程的內(nèi)核棧ESP指針保存在EBX中,而中斷棧的isp則賦值給了ESP,這樣接下來(lái)的代碼就將使用中斷棧了。call語(yǔ)句負(fù)責(zé)調(diào)用desc->handle_irq()函數(shù),這里會(huì)進(jìn)行中斷處理,設(shè)備驅(qū)動(dòng)程序注冊(cè)的中斷處理函數(shù)會(huì)被調(diào)用到。當(dāng)中斷處理例程結(jié)束返回時(shí),ESP將重新指向被中斷進(jìn)程的內(nèi)核棧。(此處我們應(yīng)該注意到內(nèi)核棧中還保留著中斷發(fā)生時(shí)處理器硬件邏輯所壓入的CS, EIP等寄存器,所以在內(nèi)核棧中做中斷返回是完全正確的)。
2. 中斷棧的分配

獨(dú)立的中斷棧所在內(nèi)存空間的分配發(fā)生在arch/x86/kernel/irq_32.c的irq_ctx_init函數(shù)中(如果是多處理器系統(tǒng),那么每個(gè)處理器都會(huì)有一個(gè)獨(dú)立的中斷棧),函數(shù)使用__alloc_pages在低端內(nèi)存區(qū)分配2個(gè)物理頁(yè)面(2的THREAD_ORDER次方),也就是8KB大小的空間。有趣的是,這個(gè)函數(shù)還會(huì)為softirq分配一個(gè)同樣大小的獨(dú)立堆棧,如此說(shuō)來(lái),softirq將不會(huì)在hardirq的中斷棧上執(zhí)行,而是在自己的上下文中執(zhí)行。

總結(jié)一下,系統(tǒng)中每個(gè)進(jìn)程都會(huì)擁有屬于自己的內(nèi)核棧,而系統(tǒng)中每個(gè)CPU都將為中斷處理準(zhǔn)備了兩個(gè)獨(dú)立的中斷棧,分別是hardirq棧和softirq棧。草圖如下:
 

關(guān)于在中斷處理函數(shù)中涉及到的阻塞問(wèn)題,我個(gè)人的觀點(diǎn)是:現(xiàn)實(shí)中絕對(duì)不要這么干,其中的原因就不多說(shuō)了。從內(nèi)核理論實(shí)現(xiàn)的角度,調(diào)度其他進(jìn)程是可行的。

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

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多

    加勒比系列一区二区在线观看| 亚洲妇女作爱一区二区三区| 日本丰满大奶熟女一区二区| 免费在线观看激情小视频| 日韩精品成区中文字幕| 久久国产精品熟女一区二区三区| 欧美加勒比一区二区三区| 欧美大粗爽一区二区三区| 沐浴偷拍一区二区视频| 亚洲精品国产精品日韩| 午夜激情视频一区二区| 日韩欧美亚洲综合在线| 国产又色又爽又黄又免费| 91久久国产福利自产拍| 久久久免费精品人妻一区二区三区 | 麻豆最新出品国产精品| 欧美人与动牲交a精品| 少妇人妻无一区二区三区| 加勒比人妻精品一区二区| 欧美日韩综合在线精品| 成人精品一区二区三区综合| 国产精品久久久久久久久久久痴汉| 欧美日本亚欧在线观看| 欧美成人一区二区三区在线| 亚洲国产日韩欧美三级| 久久精品亚洲欧美日韩| 亚洲综合色婷婷七月丁香| 中文字幕欧美视频二区| 99久久精品久久免费| 免费在线播放一区二区| 日韩性生活视频免费在线观看| 91人妻人澡人人爽人人精品| 久久香蕉综合网精品视频| 内射精子视频欧美一区二区| 成人国产激情福利久久| 中国一区二区三区人妻| 国产91人妻精品一区二区三区| 大屁股肥臀熟女一区二区视频| 熟妇人妻av中文字幕老熟妇| 尤物久久91欧美人禽亚洲| 国产一区二区熟女精品免费|