JasonWang's Blog

如何通过QEMU启动Linux系统

看Linux驱动相关的代码, 却没有一个好的调试环境可以跟踪内核相关的调用流程。于是,想着用QEMU虚拟机来搭建一个Linux系统。花了大半天时间,终于能够启动一个简单的Linux系统了。中间踩了不少坑,找了不少资料,这里简单总结下整个过程。

以下操作都是基于Ubuntu 18.04 x86_64平台

最开始参考了如何使用QEMU跑内核,使用系统自带的QEMU工具,结果提示如下错误:

1
2
3

qemu-system-aarch64 rom check and register reset failed

怀疑是QEMU的版本太低导致,于是只好又重新编译QEMU源码,最后总算大功告成。总的说来,大致要做的事情有这么几个:

  • 编译Linux内核,利用busybox来生成一个小的rootfs(关于什么是rootfs,可以参考The rootfs FS)
  • 编译QEMU,确保正常配置ARM64架构的虚拟环境
  • 一切就绪,通过qemu-system-aarch64跑起来虚拟机来
一个SMMU内存访问异常的问题

最近碰到棘手的问题: 以太网进行iperf测试时, 发生了SMMU (System Memory Management Unit)访问异常导致内核崩溃. 原本只是内部测试发现, 后面在试验车上也概率性的出现. 问题发生的概率还不小. 很严重. 只能先从头把一些基本概念与流程梳理清楚. 好在最后还是找到了原因并解决了. 松了口气, 才有时间把整个问题的来龙去脉细细的总结下, 算是一个SMMU相关问题的案例.

首先来看看问题的发生的背景.

问题背景

问题发生在利用iperf做网络性能测试的时候, 测试系统(采用高通8155平台, 内置一个EMAC芯片, 最高支持1Gbps速率)作为客户端:

1
2
3

iperf -c 172.20.2.33 -p 8989 -f m -R

这里加-R参数表示客户端作为数据接收方(奇怪的是, 测试不加-R参数就不会有问题, 这也说明只有在接收数据的过程才会出现问题), 而服务端是发送方:

1
2
3

iperf -s -p 8989 -f m

这么测试几十个小时就很快出现了, 抓取到的问题堆栈如下. 前面的日志是SMMU相关的寄存器状态打印, 后面是内核调用堆栈.

Linux内核中的锁

在看Linux内核代码时,经常会遇到各种锁(lock)的使用。对于像spin_lock_irq/spin_lock_irqsave的区别感到困惑,每次都要重新查一下资料。遂决定写一篇文章记录下内核中使用到的锁,以及使用的场景。

与应用中的锁类似,内核中的锁也只是为了保护某个内核数据结构或者内存区域在多个并发执行路径时不被破坏,确保数据的一致性。Linux内核作为应用层服务的提供者,一方面要为应用提供系统调用接口(system call),代表用户进程执行任务,即process context, 在进程上下文中可以休眠,执行调度;同时与硬件直接交互,要响应硬件中断的请求,处理诸如网卡数据/串口数据等请求,即Interrupt Context,在中断上下文内核不能休眠,无法重新调度. 内核就是在进程上下文/中断上下文直接来回切换,执行相应的任务请求。这就自然产生了数据的并发访问,产生了竞争条件(race condition)。另一方面,目前大多数的系统都是多核CPU、支持多进程,多个CPU、多个进程同时访问内核数据也同样会产生竞争条件。