操作系统专题实验报告

更新时间:2023-04-25 15:18:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

操作系统专题实验报告

班级:计算机01

学号:10055008

姓名:陈世阳

2013 年5月27 日

目录

1内核编译与系统调用 (1)

1.1实验目的 (1)

1.2实验内容 (1)

1.3实验思想(或流程图) (1)

1.4实验步骤 (2)

1.5实验结果 (11)

1.6实验过程中的问题 (12)

1.7附件1 (13)

2 模块编程与字符设备驱动 (14)

2.1实验目的 (14)

2.2实验内容 (14)

2.3实验原理 (14)

2.4实验目标 (15)

2.5实验步骤 (15)

3 类EXT2文件系统 (18)

3.1实验目的 (18)

3.2实验内容 (18)

3.3实验原理 (18)

3.4实验步骤 (24)

4 实验总结与心得 (26)

5 附件 (27)

1内核编译与系统调用

1.1实验目的

1.熟悉Linux 操作系统的安装步骤,建立实验环境。

2.通过编译Linux 内核,掌握对内核功能的裁剪,以构造满足自身环境需要

的Linux 内核。

3.掌握系统调用的设计过程,为以后设计更复杂的系统调用奠定基础。

1.2实验内容

1.安装VMwrae 虚拟机,并在其上安装Linux 操作系统,并编译内核。

2.下载新的内核源代码,配置之后再进行编译链接,形成自己所需的内核映像

文件,并予以使用。

3.设计一个系统调用,功能为在内核日志中打印“Hello ,My ,World”(或

其他功能,如输出系统所有进程的相关信息)。

1.3实验思想

1.3.1内核

内核是一个操作系统的核心。它负责管理系统的进程、内存、设备驱动程序、文件和网络系统,决定着系统的性能和稳定性。

Linux作为一个自由软件,在广大爱好者的支持下,内核版本不断更新。新

的内核修订了旧内核的bug,并增加了许多新的特性。如果用户想要使用这些新特性,或想根据自己的系统度身定制一个更高效、更稳定的内核,就需要重新编译内核。

为了正确、合理地设置内核编译配置选项,从而只编译系统需要的功能代码,一般主要有下面四个考虑:

1) 自己定制编译的内核运行更快(具有更少的代码);

2) 系统将拥有更多的内存(内核部分将不会被交换到虚拟内存中);

3) 不需要的功能编译进入内核可能会增加被系统攻击者利用的漏洞;

4) 将某种功能编译为模块方式会比编译到内核内的方式速度要慢一些。

1.3.2系统调用

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

在Linux系统中,系统调用是作为一种异常类型实现的,它将执行相应的机

器代码指令来产生异常信号,产生中断或异常的重要效果是系统自动将用户态切

1

换为核心态来对它进行处理。这就是说,执行系统调用异常指令时,自动地将系统由用户态切换为核心态,并安排异常处理程序的执行。Linux用来实现系统调用异常的实际指令是:

int $0x80

这一指令使用中断/异常向量号128(即16进制的80)将控制权转移给内核。为达到在使用系统调用时不必用机器指令编程,在标准的C语言库中为每一系统调用提供了一段短的子程序,完成机器代码的编程工作。事实上,机器代码段非常简短。它所要做的工作只是将送给系统调用的参数加载到CPU寄存器中,接着执行int $0x80指令,然后运行系统调用。系统调用的返回值将送入CPU的一个寄存器中,标准库的子程序取得这一返回值,并将它送回用户程序。为使系统调用的执行成为一项简单的任务,Linux提供了一组预处理宏,这些宏指令取一定的参数,然后扩展为调用指定的系统调用的函数,这样就可以在用户程序中执行这一系统调用。

1.4实验步骤

1.4.1安装linux

Linux安装的主要步骤如下:

.

步骤一:新建虚拟机,选择自定义。如图1-4-1所示

图1-4-1

步骤二:稍后再将虚拟机光驱设为Linux 安装光盘镜像文件。如图1-4-2.

2

图1-4-2

步骤三:虚拟机磁盘选择IDE 类型。如图1-4-3.

3

图1-4-3

步骤四:创建虚拟机完成后编辑虚拟机,设置虚拟机镜像文件。如图1-4-4.

4

步骤五:启动虚拟机按照提示安装。如图1-4-5.

5

6

