公司的专用服务器使用自定义Linux内核,运行一个由busybox构成的最小镜像. 由于某些原因, 使用的内核来自其他人已经编译好的,并且也拿不到配置文件。 现在需要:
1. 添加某个专用驱动到内核中,并且添加一些脚本到新的系统运行镜像包initrd中
2. 兼容以前的系统镜像,不能出现使用旧的内核搭配新镜像时无法启动的问题
本文把用到的知识点记录下来,便于有相同需求的同学参考。
系统内核称为bzImage或kernel , 系统镜像称为 initrd
本文中只叙述某些关键点,具体细节可以参考每一节中给出的链接
关于两种技术的区别, 请参考内核源码目录下 Documentation/initrd.txt 和 IBM: Linux2.6 内核的 Initrd 机制解析
要制作支持initrd的内核 参考这个链接 CSDN:移植linux 内核支持ramdisk
extLinux是一种启动引导,优点是支持多种启动介质,配置简单。
一般用法是
mkdir -p /boot/extlinux
extlinux --install /boot/extlinux
cat mbr.bin > /dev/XXX ##mbr.bin 在extlinux的安装目录下,如果是系统自带的的则可能在 /usr/lib/EXTLINUX/ 下, 如果没有,请自行搜索文件位置
配置文件在安装目录的 extlinux/extlinux.conf
配置文件中的参数会传给内核 ,通过指定特定的的参数, 可以用来调试内核问题。 系统启动后可以在 /proc/cmdline 中查看
/root # cat /proc/cmdline
vga=0x305 loglevel=3 initrd=/rootfs BOOT_IMAGE=/bzImage
extlinux 官网用法介绍
extlinux.confg 配置文件详解
Configuring a Linux Kernel
上面的链接说明了如何编译一个内核
一般系统的步骤为:
make menuconfig #该步骤可能会提示缺少 ncurses , apt install libncurses5-dev 即可
#配置好选项, 关于如何配置,参考下一节
make -j4 #开始编译,指定4个线程编译,根据配置的不同,这里可能花费几个小时
make modules_install #安装模块
make install #安装kernel,initrd 并自动更新引导 内核名称为vmlinuz*
由于公司的服务器使用busybox最小镜像,只需要编译内核,不需要生成initrd(后面第8节说明如何使用busybox生成initrd), 编译步骤为:
make menuconfig
make -j4
make bzImage
将 bzImage 拷贝到服务器,然后在 extlinux.conf 中指定为 kernel选项的值即可。 或者 extlinux.conf 中kernel的值为一个符号链接, 这样只需要修改符号链接即可
公司服务器硬件比较特殊, 如果直接使用默认的配置生成bzImage,开机后提示没有硬盘,同时键盘也无法使用,无法进入系统调试。
通用的内核选项可以参考这个链接
简书:Linux内核编译与管理
如果编译的内核启动后提示找不到硬盘或者其他驱动问题,可参考这个链接:
CSDN:制作最小linux内核
如果要去除所有不必要的驱动和功能, 只保留必要的功能,也可参考上面的链接
CSDN:制作最小linux内核 , 该文章主要用到命令 lspci -v , lsmod , modinfo
键盘驱动问题在第7节中专门解决。
在 linux 内核中增加程序需要完成以下三项工作:
1. 将编写的源代码复制到 Linux 内核源代码的相应目录
2. 在目录的 Kconfig 文件中增加新源代码对应项目的编译配置选项
3. 在目录的 Makefile 文件中增加对新源代码的编译条目
参考这个链接
CSDN:Linux内核开发之将驱动程序添加到内核
旧式 init ram disk initrd的块大小必须和内核编译时的值匹配才能启动
如果你仔细阅读了第1节,应该不会出现这个 kernel panic。
然而, 由于公司的服务器内核配置的块大小未知,并且新编译的内核要和以前的兼容,所以必须知道原来的块大小是多少. 大致流程为:
1. 生成一个512k块大小的系统 , 并把原来的镜像文件拷贝到该镜像中
2. 使用该镜像作为initrd启动
3. 检查内核的出错信息并根据该信息修改块大小
bash# dd if=/dev/zero of=../initrd.img bs=512k count=100
bash# mkfs.ext2 -F -m0 ../initrd.img
bash# mount -t ext2 -o loop ../initrd.img /mnt
bash# cp -r * /mnt #拷贝需要的文件到镜像
bash# umount /mnt
bash# gzip -9 ../initrd.img
修改initrd为上面生成的压缩文件, 重新启动系统,出现 kernel panic
Kernel panic - not syncing :VFS: Unable to mount root fs on unknown-block(2,0)
Kernel Offset:0x0 from 0xffffffff81000000 (relocation randge :0xffffffff80000000-0x0xffffffff9fffffff)
0xffffffff81000000 和 0xffffffff80000000 相差16M, 1677721字节.
在extlinux.conf 文件中添加配置
APPEND ramdisk_size=16777216
重新启动成功。 因此块大小应该为 16M .
删掉 APPEND ramdisk_size=16777216
根据第1节的方法, 修改内核配置参数
#make menuconfig
打开配置菜单,修改两个配置项,分别是:
- General setup–>选择 Initial RAM filesystem and RAM disk…… 项
- Device Drivers–>Block devices–>选择 RAM block device support 项
- device driver->block device里的一个选项,Default Ramdisk 设置ramdisk的大小16777216
保存退出, 重新编译即可
可能是主板的原因, 编译的内核启动后无法识别键盘, 再bootLoader能使用的键盘,在开机后反而无法使用.
键盘驱动问题,请参考这个链接
linux-usb
该链接说明了 鼠标/键盘/手柄的驱动配置方法
步骤
1. 下载 busybox 并解压
2. 进入目录 make menuconfig ,并配置 Busybox Settings —> Build Options —> Build BusyBox as a static binary (no shared libs) —> yes
3. make
4. make install
5. 需要的系统文件在 busyboxdir/_install/ 下 ,拷贝所有文件到镜像的挂载目录 , 如果使用 init ram disk , 修改 /linuxrc 脚本 为如下内容
#! /bin/sh
mount -n -t proc proc /proc
#
# disable console login
grep -q console=null /proc/cmdline && sed -i s/^tty/#tty/ /etc/inittab
#
# this is a traditional mechanism for initrd
# notify kernel remount /dev/ram0 as root
echo 0x0100 > /proc/sys/kernel/real-root-dev
umount -n /proc
卸载镜像, 压缩镜像, 请参考第一节
如果使用 ram filesystem , 删除 /linuxrc 添加 /init
#!/bin/sh
#init
mount -t proc none /proc
mount -t sysfs none /sys
exec /bin/sh
打包所有文件为 cpio文件并压缩
find . | cpio --quiet -H newc -o | gzip -9 -n > /boot/initrd.img
参考链接
https://gitlab.eurecom.fr/snippets/23