二.掌握系统调用的实现过程,通过编译内核方法,增加一个新

合集下载

编译内核-新增Linux系统调用过程

编译内核-新增Linux系统调用过程

一、题目:新增Linux系统调用(1)需要重新编译Linux内核(2)增加一个Linux的系统调用(3)写一个用户程序进行调用测试。

系统调用实现的功能:计算一个数字的三次方,并打印出来。

二、版本:编译版本:Win10上虚拟机(Virtual Box) Ubuntu(64bit)15.04系统原内核版本:3.19.0编译的新内核源码版本:3.2.75不同内核版本,32位和64位文件位置以及文件名可能有所不同。

添加系统调用时要根据自己的版本的文件位置和文件名修改相应的三个文件。

三、步骤:1.前期准备:下载内核及解压1.1下载内核:1.2打开终端获得权限然后再输入su输入刚刚设置的密码。

1.3移动文件并解压下载目录2.添加系统调用2.1添加系统调用函数在文末添加调用函数。

然后保存,关闭。

2.2 添加调用函数声明在文末#endif前添加函数声明。

然后保存关闭。

2.3添加系统调用号因为前一个系统调用号是311 所以这里我们写312将原本的#defineNR_syscalls (__NR_syscall_max+1)修改为:#defineNR_syscalls (__NR_syscall_max + 2)然后保存,关闭。

3.编译内核3.1安装基本编译器套件3.2编译3.1make mrproper清除以前配置(如果是第一次编译,不用执行此操作)3.2 make menuconfig配置内核(此处选择了默认配置)3.3 make编译内核如果电脑是双核则也可以用make–j4代替make(双核编译会更快一些)接下来就是漫长的等待过程,不过要随时注意是否编译过程中因有错误而停止。

我的电脑用了两个小时。

(也有教程里用的是make bzlmage和makemodules,make bzlmage+make modules=make)4.安装内核4.1makemodules_install4.2makeinstall4.2 reboot重启(或不使用命令直接对电脑进行重启)ﻩ重启之后在开机时候开机时候,如果是虚拟机需要同时按esc和↑键出现开机启动项(如果是真机开机一般会自动出现开机启动项),选择新建的内核版本进入。

编译Linux2.6内核并添加一个系统调用

编译Linux2.6内核并添加一个系统调用

1. 0 让新 内核和 旧内核 都可 以加载 的配置 的步骤 :
my. r h i 8 / o t z ma e/ o t / c /3 6 b o / l g b o a b mv. y t m. p/ o t / s e ma b o S
mv/ o t zma e/o t mln z 261 ..5 3 b / l g b b / i u - ..510 0 v
2 1 年第 4期 0 1

建 电

19 4
编 译 iu26内 并 添 加 一 个 系统调 用 Ln x . 核
张 伟 华 .王 海 英 。高 静
(河南 财经政 法 大学成 功 学院 河 南 郑 州 4 10 5 2 0)
【 摘 要 】 本 文 以实例 来详 细描 述 了从 准备 一直 到使 用新 内核 的 Lnx 。 : iu 26内核 编译过 程 , 然后介 绍 了
轻 易地 对它进 行修 改 .使 我们 能够 根据 自己的要 求 度 身 定制 一个更 高效 、 更稳 定 的 内核 。
系统调 用【 用户 进程 与 系统之 间 的接 口, 们在 2 ] 是 它 内核 中实 现 .其 主要 目的是 使得 用户 可 以使 用操 作 系 统提 供 的操作底 层设 备 的功 能 用 户 程序 肯定 要 操作
mv/ o t y tm. p/ o ' y t m. p 2 6 1 .. 5 b / se ma b oJ s e ma - .. 5 10 03 S , S mk n td/ o g n td 2.. 5 10 0 . 6.5 1 ii b r i i - 6 1 . . 5 3 i 2. 1 r mg v / o t rbgu e n ib / u / r b.o f g

操作系统实验一向LINUX内核增加一个系统调用

操作系统实验一向LINUX内核增加一个系统调用

操作系统实验一向LINUX内核增加一个系统调用一、背景介绍操作系统是计算机硬件与应用程序之间的接口,负责管理和调度计算机系统的各种资源,并提供用户与计算机系统的交互界面。

内核是操作系统的核心部分,负责管理和分配计算机系统的资源,执行各种任务。

系统调用是操作系统提供给应用程序的一种接口,可以让应用程序访问内核提供的功能,例如文件操作、进程管理、网络通信等。

在一些情况下,我们可能需要在LINUX内核中增加新的系统调用,以满足特定的需求。

本文将介绍如何向LINUX内核增加一个系统调用的具体步骤。

二、增加系统调用的步骤1.编写系统调用的具体实现代码首先,我们需要编写一个具体的系统调用的实现代码。

在LINUX内核中,系统调用的实现代码通常位于内核的/syscalls目录下。

我们可以在该目录下新建一个.c文件,编写我们自己的系统调用代码。

2.修改内核源代码3.更新系统调用表每个系统调用都在内核中有一个唯一的标识符,存储在一个叫做系统调用表的地方。

我们需要更新系统调用表,将新增的系统调用添加到表中。

这样,用户程序才能够通过系统调用号来调用新增的系统调用。

4.重新编译内核在修改完内核源代码后,我们需要重新编译内核。

这通常涉及到一些繁琐的步骤,例如配置内核选项、编译内核、安装内核等。

在重新编译内核之后,我们需要重新启动计算机,使新的内核生效。

5.修改用户程序最后,我们需要修改用户程序,以便能够调用新增的系统调用。

用户程序通常是通过C语言编写的,我们可以在用户程序的代码中添加对新增系统调用的调用代码。

三、实验结果在完成上述步骤后,我们就成功地向LINUX内核增加了一个系统调用。

用户程序可以通过系统调用调用自己新增的系统调用,从而实现特定的功能。