图1-4-5

步骤六:建立Linux 分区,默认即可,或者自定义分区。如图

1-4-6.

图1-4-6

步骤七:按照提示完成后续安装。安装完毕后从虚拟机启动新的系统。

为了使得诸操作系统和虚拟机下的了Linux 方便地共享文件,还得安

装VMwareTools,安装VMware Tools 的详细步骤如下:

1)进入Ubuntu Linux(桌面环境)。

2)首次使用Ubuntu 设置root 密码。在终端输入sudo passwd root ,然

后输入两遍新的root 密码即可。

3)获取Linux root 权限,终端输入su,按照提示输入root 密码后回车即

可。

4)按下 CTRL + ALT 组合键,进入主操作系统,点击虚拟菜单下的安装虚拟

机工具子菜单。

5)菜单:VM->Install VMware tools...(虚拟机->安装VMware Tools...)。

6)点击“弹出的对话框”中的“Install”按钮,确认安装VMware Tools。

7)鼠标点击Linux界面, 进入Linux,Linux 将会自动加载cdrom 到/mnt,

并打开窗口/mnt/cdrom ,显示VMware Tools 的Linux 软件包

VMwareTools-8.8.2-590212.tar.gz(其中8.8.2-590212为版本号,可能会有所不同)。

8)以命令行方式安装VMwareTools。

a) 使用如下命令挂载光驱设备,注意大小写:

#mount -t iso9660 /dev/cdrom /mnt/cdrom

(如果提示目录不存在,可以先mkdir /mnt/cdrom)

b) 使用如下命令进入/mnt 文件夹:

#cd /mnt/cdrom

c) 使用如下命令,解压缩VMware Tools软件包:

#tar –xvf VMwareTools-8.8.2-590212.tar.gz

d) 使用如下命令进入VMware Tools目录

#cd vmware-tools-distrib

e) 运行vmware-config-tools.pl 文件:

./vmware-config-tools.pl

最后会出现一个界面,让你选择当前屏幕的分辨率.选择一个数字,重新执

行一路回车即可。之后在/mnt下可以看到已经创建有一个名为hgfs的文件夹,该文件夹作为主操作系统与虚拟机Linux共享信息的文件夹,利用它可以实现两者之间的信息共享。

1.4.2 编译linux内核

本实验在Ubuntu8.04 上编译2.6.26 版本内核。

步骤一:从https://5e30fa2131126edb6f1a104e/ 上下载2.6.26 版本的内核源代码解

压至/usr/src 目录。

#cd /usr/src

#tar –xvf linux-2.6.26.tar.bz2

#cd linux-2.6.26

步骤二:配置前准备。

#make mrproper 该命令确保源代码目录下没有不正确的.o 文件以及文件

的互相依赖,如果要多次编译内核最好执行此步骤。

步骤三:启动内核配置程序。

7

8 配置方式采用基于文本菜单的配置界面。使用make menuconfig 命令。在make menuconfig 下,*表示Y ,M

表示M ,空白表示N 。该命令是基于ncurse 的菜单选择模式,需要ncurse 库的 支持, ubuntu 中默认没有安装,需要安装一下,使用以下命令安装:

# apt-get install libncurses5-dev

步骤四:配置内核各选项。

1)在General setup -> Local version –append to kernel release 中 为本地内核的版本号添加一个标志,本实验中添加-2,如图1-8 所示,这样新 内核的版本号为2.6.26-2。在多次编译同一版本的内核源代码时,此选项方便 查看新的本地内核版本。如图

1-4-7.

图1-4-7添加自定义版本号

2)鉴于之后要进行模块加载的实验,确保在Enable loadable module

support 中模块加载支持的选项被选中,如图1-4-8 所示。

9

图1-4-8

3)在文件系统File systems 中,确保选中对ext3 文件系统的支持,如图 1-11 所示。在File systems -> DOS/FAT/NT Filesystems 中确保选中对NTFS 文件系统的支持选项,如图1-4-9 所示。

图1-4-9ext3文件系统支持

步骤五:编译内核。

#make clean 完成删除前面步骤留下的文件,以避免出现一些错误。

#make bzImage 内核编译成功后,会在linux-2.6.26/arch/x86/boot 目录中生成一个新内核的映像文件bzImage 。

步骤六:编译安装可加载模块。

