Understand Qemu

1070阅读 0评论2014-09-10 embeddedlwp
分类:LINUX

1. The whole executing process of QEMU

main() //vl.c
    main_loop() //vl.c
        cpu_exec_all() //cpus.c
            qemu_cpu_exec(env) //cpus.c
                cpu_exec() //cpu-exee.c
                     tb = tb_find_fast(); // translate target code to host assemble  language and host machine code.
                      next_tb = tcg_qemu_tb_exec(tc_ptr); // execute the code     contained in translation block.



next_tb = 0; /* force lookup of first TB */
for(;;) {
    process interrupt request;

    tb_find_fast();

    tcg_qemu_tb_exec(tc_ptr);   
}

tb_find_fast() {
    get translation block from tb cache;
    if not found
        tb_find_slow();
}

tb_find_slow() {
    get translation block from hash table;
    if not found
        tb_gen_code();//translate it now
}

//generate host code
tb_gen_code() // return a translated block
    cpu_gen_code()
         gen_intermediate_code(env, tb);
            gen_intermediate_code_internal()
                        pc_ptr = disas_insn(dc, pc_ptr);
            gen_code_size = tcg_gen_code(s, gen_code_buf); //generate machine code
                tcg_gen_code_common(s, gen_code_buf, -1);



2. How do QEMU execute host instructions containing in translation block ?

2.1 There is a array defined in exec.c:

uint8_t code_gen_prologue[1024] code_gen_section;


2.2 in function tcg_prologue_init() in tcg.c

/* init global prologue and epilogue */
    s->code_buf = code_gen_prologue;
    s->code_ptr = s->code_buf;
    tcg_target_qemu_prologue(s);


then, {s->code_ptr) points to the address of code_gen_prologue[].

2.3 function: tcg_target_qemu_prologue(), call tcg_out_push(), which fills value to *(s->code_ptr).

/* Generate global QEMU prologue and epilogue code */
static void tcg_target_qemu_prologue(TCGContext *s)
{
    int i, frame_size, push_size, stack_addend;

    /* TB prologue */

    /* Save all callee saved registers. */
    for (i = 0; i < ARRAY_SIZE(tcg_target_callee_save_regs); i++) {
        tcg_out_push(s, tcg_target_callee_save_regs[i]);
    }

    /* Reserve some stack space. */
    push_size = 1 + ARRAY_SIZE(tcg_target_callee_save_regs);
    push_size *= TCG_TARGET_REG_BITS / 8;

    frame_size = push_size + TCG_STATIC_CALL_ARGS_SIZE;
    frame_size = (frame_size + TCG_TARGET_STACK_ALIGN - 1) &
        ~(TCG_TARGET_STACK_ALIGN - 1);
    stack_addend = frame_size - push_size;
    tcg_out_addi(s, TCG_REG_ESP, -stack_addend);

    /* jmp *tb. */
    tcg_out_modrm(s, OPC_GRP5, EXT5_JMPN_Ev, tcg_target_call_iarg_regs[0]);

    /* TB epilogue */
    tb_ret_addr = s->code_ptr;

    tcg_out_addi(s, TCG_REG_ESP, stack_addend);

    for (i = ARRAY_SIZE(tcg_target_callee_save_regs) - 1; i >= 0; i--) {
        tcg_out_pop(s, tcg_target_callee_save_regs[i]);
    }
    tcg_out_opc(s, OPC_RET, 0, 0, 0);
}


2.4 After getting a translation block by calling tb_find_fast(), call tcg_qemu_tb_exec(tc_ptr), which is a macro defined as following:

#define tcg_qemu_tb_exec(tb_ptr)   \

((long REGPARM (*)(void *))code_gen_prologue)(tb_ptr)


code_gen_prologue(tb_ptr) is casted to a function with one parameter, in such a way, execute host machine code stored in code_gen_prologue[].

3. Distinction between user mode and system mode emulation of QEMU?

QEMU has two operating modes:

4. One macro glue

#define xglue(x, y) x ## y
#define glue(x, y) xglue(x, y)


#define SUFFIX _mmx

void glue(helper_pcmpistrm, SUFFIX) (Reg *d, Reg *s, uint32_t ctrl)


First, this function is expanded to :(glue(x, y) -> xglue(x, y))

xglue(helper_pcmpistrm, _mmx) (Reg *d, Reg *s, uint32_t ctrl)


Second, (  xglue(x, y) > x ## y )

helper_pcmpistrm_mmx (Reg *d, Reg *s, uint32_t ctrl)


So,

void glue(helper_pcmpistrm, SUFFIX) (Reg *d, Reg *s, uint32_t ctrl)

==

helper_pcmpistrm_mmx (Reg *d, Reg *s, uint32_t ctrl)


5. How do the qemu translate virtual address to physical address when load a instruction ?

phys_pc = get_page_addr_code(env, pc);


/* NOTE: this function can trigger an exception */
/* NOTE2: the returned address is not exactly the physical address:    it is the offset relative to phys_ram_base */
static inline tb_page_addr_t get_page_addr_code(CPUState *env1, target_ulong addr)
{
    int mmu_idx, page_index, pd;
    void *p;

    page_index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
    mmu_idx = cpu_mmu_index(env1);
    if (unlikely(env1->tlb_table[mmu_idx][page_index].addr_code !=
                 (addr & TARGET_PAGE_MASK))) {
        ldub_code(addr);
    }
    pd = env1->tlb_table[mmu_idx][page_index].addr_code & ~TARGET_PAGE_MASK;
    if (pd > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) {
#if defined(TARGET_SPARC) || defined(TARGET_MIPS)
        do_unassigned_access(addr, 0, 1, 0, 4);
#else
        cpu_abort(env1, "Trying to execute code outside RAM or ROM at 0x" TARGET_FMT_lx "\n", addr);
#endif
    }
    p = (void *)(unsigned long)addr
        + env1->tlb_table[mmu_idx][page_index].addend;
    return qemu_ram_addr_from_host(p);
}


5. TCG .vs. Dyngen



6. Helper function


7. Memory simulation in QEMU


8. For system simulation.

b = ldub_code(s->pc);

will call this function(in softmmu_header.h):
glue is a marico, after replacing, it is :
     static inline RES_TYPE ld_{USUFFIX}_{MEMSUFFIX}(target_ulong ptr);

static inline RES_TYPE glue(glue(ld, USUFFIX), MEMSUFFIX)(target_ulong ptr)
{
    int page_index;
    RES_TYPE res;
    target_ulong addr;
    unsigned long physaddr;
    int mmu_idx;

    addr = ptr;
    page_index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
    mmu_idx = CPU_MMU_INDEX;
    if (unlikely(env->tlb_table[mmu_idx][page_index].ADDR_READ !=
                 (addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))))) {
        res = glue(glue(__ld, SUFFIX), MMUSUFFIX)(addr, mmu_idx);
    } else {
        physaddr = addr + env->tlb_table[mmu_idx][page_index].addend;
        res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)physaddr);
    }
    return res;
}


9. QEMU device model
http://blog.csdn.net/kanghua/archive/2007/09/26/1801424.aspx
上一篇:qemu aio简记
下一篇:深入分析 QEMU 的 cache 机制