总结:本文介绍了向LINUX内核增加一个系统调用的具体步骤,包括编写系统调用的具体实现代码、修改内核源代码、更新系统调用表、重新编译内核和修改用户程序。

在实施这些步骤之前,我们需要对操作系统和内核的相关概念有一定的了解,并具备一定的编程能力。

增加系统调用实验报告(3篇)

增加系统调用实验报告(3篇)

第1篇一、实验目的1. 了解系统调用的基本概念和作用。

2. 掌握在Linux内核中增加系统调用的方法。

3. 熟悉系统调用在用户空间和内核空间之间的交互过程。

4. 提高编程能力和系统理解能力。

二、实验环境1. 操作系统:Linux2. 编译器:gcc3. 开发工具:内核源代码、makefile三、实验原理系统调用是操作系统提供的一种服务,允许用户空间程序请求内核空间的服务。

在Linux内核中,系统调用通过系统调用表来实现。

增加系统调用需要修改内核源代码,并重新编译内核。

四、实验步骤1. 创建系统调用函数首先,我们需要创建一个系统调用函数,该函数将实现一个简单的功能,例如打印一条消息。

以下是一个简单的系统调用函数示例:```cinclude <linux/module.h>include <linux/kernel.h>include <linux/init.h>static int __init hello_init(void) {printk(KERN_INFO "Hello, World!\n");return 0;}static void __exit hello_exit(void) {printk(KERN_INFO "Goodbye, World!\n");}module_init(hello_init);module_exit(hello_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("Your Name");MODULE_DESCRIPTION("A simple system call module");MODULE_VERSION("0.1");```2. 修改系统调用表接下来,我们需要修改内核源代码中的系统调用表,以注册我们创建的系统调用。

计算机操作系统实验指导计算机系统调用

计算机操作系统实验指导计算机系统调用

使用内核编译法添加系统调用
为了验证系统调用是否成功,编写验证代码如下。 #include <stdio.h> #include <linux/kernel.h> #include <sys/syscall.h> #include <unistd.h> int main() { long int a = syscall(三三三); printf("System call sys_helloworld reutrn %ld\n", a); return 0; }
如图地执行结果,我们得到sys_call_table地址:ffffffffabe00一a0 三. 编写Makefile文件,可参考实验指导书地内容。 四. 编译并装入模块 # sudo make //编译 # sudo insmod hello.ko //装入模块 # lsmod //该命令查看所有模块,用以检查hello是否被装入系统 # sudo rmmod hello.ko //卸载模块
三三三 六四 helloworld
sys_helloworld
使用内核编译法添加系统调用
六. 配置内核 # cd /usr/src/linux-四.一六.一0 # sudo make mrproper # sudo make clean # sudo make menuconfig 七. 编译与安装内核(与第七章类似) # sudo make -j八 # sudo make modules -j八 # sudo make modules_install # sudo make install 八. 重启系统 # uname -r 查看此时地内核版本
编译验证代码: # gcc hello.c

Linux系统调用详细全过程

Linux系统调用详细全过程
方法分配和释放内存。
6
系统命令、内核函数
系统调用与系统命令

系统命令相对API来说,更高一层。每个系统命令
都是一个执行程序,如ls命令等。这些命令的实现
调用了系统调用。
系统调用与内核函数


系统调用是用户进入内核的接口层,它本身并非内
核函数,但是它由内核函数实现。
进入内核后,不同的系统调用会找到各自对应的内
常,CPU便被切换到内核态执行内核函
数,转到了系统调用处理程序的入口:
system_call()。
int $0x80指令将用户态的执行模式转变为内
核态,并将控制权交给系统调用过程的起点
system_call()处理函数。
4
system_call()函数
system_cal()检查系统调用号,该号码告诉内核
SYMBOL_NAME(sys_exit)
.long
.longSYMBOL_NAME(sys_read)
SYMBOL_NAME(sys_fork)
.long
.longSYMBOL_NAME(sys_write)
SYMBOL_NAME(sys_read)
.long
.longSYMBOL_NAME(sys_open)
SYMBOL_NAME(sys_write)
.long
.long
…… SYMBOL_NAME(sys_open)
……
……
……
.long
SYMBOL_NAME(sys_getuid)
.long SYMBOL_NAME(sys_getuid)
* 4
+
21
系统调用的返回
当服务例程结束时,system_call( ) 从eax

实验报告增加新的系统调用参考模板

实验报告增加新的系统调用参考模板

操作系统《实验2》实验报告实验项目2:增加新的系统调用学号1209050123 姓名宋玉美课程号实验地点指导教师万少华时间2013.11评语:成绩教师签字万少华线性表链式存储(双向链表)插入、删除运算1、预备知识:Linux内核结构、Linux内核源码、Linux系统调用2、实验目的:增加新的系统调用3、实验内容及要求:(1)增加新的系统调用新增的系统调用名为get_proc_run_time,其功能是根据指定的进程pid,从该进程的进程描述符task_struct结构中提取出它的系统时间stime与用户时间utime (2)编译内核用编译内核的方法,将其增加到内核源码并编译内核(3)程序测试在用户空间编写测试程序测试该系统调用。

程序中调用此系统调用能准确的度量一个程序的时间效率,考虑是否还有别的方法比这更准确的学生信息,参数x, i,j从键盘输入(4)给出程序运行截图。

4、该文档的文件名不要修改,存入<学号><姓名> 命名的文件夹中5、该表中的数据只需填空,已有内容不要修改1.添加系统调用函数,修改文件/usr/src/linux—3.5/kernel/sys.c2. 添加系统调用号,修改文件/arch/x86/systemcalls/syscall_32.tbl3. 添加声明到头文件,修改文件,/include/linux/syscalls.h4. 重新编译内核(前几步只顾着运行忘记截图了,不好意思哈老师~)1)安装ncurses2)make menuconfig3)make dep 确定依赖性4)make clean 清理编译中间文件5)make bzImage 生成新内核6)make modules 生成modules 7)安装modules9)安装内核make install 10)配置grub引导程序13)重启。

