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

题目

返回指定进程的相关时间信息,如进程创建时间、进程在用户态及内核态的运行时间、进程的所有子孙进程在用户态的运行时间及在内核态的运行时间等。

调用原型

1.copy_to_user()

image.png
image.png

2.find_get_pid()

image.png
参数含义:
*pid_t nr:指定pid号
typedef int pid_t;
返回值:
*pid
image.png
解析函数:
*find_get_pid()中获取pid的方式是调用get_pid()函数,而 get_pid()函数需要调用find_vpid(nr)
*同时,在获取pid之前我们对这段临界区代码加锁,获取后,解锁

相关调用:

get_pid()
image.png
find_vpid()
image.png
*current宏指向当前进程
*current https://blog.csdn.net/dragon101788/article/details/8079273
find_pid_ns()
image.png
*用于从namespace下找到对应的pid结构
image.png
*PID Namespace对进程PID重新标号,即不同的Namespace下的进程可以有同一个PID。
*内核为所有的PID Namespace维护了一个树状结构,最顶层的是系统初始化创建的,被称为Root Namespace,由它创建的新的PID Namespace成为它的Child namespace,原先的PID Namespace成为新创建的Parent Namespace,这种情况下不同的PID Namespace形成一个等级体系:父节点可以看到子节点中的进程,可以通过信号对子节点的进程产生影响,反过来子节点无法看到父节点PID Namespace里面的进程。
*Pid Namespace 原理与源码分析
https://zhuanlan.zhihu.com/p/335171876
idr_find()
*idr_find()函数返回了指向给定ID的指针
image.png
image.png

3.pid_task()

image.png
image.png
*PIDTYPE_PID表示当前进程的进程号
*PIDTYPE_PGID表示进程组的领头进程的进程号
参数含义:
*pid:指定pid结构,pid_type,pid 的类型
返回值:
*指定pid的task_struct结构

3.list_for_each(pos,head)

image.png
遍历链表节点中list_head域的位置

4.list_entry(ptr,type,member)

image.png
image.png

实现

1.linux5.10/kernel.sys.c

SYSCALL_DEFINE5(zwhsyscall,pid_t,pid,u64*,start_time,u64*,utime,u64*,stime,u64*,pid_list)
{
    int s_num=0;
    struct pid* fpid=NULL;
    struct task_struct *ftask=NULL;
    struct task_struct *p=NULL;
        struct list_head *pos=NULL;
        struct task_struct *p_=NULL;
        struct list_head *pos_=NULL;
        fpid=find_get_pid(pid);
    ftask=pid_task(fpid,PIDTYPE_PID);
    if(ftask==NULL){
        return s_num;
    }
    copy_to_user(start_time,&ftask->start_time,sizeof(ftask->start_time));
    copy_to_user(utime,&ftask->utime,sizeof(ftask->utime));
    copy_to_user(stime,&ftask->stime,sizeof(ftask->stime));
    copy_to_user(pid_list,&ftask->pid,sizeof(ftask->pid));
    s_num=1;
    list_for_each(pos,&ftask->children){
        p=list_entry(pos,struct task_struct,sibling);
        copy_to_user(start_time+s_num,&p->start_time,sizeof(p->start_time));
        copy_to_user(utime+s_num,&p->utime,sizeof(p->utime));
        copy_to_user(stime+s_num,&p->stime,sizeof(p->stime));
        copy_to_user(pid_list+s_num,&p->pid,sizeof(p->pid));
        s_num+=1;
        list_for_each(pos_,&p->children){
                    p_=list_entry(pos_,struct task_struct,sibling);
            copy_to_user(start_time+s_num,&p_->start_time,sizeof(p_->start_time));
            copy_to_user(utime+s_num,&p_->utime,sizeof(p_->utime));
            copy_to_user(stime+s_num,&p_->stime,sizeof(p_->stime));
            copy_to_user(pid_list+s_num,&p_->pid,sizeof(p_->pid));
            s_num+=1;
            }
    }
    return s_num;
}

2.arch/x86/entry/syscalls/syscall_64.tbl修改系统调用表
3.linux5.10/include/linux/syscalls.h申明系统调用服务例程

4.编译内核

1.配置实验环境
虚拟机配置:建议虚拟机有60G左右的空间。
linux内核版本:5.10.37
*我的linux内核版本是5.10.37,在此内核版本下make编译后内核会占用40G左右
*随着linux版本越高,一般来说所需要的编译时间越长,占用空间也越大
2.解压缩内核源码文件
xz -d linux-5.10.tar.xz
tar -xvf linux-...tar
3.清除残留的.config和.o文件
make mrproper
4.配置内核
make menuconfig

此处需要gedit ./.config,ctrl+F查找debian,删除相关项的值为空""

5.编译内核 生成启动映像文件

(1)执行命令之前需要做一些准备工作,如安装包等,防止我们在编译许久后突然发现自己某个包没装又需要重来一次,建议sudo su,管理员权限下安装apt-get install libssl-dev ison flex zstd build-essentialdwares,一般提前安装这些包基本能够解决编译过程中报的错。
(2)执行命令:make make -j12
建议:make是编译内核过程中耗时最久的一步,且容易出错,因此建议把处理线程j12/j2等开到最大,如何得知自己的电脑能够开到多大的线程?在任务管理器-性能中查看即可,如我的电脑的最大是16,那么最好就是开到12,比你的最大承受力稍微开低4个线程,保护电脑。
image.png
(3)如何判断编译是否成功?
linux5.10/arch/x86_64/boot/bzImage文件存在
6.编译模块
make modules
7.安装内核
make modules_install
make install
8.配置grub开机引导程序
update-grub2,该命令自动修改grub
9.reboot重启
uname -a查看内核版本,变化即成功;若未变化,可以在重启开机时按住shift键,进入Ubuntu高级选项,启动你对应需要的内核版本,启动后再次使用uname -a命令即可发现内核成功切换。

相关问题

1.已编译内核,但又修改了自己的系统调用例程,需要从make mrproper步骤重新开始吗?
R:不需要,直接make -j12即可,make命令只会重新编译修改的部分,一般几分钟就能完成二次编译。

参考

https://www.cnblogs.com/chicken-gay/p/17516238.html
https://blog.csdn.net/qq_36393978/article/details/124274364
https://blog.csdn.net/qq_44222849/article/details/105754952
https://blog.csdn.net/m0_56475481/article/details/127935829(可参考,但本人认为这篇代码有错误)
推荐一篇相关参考https://segmentfault.com/a/1190000021940881(此文写的很不错)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值