日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

Linux 0.11 内核解析:中断相关(1)asm.s文件中断处理分析

發布時間:2023/11/30 linux 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux 0.11 内核解析:中断相关(1)asm.s文件中断处理分析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

0 源代碼

有兩個版本的,一個是帶中文注釋,Intel格式的;一個是不帶注釋是AT&T格式的。

Linux 0.11 中文注釋版
Linux 0.11 源碼,基于《Linux內核完全注釋》趙炯

1 asm.s 文件

我們先假設該文件處理的中斷是無特權過渡的情況(具體是不是暫時不知道)。

我們看一下,當中斷發生且被檢測到之后,硬件做了什么。

我們可以看到,中斷被檢測到之后,一些必要的信息被壓棧了。

在80386手冊中提到,中斷發生之后,一些必要的,為了中斷程序結束之后返回原程序繼續執行的信息,會被壓棧,就像最開始那個圖看到的內樣,這里分成了4種情況,我們只討論無特權轉換的兩種情況,分別輸有出錯碼的異常和無處錯碼的異常。

這個壓棧過程是硬件完成的,回顧一下我們之前的知識

在中斷發生之后,80386執行了

  • 保存斷點(將EFLAGS,CS,EIP依次壓棧)
  • 識別中斷源
  • 至于怎么通過中斷號,找到對應的中斷服務程序,我們后面說。

    2 無處錯碼中斷

    源代碼在kernel/asm.s文件中

    _divide_error: # int0 除法錯中斷,中斷錯誤碼是0pushl $_do_divide_error # 用于打印除法錯中斷的錯誤信息的函數,在traps.c實現# 中斷處理程序的地址入棧 no_error_code:# 保護現場xchgl %eax,(%esp) # eax的值入棧,eax保存中斷處理程序地址pushl %ebxpushl %ecxpushl %edxpushl %edipushl %esipushl %ebppush %ds # 占4字節而非2字節push %espush %fspushl $0 # "error code" 中斷有無錯誤碼,是有相關規定的lea 44(%esp),%edxpushl %edx# 設置內核數據段選擇符,設置好數據尋址的基址movl $0x10,%edxmov %dx,%dsmov %dx,%esmov %dx,%fscall *%eax # 執行中斷處理程序,C語言函數do_divide_error# 恢復現場addl $8,%esppop %fspop %espop %dspopl %ebppopl %esipopl %edipopl %edxpopl %ecxpopl %ebxpopl %eaxiret # 返回中斷處理之前的程序,繼續執行后續指令_debug:pushl $_do_int3 # _do_debugjmp no_error_code

    我們通過畫堆棧內存圖的方式分析一下這個過程。

    2.1 檢測中斷后,硬件完成的事情

    硬件完成的事情其實就是壓棧,壓棧之后的內存圖是:

    2.2 進入中斷服務程序

    在識別到中斷源之后,通過某種方式,CPU獲取的中斷服務程序的CS:EIP,進入了終端服務程序,我們這里以debug為例子。

    注意,所有的無出錯號的中斷,默認當成出錯號是0,會在保護現場的時候入棧,這個其實是配合實際出錯號是0的除法錯中斷,先不管它。

    pushl $_do_int3 # _do_debug 中斷服務程序主體,中斷處理程序 jmp no_error_code

    執行完這兩條指令,內存分布是:

    然后就跳轉到了no_error_code。

    它主要分成三大部分

  • 保護現場
  • 執行中斷處理程序
  • 恢復現場和返回原程序

  • 下面是保護現場的部分

    # 保護現場xchgl %eax,(%esp) # eax的值入棧,eax保存中斷處理程序地址pushl %ebxpushl %ecxpushl %edxpushl %edipushl %esipushl %ebppush %ds # 占4字節而非2字節push %espush %fspushl $0 # "error code" 中斷有無錯誤碼,是有相關規定的lea 44(%esp),%edxpushl %edx

    然后是執行中斷處理程序的部分,會有數據段選擇符是設定,先暫時不管,這個其實就是類似于8086設置ds的值。

    # 設置內核數據段選擇符,設置好數據尋址的基址movl $0x10,%edxmov %dx,%dsmov %dx,%esmov %dx,%fscall *%eax # 執行中斷處理程序,C語言函數do_debug

    緊接著是恢復現場和返回原程序

    # 恢復現場addl $8,%esppop %fspop %espop %dspopl %ebppopl %esipopl %edipopl %edxpopl %ecxpopl %ebxpopl %eaxiret # 返回中斷處理之前的程序,繼續執行后續指令

    這里需要補充

    iret的作用

    中斷門或陷阱門中斷服務例程的返回,按照之前入棧的相反順序將EIP、CS先后出棧;再將EFLAGS標志寄存器出棧,恢復現場(IRET指令)。

    簡而言之,就是把最開始保存斷點的部分依次出棧,從而回到源程序。

    我們看一下這個過程的內存分布

    其中

    • esp0對應push $0
    • esp1對應pushl %edx
    • esp2對應addl $8,%esp
    • esp3對應popl %eax

    還有一個比較值得關心的

    call指令執行前后,寄存器的變化

    這一點,使用C語言分析一下函數調用,看看前后變化,在學堂在線《Linux內核分析》中科大孟寧老師MOOC講解很清晰。


    后面的內些的無處錯碼的函數,與上面的例子完全一樣

    _debug:pushl $_do_int3 # _do_debugjmp no_error_code_nmi:pushl $_do_nmijmp no_error_code_int3:pushl $_do_int3jmp no_error_code_overflow:pushl $_do_overflowjmp no_error_code_bounds:pushl $_do_boundsjmp no_error_code_invalid_op:pushl $_do_invalid_opjmp no_error_code_coprocessor_segment_overrun:pushl $_do_coprocessor_segment_overrunjmp no_error_code_reserved:pushl $_do_reservedjmp no_error_code_irq13:pushl %eaxxorb %al,%aloutb %al,$0xF0movb $0x20,%aloutb %al,$0x20jmp 1f 1: jmp 1f 1: outb %al,$0xA0popl %eaxjmp _coprocessor_error

    這些都一樣,其中比較特別的是,Linux0.11實現了幾個用戶自定義中斷,_irq13就是int45。

    2.2.1 其他細節的說明

    這里保存中斷號0,以及保存最開始的堆棧地址esp的值,似乎沒啥用,以后再說吧。

    這里比較奇怪的是,除法零中斷,它的錯誤碼是0,使用的是無處錯碼的處理程序,如果錯誤碼在之前就被壓入棧的話,iret指令執行之前,指向的應該是error code 0,而不是eip,除非這個除法零中斷的處理比較特殊,不將出錯碼壓棧,與其他無處錯碼的中斷等同對待,才比較合理。以后再看看這個細節,暫時先放放。

    3 有出錯碼中斷

    結構與無處錯碼中斷基本一致,這里簡要說明一下區別。

    首先,硬件處理有區別,壓棧之后,會把出錯碼壓棧。


    然后,在保存現場的處理上,有一些不同。

    _double_fault:pushl $_do_double_fault error_code:xchgl %eax,4(%esp) # error code <-> %eaxxchgl %ebx,(%esp) # &function <-> %ebxpushl %ecxpushl %edxpushl %edipushl %esipushl %ebppush %dspush %espush %fspushl %eax # error codelea 44(%esp),%eax # offsetpushl %eaxmovl $0x10,%eaxmov %ax,%dsmov %ax,%esmov %ax,%fscall *%ebxaddl $8,%esppop %fspop %espop %dspopl %ebppopl %esipopl %edipopl %edxpopl %ecxpopl %ebxpopl %eaxiret

    看最開始的指令

    上圖是將中斷處理函數壓棧之后。

    然后執行

    xchgl %eax,4(%esp) # error code <-> %eax xchgl %ebx,(%esp) # &function <-> %ebx

    分別將

  • eax與棧內的error code交換,eax入棧
  • ebx保存中斷處理函數地址,ebx入棧
  • 然后,在壓入錯誤碼的時候,壓入的是pushl %eax # error code,這個時候error code就是動態的了,取決于之前硬件壓入的錯誤碼是多少,所以,之前的除法零是靜態的0,極大概率可能不壓入錯誤碼,當成固定機制處理,也可能與兼容性有關。

    然后就是調用中斷處理函數的時候,執行call *%ebx,因為這次是ebx存放函數地址。

    其他的就沒有差別了,需要注意的是,error code最開始就被替換下來了,在后面才壓棧。

    錯誤碼壓棧的作用

    好吧,看起來錯誤碼壓棧之后,好像根本沒有使用就略過了啊,肯定不會的,我們看看手冊。

    某種類型的異常也導致錯誤碼壓棧。異常處理器也能夠使用錯誤碼幫助檢測異常。

    這一點說明了

  • 錯誤碼的功能:幫助檢查異常
  • 某些有錯誤碼的異常會壓棧,不是所有的都會把錯誤碼壓棧,比如除法零錯誤,很可能就不壓棧
  • 總結

    以上是生活随笔為你收集整理的Linux 0.11 内核解析:中断相关(1)asm.s文件中断处理分析的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。