1 编译内核,去优化编译

(1)Makefile 中-O2 变成-O1

# 进入内核源码目录
cd linux-4.10.1
# 编辑Makefile
vim Makefile
# 修改Makefile中的优化级别
# 将-O2改为-O1
641 ifdef CONFIG_PROFILE_ALL_BRANCHES
642 KBUILD_CFLAGS   += -O1 $ (call cc-disable-warning,maybe-uninitialized,)
643 else
644 KBUILD_CFLAGS   += -O1
645 endif
# Esc :wq! 保存文件

(2)修改配置文件.config

可以将当前系统的配置文件复制到源码目录下:

cp /boot/config-4.10.0-28-generic .config
# config-4.10.0-28-generic为我的内核版本,到了这一目录的时候输入config,然后使用Tab键补全即可。

然后执行 make oldconfig.

make oldconfig
# 如果有新的配置项,系统将会提示,直接回车选择默认项即可

推荐的配置

需要注意的是:
为了方便 kgdb 调试,需要将.config 中的一些项这样设置(其实make oldconfig后这些项大多数已经设置好了,没有设置好的将在后面小节中介绍修改方法):

# 使用gdb
CONFIG_KGDB = y
# 使用串口进行通信
CONFIG_KGDB_SERIAL_CONSOLE = y
# CONFIG_DEBUG_RODATA是将内核的一些内存区域空间设置为只读,这样可能导致kgdb的设置软断点功能失效。所以推荐将该选项关闭。
CONFIG_DEBUG_RODATA = n
# 使得编译的内核包含一些调试信息
CONFIG_DEBUG_INFO = y
# 使得内核使用帧指针寄存器来维护堆栈,从而就可以正确地执行堆栈回溯,即函数调用栈信息
CONFIG_FRAME_POINTER = y
# 激活"魔术 SysRq"键. 该选项对kgdboc调试非常有用,kgdb向其注册了‘g’魔术键来激活kgdb
CONFIG_MAGIC_SYSRQ = y
# CONFIG_DEBUG_SET_MODULE_RONX会将内核模块空间设置为只读,这样会导致调试内核模块时设置断点功能失效,设置断点时出现以下错误,Cannot insert breakpoint 1.
# 这一项在内核为4.11及以上,将RONX变为了RWX
# 这一项为4.10版本及之前版本
CONFIG_DEBUG_SET_MODULE_RONX = n
# 这四项为4.11版本及以上版本
CONFIG_ARCH_OPTIONAL_KERNEL_RWX = n
CONFIG_ARCH_OPTIONAL_KERNEL_RWX_DEFAULT = n
CONFIG_STRICT_KERNEL_RWX = n
CONFIG_STRICT_MODULE_RWX = n

一般在执行make oldconfig后,上面的许多项已经成功设置了。可以通过查看.config 文件确定上述配置已正确!

(3)若内核为 4.11 之前版本 命令:uname -r

(3-1)确定 CONFIG_DEBUG_RODATA=n

答主的系统为 Ubuntu 16.04,在执行 make oldconfig 后,发现.config 文件中的 CONFIG_DEBUG_RODATA 的设置仍旧为 y(推荐配置为 n)。

如果这一项为 y,则会将内核的一些内存区域空间设置为只读,这样可能导致 kgdb 的设置软断点功能失效。表现为编译器报错:Cannot insert breakpoint 1.

控制台输入命令:

make menuconfig
# 进入menuconfig后 输入'/'来搜索配置:DEBUG_RODATA

回车发现:

Symbol: DEBUG_RODATA [=y]
Type  : boolean
Defined at arch/x86/Kconfig:312
# Exit退出

可以看到 DEBUG_RODATA 配置是在 arch/x86/Kconfig 文件的 312 行定义的。

因此:

vim arch/x86/Kconfig
# 编辑Kconfig文件,定位到312行
# 将 def_bool y 改成 def_bool n
312 config DEBUG_RODATA
313         def_bool n
# wq! 保存文件
# 返回源代码目录
cd ../../
make oldconfig

