Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1274319
  • 博文数量: 494
  • 博客积分: 161
  • 博客等级: 入伍新兵
  • 技术积分: 5084
  • 用 户 组: 普通用户
  • 注册时间: 2011-07-01 07:37
个人简介

只有偏执狂才能生存

文章分类

全部博文(494)

文章存档

2016年(10)

2015年(112)

2014年(69)

2013年(275)

2012年(28)

分类: LINUX

2014-07-13 22:10:30

原文地址:Understand Qemu 作者:letmego163

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:

  • Full system emulation. In this mode, QEMU emulates a full system (for example a PC), including one or several processors and various peripherals. It can be used to launch different Operating Systems without rebooting the PC or to debug system code.
  • User mode emulation. In this mode, QEMU can launch processes compiled for one CPU on another CPU. It can be used to launch the Wine Windows API emulator (http://www.winehq.org) or to ease cross-compilation and cross-debugging.
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

http://comments.gmane.org/gmane.comp.emulators.qemu/87571

http://permalink.gmane.org/gmane.comp.emulators.qemu/91039

6. Helper function
http://www.greensocs.com/Projects/QEMUSystemC/docs/QEMUSystemC/QEMUSystemCDataflow

7. Memory simulation in QEMU
http://www.slideshare.net/zchen/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
阅读(961) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~
评论热议
请登录后评论。

登录 注册