Linux配置、编译和移植以及GDB调试


2023.12.2.-10

本文阐述拿到Linux源码之后,如何对其进行配置、编译,让Linux跑到目标硬件环境上。

  1. 移植三板斧之一:配置和编译
  2. 移植三板斧之二:bootloader-uboot
  3. 移植三板斧之三:根文件系统-busybox
  4. 磁盘镜像制作(移植三板斧之隐藏的四)
  5. qemu仿真和debug

阅读建议:
如果你关心linux内核编译和调试,只用看1和5。
如果你关注Linux移植,需要全看,特别要注意步骤4。


1. 为目标板编译Linux镜像

linux中,存在多种配置方式,这些方式都是图形化给普通人看的:

  1. menuconfig
  2. xconfig
  3. nconfig
  4. gconfig

这些不同的配置方式原理是相似的

menuconfig等工具
后处理工具
KConfig文件
.config文件
头文件-宏

在Linux仓库里已经适配的开发板

如果要用的开发版已经在Linux仓库里了,可以先使用defconfig,选择开发板的默认配置,然后在此基础上使用图形化的配置方法进行个性化配置。

方法如下进入到Linux代码目录下,进行配置:

make ARCH=arm vexpress_defconfig
make ARCH=arm menuconfig
# 还可以使用 make ARCH=arm nconfig/xconfig/gconfig

ARCH请选择Linux目录arch子目录下的名称,如果不指定arm,则会自动检测当前的体系结构,基本上都是x86.
默认的配置文件请选择对应的arch目录下的configs文件夹下的文件
Linux配置、编译和移植以及GDB调试_第1张图片

Linux仓库中没有的开发板

如果仓库里没有我们想要的开发板,可以直接采用menuconfig进行逐一配置。

make ARCH=arm menuconfig
# 还可以使用 make ARCH=arm nconfig/xconfig/gconfig

本文认为更靠谱、更快速的方式是找一个仓库中已有的开发板,复制一份其defconfig,即建立一个自定义的defconfig进行集中修改,然后再使用menuconfig进行修改。

编译配置好的Linux

编译的前提,一定是通过前面的配置,生成了.config,这是会影响到各个功能模块的选择。

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- 

编译好之后,会得到vmlinux,这是一个elf格式的可执行文件。

2. Bootloader

为什么要有Bootloader?
vmlinux的入口地址是0x80008000,不是0x0或者某个所有硬件都遵循的地址,所以这个elf并不能够直接运行,而是需要一个软件将其搬移到正确的位置,然后将控制权交给它。
Linux配置、编译和移植以及GDB调试_第2张图片

如何编译uboot

uboot的编译和配置过程与linux相似(configs文件夹提前了),本小节直接给出编译vexpress的Uboot的过程。
Linux配置、编译和移植以及GDB调试_第3张图片

git clone https://github.com/u-boot/u-boot.git
cd u-boot
make ARCH=arm vexpress_ca9x4_defconfig
make ARCH=arm menuconfig
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi-

编译结束之后,在根目录下,会生成u-boot,这是一个elf文件
Linux配置、编译和移植以及GDB调试_第4张图片

3. 根文件系统

根文件系统可以提供应用代码存储的地方,在linux启动之后,从文件系统中加载应用程序进行执行。此外,还可以存储驱动module,存储Linux命令的镜像等等,实际上根文件系统相当于提供了一个与Linux内核交互的方式。

wget https://www.busybox.net/downloads/busybox-1.36.0.tar.bz2

tar -xvf busybox-1.36.0.tar.bz2
cd busybox-1.36.0

make CROSS_COMPILE=arm-linux-gnueabi- ARCH=arm menuconfig
mkdir myrootfs
make install CROSS_COMPILE=arm-linux-gnueabi- ARCH=arm CONFIG_PREFIX=myrootfs -j20

在menuconfig时需要将Build static binary选择上,不使用动态加载机制。
Linux配置、编译和移植以及GDB调试_第5张图片

编译之后,可以在指定的文件夹下面看到被写入了四个文件(夹)。
Linux配置、编译和移植以及GDB调试_第6张图片
可以看见,以及生成了很多linux下的命令,这样我们就能在目标板上使用linux命令了。

Linux配置、编译和移植以及GDB调试_第7张图片

4. 创建磁盘镜像

