新聞中心

EEPW首頁(yè) > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > 《ARM與Linux些許問(wèn)題》第四章:ARM平臺(tái)系統(tǒng)調(diào)用原理分析

《ARM與Linux些許問(wèn)題》第四章:ARM平臺(tái)系統(tǒng)調(diào)用原理分析

作者: 時(shí)間:2016-11-09 來(lái)源:網(wǎng)絡(luò) 收藏
本文基于mstar801平臺(tái)Linux2.6.35.11版本。

首先說(shuō)明:系統(tǒng)調(diào)用不會(huì)導(dǎo)致進(jìn)程上下文切換。

本文引用地址:http://butianyuan.cn/article/201611/317769.htm

一、介紹系統(tǒng)調(diào)用——Linux用戶空間主動(dòng)進(jìn)入內(nèi)核空間的唯一方法

1.系統(tǒng)調(diào)用是操作系統(tǒng)提供給用戶程序調(diào)用的一組“特殊”接口;用戶程序可以通過(guò)這組“特殊”接口來(lái)獲得操作系統(tǒng)內(nèi)核提供的服務(wù)。

從邏輯上來(lái)說(shuō),系統(tǒng)調(diào)用可被看成是一個(gè)內(nèi)核與用戶空間程序交互的接口;把用戶進(jìn)程的請(qǐng)求傳達(dá)給內(nèi)核,待內(nèi)核把請(qǐng)求處理完畢后再將處理結(jié)果送回給用戶空間。

2.系統(tǒng)調(diào)用按照功能邏輯大致可分為“進(jìn)程控制”、“文件系統(tǒng)控制”、“系統(tǒng)控制”、“存儲(chǔ)管理”、“網(wǎng)絡(luò)管理”、“socket控制”、“用戶管理”和“進(jìn)程間通信”幾類。

3.內(nèi)核接口:kernel2.6.35.11/arch/arm/include/asm/unistd.h

二、系統(tǒng)調(diào)用的主要用途

1.控制硬件——系統(tǒng)調(diào)用往往作為硬件資源和用戶空間的抽象接口,比如讀寫(xiě)文件時(shí)用到的write/read調(diào)用。

2.設(shè)置系統(tǒng)狀態(tài)或讀取內(nèi)核數(shù)據(jù)——因?yàn)橄到y(tǒng)調(diào)用是用戶空間和內(nèi)核的唯一通訊手段,所以用戶設(shè)置系統(tǒng)狀態(tài)、比如開(kāi)/關(guān)某項(xiàng)內(nèi)核服務(wù)(設(shè)置某個(gè)內(nèi)核變量)或讀取內(nèi)核數(shù)據(jù)都必須通過(guò)系統(tǒng)調(diào)用。比如getpid、getpriority、setpriority和sethostname等。

3.進(jìn)程管理——系統(tǒng)調(diào)用接口用來(lái)保證系統(tǒng)中進(jìn)程能以多任務(wù)在虛擬內(nèi)存環(huán)境下運(yùn)行。比如fork、clone、execve和exit等。

三、內(nèi)核函數(shù)和系統(tǒng)調(diào)用、用戶編程接口(API)、系統(tǒng)命令的關(guān)系

1.系統(tǒng)調(diào)用并非直接和程序員或系統(tǒng)管理員打交道,它僅僅是一個(gè)通過(guò)軟中斷機(jī)制向內(nèi)核提交請(qǐng)求、獲取內(nèi)核服務(wù)的接口。而在實(shí)際使用中程序員調(diào)用的多是用戶編程接口——api,而管理員使用的則多是系統(tǒng)命令。

2.用戶編程接口(API)其實(shí)是一個(gè)函數(shù)定義,說(shuō)明了如何獲得一個(gè)給定的服務(wù),比如read()、malloc()、free()、abs()等。

它有可能和系統(tǒng)調(diào)用形式一致,比如read()接口就和read系統(tǒng)調(diào)用一一對(duì)應(yīng);

往往會(huì)出現(xiàn)幾種不同的API內(nèi)部用到同一個(gè)系統(tǒng)調(diào)用,比如malloc()、free()內(nèi)部利用brk()系統(tǒng)調(diào)用來(lái)擴(kuò)大或縮小進(jìn)程的堆;

或一個(gè)API利用了好幾個(gè)系統(tǒng)調(diào)用組合來(lái)完成任務(wù);