重启系统,从grub菜单中选中新内核引导linux。

简述系统调用的实现过程

简述系统调用的实现过程

简述系统调用的实现过程系统调用是操作系统提供给用户程序的一种服务机制,用户程序可以通过系统调用来向操作系统发出请求,以获取需要的服务。

系统调用的实现过程可以分为以下几个步骤:1.客户程序发出系统调用请求:当用户程序需要操作系统提供的项服务时,它会通过指定的接口函数(通常是一个特定的汇编指令或函数调用)向操作系统发出系统调用请求。

这个接口函数通常被包含在操作系统的动态链接库中,用户程序通过加载并调用该库中的函数来实现系统调用。

2.用户程序传递参数:用户程序在发出系统调用请求时,通常需要传递给操作系统一些参数,以指定需要的服务和操作。

这些参数通常被存储在特定的寄存器或栈帧中,并通过调用操作系统的接口函数来传递给操作系统。

3.用户程序切换到内核模式:在进行系统调用时,用户程序需要从用户模式切换到内核模式。

这是因为系统调用需要访问操作系统的内核空间,而用户程序只能访问自己的用户空间。

为了实现这一切换,处理器会通过异常或中断的方式将控制权转移到操作系统的特定处理程序中,使得操作系统可以执行系统调用服务。

4.操作系统处理请求:当操作系统接收到用户程序发出的系统调用请求后,它会根据用户程序提供的参数和请求类型来执行相应的操作。

操作系统会根据请求的性质,执行相应的服务并返回结果。

5.操作系统返回结果给用户程序:在操作系统完成请求的处理后,它会将结果返回给用户程序。

返回结果通常也通过寄存器或栈帧来传递,并通过操作系统的接口函数返回给用户程序。

6.返回用户模式:当操作系统返回结果给用户程序后,用户程序会从内核模式切换回用户模式。

这样用户程序就可以继续执行后续的指令,并对操作系统返回的结果进行处理和使用。

总结起来,系统调用的实现过程包括发出系统调用请求、传递参数、切换到内核模式、操作系统处理请求、返回结果给用户程序以及返回用户模式等步骤。

通过这个过程,用户程序可以利用操作系统提供的服务来完成各种任务。

系统调用是操作系统与用户程序之间的桥梁,它为用户程序提供了一种方便且安全地访问操作系统功能的手段。

简述系统调用的实现过程。

简述系统调用的实现过程。

简述系统调用的实现过程。

1.引言系统调用是操作系统与用户空间之间的接口,为应用程序提供了访问内核级功能的方法。

当应用程序需要访问内核态的资源时,例如读写文件、创建新进程等,就需要通过系统调用来完成。

2.系统调用的分类系统调用可以分为几类,例如进程管理、文件管理、网络管理、内存管理等。

每种类型的系统调用都对应着一组内核级的函数,应用程序可以通过调用这些函数来完成相应的操作。

3.系统调用的实现系统调用的实现一般分为两个步骤:进入内核态和执行内核函数。

下面分别进行介绍。

3.1进入内核态当应用程序需要调用系统调用时,首先需要将控制权转移到内核态。

这可以通过软中断或者硬件中断来实现。

在Linux操作系统中,系统调用的调用号存储在eax寄存器中,通过int0x80指令触发0x80号中断进入内核态。

进入内核态后,会切换到内核态的栈,以便内核可以保存相关寄存器的值。

此外,内核会对用户传入的参数进行校验,确保其合法性。

3.2执行内核函数进入内核态后,内核会根据系统调用号找到对应的内核级函数。

函数执行完毕后,将返回值放入eax寄存器中,并返回到上下文,即切换回用户态。

需要注意的是,在内核态中不能直接访问用户空间的内存,必须通过一系列安全机制,如copy_from_user和copy_to_user等,将用户空间的内存数据拷贝到内核空间中进行操作。

4.系统调用的性能优化由于系统调用需要发生用户态到内核态的切换,因此开销较大。

为了提高性能,常常采用以下两种方式进行优化。

4.1零拷贝技术零拷贝技术是指,在系统调用中尽量避免内核空间与用户空间之间的数据拷贝操作。

例如可以使用mmap等方法,将文件的一部分映射到内存中,并通过指针进行读写,从而避免了数据复制的开销。

4.2系统调用重载系统调用重载是指将多个系统调用合并成一个,通过参数的不同来区分不同的子功能。

例如read、write、sendto等系统调用可以使用一个通用的系统调用,通过参数的不同来区分不同的操作,从而减少系统调用的数量,提高系统性能。

LinuxOS实验一:内核编译及添加系统调用

LinuxOS实验一:内核编译及添加系统调用

LinuxOS实验⼀:内核编译及添加系统调⽤简单整理下上周做的OS的lab1,前半部分主要介绍Linux内核编译和添加系统调⽤的流程,后半部分主要简要探索⼀下添加的系统调⽤中所⽤到的内核函数的源码。

⾸先贴⼀下这次实验的要求和我的实验流程图:Linux内核编译流程实验环境我的实验环境是VMware虚拟机下的Ubuntu 16.04,使⽤uname -a命令查看了⾃⼰的内核版本是4.15.0,于是确定待编译的新内核版本是:4.16.1(这个版本应略⾼于Linux系统的内核版本)。

同时,由于在内核编译过程中会⽣成较多的临时⽂件,如果磁盘空间预留很⼩,会出现磁盘空间不⾜的错误⽽导致内核编译失败;内存太⼩则会影响编译速度。

所以,这⾥建议虚拟机的配置参数:内存2GB以上,磁盘空间40GB以上。

由于我在做内核编译之前的时候就已经安装了linux虚拟机,所以这⾥我需要先扩展磁盘内存,具体参考了以下博⽂:。

