1.5 Linux内核实验入门
1.5.1 实验1:在虚拟机中安装优麒麟Linux 18.04系统
1.实验目的
通过本实验熟悉Linux系统的安装过程。首先,要在虚拟机上安装优麒麟18.04版本的Linux。掌握了安装方法之后,读者可以在真实的物理机器上安装Linux。
2.实验步骤
1)从优麒麟官方网站上下载优麒麟18.04的安装程序。
2)到VMware官网下载VMware Workstation Player。这个工具对于个人用户是免费的,对于商业用户是收费的,如图1.6所示。
图1.6 免费安装VMware Workstation Player
3)打开VMware Player。在软件的主界面中选择“Create a New Virtual Machine”。
4)在New Virutal Machine Wizard界面中,选择“Installer disc image file(iso)”单选按钮,单击 Browse 按钮,选择刚才下载的安装程序,如图 1.7 所示。然后,单击“Next”按钮。
图1.7 选择下载的安装介质
5)在弹出的窗口中输入即将要安装的Linux的用户名和密码,如图1.8所示。
图1.8 输入用户名和密码
6)设置虚拟机的磁盘空间,尽可能设置得大一点。虚拟机的磁盘空间是动态分配的,如这里设置了200GB,但并不会马上在主机上分配200GB的磁盘空间,如图1.9所示。
图1.9 设置磁盘空间
7)可以在Customize Hardware选项里重新对一些硬件进行配置,如把内存设置得大一点。完成VMware Player的设置之后,就会马上进入虚拟机。
8)在虚拟机中会自动执行安装程序,如图1.10所示。安装完成之后,自动重启并显示新安装系统的登录界面,如图1.11和1.12所示。
图1.10 配置硬件
图1.11 Vmware Workstation 14 Player登录界面(1)
图1.12 Vmware Workstation 14 Player登录界面(2)
1.5.2 实验2:给优麒麟Linux系统更换“心脏”
1.实验目的
1)学会如何给Linux系统更换最新版本的Linux内核。
2)学习如何编译和安装Linux内核。
2.实验步骤
在编译Linux内核之前,需要安装如下软件包。
sudo apt-get install libncurses5-dev libssl-dev build-essential openssl
到Linux内核的官方网站中下载最新的版本,比如写作本书时最新并且稳定的内核版本是Linux 4.16.3,其界面如图1.13所示。Linux内核的版本号分成3部分,第一个数字表示主版本号,第二个数字表示次版本号,第三个数字表示修正版本号。
图1.13 Linux内核
可以通过如下命令对下载的xz压缩包进行解压:
#xz –d linux-4.16.3.tar.xz
#tar –xf linux-4.16.3.tar
解压完成之后,可以通过make menuconfig来进行内核配置,如图1.14所示。
图1.14 内核配置
除了手工配置Linux内核的选项之外,还可以直接复制优麒麟Linux系统中自带的配置文件。
#cd linux-4.16.3
#cp /boot/config-4.4.0-81-generic .config
开始编译内核,其中-jn中的“n”表示使用多少个CPU核心来并行编译内核。
#make –jn
为了查看系统中有多少个CPU核心,可以通过如下命令实现。
#cat /proc/cpuinfo
…
processor : 7
vendor_id : GenuineIntel
cpu family : 6
model : 60
model name : Intel(R) Core(TM) i7-4770 CPU @ 3.40GHz
stepping : 3
processor这一项等于7,说明系统有8个CPU核心,因为是从0开始计数的,所以刚才那个make -jn的命令就可以写成make -j8了。
编译内核是一个漫长的过程,可能需要几十分钟时间,这取决于电脑的运算速度和配置的内核选项。
通过make编译完成之后,下一步需要编译和安装内核的模块。
#sudo make modules_install
最后一步就是把编译好的内核镜像安装到优麒麟Linux系统中。
#sudo make install
完成之后就可以重启电脑,登录最新的系统了。
1.5.3 实验3:使用定制的内核runninglinuxkernel
1.实验目的
通过本实验学习如何编译一个ARM版本的内核镜像,并且在QEMU上运行。
2.实验步骤
为了方便读者快速完成实验,我们定制了一个Linux内核的git仓库,读者可以很方便地复制这个git仓库来完成本实验。git仓库包含如下内容。
定制的可以运行在ARM、ARM64和x86架构的小文件系统。
支持GCC的“O0”编译选项。
主机和QEMU虚拟机的共享文件。
(1)安装工具
首先在优麒麟Linux 18.04中安装如下工具。
$ sudo apt-get install qemu libncurses5-dev gcc-arm-linux-gnueabi buildessential gcc-5-arm-linux-gnueabi git
(2)GCC版本切换
在优麒麟Linux 18.04系统中默认安装ARM GCC编译器7.3版本。在编译Linux 4.0内核时会编译出错,因此需要切换成5.5版本的ARM GCC编译器。
接下来,使用update-alternatives命令对GCC工具的多个版本进行管理,通过它可以很方便地设置系统默认使用的 GCC 工具的版本。下面使用这个命令来设置arm-linux-gnueabi-gcc的版本。刚才安装了两个版本的ARM GCC工具链,分别是5.5和7.3版本。
update-alternatives命令的用法如下。
update-alternatives --install <link> <name> <path> <priority>
下面介绍其中的几个参数。
link:指向/etc/alternatives/<name>的符号引用。
name:链接的名称。
path:这个命令对应的可执行文件的实际路径。
priority:优先级,在auto模式下,数字越大,优先级越高。
接着向系统中添加一个arm-linux-guneabi-gcc-5的链接配置并设置优先级。
$ sudo update-alternatives --install /usr/bin/arm-linux-gnueabi-gcc arm-linux-gnueabi-gcc /usr/bin/arm-linux-gnueabi-gcc-5 5
update-alternatives: using /usr/bin/arm-linux-gnueabi-gcc-5 to provide/usr/bin/arm-linux-gnueabi-gcc (arm-linux-gnueabi-gcc) in auto mode
接下来向系统中添加一个arm-linux-guneabi-gcc-7的链接配置并设置优先级。
$ sudo update-alternatives --install /usr/bin/arm-linux-gnueabi-gcc arm-linux-gnueabi-gcc /usr/bin/arm-linux-gnueabi-gcc-7 7
update-alternatives: using /usr/bin/arm-linux-gnueabi-gcc-7 to provide/usr/bin/arm-linux-gnueabi-gcc (arm-linux-gnueabi-gcc) in auto mode
使用update-alternatives命令来选择一个配置。
$ sudo update-alternatives --config arm-linux-gnueabi-gcc
There are 2 choices for the alternative arm-linux-gnueabi-gcc (providing/usr/bin/arm-linux-gnueabi-gcc).
Selection Path Priority Status
----------------------------------------------------------------
* 0 /usr/bin/arm-linux-gnueabi-gcc-7 7 auto mode
1 /usr/bin/arm-linux-gnueabi-gcc-5 5 manual mode
2 /usr/bin/arm-linux-gnueabi-gcc-7 7 manual mode
Press <enter> to keep the current choice[*], or type selection number:
其中有3个候选项,选择“1”就会设置系统默认使用arm-linux-gnueabi-gcc-5。
查看系统中arm-linux-gnueabi-gcc的版本是否为5.5版本。
$ arm-linux-gnueabi-gcc -v
Using built-in specs.
COLLECT_GCC=arm-linux-gnueabi-gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc-cross/arm-linux-gnueabi/5/lto-wrapper
Target: arm-linux-gnueabi
Configured with: ../src/configure -v --with-pkgversion='Ubuntu/Linaro
5.5.0-12ubuntu1' --with-bugurl=file:///usr/share/doc/gcc-5/README.Bugs
--enable-languages=c,ada,c++,go,d,fortran,objc,obj-c++ --prefix=/usr
--program-suffix=-5 --enable-shared --enable-linker-build-id
--libexecdir=/usr/lib --without-included-gettext --enable-threads=posix
--libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu
--enable-libstdcxx-debug --enable-libstdcxx-time=yes
--with-default-libstdcxx-abi=new --enable-gnu-unique-object
--disable-libitm --disable-libquadmath --enable-plugin --with-system-zlib
--enable-multiarch --enable-multilib --disable-sjlj-exceptions
--with-arch=armv5t --with-float=soft --disable-werror --enable-multilib
--enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu
--target=arm-linux-gnueabi --program-prefix=arm-linux-gnueabi
--includedir=/usr/arm-linux-gnueabi/include
Thread model: posix
gcc version 5.5.0 20171010 (Ubuntu/Linaro 5.5.0-12ubuntu1)
(3)下载仓库
下载runninglinuxkernel的git仓库并切换到rlk_basic分支。
$ git clone https://gitee.com/benshushu/runninglinuxkernel_4.0.git
$ git checkout rlk_basic
(4)编译内核
$ cd runninglinuxkernel-4.0
$ export ARCH=arm
$ export CROSS_COMPILE=arm-linux-gnueabi
$ make vexpress_defconfig
$ make menuconfig
在_install_arm32/dev目录下创建如下设备节点,这时需要root权限。
$ cd _install_arm32
$ mkdir dev
$ cd dev
$ sudo mknod console c 5 1
开始编译内核。
$ make bzImage –j4
$ make dtbs
(5)运行QEMU虚拟机
运行run.sh脚本。runninglinuxkernel在这个版本中支持Linux主机和QEMU虚拟机的文件共享。
$ ./run.sh arm32
运行结果如下。
Booting Linux on physical CPU 0x0
Initializing cgroup subsys cpuset
Linux version 4.0.0 (figo@figo-OptiPlex-9020) (gcc version 4.6.3
(Ubuntu/Linaro 4.6.3-1ubuntu5) ) #9 SMP Wed Jun 22 04:23:19 CST 2016
CPU: ARMv7 Processor [410fc090] revision 0 (ARMv7), cr=10c5387d
CPU: PIPT / VIPT nonaliasing data cache, VIPT nonaliasing instruction cache
Machine model: V2P-CA9
Memory policy: Data cache writealloc
On node 0 totalpages: 262144
free_area_init_node: node 0, pgdat c074c600, node_mem_map eeffa000
Normal zone: 1520 pages used for memmap
Normal zone: 0 pages reserved
Normal zone: 194560 pages, LIFO batch:31
HighMem zone: 67584 pages, LIFO batch:15
PERCPU: Embedded 10 pages/cpu @eefc1000 s11712 r8192 d21056 u40960
pcpu-alloc: s11712 r8192 d21056 u40960 alloc=10*4096
pcpu-alloc: [0] 0 [0] 1 [0] 2 [0] 3
Built 1 zonelists in Zone order, mobility grouping on. Total pages: 260624
Kernel command line: rdinit=/linuxrc console=ttyAMA0 loglevel=8
log_buf_len individual max cpu contribution: 4096 bytes
log_buf_len total cpu_extra contributions: 12288 bytes
log_buf_len min size: 16384 bytes
log_buf_len: 32768 bytes
early log buf free: 14908(90%)
PID hash table entries: 4096 (order: 2, 16384 bytes)
Dentry cache hash table entries: 131072 (order: 7, 524288 bytes)
Inode-cache hash table entries: 65536 (order: 6, 262144 bytes)
Memory: 1031644K/1048576K available (4745K kernel code, 157K rwdata, 1364K
rodata, 1176K init, 166K bss, 16932K reserved, 0K cma-reserved, 270336K highmem)
Virtual kernel memory layout:
vector : 0xffff0000 - 0xffff1000 ( 4 KB)
fixmap : 0xffc00000 - 0xfff00000 (3072 KB)
vmalloc : 0xf0000000 - 0xff000000 ( 240 MB)
lowmem : 0xc0000000 - 0xef800000 ( 760 MB)
pkmap : 0xbfe00000 - 0xc0000000 ( 2 MB)
modules : 0xbf000000 - 0xbfe00000 ( 14 MB)
.text : 0xc0008000 - 0xc05ff80c (6111 KB)
.init : 0xc0600000 - 0xc0726000 (1176 KB)
.data : 0xc0726000 - 0xc074d540 ( 158 KB)
.bss : 0xc074d540 - 0xc0776f38 ( 167 KB)
SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=4, Nodes=1
Hierarchical RCU implementation.
Additional per-CPU info printed with stalls.
RCU restricting CPUs from NR_CPUS=8 to nr_cpu_ids=4.
RCU: Adjusting geometry for rcu_fanout_leaf=16, nr_cpu_ids=4
NR_IRQS:16 nr_irqs:16 16
smp_twd: clock not found -2
sched_clock: 32 bits at 24MHz, resolution 41ns, wraps every 178956969942ns
CPU: Testing write buffer coherency: ok
CPU0: thread -1, cpu 0, socket 0, mpidr 80000000
Setting up static identity map for 0x604804f8 - 0x60480550
CPU1: thread -1, cpu 1, socket 0, mpidr 80000001
CPU2: thread -1, cpu 2, socket 0, mpidr 80000002
CPU3: thread -1, cpu 3, socket 0, mpidr 80000003
Brought up 4 CPUs
SMP: Total of 4 processors activated (1648.43 BogoMIPS).
Advanced Linux Sound Architecture Driver Initialized.
Switched to clocksource arm,sp804
Freeing unused kernel memory: 1176K (c0600000 - c0726000)
Please press Enter to activate this console.
/ # ls
bin dev etc linuxrc proc sbin sys tmp usr
/ #
在优麒麟Linux的另一个超级终端中输入killall qemu-system-arm,即可关闭QEMU平台,或在QEMU中输入“Ctrl+a”,再输入“x”后,即可关闭QEMU。
(6)测试主机和QEMU虚拟机的共享文件
这个实验支持主机和QEMU虚拟机的共享文件,可以通过如下简单方法来测试。
复制一个文件到runninglinuxkernel-4.0/kmodules目录下面。
$cp test.c runninglinuxkernel-4.0/kmodules
启动QEMU虚拟机之后,首先检查一下/mnt目录是否有test.c文件。
/ # cd /mnt/
/mnt # ls
README test.c
/mnt #
我们在后续的实验中会经常利用这个特性,比如把编译好的内核模块放入 QEMU 虚拟机并加载。
1.5.4 实验4:如何编译和运行一个ARM Linux内核
1.实验目的
通过本实验学习如何编译一个ARM版本的内核镜像,并在QEMU虚拟机上运行。
2.实验步骤
为了加速开发过程,ARM 公司提供了Versatile Express 开发平台。客户可以基于Versatile Express平台进行产品原型开发。作为个人学习者,没有必要去购买Versatile Express开发平台或其他ARM开发板,完全可以通过QEMU来模拟开发平台,同样可以达到学习的目的。
(1)准备工具
下载如下代码包。
Linux 4.0内核,见kernel网站。
busybox工具包,见busybox网站。
(2)编译最小文件系统
首先利用busybox手工编译一个最小文件系统。
$ cd busybox
$ export ARCH=arm
$ export CROSS_COMPILE=arm-linux-gnueabi
$ make menuconfig
进入menuconfig之后,配置成静态编译。
Busybox Settings --->
Build Options --->
[*] Build BusyBox as a static binary (no shared libs)
在make && make install编译完成后,在busybox根目录下会有一个“_install”目录,该目录存放了编译好的文件系统需要的一些命令集合。
把_install目录复制到linux-4.0目录下。进入_install目录,先创建etc、dev等目录。
#mkdir etc
#mkdir dev
#mkdir mnt
#mkdir –p etc/init.d/
在_install /etc/init.d/目录下新建一个rcS文件,并写入如下内容。
mkdir –p /proc
mkdir –p /tmp
mkdir -p /sys
mkdir –p /mnt
/bin/mount -a
mkdir -p /dev/pts
mount -t devpts devpts /dev/pts
echo /sbin/mdev > /proc/sys/kernel/hotplug
mdev –s
修改_install/etc/init.d/rcS文件需要可执行权限,可使用chmod命令来实现,比如“chmod+x _install/etc/init.d/rcS”。
在_install /etc目录中新建一个fstab文件,并写入如下内容。
proc /proc proc defaults 0 0
tmpfs /tmp tmpfs defaults 0 0
sysfs /sys sysfs defaults 0 0
tmpfs /dev tmpfs defaults 0 0
debugfs /sys/kernel/debug debugfs defaults 0 0
在_install /etc目录中新建一个inittab文件,并写入如下内容。
::sysinit:/etc/init.d/rcS
::respawn:-/bin/sh
::askfirst:-/bin/sh
::ctrlaltdel:/bin/umount -a –r
在_install/dev目录中创建如下设备节点,这时需要root权限。
$ cd _install/dev/
$ sudo mknod console c 5 1
$ sudo mknod null c 1 3
(3)编译内核
$ cd linux-4.0
$ export ARCH=arm
$ export CROSS_COMPILE=arm-linux-gnueabi
$ make vexpress_defconfig
$ make menuconfig
配置initramfs,在initramfs source file中填入_install,并把Default kernel command string清空。
General setup --->
[*] Initial RAM filesystem and RAM disk (initramfs/initrd) support
(_install) Initramfs source file(s)
Boot options -->
()Default kernel command string
配置memory split为“3G/1G user/kernel split”,并打开高端内存。
Kernel Features --->
Memory split (3G/1G user/kernel split) --->
[ *] High Memory Support
开始编译内核。
$ make bzImage –j4 ARCH=arm CROSS_COMPILE=arm-linux-gnueabi
$ make dtbs
(4)运行QEMU虚拟机
运行QEMU虚拟机来模拟4核Cortex-A9的Versatile Express开发平台。
$ qemu-system-arm -M vexpress-a9 -smp 4 -m 200M -kernel arch/arm/boot/zImage
-append "rdinit=/linuxrc console=ttyAMA0 loglevel=8" -dtb
arch/arm/boot/dts/vexpress-v2p-ca9.dtb -nographic
运行结果与实验3相同。