向Linux内核增加一个系统调用

这是计算机系统工程课程实验之一,来自于《Operating System Concepts》(第七版)一书中个的第一个项目。由于书的版本和现在已经出现了代沟,书上的实验指导基本没有作用,所以只能通过自己网上学习。

认识Linux内核

什么是内核?

Linux是一个一体化内核(monolithic kernel)系统。“内核”指的是一个提供硬件抽象层、磁盘及文件系统控制、多任务等功能的系统软件。
实际上内核只是一个软件,可以安装和修改。在Linux中,它是独立的,模块化的,可以重新加载内核。

内核结构

Linux内核的主要模块(或组件)分以下几个部分:存储管理、CPU和进程管理、文件系统、设备管理和驱动、网络通信,以及系统的初始化(引导)、系统调用等。

实验内容

安装Linux系统

要修改内核首先得有内核支撑的环境——Linux系统。本实验采用的是Ubuntu 15.04 64bit操作系统,安装在虚拟机Vmware 12。这一步比较简单,按部就班就好了。当然安装完还需要配置基本的编译器比如GCC等,不过现在的Ubuntu都自带了,不用费心。如果编译出了问题,可以查查是不是缺了什么软件,再使用如下代码,就好了。

1
sudo apt-get install xxxx

之后可以到路径

1
2
3
4
### 下载内核
访问 [The Linux Kernel Archives](https://www.kernel.org/),你会看到有多种版本号的内核可以选择。建议选择2或3的版本。
**下面操作确保已经取得管理员权限**

sudo su

1
假设下载的是`linux-2.6.32.68.tar.xz`,移动到```/usr/src/```中,解压

tar xvf linux-2.6.32.68.tar.xz .

1
2
3
4
5
6
7
### 修改程序
修改程序的步骤和书上**几乎完全不同**,虽然我觉得按照书上的也能做但是第一还是强烈建议按照能一步一步做的教程来。
#### 修改源程序
```bash
vim /usr/src/linux-2.6.32.68/kernel/sys.c

找个地方加入下面的函数

1
2
3
4
5
asmlinkage int sys_helloworld() // 该函数名中有下划线
{
printk(KERN_EMERG "hello, world!"); //printk()函数是系统内核的输出函数,区别 //于printf()。
return 1;
}

修改头文件,增加系统调用声明

1
vim /usr/src/linux-2.6.32.68/arch/x86/kernel/syscall_table_32.S

将第225行(注意:此处会有两个地方名字叫做.long sys_ni_syscall, 其中一个后面有注释,请修改没有注释的那一条)改成.long sys_helloworld。

修改系统调用表,注册系统调用

1
vim /usr/src/linux-2.6.32.68/arc/x86/include/asm/unistd_32.h

增加一行

1
#define __NR_helloworld 225 // 这个数字与上面的行号对应。

编译安装内核

请回到内核的根目录(/usr/src/linux-2.6-32.68

  1. \$make mrproper 清除内核中不稳定的目标文件,附属文件及内核配置文件
  2. \$make clean 清除以前生成的目标文件和其他文件
  3. \$make menuconfi 这一步如果出错请看make menuconfig出错(ncurses)解决方案执行完3之后,会进入一个奇怪的界面,其中Device Drivers中scis相关的全悬赏,这个直接退出保存就可以了。
  4. \$make 耐心等待
  5. \$make modules_install 安装
  6. \$make install

这里要注意,ubuntu11之后的版本,启动引导使用的是grub2,没有网上说的/boot/grub/grub.conf这个文件了,取而代之的是grub.cfg

修改/etc/default/grub,将所有的timeout时间调成5,就能选择内核了。

失败

非常可惜的是,即使这样还是会失败。网络上的教程没有一个能够直接解决我的问题的。总结了一下,大概是因为我使用的内核版本和别人的都不一样以及我的ubuntu版本过高而且是64位。编译了若干次还是不成功,非常耗费时间,所以我决定下载一个完全和教程一样的内核开始修改和编译,如果还是不成功那可能即使ubuntu版本或者64bit的问题了。

重新开始,

这个步骤差不多,由于用的是一模一样的内容,所以直接放链接就好了。linux内核编译与系统调用的添加(适合3.0及以后版本内核)

搞完之后成功进入内核了,但是伴随着新的问题就是调用不正常,返回的还是-1而不是之前写好的1。仔细检查了代码之后发现我确实打错了一个变量名,所以调用不正常。