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跑起来虚拟机来
如何移植openssh到ARM开发板

最近因为公司安全的需求, 要修改openssh的源码, 将其移植到一个ARM的嵌入式系统上, 替换原有的预编译的版本. 参考了网上的一些移植openssh的资料, 如openssl官网编译安装说明; 移植openssh到arm-linux, 但是由于目标平台不一样, 实践起来并不能完全参考, 会有细微的差异. 这里把整个流程写下来, 总结一下, 方便后面移植相关开发工具.

理解Android eBPF

Android从9.0版本开始全面支持eBPF(extended Berkeley Packet Filters), 其主要用在流量统计上, 也可以用来监控CPU/IO/内存等模块的状态.简单来说, eBPF可以与内核的kprobe/tracepoints/skfilter等模块相结合, 将eBPF的函数hook到内核事件从而监控相应的系统状态.

Android为eBPF提供了许多封装的库, 并提供了eBPF加载器bpfloader:

  • bpfloader: 位于/system/bpf/bpfloader, 系统启动时负责加载位于/system/etc/bpf 中的eBPF目标文件
  • libbpf_android: 位于/system/bpf/libbpf_android提供创建bpf容器/加载bpf目标文件的接口
  • libbpf: 位于/external/bcc, 封装了bpf的系统调用, 提供如attach/dettach程序的接口
  • libnetdbpf: 位于/system/netd/libnetdbpf, 实现了netd流量统计功能的函数

目前在Android(Q)上有两处eBPF的代码: 一个是/system/netd/bpf_progs/netd.c, 主要是用于流量统计;一个是/system/bpfprogs/time_in_state.c用于监控CPU运行频率以及上下文切换的耗时.

接下来我们就从三个部分来深入理解下Android是如何利用eBPF的:

  • eBPF程序与目标文件格式
  • Android eBPF加载与执行流程
  • Android如何基于eBPF实现流量统计
一个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、多个进程同时访问内核数据也同样会产生竞争条件。

BPF与eBPF

最近了解Linux的性能优化时, 接触到了BPF(Berkeley Packet Filter)。很有意思也很强大的功能;想把学到的一些基本原理与知识记录下来, 算是一个初步的总结. 这篇文章主要从如下几个方面介绍下BPF:

  • BPF的原理
  • 什么是eBPF
  • 如何在Linux中使用BPF

用过tcpdump的同学应该都了解pcap, 实际上pcap就是基于BPF来实现网络数据包的过滤的. tcpdump的原理如下图所示: tcpdump将包过滤的表达式, 如查看某个网口所有udp包, 输入tcpdump -n -i eth0 udp, 这个表达式通过PCAP库编译成伪机器字节码后, 通过系统调用发送给内核(内核中有对应的机器码解释器)解释执行, 这样只要系统有udp包, 内核都会过滤出来转发给用户进程tcpdump:

how tcpdump works

Linux下常用网络工具使用总结

平时在Android/Ubuntu这样的Linux系统中, 经常跟网络打交道, 不可避免的要使用网络工具来定位问题;这里对Linux常用的网络工具进行简单的总结, 方便后续查阅使用. 主要看看以下几个常用的网络工具:

  • ping: 基于ICMP协议, 发送ICMP数据包用于测试网络连通状态
  • traceroute: 基于UDP/ICMP/TCP协议用于跟踪网络连通状态, 打印达到目标地址的路由信息
  • tcpdump : 用于抓取tcp/ip包, 分析网络问题的必需神器
  • iproute2 : 查看/添加/删除当前路由信息
  • netstat: 查看网络状态
  • netcfg: 配置网口(使能网口以及配置IP等)
  • iptables: 网络数据包的过滤以及防火墙策略配置
  • netcat: 用于快速建立TCP/UDP链接,检测网络的连通性
  • iperf: 网络性能测试工具, 用来衡量网络吞吐量/带宽
  • tc: Traffic Control, 用于显示/修改网卡配置的工具
  • curl: 基于libcurl的数据传输工具, 支持HTTP/HTTPS/FTP/RTMP/RTSP/SCP等常见协议
  • iw: 用于显示/设置WiFi设备接口的工具, 比如展示当前设备WiFi热点信息, 主动扫描周围WiFi热点等
  • ethtool: 查看/设置以太网网卡驱动/硬件配置
socket编程与IO multiplexing

socket通常用于跨进程通信(Inter-Process Communication,IPC),由于其最早BSD Unix发行版中使用,因此也叫做Barkeley sockets。socket封装了底层网络通信协议细节,为上层应用提供了一个统一的接口,按照使用的“域”不同,又分为用于网络通信的internet socket以及用于本地进程通信的Unix domain socket。

那么,如何利用socket实现IPC通信了?在多个客户端的情况下,服务端要如何实现同时响应多个客户请求了,即如何实现多个IO端口的监听(I/O multiplex)?这篇文章,就来看看这两个问题。首先,来看下socket编程的一些基本知识。

Linux Shell快速入门

前言

开始使用Ubuntu操作系统,使用起来感觉挺顺,但是对于Shell脚本了解不多,以下是一个简单的shell入门总结。

不同的类Unix系统可能使用不同的Shell程序, 这里所有的例子都是基于Bash(Bourne Again Shell)

脚本语言,既然冠之以“语言”,就说明它跟其他C/C++等编译语言在形式上是完全一样的,有变量,有函数,有if,else,while等条件分支,只是脚本语言是解释性的执行:碰到一句,解释一句,执行。