操作系统作业(一):编译Linux内核

背景&要求:
除了BIOS以外,内核是操作系统中最早加载到内存的。编译内核的目的在于让Linux更加符合使用者的要求,比如说新功能的需求、原来的内核太过于臃肿、或者是嵌入式操作系统的需求。

环境:VMware虚拟机+Ubuntu 16.04(硬盘大小最好大于30G,不然可能会崩)

第一步:在官网上下载内核

网址:https://www.kernel.org/
操作系统作业(一):编译Linux内核我这里选用的是4.19的版本,点击tarball下载,解压的时候我是直接解压到/home/download的文件下面,然后用命令:

sudo mv /home/download/linux-4.19.28 /usr/src

这里一定要注意权限呀!!
这样内核就下载好了

第二步:安装依赖

build-essential (基本的编程库(gcc, make等)
kernel-package (Debian 系统里生成 kernel-image 的一些配置文件和工具)
libncurses5-dev (meke menuconfig要调用的)
在终端输入:

sudo apt-get install build-essential kernel-package libncurses5-dev

再转化到/usr/src/linux-4.19.28目录下终端输入make menuconfig如果报错说xxx not found,再用sudo apt-get install xxx下载,这样我就配置好了。

最后为了保证源码的干净,将以前执行过的内核功能选择文件删除,执行

make mrproper

注意:一般这个命令在第一次执行核编译前执行,如果以后想要删除前一次编译过程的残留数据,只需要执行:

make clean

输入make menuconfig就出现了这样的界面

操作系统作业(一):编译Linux内核其实除了这种config界面,还有许多其他的品种,比如说:

make oldconfig:一般用于升级内核源代码后的功能挑选,只列出原来没有的新功能。
make xconfig:QT为基础的图形界面,需要X Windows的支持。
make gconfig:gtk为图形接口基础的界面显示,如果在GNOME界面中,则用这个会很方便。
make config:很麻烦。。不推荐使用。

当然选择这些界面都需要配置相应的环境等等,由于时间的关系,就不展开了。

第三步:那些内核功能

刚刚看到这么多功能,,一脸黑人问号脸。。。
这里介绍一下吧:
1.---->表示可设置选项,选择时< select >,按下enter键
2.在详细选项中,前面由[ ]或者< >才能选择,用空格键选择
3.若前面为[ ]、或者< * >表示编译进内核、< M >表示编译进模块,如果不知道怎么选时,那就编译进模块吧。

如果不知道怎么改,一定要查看< help >!!

根据要求调好后,save就可以了。

第四步:内核的编译以及安装

如果好奇的话可以看make help
基本功能有:

make vmlinux  #Build the bare kernel
make modules  #Build all modules
make bzImage  #Compressed kernel image (arch/x86/boot/bzImage)
make all      # Build all targets marked with [*](就是上面三个)

接下来制作压缩的内核,也就是系统开机信息(注意bzImage中第三个字母是I的大写)

➜  linux-4.19.28 make clean <==清除临时文件
➜  linux-4.19.28 make bzImage <==压缩编译内核
➜  linux-4.19.28 make modules <==再编译模块

在执make bzImage时,出现报错:
操作系统作业(一):编译Linux内核
解决方法:下载 libssl-dev:libssl-dev是OpenSSL的通用库SSL也即Secure Socket Layer,是由网景公司为了传输敏感数据而提出的协议。SSL使用私钥加密传输的数据,防止被窃听,输入命令行

sudo apt-get install libssl-dev

然后看着滚动着的字幕真的是热泪盈眶啊!!
操作系统作业(一):编译Linux内核
然而40分钟后出现了报错。。。
操作系统作业(一):编译Linux内核
查得原因为:内存大小不够,编译被迫中止,可是人家虚拟机只给了我1G的空间,这时候就是交换分区大展身手的时候了。
问题解决参考:https://xwsoul.com/posts/684

第五步:实际安装模块

模块是要放置在/lib/modules/$(uname -r)

思考:如果同一个版本的模块反复编译后安装时,发生冲突怎么办?
方法一:将旧版本的模块重新命名
方法二:在make menuconfig的时候,将General setup中的Local version修改成新的名称

想要将模块安装到正确的目标目录下,执行下面的命令:

sudo make modules_install  #注意权限
ll /lib/modules/  ##查看该目录下的改变

最后是这样的就可以了
操作系统作业(一):编译Linux内核

第六步:安装新的内核与多重内核菜单

自动生成:
sudo make install #将新增内核、config文件、System.map放在/boot下,更新修复模式等等sudo update-initramfs -u  #更新initial RAM Disksudo update-grub	#更新grub

上面的命令可以省去写下面所有命令的麻烦

手动生成:

1.现在内核文件放在目录/usr/src/linux-4.19.28/arch/x86/boot/bzImage下,但是理论上应该在\boot下,而且以vmlinuz开头的文件。下面再保留原有的旧内核下,新增新版的内核。保留旧内核的好处就是能够保障顺利开机。。。。。
可以这样做:

sudo cp /usr/src/linux-4.19.28/arch/x86/boot/bzImage /boot/vmlinuz-4.19.28-generic
➜  sudo cp System.map /boot/System.map-4.19.28-generic
➜  sudo cp /usr/src/linux-4.19.28/.config /boot/vmlinuz-4.19.28-generic #最好备份一下

2.新建相应的Initial RAM Disk(initrd)
需要initrd是因为在启动时无法挂载根目录,例如根目录在特殊的磁盘接口(USB、SATA、SCSI)中,或者系统文件较为特殊(LVM、RAID)等,如果Linux是安装在IDE接口的磁盘上,并且使用默认的ext2/ext3系统文件,则不需要initrd也能进入Linux。
为了安全起见,我决定生成initrd,命令为:

sudo mkinitramfs -o /boot/initrd.img-4.19.28-generic  ##ubuntu中没有mkinitrd只有mkinitramfs
sudo update-initramfs -u

3.编辑开机菜单(grub)
显示grub,在/etc/default/grub更改(用编辑器更改vim 或者 gedit)
注释掉下面的两行:
#GRUB_HIDDEN_TIMEOUT=0
#GRUB_HIDDEN_TIMEOUT_QUIET=true
更新grub:

sudo update-grub

然后更改/boot/grub下的grub.cfg:将原有的内核启动代码复制到新的启动代码中,更改一下名称
操作系统作业(一):编译Linux内核

第七步:测试

一切准备就绪后。。。
重新开机,进入grub
操作系统作业(一):编译Linux内核
高级选项,选择新的内核进行测试

可以开机后,输入

uname -r

查看内核,是新内核!!!
操作系统作业(一):编译Linux内核

问题

在第六步进行手动操作时,全部完成后,开机测试时出现unable mount root
操作系统作业(一):编译Linux内核
在改变根的磁盘后出现加载root时间过长的问题,但是用make install命令就不会出现这样的问题。

不知道为什么,有什么好的解决方案吗?欢迎指正。

参考资料:
《鸟叔Linux私房菜 第三版》
生成initrd:https://www.cnblogs.com/wwang/archive/2010/10/27/1862222.html
vim教程:http://www.runoob.com/linux/linux-vim.html
grub显示:http://www.voidcn.com/article/p-tqdwfijw-pe.html

相关文章: