1、macOS上的Parallels Desktop虚拟机
2、Ubuntu版本:16.04 64位 使用的Ubuntu内核版本:4.15.0
3、用于修改的内核版本:4.10.14
4、CPU 8259u 4核8线程(分配给虚拟机4个核心) 内存:16G(分配给虚拟机8G)
推荐大家在进行此实验前,将虚拟机设置中,分配的内核数提到最大,同时分配给虚拟机的硬盘空间设置在50G以上(比较保险,最好不要低于40G,底线是30G)
由于部分Ubuntu装好后默认的软件下载地址是国外的地址,会出现下载软件速度极慢甚至无法下载的情况
因此我们需要先将软件的下载源更换为国内镜像
选择System-Software&Updates,在Download from处下拉菜单,选择other-China-任意国内源即可,图中显示的是阿里的源,选好后会需要输入管理员密码
之后在terminal中输入
sudo apt-get update
官方地址:https://www.kernel.org/pub/linux/kernel/v4.x/
由于官方地址下载较慢,我们采用国内镜像
国内镜像地址:https://mirror.bjtu.edu.cn/kernel/linux/kernel/v4.x/
至于下载何种版本的内核源码,如果是16.04的话下载4.10.14(也是我做这个实验使用的版本),其它版本的Ubuntu的话…百度吧亲
双击此压缩包,打开,右键单击文件夹,选择Extract进行解压
之后我们再将源码文件移动至指定目录下面
命令(在Desktop下运行此命令):
sudo mv linux-4.10.14 /usr/src/
首先进入源码文件中的kernel目录
cd /usr/src/linux-4.10.14/kernel
用vim打开文件sys.c,在sys.c中添加一个函数,为了避免这段函数实现被放入到某个预编译命令之中,我们在vim中使用shift+g跳至文件末尾,使用i切换到编辑模式,添加完后使用:wq保存并退出(每一处做完修改都要保存哦,之后不再赘述)。如果打开文件出现权限不够的情况,请在命令的最前面加上sudo(之后碰到这种问题都按此法解决)
#include
函数实现的地方
函数实现代码:
asmlinkage int sys_helloworld(void){
printk(KERN_EMERG “hello JYQ!”) // hello后面是我自己的名字,大家可以随便改(hello改了也行)
return 1;
}
刚刚只是在sys.c文件里面进行了函数实现,我们还需要在一个名为syscalls.h的头文件里对该函数进行声明
进入如下目录
cd /usr/src/linux-4.10-14/arch/x86/include/asm/
用vim打开syscalls.h进行编辑,加入函数声明
命令如下
vim syscalls.h
asmlinkage int sys_helloworld(void);
进入如下目录
cd /usr/src/linux-4.10.14/arch/x86/entry/syscalls/
这里要注意的是,这个路径是针对64位Ubuntu的,如果使用32位Ubuntu进行实验的话,是如下路径(这也是原教程没说明白的地方…两个路径有区别的):
cd /usr/src/linux-3.10.4/arch/x86/syscalls/
//这里的3.10.4瞎写的,根据实际情况改就行
用vim打开syscall_64.tbl(32位的童鞋请打开syscall_32.tbl)
64位:
vim syscall_64.tbl
332 64 helloworld sys_helloworld
这里的332是系统调用的id,可以不一样,但自己要记住,之后有用
后面的64是Linux应用二进制接口的一种类型,剩下的还有common和x32,网上说三个都可以,本人未进行实验(改一下重新编译一下时间成本太高了,有兴趣的童鞋可以试一下)
32位:
vim syscall_32.tbl
首先我们需要安装一些编译内核需要的依赖
请依次执行以下命令
sudo apt-get update
sudo apt-get install libncurses5-dev
sudo apt-get install libssl-dev
sudo apt-get install libelf-dev
以上的依赖不一定全,由各自的系统情况而定,如果在编译过程中发现缺失,比如我在make modules时,遇到报错
报错中有明显的提示“please install libelf-dev…”,于是去安装这个包即可。大家根据自己的实际情况,遇到缺失再安装也是可以的。
之后执行以下命令
sudo make mrproper
sudo make clean
sudo make menuconfig
实现完全干净的第一次编译
mrproper为清除编译过程中产生的所有中间文件
clean为清除上一次产生的编译中间文件
(如果大家需要重新编译内核请务必执行以上三条指令)
执行完第三条指令后,会出现图形化配置窗口
方向键向下,选择General setup
再方向键向右,选择save
之后选择ok、exit、exit即可
之后就是正式编译啦
我们还需要再做一些预备工作
使用命令
lscpu
查看自己的cpu支持几个线程
以上是我的,线程数为CPU(s) (4)乘上 Thread(s) per core(1),这里等于4,即支持4线程(实际上我的电脑CPU支持8线程,我也不明白这里怎么回事,而且实测以8线程进行编译的CPU占用率会比4线程进行编译的CPU占用率高百分之20左右)
得到线程数后,就可以开始编译内核啦
sudo make bzImage -j8
-j后面是线程数,大家按各自情况选择,如果一不小心没加-j,推荐还是ctrl+C停止编译,加上-j再编译(单线程速度感人)
如果编译成功(没有报错、warnings一般都可以无视),下一步进行编译模组
sudo make modules -j8
然后就是漫长的等待了(取决于线程数和大家电脑CPU的性能)
编译结束后,依次安装内核模块和内核
sudo make modules_install
sudo make install
(这里相比较原教材省去了很多步骤,经测试make install可以完成之后的拷贝和创建镜像过程,大家不放心的话可以使用原教材的步骤)
原教材步骤(把make install替换成下述命令):
cp arch/x86/boot/bzImage /boot/vmlinuz-4.10.14
cp .config /boot/config-4.10.14
mkinitramfs -o /boot/initrd.img-4.10.14 4.10.14
使用如下命令打开要修改的文件
vim /etc/default/grub
将图中选中的这句语句注释掉
将GRUB_TIMEOUT改为一个大于0的数
调用命令更新开机启动项
sudo update-grub
输入以下命令
reboot
系统会进行重启,应该会进入镜像选择的界面,如果未进入,原教材的说法是
按下ESC,考虑到教材年代久远,推荐百度
在我的机器上,reboot后进入以下界面
方向键向下,选择Advanced options for Ubuntu,进入如下界面
(大家应该不会和我这一样这么多镜像的,我踩坑踩多了重编译了好几次qwq)
由于之前我们用4.10.14的源码进行编译,所以我们选择Ubuntu,with Linux 4.10.14 进入即可
进入系统后,可以用以下命令查看当前运行的系统的内核版本
uname -r
首先用vim新建一个文件
vim sys_helloworld.c
代码如下:
#include
#define _NR_helloworld 332
int main(void){
syscall(_NR_helloworld);
return 0;
}
这里的_NR_helloworld 332中的332即为之前添加的系统调用的id,各位可以按照之前添加的id填写
之后使用gcc进行编译,编译时将编译后的可执行文件命名为sys_helloworld(别的名字也行,这样好记一些)
执行以下命令,打印开机信息
sudo dmesg -c
接下来关闭当前的这个terminal,重新打开一个terminal(玄学,似乎在之前那个窗口里之后的步骤会失败)
执行该可执行文件
./sys_helloworld
再次执行
sudo dmesg -c