QEMU源码全解析 —— 内存虚拟化(22)

接前一篇文章: QEMU源码全解析 —— 内存虚拟化(21)

本文内容参考:

《趣谈 Linux操作系统 》 —— 刘超, 极客时间

QEMU /KVM源码解析与应用》 —— 李强,机械工业出版社

QEMU内存管理模型

浅谈QEMU Memory Region 与 Address Space

【QEMU系统分析之实例篇(七)】-CSDN博客

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函数的解析。