#make modules 设置了可加载模块 所以用此命令生成内核模块。

#make modules_install 安装生成的内核模块。

步骤七:安装编译生成的内核文件。

#make install 安装编译生成的内核文件。

步骤八:修改开机引导文件。

首先生成initrd 镜像文件。Ubuntu8.04 中使用mkinitramfs 命令。

# mkinitramfs –o initrd.img-2.6.26-2 2.6.26-2

在当前目录下生成initrd 镜像文件,然后把它移动到boot 目录下

#cp initrd.img-2.6.26-2 /boot/ initrd.img-2.6.26-2

接着更新grub 引导菜单,使用如下命令:

#update-grub

10 打开一下menu.lst 文件,检查一下新内核的镜像文件设置是否正确。 #gedit /boot/grub/menu.lst

将timeout 设置为10秒。

步骤九:重启系统,开机时按Esc 键,选择新的内核,如图1-4-10 所示。

#reboot

图1-4-10选择新内核

步骤十:验证内核版本

在终端输入uname –r ,若显示2.6.26-2 证明新内核编译安装成功,且 正在运行的系统使用的即是新编译的内核。

如图

1-4-11.

图1-4-11查看内核版本

1.4.3添加系统调用

Linux 下设计实现一个系统调用的步骤如下:

步骤一:设计系统调用源代码并将其加入Linux 内核源代码中。

在/usr/src/Linux-2.6.26/kernel 目录下,打开文件sys.c ,在文件的最 后部位增加系统调用函数:

asmlinkage int sys_my_syscall(int n)

{

printk("Hello,My,World"); //或者其他功能

return n;

}

步骤二:修改与系统调用表相关的文件,以便根据系统调用号在系统调用表 中确定其对应的系统调用名。

编辑系统调用入口文件。打开/usr/src/linux-2.6.26/arch/x86/kernel 目 录下的syscall_table_32.S 文件,在最后添加系统调用符号名:

.long sys_my_syscall

以便以系统调用号来确定新的系统调用的入口地址。

步骤三:修改头文件unistd.h ,定义新的系统调用所对应的系统调用号。 对于新设计的系统调用,还要求定义一个新的系统调用号,此时需要修改两

个不同地方的unistd.h,分别是:

/usr/src/linux-2.6.26/include/asm-x86/unistd_32.h

/usr/include/asm/unistd_32.h

它们一个代表了内核代码的头文件,一个代表了标准C库的头文件,建议两

个文件都进行修改。

分别在定义系统调用号的最后添加:

#define __NR_my_syscall 327

用户程序在调用某一系统调用时,使用了系统调用号,系统可根据该调用号在系统调用表中确定该系统调用代码的起始地址,进一步可根据该起始地址执行其相应的系统调用程序。

步骤四:编译内核。

编译过程同实验前面一样,可以给内核版本号添加一个标志这里添加为3,以作区别。

步骤五:重启系统,进入新编译的内核。

步骤六:利用用户程序测试新设计的系统调用。

编写用户程序syscall_test.c 。

#include

#include

int main()

{

int ret;

/*327 号系统调用是新设计的系统调用*/

ret=syscall(327,2);

printf("%d\n",ret);

if(2==ret)

printf("the first syscall is success!\n");

return 0;

}

编译运行测试程序。

gcc –o syscall_test syscall_test.c

./ syscall_test

运行成功在终端应显示:

2

the first syscall is success!

而对于新系统调用执行的输出结果“Hello,My,World”,可以通过内核日

志查看命令dmesg 进行观察。

输入命令:#dmesg –c

显示内核进程输出结果。(需在执行./syscall_test 之后)若显示“Hello,My,World”则证明已经成功运行了新设计的系统调用。

1.5实验结果

系统调用测试,执行后如图如图1-5-1.查看内核日志信息如图1-5-2.

11

12

1-5-1

图1-5-2

1.6实验过程中的问题

问题1.在1.4.2编译内核的步骤三中,执行

# apt-get install libncurses5-dev

时,由于在虚拟机内无法上网,卡了一晚上。

后来终于解决了,分析原因如下:

在主系统中打开网络和共享中心,选择更改适配器设置选项卡,可以看到如图1-6-1的图标。

图1-6-1

其中,后两个虚拟机被我禁用了,因此应将其打开。

