操作系统实验一
一、基本信息:
实验题目:向Linux内核新增一个系统调用
完成人姓名:袁昌铃学号:71115138 报告日期:2017.3.18 二、实验目的:
通过实验,熟悉Linux操作系统的使用,掌握构建与启动Linux内核的方法;掌握用户程序如何利用系统调用与操作系统内核实现通信的方法,加深对系统调用机制的理解;进一步掌握如何向操作系统内核增加新的系统调用的方法,以扩展操作系统的功能。
三、实验内容:
1. Linux环境下的C或C++编译和调试工具的使用。
2. 向Linux内核增加新的系统调用,系统调用名称和功能自行定义,但必须实现如下输出功能:“My Student No. is ×××,and My Name is ×××”。
3. Linux新内核的编译、安装和配置。
4. 编写应用程序以测试新的系统调用并输出测试结果。
四、实验步骤:
准备
源码下载
内核源码下载
下载合适内核, 我选择的是目前最新的linux-4.10。
Busybox 源码下载
下载Busybox, 我选择的是目前最新的 busybox-1.26.2。
目录设置
上面两个源码压缩包下载后解压到下面对应目录。
o $KERNEL 内核工作目录
o
$LINUX Linux 内核源码目录 o $BUSYBOX Busybox
源码目录 PS: $KERNEL 目录是另外两个目录的父目录。
编译
kernel 编译 1 2 3 4 5 6 7 8 9 cd $LINUX # 此处应为你的 linux 源码根目录
make x86_64_defconfig
cat <<EOF >.config-fragment
CONFIG_DEBUG_INFO=y
CONFIG_GDB_SCRIPTS=y
EOF
./scripts/kconfig/merge_config.sh .config .config-fragment
# -j? 可加快编译速度。
若报错取消该选项方便查看报错信息
make bzImage -j4
若遇到编译报错
1 s cripts/sign-file.c:25:30: fatal error: openssl/opensslv.h: 没有那个文件或目录
安装 Openssl 即可
1 s udo apt-get install libssl-dev
Busybox 编译
设置编译选项
因为Linux 运行环境当中是不带动态库的,所以必须以静态方式来编译BusyBox 。
执行 1 2 cd $BUSYBOX
make menuconfig
选中 o Busybox Settings —>
o Build Options —>
o [*] Build BusyBox as a static binary(no shared libs)
正式编译
1 2 make
make install
qemu 安装
也可源码安装,这里我是 Ubuntu 直接用仓库装了。
1 s udo apt-get install qemu 通过 Qemu 模拟 Linux
在这里,我们将选择 busybox 中的 init 作为Linux 启动之后第一个执行的进程,而 init 所使用的启动将脚本便是etc/init.d/rcS 。
编写 initrd 启动脚本
1 2 3 cd $BUSYBOX /_install
mkdir -p proc sys dev etc etc/init.d
vim ./etc/init.d/rcS
rcS 中写入 1 2 3 4 5 6 #!/bin/sh
#将 proc 文件系统挂载到 /proc 目录中
mount -t proc proc /proc
#将 sys 文件系统挂载到 /sys 的目录上
mount -t sysfs sysfs /sys
#mdev 是 busybox 自带的一个 udev ,它是用于系统启动和
7 8 9 #热插拔或是动态加载驱动程序的时候,而自动产生设别节点的,
#这句话如果不加上的话,
这需要手动的 mknod 来挂载设备节点 /sbin/mdev -s
为 rcS 添加执行权限
1 c hmod +x ./etc/init.d/rcS 编写构建 initrd 镜像脚本
qemu 既然是模拟cpu 来产生指令,那么对于一个虚拟机而言必须要有一个磁盘才能够保证系统能够运行的起来。
所以在这里,我们将要制作的就是小的浓缩了 linux 文件系统的镜像文件,用来作为加载内核文件 bzImage 的一个载体。
创建一个可以生成名为 rootfs.img 的脚本文件 build-initrd.sh 。
1 2 cd $KERNEL
vim build-initrd.sh
写入 1 2 3 4 5 6 7 8 9 10 11 #!/bin/sh
#定义变量
KERNEL=$(pwd )
BUSYBOX=$(find busybox* -maxdepth 0)
LINUX=$(find linux* -maxdepth 0)
#通过cpio 创建镜像
cd $BUSYBOX /_install
find . | cpio -o --format=newc >$KERNEL /rootfs.img
cd $KERNEL
#通过gzip 创建zip 镜像
gzip -c rootfs.img > rootfs.img.gz
添加执行权限同上。
编写快速运行脚本
编写运行 qemu 将编译生成的内核文件 bzImage 加载到刚刚生成的 rootfs.img 文件中的脚本。
1 2 cd $KERNEL
vim run.sh
1 2 3 4 5 6 7 8 9 10 11 12 13
14
#!/bin/sh #定义变量 LINUX=$(find linux* -maxdepth 0) DEBUG=""; # 附加任意参数即打开调试 if [ -n "$1" ]; then DEBUG="-s -S" fi #启动qemu qemu-system-x86_64 -enable-kvm -monitor stdio -kernel $LINUX /arch/x86_64/boot/bzImage \ -initrd rootfs.img.gz -smp 2 -append 'root=/dev/ram rdinit=sbin/init noapic'$DEBUG PS:
1.
同编译内核中,这里需要选择对应架构的 qemu 。
2. 若你的环境不支持 kvm ,请去掉 -enable-kvm 参数( vmware 似乎是不支持)。
添加执行权限,执行
1 ./run.sh
顺利的话就可以启动了。
新增系统调用
这里以 Linux-4.10 为例,本文中 $LINUX 指 linux 源码根目录。
一、添加系统调用号
1 2 # 32位系统是syscall_32.tbl
vim $LINUX /arch/x86/entry/syscalls/syscall_64.tbl
添加
1 xxx 64 mySyscall sys_mySyscall
二、声明系统调用函数原型
1 v im $LINUX /include/linux/syscalls.h
1 2 // if your type list is void, the key word void is needed
asmlinkage long sys_mySyscall (void);
1 v im $LINUX /kernel/sys.c
添加函数代码 1 2
3 4 // if your type list is void, the key word void is needed asmlinkage long sys_mySyscall (void ){ Printk(“71115138 yuanchangling ”); Return o; }
五、主要数据结构及其说明
六、程序运行时的初值和运行结果(系统截图)
七、实验体会:
实验遇到的最大的问题就是以前没有使用过Linux操作系统,对这个系统十分的陌生,对于命令行操作十分的不熟悉,花了大量的时间在网上学习如何使用Linux操作系统。
遇到的第二个问题就是一开始用虚拟机分配给Linux操作系统的资源太少了,导致这个系统运行速度十分低,编译内核的时候花了大量的时间,导致完成实验花了许多的时间,再完成实验后才更改了虚拟机的配置问题,花了较少的时间完成实验。
通过这次实验,我掌握了用户程序如何利用系统调用与操作系统内核实现通信的方法,加深对系统调用机制的理解;进一步掌握了如何向操作系统内核增加新的系统调用的方法。