導航:首頁 > 操作系統 > linux中斷與系統調用

linux中斷與系統調用

發布時間:2022-12-12 10:42:37

linux系統調用是通過軟中斷實現的嗎

軟中斷是利用硬體中斷的概念,用軟體方式進行模擬,實現宏觀上的非同步執行效果。很多情況下,軟中斷和信號有些類似,同時,軟中斷又是和硬中斷相對應的,硬中斷是外部設備對CPU的中斷,軟中斷通常是硬中斷服務程序對內核的中斷,信號則是由內核(或其他進程)對某個進程的中斷(《Linux內核源代碼情景分析》第三章)。軟中斷是linux系統原「底半處理」的升級,在原有的基礎上發展的新的處理方式,以適應多cpu 、多線程的軟中斷處理。
軟中斷是實現系統API函數調用的手段
函數調用時將返回地址和CPU狀態寄存器內容壓棧,函數執行完畢後出棧返回斷點繼續執行。
軟中斷調用時將返回地址和CPU狀態寄存器內容壓棧,修改特權級,根據中斷號查找中斷向量表,找到ISR中斷服務常式地址,跳轉執行。

② 如何在Linux內核里增加一個系統調用

一、Linux0.11下添加系統調用:x0dx0ax0dx0a我在bochs2.2.1中對linux0.11內核添加了一個新的系統調用,步驟如下: x0dx0a1./usr/src/linux/include/unistd.h中添加:#define __NR_mytest 87 x0dx0a然後在下面聲明函數原型:int mytest(); x0dx0a2./usr/src/linux/include/linux/sys.h中添加:extern int sys_mytest(); x0dx0a然後在sys_call_table中最後加上sys_mytest; x0dx0a3.在/usr/src/linux/kernel/sys.c中添加函數實現如下: x0dx0aint sys_mytest(){ x0dx0aprintk("This is a test!"); x0dx0areturn 123; x0dx0a} x0dx0a4.在/usr/src/linux/kernel/system_call.s中對系統調用號加1(原來是86改成了87) x0dx0a5.然後到/usr/src/linux目錄下編譯內核make clean; make Image x0dx0a6. cp /usr/src/linux/include/unistd.h /usr/include/unistd.h x0dx0a7. reset bochs x0dx0a8. 在/usr/root中生成test.c文件如下: x0dx0a#define __LIBRARY__ x0dx0a#include x0dx0a_syscall0(int,mytest) x0dx0aint main(){ x0dx0aint a; x0dx0aa = mytest(); x0dx0aprintf("%d", a); x0dx0areturn 0; x0dx0a} x0dx0a9.然後gcc test.c編譯之後運行a.out,前面所有步驟都通過,但是每次調用都是返回-1,然後我查過errno為1(表示操作不允許),就不知道為什麼了? x0dx0a系統知道的高手們能夠告知一下,不勝感激!這個問題困擾我很久了! x0dx0ax0dx0a二、新Linux內核添加系統調用x0dx0ax0dx0a如何在Linux系統中添加新的系統調用x0dx0a系統調用是應用程序和操作系統內核之間的功能介面。其主要目的是使得用戶可以使用操作系統提供的有關設備管理、輸入/輸入系統、文件系統和進程式控制制、通信以及存儲管理等方面的功能,而不必了解系統程序的內部結構和有關硬體細節,從而起到減輕用戶負擔和保護系統以及提高資源利用率的作用。x0dx0ax0dx0aLinux操作系統作為自由軟體的代表,它優良的性能使得它的應用日益廣泛,不僅得到專業人士的肯定,而且商業化的應用也是如火如荼。在Linux中,大部分的系統調用包含在Linux的libc庫中,通過標準的C函數調用方法可以調用這些系統調用。那麼,對Linux的發燒友來說,如何在Linux中增加新的系統調用呢? x0dx0a1 Linux系統調用機制x0dx0ax0dx0a在Linux系統中,系統調用是作為一種異常類型實現的。它將執行相應的機器代碼指令來產生異常信號。產生中斷或異常的重要效果是系統自動將用戶態切換為核心態來對它進行處理。這就是說,執行系統調用異常指令時,自動地將系統切換為核心態,並安排異常處理程序的執行。Linux用來實現系統調用異常的實際指令是:x0dx0ax0dx0aInt $0x80x0dx0ax0dx0a這一指令使用中斷/異常向量號128(即16進制的80)將控制權轉移給內核。為達到在使用系統調用時不必用機器指令編程,在標準的C語言庫中為每一系統調用提供了一段短的子程序,完成機器代碼的編程工作。事實上,機器代碼段非常簡短。它所要做的工作只是將送給系統調用的參數載入到CPU寄存器中,接著執行int $0x80指令。然後運行系統調用,系統調用的返回值將送入CPU的一個寄存器中,標準的庫子程序取得這一返回值,並將它送回用戶程序。x0dx0ax0dx0a為使系統調用的執行成為一項簡單的任務,Linux提供了一組預處理宏指令。它們可以用在程序中。這些宏指令取一定的參數,然後擴展為調用指定的系統調用的函數。x0dx0ax0dx0a這些宏指令具有類似下面的名稱格式:x0dx0ax0dx0a_syscallN(parameters)x0dx0ax0dx0a其中N是系統調用所需的參數數目,而parameters則用一組參數代替。這些參數使宏指令完成適合於特定的系統調用的擴展。例如,為了建立調用setuid()系統調用的函數,應該使用:x0dx0ax0dx0a_syscall1( int, setuid, uid_t, uid )x0dx0ax0dx0asyscallN( )宏指令的第1個參數int說明產生的函數的返回值的類型是整型,第2個參數setuid說明產生的函數的名稱。後面是系統調用所需要的每個參數。這一宏指令後面還有兩個參數uid_t和uid分別用來指定參數的類型和名稱。x0dx0ax0dx0a另外,用作系統調用的參數的數據類型有一個限制,它們的容量不能超過四個位元組。這是因為執行int $0x80指令進行系統調用時,所有的參數值都存在32位的CPU寄存器中。使用CPU寄存器傳遞參數帶來的另一個限制是可以傳送給系統調用的參數的數目。這個限制是最多可以傳遞5個參數。所以Linux一共定義了6個不同的_syscallN()宏指令,從_syscall0()、_syscall1()直到_syscall5()。x0dx0ax0dx0a一旦_syscallN()宏指令用特定系統調用的相應參數進行了擴展,得到的結果是一個與系統調用同名的函數,它可以在用戶程序中執行這一系統調用。x0dx0a2 添加新的系統調用 x0dx0a如果用戶在Linux中添加新的系統調用,應該遵循幾個步驟才能添加成功,下面幾個步驟詳細說明了添加系統調用的相關內容。x0dx0ax0dx0a(1) 添加源代碼x0dx0ax0dx0a第一個任務是編寫加到內核中的源程序,即將要加到一個內核文件中去的一個函數,該函數的名稱應該是新的系統調用名稱前面加上sys_標志。假設新加的系統調用為mycall(int number),在/usr/src/linux/kernel/sys.c文件中添加源代碼,如下所示:x0dx0aasmlinkage int sys_mycall(int number) x0dx0a{ x0dx0areturn number; x0dx0a}x0dx0a作為一個最簡單的例子,我們新加的系統調用僅僅返回一個整型值。x0dx0ax0dx0a(2) 連接新的系統調用x0dx0ax0dx0a添加新的系統調用後,下一個任務是使Linux內核的其餘部分知道該程序的存在。為了從已有的內核程序中增加到新的函數的連接,需要編輯兩個文件。x0dx0ax0dx0a在我們所用的Linux內核版本(RedHat 6.0,內核為2.2.5-15)中,第一個要修改的文件是:x0dx0ax0dx0a/usr/src/linux/include/asm-i386/unistd.hx0dx0ax0dx0a該文件中包含了系統調用清單,用來給每個系統調用分配一個唯一的號碼。文件中每一行的格式如下:x0dx0ax0dx0a#define __NR_name NNNx0dx0ax0dx0a其中,name用系統調用名稱代替,而NNN則是該系統調用對應的號碼。應該將新的系統調用名稱加到清單的最後,並給它分配號碼序列中下一個可用的系統調用號。我們的系統調用如下:x0dx0ax0dx0a#define __NR_mycall 191x0dx0ax0dx0a系統調用號為191,之所以系統調用號是191,是因為Linux-2.2內核自身的系統調用號碼已經用到190。x0dx0ax0dx0a第二個要修改的文件是:x0dx0ax0dx0a/usr/src/linux/arch/i386/kernel/entry.Sx0dx0ax0dx0a該文件中有類似如下的清單:x0dx0a.long SYMBOL_NAME()x0dx0ax0dx0a該清單用來對sys_call_table[]數組進行初始化。該數組包含指向內核中每個系統調用的指針。這樣就在數組中增加了新的內核函數的指針。我們在清單最後添加一行:x0dx0a.long SYMBOL_NAME(sys_mycall)x0dx0ax0dx0a(3) 重建新的Linux內核x0dx0ax0dx0a為使新的系統調用生效,需要重建Linux的內核。這需要以超級用戶身份登錄。x0dx0a#pwd x0dx0a/usr/src/linux x0dx0a#x0dx0ax0dx0a超級用戶在當前工作目錄(/usr/src/linux)下,才可以重建內核。x0dx0ax0dx0a#make config x0dx0a#make dep x0dx0a#make clearn x0dx0a#make bzImagex0dx0ax0dx0a編譯完畢後,系統生成一可用於安裝的、壓縮的內核映象文件:x0dx0ax0dx0a/usr/src/linux/arch/i386/boot/bzImage x0dx0a(4) 用新的內核啟動系統 x0dx0a要使用新的系統調用,需要用重建的新內核重新引導系統。為此,需要修改/etc/lilo.conf文件,在我們的系統中,該文件內容如下:x0dx0ax0dx0aboot=/dev/hda x0dx0amap=/boot/map x0dx0ainstall=/boot/boot.b x0dx0aprompt x0dx0atimeout=50 x0dx0ax0dx0aimage=/boot/vmlinuz-2.2.5-15 x0dx0alabel=linux x0dx0aroot=/dev/hdb1 x0dx0a read-only x0dx0ax0dx0aother=/dev/hda1 x0dx0alabel=dos x0dx0atable=/dev/hadx0dx0ax0dx0a首先編輯該文件,添加新的引導內核:x0dx0aimage=/boot/bzImage-new x0dx0alabel=linux-new x0dx0aroot=/dev/hdb1 x0dx0aread-onlyx0dx0ax0dx0a添加完畢,該文件內容如下所示:x0dx0aboot=/dev/hda x0dx0amap=/boot/map x0dx0ainstall=/boot/boot.b x0dx0aprompt x0dx0atimeout=50 x0dx0ax0dx0aimage=/boot/bzImage-new x0dx0alabel=linux-new x0dx0aroot=/dev/hdb1 x0dx0aread-only x0dx0ax0dx0aimage=/boot/vmlinuz-2.2.5-15 x0dx0alabel=linux x0dx0aroot=/dev/hdb1 x0dx0aread-only x0dx0ax0dx0aother=/dev/hda1 x0dx0alabel=dos x0dx0atable=/dev/hdax0dx0ax0dx0a這樣,新的內核映象bzImage-new成為預設的引導內核。為了使用新的lilo.conf配置文件,還應執行下面的命令:x0dx0a#cp /usr/src/linux/arch/i386/boot/zImage /boot/bzImage-newx0dx0ax0dx0a其次配置lilo:x0dx0ax0dx0a# /sbin/lilox0dx0ax0dx0a現在,當重新引導系統時,在boot:提示符後面有三種選擇:linux-new 、linux、dos,新內核成為預設的引導內核。x0dx0a至此,新的Linux內核已經建立,新添加的系統調用已成為操作系統的一部分,重新啟動Linux,用戶就可以在應用程序中使用該系統調用了。x0dx0ax0dx0a(5)使用新的系統調用x0dx0ax0dx0a在應用程序中使用新添加的系統調用mycall。同樣為實驗目的,我們寫了一個簡單的例子xtdy.c。x0dx0ax0dx0a/* xtdy.c */ x0dx0a#include x0dx0a_syscall1(int,mycall,int,ret) x0dx0amain() x0dx0a{ x0dx0aprintf("%d \n",mycall(100)); x0dx0a}x0dx0a編譯該程序:x0dx0a# cc -o xtdy xtdy.cx0dx0a執行:x0dx0a# xtdyx0dx0a結果:x0dx0a# 100x0dx0a注意,由於使用了系統調用,編譯和執行程序時,用戶都應該是超級用戶身份。

