本文所用qemu为1.5版本的,不是android emulator的。
之前几篇文章介绍的都是android emulator中的设备模拟。一些是android自己加的platform bus上的虚拟设备;一些是qemu自己的虚拟设备,但是这部分代码很旧,没有使用到QOM模型。
qemu1.1以及之后的qemu开始有了QOM模型。QOM很大一部分代码是为了实现了C++的继承,公用的东西放到ObjectClass里,只有一个实例;其他的放Object里,可以有多个实例。
PS:android emulator的代码对应了qemu 0.1x的代码,但是又有一些新版本的qemu的代码porting上去了。
QOM设备模型可以看:
1、Qemu中的设备注册:http://ytliu.info/blog/2015/01/10/qemushe-bei-chu-shi-hua/
2、QEMU 设备模拟:http://mnstory.net/wp-content/uploads/2014/10/qemu-device-simulation/qemu-device-simulation.pdf
第二篇pdf讲的非常详细了,但是最后关于PMIO地址和读写函数如何对应起来的,还是有些没清楚的地方。
本文针对这个问题进行一些补充。
初始化内存空间
在memory_map_init(main->cpu_exec_init_all->memory_map_init)中,会设置MemoryRegion改变时的回调函数,memory_map_init是在设备注册之前调用的:
static void memory_map_init(void)
{
system_memory = g_malloc(sizeof(*system_memory));
memory_region_init(system_memory, "system", INT64_MAX);
address_space_init(&address_space_memory, system_memory);
address_space_memory.name = "memory";
system_io = g_malloc(sizeof(*system_io));
memory_region_init(system_io, "io", 65536);
address_space_init(&address_space_io, system_io);
address_space_io.name = "I/O";
memory_listener_register(&core_memory_listener, &address_space_memory);
memory_listener_register(&io_memory_listener, &address_space_io);
memory_listener_register(&tcg_memory_listener, &address_space_memory);
dma_context_init(&dma_context_memory, &address_space_memory,
NULL, NULL, NULL);
}
这个是PMIO的listener,PMIO的MemoryRegion改变后,会调用io_region_add函数,映射PMIO地址和设备读写函数。
普通内存是其他的listener。
static MemoryListener io_memory_listener = {
.region_add = io_region_add,
.region_del = io_region_del,
.priority = 0,
};
把注册的listener添加到全局的memory_listeners链表中:
void memory_listener_register(MemoryListener *listener, AddressSpace *filter)
{
MemoryListener *other = NULL;
AddressSpace *as;
listener->address_space_filter = filter; // listener是处理那个AddressSpace的
if (QTAILQ_EMPTY(&memory_listeners)
|| listener->priority >= QTAILQ_LAST(&memory_listeners,
memory_listeners)->priority) {
QTAILQ_INSERT_TAIL(&memory_listeners, listener, link);
} else {
QTAILQ_FOREACH(other, &memory_listeners, link) {
if (listener->priority < other->priority) {
break;
}
}
QTAILQ_INSERT_BEFORE(other, listener, link);
}
QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) {
listener_add_address_space(listener, as);
}
}
对AddressSpace(也就是根MemoryRegion)中的每一个MemoryRegion进行一下listener->region_add
static void listener_add_address_space(MemoryListener *listener,
AddressSpace *as)
{
FlatRange *fr;
if (listener->address_space_filter
&& listener->address_space_filter != as) {
return;
}
if (global_dirty_log) {
if (listener->log_global_start) {
listener->log_global_start(listener);
}
}
FOR_EACH_FLAT_RANGE(fr, as->current_map) {
MemoryRegionSection section = {
.mr = fr->mr,
.address_space = as,
.offset_within_region = fr->offset_in_region,
.size = int128_get64(fr->addr.size),
.offset_within_address_space = int128_get64(fr->addr.start),
.readonly = fr->readonly,
};
if (listener->region_add) {
listener->region_add(listener, secion);