Linux0.11使用的Intel i386芯片共有256个中断,表现为中断号0~255.
其中前0~31号中断已经由Intel预定义,其余中断号为可编程中断。
32~47号分别对应linux的16个硬件中断信号(包括时钟、键盘、软盘等)。
0x80中断即128号中断为linux系统调用软中断。
系统调用int 0x80是一个软中断,是应用程序与Linux内核交互的接口。
在init/main.c初始化主程序main()中调用的sched_init()调度初始化函数中最后一行
set_system_gate(0x80,&system_call);
将0x80软中断与系统调用入口函数system_call联系起来。
---------------------------------------------------------------------------------------------------------------------------------------------
init/main.c : main() : line-132 --> kernel/sched.c : sched_init() --> set_system_gate(0x80,&system_call);
------------------------------------------------------------------------------------------------------------------------------------
为include/asm目录中system.h文件中的宏函数
#define set_system_gate(n,addr) \
_set_gate(&idt[n],15,3,addr)
#define _set_gate(gate_addr,type,dpl,addr) \ __asm__ ("movw %%dx,%%ax\n\t" \ "movw %0,%%dx\n\t" \ "movl %%eax,%1\n\t" \ "movl %%edx,%2" \ : \ : "i" ((short) (0x8000+(dpl<<13)+(type<<8))), \ "o" (*((char *) (gate_addr))), \ "o" (*(4+(char *) (gate_addr))), \ "d" ((char *) (addr)),"a" (0x00080000))
该函数即为设置0x80号中断的中断描述符,附陷阱门描述符结构
extern desc_table idt
typedef struct desc_struct {
unsigned long a,b;
} desc_table[256];
即把system_call函数的地址存入和优先级、中断类型的信息存入中断描述符表中0x80号中断
--------------------------------------------------------------------------------------------------------------------------------------------
int 0x80 --> kernel/system_call.s : 80 : _system_call --> include/linux/sys.h : 74 : sys_call_table[eax]()
------------------------------------------------------------------------------------------------------------------------------------
int 0x80在linux0.11中已经封装好系统调用接口,见include/unistd.h文件133~183行
共_syscall0、_syscall1、_syscall2、_syscall3四个宏函数,分别为无参~含有三个参数的系统调用
这里贴出无参的系统调用_syscall0代码
#define _syscall0(type,name) \ type name(void) \ { \ long __res; \ __asm__ volatile ("int $0x80" \ : "=a" (__res) \ //将输出赋给变量__res,"=a"表示强制使用ax寄存器 : "0" (__NR_##name)); \ //将__NR_name作为输入(系统调用号,在include/unistd.h定义),"0"表示使用与上一行一样的寄存器 if (__res >= 0) \ return (type) __res; \ errno = -__res; \ return -1; \ }
举个调用该宏函数的例子进行讲解
在init/main.c:23 调用该函数
static inline _syscall0(int,fork)
调用该函数的作用为定义了一个
静态(static) 内联(inline) 返回型为int(对应宏函数的type参数) 函数名为fork(对应宏函数name参数) 的无参函数:static inline int fork(void){}
该函数使用了内联汇编触发0x80号中断
--------------------------------------------------------------------------------------------------------------------------------------------
为C语言调用的汇编函数,在kernel/system_call.s第80行
主要作用为将进程从用户态切换到内核态,然后调用该文件94行的call _sys_call_table(,%eax,4)
这条指令的含义为跳转到sys_call_table + eax*4地址去执行。
即实际指令为跳转到系统调用函数指针数组中执行对应的系统调用。
以下为函数指针数组的初始化
typedef int (*fn_ptr)(); //在include/linux/sched.h 38行
fn_ptr sys_call_table[] = { sys_setup, sys_exit, sys_fork, sys_read, sys_write, sys_open, sys_close, sys_waitpid, sys_creat, sys_link, sys_unlink, sys_execve, sys_chdir, sys_time, sys_mknod, sys_chmod, sys_chown, sys_break, sys_stat, sys_lseek, sys_getpid, sys_mount, sys_umount, sys_setuid, sys_getuid, sys_stime, sys_ptrace, sys_alarm, sys_fstat, sys_pause, sys_utime, sys_stty, sys_gtty, sys_access, sys_nice, sys_ftime, sys_sync, sys_kill, sys_rename, sys_mkdir, sys_rmdir, sys_dup, sys_pipe, sys_times, sys_prof, sys_brk, sys_setgid, sys_getgid, sys_signal, sys_geteuid, sys_getegid, sys_acct, sys_phys, sys_lock, sys_ioctl, sys_fcntl, sys_mpx, sys_setpgid, sys_ulimit, sys_uname, sys_umask, sys_chroot, sys_ustat, sys_dup2, sys_getppid, sys_getpgrp, sys_setsid, sys_sigaction, sys_sgetmask, sys_ssetmask, sys_setreuid,sys_setregid };
------------------------------------------------------------------------------------------------------------------------------------
欢迎大家指正、讨论