系统调用系统调用的过程voidsched_init(void){set_system_gate(0x80,&system_call);注册}system_call:c
系统调用 系统调用的过程 void sched_init ( void ) { . . . set_system_gate ( 0x80 , & system_call) ; } system_call: cmpl $nr_system_calls- 1 , % eaxja bad_sys_callpush % dspush % espush % fspushl % edxpushl % ecx # push % ebx, % ecx, % edx as parameterspushl % ebx # to the system callmovl $0x10 , % edx # set up ds, es to kernel spacemov % dx, % dsmov % dx, % esmovl $0x17 , % edx # fs points to local data spacemov % dx, % fs call sys_call_table ( , % eax, 4 ) pushl % eaxmovl current, % eaxcmpl $0 , state ( % eax) # statejne reschedulecmpl $0 , counter ( % eax) # counterje reschedule ret_from_sys_call: movl current, % eax # task[ 0 ] cannot have signalscmpl task, % eaxje 3f cmpw $0x0f , CS ( % esp) # was old code segment supervisor ? jne 3f cmpw $0x17 , OLDSS ( % esp) # was stack segment = 0x17 ? jne 3f movl signal ( % eax) , % ebxmovl blocked ( % eax) , % ecxnotl % ecxandl % ebx, % ecxbsfl % ecx, % ecxje 3f btrl % ecx, % ebxmovl % ebx, signal ( % eax) incl % ecxpushl % ecxcall do_signalpopl % eax3 : popl % eaxpopl % ebxpopl % ecxpopl % edxpop % fspop % espop % dsiret 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, sys_iam, sys_whoami } ;
添加系统调用 在kernal 的 makefile中增加文件
diff --git a/linux-0.11/kernel/Makefile b/linux-0.11/kernel/Makefile index 0afa1dc..2ae5152 100644 --- a/linux-0.11/kernel/Makefile +++ b/linux-0.11/kernel/Makefile @@ -26,7 +26,7 @@ CPP =gcc-3.4 -E -nostdinc -I../includeOBJS = sched.o system_call.o traps.o asm.o fork.o \panic.o printk.o vsprintf.o sys.o exit.o \ - signal.o mktime.o + signal.o mktime.o who.okernel.o: $(OBJS)$(LD) -m elf_i386 -r -o kernel.o $(OBJS) @@ -48,6 +48,11 @@ dep:(cd blk_drv; make dep)### Dependencies: +who.s who.o: who.c ../include/errno.h ../include/signal.h \ + ../include/sys/types.h ../include/sys/wait.h ../include/linux/sched.h \ + ../include/linux/head.h ../include/linux/fs.h ../include/linux/mm.h \ + ../include/linux/kernel.h ../include/linux/tty.h ../include/termios.h \ + ../include/asm/segment.hexit.s exit.o: exit.c ../include/errno.h ../include/signal.h \../include/sys/types.h ../include/sys/wait.h ../include/linux/sched.h \../include/linux/head.h ../include/linux/fs.h ../include/linux/mm.h \
编写在kernal中编写who.c文件,
# include # include # include # define NAMELEN 23 char username[ NAMELEN&#43; 1 ] ; int sys_iam ( const char * name) { unsigned int namelen &#61; 0 ; int i &#61; 0 ; int res &#61; - 1 ; while ( get_fs_byte ( name&#43; namelen) !&#61; &#39;\0&#39; ) namelen&#43;&#43; ; if ( namelen <&#61; NAMELEN) { for ( i &#61; 0 ; i < namelen; i&#43;&#43; ) { username[ i] &#61; get_fs_byte ( name&#43; i) ; } username[ i] &#61; &#39;\0&#39; ; res &#61; namelen; } else { printk ( "Error, the user space&#39;s name&#39;s length is %d longer than 23!\n" , namelen) ; res &#61; - ( EINVAL) ; } return res; } int sys_whoami ( char * name, unsigned int size) { unsigned int namelen &#61; 0 ; int i &#61; 0 ; int res &#61; - 1 ; while ( username[ namelen] !&#61; &#39;\0&#39; ) namelen&#43;&#43; ; if ( namelen < size) { for ( i &#61; 0 ; i < namelen; i&#43;&#43; ) { put_fs_byte ( username[ i] , name&#43; i) ; } put_fs_byte ( &#39;\0&#39; , name&#43; i) ; res &#61; namelen; } else { printk ( "Error, the kernel&#39;s name&#39;s length is longer than %d\n" , size) ; res &#61; - ( EINVAL) ; } return res; }
修改几个宏
jewinh&#64;ubuntu:~/oslab/linux-0.11$ git diff diff --git a/linux-0.11/include/linux/sys.h b/linux-0.11/include/linux/sys.h index c538fc1..1d1ef15 100644 --- a/linux-0.11/include/linux/sys.h &#43;&#43;&#43; b/linux-0.11/include/linux/sys.h &#64;&#64; -70,6 &#43;70,8 &#64;&#64; extern int sys_sgetmask();extern int sys_ssetmask();extern int sys_setreuid();extern int sys_setregid(); &#43;extern int sys_iam(); &#43;extern int sys_whoami();fn_ptr sys_call_table[] &#61; { sys_setup, sys_exit, sys_fork, sys_read,sys_write, sys_open, sys_close, sys_waitpid, sys_creat, sys_link, &#64;&#64; -83,4 &#43;85,4 &#64;&#64; 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 }; &#43;sys_setreuid,sys_setregid, sys_iam, sys_whoami }; diff --git a/linux-0.11/include/unistd.h b/linux-0.11/include/unistd.h index bf71dcb..43af333 100644 --- a/linux-0.11/include/unistd.h &#43;&#43;&#43; b/linux-0.11/include/unistd.h &#64;&#64; -129,6 &#43;129,8 &#64;&#64;#define __NR_ssetmask 69#define __NR_setreuid 70#define __NR_setregid 71 &#43;#define __NR_iam 72 &#43;#define __NR_whoami 73#define _syscall0(type,name) \type name(void) \ diff --git a/linux-0.11/kernel/system_call.s b/linux-0.11/kernel/system_call.s index 05891e1..8b096d6 100644 --- a/linux-0.11/kernel/system_call.s &#43;&#43;&#43; b/linux-0.11/kernel/system_call.s &#64;&#64; -58,7 &#43;58,7 &#64;&#64; sa_mask &#61; 4sa_flags &#61; 8sa_restorer &#61; 12-nr_system_calls &#61; 72 &#43;nr_system_calls &#61; 74 # origin is 72, now add sys_iam and sys_whoami
应用编写 通过上面操作&#xff0c;我们的内核已经有了两个系统调用的函数。
下面&#xff0c;我们在应用层去调用系统的函数。
iam.c
# define __LIBRARY__ # include # include _syscall1 ( int , iam, const char * , name) # define NAMELEN 100 char name[ NAMELEN] ; int main ( int argc, char * argv[ ] ) { int res; int namelen &#61; 0 ; if ( 2 <&#61; argc) { while ( ( name[ namelen] &#61; argv[ 1 ] [ namelen] ) !&#61; &#39;\0&#39; ) namelen&#43;&#43; ; printf ( "iam.c: %s, %d\n" , name, namelen) ; res &#61; iam ( name) ; errno &#61; EINVAL; return res; } }
# define _syscall1 ( type, name, atype, a) \ type name ( atype a) \ { \ long __res; \ __asm__ volatile ( "int $0x80" \ : "&#61;a" ( __res) \ : "0" ( __NR_## name) , "b" ( ( long ) ( a) ) ) ; \ if ( __res >&#61; 0 ) \ return ( type) __res; \ errno &#61; - __res; \ return - 1 ; \ } int iam ( char * name) { long __res; \__asm__ volatile ( "int $0x80" \: "&#61;a" ( __res) \: "0" ( __NR_iam) , "b" ( ( long ) ( name) ) ) ; \if ( __res >&#61; 0 ) \return ( type) __res; \errno &#61; - __res; \return - 1 ; \}
int sys_iam(const char *name) 做了什么&#xff1f;
通过get_fs_byte把用户空间的内容拷贝到内核空间。
在system_call中&#xff0c;fs&#61;0x17 是本地数据空间。
通过从寄存器中读出东西&#xff0c;回写到内核空间来完成&#xff0c;最终保存到who.c 中的 char username[NAMELEN&#43;1];
int sys_whoami(char *name, unsigned int size) 反过来&#xff0c;从内核空间把username的内容拷贝回来&#xff0c;
static inline unsigned char get_fs_byte ( const char * addr) { unsigned register char _v; __asm__ ( "movb %%fs:%1,%0" : "&#61;r" ( _v) : "m" ( * addr) ) ; return _v; } static inline void put_fs_byte ( char val, char * addr) { __asm__ ( "movb %0,%%fs:%1" :: "r" ( val) , "m" ( * addr) ) ; }
linux0.11中的编译&#xff1a;
gcc -o iam iam.c -Wall
测试用例 注意用例3&#xff0c;当输入太长时&#xff0c;iam不会修改username的内容&#xff0c;因此还是跟第二次修改之后的内容一致。
#/bin/shstring1&#61;"Sunner" string2&#61;"Richard Stallman" string3&#61;"This is a very very long string!"score1&#61;10 score2&#61;10 score3&#61;10expected1&#61;"Sunner" expected2&#61;"Richard Stallman" expected3&#61;"Richard Stallman"echo Testing string:$string1 ./iam "$string1" result&#61;&#96;./whoami&#96; if [ "$result" &#61; "$expected1" ]; thenecho PASS. elsescore1&#61;0echo FAILED. fi score&#61;$score1echo Testing string:$string2 ./iam "$string2" result&#61;&#96;./whoami&#96; if [ "$result" &#61; "$expected2" ]; thenecho PASS. elsescore2&#61;0echo FAILED. fi score&#61;$score&#43;$score2echo Testing string:$string3 ./iam "$string3" result&#61;&#96;./whoami&#96; if [ "$result" &#61; "$expected3" ]; thenecho PASS. elsescore3&#61;0echo FAILED. fi score&#61;$score&#43;$score3let "totalscore&#61;$score" echo Score: $score &#61; $totalscore%
总结 我们通过系统调用实现了一个库函数&#xff0c;这个库函数可以实现往内核的某个内存写入一些东西&#xff0c;然后从内核中再把这个东西读出来。