下载内核源码并解压在中找到对应版本的内核源码并下载(如上⽂所说,这⾥我选择4.16.10,请视Linux系统的具体情况⽽定):在Linux系统中切换⾄root⽤户(随后的所有步骤都应以root⽤户进⾏操作,⽆法切换的可以尝试passwd命令修改root⽤户密码),然后将压缩⽂件复制到/home或其他⽐较空闲的⽬录中,进⼊压缩⽂件所在⼦⽬录,使⽤以下命令解压:xz -d linux-4.16.10.tar.xztar -xvf linux-4.16.10.tar清楚残留的.config和.o⽂件每次完全重新编译的时候都应从这⼀步开始,为了防⽌出现错误,我们先安装所需要的对应包:apt-get install libncurses5-dev随后执⾏命令:make mrproper配置内核执⾏命令:make menuconfig,随后出现诸如以下界⾯:我们选择默认值:保存配置信息,选⽤默认的⽂件名.config,最后编译内核先安装所需的包以防编译时报错:=>安装openssl:apt-get install libssl-dev=>安装bison:apt-get install bison=>安装flex:apt-get install flex随后执⾏命令:make,强烈建议使⽤命令make -j4或make -j8来加快编译速度,这⾥第⼀次进⾏内核编译的时候需要⽐较长的时间,我的电脑⼤概跑了⼀个多⼩时。

操作系统项目:向Linux内核添加一个系统调用

操作系统项目:向Linux内核添加一个系统调用

操作系统项⽬:向Linux内核添加⼀个系统调⽤内容:1. 向Linux增加⼀个系统调⽤2. 撰写⼀个应⽤测试程序调⽤该系统调⽤3. 使⽤ptrace或类似的⼯具对该测试程序进⾏跟踪调环境:1.vmware workstation 15.0.02.ubuntu-18.10-desktop3.linux-4.18.14步骤:⼀.准备环境在终端操作:sudo apt-get update //更新系统源码sudo apt-get install vim //安装vimsudo apt-get install libncurses5-dev libssl-dev //下载依赖包sudo apt-get install libelf-devsudo apt-get install build-essential opensslsudo apt-get install zlibc minizipsudo apt-get install libidn11-dev libidn11sudo apt-get install flex bison⼆.构建新内核1.准备在下载解压将在官⽹下好的内核直接拉到ubuntn⾥,然后将压缩包⽤指令移到/usr/src⽬录下(过程需要root权限)。

sudo su //获取rootsudo mv 压缩包位置 /usr/src //移动⽂件cd /usr/src //切换到该⽬录下进⾏操作sudo tar -xvflinux-4.18.14.tar.gz //解压2.添加系统调⽤先将⽬录切换到解压后的内核⾥操作1. sudo vim kernel/sys.c //添加⾃⼰的函数这⾥添加了sys_helloworld2.sudo vim arch/x86/include/asm/syscalls.h //添加声明3.sudo vimarch/x86/entry/syscalls/syscall_64.tbl //添加调⽤号3.删除⽆⽤的⽂件sudo make mrpropersudo make clean4.配置sudo make menuconfig此处直接save,exit即可,⽆需修改5.编译新内核并安装A.编译sudo make -j2 //将处理机内核总数调整为4,会明显加快编译速度(-j2为开启双线程编译)B.安装sudo make modules_installsudo make install6.重启//reboot三.测试先使⽤vim写⼀个测试的cpp之后gcc编译(前提是apt-get install build-essential安装gcc/g++/gdb/make 等基本编程⼯具。

嵌入式操作系统教学改革研究

嵌入式操作系统教学改革研究

嵌入式操作系统教学改革研究摘要:linux是一个完全免费、开放、跨平台的操作系统。

随着linux内核的日益完善,应用越来越广泛。

本文针对我校计算机科学与技术专业嵌入式方向的学生学习linux的情况,结合本人的教学经验,从授课内容、理论教学、实践教学及考核方式四个方面进行了研究。

关键词:linux;理论教学;实践教学中图分类号:g642虽然计算机的应用已渗透到各行各业,可是计算机科学与技术专业的学生就业形势却不太好,主要是由计算机科学与技术专业的专业特色不明确,无法满足社会需求所致。

目前,嵌入式计算机技术正在迅速发展,市场对各类嵌入式产品提出了巨大的需求。

因此,作为计算机科学与技术专业,突出专业特色的出路理应在嵌入式系统方面多下功夫。

而嵌入式操作系统是计算机科学与技术专业嵌入式方向的核心课程之一,在教学中起着至关重要的作用,是嵌入式系统开发与设计的灵魂。

嵌入式操作系统的种类很多,如linux、c/os、windows ce、vxworks 等,而我们之所以选择linux操作系统,是因为:linux是一个免费的操作系统,用户可以免费获得其源代码,并能够随意修改。

它是在gnu的公用许可证gpl保护下发行的自由软件[1];同时由于它与arm的结合,是一种主流的解决方案,已经广泛应用于掌上电脑、消费电子、工业控制等领域,具有良好的市场前景。

1 教学内容选取根据培养方向和教学内容的不同,将linux课程体系也相应分为应用开发和系统管理两类[2]。

系统管理主要以应用为主,讲解linux对计算机的管理功能、shell编程基础和服务器管理的应用,包括:linux用户/文件系统管理、linux网络管理、linux磁盘管理、系统和日志维护管理、linux安全优化、linux系统恢复与备份、shell初步编程、linux各类服务器管理等;应用开发主要理解和把握linux内核,将linux操作系统的原理、结构、内核特征及编程技术联系在一起,包括:shell编程基础、基于linux的c 语言程序开发、内核基础及实施细节及其程序设计等。

操作系统课内实验报告

操作系统课内实验报告

