自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Linux中斷,本質(zhì)到底是什么?

系統(tǒng) Linux
在軟件開(kāi)發(fā)中,中斷是一個(gè)繞不開(kāi)的重要話題,但是,不知道您是否遇到過(guò)這樣的困惑:很多書(shū)籍、文章在介紹中斷相關(guān)的知識(shí)點(diǎn)時(shí),說(shuō)的都挺有道理。

[[421424]]

 在軟件開(kāi)發(fā)中,中斷是一個(gè)繞不開(kāi)的重要話題,但是,不知道您是否遇到過(guò)這樣的困惑:

很多書(shū)籍、文章在介紹中斷相關(guān)的知識(shí)點(diǎn)時(shí),說(shuō)的都挺有道理。

這篇文章對(duì)中斷的講解很正確,那篇文章在描述中斷的時(shí)候也挺對(duì)的,但是,這兩篇文章中,怎么有些內(nèi)容是矛盾的???!

單獨(dú)看任何一篇文章感覺(jué)都有道理,看的越多,反而越迷糊?

好比在森林里迷路了,如果只有一個(gè)指南針,肯定能走出來(lái)。

但是,如果你有 2 個(gè)指南針,所指的方向卻是相反的,這個(gè)時(shí)候應(yīng)該相信誰(shuí)呢?!

我們仔細(xì)梳理了一下就會(huì)發(fā)現(xiàn):每一篇文章都是在一定的語(yǔ)境、一定的上下文環(huán)境中來(lái)講解的,不同文章的矛盾之處,恰恰是它們所描述的那個(gè)上下文大環(huán)境不同。

上下文環(huán)境,就是描述當(dāng)前正在執(zhí)行的程序相關(guān)的靜態(tài)信息,比如:有哪些代碼段,??臻g在哪里,進(jìn)程描述信息在什么位置,當(dāng)前執(zhí)行到哪一條指令等等。

如果我們沒(méi)有一個(gè)全局的視角,在同一個(gè)上下文環(huán)境中來(lái)對(duì)比不同的文章,就會(huì)讓自己的理解和認(rèn)識(shí)越來(lái)越蒙圈。

因此,對(duì)于這種概念比較龐雜,無(wú)法用某種確定的邏輯來(lái)貫穿的知識(shí)點(diǎn),在腦袋中一定要有一幅全局的地圖。

[[421426]]

只有對(duì)這個(gè)全局的地圖掌握了,在具體學(xué)習(xí)每一個(gè)局部的知識(shí)點(diǎn)時(shí),才能知道自己所處的位置在哪里,才不至于走偏。

這篇文章,我們繼續(xù)去繁從簡(jiǎn),從 8086 這個(gè)最簡(jiǎn)單的處理器入手,來(lái)聊一下關(guān)于中斷的一些知識(shí)。

有了這個(gè)儲(chǔ)備,理清了基本的脈絡(luò)之后,以后再去學(xué)習(xí) Linux 系統(tǒng)中的中斷相關(guān)內(nèi)容時(shí),才會(huì)有原來(lái)如此的感覺(jué)!

中斷向量與中斷描述符

中斷向量這個(gè)詞很時(shí)髦,也很神秘!

按道理,不應(yīng)該在第一部分就端上中斷向量這盤(pán)硬菜,應(yīng)該從中斷源開(kāi)始聊起。

但是,畢竟我們已經(jīng)學(xué)習(xí)過(guò)那么多關(guān)于中斷的知識(shí)了,腦袋中肯定是對(duì)中斷已經(jīng)有了一些的基本認(rèn)知。

所以,在這里我們還是首先來(lái)明確一下中斷向量和中斷描述符這個(gè)問(wèn)題。

在前面的文章中已經(jīng)聊過(guò)關(guān)于實(shí)模式和保護(hù)模式的問(wèn)題,在 【Linux 從頭學(xué)】這個(gè)系列中,我們一直以來(lái)描述的都是實(shí)模式下的事情。

本文是實(shí)模式下的最后一篇文章,下一篇文章將會(huì)進(jìn)入保護(hù)模式。

那么,中斷向量就是工作在實(shí)模式下的,處理器通過(guò)中斷號(hào)和中斷向量,來(lái)定位到相應(yīng)的中斷處理程序。

而中斷描述符呢,就是工作在保護(hù)模式下,處理器通過(guò)中斷號(hào)和中斷描述符,來(lái)定位到相應(yīng)的中斷處理程序。

