Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge remote-tracking branch 'remotes/rth/tags/pull-tgt-20170906' int…
…o staging tcg generic translate loop v15 # gpg: Signature made Wed 06 Sep 2017 17:02:31 BST # gpg: using RSA key 0x64DF38E8AF7E215F # gpg: Good signature from "Richard Henderson <richard.henderson@linaro.org>" # gpg: WARNING: This key is not certified with sufficiently trusted signatures! # gpg: It is not certain that the signature belongs to the owner. # Primary key fingerprint: 7A48 1E78 868B 4DB6 A85A 05C0 64DF 38E8 AF7E 215F * remotes/rth/tags/pull-tgt-20170906: (32 commits) target/arm: Perform per-insn cross-page check only for Thumb target/arm: Split out thumb_tr_translate_insn target/arm: Move ss check to init_disas_context target/arm: [a64] Move page and ss checks to init_disas_context target/arm: [tcg] Port to generic translation framework target/arm: [tcg,a64] Port to disas_log target/arm: [tcg] Port to disas_log target/arm: [tcg,a64] Port to tb_stop target/arm: [tcg] Port to tb_stop target/arm: [tcg,a64] Port to translate_insn target/arm: [tcg] Port to translate_insn target/arm: [tcg,a64] Port to breakpoint_check target/arm: [tcg,a64] Port to insn_start target/arm: [tcg] Port to insn_start target/arm: [tcg] Port to tb_start target/arm: [tcg,a64] Port to init_disas_context target/arm: [tcg] Port to init_disas_context target/arm: [tcg] Port to DisasContextBase target/i386: [tcg] Port to generic translation framework target/i386: [tcg] Port to disas_log ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
- Loading branch information
Showing
17 changed files
with
909 additions
and
570 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
obj-$(CONFIG_SOFTMMU) += tcg-all.o | ||
obj-$(CONFIG_SOFTMMU) += cputlb.o | ||
obj-y += cpu-exec.o cpu-exec-common.o translate-all.o | ||
obj-y += translator.o |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
/* | ||
* Generic intermediate code generation. | ||
* | ||
* Copyright (C) 2016-2017 Lluís Vilanova <vilanova@ac.upc.edu> | ||
* | ||
* This work is licensed under the terms of the GNU GPL, version 2 or later. | ||
* See the COPYING file in the top-level directory. | ||
*/ | ||
|
||
#include "qemu/osdep.h" | ||
#include "qemu-common.h" | ||
#include "qemu/error-report.h" | ||
#include "cpu.h" | ||
#include "tcg/tcg.h" | ||
#include "tcg/tcg-op.h" | ||
#include "exec/exec-all.h" | ||
#include "exec/gen-icount.h" | ||
#include "exec/log.h" | ||
#include "exec/translator.h" | ||
|
||
/* Pairs with tcg_clear_temp_count. | ||
To be called by #TranslatorOps.{translate_insn,tb_stop} if | ||
(1) the target is sufficiently clean to support reporting, | ||
(2) as and when all temporaries are known to be consumed. | ||
For most targets, (2) is at the end of translate_insn. */ | ||
void translator_loop_temp_check(DisasContextBase *db) | ||
{ | ||
if (tcg_check_temp_count()) { | ||
qemu_log("warning: TCG temporary leaks before " | ||
TARGET_FMT_lx "\n", db->pc_next); | ||
} | ||
} | ||
|
||
void translator_loop(const TranslatorOps *ops, DisasContextBase *db, | ||
CPUState *cpu, TranslationBlock *tb) | ||
{ | ||
int max_insns; | ||
|
||
/* Initialize DisasContext */ | ||
db->tb = tb; | ||
db->pc_first = tb->pc; | ||
db->pc_next = db->pc_first; | ||
db->is_jmp = DISAS_NEXT; | ||
db->num_insns = 0; | ||
db->singlestep_enabled = cpu->singlestep_enabled; | ||
|
||
/* Instruction counting */ | ||
max_insns = db->tb->cflags & CF_COUNT_MASK; | ||
if (max_insns == 0) { | ||
max_insns = CF_COUNT_MASK; | ||
} | ||
if (max_insns > TCG_MAX_INSNS) { | ||
max_insns = TCG_MAX_INSNS; | ||
} | ||
if (db->singlestep_enabled || singlestep) { | ||
max_insns = 1; | ||
} | ||
|
||
max_insns = ops->init_disas_context(db, cpu, max_insns); | ||
tcg_debug_assert(db->is_jmp == DISAS_NEXT); /* no early exit */ | ||
|
||
/* Reset the temp count so that we can identify leaks */ | ||
tcg_clear_temp_count(); | ||
|
||
/* Start translating. */ | ||
gen_tb_start(db->tb); | ||
ops->tb_start(db, cpu); | ||
tcg_debug_assert(db->is_jmp == DISAS_NEXT); /* no early exit */ | ||
|
||
while (true) { | ||
db->num_insns++; | ||
ops->insn_start(db, cpu); | ||
tcg_debug_assert(db->is_jmp == DISAS_NEXT); /* no early exit */ | ||
|
||
/* Pass breakpoint hits to target for further processing */ | ||
if (unlikely(!QTAILQ_EMPTY(&cpu->breakpoints))) { | ||
CPUBreakpoint *bp; | ||
QTAILQ_FOREACH(bp, &cpu->breakpoints, entry) { | ||
if (bp->pc == db->pc_next) { | ||
if (ops->breakpoint_check(db, cpu, bp)) { | ||
break; | ||
} | ||
} | ||
} | ||
/* The breakpoint_check hook may use DISAS_TOO_MANY to indicate | ||
that only one more instruction is to be executed. Otherwise | ||
it should use DISAS_NORETURN when generating an exception, | ||
but may use a DISAS_TARGET_* value for Something Else. */ | ||
if (db->is_jmp > DISAS_TOO_MANY) { | ||
break; | ||
} | ||
} | ||
|
||
/* Disassemble one instruction. The translate_insn hook should | ||
update db->pc_next and db->is_jmp to indicate what should be | ||
done next -- either exiting this loop or locate the start of | ||
the next instruction. */ | ||
if (db->num_insns == max_insns && (db->tb->cflags & CF_LAST_IO)) { | ||
/* Accept I/O on the last instruction. */ | ||
gen_io_start(); | ||
ops->translate_insn(db, cpu); | ||
gen_io_end(); | ||
} else { | ||
ops->translate_insn(db, cpu); | ||
} | ||
|
||
/* Stop translation if translate_insn so indicated. */ | ||
if (db->is_jmp != DISAS_NEXT) { | ||
break; | ||
} | ||
|
||
/* Stop translation if the output buffer is full, | ||
or we have executed all of the allowed instructions. */ | ||
if (tcg_op_buf_full() || db->num_insns >= max_insns) { | ||
db->is_jmp = DISAS_TOO_MANY; | ||
break; | ||
} | ||
} | ||
|
||
/* Emit code to exit the TB, as indicated by db->is_jmp. */ | ||
ops->tb_stop(db, cpu); | ||
gen_tb_end(db->tb, db->num_insns); | ||
|
||
/* The disas_log hook may use these values rather than recompute. */ | ||
db->tb->size = db->pc_next - db->pc_first; | ||
db->tb->icount = db->num_insns; | ||
|
||
#ifdef DEBUG_DISAS | ||
if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM) | ||
&& qemu_log_in_addr_range(db->pc_first)) { | ||
qemu_log_lock(); | ||
qemu_log("----------------\n"); | ||
ops->disas_log(db, cpu); | ||
qemu_log("\n"); | ||
qemu_log_unlock(); | ||
} | ||
#endif | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
/* | ||
* Generic intermediate code generation. | ||
* | ||
* Copyright (C) 2016-2017 Lluís Vilanova <vilanova@ac.upc.edu> | ||
* | ||
* This work is licensed under the terms of the GNU GPL, version 2 or later. | ||
* See the COPYING file in the top-level directory. | ||
*/ | ||
|
||
#ifndef EXEC__TRANSLATOR_H | ||
#define EXEC__TRANSLATOR_H | ||
|
||
/* | ||
* Include this header from a target-specific file, and add a | ||
* | ||
* DisasContextBase base; | ||
* | ||
* member in your target-specific DisasContext. | ||
*/ | ||
|
||
|
||
#include "exec/exec-all.h" | ||
#include "tcg/tcg.h" | ||
|
||
|
||
/** | ||
* DisasJumpType: | ||
* @DISAS_NEXT: Next instruction in program order. | ||
* @DISAS_TOO_MANY: Too many instructions translated. | ||
* @DISAS_NORETURN: Following code is dead. | ||
* @DISAS_TARGET_*: Start of target-specific conditions. | ||
* | ||
* What instruction to disassemble next. | ||
*/ | ||
typedef enum DisasJumpType { | ||
DISAS_NEXT, | ||
DISAS_TOO_MANY, | ||
DISAS_NORETURN, | ||
DISAS_TARGET_0, | ||
DISAS_TARGET_1, | ||
DISAS_TARGET_2, | ||
DISAS_TARGET_3, | ||
DISAS_TARGET_4, | ||
DISAS_TARGET_5, | ||
DISAS_TARGET_6, | ||
DISAS_TARGET_7, | ||
DISAS_TARGET_8, | ||
DISAS_TARGET_9, | ||
DISAS_TARGET_10, | ||
DISAS_TARGET_11, | ||
} DisasJumpType; | ||
|
||
/** | ||
* DisasContextBase: | ||
* @tb: Translation block for this disassembly. | ||
* @pc_first: Address of first guest instruction in this TB. | ||
* @pc_next: Address of next guest instruction in this TB (current during | ||
* disassembly). | ||
* @is_jmp: What instruction to disassemble next. | ||
* @num_insns: Number of translated instructions (including current). | ||
* @singlestep_enabled: "Hardware" single stepping enabled. | ||
* | ||
* Architecture-agnostic disassembly context. | ||
*/ | ||
typedef struct DisasContextBase { | ||
TranslationBlock *tb; | ||
target_ulong pc_first; | ||
target_ulong pc_next; | ||
DisasJumpType is_jmp; | ||
unsigned int num_insns; | ||
bool singlestep_enabled; | ||
} DisasContextBase; | ||
|
||
/** | ||
* TranslatorOps: | ||
* @init_disas_context: | ||
* Initialize the target-specific portions of DisasContext struct. | ||
* The generic DisasContextBase has already been initialized. | ||
* Return max_insns, modified as necessary by db->tb->flags. | ||
* | ||
* @tb_start: | ||
* Emit any code required before the start of the main loop, | ||
* after the generic gen_tb_start(). | ||
* | ||
* @insn_start: | ||
* Emit the tcg_gen_insn_start opcode. | ||
* | ||
* @breakpoint_check: | ||
* When called, the breakpoint has already been checked to match the PC, | ||
* but the target may decide the breakpoint missed the address | ||
* (e.g., due to conditions encoded in their flags). Return true to | ||
* indicate that the breakpoint did hit, in which case no more breakpoints | ||
* are checked. If the breakpoint did hit, emit any code required to | ||
* signal the exception, and set db->is_jmp as necessary to terminate | ||
* the main loop. | ||
* | ||
* @translate_insn: | ||
* Disassemble one instruction and set db->pc_next for the start | ||
* of the following instruction. Set db->is_jmp as necessary to | ||
* terminate the main loop. | ||
* | ||
* @tb_stop: | ||
* Emit any opcodes required to exit the TB, based on db->is_jmp. | ||
* | ||
* @disas_log: | ||
* Print instruction disassembly to log. | ||
*/ | ||
typedef struct TranslatorOps { | ||
int (*init_disas_context)(DisasContextBase *db, CPUState *cpu, | ||
int max_insns); | ||
void (*tb_start)(DisasContextBase *db, CPUState *cpu); | ||
void (*insn_start)(DisasContextBase *db, CPUState *cpu); | ||
bool (*breakpoint_check)(DisasContextBase *db, CPUState *cpu, | ||
const CPUBreakpoint *bp); | ||
void (*translate_insn)(DisasContextBase *db, CPUState *cpu); | ||
void (*tb_stop)(DisasContextBase *db, CPUState *cpu); | ||
void (*disas_log)(const DisasContextBase *db, CPUState *cpu); | ||
} TranslatorOps; | ||
|
||
/** | ||
* translator_loop: | ||
* @ops: Target-specific operations. | ||
* @db: Disassembly context. | ||
* @cpu: Target vCPU. | ||
* @tb: Translation block. | ||
* | ||
* Generic translator loop. | ||
* | ||
* Translation will stop in the following cases (in order): | ||
* - When is_jmp set by #TranslatorOps::breakpoint_check. | ||
* - set to DISAS_TOO_MANY exits after translating one more insn | ||
* - set to any other value than DISAS_NEXT exits immediately. | ||
* - When is_jmp set by #TranslatorOps::translate_insn. | ||
* - set to any value other than DISAS_NEXT exits immediately. | ||
* - When the TCG operation buffer is full. | ||
* - When single-stepping is enabled (system-wide or on the current vCPU). | ||
* - When too many instructions have been translated. | ||
*/ | ||
void translator_loop(const TranslatorOps *ops, DisasContextBase *db, | ||
CPUState *cpu, TranslationBlock *tb); | ||
|
||
void translator_loop_temp_check(DisasContextBase *db); | ||
|
||
#endif /* EXEC__TRANSLATOR_H */ |
Oops, something went wrong.