.. 西安交通大学实验报告操作系统实验报告2130505133计算机36班操作系统实验实验一:用户接口实验实验目的1)理解面向操作命令的接口Shell。

2)学会简单的shell编码。

3)理解操作系统调用的运行机制。

4)掌握创建系统调用的方法。

操作系统给用户提供了命令接口和程序接口(系统调用)两种操作方式。

用户接口实验也因此而分为两大部分。

首先要熟悉Linux的基本操作命令,并在此基础上学会简单的shell 编程方法。

然后通过想Linux内核添加一个自己设计的系统调用,来理解系统调用的实现方法和运行机制。

在本次实验中,最具有吸引力的地方是:通过内核编译,将一组源代码变成操作系统的内核,并由此重新引导系统,这对我们初步了解操作系统的生成过程极为有利。

实验内容1)控制台命令接口实验该实验是通过“几种操作系统的控制台命令”、“终端处理程序”、“命令解释程序”和“Linux操作系统的bash”来让实验者理解面向操作命令的接口shell和进行简单的shell编程。

➢查看bash版本。

在shell 提示符下输入:$echo $BASH_VERSION我们的版本是4.3.42(1)-release(2)建立bash 脚本,输出Hello word在编辑器中输入以下内容#!/bin/bashecho Hello World!执行脚本使用指令:$./script➢编写bash脚本,统计/my目录下c语言文件的个数通过bash 脚本,可以有多种方式实现这个功能,而使用函数是其中个一个选择。

在使用函数之前,必须先定义函数。

进入自己的工作目录,编写名为count 的文件脚本程序:#! /bin/bashfunction count{echo –n " Number of matches for $1: " #接收程序的第一个参数ls $1|wc –l #对子程序的第一个参数所在的目录进行操作}将count 文件复制到当前目录下,然后在当前目录下建立文件夹,在my 目录下建立几个c 文件,以便用来进行测试2)系统调用实验该实验是通过实验者对“Linux操作系统的系统调用机制”的进一步了解来理解操作系统调用的运行机制;同时通过“自己创建一个系统调用mycall()”和“编程调用自己创建的系统调用”进一步掌握创建和调用系统调用的方法。

操作系统-内核的编译与添加系统调用

操作系统-内核的编译与添加系统调用

广州大学松田学院操作系统课程设计(第 1 次)题目:修改内核及Linux内核重编译学生学号:00908010116学生姓名:林涛专业班级:计算机科学与技术(1)班老师姓名:甘页昌二○一二年六月修改内核及Linux内核重编译--为Linux内核增加系统调用systest( )1概述1、由同学自由组合,5人一组共同完成组长:林涛组员:董守义许建伟陈嘉茵黄坚钊分工:林涛:具体操作与指导董守义:平台的提供与调试许建伟:收集资料陈嘉茵:PPT的处理黄坚钊:后期修改2、修改内核的具体内容,由同组人员共同协商确定,如(1)为系统增加某个设备驱动程序(2)为系统增加一个系统调用如systest,该系统调用的功能,可以很简单3、组内成员中分工明确,同步进行4、第18周实验课,每组要求做PPT,上台讲解课程设计的内容以及编译过程(10分钟)5、其他同学为讲解的组打分(ABCDE级别)核修改内容介绍本次实验目的:为系统添加一个系统调用1.1 内核编译环境介绍硬件环境:台式机CPU:酷睿2双核2.5G 内存:3G软件环境:本次编译采用Ubuntu11.10系统。

并且系统安装在虚拟机中。

虚拟机版本:Vmware Workstation 8.04。

内核版本:linux-2.6.34.122内核修改2.1 系统设计2.1.1内核修改的基本思路配置内核→编译二进制内核映像文件→编译模块2.1.2内核修改的实现步骤搭建环境:在Win7 环境下安装虚拟机软件,安装Ubuntu系统,为了给内核的编译预留足够的磁盘与内存空间,建议给Ubuntu系统分配20G硬盘空间,1G内存.。

任务描述:编译内核(注意内核编译需要root权限)获取root权限的方法:lt@ubuntu:~$ sudo passwd root[sudo] password for lt:Enter new UNIX password:Retype new UNIX password:passwd: password updated successfullylt@ubuntu:~$ suPassword:root@ubuntu:/home/lt#Retype new UNIX password:passwd: password updated successfully任务分析:内核编译过程中最复杂的是参数的配置,选项根据实际情况进行选择。

系统调用的实现原理【转】

系统调用的实现原理【转】

系统调⽤的实现原理【转】在看《unix/linux编程实践教程》时,忽然意识到,系统调⽤是如何实现的?在实际编程中,往往是调⽤相关的函数,⽐如open(),read()等等。

但是调⽤这些函数怎么可能让程序的运⾏在⽤户空间和内核空间切换呢?看了下⾯的⽂章,才知道怎么回事。

让我想到了《计算机组成原理》中讲到的东西。

原⽂地址:系统调⽤1什么是系统调⽤系统调⽤,顾名思义,说的是操作系统提供给⽤户程序调⽤的⼀组“特殊”接⼝。

⽤户程序可以通过这组“特殊”接⼝来获得操作系统内核提供的服务,⽐如⽤户可以通过⽂件系统相关的调⽤请求系统打开⽂件、关闭⽂件或读写⽂件,可以通过时钟相关的系统调⽤获得系统时间或设置定时器等。

从逻辑上来说,系统调⽤可被看成是⼀个内核与⽤户空间程序交互的接⼝——它好⽐⼀个中间⼈,把⽤户进程的请求传达给内核,待内核把请求处理完毕后再将处理结果送回给⽤户空间。

系统服务之所以需要通过系统调⽤来提供给⽤户空间的根本原因是为了对系统进⾏“保护”,因为我们知道Linux的运⾏空间分为内核空间与⽤户空间,它们各⾃运⾏在不同的级别中,逻辑上相互隔离。