# 创建硬盘镜像,block_size=1M,1024个block, 即1GB硬盘
dd if=/dev/zero of=rootfs.ext3 bs=1M count=1024
# 将这个硬盘进行分区
sgdisk -n 0:0:+10M -c 0:kernel rootfs.ext3
sgdisk -n 0:0:0 -c 0:rootfs rootfs.ext3

# 将这个硬盘镜像,映射到文件夹,方便做操作
losetup -f
sudo losetup /dev/loop1 rootfs.ext3 
sudo partprobe /dev/loop1
sudo mkfs.ext3 /dev/loop1p1
sudo mkfs.ext3 /dev/loop1p2
sudo mount -t ext3 /dev/loop1p1 p1
sudo mount -t ext3 /dev/loop1p2 p2
# 将Linux压缩镜像和对应的dtb复制到第一分区
sudo cp linux_old1/arch/arm/boot/zImage p1
sudo cp linux_old1/arch/arm/boot/dts/vexpress-v2p-ca9.dtb p1
# 将根文件系统放到第二分区,并且创建4个tty设备文件
sudo cp -raf busybox-1.36.0/myrootfs/* p2
sudo mkdir dev
cd dev
sudo mknod tty1 c 4 1
sudo mknod tty2 c 4 2
sudo mknod tty3 c 4 3
sudo mknod tty4 c 4 4

#硬盘镜像创建结束,接触映射,这时所有的文件都写入到rootfs.ext3这个硬盘镜像中了
cd ../.. #回到主目录
sudo umount p1 p2
sudo losetup /dev/loop1
sudo losetup -d /dev/loop1

5. qemu仿真和GDB调试

方法一:直接调试内核

在启动之前,需要首先确定内核的入口地址,本文是0x80008000,需要在启动qemu时,让loader把内核镜像加载到这个地址。

Linux配置、编译和移植以及GDB调试_第8张图片

启动qemu模拟器,并且暂停运行,等待GDB接入(-s -S).

qemu-system-arm -M vexpress-a9 -m 512M -kernel arch/arm/boot/zImage-dtb arch/arm/boot/dts/vexpress-v2p-ca9.dtb -append "console=ttyAMA0" -nographic -s -S -device loader,addr=0x80008000,cpu-num=0

# Boot Image or Kernel specific:
# -bios file      set the filename for the BIOS
# -pflash file    use 'file' as a parallel flash image
# -kernel bzImage use 'bzImage' as kernel image
# -append cmdline use 'cmdline' as kernel command line
# -initrd file    use 'file' as initial ram disk
# -dtb    file    use 'file' as device tree image
# -S              freeze CPU at startup (use 'c' to start execution)
# -s              shorthand for -gdb tcp::1234
# -device loader,addr=  The loader device allows the CPU’s PC to be set from the command line。

然后使用gdb-multiarch进行调试

sudo apt install gdb-multiarch #如果没有的话执行这句话

gdb-multiarch vmlinux

(gdb) target remote:1234
(gdb) layout src

之后可以看到linux的源码被加载到gdb中了:
Linux配置、编译和移植以及GDB调试_第9张图片

方法二:全流程模拟

这种方式更加复杂,从bootloader到linux内核再到加载根文件系统。这更加符合实际的流程,因此要先制作磁盘镜像,也就是把Linux内核和根文件系统放到磁盘中(flash),然后u-boot从磁盘中加载内核,内核再从磁盘中加载根文件系统。

qemu-system-arm -M vexpress-a9 -m 512M -kernel u-boot/u-boot -append "root=/dev/mmcblk0 console=ttyAMA0 rw init=/linuxrc" -sd rootfs.ext3 -serial stdio

在自动boot前,按空格键,进入手动模式,然后在qemu上的Linux下输入:

mmc dev 0
part list mmc 0
load mmc 0:1 0x60008000 zImage
setenv bootargs 'root=/dev/mmcblk0p2 rw rootfstype=ext3 rootwait earlycon console=tty0 console=ttyAMA0 init=/linuxrc ignore_loglevel'

如果要u-boot自动加载内核镜像,需要去配置u-boot的makefile重新编译u-boot. 有需要可以留言。
Linux配置、编译和移植以及GDB调试_第10张图片

你可能感兴趣的:(linux学习计划,linux,arm开发,运维)