nios软核cpu中架构类shell的一种解决方式

在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如下

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-08-29 11:29:33

nios软核cpu中架构类shell的一种解决方式的相关文章

C++中的类继承(1) 三种继承方式

继承是使代码可以复用的重要手段,也是面向对象程序设计的核心思想之一.简单的说,继承是指一个对象直接使用另一对象的属性和方法.继承呈现了 面向对象程序设 计的层次结构, 体现了 由简单到复杂的认知过程.C++中的继承关系就好比现实生活中的父子关系,继承一笔财产比白手起家要容易得多,原始类称为基类,继承类称为子类,它们是类似于父亲和儿子的关系,所以也分别叫父类和子类.继承的方式有三种分别为公有继承(public),保护继承(protect),私有继承(private).定义格式如下: 1. 公有继承

mysql中limit与in不能同时使用的解决方式.

mysql中limit与in不能同时使用的解决方式. 分类: MySQL2011-10-31 13:53 1277人阅读 评论(0) 收藏 举报 mysqlsubquery MySQL5.1中子查询是不能使用LIMIT的,报错: "This version of MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery' " 这样的语句是不能正确执行的.select * from message where id i

appium在android 7.0真机上运行报错command failed shell:............ps:'uiautomator"的解决方式

appium版本:1_4_16 在CSDN中找到相关解决的方案,根据此解决方案顺利的解决了让人惆怅的问题,再次记录. 1.找到appium安装目录下的adb.js文件,目录为:Appium\node_modules\appium\node_modules\appium-adb\lib 2.打开adb.js,可使用notepad++编辑器等打开文件(说明:在修改代码的时候先注释掉以前的代码,并且添加自己容易识别的标记,以防出错后还有回旋的余地,或者将代码备份也可行),找到如下代码: ADB.pro

Ajax中的get和post两种请求方式的异同

Ajax中我们经常用到get和post请求.那么什么时候用get请求,什么时候用post方式请求呢? 在做回答前我们首先要了解get和post的区别.   1. get是把参数数据队列加到提交表单的ACTION属性所指的URL中,值和表单内各个字段一一对应,在URL中可以看到.post是通过HTTP post机制,将表单内各个字段与其内容放置在HTML HEADER内一起传送到ACTION属性所指的URL地址.用户看不到这个过程.   2. 对于get方式,服务器端用Request.QueryS

Java并发编程里的volatile。Java内存模型核CPU内存架构的对应关系

CPU内存架构:https://www.jianshu.com/p/3d1eb589b48e Java内存模型:https://www.jianshu.com/p/27a9003c33f4 多线程下的缓存一致性问题:https://www.jianshu.com/p/97dc5242c3a6 java volatile关键字解惑:https://www.jianshu.com/p/195ae7c77afe Google-Java Memory Model:https://www.jianshu.

关于mybatis中的实体类属性与数据库中的列名不一致的两种解决方法

1.我们都知道,在mybatis中写实体类的时候,是按照数据库中的列名来给实体类定义属性的,举个例子: public class User implements Serializable { private Integer id; private String username; private String address; private String sex; private Date birthday; } 2.但是,如果我们在定义实体类的时候,实体类中的属性与数据库列名不一致呢?比如:

MyBatis中主键回填的两种实现方式

主键回填其实是一个非常常见的需求,特别是在数据添加的过程中,我们经常需要添加完数据之后,需要获取刚刚添加的数据 id,无论是 Jdbc 还是各种各样的数据库框架都对此提供了相关的支持,本文我就来和和大家分享下数据库主键回填在 MyBatis 中的两种实现思路. 原生写法 框架来源于我们学过的基础知识,主键回填实际上是一个在 JDBC 中就被支持的写法,有的小伙伴可能不知道这一点,因此这里我先来说说在 JDBC 中如何实现主键回填. JDBC 中实现主键回填其实非常容易,主要是在构造 Prepar

在web项目中获取ApplicationContext上下文的3种主要方式及适用情况

最近在做web项目,需要写一些工具方法,涉及到通过Java代码来获取spring中配置的bean,并对该bean进行操作的情形.而最关键的一步就是获取ApplicationContext,过程中纠结和错误了很久,总结一下获取ApplicationContext的三种方式: 方式一:实现ApplicationContextAware接口 对于实现ApplicationContextAware接口的类,spring容器在初始化的时候会扫描他,并把容器的context环境注入给它.如下: 1 publ

我爱Java系列之---【SpringBoot中常用的注解和两种注入方式】

@EnableConfigurationProperties(DataSourceProperties.class) 来声明要使用DataSourceProperties 这个类并初始化该类对象,该类不用放在IOC容器中,可以通过该注解直接使用. [email protected]:一般写在类上边,通过该注解将当前类初始化到Spring的IOC容器中,其他类若想调用,直接用@Autowired去容器中拿. [email protected]: 一般写在类上边,标明该类是一个配置类,被注解的类内部