【嵌入式课程实验报告】QEMU模拟Cortex-A9运行U-boot和Linux

本文详细介绍了一种在PC机上使用QEMU模拟器和VMware虚拟机搭建嵌入式Linux开发环境的方法,包括安装配置、编译U-boot、Linux内核及Busybox,以及在QEMU上运行Linux系统和应用程序的全过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 实验目的

  1. 熟练使用Linux操作系统;
  2. 认识一种新的内核模拟器QEMU;
  3. 掌握嵌入式Linux系统的开发流程;

2. 实验要求

  1. 在PC机上安装VMware虚拟机,并在VMware中安装Linux操作系统(Ubuntu 12.04);
  2. 在Ubuntu中安装QEMU;
  3. 编译U-boot,并在QEMU上运行;
  4. 编译Linux内核,并使用Busybox制作根文件系统;
  5. 在QEMU上运行Linux操作系统;
  6. 在该Linux系统上运行应用程序。

3. 实验原理

  1. VMware Workstation虚拟机是可以在Windows/Linux系统上运行的应用程序,它可以模拟基于x86的标准PC环境。这个环境和真实的计算机一样,都有芯片组、CPU、内存、显卡、声卡、网卡、软驱、硬盘、光驱、串口、并口、USB控制器、SCSI控制器等设备。与“多启动”系统相比,VMWare采用了完全不同的概念,多启动系统在一个时刻只能运行一个系统,在系统切换时需要重新启动机器。而VMWare虚拟机软件是一个“虚拟PC”软件,它可以使你在一台机器上同时运行多个Windows、DOS、LINUX系统,并且在系统切换时不需要重启计算机。
    在使用上,这台虚拟机和真正的物理主机几乎没有区别,都需要分区、格式化、安装操作系统、安装应用程序和软件,总之,一切操作都跟一台真正的计算机一样。

  2. QEMU模拟器:QEMU 是一个面向完整PC系统的开源仿真器。除了可以仿真处理器之外,QEMU 还可以仿真所有必要的子系统,如连网硬件和视频硬件。它还允许实现高级概念上的仿真(如对称多处理系统(多达 255个CPU))和对其他处理器架构(如 ARM 和 PowerPC)的仿真。QEMU有两种运行模式:

  • User mode模拟模式,亦称作使用者模式。QEMU能启动那些为不同中央处理器编译的Linux程序。
  • System mode模拟模式,亦称作系统模式。QEMU能模拟整个电脑系统,包括中央处理器及其他周边设备。它使得对跨平台编写的程序进行测试及调试变得容易。其亦能用来在一部主机上虚拟多部不同的系统。
  1. 嵌入式Linux系统的结构
    嵌入式Linux系统从软件的角度看通常可以分为4个层次:
    ①引导加载程序Bootloader。
    ②内核。完成对硬件设备的控制,Linux内核的主要模块分为以下几个部分:存储管理、CPU和进程管理、文件系统、设备管理和驱动、网络通信、以及系统的初始化(引导)、系统调用等。
    ③文件系统。它提供了用于管理系统的各种配置文件,以及为系统执行用户应用程序提供了良好的运行环境。
    ④用户应用程序。根据不同的用户需求而编写的程序。

  2. QEMU与宿主机之间的通信机制:QEMU提供了四种网络通信模式:TAP、user、Sockets和VDE。利用user模式可以实现虚拟机和宿主机之间的通信且较为简单易行,在这种通信模式中,虚拟机处于10.0.2.*网段,该网段通过一个NAT服务器与外界通信,NAT服务器的地址是10.0.2.2,虚拟机的IP地址从10.0.2.15开始分配。

4. 实验步骤

4.1 实验准备

  1. 实验环境选定ubuntu12.04,VMware
  2. 终端sudo apt-get update完成更新
  3. 安装GNU交叉编译工具链:
sudo apt-get install gcc-arm-linux-gnueabi
sudo apt-get install g++-arm-linux-gnueabi

4.2 安装QEMU

sudo apt-get install qemu qemu-system qemu-utils
qemu-system-arm --version//查看版本信息

在这里插入图片描述

4.3 编译并运行U-boot

  1. 下载U-boot源码,并进行解压(以u-boot-2012.04.tar.bz2为例):
ftp://ftp:denx.de/pub/u-boot/        #下载链接
tar jxvf u-boot-12.04.tar.bz2        //解压命令
  1. 修改Makefile,添加下列两行:
ARCH ?=arm
CROSS_COMPILE ?= arm-linux-gnueabi-
  1. 进入u-boot-12.04文件夹,执行下列命令,生成u-boot.bin文件:
make ca9x4_ct_vxp_config 
make

在这里插入图片描述

  1. 执行命令启动u-boot:
qemu-system-arm -M vexpress-a9 -m 256M -nographic -kernel u-boot

在这里插入图片描述
此时是检测Flash failed后停止运行,是因为在 arch/arm/lib/board.c里面 board_init_r()函数里检测Flash失败后调用了hang(), 暂时先把hang()去掉就可以运行下去了【修改了board.c需要重新执行上述的两个make】。正常的运行结果如下:

在这里插入图片描述

4.4 编译并运行Linux

4.4.1 生成内核映像文件

  1. 下载Linux内核源码(此处以linux-3.4.4.tar.bz2为例),并修改Makefile:
http://www.kernel.org/    #下载链接

ARCH = arm                    //修改文件,直接打开Makefile,搜索ARCH,找到第一个匹配的修改
CROSS_COMPILE=arm-linux-gnueabi-
  1. 在解压后的目录下make vexpress_defconfig在这里插入图片描述

  2. make menuconfig–>System TypeEnable the L2x0 outer cache controller取消,否则QEMU会起不来
    在这里插入图片描述

  3. 在这里可能报错,需要执行apt-get install ncurses-dev:
    在这里插入图片描述
    在这里插入图片描述

  4. make,会在arch/arm/boot/ 目录下生成zImage内核映像文件,这就是我们需要的内核映像。
    在这里插入图片描述

4.4.2 制作根目录系统

4.4.2.1 编译busybox
  1. 下载busybox源码(以busybox-1.21.0.tar.bz2为例),一样的修改Makefile:
http://www.busybox.net/downloads/busybox-1.21.0.tar.bz2   #下载链接

ARCH = arm       //修改文件
CROSS_COMPILE=arm-linux-gnueabi-
  1. make menuconfig, Busybox Setting–>Build Opdions–>选择[]Build BusyBox as a static binary(no shared libs)使用静态编译
    在这里插入图片描述

  2. make报错,进入make menuconfig,在菜单中Networking Utilities-->Support RPC serverces取消选择,再次make
    在这里插入图片描述
    在这里插入图片描述

  3. make,产生install文件;make install,产生文件夹_install
    在这里插入图片描述
    在这里插入图片描述

4.4.2.2 制作根文件系统目录
  1. 在主目录下执行:
mkdir rootfs
cd rootfs

进入rootfs目录下执行:

//建立目录结构
mkdir bin etc dev lib proc tmp root home sys usr sbin var mnt
//运行库-来自工具链
cp -a /usr/arm-linux-gnueabi/lib/* lib
//配置文件-来自busybox
cp -a /home/ersheng/busybox-1.21.0/examples/bootfloppy/etc/* etc
//busybox工具集
cp -a /home/ersheng/busybox-1.21.0/_install/* .
//设备文件
sudo cp -a /dev/console /dev/loop0 /dev/loop1 /dev/null /dev/ram0 /dev/tty /dev/tty0 /dev/tty1 /dev/tty2 /dev/zero dev

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  1. 修改mdev配置,mdev负责自动生成设备节点,mdev.conf是配置文件:
vim etc/mdev.conf

在这里插入图片描述

  1. 修改启动配置:
vi etc/init.d/rcS

在这里插入图片描述

4.4.2.3 根文件系统镜像
  1. 在主目录下建立一个test.sh脚本(方便执行),脚本内容如下:
dd if=/dev/zero of=rootfs.img bs=1M count=32 # 32M的镜像
mkfs.ext3 rootfs.img
mkdir tmpfs
sudo mount -o loop rootfs.img tmpfs
sudo cp -a rootfs/* tmpfs/

在这里插入图片描述
运行脚本:

chmod +x ./test.sh 
./test.sh
  1. 卸载tmpfs:
sudo umount tmpfs

4.4.3 QEMU运行Linux系统

qemu-system-arm -M vexpress-a9 -m 256M -kernel /home/ersheng/linux-3.4.4/arch/arm/boot/zImage -append "root=/dev/mmcblk0 console=tty0 init=/linuxrc" -sd rootfs.img

在这里插入图片描述

4.5 在目标机运行应用程序

用户应用程序在目标机上运行有两种方法:
将编译后的可执行文件放入到根文件系统中,在做成根文件系统的镜像后,由内核调用并执行。
②使用NFS(网络文件系统)在本地机和目标机之间建立通信。
1)QEMU与Ubuntu之间的通信

  1. 首先在Ubuntu上安装NFS网络文件系统
apt-get install nfs-kernel-server
  1. 在NFS服务的配置文件/etc/exports中添加:
/    *(rw,no_root_squash,insecure)
  1. 关闭Ubuntu的网关,避免连接不上:
    在/etc/resolv.conf中全部注释掉,不要DNS服务器地址。
  2. 在宿主机Ubuntu中开启NFS服务:
/etc/init.d/nfs-kernel-server start
  1. 再次启动Qemu,在最后面添加如下命令
-net user -net nic –s
  1. 最后,在目标机中配置网络、挂载NFS文件系统、切换根文件系统:
ifconfig eth0 10.0.2.15 up  
route add default gw 10.0.2.2
mount -t nfs -o nolock 192.168.1.241:/ /mnt

这样就可将192.168.1.241的主机的文件系统挂载到/mnt目录下。
(注:192.168.1.241是我的Ubuntu的IP地址,可用ifconfig查看本地机的IP地址。)

目前第二种方法暂配失败,下面采取第一种方法

  1. 先在本地创建hello.c,然后使用arm-linux-gnueabi-gcc编译该文件得到可执行文件hello(使用arm-linux-gnueabi-gcc适应目标机的体系架构):
    在这里插入图片描述
#include <stdio.h>
int main()
{
	printf("hello world");
	return 0;
}
  1. 拷贝到tempfs,与目标机共享文件:
cp hello ./tempfs/
  1. 重新启动QEMU,进行测试:
    在这里插入图片描述

5. 思考题

  1. QEMU运行的Linux系统中是否需要安装gcc
    答: 不需要,QEMU中运行的Linux系统由于系统架构不同,所以直接采用交叉编译工具进行编译即可
  2. 在本地机编译应用程序时,是使用gcc还是arm-linux-gcc?为什么?
    答:使用arm-linux-gcc,原因与上题一致
  3. 如何将可执行文件在系统开机后自启动?
    答:将可执行文件放在/etc/init.d/下的这个文件rcS里,在这个文件下的最后一行再加上这样一句命令:cd 你要执行的程序的绝对路径 ./test(test为你要执行的文件)
  4. QEMU运行的Linux系统是命令行模式,如何将它改成图形用户界面模式?
    答:将ttyS0改为tty0

6. 个人总结

经过近3天的学习与动手,大致将本次实验做完了,其中出了不少的bug,但在同学的帮助下都得到了解决,我觉得此次实验最大的好处即是提升了个人的linux能力,以及解决问题及分析问题能力。
通过此次实验,了解了QEMU这一内核模拟器,也大致了解了嵌入式Linux系统的开发流程,锻炼了自己独立解决问题的能力,不管从哪方面来说,这都是一次很好的实验经历。

<think>好的,用户现在想了解如何学习Cortex-A9处理器。首先,我需要回顾之前的对话,用户之前已经询问过Cortex-A9的详细介绍,现在转向学习方法。这可能意味着用户有实际应用的需求,比如嵌入式开发或相关项目,或者他们正在准备进入这一领域的学习。 接下来,我需要考虑用户可能的背景。由于Cortex-A9属于较老的架构,但仍在许多嵌入式系统中使用,用户可能是在工作中遇到相关项目,或者是学生需要掌握这一技术。因此,回答需要既包含理论基础,又强调实践操作,同时可能涉及工具链实际案例。 用户的需求可能不仅仅是学习架构本身,而是如何系统地掌握,包括开发环境搭建、编程、调试以及项目应用。需要分步骤引导,从基础到进阶,逐步深入。可能还需要推荐资源,如书籍、在线课程或实验平台,帮助用户找到学习材料。 另外,用户可能对实践环节特别关注,比如如何获取开发板,如何开始第一个程序,如何处理多核编程或性能优化等问题。需要提供具体的例子,比如代码片段、调试命令,以及常见问题的解决方法。 还需要考虑用户可能遇到的挑战,比如交叉编译环境的配置、硬件调试的复杂性、多核同步问题等。在回答中需要预先提及这些难点,并给出解决建议,帮助用户规避常见陷阱。 最后,结合之前的回答结构,保持一致的风格,使用清晰的标题、分点说明、代码示例公式,增强可读性实用性。确保语言口语化,避免过于技术化的术语,或在必要时进行解释,让不同层次的读者都能理解。</think>学习Cortex-A9处理器需要理论与实践相结合,以下是系统化的学习路径关键实践方法,包含具体操作案例开发技巧: --- ### 一、基础理论准备 1. **架构文档精读** - 必读手册: - 《ARM Cortex-A9 MPCore Technical Reference Manual》(ARM DDI 0407) - 《ARM Architecture Reference Manual ARMv7-A and ARMv7-R edition》 - 重点章节标注示例: ```markdown [!NOTE] 关键章节标记 - Chapter 3: Processor Modes (USR/SVC/IRQ等模式转换) - Chapter 4: Memory Management Unit (页表项bitmap解析) - Chapter 10: L1 Cache Controller (缓存替换策略) ``` 2. **指令集训练** - 编写基础汇编程序(使用GAS语法): ```assembly .global _start _start: MOV R0, #0x1000 @ 立即数加载 LDR R1, =data_block @ 伪指令地址加载 loop: LDR R2, [R1], #4 @ 自动后变址加载 ADD R0, R0, R2 @ 累加操作 CMP R1, #end_data @ 地址比较 BNE loop data_block: .word 0x1,0x2,0x3,0x4 end_data: ``` --- ### 二、开发环境搭建 1. **工具链配置** - 推荐使用Linaro GCC交叉编译链: ```bash # 安装命令 sudo apt-get install gcc-arm-linux-gnueabihf # 验证版本 arm-linux-gnueabihf-gcc -v ``` 2. **QEMU仿真环境** - 启动带Cortex-A9仿真的虚拟机: ```bash qemu-system-arm -M vexpress-a9 -kernel zImage \ -dtb vexpress-v2p-ca9.dtb -nographic -append "console=ttyAMA0" ``` 3. **硬件开发板选择** | 开发板型号 | 特点 | 参考价格 | |------------------|-------------------------------|----------| | Zynq-7000系列 | FPGA+双核A9,适合异构开发 | $300 | | i.MX6 Solo | 工业级单核方案 | $150 | | STM32MP157 | 集成3D GPU,支持Android | $80 | --- ### 三、关键实验项目 1. **启动代码分析** - 分析Uboot启动流程(以vexpress板为例): ```c // arch/arm/cpu/armv7/start.S reset: bl save_boot_params mrc p15, 0, r0, c1, c0, 0 @ 读取SCTLR bic r0, r0, #0x2000 @ 关闭指令缓存 mcr p15, 0, r0, c1, c0, 0 @ 写回SCTLR ``` 2. **中断控制器实验** - 编写GIC中断处理程序: ```c void __irq_handler() { uint32_t int_id = readl(GIC_CPU_INTACK); switch(int_id) { case TIMER_IRQ: handle_timer(); // 定时器中断处理 break; } writel(int_id, GIC_CPU_EOI); } ``` 3. **多核通信实践** - 使用核间中断(IPI)实现任务分发: ```c // Core0发送信号 send_ipi(1, TASK_START); // 向Core1发送任务启动指令 // Core1接收处理 while(!pending_ipi()); task_id = get_ipi_msg(); ``` --- ### 四、性能优化技巧 1. **NEON加速实践** - 矩阵乘法优化(4x4单精度): ```c void neon_matmul(float *C, float *A, float *B) { asm volatile ( "vld1.32 {d16-d19}, [%1]! \n" // 加载A矩阵 "vld1.32 {d20-d23}, [%2]! \n" // 加载B矩阵 "vmla.f32 q12, q8, q10 \n" // 乘加运算 "vst1.32 {d24-d27}, [%0]! \n" // 存储结果 : "+r"(C) : "r"(A), "r"(B) : "q8","q9","q10","q11","q12" ); } ``` 2. **缓存优化策略** - 数据预取示例: ```c #define PREFETCH(addr) __builtin_prefetch(addr,0,3) for(int i=0; i<size; i+=64){ PREFETCH(&data[i+64]); // 提前预取下一缓存行 process(data[i]); } ``` --- ### 五、调试与问题排查 1. **JTAG调试配置** - OpenOCD配置文件示例(J-Link调试器): ```tcl interface jlink transport select jtag set CHIPNAME cortex_a9 jtag newtap $CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf targets cortex_a9.cpu ``` 2. **常见问题解决方案** | 问题现象 | 排查步骤 | 典型原因 | |--------------------------|-----------------------------------|------------------------| | 启动卡在uboot | 检查DDR初始化参数 | 时序配置错误 | | 多核系统死锁 | 分析spinlock使用情况 | 未正确释放锁 | | NEON计算结果异常 | 检查内存对齐(16字节对齐) | 未使用ALIGNED属性 | --- ### 六、进阶学习资源 1. **推荐书籍** - 《ARM System Developer&#39;s Guide》Andrew Sloss 著 -Cortex-A Series Programmer&#39;s Guide》ARM官方文档 2. **在线实验平台** - ARM DS-5 Development Studio:支持虚拟化Cortex-A9仿真 - Keil MDK-Arm:提供完整开发环境(需License) --- ### 七、学习路线图 ```mermaid graph TD A[基础理论] --> B(ARMv7架构) A --> C(汇编指令集) B --> D[开发环境搭建] C --> D D --> E[单核实验] D --> F[多核通信] E --> G[性能优化] F --> G G --> H[实际项目] ``` 通过以上系统性学习,建议在6个月内完成从基础到项目开发的过渡。重点掌握:**多核同步机制**、**NEON优化****异常处理流程**。实际操作中遇到问题时,建议结合ARM CoreSight技术进行实时追踪调试。
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值