在打开后还是不能上网。因此我又将第一个图标my wifi 关闭了,这是win7系统自带的建立wifi 热点的功能。关闭了这个功能后。虚拟机就能上网了,猜测可能只wifi 热点和虚拟机的上网起了冲突。

问题2.在更新grub 引导菜单时,对实验指导书上的讲解理解有误,自己在menu.lst 文件中又添加了如下语句

title Ubuntu 8.04, kernel 2.6.26-2

root (hd0,0)

kernel /boot/vmlinuz-2.6.26-2

root=UUID=b1e86b1f-1d0b-407e-8b8c-cf9a8b49eef8 ro quiet splash

initrd /boot/initrd.img-2.6.26-2

Quiet

导致在开机时选择名字为2.6.26-2的内核是无效的。实际上,系统已经自己更新了menu.lst 文件,我所加的那个启动项实际是没有对应的内核存在的。

如图1-6-2中,倒数第二个即为自己添加的无效映像文件,系统生成的是第三个。

13

图1-6-2

解决方法:在开机时,选择系统自己更新的启动项,而不是选择我自己添加的,则顺利启动系统。

1.7附件1

/*****************************?

/*** syscall_test.c ***/

/*****************************/

#include

#include

int main()

{

int ret;

/*327 号系统调用是新设计的系统调用*/

ret=syscall(327,2);

printf("%d\n",ret);

if(2==ret)

printf("the first syscall is success!\n");

return 0;

}

2 模块编程与字符设备驱动

2.1实验目的

1.掌握Linux 下内核模块的实现机制,熟练运用动态模块进行系统程序编程;

2.理解 Linux 字符设备驱动程序的基本原理;

3.掌握字符设备驱动程序的编写原则和过程;

4.学会编写字符设备驱动程序。

2.2实验内容

1.为内核设计一个简单的动态模块,并利用用户程序进行测试,之后再予以卸载。

2.编写一个简单的字符设备驱动程序。该字符设备并不驱动特定的硬件, 用内存文件模拟实现,要求该字符设备包括以下几个基本操作,打开、读、写和释放,并编写测试程序用于测试所编写的字符设备驱动程序。在此基础上,编写程序实现对该字符设备的同步操作。

2.3实验原理

2.3.1模块编程

编写一个简单的内核动态模块,该模块至少包括两个函数,一个是init_moudule 函数,在把模块加载到内核时被调用,它为内核注册一个处理程序,或是用自身的代码取代某个内核函数;另一个函数是cleanup_module 函数,在卸载内核模块时被调用,其任务是清除init_moudule 函数所做的一切操作。编写完成进行该模块的编译、加载和卸载操作,并对模块加载前后系统的相关内容进行比较。模块是否加载可以通过lsmod 函数观察。假如加载,则产生的列表中将会有相应的模块项目(模块程序名);也可以使用命令dmesg 查看日志,观察其变化情况;或者查看/pro/modules 文件,检查文件内容是否包含形影的模块项目。同理,在卸载时也同时观察二者的变化。

2.3.2驱动程序

编写字符设备驱动程序,且实现信号量机制,有PV 操作和同步操作。由于字符设备驱动程序都有相关的模版,因此此程序是在模版下写出来的。在此程序中,定义了主设备号为456。可以看到,还有一个设备驱动程序globalvar2.c,这个程序与globalvar.c 是一样的,设备号为654。

14

2.4实验目标

编写一个简单的字符设备驱动程序。该字符设备并不驱动特定的硬件, 用内存文件模拟实现,要求该字符设备包括以下几个基本操作,打开、读、写和释放,并编写测试程序用于测试所编写的字符设备驱动程序。在此基础上,编写程序实现对该字符设备的同步操作。

2.5实验步骤

2.5.1编写“globalvar.c”模块程序,程序代码参见附件1。保存在/home/shiyanliu/文件夹内。

2.5.2编写MakeFile 文件,也保存在/home/shiyanliu/文件夹内,代码如下:/****************************************************************/ ifneq ($(KERNELRELEASE),)

obj-m := globalvar.o #obj-m指编译成外部模块

else

KERNELDIR := /lib/modules/$(shell uname -r)/build #定义一个变量,指向内核目录

PWD := $(shell pwd)

modules:

$(MAKE) -C $(KERNELDIR) M=$(PWD) modules #编译内核模块

endif

