操作系统为用户态运行的进程与硬件设备进行交互提供供了一组接口。使得编程更加容易,极大的提高了系统的安全性,内核在要满足的某个请求之前就可以在接口级检查这种请求的正确性。而且这些接口使得程序更加具有可移植性。这组接口就是“系统调用”。
1. 服务例程:内核函数被称为系统调用的“服务例程”。
2. 封装例程:系统调用getpid()是服务例程sys_getpid()的封装例程。
3 .系统调用的基本要素:
(1)系统调用门:Linux内核在最高权限的0号级别运行,称之为内核态,其他软件都在最低权限的3号级别运行,称之为用户态。Linux使用软中断机制来完成用户进程不同运行级别的切换。系统调用接口基于软终端实现。在内核的初始化过程中为系统调用设置了0x80号中断门。系统调用时必须通过该中断门的安全验证,然后切换到内核态栈。
(2)内核态栈:在:Linux系统中,一个用户进程包括一个用户态栈和一个内核态栈。
(3)系统调用号:唯一的标识每一个系统调用。它定义在linux/arch/x86/include/asm/unistd_32.h.系统调用号的另一个目的是作为系统调用表的下标,当用户空间的进程执行一个系统调用的时候,这个系统调用号就被用来指明到底是要执行哪个系统调用。
(4)系统调用表:为了把系统调用号与相应的服务例程关联起来,内核利用了一个系统调用表,此表定义在linux/arch/x86/kernel/syscall_table_32.S中。
功能简介:该代码段保存了系统调用表,系统调用时,内核根据系统调用表找到相应的系统调用处理函数。
4.系统调用的处理步骤:
(1)初始化系统调用。
内核初始化期间,负责异常初始化的函数trap_init()通过下面的函数调用设置了系统调用的入口函数为system_call.
- set_system_gate(SYSCALL_VECTOR,&system_call);
其中SYSCALL_VECTOR在文件src/include/asm-i386/mach_default/irq_vectors.h中。
(2)请求系统调用。
(3)处理系统调用。
system_call()函数实现了系统调用处理程序。它首先把系统调用号和这个异常处理程序可以用到的所有CPU寄存器保存到相应的栈中。然后对用户进程传递来的系统调用号进行有效性检查,最后,根据EAX中所包含的系统调用号调用对应的服务例程。
5.如何添加新系统调用。
(1)修改系统调用表,具体在arch/x86/include/asm/unistd_32.h
- 353 #define __NR_sendmmsg 345
- 354 #define __NR_setns 346
- 355 #define __NR_mysyscall 347 //添加部分
- 356
- 357 #ifdef __KERNEL__
- 358
- 359 #define NR_syscalls 348 //添加部分
(2)在系统调用表中添加相应表项,具体在arch/x86/kernel/saarch/x86/syscall_table_32.S中。
- 347 .long sys_sendmmsg /* 345 */
- 348 .long sys_setns
- 349 .long sys_mysyscall //添加部分
(3)实现系统调用服务例程,具体在arch/x86/kernel/saarch/x86/sys_i386_32.c
- asmlinkage int sys_mysyscall(void)
- {
- current->uid=0;
- }
(4)重新编译内核:
make menuconfig(如果提示错误要先安装apt-get install ncurses-dev).
make
make moudles
make modules_install
male install
(5)编写用户态程序。
阅读(1887) | 评论(0) | 转发(0) |