当前位置:文档之家› 操作系统课设

操作系统课设

学号:课程设计课程名称操作系统学院计算机科学与技术学院专业班级姓名指导教师20 ——20 学年第学期课程设计任务书题目: 系统调用初始条件:学习了高级语言程序设计、汇编语言、数据结构、计算机组成原理课程,掌握了一种计算机高级语言。

要求完成的主要任务:(包括课程设计工作量及其技术要求,以及说明书撰写等具体要求)学习在Linux中产生一个系统调用以及怎样通过往Linux内核中增加一个新函数从而在该内核空间中实现对用户空间的读写。

这个函数的功能是返回当前的系统时间。

实验条件要求:每人一台Linux主机且有超级用户权限。

时间安排:指导教师签名: 20 年月日系主任(或责任教师)签名:年月日目录1.简介 (1)1.1实验环境 (1)1.2 Linux系统及内核 (1)1.3 Linux系统调用 (2)2.实验原理及详细步骤流程 (3)2.1.实验原理和思路 (3)2.2.详细步骤 (3)2.2.1.环境搭建及前期准备 (3)2.2.2.内核文件修改 (4)2.2.3.编译并切换内核 (5)2.2.4.测试新系统调用 (6)3.过程分析及实验结果 (7)2.1 过程分析 (7)2.2.运行结果 (9)4.调试记录 (9)5.自我评价与总结 (10)6.参考文献 (11)评分表 (12)一.简介1.1.实验环境1.2. Linux系统及内核Linux是一种开源电脑操作系统内核。

它是一个用C语言写成,符合POSIX标准的类Unix操作系统。

Linux是一个一体化内核(monolithic kernel)系统。

"内核"指的是一个提供硬件抽象层、磁盘及文件系统控制、多任务等功能的系统软件。

操作系统的主要功能是为应用程序的运行创建良好的环境,为了达到这个目的,Linux内核提供一系列具备预定功能的多内核函数,通过一组称为系统调用(system call)的接口呈现给用户。

系统调用把应用程序的请求传给Linux内核,调用相应的的Linux内核函数完成所需的处理,将处理结果返回给应用程序,如果没有系统调用和内核函数,用户将不能编写大型应用程序。

1. 3. Linux系统调用系统调用是应用程序和操作系统内核之间的功能接口。

其主要目的是使得用户可以使用操作系统提供的有关设备管理、输入/输入系统、文件系统和进程控制、通信以及存储管理等方面的功能,而不必了解系统程序的内部结构和有关硬件细节,从而起到减轻用户负担和保护系统以及提高资源利用率的作用。

Linux系统调用,包含了大部分常用系统调用和由系统调用派生出的的函数。

系统调用在Linux系统中发挥着巨大的作用,如果没有系统调用,那么应用程序就失去了内核的支持。

我们在编程时用到的很多函数,如fork、open等这些函数最终都是在系统调用里实现的,fork和exit,这两函数都是glibc中的函数,如果我们跟踪函数的执行过程,看看glibc对fork和exit函数的实现就可以发现在glibc的实现代码里都是采用软中断的方式陷入到内核中再通过系统调用实现函数的功能的。

由此可见,系统调用是用户接口在内核中的实现,如果没有系统调用,用户就不能利用内核。

Linux系统调用机制如下 :在Linux系统中,系统调用是作为一种异常类型实现的。

它将执行相应的机器代码指令来产生异常信号。

产生中断或异常的重要效果是系统自动将用户态切换为核心态来对它进行处理。

这就是说,执行系统调用异常指令时,自动地将系统切换为核心态,并安排异常处理程序的执行。

为使系统调用的执行成为一项简单的任务,Linux提供了一组预处理宏指令。

它们可以用在程序中。

这些宏指令取一定的参数,然后扩展为调用指定的系统调用的函数。

一旦宏指令用特定系统调用的相应参数进行了扩展,得到的结果是一个与系统调用同名的函数,它可以在用户程序中执行这一系统调用。

二.实验原理及详细步骤流程2.1.实验原理和思路如果用户需要在在Linux中添加新的系统调用,应该遵循几个步骤才能添加成功,下面几个步骤详细说明了添加系统调用的相关内容。

1.修改Linux内核编写源代码,向Linux内核文件添加新的系统调用函数,包括系统调用函数实现、设置系统调用号、添加系统调用声明到头文件。