③ Linux中斷 異常 系統調用 中斷上半部 中斷下半部 這些有什麼區別和聯系

中斷分軟中斷跟硬中斷,硬中斷是由硬體從外部觸發,軟中斷由軟體觸發,就像linux系統調用int 80一樣。至於中斷的上下部其實就是因為中斷的處理時間跟它的優先順序不一定成正比,所以一般先處理中斷最重要的部分(上半部),待到不怎麼忙的時候,再來處理比較悠閑的部分(下半部)。就像輸入的時候,拿到鍵盤輸入的是什麼才是最重要的(上半部),顯示字元才是次要的(下半部)。

④ 什麼是中斷系統調用

中斷、異常和系統調用

所謂中斷是指CPU對系統發生的某個事件做出的一種反應,CPU暫停正在執行的程序,保留現場後自動地轉去執行相應的處理程序,處理完該事件後再返回斷點繼續執行被「打斷」的程序。

中斷可分為三類,第一類是由CPU外部引起的,稱作中斷,如I/O中斷、時鍾中斷、控制台中斷等。第二類是來自CPU的內部事件或程序執行中的事件引起的過程,稱作異常,如由於CPU本身故障(電源電壓低於105V或頻率在47~63Hz之外)、程序故障(非法操作碼、地址越界、浮點溢出等)等引起的過程。

