1 系统调用的直观实现

实现一个 whoami 系统调用,用户程序调用whoami,一个字符串"userName"放在操作系统中,取出来打印

操作系统 第五节 系统调用的实现
用户程序和OS都在内存中,想要打印"userName"为什么不直接jmp到OS内核中打印它,而间接的采用whoami系统调用实现?

1,OS中存在许多重要的数据,不能随意的调用数据,不能随意的jmp
2,用户程序如果可以直接访问OS,那么root密码等其它重要信息会被暴露甚至被修改
3,如果可以随意访问OS,可以通过显存看到别人应用程序里的内容

2 内核(用户)态,内核(用户)段

硬件设计将内核程序和用户程序隔离,区分了内核态和用户态,在内存中对应的内存段称为内核段和用户段

操作系统 第五节 系统调用的实现
由于CS:IP指示当前执行指令的地址,所以用CS的最低两位表示:0是内核态,3是用户态,内核态可以访问任何数据,用户态不能访问内核数据,对于内存段和指令跳转都实现了隔离

为了隔离内核段和用户段,采用DPL(目标内存段的特权级)CPL(当前内存段的特权级),在head.s执行时,会对内核态的代码和数据建立gdt表,设置其DPL为0,启动用户程序时,设置用户段的CPL为3,用户态下执行时CPL均为3

对于标题1中的程序,用户程序运行在用户态,指令和数据属于用户段,OS处于内核态,OS内的数据与指令处于内核段,此时应用程序想要打印处于OS中的"userName",此时目标内存段是OS即内核段,当前内存段是应用程序即用户段,DPL=0,CPL=3,此时应用程序中的指令不能访问内核段,内核段拒绝了来自低特权级用户段的想直接访问内核段的jmp等指令

由于处于用户态的应用程序无法直接访问处于内核态的内核段数据,所以提供了系统调用来解决问题

3 硬件提供了 “主动进入内核的方法”

对于x86计算机,进入内核的唯一方法是中断指令 int,这是用户程序发起的调用内核代码的唯一方式

系统调用表面上是一个函数,但实际上它包含了 int 指令的一段程序,通过中断来进入内核

系统调用的核心:
1,用户程序中包含了一段包含int指令的代码
2,操作系统写中断处理,获取想调程序的编号
3,操作系统根据编号执行相应代码

4 系统调用的实现

如想要打印字符串的系统调用过程:
操作系统 第五节 系统调用的实现
真正完成作业的是write()系统调用,printf()函数要先展开为库函数printf(),由于参数的不匹配,需要转换成write()库函数,由系统调用write()访问OS,完成作业,一开始的printf()函数被最终展开成一段包含 int指令的代码,然后才能进入内核

5 系统调用的具体过程

操作系统 第五节 系统调用的实现

相关文章: