Full analysis of QEMU source code 9 - define a QEMU module (1)

Continued from the previous article: Full Analysis of QEMU Source Code 8 —— Initialize all Modules

References for the content of this article:

"Interesting Talk about Linux Operating System " —— Liu Chao, Geek Time

" QEMU /KVM" source code analysis and application - Li Qiang, Machinery Industry Press

Thank you very much!

Defining a QEMU module calls type_init. Taking kvm as an example, the kvm module is implemented in accel/kvm/kvm-all.c. In this file, there is the following 1 line of code:

type_init(kvm_type_init);

type_init is a macro definition, in include/qemu/module.h, the code is as follows:

#define type_init(function) module_init(function, MODULE_INIT_QOM)

Therefore, type_init(kvm_type_init) expands to:

module_init(kvm_type_init, MODULE_INIT_QOM)

The definition of module_init is in include/qemu/module.h, the code is as follows:

#ifdef BUILD_DSO
void DSO_STAMP_FUN(void);
/* This is a dummy symbol to identify a loaded DSO as a QEMU module, so we can
 * distinguish "version mismatch" from "not a QEMU module", when the stamp
 * check fails during module loading */
void qemu_module_dummy(void);

#define module_init(function, type)                                         \
static void __attribute__((constructor)) do_qemu_init_ ## function(void)    \
{                                                                           \
    register_dso_module_init(function, type);                               \
}
#else
/* This should not be used directly.  Use block_init etc. instead.  */
#define module_init(function, type)                                         \
static void __attribute__((constructor)) do_qemu_init_ ## function(void)    \
{                                                                           \
    register_module_init(function, type);                                   \
}
#endif

Since BUILD_DSO is not defined in the system, it actually takes the #else branch, that is, the following code:

/* This should not be used directly.  Use block_init etc. instead.  */
#define module_init(function, type)                                         \
static void __attribute__((constructor)) do_qemu_init_ ## function(void)    \
{                                                                           \
    register_module_init(function, type);                                   \
}

Substitute into module_init(kvm_type_init, MODULE_INIT_QOM), as:

static void __attribute__((constructor)) do_qemu_init_kvm_type_init(void)
{
    register_module_init(kvm_type_init, MODULE_INIT_QOM);
}

And register_module_init is in util/module.c, the code is as follows:

void register_module_init(void (*fn)(void), module_init_type type)
{
    ModuleEntry *e;
    ModuleTypeList *l;

    e = g_malloc0(sizeof(*e));
    e->init = fn;
    e->type = type;

    l = find_type(type);

    QTAILQ_INSERT_TAIL(l, e, node);
}

See also the find_type function, which was analyzed last time. Here, for the sake of understanding, paste the code again, in the same file (actually above register_module_init):

static ModuleTypeList *find_type(module_init_type type)
{
    init_lists();

    return &init_type_list[type];
}

QTAIL_INSERT_TAIL is of course defined in include/qemu/queue.h, the code is as follows:

#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)

Thus, for register_module_init(kvm_type_init, MODULE_INIT_QOM), the register_module_init function actually looks like this:

void register_module_init(void (*fn)(void), module_init_type type)
{
    ModuleEntry *e;
    ModuleTypeList *l;

    e = g_malloc0(sizeof(*e));
    e->init = fn; //实际上是:e->init = kvm_type_init;
    e->type = type; //实际上是:e->type = MODULE_INIT_QOM;

    l = find_type(type); //实际上是:l = find_type(MODULE_INIT_QOM);

    QTAILQ_INSERT_TAIL(l, e, node);
}

For type_init(kvm_type_init), finally call register_module_init(kvm_type_init, MODULE_INIT_QOM), which is the type of MODULE_INIT_QOM. Belonging to the type of MODULE_INIT_QOM, there is a Module list ModuleTypeList (analyzed last time), and there are ModuleEntry items one by one in the list. KVM is one of them, and of course there are many other items, such as Machine, CPU and so on. The init function that will initialize each item is the function fn represented by the parameter. For the KVM module, its init function is kvm_type_init; for the Machine module, its init function is machine_register_types. Finally, in the module_call_init function analyzed last time, the initialization fn assigned here is actually called to perform the actual initialization work.

Next time we will take a look at the initialization function kvm_type_init of KVM.

Guess you like

Origin blog.csdn.net/phmatthaus/article/details/131923111