您的位置 首页 编程

《ARM与Linux少许问题》第四章:ARM渠道体系调用原理剖析

本文基于mstar801平台Linux2.6.35.11版本。首先说明:系统调用不会导致进程上下文切换。一、介绍系统调用——Linux用户空间主动进入内核空…

本文根据mstar801渠道Linux2.6.35.11版别。

首要阐明:体系调用不会导致进程上下文切换。

一、介绍体系调用——Linux用户空间自动进入内核空间的仅有办法

1.体系调用是操作体系供给给用户程序调用的一组“特别”接口;用户程序能够经过这组“特别”接口来取得操作体系内核供给的服务。

从逻辑上来说,体系调用可被看成是一个内核与用户空间程序交互的接口;把用户进程的恳求传达给内核,待内核把恳求处理完毕后再将处理结果送回给用户空间。

2.体系调用依照功用逻辑大致可分为“进程操控”、“文件体系操控”、“体系操控”、“存储办理”、“网络办理”、“socket操控”、“用户办理”和“进程间通讯”几类。

3.内核接口:kernel2.6.35.11/arch/arm/include/asm/unistd.h

二、体系调用的首要用途

1.操控硬件——体系调用往往作为硬件资源和用户空间的笼统接口,比方读写文件时用到的write/read调用。

2.设置体系状况或读取内核数据——由于体系调用是用户空间和内核的仅有通讯手法,所以用户设置体系状况、比方开/关某项内核服务(设置某个内核变量)或读取内核数据都有必要经过体系调用。比方getpid、getpriority、setpriority和sethostname等。

3.进程办理——体系调用接口用来确保体系中进程能以多使命在虚拟内存环境下运转。比方fork、clone、execve和exit等。

三、内核函数和体系调用、用户编程接口(API)、体系指令的联系

1.体系调用并非直接和程序员或体系办理员打交道,它仅仅是一个经过软中止机制向内核提交恳求、获取内核服务的接口。而在实际运用中程序员调用的多是用户编程接口——api,而办理员运用的则多是体系指令。

2.用户编程接口(API)其实是一个函数界说,阐明了怎么取得一个给定的服务,比方read()、malloc()、free()、abs()等。

它有或许和体系调用方式共同,比方read()接口就和read体系调用一一对应;

往往会呈现几种不同的API内部用到同一个体系调用,比方malloc()、free()内部运用brk()体系调用来扩展或缩小进程的堆;

或一个API运用了好几个体系调用组合来完成使命;

更有些API乃至不需求任何体系调用,由于它不需求内核服务、如核算整数绝对值的abs()接口。

Linux体系中这些API首要是经过C库(libc)完成的;它除了界说的一些规范的C函数外,一个重要的使命是供给了一套封装例程、将体系调用在用户空间包装后供用户编程运用。

阐明:上述封装并非有必要;假如你乐意直接调用,Linux供给了一个syscall()的体系调用函数来完成调用。

3.体系指令相对编程接口更高了一层,它是内部引证API的可履行程序,比方咱们常用的体系指令ls、hostname等。

三、内核函数和体系调用的联系

内核函数没有想像中那么杂乱;它们和一般函数很像、只不过在内核完成,因而要满意一些内核编程的要求。

体系调用是一层用户进入内核的接口,它自身并非内核函数;进入内核后,不同的体系调用会找到对应到各自的内核函数——专业术语叫:体系调用服务例程。

总结:从用户视点向内核看;依次是体系指令、编程接口、体系调用和内核函数。
四、体系调用的完成

体系调用运用了ARM体系结构中的软件中止,软件中止和咱们常说的中止(硬件中止)不同之处在于———它是经过软件指令触发而并非外设,也便是说由编程人员宣布的一种反常;详细地讲便是调用SWI汇编指令(x86上int $0x80),这条汇编指令将发生向量为128的编程反常,ARM从用户形式切入办理形式、并强制R15-PC(程序计数器)为0x0000 0008,Linux从用户态进入内核态。见:《ARM与Linux少许问题》第一章:ARM作业形式

之所以体系调用需求凭借反常完成;是由于当用户态的进程调用一个体系调用时,CPU便被切换到内核态履行内核函数。咱们前边剖析ARM体系结构部分现已讲过进入内核态——ARM高特权形式,有必要经过体系的门机制——反常(SWI汇编指令(x86上int $0x80等);其他反常用户空间无法运用,都是由内核运用的。)。

1.SWI汇编指令(x86上int $0x80)指令的意图是发生一个编号为128的编程反常,这个编程反常对应中止描述符表IDT中的第128项——也便是对应的体系门描述符。门描述符中含有一个预设的内核空间地址,它指向了体系调用处理程序:vector_SWI()(x86上system_call())。留意:不是体系调用服务程序自身。

即:体系指令——>用户编程API——>体系调用(调用SWI汇编指令反常)——>体系调用处理函数(vector_SWI)——>详细的体系调用服务程序。其间蓝色部分是内核态函数。

2.一切的用户空间体系调用函数都是经过调用SWI汇编指令(x86上int $0x80)反常、进入内核态,此刻、ARM默许从某一固定地址履行程序(vector_SWI()(x86上system_call())的地址)。vector_SWI()(x86上system_call())这个内核函数又怎样分发这些体系调用到各自的内核服务程序中呢?Linux为每个体系调用都进行了编号(0——_NR_syscall);一起在内核中保存一张体系调用表,该表中保存了体系调用编号和其对应的服务例程。因而,在体系调用经过门堕入内核前,需求把体系调用号同时传入内核。这个传递作业是经过把体系调用号装入相应寄存器完成的。

有了如上的剖析:体系调用处理程序vector_SWI()(x86上system_call())一旦运转;就能够从相应寄存器中得到数据,然后再去体系调用表中寻觅相应的服务例程了。

留意:除了体系调用号之外,有的体系调用还需求传递一些参数给内核;这是Linux在vector_SWI()(x86上system_call())调用时将参数等值传入其他寄存器。

内核体系服务例程结束时,system_call()从相应寄存器中取得体系调用返回值,并把这个返回值放在曾保存用户态相应寄存器栈单元的那个方位;然后跳转到ret_from_sys_call(),停止体系调用处理程序的履行。

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

五、首要途径

1.用户空间:libc库没有研究代码,大体机制如下——

调用SWI汇编指令(x86上int $0x80))软中止进入内核,并传入中止向量号

相关中止向量号arm-2010.09/arm-none-linux-gnueabi/libc/usr/include/bits/syscall.h

#define SYS_getuid __NR_getuid

2.内核空间:ARM中体系调用号界说途径:kernel2.6.35.11/arch/arm/include/asm/unistd.h
#define __NR_getuid (__NR_SYSCALL_BASE+ 24)

反常进入内核空间函数途径:kernel2.6.35.11/arch/arm/kernel/entry-common.s

默许履行vector_SWI(x86上system_call())函数

ARM中体系调用表界说途径:kernel2.6.35.11/arch/arm/kernel/calls.S

CALL(sys_getuid) //第24个,要与前面unistd中对应

ARM中体系调用服务程序的声明途径:kernel2.6.35.11/include/linux/syscalls.h

asmlinkage long sys_getuid(void);

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

x86渠道相关途径(内核):

体系调用号途径——kernel2.6.35.11/arch/x86/include/asm/unistd.h

system_call()函数途径——kernel2.6.35.11/arch/x86/kernel/entry.S

体系调用表途径——kernel2.6.35.11/arch/x86/kernel/syscall_table.S或直接在entry.S中界说

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/fangan/biancheng/276829.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部