/********************************************************************* *****/

2.5.3编译模块

在模块程序所在文件夹下编译,

#make

如图2-5-2。

图2-5-2

可见生成了globalvar.ko模块文件。

15

2.5.4加载globalvar 模块

insmod globalvar.ko

加载后使用lsmod命令可以看到如图2-4-3所示。

图2-5-3

2-5-4.

或者观察内核日志信息-dmesg.如图

图2-5-4

可以看到模块注册成功。

2.5.5创建设备节点,如图

2-4-5

2.5.6创建globalvar2模块

在实验中,我使用了2个模块来分别创建2个设备节点。因此还要创建一个globalvar2模块,创建步骤和globalvar完全相同,知识其设备号定义为654。过程就不再叙述。以下给出globalvar2创建创建设备节点的图

2-5-6.

2.5.7编写读写测试程序

读写测试程序代码请见附件3、附件4.其实在我的设计里,读写程序都分别具有读写功能。只是writer是先写后读,reader是先读后写.

以writer为例,writer打开2个设备,设备1globalvar用来写信息,写入缓冲区num,设备2globalvar2用来从缓冲区num2读信息。使用一个while语句来监听num2是否有新内容,若reader在num2里面写入内信息,则writer可以立

16

即读到并发送出来,起到类似即时通讯的效果。

Reader原理一样,其写入num2缓冲区,从num缓冲区读数据。

2.5.8编译测试程序

编译测试程序read.c write.c

gcc -o read read.c

gcc -o write write.c

2-5-7.

结果如图

2.5.9同时运行reader 和writer。结果如图2-5-8所示。

图2-5-8 聊天

17

3类EXT2文件系统

3.1实验目的

通过一个简单文件系统的设计,加深理解文件系统的内部功能及内部实现,为提出更好的文件系统做好准备。

3.2实验内容

在分析Linux 的文件系统的基础上,设计实现一个完全类似于Ext 文件系统的虚拟多级文件系统。

1) 可以实现下列几条命令:

login

ls

create

delete

cd

close

read

write

format

password

2) 列目录时要列出文件类型、文件名、创建时间、最后访问时间和修改时

间。

3)源文件可以进行读写保护。

3.3实验原理

Ext2文件系统是一个实际可用的文件系统,是庞大而复杂的。基于Ext2的思想和算法,设计一个类Ext2的文件系统,实现Ext2文件系统的一个功能子集,以真正了解文件系统的运作机制。在设计实现中,为了简化操作,可用现有操作系统的文件来代替硬盘进行硬件模拟。

1)设计文件系统应该考虑的几个层次

◆介质的物理结构

◆物理操作——设备驱动程序完成

◆文件系统的组织结构(逻辑组织结构)

18

◆对组织结构其上的操作

◆为用户使用文件系统提供的接口

对于类Ext2文件系统而言,由于采用硬盘文件代替模拟物理硬盘,不涉及具体的物理设备(硬盘)的操作,也就是说不涉及介质的物理结构和设备的驱动,仅考虑三个层次,即文件系统低层的组织结构、其上的具体操作以及为用户提供的接口命令。而类Ext2文件系统的低层组织结构,实际上就是硬盘(用文件代替)的空间划分、存放信息的布局、采用的数据结构;其上的操作就是如何管理这些空间、如何读写维护其上的信息,为了实现这些功能,需要定义具体的操作(函数);为了用户对文件系统使用的方便,当然要求该文件系统应为用户提供一些接口,这些接口可以是编程接口也可以是命令接口。类Ext2文件系统的层次结构如图3-3-1所示。

图3-3-1

从另外一个角度可以认为,对于类Ext2文件系统可以划分为三个部分:接口和用户界面设计、节点创建删除设计、节点操作设计。

2)类ext2 文件系统的数据结构

(1)块的定义

为简单起见,逻辑块大小与物理块大小作为参考均可定义为512字节。由于

位图只占用一个块,因此,每个组的数据块个数以及索引结点的个数均确定为512*8=4096。进一步,每组的数据容量确定为4096*512B=2MB。另外,类Ext2中,假设只有一个用户,故可以省略去文件的所有者ID的域。

(2)组描述符

为简单起见,可以只定义一个组。因此,组描述符只占用一个块。同时,

19

本文来源:https://www.bwwdw.com/article/qkbq.html

Top