龙芯MIPS64 QEMU ioctl的问题
龙芯 QEMU 问题
最近搞了一块使用国产龙芯 3A3000 处理器的开源开发板,顺便捣鼓移植我们的服务程序,安装龙芯开源社区的 Loongnix 系统之后测试下来 3A3000 处理器的性能还是基本能用的。龙芯处理器自带的内存控制器也能到 DDR3-1600 了,只是目前还在使用 HT3.0 总线确实拖累系统性能。
我们部署的一些服务目前还依赖几个 x86 系统的闭源程序,无法直接在龙芯 MIPS64 系统下运行,就想到使用 QEMU 的 User-mode emulation 来实现了。
Loongnix 系统中的 qemu-i386 运行比较简单的 x86 程序一般都没有问题,不过我发现即使用打了 ioctl patch 的 QEMU 运行其中一个使用了私有 ioctl 调用的 x86 程序仍然会出错,通过开启 qemu-i386 的 strace 可以看到错误信息:
zzm@loongnix:~$ qemu-i386 -strace /lib/i386-linux-gnu/ld-linux.so.2 --library-path /lib/i386-linux-gnu /usr/sbin/test-agent 2459 ioctl(5,-1055634175,-42368,0,0,-42056) = -1 errno=25 (Inappropriate ioctl for device) 2459 ioctl(5,-1055634175,-41488,0,0,-41176) = -1 errno=25 (Inappropriate ioctl for device) 2459 ioctl(5,-1055634175,-44192,0,0,-43880) = -1 errno=25 (Inappropriate ioctl for device)
上面的 /usr/sbin/test-agent
就是要模拟运行的 x86 二进制程序,/lib/i386-linux-gnu
是我在龙芯 MIPS64 系统上增加的 x86 程序依赖基础库目录,其中最重要的就是 libc.so.6
和 ld-linux.so.2
库了。
从 strace 数据应该可以发现该 ioctl 已经发到设备,但是 kernel 返回 Inappropriate ioctl
错误,而 -1055634175
则表示 x86 二进制程序发送的是 compat ioctl,此时我才想起来确认下 qemu-i386 程序是否正确:
zzm@loongnix:~$ file `which qemu-i386` /usr/bin/qemu-i386: ELF 64-bit LSB executable, MIPS, MIPS64 rel2 version 1 (SYSV), dynamically linked (uses shared libs), BuildID[sha1]=39cac8103f052b4ffa161f615159c888024ef4e3, for GNU/Linux 2.6.32, stripped
龙芯 Loongnix MIPS64 系统目前兼容几种 ABI:
- O32:MIPS 32 位处理器使用;
- N64:只适用于 MIPS 64 位处理器,使用 64 位指针和 long integers;
- N32:只适用于 MIPS 64 位处理器,在保留 MIPS N64 ABI 的几乎所有特性的情况下,使用 32 位指针和 long integers。
这个 qemu-i386 使用的是 MIPS64 N64 ABI,而 qemu-i386 实际运行的 x86 二进制程序在龙芯 64 位 kernel 下会发送 compat ioctl,这样最终 qemu-i386 程序调用 compat ioctl 时就显然会有问题,报 Inappropriate ioctl
也就不奇怪了。
解决方法也就很简单了,我只要重新编译出使用 N32 或者 O32 ABI 的 qemu-i386 程序应该就能解决,为了性能考虑可以尽量使用 N32 ABI。
编译 N32 ABI QEMU
首先需要在 Loongnix MIPS64 系统下安装编译 QEMU 需要的 N32 版本的开发包,这里我只安装了 QEMU 用户模式需要的开发包:
zzm@loongnix:~$ yum install glibc-devel.mipsn32el glib2-devel.mipsn32el zlib-devel.mipsn32el libffi.mipsn32el pixman-devel.mipsn32el
提示
Loongnix 系统的 N64 相关库文件一般放在
/usr/lib64
目录下,N32 相关库文件在/usr/lib32
目录下,而 O32 相关库文件则在/usr/lib
目录下。
然后进入 QEMU 源代码目录重新 configure,增加特定编译参数指定生成 N32 位的程序:
zzm@loongnix:qemu$ PKG_CONFIG_LIBDIR=/usr/lib32/pkgconfig ./configure --target-list=i386-linux-user --disable-kvm --disable-xen --enable-pie --extra-cflags=-mabi=n32
简单说明一下:
PKG_CONFIG_LIBDIR
环境变量指定使用什么版本的 pkgconfig 查找库及开发包,这里使用/usr/lib32/pkgconfig
N32 版本;--target-list
指定 QEMU 编译目标,这里我们只需要 qemu-i386,因此把 KVM、Xen 等功能也禁用了;--extra-cflags
指定额外编译参数为-mabi=n32
,这样编译和链接时都是 N32 版本了。
重新编译安装之后可以看到新的 qemu-i386 使用的就是 N32 ABI 了:
zzm@loongnix:~$ file `which qemu-i386` /usr/local/bin/qemu-i386: ELF 32-bit LSB executable, MIPS, N32 MIPS64 rel2 version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=12e0025c42a9a63b8045c31159950f9b185f8745, stripped
最后测试使用新的 qemu-i386 运行依赖 ioctl 的 x86 二进制程序,现在就没有直接报错的问题了。
共有 0 条评论