添加新的Linux内核系统调用

系统调用是内核提供给用户应用程序使用的内核函数名,这些函数提供了内核为用户应用程序所提供的系统服务功能。这些函数在用户应用程序中的书写格式与用户自定义函数形式上没有什么不同,但这些函数的编写和调用过程却与自定义函数有着很大的不同。它们需要事先在内核中安排好入口和函数体,当调用时会引发系统软中断根据对应的存根函数查中断表进入请求的内核函数。


在内核源代码中引入用户自定义系统调用入口过程如下:

  1. 在采用的系统内核源代码中找到与系统架构相对应的系统调用表文件如:syscall_table.S,在中添加新的系统调用函数名,要求声明的格式为:long sys_系统调用函数名
    例如:
    .long sys_mySyscall

  2. 在采用的系统内核源代码中找到与系统架构相对应的系统调用号文件如:unistd.h,在其中添加新的系统调用号的宏定义,要求声明的格式为:
    #define NR 系统调用函数名 系统调用最后一个编号
    例如:
    #define _NR_mySyscall 333

  3. 选择一个编有系统调用函数的内核文件将新加入的系统调用函数编写进去,例如:许多系统调用在 kernel/sys.c 中,我们也可在其中编写一个新的系统调用函数,假设该函数带有两个参数,第一个参数为一个 struct timeval 结构的指针,可通过该指针取回系统的秒和毫秒值,第二参数为 struct timespec 结构的指针,可通过该指针取回系统的秒和纳秒值 。该函数返回 jiffies 的值。

asmlinkage long sys_mySyscall( struct timeval * t_time,struct timespec * x_time){
    do_gettimeofday(t_time);//获取秒/毫秒
    x_time=current_kernel_time(););//获取秒/纳秒

    return 0;
}

接下来我们通过一个实例来了解一下上述过程:
操作系统:RedHat5 Enterprise
内核版本:2.6.18

  • 下载linux内核源码,参考地址:https://www.kernel.org/pub/linux/kernel/v2.6/

  • 打开终端,进入/usr/src目录,将源码解压到该目录。

  • 进入/usr/src/linux-2.6.18/kernel,在sys.c中添加如下代码

asmlinkage long sys_mySyscall( struct timeval * t_time,struct timespec * x_time){
    do_gettimeofday(t_time);//获取秒/毫秒
    x_time=current_kernel_time(););//获取秒/纳秒

    return 0;
}
  • 修改/usr/src/linux-2.6.18/include/asm-i386/unistd.h
    添加一行#define__NR_mycall 318 到当前的最大系统调用号之后,比如原来最大的是317,在317的这一行之后,加上一行 #define __NR_mySyscall 318
    修改 #define NR_mySyscall 的值,改成原来的值+1,比如原来是318 改成319
  • 编辑/usr/src/linux-2.6.18/arch/i386/kernel/syscall_table.S,在文件最后加上一行:
    .long sys_mycall

  • 编译内核
    1.打开终端,输入命令 cd /usr/src/linux-2.6.18
    2.输入命令 make mrproper
    3.输入命令 make clean
    4.输入命令 make menuconfig, 进入内核配置选项界面,进入后可执行选择Exit退出
    5.输入命令 make;make modules;make modules_install;make install 编译/安装内核(时间有点久,可以活动一下~~)
    6.按照如下配置/boot/grub/grub.conf
# grub.conf generated by anaconda  #  
# Note that you do not have to rerun grub after making changes to this file  
# NOTICE:  You have a /boot partition.  This means that  #          all kernel and initrd paths are relative to /boot/, eg.  #          root (hd0,0)  
#          kernel /vmlinuz-version ro root=/dev/sda3  
#          initrd /initrd-version.img  
#boot=/dev/sda  
default=0   //设置默认的启动内核为2.6.18 
timeout=5 
splashimage=(hd0,0)/grub/splash.xpm.gz  
hiddenmenu  title Red Hat Enterprise Linux Server (2.6.18)          
  root (hd0,0)          
  kernel /vmlinuz-2.6.18 ro root=root=LABEL=/dev/sda2 rhgb quiet enforcing=0  
  initrd /initrd-2.6.18.img  
title Red Hat Enterprise Linux Server (2.6.18-53.el5)          
  root (hd0,0)          
  kernel /vmlinuz-2.6.18-53.el5 ro root=LABEL=/ rhgb quiet          
  initrd /initrd-2.6.18-53.el5.img 

测试新添加的内核调用:

#include 
#include 
#include 

int main(void){
    struct timeval t_time_sys;
    struct timeval t_time_user;
    struct timespec x_time;

    while(1){
        syscall(318,&t_time,&x_time);
        gettimeofday(&t_time,NULL);
        printf("%u %u\n",t_time_sys.tv_sec,t_time_sys.tv_userc);
        printf("%u %u\n",t_time_user.tv_sec,t_time_user.tv_userc);
        sleep(2);
    }
}

参考文献:

  1. 下载及解包解压缩内核源码 http://book.51cto.com/art/201006/206554.htm
  2. linux中timeval结构体http://www.cnblogs.com/Neddy/archive/2012/01/31/2332957.html
  3. Linux内核中获取当前时间 http://blog.csdn.net/heanyu/article/details/6552578

你可能感兴趣的:(linux内核)