更有些API甚至不需要任何系統(tǒng)調(diào)用,因?yàn)樗恍枰獌?nèi)核服務(wù)、如計(jì)算整數(shù)絕對(duì)值的abs()接口。

Linux系統(tǒng)中這些API主要是通過(guò)C庫(kù)(libc)實(shí)現(xiàn)的;它除了定義的一些標(biāo)準(zhǔn)的C函數(shù)外,一個(gè)重要的任務(wù)是提供了一套封裝例程、將系統(tǒng)調(diào)用在用戶空間包裝后供用戶編程使用。

說(shuō)明:上述封裝并非必須;如果你愿意直接調(diào)用,Linux提供了一個(gè)syscall()的系統(tǒng)調(diào)用函數(shù)來(lái)實(shí)現(xiàn)調(diào)用。

3.系統(tǒng)命令相對(duì)編程接口更高了一層,它是內(nèi)部引用API的可執(zhí)行程序,比如我們常用的系統(tǒng)命令ls、hostname等。

三、內(nèi)核函數(shù)和系統(tǒng)調(diào)用的關(guān)系

內(nèi)核函數(shù)沒(méi)有想像中那么復(fù)雜;它們和普通函數(shù)很像、只不過(guò)在內(nèi)核實(shí)現(xiàn),因此要滿足一些內(nèi)核編程的要求。

系統(tǒng)調(diào)用是一層用戶進(jìn)入內(nèi)核的接口,它本身并非內(nèi)核函數(shù);進(jìn)入內(nèi)核后,不同的系統(tǒng)調(diào)用會(huì)找到對(duì)應(yīng)到各自的內(nèi)核函數(shù)——專業(yè)術(shù)語(yǔ)叫:系統(tǒng)調(diào)用服務(wù)例程。

總結(jié):從用戶角度向內(nèi)核看;依次是系統(tǒng)命令、編程接口、系統(tǒng)調(diào)用和內(nèi)核函數(shù)。
四、系統(tǒng)調(diào)用的實(shí)現(xiàn)

系統(tǒng)調(diào)用利用了ARM體系結(jié)構(gòu)中的軟件中斷,軟件中斷和我們常說(shuō)的中斷(硬件中斷)不同之處在于———它是通過(guò)軟件指令觸發(fā)而并非外設(shè),也就是說(shuō)由編程人員發(fā)出的一種異常;具體地講就是調(diào)用SWI匯編指令(x86上int $0x80),這條匯編指令將產(chǎn)生向量為128的編程異常,ARM從用戶模式切入管理模式、并強(qiáng)制R15-PC(程序計(jì)數(shù)器)為0x0000 0008,Linux從用戶態(tài)進(jìn)入內(nèi)核態(tài)。見(jiàn):《ARM與Linux些許問(wèn)題》第一章:ARM工作模式

之所以系統(tǒng)調(diào)用需要借助異常實(shí)現(xiàn);是因?yàn)楫?dāng)用戶態(tài)的進(jìn)程調(diào)用一個(gè)系統(tǒng)調(diào)用時(shí),CPU便被切換到內(nèi)核態(tài)執(zhí)行內(nèi)核函數(shù)。我們前邊分析ARM體系結(jié)構(gòu)部分已經(jīng)講過(guò)進(jìn)入內(nèi)核態(tài)——ARM高特權(quán)模式,必須經(jīng)過(guò)系統(tǒng)的門(mén)機(jī)制——異常(SWI匯編指令(x86上int $0x80等);其他異常用戶空間無(wú)法利用,都是由內(nèi)核使用的。)。

1.SWI匯編指令(x86上int $0x80)指令的目的是產(chǎn)生一個(gè)編號(hào)為128的編程異常,這個(gè)編程異常對(duì)應(yīng)中斷描述符表IDT中的第128項(xiàng)——也就是對(duì)應(yīng)的系統(tǒng)門(mén)描述符。門(mén)描述符中含有一個(gè)預(yù)設(shè)的內(nèi)核空間地址,它指向了系統(tǒng)調(diào)用處理程序:vector_SWI()(x86上system_call())。注意:不是系統(tǒng)調(diào)用服務(wù)程序本身。

即:系統(tǒng)命令——>用戶編程API——>系統(tǒng)調(diào)用(調(diào)用SWI匯編指令異常)——>系統(tǒng)調(diào)用處理函數(shù)(vector_SWI)——>具體的系統(tǒng)調(diào)用服務(wù)程序。其中藍(lán)色部分是內(nèi)核態(tài)函數(shù)。