所以⽤户进程在通常情况下不允许访问内核数据,也⽆法使⽤内核函数,它们只能在⽤户空间操作⽤户数据,调⽤⽤户空间函数。

⽐如我们熟悉的“hello world”程序(执⾏时)就是标准的⽤户空间进程,它使⽤的打印函数printf就属于⽤户空间函数,打印的字符“hello word”字符串也属于⽤户空间数据。

但是很多情况下,⽤户进程需要获得系统服务(调⽤系统程序),这时就必须利⽤系统提供给⽤户的“特殊接⼝”——系统调⽤了,它的特殊性主要在于规定了⽤户进程进⼊内核的具体位置;换句话说,⽤户访问内核的路径是事先规定好的,只能从规定位置进⼊内核,⽽不准许肆意跳⼊内核。

有了这样的陷⼊内核的统⼀访问路径限制才能保证内核安全⽆虞。

我们可以形象地描述这种机制:作为⼀个游客,你可以买票要求进⼊野⽣动物园,但你必须⽼⽼实实地坐在观光车上,按照规定的路线观光游览。

linux内核剖析(六)Linux系统调用详解(实现机制分析)

linux内核剖析(六)Linux系统调用详解(实现机制分析)

linux内核剖析(六)Linux系统调⽤详解(实现机制分析)本⽂介绍了系统调⽤的⼀些实现细节。

⾸先分析了系统调⽤的意义,它们与库函数和应⽤程序接⼝(API)有怎样的关系。

然后,我们考察了Linux内核如何实现系统调⽤,以及执⾏系统调⽤的连锁反应:陷⼊内核,传递系统调⽤号和参数,执⾏正确的系统调⽤函数,并把返回值带回⽤户空间。

最后讨论了如何增加系统调⽤,并提供了从⽤户空间访问系统调⽤的简单例⼦。

参考系统调⽤概述计算机系统的各种硬件资源是有限的,在现代多任务操作系统上同时运⾏的多个进程都需要访问这些资源,为了更好的管理这些资源进程是不允许直接操作的,所有对这些资源的访问都必须有操作系统控制。

也就是说操作系统是使⽤这些资源的唯⼀⼊⼝,⽽这个⼊⼝就是操作系统提供的系统调⽤(System Call)。

在linux 中系统调⽤是⽤户空间访问内核的唯⼀⼿段,除异常和陷⼊外,他们是内核唯⼀的合法⼊⼝。

⼀般情况下应⽤程序通过应⽤编程接⼝API,⽽不是直接通过系统调⽤来编程。

在Unix世界,最流⾏的API是基于POSIX标准的。

操作系统⼀般是通过中断从⽤户态切换到内核态。

中断就是⼀个硬件或软件请求,要求CPU暂停当前的⼯作,去处理更重要的事情。

⽐如,在x86机器上可以通过int指令进⾏软件中断,⽽在磁盘完成读写操作后会向CPU发起硬件中断。

中断有两个重要的属性,中断号和中断处理程序。

中断号⽤来标识不同的中断,不同的中断具有不同的中断处理程序。

在操作系统内核中维护着⼀个中断向量表(Interrupt Vector Table),这个数组存储了所有中断处理程序的地址,⽽中断号就是相应中断在中断向量表中的偏移量。

⼀般地,系统调⽤都是通过软件中断实现的,x86系统上的软件中断由int $0x80指令产⽣,⽽128号异常处理程序就是系统调⽤处理程序system_call(),它与硬件体系有关,在entry.S中⽤汇编写。

接下来就来看⼀下Linux下系统调⽤具体的实现过程。

操作系统:系统调用的实现

操作系统:系统调用的实现