也就是說(shuō):中斷向量和中斷描述符,它倆的根本作用是一樣的。

只是它們存在于不同的大環(huán)境中,而且從描述上也能感覺(jué)到,保護(hù)模式下的中斷描述符會(huì)更復(fù)雜一些,功能也更強(qiáng)大一些。

它倆就像一對(duì)兄弟一樣,從外表上看是差不多,功能也是類(lèi)似。但是透入到內(nèi)部去看,就會(huì)發(fā)現(xiàn)有很多的不同之處。

[[421427]]

因此,這篇文章我們講解的就是在實(shí)模式下的中斷,這一點(diǎn)請(qǐng)大家先明白。

中斷的分類(lèi)

在 x86 系統(tǒng)中,中斷的分類(lèi)如下:

內(nèi)部中斷

所謂的內(nèi)部中斷,是在 CPU 內(nèi)部產(chǎn)生并進(jìn)行處理的。比如:

  1.   CPU 遇到一條除以 0 的指令時(shí),將產(chǎn)生 0 號(hào)中斷,并調(diào)用相應(yīng)的中斷處理程序;
  2.   CPU 遇到一條不存在的非法指令時(shí),將產(chǎn)生 6 號(hào)中斷,并調(diào)用相應(yīng)的中斷處理程序;

對(duì)于內(nèi)部中斷,有時(shí)候也稱(chēng)之為異常。

軟中斷也屬于內(nèi)部中斷,是非常有用的,它是由 int 指令觸發(fā)的。比如 int3 這條指令,gdb 就是利用它來(lái)實(shí)現(xiàn)對(duì)應(yīng)用程序的調(diào)試。

外部中斷

x86 CPU 上有 2 個(gè)中斷引腳:INT 和 INTR,分別對(duì)應(yīng):不可屏蔽中斷和可屏蔽中斷。

所謂不可屏蔽,就是說(shuō):中斷不可以被忽視,CPU 必須處理這個(gè)中斷。

如果不處理,程序就沒(méi)法繼續(xù)執(zhí)行。

而對(duì)于可屏蔽中斷,CPU 可以忽略它不執(zhí)行,因?yàn)檫@類(lèi)中斷不會(huì)對(duì)系統(tǒng)的執(zhí)行造成致命的影響。

對(duì)于外部的可屏蔽中斷,CPU 上只有一根 INTR 引腳,但是需要產(chǎn)生中斷信號(hào)的設(shè)備那么多,如何對(duì)眾多的中斷信號(hào)進(jìn)行區(qū)分呢?

一般都是通過(guò)可編程中斷控制器(Programmable Interrupt Controller, PIC),在計(jì)算機(jī)中使用最多的就是 8259a 芯片。

雖然現(xiàn)代計(jì)算機(jī)都已經(jīng)是 APIC(高級(jí)可編程中斷控制器) 了,但是由于 8259a 芯片是那么的經(jīng)典,大部分描述外部中斷的文章都會(huì)用它來(lái)舉例。

每一片 8259a 可以提供 8 個(gè)中斷輸入引腳,兩片芯片級(jí)聯(lián)在一起,就可以提供 15 個(gè)中斷信號(hào):

  1.  主片的輸出引腳 INT 連接到 CPU 的 INTR 引腳上;
  2.  從片的輸出引腳 INT 連接到主片的引腳 2 上;

這樣的話,兩片 8259a 芯片就可以向 CPU 提供 15 個(gè)中斷信號(hào)了,比如:鼠標(biāo)、鍵盤(pán)、串口、硬盤(pán)等等外設(shè)。

    1. 8259a 之所以稱(chēng)作可編程,是因?yàn)樗膬?nèi)部有相關(guān)的寄存器。

    2. 可以通過(guò)指定的端口號(hào),對(duì)這些寄存器進(jìn)行設(shè)置,讓 8 根 IRQ 中斷線上的信號(hào),在送到 CPU 時(shí),對(duì)應(yīng)不同的中斷號(hào)。

另外,對(duì)于外部可屏蔽中斷,有 2 層的屏蔽機(jī)制:

  1.  在 8259 芯片中,有中斷屏蔽寄存器,可以對(duì) IRQ0 ~ IRQ7 輸入引腳進(jìn)行屏蔽;
  2.  在 CPU 內(nèi)部,也有一個(gè)標(biāo)志寄存器,可以對(duì)某一類(lèi)中斷信號(hào)進(jìn)行屏蔽;

