接前一篇文章: QEMU源码全解析 —— 内存虚拟化(21)
本文内容参考:
《 QEMU /KVM源码解析与应用》 —— 李强,机械工业出版社
浅谈QEMU Memory Region 与 Address Space
QEMU内存分析(一):内存虚拟化关键结构体 - Edver - 博客园
特此致谢!
2. QEMU虚拟机内存初始化
上一回在讲解address_space_init函数时,讲解了一部分,还剩余QTAILQ相关的宏(函数)没有讲,本回解析这一部分。为了便于理解和回顾,再次贴出address_space_init函数代码,在softmmu/memory.c中,如下:
void address_space_init(AddressSpace *as, MemoryRegion *root, const char *name)
{
memory_region_ref(root);
as->root = root;
as->current_map = NULL;
as->ioeventfd_nb = 0;
as->ioeventfds = NULL;
QTAILQ_INIT(&as->listeners);
QTAILQ_INSERT_TAIL(&address_spaces, as, address_spaces_link);
as->name = g_strdup(name ? name : "anonymous");
address_space_update_topology(as);
address_space_update_ioeventfds(as);
}
QTAILQ_INIT是一个宏,在include/qemu/queue.h中定义,如下:
/*
* Tail queue functions.
*/
#define QTAILQ_INIT(head) do { \
(head)->tqh_first = NULL; \
(head)->tqh_circ.tql_prev = &(head)->tqh_circ; \
} while (/*CONSTCOND*/0)
此处head对应的实参为&as->listeners,那么实际上就是:
do { \
(&as->listeners)->tqh_first = NULL; \
(&as->listeners)->tqh_circ.tql_prev = &(&as->listeners)->tqh_circ; \
} while (/*CONSTCOND*/0)
QTAILQ_INSERT_TAIL也是一个宏,也在include/qemu/queue.h中定义,如下:
#define QTAILQ_INSERT_TAIL(head, elm, field) do { \
(elm)->field.tqe_next = NULL; \
(elm)->field.tqe_circ.tql_prev = (head)->tqh_circ.tql_prev; \
(head)->tqh_circ.tql_prev->tql_next = (elm); \
(head)->tqh_circ.tql_prev = &(elm)->field.tqe_circ; \
} while (/*CONSTCOND*/0)
address_space_init函数中是:
QTAILQ_INSERT_TAIL(&address_spaces, as, address_spaces_link);
因此,展开来是:
do { \
(as)->address_spaces_link.tqe_next = NULL; \
(as)->address_spaces_link.tqe_circ.tql_prev = (&address_spaces)->tqh_circ.tql_prev; \
(&address_spaces)->tqh_circ.tql_prev->tql_next = (as); \
(&address_spaces)->tqh_circ.tql_prev = &(as)->address_spaces_link.tqe_circ; \
} while (/*CONSTCOND*/0)
这其中的as指向的是address_space_memory,
address_spaces的定义在softmmu/memory.c中,如下:
static QTAILQ_HEAD(, AddressSpace) address_spaces
= QTAILQ_HEAD_INITIALIZER(address_spaces);
结合struct AddressSpace的定义来看:
接下来就该是address_space_init函数中的两个重要函数了:
address_space_update_topology(as);
address_space_update_ioeventfds(as);
下一回开始对于address_space_update_topology函数的解析。