2.重建Linux内核3.切换新Linux内核2.2.详细步骤流程2.2.1.环境搭建及前期准备①下载并安装Ubuntu系统从Ubuntu官网获取Ubuntu 14.10系统镜像并安装②安装必备编译工具及实验过程所需相关依赖安装libncurses5-dev build-essential kernel-package libncurses5-dev,其中libncurses5-dev是为之后配置内核能运行 make menuconfig程序做准备,Build-essential为编译工具,kernel-package是编译内核工具③下载内核源码源码内核版本为 3.14.34,下载并解压,移动至目录/usr/src,命令如下:tar -xvf linux-3.14.34.tar.xzcp –r linux-3.14.34.tar.xz /usr/src2.2.2.内核文件修改①系统调用函数实现修改kernel/sys.c文件,在文件末尾添加如下代码实现时间调用:asmlinkage long sys_time_call(void){struct timex txc;struct rtc_time tm;do_gettimeofday(&(txc.time));rtc_time_to_tm(_sec,&tm);printk("UTC time :%d-%d-%d %d:%d:%d \n",tm.tm_year+1990,tm.tm_mon,tm.tm_mday,tm.tm_h our,tm.tm_min,tm.tm_sec);return 0;}②设置系统调用号修改arch/x86/syscalls/syscall_64.tbl文件,在文件末尾添加如下代码:316 i386 time_call sys_time_call //316即为新的系统调用号③添加系统调用声明到头文件在文件倒数第二行,即“#endif /* __ASM_GENERIC_SYSCALLS_H */ ”这行的上面一行添加如下内容#ifndef sys_time_callasmlinkage long sys_time_call();#endif2.2.3.编译并切换内核①生成内核配置文件执行命令#make menuconfig,决定将内核的各个功能系统编译进内核还是编译为模块还是不编译。

选择save后exit。

②编译内核执行命令#make,对修改后的内核进行编译③加入模块执行命令#make modules_install④生成可执行的内核引导文件执行命令#make bzImage,生成内核引导文件,其路径是:arch/x86/boot/bzImage,然后执行命令#cp arch/x86/boot/bzImage /boot/vmlinuz-3.14.34,将刚生成的引导文件拷贝到/boot的目录下,并重新命名为vmlinuz-3.14.34⑤将System.map复制到/boot下执行命令#cp System.map /boot/System.map-3.14.34⑥生成initrd.img文件执行命令:#cd /lib/modules/3.14.34#update-initramfs –c –k 3.14.34⑦自动查找新内核,并添加至grub引导执行命令#update-grub2.2.4.测试新系统调用①编写测试代码,代码如下#include<stdio.h>#include<unistd.h>int main(){//通过系统调用号316调用添加的函数,获取当前时间printf("%ld\n",syscall(316));return 0;}编译运行以上代码,并执行命令dmesg -c查看查看系统调用log日志三. 过程分析及实验结果2.1过程分析①系统调用函数代码分析:asmlinkage long sys_time_call(void)//asmlinkage表示这些函数通过堆栈而不是通过寄存器传递参数{struct timex txc;/*timex是Linux内核内置的时钟数据结构体,结构如下:struct timex {… //省略与本次课程设计无关的参数struct timeval time; //系统时间(只读)}其中timeval也是Linux内核内置的时钟数据结构体,结构如下:struct timeval {time_t tv_sec; //从1970年1月1日开始计算的秒速… //省略与本次课程设计无关的参数}*/struct rtc_time tm;/*rtc_time是Linux内核内置的时钟数据结构体,结构如下:structrtc_time {int tm_sec; //秒,0~60(60是闰秒的需要)int tm_min; //分钟,0~59int tm_hour; //小时,0~23int tm_mday; //本月中的第几天,1~31int tm_mon; //自一月以来的第几个月,0~11int tm_year; //自1900年以来的年数…} */do_gettimeofday(&(txc.time));/* 获取1970年1月1日至当前时间的总秒数,并保存至txc的time属性中 */rtc_time_to_tm(_sec,&tm);/* 将保存在txc的time中的1970年1月1日至当前时间的总秒数tv_sec转换为年月日时分秒并保存至tm中 */printk("UTC time :%d-%d-%d %d:%d:%d \n",tm.tm_year+1970,tm.tm_mon,tm.tm_mday,tm.tm_hour,tm.t m_min,tm.tm_sec);// 输出当前时间return 0;}2.2.运行结果运行测试程序后,输出系统调用函数(返回当前系统时间函数)的返回值0,表明系统调用函数正常运行,系统调用正常且成功结束。

通过查看系统调用日志文件可以查看系统调用函数的输出,为当前系统时间四.调试记录①实验中对内核编译时提示permission denied,后发现是使用root 权限执行命令。

对内核进行操作时绝大多数命令均需以root权限运行。

②在设置系统调用号时,64位系统需要修改syscall_64.tbl文件,而不是syscall_32.tbl文件,否则会找不到系统调用号③自定义系统调用函数名需以sys_开头五.自我评价与总结虽然已经使用了近一年的linux系统了,但由于觉得学习Linux 内核相当困难麻烦,一直对Linux系统内核没有进行过深入的了解和研究,只是学习了一些Linux系统下常用了一些命令。

相关主题