Chinaunix首页 | 论坛 | 博客
  • 博客访问: 3125496
  • 博文数量: 685
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 5303
  • 用 户 组: 普通用户
  • 注册时间: 2014-04-19 14:17
个人简介

文章分类

全部博文(685)

文章存档

2015年(116)

2014年(569)

分类: LINUX

2014-12-12 15:13:14

原文地址:http://blog.chinaunix.net/uid-25739055-id-4464365.html
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 (= 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 (= 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 () 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



6. Helper function


7. Memory simulation in QEMU


8. For system simulation.

= 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

阅读(771) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~