提升 QEMU 中 MIPS-Malta 机器的 RAM 容量上限

目前 QEMU 中 MIPS-Malta 机器的 RAM 容量被限制在了最高 256M,原因是其外围设备被映射在了物理地址空间的 0x10000000 – 0x20000000 之间。为了使用更多的 RAM,需要同时修改机器的“硬件”配置和内核中的地址空间映射表来使用高端内存。为此需要使用 MIPS-5Kf 处理器且需要使用64位的内核,因为要访问 0x20000000 之后的物理地址空间。

在 QEMU 中,当 RAM 配置 <= 256M 时,只使用低 256M物理地址空间来映射;当 RAM 配置 > 256M 时,将其余部分映射到 0x20000000 之后,配置为:

0x00000000 - 0x0fffffff => RAM
0x10000000 - 0x1fffffff => 设备
0x20000000 -            => RAM

在 内核 中,增加一个内存映射表项,来标记 0x20000000 – 0x? 为 BOOT_MEM_RAM。

QEMU 补丁 => https://github.com/heiher/hev-patches/blob/master/qemu/qemu-mips-malta.diff
Kernel 补丁 => https://github.com/heiher/hev-patches/blob/master/linux/mips-malta.diff
Kernel 配置 => http://heiher.info/sftp/files/config.malta

目前,最高可设置为 2047M 的 RAM。

Over!

udevd worker timeout

Error information

Waiting for UDev uevents to be processed    [BUSY]
udevd[155]: worker [173] timeout, kill it
udevd[155]: seq 1431 '/devices/pci0000:00/0000:00:1c.1/0000:12:00.0' killed
udevd[155]: worker [173] terminated by signal 9 (Killed)

PCI device

12:00.0 Network controller: Broadcom Corporation BCM4313 802.11b/g/n Wireless LAN Controller (rev 01)

How to fix?
Edit /etc/rc.conf

MODULES=(fuse brcmsmac)  # add brcmsmac

Over!

Python for MIPS 修正记录

最近发现 Python2 和 Python3 在 import 共享库形式的模块时经常出现 “invalid mode parameter” 错误,追踪后发现是由于 MIPS 平台中 RTLD_GLOBAL 等宏和 x86 平台中定义值是不同的,而 Python 源代码中是默认为 x86 平台生成的,所以在编译前需要重新生成。

重新生成方法
Python2

cd Lib/plat-linux2/
./regen

Python3

cd Lib/plat-linux2/
./regen
cd Lib/plat-linux3/
./regen

Over!

Linux 输入设备共享程序: RInput

是否在调试中因频繁切换 Target 和 Host 的输入设备而感觉头大?是否因为 Target 主机的键盘不适应还感到不爽?RInput
帮你解决这个问题,它可以通过定义的一个按键来将 Host 主机的输入设备在两个主机间切换。

How to Build
Linux:

git clone --recursive https://gitlab.com/hev/hev-rinput
cd hev-rinput
make

Android:

mkdir hev-rinput
cd hev-rinput
git clone --recursive https://gitlab.com/hev/hev-rinput jni
ndk-build

How to Use
Receiver:

cat conf/main.ini
[Main]
Port=6380
Address=0.0.0.0
 
sudo bin/hev-rinput conf/main.ini

Sender:

cat conf/main.ini
[Main]
Port=6380
Address=192.168.1.2
; See /usr/include/linux/input-event-codes.h
SwitchKeyCode=119
 
sudo bin/hev-rinput conf/main.ini

默认 Switch Key
Pause

Over!

Build fastboot for Loongson(MIPS)

Step 1: Clone source code from git repos

git clone https://android.googlesource.com/platform/system/core.git

Step 2: Write a standalone Makefile

vim core/fastboot/Makefile
# Makefile for fastboot
 
SRCS+=protocol.c
SRCS+=engine.c
SRCS+=bootimg.c
SRCS+=fastboot.c
SRCS+=usb_linux.c
SRCS+=util_linux.c
 