中斷號(hào)

在 x86 處理器中,一共支持 256 個(gè)中斷,每一個(gè)中斷都分配了一個(gè)中斷號(hào),從 0 到 255。

其中,0 ~ 31 號(hào)中斷向量被保留,用來(lái)處理異常和非屏蔽中斷(其中只有 2 號(hào)向量用于非屏蔽中斷,其余全部是異常)。

當(dāng) BIOS 或者操作系統(tǒng)提供了異常處理程序之后,當(dāng)一個(gè)異常產(chǎn)生時(shí),就會(huì)通過(guò)中斷向量表找到響應(yīng)的異常處理程序,查找的過(guò)程馬上就會(huì)介紹到。

從中斷號(hào) 32 開(kāi)始,全部分配給外部中斷。

比如:

    1. 系統(tǒng)定時(shí)器中斷 IRQ0,分配的就是 32 號(hào)中斷;

    2. Linux 的系統(tǒng)調(diào)用,分配的就是 128 號(hào)中斷;

我們來(lái)分別看一下內(nèi)部中斷和外部中斷相關(guān)的中斷號(hào):

對(duì)于通過(guò) 8259a 可編程中斷控制器接入的中斷信號(hào)分配如下圖所示:

剛才已經(jīng)說(shuō)過(guò),8259a 是可編程的,假如我們通過(guò)配置寄存器,把 IRQ0 的中斷號(hào)設(shè)置為 32, 那么主片上 IRQ1 ~ IRQ7 所對(duì)應(yīng)的中斷號(hào)依次加 1,從片上 IRQ8~IRQ15 對(duì)應(yīng)的中斷號(hào)也是依次遞增。

所以,有時(shí)候我們可以在代碼中斷看到下面的宏定義:

中斷向量和中斷處理程序

當(dāng)一個(gè)中斷發(fā)生的時(shí)候,CPU 獲取到該中斷對(duì)應(yīng)的中斷號(hào),下一步就是要確定調(diào)用哪一個(gè)函數(shù)來(lái)處理這個(gè)中斷,這個(gè)函數(shù)就稱(chēng)作中斷服務(wù)程序(Interrupt Service Routine,ISR),有時(shí)候也稱(chēng)作中斷處理程序、中斷處理函數(shù),本質(zhì)都一樣。

中斷向,就是通過(guò)中斷號(hào)去查找處理程序的重要的橋梁!

中斷向量的本質(zhì)

在 8086 中,一個(gè)中斷向量,就是一個(gè) 段地址:中斷處理函數(shù)偏移量 這樣的一對(duì)數(shù)據(jù),通過(guò)這個(gè)數(shù)據(jù),就可以定位到內(nèi)存中指定位置的那個(gè)中斷處理函數(shù)。

非常類(lèi)似于高級(jí)編程語(yǔ)言中的函數(shù)指針,就是用來(lái)指向一個(gè)函數(shù)的開(kāi)始地址。

8086 規(guī)定:256 個(gè)中斷向量,必須從內(nèi)存的 0 地址處開(kāi)始存放。

每一個(gè)中斷向量占用 4 個(gè)字節(jié)(2 個(gè)字節(jié)的段地址,2 個(gè)字節(jié)的偏移地址),256 個(gè)中斷一共占用了 1024 個(gè)字節(jié)的空間。

之前的文章中,已經(jīng)介紹過(guò)相關(guān)的內(nèi)存模型,如下圖所示:

如果把一個(gè)中斷向量看作函數(shù)指針,那么這個(gè)中斷向量表就相當(dāng)于是函數(shù)指針數(shù)組。

舉例:

假設(shè) 2 號(hào)中斷被觸發(fā)了,CPU 就會(huì)到中斷向量表中查找 2 號(hào)中斷的中斷向量。

因?yàn)槊恳粋€(gè)中斷向量占據(jù) 4 個(gè)字節(jié),那么 2 號(hào)中斷向量的開(kāi)始地址就是 2 * 4 = 8,第 8 個(gè)字節(jié)。

然后在第 8 個(gè)字節(jié)開(kāi)始,取 4 個(gè)字節(jié)的內(nèi)容:0x1000:0x2000。

