标签:
在nios中要实现一个类shell的交互系统,用户在终端可以通过命令调用系统函数。
想到linus当年在写下系统函数调用时,其实基于的思想是一样的,就是查表,每一种系统函数都对应一种中断服务号,然后通过0x80系统调用进入内核,然后查表,这里就可以找到对应的内核系统函数,回顾一下linus是怎么做到的。
就以系统函数open为例子
int open(const char * filename, int flag, ...)
{
register int res;
va_list arg;
va_start(arg,flag);
__asm__("int $0x80"
:"=a" (res)
:"0" (__NR_open),"b" (filename),"c" (flag),
"d" (va_arg(arg,int)));
if (res>=0)
return res;
errno = -res;
return -1;
}
这个open函数是一个变参函数,对变参函数的研究在前面用一片博文已经讲过,不多说。
主要看着这几个重要代码
"int $0x80"
:"0" (__NR_open)
这是软件调用,__NR_open是传入的参数,是一个宏定义
#define __NR_open 5
对与0x80这个中断号,需要在找到中断向量表其对应的中断向量,
在调度初始化函数sched.c中有
set_system_gate(0x80,&system_call);
就是对应中断0x80的中断向量为system_call,所以这就是为什么大家叫0x80是系统函数调用中断号了。
看看systen_call
_system_call:
push %ds
push %es
push %fs
pushl %eax # save the orig_eax
pushl %edx
pushl %ecx # push %ebx,%ecx,%edx as parameters
pushl %ebx # to the system call
movl $0x10,%edx # set up ds,es to kernel space
mov %dx,%ds
mov %dx,%es
movl $0x17,%edx # fs points to local data space
mov %dx,%fs
cmpl _NR_syscalls,%eax
jae bad_sys_call
call _sys_call_table(,%eax,4)
pushl %eax
看重要的几句代码
cmpl _NR_syscalls,%eax
call _sys_call_table(,%eax,4)
第一句对比传进来的参数,以确定需要调用什么系统函数
第二句调用相应的系统函数
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_sigsuspend, sys_sigpending, sys_sethostname,
sys_setrlimit, sys_getrlimit, sys_getrusage, sys_gettimeofday,
sys_settimeofday, sys_getgroups, sys_setgroups, sys_select, sys_symlink,
sys_lstat, sys_readlink, sys_uselib };
这其实是一个数组,其中typedef int (*fn_ptr)();
所以是函数指针数组,中断服务号作为数组的下标查表,
上面知道open的服务号是5,则 sys_call_table[5]确实对应着函数 sys_open的地址。
所以这样就完成的整个一个从用户到内核的调用,如图所示
所以在 nois中开发一个类shell的交互系统,是可以借鉴这个模型的,在对这个模型简化一下,这里面最重要的是那个表(函数指针数组),在nios是是单线程跑的,所以中断这块可以去掉,利用查询的方式来完成。还有就是如何将用户输入的命令和系统命令匹配起来,是否还是想linus一样采用数字来对应,但是实际用户输入的是字符串,所以是否字节是字符串匹配,既然是字符串就不可以是用数组下标的方式了,想到c++中的map类;这是一种关联变量,为此可以写一个结构体,也可以达到这种效果。
typedef struct key
{
用户命令字符串;
用户参数;
命令处理函数;
}KEY;
实际这就是一个命令所有相关的东西,然后用数组将这些命令结构体存储起来。
KEY cmd_table[];
通过对比每个结构体的第一个成员,以确定命令然后调用命令函数。
最终实现的初始化cmd_table如下
版权声明:本文为博主原创文章,未经博主允许不得转载。
标签:
原文地址:http://blog.csdn.net/u010442328/article/details/47160409