操作系统真象还原[12章/一]-系统调用

一、系统调用的逻辑

        本章的内容前半部分对应于12.1~12.3节讲解了系统调用,理解了系统调用的逻辑后便可以轻松的增加自己编写的系统调用,所以理解这个逻辑非常重要。

        系统调用是提供给处于用户态即CPL=3下的用户进程使用的内核代码,这些功能非常重要以至于不能让用户态进程直接使用。比如内核态下可以直接向端口传输信息,但是用户态下是根据eflags中的IOPL位以及IO位图来决定能使用哪些端口,通常是不能使用任何端口的。这时如果我们想要往屏幕上输出信息就需要向显卡端口写数据,这在用户态下是办不到的,所以我们需要系统调用来帮助我们完成这件事。

        重点来了,借鉴linux的系统调用我们也使用0x80中断号作为系统调用中断号,具体流程如下。

        (用户态下)

        第一部分是用户态下的操作,首先用户态程序将子功能号写入eax寄存器,ebx保存第一个参数,ecx保存第二个参数,edx保存第三个参数,发出软中断命令int 0x80,系统调用会将结果保存在eax寄存器中,用户态下程序只需要从eax寄存器中取出值并返回即可,通常这部分由宏定义+内嵌汇编的形式编写。

        (内核态下)

        第二部分是进入中断后的操作,也是0x80号中断要实现的功能,由于进入中断所以需要保存进入中断前的处理器上下文环境,还需要将参数push进入内核栈,最后调用子功能号对应的内核函数,这一部分因为涉及到处理器上下文的保存用汇编语言实现更加方便。

        第三部分是根据eax中对应的中断子功能号执行对应的系统调用程序,这一部分由C语言编写,C语言编写的程序会将返回值保存到eax中。

        第四部分是执行完系统调用C函数后会继续执行0x80中断的汇编,这时我们需要将系统调用结果保存到进入中断时push的eax中,这样当从中断返回时,系统调用结果会被带入到用户态下的eax寄存器中,这样我们从用户态下的eax寄存器中便可以拿到结果使用。

        根据以上原理,我们实现系统调用要做的事情有。

        1、编写系统调用内嵌汇编宏_syscall0、_syscall1、_syscall2,其对应功能如第一部分所述(syscall.c中编写)

        2、用汇编语言编写0x80号中断,其对应的功能如第二和第四部分所述。并将其注册在IDT表中,且系统调用的中断门DPL需要设置为3才能通过特权级检查。(kernel.S中编写0x80号中断处理程序,interrupt.c中将0x80号中断处理程序加入到IDT表中)

        3、编写系统调用函数,并将系统调用函数根据其子功能号注册到syscall_table数组的对应下标处,汇编中会引入syscall_table数组并通过call [syscall_table + eax*4]的形式调用对应的子功能。(syscall-init.c编写系统调用,创建数组syscall_table并将对应的系统调用函数注册到数组syscall_table中)

        流程图简化如下:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值