Lab 6:Linux系统调用

来源:互联网 发布:平定四方巾 知乎 编辑:程序博客网 时间:2024/05/22 07:59


一、连接和器材

器材列表:

RaspberryPi(树莓派)一块、USB-TTL串口线一根(PL2303芯片)、以太网线一根、8G容量SD卡一张、带windows7操作系统的PC一台。

 

连接示意图:


二、实验步骤

a.寻找、下载Linux实验板卡所用的Linux内核源码

在ubuntu14.04下直接使用命令git clone --depth=1 https://github.com/raspberrypi/linux获取最新版本的树莓派源码。源码放在~/test1/linux下


另外,由于网速问题,我直接从https://github.com/raspberrypi/下载了对应的firmware和tools的zip压缩包并且解压后依次命名为~/RpiFirmware和~/RpiTools。

然后修改~/.bashrc加上环境变量:

 

b.在内核中加入新的系统调用

在linux/arch/arm/kernel文件夹下新建mysyscall.c文件,内容如下:


 

然后打开linux/arch/arm/kernel/calls.S添加系统调用号223为mysyscall:

 

最后修改linux/arch/arm/kernel/Makefile文件,在obj –y结尾加上mysyscall.o

 

至此,添加新的系统调用准备工作完成。

 

c.修改内核代码配置,编译内核

 

编译过程主要参考自树莓派官方文档

https://www.raspberrypi.org/documentation/linux/kernel/building.md

 

直接采用了默认内核配置,所以没有修改内核代码配置。

在linux目录下输入如下的操作命令:

cd linux
KERNEL=kernel
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- bcmrpi_defconfig
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- zImage modules dtbs

随后看到内核开始编译,完成后在linux/arch/arm/boot下找到了zImage文件:

此后进入输入命令

sudo ~/linux/scripts/mkknlimg arch/arm/boot/zImage ~/kernel.img

可以在home目录下看到kernel.img文件:


 

编译完内核后,还要编译lib。

使用如下命令:

sudo make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- INSTALL_MOD_PATH=~/modules2 modules_install

 

d.将编译好的内核装载到板卡启动

将树莓派连接上局域网,随后使用scp命令将内核kernel.img拷贝到/boot/kernel.img,

在编译好的modules2文件夹内找到lib文件夹,里面有firmware和modules两个文件夹,分别拷贝覆盖树莓派的/lib/firmware和/lib/modules文件夹。

最后还要使用如下命令覆盖掉一些文件:

sudo scp arch/arm/boot/dts/*.dtb pi@/192.168.137.71:/boot/
sudo scp arch/arm/boot/dts/overlays/*.dtb* pi@/192.168.137.71:/boot/overlays/
sudo scp arch/arm/boot/dts/overlays/README pi@/192.168.137.71:/boot/overlays/

(所有被覆盖的文件都已经提前备份)

 

完成上述操作后,在树莓派内输入reboot命令,即可重启。

重启后的输出信息表明,内核已经更新为4.4.11+,如下所示:

 

e.编写C代码,用两种方法做系统调用,测试:

1、嵌入汇编代码,用r0传参数;

2、用syscall()函数。

 

在树莓派的home目录下,创建syscall_test.c文件内容如下:


(嵌入汇编代码调用syscall)

编译执行后,输入dmesg | tail可以看到系统调用成功,下图中最后一句This is mysyscall即为系统调用输出信息:

 

随后在home目录下再新建一个syscall_test2.c函数:


(通过syscall函数调用syscall)

 

编译运行后同样能成功调用mysyscall如下:


(上图中最后两句”This is mysyscall”分别是运行syscall_test和syscall_test2时输出的)

 

由此可见,两种系统调用方法均成功了。

 

 

f.编写内核模块,在模块加载和卸载时能通过内核打印函数输出提示信息并且通过insmod和lsmod等命令测试内核模块

首先在ubuntu环境下写好需要的show.c函数和Makefile文件。

其中show.c的作用是遍历进程,输出系统中:每个进程的名字、进程pid、进程的状态、父进程的名字;统计系统中进程个数,统计系统中TASK_RUNNING、TASK_INTERRUPTIBLE、TASK_UNINTERRUPTIBLE、TASK_ZOMBIE、TASK_STOPPED等(还有其他状态)状态进程的个数。这个程序是我在操作系统实验课上写的。

两文件内容分别如下:

show.c

#include<linux/kernel.h>

#include<linux/module.h>

#include<linux/init.h>

#include<linux/sched.h>

#include<linux/list.h>

 

static__init int print_pid(void)

{

    struct task_struct *task,*p;

    struct list_head *pos;

    intrunning=0,interruptible=0,uninterruptible=0,zombie=0,stopped=0,dead=0,traced=0,unknown=0;   

 

    printk("Begin\n");

    task=&init_task;

    list_for_each(pos,&task->tasks)

    {

        p=list_entry(pos,structtask_struct,tasks);

        printk("%s---%d---%ld---%s\n",p->comm,p->pid,p->state,p->parent->comm);

        switch(p->state){

                   caseEXIT_ZOMBIE:zombie++;break;

                   case EXIT_DEAD:dead++;break;

                   caseTASK_RUNNING:running++;break;

                   caseTASK_INTERRUPTIBLE:interruptible++;break;

                   caseTASK_UNINTERRUPTIBLE:uninterruptible++;break;

                   caseTASK_STOPPED:stopped++;break;

                   caseTASK_TRACED:traced++;break;

                   default:unknown++;break;

         }

    }

    printk("TASK_RUNNING:%d\n",running);

    printk("TASK_INTERRUPTIBLE:%d\n",interruptible);

    printk("TASK_UNINTERRUPTIBLE:%d\n",uninterruptible);

    printk("TASK_STOPPED:%d\n",stopped);

    printk("TASK_TRACED:%d\n",traced);

    printk("EXIT_ZOMBIE:%d\n",zombie);

    printk("EXIT_DEAD: %d\n",dead);

    printk("End\n");

    return 0;

}

 

static __exitvoid print_exit(void)

{

    printk("<0>end!\n");

}

module_init(print_pid);

module_exit(print_exit);

 

 

Makefile:

TARGET =show

KVER ?=$(shell uname -r)

KDIR =/home/xuanzhuanecy/modules/lib/modules/4.4.11+/build/

PWD =$(shell pwd)

obj-m +=$(TARGET).o

default:

         make -C $(KDIR) M=$(PWD) modules

随后在ubuntu环境下交叉编译树莓派的内核模块show.ko如下所示:


makeARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- make –C/home/xuanzhuanecy/modules/lib/modules/4.4.11+/build/ M=/home/xuanzhuanecymodules

然后通过scp命令拷贝这个show.ko到树莓派的home目录下。

运行sudo insmod show.ko命令后再输入sudo lsmod,可以看到show模块成功载入:

 

然后输入cat /var/log/kern.log命令,最后显示的几行内容如下:


可见show模块被载入成功,并且打印输出了当前系统中的各种状态的进程的数量的信息到/var/log/kern.log。

 

 

 

 

0 0
原创粉丝点击