qemu是一个支持跨平台的虚拟机,其使用分两种方式,分别是system mode和user mode。在qemu的system mode的配置下可以
模拟出来整个计算机。从源码的路径看user mode 根据架构的不同有分为bsd-user和linux-user,这里以linux-user为例看看
user mode具体作用是啥?
linux-user mode的的源码在linux-user中,从源码中可以看到linux-user mode支持的要模拟的架构,例如aarch64/alpha 等
[root@localhost linux-user]# ls -al
total 1100
drwxr-xr-x. 25 root root   4096 Jun 11 02:42 .
drwxr-xr-x. 57 root root   4096 Jun 11 03:02 ..
-rw-r--r--.  1 root root    791 Jun 11 02:42 Makefile.objs
drwxr-xr-x.  2 root root    229 Jun 11 02:42 aarch64
drwxr-xr-x.  2 root root    270 Jun 11 02:42 alpha
drwxr-xr-x.  3 root root   4096 Jun 11 02:42 arm
-rw-r--r--.  1 root root   1573 Jun 11 02:42 cpu_loop-common.h
drwxr-xr-x.  2 root root    229 Jun 11 02:42 cris
-rw-r--r--.  1 root root 116436 Jun 11 02:42 elfload.c
-rw-r--r--.  1 root root  10124 Jun 11 02:42 errno_defs.h
-rw-r--r--.  1 root root   1118 Jun 11 02:42 exit.c
-rw-r--r--.  1 root root  44353 Jun 11 02:42 fd-trans.c
-rw-r--r--.  1 root root   3084 Jun 11 02:42 fd-trans.h
-rw-r--r--.  1 root root   2607 Jun 11 02:42 flat.h
-rw-r--r--.  1 root root  26124 Jun 11 02:42 flatload.c
drwxr-xr-x.  2 root root     55 Jun 11 02:42 generic
drwxr-xr-x. 17 root root    200 Jun 11 02:42 host
drwxr-xr-x.  2 root root    270 Jun 11 02:42 hppa
drwxr-xr-x.  2 root root    273 Jun 11 02:42 i386
-rw-r--r--.  1 root root  27359 Jun 11 02:42 ioctls.h
-rw-r--r--.  1 root root   2696 Jun 11 02:42 linux_loop.h
-rw-r--r--.  1 root root   4099 Jun 11 02:42 linuxload.c
drwxr-xr-x.  2 root root    270 Jun 11 02:42 m68k
-rw-r--r--.  1 root root  24711 Jun 11 02:42 main.c
drwxr-xr-x.  2 root root    270 Jun 11 02:42 microblaze

[root@localhost linux-user]#

linux-user 最终会编译成qemu-user 和 qemu-user-static 两个binary,
从makefile中可以看到入口函数在main.c中
obj-y = main.o syscall.o strace.o mmap.o signal.o \
        elfload.o linuxload.o uaccess.o uname.o \
        safe-syscall.o $(TARGET_ABI_DIR)/signal.o \
        $(TARGET_ABI_DIR)/cpu_loop.o exit.o fd-trans.o

其入口函数在main
int main(int argc, char **argv, char **envp)
{
   
    #tcg的初始化,可见user mode 也是用tcg 来翻译代码的。
    /* init tcg before creating CPUs and to get qemu_host_page_size */
    tcg_exec_init(0);

    cpu = cpu_create(cpu_type);
    env = cpu->env_ptr;
    cpu_reset(cpu);
    thread_cpu = cpu;

    
    /*
     * Prepare copy of argv vector for target.
     */
    target_argc = argc - optind;
    target_argv = calloc(target_argc + 1, sizeof (char *));
    if (target_argv == NULL) {
        (void) fprintf(stderr, "Unable to allocate memory for target_argv\n");
        exit(EXIT_FAILURE);
    }

    /*
     * If argv0 is specified (using '-0' switch) we replace
     * argv[0] pointer with the given one.
     */
    i = 0;
    if (argv0 != NULL) {
        target_argv[i++] = strdup(argv0);
    }
    for (; i < target_argc; i++) {
        target_argv[i] = strdup(argv[optind + i]);
    }
    target_argv[target_argc] = NULL;

    ts = g_new0(TaskState, 1);
    init_task_state(ts);
    /* build Task State */
    ts->info = info;
    ts->bprm = &bprm;
    cpu->opaque = ts;
    task_settid(ts);
#加载要执行的程序,即要执行的guest code

    ret = loader_exec(execfd, exec_path, target_argv, target_environ, regs,
        info, &bprm);
    if (ret != 0) {
        printf("Error while loading %s: %s\n", exec_path, strerror(-ret));
        _exit(EXIT_FAILURE);
    }

    for (wrk = target_environ; *wrk; wrk++) {
        g_free(*wrk);
    }

    g_free(target_environ);

  

    target_set_brk(info->brk);
    syscall_init();
    signal_init();

    /* Now that we've loaded the binary, GUEST_BASE is fixed.  Delay
       generating the prologue until now so that the prologue can take
       the real value of GUEST_BASE into account.  */
    tcg_prologue_init(tcg_ctx);
    tcg_region_init();

    target_cpu_copy_regs(env, regs);

    if (gdbstub) {
        if (gdbserver_start(gdbstub) < 0) {
            fprintf(stderr, "qemu: could not open gdbserver on %s\n",
                    gdbstub);
            exit(EXIT_FAILURE);
        }
        gdb_handlesig(cpu, 0);
    }
开始执行guest code 翻译成host code执行,其中首先通过translate-all.c中的gen_intermediate_code讲guest code
翻译成TCG Operation,然后通过调用tcg/tfg.c 中的tcg_gen_code将TCG Operation 转成host code,执行.
    cpu_loop(env);
    /* never exits */
    return 0;
}

 

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