(3-2)确定 CONFIG_DEBUG_SET_MODULE_RONX = n

CONFIG_DEBUG_SET_MODULE_RONX 会将内核模块空间设置为只读,这样会导致调试内核模块时设置断点功能失效,设置断点时出现以下错误,Cannot insert breakpoint 1.

与(3)一样,执行:

make menuconfig
# 进入kernel hacking
# 找到:Set loadable kernel module data as NX and text as RO
# 将其设置为N
# 移动下面的选项,Save之后exit

请再次去.config 文件查看配置是否正确。尤其是(3-1)和(3-2)的这两项配置。

下面是我的配置:

cat .config|grep -E 'RODATA|RONX'
# CONFIG_DEBUG_RODATA is not set
# CONFIG_DEBUG_RODATA_TEST is not set
# CONFIG_DEBUG_SET_MODULE_RONX is not set

不清楚 menuconfig 中设置为 n 后,为什么.config 文件中会显示为”is not set”,不过只要不是 y 就行。目前没有发现会影响后期的调试。

(4)若内核为 4.11 版本及以上

CONFIG_DEBUG_SET_MODULE_RONX 会将内核模块空间设置为只读,这样会导致调试内核模块时设置断点功能失效,设置断点时出现以下错误,Cannot insert breakpoint 1. 这一项在内核为 4.11 及以上,将 RONX 变为了 RWX

vim arch/Kconfig

# 编辑Kconfig文件,定位到907行,编辑为:
907 config ARCH_OPTIONAL_KERNEL_RWX
908         def_bool n
909         default n

# 定位到911行,编辑为:
911 config ARCH_OPTIONAL_KERNEL_RWX_DEFAULT
912         def_bool n
913         default n

# 定位到915行,将关于config ARCH_HAS_STRICT_KERNEL_RWX的代码注释掉:
915 # config ARCH_HAS_STRICT_KERNEL_RWX
916 #       def_bool n
917 #       default n

# 定位到919行,将depends行和default行注释掉,然后加一行default n
919 config STRICT_KERNEL_RWX
920         bool "Make kernel text and rodata read-only" if ARCH_OPTIONAL_KERNEL    _RWX
921         # depends on ARCH_HAS_STRICT_KERNEL_RWX
922         # default !ARCH_OPTIONAL_KERNEL_RWX || ARCH_OPTIONAL_KERNEL_RWX_DEFA    ULT
923         default n

# 定位到933行,将关于config ARCH_HAS_STRICT_MODULE_RWX的代码注释掉:
933 # config ARCH_HAS_STRICT_MODULE_RWX
934 #       def_bool n
935 #       default n

# 定位到937行,将depends行和default行注释掉,加一行default n
937 config STRICT_MODULE_RWX
938         bool "Set loadable kernel module data as NX and text as RO" if ARCH_    OPTIONAL_KERNEL_RWX
939         # depends on ARCH_HAS_STRICT_MODULE_RWX && MODULES
940         # default !ARCH_OPTIONAL_KERNEL_RWX || ARCH_OPTIONAL_KERNEL_RWX_DEFA    ULT
941         default n

# wq! 保存文件
# 返回到源代码目录
cd ../
make oldconfig

请确认有关 RWX 的设置都为 n

cat .config|grep RWX
# CONFIG_ARCH_OPTIONAL_KERNEL_RWX is not set
# CONFIG_ARCH_OPTIONAL_KERNEL_RWX_DEFAULT is not set
# CONFIG_STRICT_KERNEL_RWX is not set
# CONFIG_STRICT_MODULE_RWX is not set

(5)编译系统

