Welcome 微信登录

首页 / 操作系统 / Linux / Linux添加内核系统调用报告

Linux内核添加系统调用一、环境说明?操作系统:Ubuntu 11.04?旧内核版本:2.6.38.9?新内核版本:2.6.39?编译器版本:GCC 4.5.2二、实验目的?掌握内核的编译方法?深入理解内核编译的原理?掌握给内核添加系统调用的方法?了解系统调用的运行机制?学会在用户态调用系统调用三、实验原理系统调用:Linux内核中用户实现系统程序的一组子程序一个程序的虚拟地址空间分为用户态和内核态,而用户进程要想进入内核就要通过系统调用或以内核模块的形式添加到内核。下图展示了系统调用的实现过程(注:该图来源于网络资料):1、C程序通过包含头文件#include<syscall.h>通过源文件追踪,找到syscall()函数其实位/usr/include/unistd.h中如下:extern long int syscall (long int __sysno, ...) __THROW;该函数使用INT 0x80软中断内核将系统调用号传递给保存到eax中,然后将按系统调用号来查找系统调用表中的相应index的函数入口地址。来执行服务例程。#define SYSCALL_DEFINE1(name, ...) SYSCALL_DEFINEx(1, _##name, __VA_ARGS__)其实是通过宏定义定义系统调用函数位于./kernel/sys.c中SYSCALL_DEFINE1(my_traverse_process,int,num){..................................}SYSCALL_DEFINE1后的‘1’它表示该系统调用有一个参数,后面参数的含义依次是函数名、参数类型、参数名该函数执行完毕后,执行syscall_exit并将值返回。INT 0x80之所以能够执行,因为系统在启动时将0x80设置了系统调用中断门。三、步骤索引?编译升级内核?添加系统调用后重新编译内核?编写用户程序调用自己添加的系统调用四、实验步骤1、编译内核?从下载Linux内核版本2.6.39?解压内核到任意目录(这里不用必须解压到/usr/src/下,Linus也说不必那样做,况且自己也试验成功)(*)注:这样有个缺点,那就是在装玩模块后,系统会在/lib/modules/2.6.39/下创建该源码的软链接用于以后用户编译内核使用,当用户无意将其删除时,将会造成无法编译自己的模块。?进入内核目录?首先配置make menuconfig配置裁剪内核(如果没有什么必要可以复制/boot/config-***,这是现在的内核配置)cp /boot/config-***  ./.config?开始编译,可以执行make all,当然也可以分步完成make depmake cleanmake bzImahemake modules?安装内核驱动make modules_install?安装内核make install?生成引导镜像文件,并将其复制到/boot目录下mkinitramfs -o initrd.img-2.6.39 2.6.39cp initrd.img-2.6.39?最后更新grubupdate-grub?启动新的内核,成功。2、修改内核源码,添加系统调用?首先打开文件./arch/x86/include/asm/unistd_32.h在最后添加系统调用号,如下(最后一行):#define __NR_name_to_handle_at  341#define __NR_open_by_handle_at   342#define __NR_clock_adjtime 343#define __NR_syncfs        344#define __NR_my_traverse_process     345 /*This is added by yan,this is a test for system call*/?打开./arch/x86/kernel/syscall_table_32.S(最后一行).long sys_prlimit64 /* 340 */.long sys_name_to_handle_at.long sys_open_by_handle_at.long sys_clock_adjtime.long sys_syncfs.long sys_my_traverse_process?打开./include/linux/syscalls.h添加系统调用函数的声明asmlinkage long sys_my_traverse_process(int num); /*This is added by yan*/?打开./kernel/sys.c文件添加其实现函数SYSCALL_DEFINE1(my_traverse_process,int,num){    struct task_struct *pos;    struct list_head *current_head;    int count=0;    printk("Traversal module is working.. ");    current_head=&(current->tasks);    list_for_each_entry(pos,current_head,tasks)    {           count++;           printk("[process %d]: %s"s pid is %d ",count,pos->comm,pos->pid);    }    printk(KERN_ALERT"The number of process is:%d ",count);    printk(KERN_ALERT"This is a sample test output from kernel! And this is added by yan ");    return (long)num;}注:该函数的功能是遍历系统中的进程,并输出进程名和进程号,并返回输入的参数值。