奔跑吧 Linux内核(入门篇)
上QQ阅读APP看书,第一时间看更新

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相同。