sudo apt install kernel-package
sudo apt-get install libssl-dev
touch REPORTING-BUGS
# 编译过程中可能还需要安装其他组件,看错误信息中缺少什么组件,apt-get install 对应组件即可
make-kpkg clean
make-kpkg --initrd kernel-headers kernel_image
# 等待大约3-4小时后,会在源码的上级目录生成deb文件
cd ../
# 可以看到上级目录有文件:
# linux-headers-4.10.1_4.10.1-10.00.Custom_amd64.deb
# linux-image-4.10.1_4.10.1-10.00.Custom_amd64.deb
dpkg -i *.deb
# 安装完成后会看到系统更新grub
reboot
# 重启后进入刚刚编译好的内核版本

如果重启后,若没有显示 grub,应该是将 grub 隐藏了。
可以查看这篇文章将其显示:后续:为什么编译完成后重启没有看到 grub 呢?

2 利用 VM clone 虚拟机,变成两个 Linux 系统

一个是服务器,一个是客户端。
答主使用的是 VM 虚拟机。
虚拟机右键,点击管理->克隆

3 为两个虚拟机配置串口

虚拟上右键,进入设置。
如果没有串口设置,可以点击 add->串口

服务器串口配置

记得选上是服务器,和轮询。

客户端串口配置

记得选上是客户端,和轮询。

4 服务器配置 grub.cfg 文件

vim /etc/default/grub
# 主要是看GRUB_CMDLINE_LINUX这一行
# 如果GRUB_CMDLINE_LINUX没有nokaslr rootdelay=90quiet splash text kgdboc=ttyS1,115200,则加上
# nokaslr 是 禁止内核起始地址随机化,如果不设置这个,将会无法插入软断点
GRUB_CMDLINE_LINUX="find_preseed=/preseed.cfg auto noprompt priority=critical locale=en_US nokaslr rootdelay=90quiet splash text kgdboc=ttyS1,115200"
# 更新grub
sudo update-grub
reboot
# 重后后进入刚刚编译好的内核版本

5 测试两个虚拟机的串口通信

服务器端

# 服务器等待串口发送的数据
cat /dev/ttyS1

客户端

# 客户端发送数据
echo "sss" > /dev/ttyS1

之后会发现服务器接收到了客户端发送的数据。


说明两个窗口通信成功!

6 双机联调实战

(1)服务器进入假死状态,将控制权交给客户端

服务器:

echo ttyS1 > /sys/module/kgdboc/parameters/kgdboc
# 将控制权限交给Kgdb,目标机进入假死状态
echo g > /proc/sysrq-trigger
# 此时回车后发现shell不动了

(2)客户端使用 gdb 调试服务器

客户端,进入源码目录(即 步骤 1 中下载的源码目录):

gdb ./vmlinux
# 读完符号信息后,设置波特率:
# 设置波特率
set serial baud 115200
# 通过串口连接kgdb
target remote /dev/ttyS1

如图所示:

# 在克隆函数中打个断点
break sys_clone
# 继续运行
c

如图所示:

可以看到程序在 sys_clone 停止。
删除断点后继续运行代码:

# 也可以step看下克隆函数是如何运行的
# 删除断点
delete 1
# 继续运行
c

此时,观察服务器已经不是处于假死状态了!

当然也可以给其他的函数打断点,然后调试!

0
Posted in Linux kernel technology

首先,initrd的全称为boot loader initialized RAM disk。就是一个由boot loader初始化的内存盘。它会在Linux系统启动之前被内核调用。

在系统启动的时候,会加载mount根文件系统。而根文件系统是存储在磁盘的。

因此,在开机的时候,必须有磁盘的驱动程序文件系统的驱动程序

但是硬盘的类型有很多?设备的种类也有很多?

因此,一个可能的解决方法就是:将各种硬件设备、文件系统的驱动程序模块化。发行商提供内核映像和系统安装程序。系统在安装的时候,就根据当前硬件配置情况,选择出系统启动需要的驱动程序,并根据此制成initrd。

之后将initrd放在BIOS能够寻址的范围内就可以了!

0
Posted in Linux kernel technology