第三類由於在程序中使用了請求系統服務的系統調用而引發的過程,稱作「陷入」(trap,或者陷阱)。前兩類通常都稱作中斷,它們的產生往往是無意、被動的,而陷入是有意和主動的。

1.中斷處理

中斷處理一般分為中斷響應和中斷處理兩個步驟。中斷響應由硬體實施,中斷處理主要由軟體實施。

(1)中斷響應

對中斷請求的整個處理過程是由硬體和軟體結合起來而形成的一套中斷機構實施的。發生中斷時,CPU暫停執行當前的程序,而轉去處理中斷。這個由硬體對中斷請求作出反應的過程,稱為中斷響應。一般說來,中斷響應順序執行下述三步動作:

◆中止當前程序的執行;

◆保存原程序的斷點信息(主要是程序計數器PC和程序狀態寄存器PS的內容);

◆從中斷控制器取出中斷向量,轉到相應的處理程序。

通常CPU在執行完一條指令後,立即檢查有無中斷請求,如果有,則立即做出響應。

當發生中斷時,系統作出響應,不管它們是來自硬體(如來自時鍾或者外部設備)、程序性中斷(執行指令導致「軟體中斷」—Software Interrupts),或者來自意外事件(如訪問頁面不在內存)。

如果當前CPU的執行優先順序低於中斷的優先順序,那麼它就中止對當前程序下條指令的執行,接受該中斷,並提升處理機的執行級別(一般與中斷優先順序相同),以便在CPU處理當前中斷時,能屏蔽其它同級的或低級的中斷,然後保存斷點現場信息,通過取得的中斷向量轉到相應的中斷處理程序的入口。