操作系统:系统调⽤的实现内核态与⽤户态、内核段与⽤户段内核态与⽤户态是保护模式下的概念内核态:具有较⾼特权,可以访问所有寄存器和存储区,执⾏所有指令;OS⼀般运⾏在内核态⽤户态:较低权限的执⾏状态,仅能执⾏规定的指令(如不能随意 jmp ),访问指定的寄存器,应⽤程序⼀般只能在⽤户态运⾏计算机中⽤两个 bit 来表⽰四种特权状态,硬件将 0 作为内核态,3 作为⽤户态,Windows 与 Linux 均只使⽤两个状态如何保证应⽤程序不能进⼊到内核态?特权保护:⽤户态不能直接转向内核态从⽽执⾏特权操作,是由硬件保证的操作系统将内存分段看待,内核态执⾏在受保护的内核段,⽤户态对应⽤户段,⽤户态的程序不能由⽤户段直接跳到内核段,⽽段是由段寄存器来表⽰CPL(Current Privilege Level)当前特权级别,CS 寄存器的最低两位DPL(Destination/Descriptor Privilege Level)⽬标特权级别,段描述符的权限位RPL (Request Privilege Level)请求特权级别,访问的数据段 DS 的最低两位,段选择⼦的最低两位简单地说,DPL描述⽬标内存段的特权级别,CPL表⽰当前特权级别,当 DPL>=CPL 时,才允许访问稍微详细⼀点说,RPL 可以与 CPL 不同,⽐如说 CPL=0,以 RPL = 3 请求访问 DPL = 3 的段,当然是允许的即 DPL >= RPL 且 DPL >= CPL 时允许访问,这⾥涉及到较为复杂的与 GDT 相关的实现,暂且不表进⼀步说明:段选择⼦与段描述符进⼀步说明:数据段与代码段权限检查即每次访问时通过硬件检查 DPL 与 CPL 是否满⾜条件,进⾏特权保护系统调⽤应⽤程序不能随意访问内核区域,但是它⼜需要特权级别完成⼀些任务,中断是硬件提供的进⼊内核的唯⼀⽅法, int 指令使 CS 中的 CPL 改成 0,可以"进⼊内核"系统调⽤就是⼀段包含 int 指令的代码,表现为⼀系列的内核函数,由应⽤程序来调⽤,在内核中执⾏,将结果返回给应⽤程序即系统调⽤是操作系统提供给上层程序访问内核的接⼝系统调⽤:1. 应⽤程序以系统调⽤的⽅式访问内核,防⽌程序随意更改、访问数据与指令2. 屏蔽底层细节,使应⽤程序有更好的移植性系统调⽤的过程:①⽤户程序通过系统调⽤触发相应的中断②操作系统进⾏中断处理,获取系统调⽤号(⼊⼝地址)③操作系统根据系统调⽤号执⾏相应的程序代码系统调⽤的实现下⾯是 Linux 0.11 中,write系统调⽤的实现可以看到,系统调⽤通过内联汇编传递参数、调⽤中断进⼀步说明:GCC内联汇编简介//<unistd.h>#define _syscall3(type,name,atype,a,btype,b,ctype,c) \type name(atype a,btype b,ctype c) \{ \long __res; \__asm__ volatile ("int $0x80" \: "=a" (__res) \: "0" (__NR_##name),"b" ((long)(a)),"c" ((long)(b)),"d" ((long)(c))); \if (__res>=0) \return (type) __res; \errno=-__res; \return -1; \}//write.c_syscall3(int,write,int,fd,const char *,buf,off_t,count)即write实现为int write(int fd, const char * buf, off_t count){long __res;__asm__ volatile("int $0x80": "=a"(__res): "0" (__NR_write),"b" ((long)(fd)),"c" ((long)(buf)),"d" ((long)(count)));if(__res>=0)return (int) __res;errno =- __res;return -1;}int 0x80 ⼜是如何利⽤中断执⾏相应的程序的呢?系统在 main 中进⾏初始化时执⾏的 sched_init 函数中设置了 0x80 的中断处理void sched_init(){set_system_gate(0x80, &system_call);//设置0x80的中断处理}//linux/include/asm/system.h#define set_system_gate(n, addr) _set_gate(&idt[n], 15, 3, addr);//idt中断向量表基址, n中断处理号, addr 中断服务程序#define _set_gate(gate_addr,type,dpl,addr) \__asm__ ("movw %%dx,%%ax\n\t" \"movw %0,%%dx\n\t" \"movl %%eax,%1\n\t" \"movl %%edx,%2" \: \: "i" ((short) (0x8000+(dpl<<13)+(type<<8))), \"o" (*((char *) (gate_addr))), \ eax的值放到idt[n]的前四个字节"o" (*(4+(char *) (gate_addr))), \ edx的值放到idt[n]的后四个字节"d" ((char *) (addr)), \"a" (0x00080000))相当于eax = 0x00080000 edx = addreax = 0x00080000 | (addr << 16)edx = addr & 0x0000 | (0x8000+(dpl<<13)+(type<<8)eax -> idt[n]前四个字节 edx -> idt[n]后四个字节这段代码将 system_call 的⼊⼝地址与相应的段选择符、DPL 及其他信息填充为 IDT 的⼀个表项即设置成为斯巴拉西注意这⾥ DPL 被置为 3,是⽤户态可访问的那么取到表项中的段选择⼦(Selector)与偏移地址(Offset)合成新的 PC(CS : IP)CS = 0x0008,CPL = 0,IP = addr = system_callsystem_call 就是中断 int 0x80 的处理程序,也就是说系统调⽤是通过中断机制实现的继续分析,system_call 如何执⾏⽤户程序调⽤的系统调⽤简单地来看,现实检查了系统调⽤号⼩于 nr_system_call - 1然后压栈保存 ds、es、fs,edx、ecx、ebx 的值再将 ds、es 设置为内核数据段,cs 已经被设置为内核代码段,fs 指向⽤户数据段通过 _sys_call_table + eax * 4 得到系统调⽤处理函数的⼊⼝地址eax 存放系统调⽤号,4 为 x86 系统地址字节数,_sys_call_table 为系统调⽤表基址pushl eax 压栈保存系统调⽤返回值,在 ret_from_sys_call 中使⽤最后恢复寄存器值,使⽤ iret 指令从中断返回再看 _sys_call_table 是如何组织的在 include/linux/sys.h 中所有的系统调⽤处理函数的指针,组织成这样的表且 fn_ptr 定义为返回值为 int 的函数指针,这⾥参数列表为空在 include/linux/sched.h 中就这样 call _sys_call_table + eax * 4 执⾏真正的系统调⽤功能,这⾥ eax 为 _NR_write = 4,执⾏ sys_write 函数在系统调⽤返回时 iret 指令会将 CPL 置回3再简单说⼀下 system_call 还做了哪些事在系统调⽤功能函数结束后,检查当前任务的运⾏状态,如果不在就绪状态就去执⾏调度程序如果在就绪态,但是时间⽚⽤完,也会执⾏调度程序即系统调⽤返回时会检查进程调度若继续执⾏,则返回⽤户程序系统调⽤总结⼀下因为安全问题,⽤户程序不能直接访问内核,由硬件检查 DPL >= CPL 保证⽽有些任务⼜必须在内核态下完成,系统调⽤是⽤户程序访问内核的接⼝,由中断机制实现因此,系统调⽤实际上是 int 0x80 对应的中断处理程序,再根据系统调⽤号执⾏不同的程序,完成相应的功能2019/12/15。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

二.掌握系统调用的实现过程,通过编译内核方法,增加一个新的系统调用。

另编写一个应用程序,调用新增加的系统调用。

(1) 实现的功能是:文件拷贝;
操作步骤:
1。

先在/usr/src/linux-2.4.18-3/kernel/sys.c文件末尾添加mycopy_s.c里的代码。

2。