0 个人系统环境(Personal system environment)

uname -a
Linux ubuntu 4.10.0-28-generic #32~16.04.2-Ubuntu SMP Thu Jul 20 10:19:48 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
cat /etc/issue
Ubuntu 16.04.3 LTS \n \l

System:Ubuntu 16.04
Kernel version:4.10.0

1 下载内核源码(Download kernel source code)

官网下载地址(Official download address):http://www.kernel.org/
清华镜像地址(Tsinghua mirror):https://mirrors.tuna.tsinghua.edu.cn/kernel/

为了简便,方便配置内核,下载与当前系统同一版本的内核,这样可以直接用当前系统的config文件。
eg,我在v4.x文件夹中选择下载了linux-4.10.1.tar.gz
In order to facilitate the configuration of the kernel, download the same version of the kernel as the current system, so that you can directly use the config file of the current system.
eg, I chose to download linux-4.10.1.tar.gz in the v4.x folder.

2 将内核文件拷贝到Linux系统中并解压(Copy the kernel file to Linux & unzip it)

答主是使用的虚拟机,因此直接拖动到了虚拟机中。如果是服务器,可以使用scp命令等上传到服务器。

tar -zxvf linux-4.10.1.tar.gz

3 将当前主机的config文件复制到内核文件夹,命名为.config(copy the config file of current system to kernel folder)

config文件在/boot目录下。
The config is in the /boot directory.

cd linux-4.10.1
cp /boot/config-4.10.0-28-generic .config

4 配置(Configuration)

make oldconfig

如果想修改配置,可以使用make menuconfig命令来配置。
If you want to modify the configuration, you can use the “make menuconfig” command to configure.

5 编译(Compile)

你也许需要先安装kernel-package,libssl-dev等文件(Linux系统下的一些组件)。如果安装的比较慢,请更换为国内源。
you may need install kernel-package,libssl-dev:

sudo apt install kernel-package
sudo apt-get install libssl-dev

答主在编译的时候,还报了下面的错误:

install: cannot stat 'REPORTING-BUGS': No such file or directory

因此在编译之前,可以touch一个REPORTING-BUGS文件:

touch REPORTING-BUGS

然后就可以编译啦:

make-kpkg clean
make-kpkg --initrd kernel-headers kernel_image

然后慢慢等待几个小时(我花了4个小时)。然后会在内核代码的上一级目录生成deb包。
Wait for a few hours(may be 4 hours), then the deb package will be generated in the upper level directory of the kernel code.

6 安装deb(Installation)

cd ../
# 可以看到上级目录有文件:
# linux-headers-4.10.1_4.10.1-10.00.Custom_amd64.deb
# linux-image-4.10.1_4.10.1-10.00.Custom_amd64.deb
dpkg -i *.deb
# 安装完成后会看到系统更新grub

然后重启系统即可以看到新编译的内核的选项。
Then reboot the system.

后续:为什么编译完成后重启没有看到grub呢?

因为系统可能将grub隐藏啦!
开机后,编辑/etc/default/grub文件:

vi /etc/default/grub

之后注释掉GRUB_HIDDEN_TIMEOUT=0:

GRUB_DEFAULT=0
# GRUB_HIDDEN_TIMEOUT=0
GRUB_HIDDEN_TIMEOUT_QUIET=true

更新grub并重启:

sudo update-grub
reboot

现在是不是有了呢?
可以进入Advanced Options for Ubuntu选项,然后就可以看到刚刚新编译的内核了!

0
Posted in Linux kernel technology


Why we should learn Linux?

  1. It is widely used in artificial intelligence, big data, cloud computing and other fields.
  2. It is the preferred operating system.

Why we should learn Linux kernel?

  1. Develop a hardware device for users to use.
  2. Listen and filter files and network data.
  3. The related development of protocol stack.
  4. Develop high-performance applications.
  5. Help us figure out a lot of stories back the system.
0
Posted in Linux kernel technology