【实验:1】Linux内核编译及添加系统调用

文章目录

  • 前言
    • 最近在使用openEuller添加系统函数并调用时走了许多弯路,现在想总结一下自己的收获,提供给大家参考。
  • 一、安装工具
  • 二、修改添加代码
    • 系统调用:
  • 三、编译安装内核
  • 四、编写调用函数
  • 总结


前言

最近在使用openEuller添加系统函数并调用时走了许多弯路,现在想总结一下自己的收获,提供给大家参考。

    首先要清楚,如果你是在**VMware安装的Oppeneuller**,那么你的架构是x86的。就完全可以按照我们
    教材7.2.3的操作进行!

【实验:1】Linux内核编译及添加系统调用_第1张图片

  而如果你是在服务器上远程操作,那么你是鲲鹏的架构。就不能按照书上的操作来。

【实验:1】Linux内核编译及添加系统调用_第2张图片

  本篇文章主要介绍对服务器上openeuller的操作。(推荐大家使用,因为这样会省很多事。比如:可以更改服务器
  核数数大大降低编译时间)

实验流程图:
【实验:1】Linux内核编译及添加系统调用_第3张图片

这里很多人会选择先完成内核编译,再进行系统函数的调用这个任务。其实没必要,完全可以将所有代码写入之后再
进行编译,这样会少编译两次(毕竟编译一次短则半小时,长则小两个小时。但是把华为云服务器核数变为60核只需
要一分钟,这个后面再讲)。

一、安装工具

通过华为云Cloudshell远程登录服务器:
【实验:1】Linux内核编译及添加系统调用_第4张图片
输入服务器密码登录
【实验:1】Linux内核编译及添加系统调用_第5张图片

依次输入:

yum group install -y "Development Tools"
yum install -y bc
yum install -y openssl-devel

获取内核源代码并解压:

wget https://gitee.com/openeuler/kernel/repository/archive/kernel-4.19.zip
unzip kernel-4.19.zip

二、修改添加代码

系统调用:

解压完毕后会在桌面生成一个kernel-kernel-4.19的文件夹,接下来的操作都是在此文件夹中进行
首先打开文件夹:
在这里插入图片描述
然后打开文件(include/uapi/asm-generic/unistd.h)
在这里插入图片描述

对应位置添加代码:

#define __NR_czq 294    //输出学号
__SYSCALL(__NR_czq, sys_czq)

#define __NR_mysetnice 295	   //
__SYSCALL(__NR_mysetnice,sys_mysetnice)

#define __NR_mysethostname 296
__SYSCALL(__NR_mysethostname,sys_mysethostname)

一定要记得将原来的294改为297!!!

【实验:1】Linux内核编译及添加系统调用_第6张图片

打开文件(include/linux/syscalls.h)
添加声明系统调用函数的代码:

asmlinkage long sys_zlk(void);
asmlinkage long sys_mysetnice(pid_t pid,int flag,int nicevalue,void __user*prio,void __user*nice);
asmlinkage long sys_mysethostname(char __user  *name, int len);

