(编译适用于ARM的linux内核并进行QEMU仿真)Compile Linux kernel 3.2 for ARM and emulate with QEMU

本文详细介绍了如何在Linux环境下编译适用于ARM的Linux内核3.2版本,并使用QEMU进行仿真。首先获取内核源码,配置编译环境,接着进行交叉编译,创建内存磁盘,最后通过QEMU模拟内核启动并运行内存磁盘中的"Hello World!"程序。适合于学习ARM平台Linux内核编译和QEMU仿真的读者。

译者序

作为第一篇翻译文档,一方面对于翻译经验不足、措辞不当,另一方面对于linux我也是初学者,很多东西尚处于待学阶段,而翻译此文的动机就是我要学习如何跨平台进行文件系统的编译,所以翻译的结果肯定有许多不到之处,欢迎大家指正,也渴望和大家一起学习进步!

 

祝枫

2016年6月17日于深圳

原文地址:

https://balau82.wordpress.com/2012/03/31/compile-linux-kernel-3-2-for-arm-and-emulate-with-qemu/

每年市场都会生产大量的运行于ARM核的新产品,并且能够运行Linux等操作系统。然而这些产品中的大多数都相当昂贵(想一想智能手机、开发工具或者评估板),由于像QEMU等软件仿真器,使方便地在ARM上探索Linux的世界成为可能。

我将展示怎么样编译内核并仿真启动。为了简化,启动过程将不包含整个完整的文件系统而是使用一个最小的内存磁盘显示内核执行一个程序的过程。

我选择模拟VersatileExpress产品,因为它支持主流的Linux内核和主流的QEMU。并且,这个硬件平台使用Cortex-A9核,一种今天在很多智能手机上使用的ARMCPU。

要求:

为了跟着我的步骤,你需要一些工具。

首先,我做的所有事都是在Linux机器上进行的,最好是一个Debian测试发行版,使用bashshell。为了管理内核的编译,GNU make应该是已经安装的(它通常在build-essential安装包内)。

为了编译ARM架构的内核,必须安装一个交叉编译器。传统编译器和交叉编译器之间的区别是传统编译器运行在一种架构(例如x86_64),产生运行在相同架构上的二进制文件。而交叉编译器产生运行在不同架构(此例中ARMv7)上二进制文件。根据你的版本和安装选项,你可以选择不同的工具链:

Ÿ  Emdebian: 这儿是安装指南

Ÿ  Linaro:如果安装了最新版的ubuntu,可以使用”sudoapt-get install gcc-arm-linux-gnueabi”命令安装;

Ÿ Fedora ARMcross-toolchain;

Ÿ  Sourcery Codebench (was CodeSourcery); 只有在注册的情况下才免费。

Ÿ other toolchain suggestions byeLinux.

交叉编译器提供了一个程序集,它们以一个标识被编译文件的库文件和二进制接口的架构和操作系统的前缀开始,主要是GCC和binutils。在我的实例中我采用了拥有”arm-linux-gnueabi-”前缀的Emdebian工具链。

最后我使用QEMU仿真器,对应的仿真ARM硬件的程序是”qemu-system-arm”。你必须根据你的版本安装正确的软件包;有时候一些版本把QEMU软件包称为不同的名字,例如Ubuntu把它打包成”qemu-extras”软件包。

小故事

建立一根空的目录,然后创建一个包含如下简单C代码的名为”init.c”的文件:

1

2

3

4

5

6

#include <stdio.h>

 

void main() {

  printf("Hello World!\n");

  while(1);

}

然后在相同的目录按顺序执行如下命令:

1

2

3

4

5

6

7

8

9

10

11

wget http://www.kernel.org/pub/linux/kernel/v3.0/linux-3.2.tar.bz2

tar xjf linux-3.2.tar.bz2

export ARCH=arm

export CROSS_COMPILE=arm-linux-gnueabi-

cd linux-3.2

make vexpress_defconfig

make all

cd ..

arm-linux-gnueabi-gcc -static init.c -o init

echo init|cpio -o --format=newc > initramfs

qemu-system-arm -M vexpress-a9 -kernel linux-3.2/arch/arm/boot/zImage -initrd initramfs -serial stdio -append "console=tty1"

内核编译(”makeall”命令)根据你的电脑性能可能花费几分钟或者几个小时。最后一个命令打开一个QEMU窗口,它将会显示一个黑色背景和大量的启动信息,且在最后会显示一个”HelloWorld!”字符串。

长故事