VPATH+= ../libzipfile
SRCS+= centraldir.c
SRCS+= zipfile.c
 
CPPFLAGS+= -DADB_HOST=1
CPPFLAGS+= -DHAVE_FORKEXEC=1
CPPFLAGS+= -DHAVE_SYMLINKS
CPPFLAGS+= -DHAVE_TERMIO_H
CPPFLAGS+= -D_GNU_SOURCE
CPPFLAGS+= -D_XOPEN_SOURCE
CPPFLAGS+= -I.
CPPFLAGS+= -I../include
CPPFLAGS+= -I../mkbootimg
CPPFLAGS+= -I../../../external/zlib
 
CFLAGS+= -O2 -Wno-unused-parameter
LDFLAGS= 
LIBS= -lrt -lpthread -lz
 
TOOLCHAIN= mipsel-unknown-linux-gnu-
CC= $(TOOLCHAIN)gcc
LD= $(TOOLCHAIN)gcc
 
OBJS= $(SRCS:.c=.o)
 
all: fastboot
 
fastboot: $(OBJS)
	$(LD) -o $@ $(LDFLAGS) $(OBJS) $(LIBS)
 
clean:
	rm -rf $(OBJS)

Step 3: Build

cd core/fastboot
make

Over!

在 MIPS 平台上运行时动态生成指令并执行 (2)

上次是直接在可执行的栈中写入指令并转移至执行的,这次在当栈和堆都不可执行的情况下,分配空间、写入指令并执行。还是直接看代码吧。

#include <stdio.h>
#include <errno.h>
#include <sys/mman.h>
 
