分类: LINUX
2010-09-08 09:44:08
In qemu, there are two different meanings of target. The first meaning of ‘target’ means the emulated target machine architecture. For example, when emulating mips machine on x86, the target is mips and host is x86. However, in tcg(tiny code generator), target has a different meaning. It means the generated binary architecture. In the example of emulating mips on x86, in tcg the target means x86 because tcg will generate x86 binary.
This article is based on qemu version 0.10.5 and target machine emulated is little endian mips. I will summarize the code path of mips lw instruction emulation in qemu.
Function decode_opc is used for decoding all the fetched instructions before tcg generating the target binary.
target-mips/translate.c
7566 static void decode_opc (CPUState *env, DisasContext *ctx)
7960 case OPC_LB ... OPC_LWR: /* Load and stores */
7961 case OPC_SB ... OPC_SW:
7962 case OPC_SWR:
7963 case OPC_LL:
7964 case OPC_SC:
7965 gen_ldst(ctx, op, rt, rs, imm);
7966 break;
It will call function gen_ldst which is also in target-mips/translate.c.
target-mips/translate.c
973 static void gen_ldst (DisasContext *ctx, uint32_t opc, int rt,
974 int base, int16_t offset)1046 case OPC_LW:
1047 op_ldst_lw(t0, ctx);
1048 gen_store_gpr(t0, rt);
1049 opn = "lw";
1050 break;
Function op_ldst_lw will generate the target binary which fetches the value from the emulated guest memory and gen_store_gpr will store this value to the emulated cpu’s general register rt.
Function op_ldst_lw is generated by the macro OP_LD.
target-mips/translate.c
901 #define OP_LD(insn,fname) \
902 static inline void op_ldst_##insn(TCGv t0, DisasContext *ctx) \
903 { \
904 tcg_gen_qemu_##fname(t0, t0, ctx->mem_idx); \
905 }910 OP_LD(lw,ld32s);
We can find that op_ldst_lw is a function which calls function tcg_gen_qemu_ld32s. It will output the OPC(INDEX_op_qemu_ld32u) and args to gen_opc_ptr.
tcg/tcg-op.h
1793 static inline void tcg_gen_qemu_ld32s(TCGv ret, TCGv addr, int mem_index)
1794 {
1795 #if TARGET_LONG_BITS == 32
1796 tcg_gen_op3i_i32(INDEX_op_qemu_ld32u, ret, addr, mem_index);
1797 #else
1798 tcg_gen_op4i_i32(INDEX_op_qemu_ld32u, TCGV_LOW(ret), TCGV_LOW(addr),
1799 TCGV_HIGH(addr), mem_index);
1800 tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31);
1801 #endif
1802 }99 static inline void tcg_gen_op3i_i32(int opc, TCGv_i32 arg1, TCGv_i32 arg2,
100 TCGArg arg3)
101 {
102 *gen_opc_ptr++ = opc;
103 *gen_opparam_ptr++ = GET_TCGV_I32(arg1);
104 *gen_opparam_ptr++ = GET_TCGV_I32(arg2);
105 *gen_opparam_ptr++ = arg3;
106 }
The path of generation of target binary code of tcg is as following.
cpu_gen_code->tcg_gen_code->tcg_gen_code_common->tcg_reg_alloc_op->tcg_out_op
tcg/i386/tcg-target.c
856 static inline void tcg_out_op(TCGContext *s, int opc,
857 const TCGArg *args, const int *const_args)1041 case INDEX_op_qemu_ld32u:
1042 tcg_out_qemu_ld(s, args, 2);
1043 break;431 static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
432 int opc)508 #if TARGET_LONG_BITS == 32
509 tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_EDX, mem_index);
510 #else
511 tcg_out_mov(s, TCG_REG_EDX, addr_reg2);
512 tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_ECX, mem_index);
513 #endif
514 tcg_out8(s, 0xe8);
515 tcg_out32(s, (tcg_target_long)qemu_ld_helpers[s_bits] -
516 (tcg_target_long)s->code_ptr - 4);
In line 514, tcg outputs 0xe8 which means a call instruction in x86. It will call the functions in array qemu_ld_helpers. The args to the functions is passed by registers EAX,EDX and ECX.
tcg/i386/tcg-target.c
413 static void *qemu_ld_helpers[4] = {
414 __ldb_mmu,
415 __ldw_mmu,
416 __ldl_mmu,
417 __ldq_mmu,
418 };
These functions __ldb_mmu/__ldw_mmu are defined in softmmu_template.h.
softmmu_tempate.h
DATA_TYPE REGPARM glue(glue(__ld, SUFFIX), MMUSUFFIX)(target_ulong addr,
int mmu_idx)
In sum, function gen_ldst outputs the OPC(INDEX_op_qemu_ld32u) to gen_opc_ptr and tcg_out_op will generates the target binary according to the OPC. In the lw instruction emulation, it will generate the x86 binary calls the functions in softmmu_template.h.