意思是:2 號(hào)中斷的處理函數(shù),在段地址為 0x1000,偏移量為 0x2000 的位置處。

那么 CPU 就按照 8086 的物理地址計(jì)算方式,得到中斷處理函數(shù)的物理地址為 0x12000 (段地址左移 4 位 + 偏移地址),于是就跳轉(zhuǎn)到該函數(shù)地址處去執(zhí)行。

    1. 由于 Linux 系統(tǒng)是運(yùn)行在保護(hù)模式,在這個(gè)模式下,當(dāng)發(fā)生中斷時(shí),是通過(guò)中斷描述符來(lái)查找中斷處理函數(shù)的。

    2. 每一個(gè)中斷描述符,描述了一個(gè)中斷處理函數(shù)所在段的選擇子和偏移量,本質(zhì)上也是用來(lái)查找一個(gè)中斷處理函數(shù)。

中斷處理程序的安裝

既然通過(guò)中斷向量,找到了中斷處理程序,那么這些中斷處理程序都是誰(shuí)放在內(nèi)存中的呢?

如果您看過(guò)一些比較底層的計(jì)算機(jī)書(shū)籍,就能看到一般都會(huì)舉例:如何手動(dòng)的把一個(gè)普通函數(shù)設(shè)置為一個(gè)中斷處理函數(shù)。

操作步驟是:

  1.  在代碼中,寫(xiě)一個(gè)普通函數(shù);
  2.  把這個(gè)函數(shù)的指令碼,搬運(yùn)到內(nèi)存中的某一個(gè)位置;
  3.  把這個(gè)位置(段地址:偏移量),作為一個(gè)中斷向量,設(shè)置到中斷向量表中;

此時(shí),如果發(fā)生了該中斷,你所提供的函數(shù)就作為中斷處理函數(shù)被執(zhí)行了。

當(dāng)然了,在一個(gè)計(jì)算機(jī)系統(tǒng)中,BIOS、操作系統(tǒng)和各種外設(shè),會(huì)自動(dòng)為我們提供很多基本的中斷處理函數(shù)的。

比如:BIOS 中就提供了軟中斷、內(nèi)部中斷、硬件中斷等處理函數(shù),這些函數(shù)是固化在 BIOS 的代碼中的(映射到 BIOS 所在的 ROM 芯片上),BIOS 只需要把這些處理函數(shù)的地址,寫(xiě)入到中斷向量表中的相應(yīng)位置即可。

在之前的文章中提到過(guò),內(nèi)存中的某些位置是映射到外設(shè)的 ROM,在這些外設(shè)的 ROM 中也存在一些外設(shè)自帶的程序。

BIOS 在啟動(dòng)時(shí),會(huì)掃描這些映射到外設(shè)的內(nèi)存空間,通過(guò)某些關(guān)鍵字信息,如果發(fā)現(xiàn)外設(shè)有自帶的程序,就會(huì)去執(zhí)行。

這些外設(shè)程序一般是進(jìn)行一些自身的初始化,并填寫(xiě)相關(guān)的中斷向量表,使它們指向外設(shè)自帶的中斷處理程序。

對(duì)于操作系統(tǒng)來(lái)說(shuō)就更不用說(shuō)了,它會(huì)重新安排自己需要的中斷處理函數(shù),這部分內(nèi)容我們以后再一起學(xué)習(xí)、討論!

[[421429]]

中斷現(xiàn)場(chǎng)的保護(hù)和恢復(fù)

當(dāng)一個(gè)中斷發(fā)生的時(shí)候,肯定有一個(gè)正在執(zhí)行的程序被打斷。

當(dāng)中斷處理函數(shù)執(zhí)行結(jié)束之后,這個(gè)被打斷的程序需要從剛才被打斷的地方繼續(xù)執(zhí)行(暫時(shí)先不要考慮從中斷返回點(diǎn),進(jìn)行多任務(wù)切換的事情)。

而一個(gè)程序執(zhí)行的上下文環(huán)境,就是處理器中的各種寄存器內(nèi)容:代碼段寄存器 cs,指令指針寄存器 sp,標(biāo)志寄存器 FLAGS。

但是,在中斷處理程序中,也需要使用這些寄存器。

處理器中的這些寄存器,就是每一個(gè)程序執(zhí)行時(shí)上下文信息的存儲(chǔ)容器,當(dāng)然也包括終端處理程序!

