標籤:
在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如下
著作權聲明:本文為博主原創文章,未經博主允許不得轉載。
nios軟核cpu中架構類shell的一種解決方式