打开文件(kernel/sys.c)
添加代码:(注意:这段代码要添加到尾部#endif之上的位置,否则也会导致编译失败)

SYSCALL_DEFINE0(czq)
{
		printk(KERN_INFO "Student number is:XXXXXX");//前面的参数一定要添加,
		return 0;
}

SYSCALL_DEFINE5(mysetnice,pid_t,pid,int,flag,int,nicevalue,void __user*,prio,void __user*,nice)
{
	int n;
	int p;
	struct pid * kpid;
	struct task_struct * task;
	kpid = find_get_pid(pid);/*得到pid */
	task = pid_task(kpid, PIDTYPE_PID);/* 返回task_struct */
	n = task_nice(task);/* 返回进程当前nice值 */
	p = task_prio(task);/*返回进程当前prio值*/
	if(flag == 1)
	{
		set_user_nice(task, nicevalue);/* 修改进程nice值 */
		n = task_nice(task);/*重新取得进程nice值*/
		p = task_prio(task);/*重新取得进程prio值*/
		copy_to_user(nice,&n,sizeof(n));/*将nice值拷贝到用户空间*/
		copy_to_user(prio,&p,sizeof(p));/*将prio值拷贝到用户空间*/
		return 0;  
	}
	else if(flag == 0)
	{
		copy_to_user(nice,&n,sizeof(n));/*将nice值拷贝到用户空间*/
		copy_to_user(prio,&p,sizeof(p));/*将prio值拷贝到用户空间*/
		return 0;
	}
	return EFAULT;
}

SYSCALL_DEFINE2(mysethostname, char __user *, name, int, len)
{
    int errno;
    char tmp[__NEW_UTS_LEN];
    if(len<0 || len>__NEW_UTS_LEN)
        return -EINVAL;
 		   errno = -EFAULT;
    if(!copy_from_user(tmp, name, len))
	{
		struct new_utsname *u;
		down_write(&uts_sem);
		u = utsname();
		memcpy(u->nodename, tmp, len);
		memset(u->nodename + len, 0, sizeof(u->nodename)- len);
		errno = 0;
		uts_proc_notify(UTS_PROC_HOSTNAME);
		up_write(&uts_sem);
	}
	return errno;
}

此处代码参考了https://blog.csdn.net/Z165165165/article/details/118486665

此时我们已经完成准备工作,接下来开始编译内核。

三、编译安装内核

此处有两种选择:1、不做更改直接编译,可忽略下面这一步(需要半小时左右)。2、换核编译(1分钟左右)。这也是我后面选择在服务器上操作的原因之一(失败太多次了)。
换核编译:
选择变更规格
【实验:1】Linux内核编译及添加系统调用_第7张图片
选择一个核数较多的更换即可(32核的就差不多了,1分钟左右,我用了一次60核的CPU占用率不到20%)
【实验:1】Linux内核编译及添加系统调用_第8张图片
在kernel-kernel-4.19目录下进行一下操作:
配置内核:make menuconfig
【实验:1】Linux内核编译及添加系统调用_第9张图片
查资料发现是缺一个插件
所以接下来下载:

sudo yum install -y ncurses-devel

再次输入:make menuconfig
会出下图
【实验:1】Linux内核编译及添加系统调用_第10张图片
选择保存退出即可

完成后依次输入:
编译内核:make -j64
编译模块:make modules
【实验:1】Linux内核编译及添加系统调用_第11张图片这里的警告可以忽略

安装模块:make modules_install
安装内核:make
make install
立即重启:reboot
如果你换了核,记得现在换回之前的0.6元/h的4核!

四、编写调用函数

输出学号函数:

#include 
#include 
#include 
int main()
{
		if (syscall(294) == 0)  //如果成功执行,返回0。如果没有调用成功,一般会返回-1.
			printf("success!\n");
		else
			printf("fail!\n");
		return 0;
}

修改优先级函数:

#define _GNU_SOURCE
#include
#include
#include
#include
int main()
{
	pid_t pid;
	int nicevalue;
	int flag;
	int n=0;
	int p=0;
	int *prio;
	int *nice;
	prio = &p;
	nice = &n;
	printf("请输入pid: \n");
	scanf("%d",&pid);
	printf("pid输入成功\n请输入nice值:\n");
	scanf("%d",&nicevalue);
	printf("nice输入成功\n请输入flag(flag为1时修改,为0时查看):\n");
	scanf("%d",&flag);
	syscall(295,pid,flag,nicevalue,prio,nice);
	printf("现在的nice为%d,prio为%d\n",n,p);
	return 0;
}

改变主机名称为自定义字符串:

#define _GUN_SOURCE
#include
#include
#include
int main()
{
	syscall(296,"Kiki",4);
	return 0;
}

代码参考:https://blog.csdn.net/Z165165165/article/details/118486665
以上三个代码编译完成后,先用先用dmesg -c命令清空原有日志,然后运行,使用dmesg查看结果。

总结

作者前前后后在这个实验上花了不下10小时,编译了不下5次,得到了血的教训,有感而发,将自己的经验分享给大家,避免更多的人犯错。

你可能感兴趣的:(linux)