int main(int argc, char *argv[])
{
	unsigned int *insn = NULL;
 
	insn = mmap(NULL, 4096, PROT_READ | PROT_WRITE | PROT_EXEC,
				MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
	if(MAP_FAILED != insn)
	{
		printf("%p\n", insn);
		insn[0] = 0x1000ffff;
		insn[1] = 0x00000000;
		__asm__ volatile (
					"jr %0 \n\t"
					"nop \n\t"
					::"r"(insn)
				);
		munmap(insn, 4096);
	}
	else
	{
		printf("%s\n", strerror(errno));
	}
 
	return 0;
}

在上面的代码中,使用系统调用 mmap 分配了一块 4096 字节的可读写、可执行的私有、匿名 VMA,并在此 VMA 中写入指令并转移至执行了。

我们来看一下此程序的运行时输出与 maps:

0x2ac88000
00400000-00404000 r-xp 00000000 08:04 262145                             /home/heiher/tmp/test
00410000-00414000 rw-p 00000000 08:04 262145                             /home/heiher/tmp/test
2ac64000-2ac88000 r-xp 00000000 08:02 917518                             /lib/ld-2.14.so
2ac88000-2ac8c000 rwxp 00000000 00:00 0 
2ac94000-2ac98000 rw-p 00020000 08:02 917518                             /lib/ld-2.14.so
2ac98000-2aca8000 rw-p 00000000 00:00 0 
2acb4000-2ae0c000 r-xp 00000000 08:02 918040                             /lib/libc-2.14.so
2ae0c000-2ae18000 ---p 00158000 08:02 918040                             /lib/libc-2.14.so
2ae18000-2ae1c000 r--p 00154000 08:02 918040                             /lib/libc-2.14.so
2ae1c000-2ae20000 rw-p 00158000 08:02 918040                             /lib/libc-2.14.so
2ae20000-2ae24000 rw-p 00000000 00:00 0 
7fc04000-7fc28000 rwxp 00000000 00:00 0                                  [stack]
7fff4000-7fff8000 r-xp 00000000 00:00 0                                  [vdso]

我们看到确定多出了一个我们所需要的 VMA:

2ac88000-2ac8c000 rwxp 00000000 00:00 0

但其长度却不是 4096 字节,而是 16K(16384)。这是因为我们当前的操作系统页面长度是 16K(16384),分配一个VMA至少需要一个完整的页面,当小于它的时候也需要分配一个完整的页面。

如何让进程的栈和堆都不可执行呢?有没有办法可以修改代码段的数据?在上面分配了 4096 字节的内存,而实际则是 16K,那么其 4096 之后的空间是否可以使用呢?动态生成指令随后立即执行是否有问题呢?

Over!

在 MIPS 平台上运行时动态生成指令并执行 (1)

昨天晚上回去后实在无聊睡不着,拿着身边的 Yeeloong 笔记本随便找点事干干,想到了 JIT 的原理,于是简单的验证了一下运行时动态生成指令并执行。

我先找了一下进程中哪个 VMA 是可以执行的,使用命令 cat /proc/self/maps 可以找到:

00400000-0040c000 r-xp 00000000 08:02 524311                             /bin/cat
00418000-0041c000 rw-p 00008000 08:02 524311                             /bin/cat
0041c000-00440000 rwxp 00000000 00:00 0                                  [heap]
2b9c8000-2b9ec000 r-xp 00000000 08:02 917518                             /lib/ld-2.14.so
2b9f8000-2b9fc000 rw-p 00020000 08:02 917518                             /lib/ld-2.14.so
2ba18000-2bb70000 r-xp 00000000 08:02 918040                             /lib/libc-2.14.so
2bb70000-2bb7c000 ---p 00158000 08:02 918040                             /lib/libc-2.14.so
2bb7c000-2bb80000 r--p 00154000 08:02 918040                             /lib/libc-2.14.so
2bb80000-2bb84000 rw-p 00158000 08:02 918040                             /lib/libc-2.14.so
2bb84000-2bb88000 rw-p 00000000 00:00 0 
2bb88000-2bd88000 r--p 00000000 08:02 786854                             /usr/lib/locale/locale-archive
7ff70000-7ff94000 rwxp 00000000 00:00 0                                  [stack]
7fff4000-7fff8000 r-xp 00000000 00:00 0                                  [vdso]

从上面的结果中可以看到 heap 和 stack 两个 VMA 的权限属性都是 rwxp,意味着我可以向里面存入指令并执行。

我选择了在栈中存入两条指令,然后转过去执行。代码如下:

#include <stdio.h>
 
int main(int argc, char *argv[])
{
	unsigned int insn[] =
	{
		0x1000ffff,
		0x00000000
	};
 
	__asm__ volatile (
				"jr %0 \n\t"
				"nop \n\t"
				::"r"(insn)
			);
 
	return 0;
}

编译程序后,执行这个程序就会进入栈里的死循环了。

你可能会想到这个操作系统的 heap 和 stack 具有可执行权限是不安全的,我确认了一下 x86 里没有可执行权限的,那么当没有可执行权限又应该怎么办呢?我们下次再说。

Over!

ArchLinux 龙芯版

ArchLinux 发行版
Arch Linux 是一个社区驱动型的 Linux 发行版,采用滚动升级模式,并提供了一个基本的已编译软件仓库,一个完美的软件包管理器,一个强大的打包工具还有一个强大的软件打包交流社区。系统极尽简洁、结构优雅、原汁原味的软件、快速跟进的升级。Arch Linux Version 0.1 (Homer) 在 2002 年 3 月 11 日发行。

架构信息

架构名称: mips32el
平台支持: 龙芯3A系列机器
编译参数: -march=mips64r2 -mtune=loongson3a -mabi=n32 -O3
基本系统: http://mirror.lemote.com/archls/system/
源服务器: http://mirror.lemote.com/archls/binaries/$repo/os/$arch
源码仓库: http://mirror.lemote.com/archls/sources/

ArchLinux 龙芯版是由社区用户移植的 ArchLinux 的龙芯(mips32el)架构版本,目前只发布 n32 ABI 版本。它和 ArchLinux i686 和 x86_64 版本一样发布源代码包和必要的预编译包。我们的目标是基于 ArchLinux 发行构建出通用的轻量级操作系统,能够应用于桌面和服务器环境,打造龙芯平台上最优秀的操作系统!

Over!