因此,在進(jìn)入中斷處理程序之前,CPU 會(huì)自動(dòng)的把這些寄存器 push 到棧中保存起來(lái),然后再跳轉(zhuǎn)到中斷處理程序中去執(zhí)行。

當(dāng)中斷處理程序執(zhí)行結(jié)束后,CPU 會(huì)從棧中彈出這些內(nèi)容,恢復(fù)到相應(yīng)的寄存器中,于是被打斷的程序就可以繼續(xù)執(zhí)行了。

總結(jié):中斷的本質(zhì)

從功能的角度看,中斷有 2 個(gè)作用:

  1.  提供執(zhí)行異步序列的機(jī)制;
  2.  給應(yīng)用程序提供進(jìn)入系統(tǒng)層的入口;

關(guān)于第 2 點(diǎn),以后在介紹到 Linux 中的 int 0x80 中斷就非常清楚了,也就是通過(guò)中斷,讓?xiě)?yīng)用層的程序有機(jī)會(huì)進(jìn)入到系統(tǒng)代碼中去執(zhí)行。

因?yàn)閼?yīng)用層與操作系統(tǒng)層的代碼,是工作在不同的安全級(jí)別。

為了系統(tǒng)的安全,Linux 操作系統(tǒng)提供了這樣的一個(gè)機(jī)制,讓低安全級(jí)別的應(yīng)用程序,進(jìn)入到高安全級(jí)別的操作系統(tǒng)代碼中去執(zhí)行,畢竟所有的硬件等系統(tǒng)資源都是由操作系統(tǒng)來(lái)統(tǒng)一管理的。

我們?cè)購(gòu)闹袛嗵幚沓绦虻陌惭b角度來(lái)看,中斷本質(zhì)上就是增加了一層間接性:通過(guò)固定位置的中斷向量表,讓中斷處理函數(shù)的實(shí)際地址可以被動(dòng)態(tài)的放在任意位置。

為什么這么做?

假如操作系統(tǒng)想為某一個(gè)中斷提供處理函數(shù),那么這個(gè)處理函數(shù)的地址放在內(nèi)存中的什么位置比較合適?

需要考慮 CPU, 內(nèi)存大小和布局等多種因素,非常復(fù)雜!

而通過(guò)使用中斷向量表,就在一個(gè)固定位置處存放了很多個(gè)“指針”。

當(dāng)中斷處理函數(shù)放在內(nèi)存中某個(gè)任意位置之后,讓“指針”指向這個(gè)函數(shù)的地址就可以了,從而達(dá)到解耦的目的。

這樣的話,無(wú)論是發(fā)生硬件中斷,還是應(yīng)用層代碼通過(guò)中斷門(mén)來(lái)調(diào)用操作系統(tǒng)提供的函數(shù),只要觸發(fā)相應(yīng)的中斷就可以了,簡(jiǎn)化了 CPU 的設(shè)計(jì)。 

 

責(zé)任編輯:龐桂玉 來(lái)源: 良許Linux
相關(guān)推薦

2021-08-16 07:51:20

Linux 中斷Linux 系統(tǒng)

2020-10-14 06:22:14

UWB技術(shù)感知

2010-11-01 01:25:36

Windows NT

2020-09-22 08:22:28

快充

2020-09-27 06:53:57

MavenCDNwrapper

2011-04-27 09:30:48

企業(yè)架構(gòu)

2019-10-30 10:13:15

區(qū)塊鏈技術(shù)支付寶

2020-08-04 14:20:20

數(shù)據(jù)湖Hadoop數(shù)據(jù)倉(cāng)庫(kù)

2013-06-09 09:47:31

.NetPDBPDB文件

2010-04-22 14:14:29

Live-USB

2021-01-21 21:24:34

DevOps開(kāi)發(fā)工具

2023-07-12 15:32:49

人工智能AI

2020-03-05 10:28:19

MySQLMRR磁盤(pán)讀

2021-07-07 05:07:15

JDKIterator迭代器

2021-09-01 23:29:37

Golang語(yǔ)言gRPC

2022-10-08 00:00:00

Spring數(shù)據(jù)庫(kù)項(xiàng)目

2021-02-05 10:03:31

區(qū)塊鏈技術(shù)智能

2024-02-04 00:01:00

云原生技術(shù)容器

2023-03-26 12:27:30

2009-06-09 22:11:44

JavaScriptObject
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)