步骤如下:

1.获得Linux内核文件源码

2.编译准备

3.配置并编译

4.准备并制作内存磁盘

5.模拟内核启动和内存磁盘的执行

1.获得Linux内核源码

主流Linux内核的官方网站为www.kernel.org,我使用的内核版本是3.2,注意如果你想使用一个不同的版本,你可能会得到不同的结果,尽管这儿使用到的绝大多数功能是非常简单的,不应该因为版本不同而改变。

FTP site下载linu-3.2.tar.bz2,或者直接运行命令行:

wget http://www.kernel.org/pub/linux/kernel/v3.0/linux-3.2.tar.bz2

这时解压内核源码,直接在相同的目录下运行如下命令:

tarxjf linux-3.2.tar.bz2

此时将会自动创建一个名为linux-3.2的包含linux内核所有源码的子目录。

2.编译准备

我们将采用交叉编译工具来为ARM架构进行编译,所以我们需要告诉linux编译系统如何去做。这儿有两个环境变量:ARCH和CROSS_COMPILE。ARCH的有效值基本上是”arch”目录的子目录;对于CROSS_COMPILE,我们需要提供工具链的前缀,就是编译器程序的名字除去最后gcc。例如我们使用arm-linux-gnueabi-gcc,我们需要设置CROSS_COMPILE为arm-linux-gnueabi-。在终端中,执行:

exportARCH=arm

exportCROSS_COMPILE= arm-linux-gnueabi-

3.配置和编译

我们要为Versatile Express架构进行编译,为此我们可以通过如下命令使用预配置文件“arch/arm/configs/vexpress_defconfig”:

make vexpress_defconfig

这将会配置编译器为期望的硬件,通过创建一个包含所有相关选项的名为”.config”的文件。然后,编译内核镜像的命令非常简单:

make all

在编译的最后会生成一个能够在RAM中自动解压的压缩的内核镜像文件”linux-3.2/arch/boot/zImage”。为了在多核主机上加速编译的过程,我建议通过执行如下命令来尝试平行编译:

make –j 2 all

这时将使用2个进程的平行编译来创建最后的镜像文件,而不再是顺序编译。

4.准备并创建内存磁盘

为了使内核做点儿什么,我们创建一个简单的”Hello World!”用户空间程序。我们可以使用一个内存磁盘作为Linux用来root的文件系统,使用”initfamfs”条目。关于内存磁盘的更多信息可以在内核源码树中找到,在文件“Documentation/early-userspace/README“。Linux尝试运行的第一个程序是”/init”,所以我们可以创建一个名称为此的可执行文件。源码非常简单:

1

2

3

4

5

6

#include <stdio.h>

 

void main() {

  printf("Hello World!\n");

  while(1);

}

它将会被我们的交叉编译工具链编译。为了使该程序单独工作,我们需要把它编译为一个静态可执行文件,将会把它所需要的库文件也包含进去。这种方式我们可以得到只有一个不用担心动态库的可执行程序作为文件系统。编译的命令是:

arm-linux-gnueabi-gcc -static init.c -o init

此命令将会为ARM创建一个名为init的可执行文件。这个文件的格式如下:

$file init

init:ELF 32-bit LSB executable, ARM, version 1 (SYSV), statically linked, forGNU/Linux 2.6.18, BuildID[sha1]=0xf78b4955773f3c5dfecdb11c62dae094a99ba8f9, notstripped

现在我们可是使用cpio应用程序创建我们的内存磁盘,仅仅把init文件放入一个归档包:

echoinit|cpio –o –format=newc > initramfs

注意这个命令必须在和init文件相同的目录中运行,initramfs文件就是我们的内存磁盘,你可以通过如下命令检查它的内容:

cpio–t <initramfs

5.模拟内核启动和内存磁盘运行

所有需要在Linux中通过QEMU执行的东西都齐备了,我们可以使用”-Mvexpress A9”选项来模拟VersatileExpress平台。zImage内核和initramfs镜像通过”-kernel”和”-initrd”选项被QEMU加载至模拟RAM中,指向相应的文件。

我们还想把启动信息送到控制台进行显示,为了在图形窗口中显示,我们需要传递”console=tty1”内核参数。这个内核参数将会被QEMU通过”-append”选项传递给Linux。

完整的命令如下:

qemu-system-arm-M vexpress-a9 -kernel linux-3.2/arch/arm/boot/zImage -initrd initramfs -append"console=tty1"