(2)中斷處理

CPU從中斷控制器取得中斷向量,然後根據具體的中斷向量從中斷向量表IDT中找到相應的表項,該表項應是一個中斷門。於是,CPU就根據中斷門的設置而到達了該通道的總服務程序的入口。

核心對中斷處理的順序主要由以下動作完成:

◆保存正在運行進程的各寄存器的內容,把它們放入核心棧的新幀面中。

◆確定「中斷源」或核查中斷發生,識別中斷的類型(如時鍾中斷或盤中斷)和中斷的設備號(如哪個磁碟引起的中斷)。系統接到中斷後,就從機器那裡得到一個中斷號,它是檢索中斷向量表的位移。中斷向量因機器而異,但通常都包括相應中斷處理程序入口地址和中斷處理時處理機的狀態字。

◆核心調用中斷處理程序,對中斷進行處理。

◆中斷處理完成並返回。中斷處理程序執行完以後,核心便執行與機器相關的特定指令序列,恢復中斷時寄存器內容和執行核心棧退棧,進程回到用戶態。如果設置了重調度標志,則在本進程返回到用戶態時做進程調度。

2.系統調用

在Unix/Linux系統中,系統調用像普通C函數調用那樣出現在C程序中。但是一般的函數調用序列並不能把進程的狀態從用戶態變為核心態,而系統調用卻可以做到。

C語言編譯程序利用一個預先確定的函數庫(一般稱為C庫),其中有各系統調用的名字。C庫中的函數都專門使用一條指令,把進程的運行狀態改為核心態。Linux的系統調用是通過中斷指令「INT 0x80」實現的。

每個系統調用都有惟一的號碼,稱作系統調用號。所有的系統調用都集中在系統調用入口表中統一管理。

系統調用入口表是一個函數指針數組,以系統調用號為下標在該數組中找到相應的函數指針,進而就能確定用戶使用的是哪一個系統調用。不同系統中系統調用的個數是不同的,目前Linux系統中共定義了221個系統調用。

另外,系統調用表中還留有一些余項,可供用戶自行添加。

當CPU執行到中斷指令「INT 0x80」時,硬體就做出一系列響應,其動作與上述的中斷響應相同。CPU穿過陷阱門,從用戶空間進入系統空間。相應地,進程的上下文從用戶堆棧切換到系統堆棧。