修改文件 /usr/src/linux-2.4.18-3/include/asm-i386/unistd.h文件在文件中相应位置加上:
#define __NR_mycopy 239
3.修改文件 /usr/src/linux-2.
4.18-3/arch/i386/kernel/entry.S文件
在文件中相应位置加上:
.long SYMBOL_NAME(sys_mycopy)
编译内核:(过程中要先后使用的命令如下,其中后两步操作为非必要,若不执行,则新内核下某些系统功能将无法实现)
make mrproper
make oldconfig
make dep
make clean
make bzImage
make modules
make modules_install
maek install
这几步均成功完成后,新内核已经生成,执行如下步骤:
cp /usr/src/linux-2.4.18-3/arch/i386/boot/bzImage /boot/bzImage-new cp /usr/src/linux-2.4.18-3/System.map /boot/System.map-new
ln –sf /boot/System.map-new /boot/System.map
然后进入 /etc/lilo.conf(本机采用Lilo配置),添加如下代码:
image=/boot/bzImage-new
label=linux-new
root=/dev/hda1 /* hda1为安装linux的分区 */
然后进入 /sbin,运行lilo,完成配置。

重启系统后选择标签为linux-new的新内核进入。

在新内核下测试系统调用,其运行结果如下:
[YAKUZA$root] ls
copy.c test.c
[YAKUZA$root] gcc mycopy_test.c –o mycopy_test
[YAKUZA$root] ls
mycopy_test mycopy_test.c test.c
[YAKUZA$root] cat test.c
#include <stdio.h>
main()
{
printf(“This is a test!!”);
}
[YAKUZA$root] ./mycopy_test test.c test1.c
[YAKUZA$root] ls
mycopy_test mycopy_test.c test.c test1.c
[YAKUZA$root] cat test1.c
#include <stdio.h>
main()
{
printf(“This is a test!!”);
}
(2) 实现的功能是:P、V操作。

1。

在/usr/src/linux-2.4.18-3/kernel/sys.c末尾添加pv_s.c代码:
2。

修改文件 /usr/src/linux-2.4.18-3/include/asm-i386/unistd.h文件在文件相关位置加上:
#define __NR_creatsem 240
#define __NR_deletesem 241
#define __NR_myp 242
#define __NR_myv 243
3.修改文件 /usr/src/linux-2.
4.18-3/arch/i386/kernel/entry.S文件
在文件相关位置加上:
.long SYMBOL_NAME(sys_creatsem)
.long SYMBOL_NAME(sys_deletesem)
.long SYMBOL_NAME(sys_myp)
.long SYMBOL_NAME(sys_myv)
按照上题的方法编译产生新内核,在新内核下测试该系统调用
测试pv操作的程序:
算法思想:
通过创建进程的方法,申请一块共享内存(大小为一个字节),一个进程往里写数据,另外一个进程往外读数据,写数据的进程每往共享内存中写入一个数据后睡眠一段时间,而读数据的进程不采用睡眠机制,观察程序运行结果,如果读数据的进程也会同样跟随写数据进程的睡眠而等待,则说明PV机制得已实现。

运行结果:
[YAKUZA$root] ls
pv_test.c
[YAKUZA$root] gcc pv_test.c -o pv_test
[YAKUZA$root] ./pv_test
Father pid put 0 into memory!
Kid pid get 0 from memory!
Father pid put 1 into memory!
Kid pid get 1 from memory!
Father pid put 2 into memory!
Kid pid get 2 from memory!
Father pid put 3 into memory!
Kid pid get 3 from memory!
Father pid put 4 into memory!
Kid pid get 4 from memory!
Father pid put 5 into memory!
Kid pid get 5 from memory!
Father pid put 6 into memory!
Kid pid get 6 from memory!
Father pid put 7 into memory!
Kid pid get 7 from memory!
Father pid put 8 into memory!
Kid pid get 8 from memory!
Father pid put 9 into memory!
Kid pid get 9 from memory!
The members for the program are:
Shi Xiaolei :2001011830691
Zhang Rui :2001011830689
Xu Faqiang :2001011830690
Yang Yaxi :2001011830705
Li Fengming :2001011830703
调试过程:
本题主要让我们了解了如何在Linux下增加新的系统调用。

首先,Linux下的系统调用函数都有一定的标准格式,并且增加新的系统调用需要修改Linux 中不同地方的几个文件。

开始将系统调用加到内核里面去了以后,运行copy的测试程序时,发现拷贝出了一个空的文件,令人百思不得其解。

后面请教了老师,才知道系统调用时,需要现将用户态下的文件内容拷贝到核态下,再由核态拷贝回用户态下,这其中涉及到段的操作,于是在系统调用函数中加入了段操作的语句,重新编译内核,终于实现了增加新的copy系统调用。

但是,不知为什么PV就是不能实现,编译内核,和测试程序编译是都没有出现错误,就是读写进程不相互等待,输出是先执行完一个进程后再执行另一个进程,开始想不明白为什么,并且发现其他组也遇到类似的问题,在此郁闷了相当长一段时间。

后来与其他组的同学相互协作,查了些相关资料,才发现我们对函数semget ()的理解有误,此函数是建立一个信号灯集,而不是建立一个信号灯,struct sembuf 应该是对应于信号灯集的一个数组,建立信号灯时,需要指定信号灯集重信号灯的个数,再通过数组sembuf的下标对每一个信号灯操作。

根据上述思想修改后,实现了PV功能。

真可谓好事多磨!
体会与心得:
通过这次操作系统课程设计,我收获颇丰:对世界上最优秀的操作系统的内核有了一定了解,加深了对pv操作的理解,知道了怎么写设备驱动;而且增强了克服困难的能力。

刚看到课程设计内容时就懵了,linux根本就不太熟系,而且设备驱动程序从来没看过,感觉无从下手;后来寒假回去看了两本有关linux 方面的书,终于是找到一点头绪了;等到开学经老师讲解后,就有信心了。

但是在编程中还是遇到很多困难,我们大家一起查资料、讨论、分析、交流经验,最后终于搞定了。

相关文档
最新文档