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指令的代码,然后才能进入内核