这个命令将会打开QEMU并打开一个黑色的控制台窗口,通过一个Tuxlogo来显示图形能力。启动信息将会在这个图形窗口显示,并且在启动信息的最后会打印出我们的”HelloWorld!”信息。

另一方面,QEMU可以重定向主机上的模拟系统的串口,使用选项”-serialstdio”,则Linux可以通过传递”console=ttyAMA0”作为内核参数而在第一个串口中显示它的信息。则命令变为:

qemu-system-arm-M vexpress-a9 -kernel linux-3.2/arch/arm/boot/zImage -initrd initramfs -serialstdio -append "console=ttyAMA0"

这个命令将会打开QEMU并打开一个黑色的控制台窗口,而启动信息会显示在主机的终端而非那个黑色的窗口。注意到”ttyAMA0”是一个依赖于其要模拟的硬件的串口名称,可能并不是所有的系统都是相同的。

在我的测试中,我使用的是QEMU1.0版本,如果你使用一个不同的版本,结果可能有所不同。

<think>好的,用户现在想了解如何编译Linux内核5.9.6版本,QEMU模拟ARM开发板进行驱动开发学习。我需要先回顾之前的对话历史,看看有没有相关信息可以参考。之前用户问过关于内核配置中修改ARM架构兼容性的问题,所以可能已经有一定的背景知识,比如配置内核选项、交叉编译工具链的使用等。 首先,用户的目标是编译特定版本的内核,然后使用QEMU模拟ARM环境进行驱动开发。这需要确保内核版本5.9.6的源码可用,QEMU支持对应的ARM开发板模拟。可能需要检查该内核版本是否兼容QEMU的某些板子,比如vexpress-a9或versatilepb,这些都是常用的模拟板。 接下来,我需要考虑用户可能的背景。用户可能刚开始学习内核驱动开发,对交叉编译QEMU的使用还不熟悉。因此,步骤需要详细,特别是环境搭建部分,比如安装依赖包、交叉编译工具链、QEMU本身等。同时,用户可能需要知道如何获取正确版本的内核源码,可能需要使用wget或者git,但5.9.6是一个较旧的版本,可能需要从kernel.org的存档下载。 然后,配置内核时,用户需要指定ARCH=arm,使用交叉编译工具链。这里可能需要提醒用户安装正确的工具链,比如gcc-arm-linux-gnueabihf。此外,在menuconfig中,确保配置支持对应的ARM板,可能需要选择对应的SOC类型,比如vexpress,同时启用必要的驱动和模块支持,比如网络驱动、文件系统支持等,方便后续测试。 编译完成后,用户需要生成zImage和dtb文件,用于QEMU启动。同时,创建根文件系统,用户可能不熟悉如何制作initramfs或者使用busybox,所以需要详细说明步骤,或者提供替代方法,比如使用预先构建的文件系统镜像。 在QEMU启动命令中,需要指定正确的机器类型、内核镜像、设备树文件、内存大小,以及根文件系统的位置。如果用户需要网络支持,可能还需要配置虚拟网络设备,比如tap设备,启用网络驱动。 驱动开发部分,用户可能需要一个简单的示例,比如字符设备驱动,包括编写代码、Makefile,以及测试步骤。需要确保编译驱动时使用正确的内核源码路径和架构。测试时,通过insmod加载模块,查看输出,可能需要QEMU的控制台或者串口输出来调试。 潜在的问题可能包括内核版本过旧导致的依赖问题,工具链不兼容,QEMU启动参数错误,根文件系统无法挂载等。需要提醒用户注意版本匹配,检查错误日志,逐步验证每个步骤。 用户可能没有提到的深层需求是希望有一个可重复、隔离的环境进行驱动开发,避免影响宿主机系统。因此,使用QEMU模拟是非常合适的,但需要确保整个流程清晰,用户能够顺利启动模拟环境进行测试。 总结来说,回答需要分步骤详细说明环境搭建、内核编译QEMU配置、根文件系统准备、驱动编写和测试,同时提供常见问题的解决方法,确保用户能够一步步完成操作,理解每个步骤的作用。</think>以下是编译 Linux 5.9.6 内核使用 QEMU 模拟 ARM 开发板进行驱动开发学习的完整流程: --- ### **1. 环境准备** #### **1.1 安装依赖** ```bash # Ubuntu/Debian 系统 sudo apt update sudo apt install -y git build-essential gcc-arm-linux-gnueabihf qemu-system-arm libssl-dev bison flex libncurses-dev ``` #### **1.2 获取内核源码** ```bash wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.9.6.tar.xz tar -xvf linux-5.9.6.tar.xz cd linux-5.9.6 ``` --- ### **2. 配置内核** #### **2.1 选择默认配置** 使用 `vexpress_defconfig`(QEMU 支持的 ARM 开发板): ```bash make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- vexpress_defconfig ``` #### **2.2 可选:自定义配置** 启动图形化配置界面: ```bash make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig ``` **关键配置项**: - **启用模块支持**:确保 `Enable loadable module support` 已开启。 - **调试支持**:在 `Kernel Hacking` 中启用 `Kernel debugging` 和 `Compile the kernel with debug info`。 - **驱动支持**:根据需要启用串口、网络、块设备等驱动(默认 `vexpress_defconfig` 已包含基础支持)。 --- ### **3. 编译内核** ```bash make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-j$(nproc) ``` 编译完成后生成文件: - **内核镜像**:`arch/arm/boot/zImage` - **设备树文件**:`arch/arm/boot/dts/vexpress-v2p-ca9.dtb` --- ### **4. 创建根文件系统** #### **4.1 使用 BusyBox 构建最小文件系统** ```bash # 下载编译 BusyBox wget https://busybox.net/downloads/busybox-1.36.1.tar.bz2 tar -xvf busybox-1.36.1.tar.bz2 cd busybox-1.36.1 make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- defconfig make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig # 可选:启用静态链接 make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-j$(nproc) make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- install ``` #### **4.2 创建 initramfs** ```bash # 创建根文件系统目录 mkdir -p rootfs/{dev,proc,sys,bin} sudo mknod rootfs/dev/console c 5 1 sudo mknod rootfs/dev/null c 1 3 # 复制 BusyBox 文件 cp -r busybox-1.36.1/_install/* rootfs/ # 创建初始化脚本 echo &#39;#!/bin/sh mount -t proc none /proc mount -t sysfs none /sys /sbin/mdev -s exec /bin/sh&#39; > rootfs/init chmod +x rootfs/init # 打包为 initramfs cd rootfs find . | cpio -o -H newc | gzip > ../initramfs.cpio.gz ``` -- ### **5. 启动 QEMU** ```bash qemu-system-M vexpress-a9 \ -m 512M \ -kernel linux-5.9.6/arch/arm/boot/zImage \ -dtb linux-5.9.6/arch/arm/boot/dts/vexpress-v2p-ca9.dtb \ -append "console=ttyAMA0 root=/dev/ram rdinit=/init" \ -initrd initramfs.cpio.gz \ -nographic \ -net nic -net user,hostfwd=tcp::2222-:22 # 可选:启用网络 ``` --- ### **6. 驱动开发示例(字符设备驱动)** #### **6.1 编写驱动代码 `hello.c`** ```c #include <linux/init.h> #include <linux/module.h> #include <linux/fs.h> #define DEVICE_NAME "hello" static int __init hello_init(void) { printk(KERN_INFO "Hello, ARM Kernel!\n"); return 0; } static void __exit hello_exit(void) { printk(KERN_INFO "Goodbye, ARM Kernel!\n"); } module_init(hello_init); module_exit(hello_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Your Name"); ``` #### **6.2 编写 Makefile** ```makefile KDIR ?= /path/to/linux-5.9.6 ARCH ?= arm CROSS_COMPILE ?= arm-linux-gnueabihf- obj-m += hello.o all: make -C $(KDIR) M=$(PWD) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules clean: make -C $(KDIR) M=$(PWD) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) clean ``` #### **6.3 编译测试** ```bash make # 将生成的 hello.ko 复制到 QEMU 虚拟机的根文件系统中 # 在 QEMU 中加载驱动: insmod hello.ko dmesg | tail # 查看输出 ``` --- ### **常见问题** 1. **QEMU 启动失败**: - 检查 `zImage` 和 `dtb` 路径是否正确。 - 确认 `vexpress-a9` 机器类型是否支持。 2. **驱动加载失败**: - 确保驱动编译时使用的内核版本 QEMU 中运行的内核一致。 - 检查 `printk` 输出是否被重定向到控制台(`console=ttyAMA0`)。 3. **网络配置**: - 若需网络支持,在 QEMU 启动命令中添加 `-net user`,内核配置中启用网络驱动。 --- 通过以上步骤,你可以在 QEMU 模拟的 ARM 环境中进行完整的内核编译和驱动开发学习。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值