2.所有的用戶空間系統(tǒng)調(diào)用函數(shù)都是通過(guò)調(diào)用SWI匯編指令(x86上int $0x80)異常、進(jìn)入內(nèi)核態(tài),此時(shí)、ARM默認(rèn)從某一固定地址執(zhí)行程序(vector_SWI()(x86上system_call())的地址)。vector_SWI()(x86上system_call())這個(gè)內(nèi)核函數(shù)又怎樣分發(fā)這些系統(tǒng)調(diào)用到各自的內(nèi)核服務(wù)程序中呢?Linux為每個(gè)系統(tǒng)調(diào)用都進(jìn)行了編號(hào)(0——_NR_syscall);同時(shí)在內(nèi)核中保存一張系統(tǒng)調(diào)用表,該表中保存了系統(tǒng)調(diào)用編號(hào)和其對(duì)應(yīng)的服務(wù)例程。因此,在系統(tǒng)調(diào)用通過(guò)門(mén)陷入內(nèi)核前,需要把系統(tǒng)調(diào)用號(hào)一并傳入內(nèi)核。這個(gè)傳遞工作是通過(guò)把系統(tǒng)調(diào)用號(hào)裝入相應(yīng)寄存器實(shí)現(xiàn)的。

有了如上的分析:系統(tǒng)調(diào)用處理程序vector_SWI()(x86上system_call())一旦運(yùn)行;就可以從相應(yīng)寄存器中得到數(shù)據(jù),然后再去系統(tǒng)調(diào)用表中尋找相應(yīng)的服務(wù)例程了。

注意:除了系統(tǒng)調(diào)用號(hào)之外,有的系統(tǒng)調(diào)用還需要傳遞一些參數(shù)給內(nèi)核;這是Linux在vector_SWI()(x86上system_call())調(diào)用時(shí)將參數(shù)等值傳入其他寄存器。

內(nèi)核系統(tǒng)服務(wù)例程結(jié)束時(shí),system_call()從相應(yīng)寄存器中獲得系統(tǒng)調(diào)用返回值,并把這個(gè)返回值放在曾保存用戶態(tài)相應(yīng)寄存器棧單元的那個(gè)位置;然后跳轉(zhuǎn)到ret_from_sys_call(),終止系統(tǒng)調(diào)用處理程序的執(zhí)行。

====================================================================================================================================

五、主要路徑

1.用戶空間:libc庫(kù)沒(méi)有研究代碼,大體機(jī)制如下——

調(diào)用SWI匯編指令(x86上int $0x80))軟中斷進(jìn)入內(nèi)核,并傳入中斷向量號(hào)

相關(guān)中斷向量號(hào)arm-2010.09/arm-none-linux-gnueabi/libc/usr/include/bits/syscall.h

#define SYS_getuid __NR_getuid

2.內(nèi)核空間:ARM中系統(tǒng)調(diào)用號(hào)定義路徑:kernel2.6.35.11/arch/arm/include/asm/unistd.h
#define __NR_getuid (__NR_SYSCALL_BASE+ 24)

異常進(jìn)入內(nèi)核空間函數(shù)路徑:kernel2.6.35.11/arch/arm/kernel/entry-common.s

默認(rèn)執(zhí)行vector_SWI(x86上system_call())函數(shù)

ARM中系統(tǒng)調(diào)用表定義路徑:kernel2.6.35.11/arch/arm/kernel/calls.S

CALL(sys_getuid) //第24個(gè),要與前面unistd中對(duì)應(yīng)

ARM中系統(tǒng)調(diào)用服務(wù)程序的聲明路徑:kernel2.6.35.11/include/linux/syscalls.h

asmlinkage long sys_getuid(void);

====================================================================================================================================

x86平臺(tái)相關(guān)路徑(內(nèi)核):

系統(tǒng)調(diào)用號(hào)路徑——kernel2.6.35.11/arch/x86/include/asm/unistd.h

system_call()函數(shù)路徑——kernel2.6.35.11/arch/x86/kernel/entry.S

系統(tǒng)調(diào)用表路徑——kernel2.6.35.11/arch/x86/kernel/syscall_table.S或直接在entry.S中定義


評(píng)論


技術(shù)專區(qū)

關(guān)閉