Linux 增加系统调用 + 内核编译

1. Linux系统调用机制

1.1 系统调用是什么

Linux内核中设置了一组用于实现各种系统功能的子程序,称为系统调用。用户可以通过系统调用命令在自己的应用程序中调用它们。从某种角度来看,系统调用和普通的函数调用非常相似。区别仅仅在于,系统调用由操作系统核心提供,运行于核心态;而普通的函数调用由函数库或用户自己提供,运行于用户态。

1.2 系统调用实现方式

系统调用是靠一些宏,一张系统调用表,一个系统调用入口来完成。进程是不能访问内核的:它不能访问内核所占内存空间也不能调用内核函数;系统调用是这些规则的一个例外。其原理是进程先用适当的值填充寄存器,然后调用一个特殊的指令,这个指令会跳到一个事先定义的内核中的一个位置。在Intel CPU中,这个由中断0x80实现。进程可以跳转到的内核位置叫做sysem_call。这个过程检查系统调用号,这个号码告诉内核进程请求哪种服务。然后,它查看系统调用表(sys_call_table)找到所调用的内核函数入口地址。接着,就调用函数,最后返回到进程。

2. Linux内核

2.1 操作系统与内核

操作系统是一个用来和硬件打交道并为用户程序提供一个有限服务集的低级支撑软件。一个计算机系统是一个硬件和软件的共生体,它们互相依赖,不可分割。计算机的硬件,含有外围设备、处理器、内存、硬盘和其他的电子设备组成计算机的发动机。但是没有软件来操作和控制它,自身是不能工作的。完成这个控制工作的软件就称为操作系统,在Linux的术语中被称为“内核”,也可以称为“核心”。Linux内核的主要模块(或组件)分以下几个部分:存储管理、CPU和进程管理、文件系统、设备管理和驱动、网络通信,以及系统的初始化(引导)、系统调用等。

2.2 Linux内核的特性

Linux由C语言写成,符合POSIX标准的类Unix操作系统。Linux 还是一个动态内核,支持动态添加或删除软件组件。被称为动态可加载内核模块,它们可以在引导时根据需要(当前特定设备需要这个模块)或在任何时候由用户插入。

3. 添加系统调用

3.1 环境

本次实验环境是Windows 10(x64)上使用VMware® Workstation 12 Pro(12.5.0 build-4352439)搭建的Linux虚拟机Ubuntu 14.04.3(32位),内核版本4.4.0-31-generic (buildd@lgw01-01), gcc版本4.8.4。

3.2 下载源码

首先,从www.kernel.org下载内核源代码 ,使用命令解压源码包,命令如下:

tar -zxvf linux-4.4.tar.gz
sudo chmod 777 -R linux-4.4

接着,将源码移动到/usr/src文件夹下。

3.3 修改SYS_CALL_TBL

向文件./arch/x86/syscalls/syscall_32.tbl中添加系统调用号:

359 hello sys_hello

3.4 修改SYSCALL头文件

向文件./include/linux/syscalls.h中添加系统调用函数原型:

asmlinkage long sys_hello(void);

3.5 修改SYS源文件

修改文件./kernel/sys.c,添加系统调用函数的定义:

asmlinkage long sys_hello(void)
{
printk(KERN_DEBUG"Hello World!");
return 0;
}

注意此处使用的是内核态的printk,相关内容在后文中解释。

4. 编译Linux内核

4.1 准备

接下来进行内核编译,编译之前首先检查依赖库的情况,安装需要的库:

sudo apt-get install libssl-dev
sudo apt-get install libncurses5-dev

4.2 获取本地配置

输入cp /boot/config-,然后按下Tab键,系统会自动填上该目录下符合条件的文件名,然后继续输入 .config ,目的是使用在boot目录下的原配置文件。使用

sudo make localmodconfig

则按照本地配置来编译内核。

4.3 编译

依此运行如下命令:

sudo make -j4
sudo make -j4 modules_install
sudo make -j4 install

分别是使用四个线程编译内核、编译模块和安装。

4.4 修改和更新GRUB

5. 附录

Printk函数

printk相当于printf的孪生姐妹,她们一个运行在用户态的,另一个则在内核态被人们所熟知的。使用方法是:

printk(日志级别 “消息文本”);

日志级别一共有8个级别,printk的日志级别定义如下(在kernel.h中):

#defineKERN_EMERG"<0>"/紧急事件消息,系统崩溃之前提示,表示系统不可用/
#defineKERN_ALERT"<1>"/报告消息,表示必须立即采取措施/
#defineKERN_CRIT"<2>"/临界条件,通常涉及严重的硬件或软件操作失败/
#defineKERN_ERR"<3>"/错误条件,驱动程序常用KERN_ERR来报告硬件的错误/
#defineKERN_WARNING"<4>"/警告条件,对可能出现问题的情况进行警告/
#defineKERN_NOTICE"<5>"/正常但又重要的条件,用于提醒。常用于与安全相关的消息/
#defineKERN_INFO"<6>"/提示信息,如驱动程序启动时,打印硬件信息/
#defineKERN_DEBUG"<7>"/调试级别的消息/

猜你喜欢

转载自blog.csdn.net/O_1CxH/article/details/88766933