接著運行內核函數system_call()。首先,進一步保存各寄存器的內容;接著調用syscall_trace( ),以系統調用號為下標檢索系統調用入口表sys_call_table,從中找到相應的函數;然後轉去執行該函數,完成具體的服務。

執行完服務程序,核心檢查是否發生錯誤,並作相應處理。如果本進程收到信號,則對信號作相應處理。最後進程從系統空間返回到用戶空間。

上面兩講簡要介紹了Linux內核的主要數據結構和相應的演算法。Linux內核包含了豐富的內容,這里僅是其中的一點點,以求起到「拋磚引玉」的作用。

信號的中斷與系統調用的重起

#include <signal.h>int sigaction(ints signo, const struct sigaction *act, struct sigaction *oact) ;struct sigaction ; 當更改信號動作時,如果sa _handler指向一個信號捕捉函數(不是常數SIG_IGN或SIG_DFL),則sa_mask欄位說明了一個信號集,在調用信號捕捉函數之前,該信號集要加到進程的信號屏蔽字中。僅當從信號捕捉函數返回時再將進程的信號屏蔽字恢復為原先值。這樣,在調用信號處理程序時就能阻塞某些信號。在信號處理程序被調用時,系統建立的新信號屏蔽字會自動包括正被遞送的信號。因此保證了在處理一個給定的信號時,如果這種信號再次發生,那麼它會被阻塞到對前一個信號的處理結束為止。A. 可自動重起的signal()的實現:#include <signal.h>#typpdef void Sigfunc(int signo); Sigfunc *signal(int signo, Sigfunc *func) else // for other signal if (sigaction(signo, &act, &oac) < 0) return (SIG_ERR); return (oact.sa_handler);}注: 在if語句中,我們檢查是否為SIGALRM信號,如果是,且系統定義了 SA_INTERRUPT(SUNOS),即為SUNOS,該系統默認的系統調用是自 動重起的,我們阻止該信號中斷的系統調用重起,因為我們要用該信號 中斷I/O操作,實現定時的功能. 接著的else語句中的信號為SIGALRM之外的其他信號,且系統定義了 SA_RESTART,即為SVR4或4.3+BSD類系統,該類系統中默認的系統 調用是不可重起的,所以應該加上SA_RESTART標志,使由這些信號中 斷的系統調用自動重起.B. 不可重起的signal_intr()實現: Sigfunc *signal_intr(int signo, Sigfunc *func)
{
struct sigaction act, oact;

act.sa_handler = func;
sigemptyset(act.sa_mask);
act.sa_flags = 0;

#ifdef SA_INTTERRUPT //SUNOS
act.flags |= SA_INTTERRUPT;
#endif
if (sigaction(signo, &act, &oac) < 0)
return (SIG_ERR);

return (oact.sa_handler);
}
注: 只有SUNOS為自動重起的,其他為不自動重起的,所以只要將SUNOS標 志為非自動重起即可.如上.

⑤ Linux系統調用表(system call table)

轉自:《 Linux系統調用表 》

《 linux系統調用表(system call table) 》

《 線上環境 Linux 系統調用追蹤 》

《 Linux系統調用權威指南 》

《 為什麼系統調用會消耗較多資源?系統調用的三種方法:軟體中斷(分析過程)、SYSCALL指令、vDSO(虛擬動態鏈接對象linux-vdso.so.1) 》

閱讀全文

與linux中斷與系統調用相關的資料

熱點內容
h3c光纖全工半全工設置命令 瀏覽:135
公司法pdf下載 瀏覽:379
linuxmarkdown 瀏覽:347
華為手機怎麼多選文件夾 瀏覽:679
如何取消命令方塊指令 瀏覽:345
風翼app為什麼進不去了 瀏覽:774
im4java壓縮圖片 瀏覽:358
數據查詢網站源碼 瀏覽:146
伊克塞爾文檔怎麼進行加密 瀏覽:886
app轉賬是什麼 瀏覽:159
php的基本語法 瀏覽:792
對外漢語pdf 瀏覽:516
如何用mamp本地web伺服器 瀏覽:869
如何加密自己js代碼 瀏覽:627
排列組合a與c的演算法 瀏覽:534
如何在文件夾中找到同名內容 瀏覽:786
有什麼app文字轉韓文配音 瀏覽:372
循環宏1命令 瀏覽:35
斐波那契數列矩陣演算法 瀏覽:674
公式保護後加密不了 瀏覽:82