Understand Qemu TCG

 

  1. The whole executing process of QEMU

    main() //vl.c

    main_loop() //vl.c

     

    x86_cpu_realizefn() //实例化虚拟机CPU设备模型

    qemu_init_vcpu() //KVM没有enable,并且启用了TCG的情况下,tcg_enabled()

    qemu_tcg_init_vcpu()//启动VCPU线程,线程处理函数为qemu_tcg_cpu_thread_fn

    qemu_tcg_cpu_thread_fn()

    tcg_exec_all()

    tcg_cpu_exec()

    cpu_exec() //cpu-exee.c

    tb = tb_find_fast(); // translate target code to host assemble  language and host machine code.

    next_tb = cpu_tb_exec()

    next_tb = tcg_qemu_tb_exec(tc_ptr); // execute the code contained in translation block.

     

    cpu_exec() 中运行如下:

    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;(老版本)

 

struct TCGContext {

//……

uint8_t *code_ptr;

/* Code generation */

uint8_t *code_gen_prologue;

};


2.2 in function tcg_prologue_init() in tcg.c

/* init global prologue and epilogue */
s->code_buf = s->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(env, tb_ptr) \
((uintptr_t (*)(void *, void *))tcg_ctx.code_gen_prologue)(env, tb_ptr)


code_gen_prologue(tb_ptr) is casted to a function with two 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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值