All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Alex Bennée" <alex.bennee@linaro.org>
To: "Lluís Vilanova" <vilanova@ac.upc.edu>
Cc: qemu-devel@nongnu.org, Richard Henderson <rth@twiddle.net>,
	Peter Crosthwaite <crosthwaite.peter@gmail.com>,
	Paolo Bonzini <pbonzini@redhat.com>
Subject: Re: [Qemu-devel] [PATCH v9 04/26] target: [tcg] Add generic translation framework
Date: Mon, 26 Jun 2017 11:14:33 +0100	[thread overview]
Message-ID: <87fuenxdh2.fsf@linaro.org> (raw)
In-Reply-To: <149838119390.6497.17430428991952287717.stgit@frigg.lan>


Lluís Vilanova <vilanova@ac.upc.edu> writes:

> Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
> ---
>  Makefile.target                |    1
>  include/exec/gen-icount.h      |    2
>  include/exec/translate-block.h |  125 +++++++++++++++++++++++++++
>  include/qom/cpu.h              |   22 +++++
>  translate-block.c              |  185 ++++++++++++++++++++++++++++++++++++++++
>  5 files changed, 334 insertions(+), 1 deletion(-)
>  create mode 100644 include/exec/translate-block.h
>  create mode 100644 translate-block.c
>
> diff --git a/Makefile.target b/Makefile.target
> index ce8dfe44a8..253c6e7999 100644
> --- a/Makefile.target
> +++ b/Makefile.target
> @@ -90,6 +90,7 @@ all: $(PROGS) stap
>  # cpu emulator library
>  obj-y = exec.o translate-all.o cpu-exec.o
>  obj-y += translate-common.o
> +obj-y += translate-block.o

This clases with the changes now in master to move tcg functions into
accel/tcg/

>  obj-y += cpu-exec-common.o
>  obj-y += tcg/tcg.o tcg/tcg-op.o tcg/optimize.o
>  obj-$(CONFIG_TCG_INTERPRETER) += tci.o
> diff --git a/include/exec/gen-icount.h b/include/exec/gen-icount.h
> index 9b26c7da5f..f4ad61014b 100644
> --- a/include/exec/gen-icount.h
> +++ b/include/exec/gen-icount.h
> @@ -44,7 +44,7 @@ static inline void gen_tb_start(TranslationBlock *tb, TCGv_env cpu_env)
>      tcg_temp_free_i32(count);
>  }
>
> -static void gen_tb_end(TranslationBlock *tb, int num_insns)
> +static inline void gen_tb_end(TranslationBlock *tb, int num_insns)
>  {
>      if (tb->cflags & CF_USE_ICOUNT) {
>          /* Update the num_insn immediate parameter now that we know
> diff --git a/include/exec/translate-block.h b/include/exec/translate-block.h
> new file mode 100644
> index 0000000000..d14d23f2cb
> --- /dev/null
> +++ b/include/exec/translate-block.h
> @@ -0,0 +1,125 @@
> +/*
> + * 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__TRANSLATE_BLOCK_H
> +#define EXEC__TRANSLATE_BLOCK_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"
> +
> +
> +/**
> + * BreakpointCheckType:
> + * @BC_MISS: No hit
> + * @BC_HIT_INSN: Hit, but continue translating TB
> + * @BC_HIT_TB: Hit, stop translating TB
> + *
> + * How to react to a breakpoint. A hit means no more breakpoints will be checked
> + * for the current instruction.
> + *
> + * Not all breakpoints associated to an address are necessarily raised by
> + * targets (e.g., due to conditions encoded in their flags), so tey can decide
> + * that a breakpoint missed the address (@BP_MISS).
> + */
> +typedef enum BreakpointCheckType {
> +    BC_MISS,
> +    BC_HIT_INSN,
> +    BC_HIT_TB,
> +} BreakpointCheckType;
> +
> +/**
> + * DisasJumpType:
> + * @DJ_NEXT: Next instruction in program order.
> + * @DJ_TOO_MANY: Too many instructions translated.
> + * @DJ_TARGET: Start of target-specific conditions.
> + *
> + * What instruction to disassemble next.
> + */
> +typedef enum DisasJumpType {
> +    DJ_NEXT,
> +    DJ_TOO_MANY,
> +    DJ_TARGET,
> +} 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 a DisasContext struct (DisasContextBase has
> + *                      already been initialized).
> + * @init_globals: Initialize global variables.
> + * @tb_start: Start translating a new TB.
> + * @insn_start: Start translating a new instruction.
> + * @breakpoint_check: Check if a breakpoint did hit. When called, the breakpoint
> + *                    has already been checked to match the PC.
> + * @disas_insn: Disassemble one instruction an return the PC for the next
> + *              one. Can set db->is_jmp to DJ_TARGET or above to stop
> + *              translation.
> + * @tb_stop: Stop translating a TB.
> + * @disas_flags: Get flags argument for log_target_disas().
> + *
> + * Target-specific operations for the generic translator loop.
> + *
> + * All operations but disas_insn() are optional, and ignored when not set.
> + * A missing breakpoint_check() will ignore breakpoints. A missing disas_flags()
> + * will pass no flags.
> + */
> +typedef struct TranslatorOps {
> +    void (*init_disas_context)(DisasContextBase *db, CPUState *cpu);
> +    void (*init_globals)(DisasContextBase *db, CPUState *cpu);
> +    void (*tb_start)(DisasContextBase *db, CPUState *cpu);
> +    void (*insn_start)(DisasContextBase *db, CPUState *cpu);
> +    BreakpointCheckType (*breakpoint_check)(DisasContextBase *db, CPUState *cpu,
> +                                            const CPUBreakpoint *bp);
> +    target_ulong (*disas_insn)(DisasContextBase *db, CPUState *cpu);
> +    void (*tb_stop)(DisasContextBase *db, CPUState *cpu);
> +    int (*disas_flags)(const DisasContextBase *db);
> +} TranslatorOps;
> +
> +/**
> + * translate_block:
> + * @ops: Target-specific operations.
> + * @db:
> + * @cpu:
> + * @tb:
> + *
> + * Generic translator loop.
> + */
> +void translate_block(const TranslatorOps *ops, DisasContextBase *db,
> +                     CPUState *cpu, TCGv_env *tcg_cpu, TranslationBlock *tb);
> +
> +#endif  /* EXEC__TRANSLATE_BLOCK_H */
> diff --git a/include/qom/cpu.h b/include/qom/cpu.h
> index 89ddb686fb..d46e8df756 100644
> --- a/include/qom/cpu.h
> +++ b/include/qom/cpu.h
> @@ -982,6 +982,28 @@ static inline bool cpu_breakpoint_test(CPUState *cpu, vaddr pc, int mask)
>      return false;
>  }
>
> +/* Get first breakpoint matching a PC */
> +static inline CPUBreakpoint *cpu_breakpoint_get(CPUState *cpu, vaddr pc,
> +                                                CPUBreakpoint *bp)
> +{
> +    if (likely(bp == NULL)) {
> +        if (unlikely(!QTAILQ_EMPTY(&cpu->breakpoints))) {
> +            QTAILQ_FOREACH(bp, &cpu->breakpoints, entry) {
> +                if (bp->pc == pc) {
> +                    return bp;
> +                }
> +            }
> +        }
> +    } else {
> +        QTAILQ_FOREACH_CONTINUE(bp, entry) {
> +            if (bp->pc == pc) {
> +                return bp;
> +            }
> +        }
> +    }
> +    return NULL;
> +}
> +
>  int cpu_watchpoint_insert(CPUState *cpu, vaddr addr, vaddr len,
>                            int flags, CPUWatchpoint **watchpoint);
>  int cpu_watchpoint_remove(CPUState *cpu, vaddr addr,
> diff --git a/translate-block.c b/translate-block.c
> new file mode 100644
> index 0000000000..1aac80560e
> --- /dev/null
> +++ b/translate-block.c
> @@ -0,0 +1,185 @@
> +/*
> + * 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/translate-block.h"
> +
> +
> +static inline void translate_block_tcg_check(const DisasContextBase *db)
> +{
> +    if (tcg_check_temp_count()) {
> +        error_report("warning: TCG temporary leaks before "TARGET_FMT_lx,
> +                     db->pc_next);
> +    }
> +}
> +
> +void translate_block(const TranslatorOps *ops, DisasContextBase *db,
> +                     CPUState *cpu, TCGv_env *tcg_cpu, TranslationBlock *tb)
> +{
> +    int max_insns;
> +
> +    /* Sanity-check ops */
> +    if (ops->disas_insn == NULL) {
> +        error_report("Missing ops->disas_insn");
> +        abort();
> +    }
> +
> +    /* Initialize DisasContext */
> +    db->tb = tb;
> +    db->pc_first = tb->pc;
> +    db->pc_next = db->pc_first;
> +    db->is_jmp = DJ_NEXT;
> +    db->num_insns = 0;
> +    db->singlestep_enabled = cpu->singlestep_enabled;
> +    if (ops->init_disas_context) {
> +        ops->init_disas_context(db, cpu);
> +    }
> +
> +    /* Initialize globals */
> +    if (ops->init_globals) {
> +        ops->init_globals(db, cpu);
> +    }
> +    tcg_clear_temp_count();
> +
> +    /* 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;
> +    }
> +
> +    /* Start translating */
> +    gen_tb_start(db->tb, *tcg_cpu);
> +    if (ops->tb_start) {
> +        ops->tb_start(db, cpu);
> +    }
> +
> +    while (true) {
> +        CPUBreakpoint *bp;
> +
> +        db->num_insns++;
> +        if (ops->insn_start) {
> +            ops->insn_start(db, cpu);
> +        }
> +
> +        /* Early exit before breakpoint checks */
> +        if (unlikely(db->is_jmp != DJ_NEXT)) {
> +            break;
> +        }
> +
> +        /* Pass breakpoint hits to target for further processing */
> +        bp = NULL;
> +        do {
> +            bp = cpu_breakpoint_get(cpu, db->pc_next, bp);
> +            if (unlikely(bp) && ops->breakpoint_check) {
> +                BreakpointCheckType bp_check = ops->breakpoint_check(
> +                    db, cpu, bp);
> +                if (bp_check == BC_HIT_INSN) {
> +                    /* Hit, keep translating */
> +                    /*
> +                     * TODO: if we're never going to have more than one BP in a
> +                     *       single address, we can simply use a bool here.
> +                     */
> +                    break;
> +                } else if (bp_check == BC_HIT_TB) {
> +                    goto done_generating;
> +                } else {
> +                    error_report("Unexpected BreakpointCheckType %d", bp_check);
> +                    abort();
> +                }
> +            }
> +        } while (bp != NULL);
> +
> +        /* Accept I/O on last instruction */
> +        if (db->num_insns == max_insns && (db->tb->cflags & CF_LAST_IO)) {
> +            gen_io_start(*tcg_cpu);
> +        }
> +
> +        /* Disassemble one instruction */
> +        db->pc_next = ops->disas_insn(db, cpu);
> +
> +        /**************************************************/
> +        /* Conditions to stop translation                 */
> +        /**************************************************/
> +
> +        /* Target-specific conditions set by disassembly */
> +        if (db->is_jmp != DJ_NEXT) {
> +            break;
> +        }
> +
> +        /* Too many instructions */
> +        if (tcg_op_buf_full() || db->num_insns >= max_insns) {
> +            db->is_jmp = DJ_TOO_MANY;
> +            break;
> +        }
> +
> +        /*
> +         * Check if next instruction is on next page, which can cause an
> +         * exception.
> +         *
> +         * NOTE: Target-specific code must check a single instruction does not
> +         *       cross page boundaries; the first in the TB is always allowed to
> +         *       cross pages (never goes through this check).
> +         */
> +        if ((db->pc_first & TARGET_PAGE_MASK)
> +            != (db->pc_next & TARGET_PAGE_MASK)) {
> +            db->is_jmp = DJ_TOO_MANY;
> +            break;
> +        }

How does the first insn avoid this check? And if it does is that right?

I mean I understand you can construct weird multi-byte instructions
(especially on x86) that cross the boundary but even if it is the first
in a TB shouldn't it error if there are no contiguous pages?

Also isn't the page crossing issue different for SoftMMU and linux-user?

> +
> +        translate_block_tcg_check(db);
> +    }
> +
> +    if (ops->tb_stop) {
> +        ops->tb_stop(db, cpu);
> +    }
> +
> +    if (db->tb->cflags & CF_LAST_IO) {
> +        gen_io_end(*tcg_cpu);
> +    }
> +
> +done_generating:
> +    gen_tb_end(db->tb, db->num_insns);
> +
> +    translate_block_tcg_check(db);
> +
> +#ifdef DEBUG_DISAS
> +    if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM) &&
> +        qemu_log_in_addr_range(db->pc_first)) {
> +        int flags;
> +        if (ops->disas_flags) {
> +            flags = ops->disas_flags(db);
> +        } else {
> +            flags = 0;
> +        }
> +        qemu_log_lock();
> +        qemu_log("----------------\n");
> +        qemu_log("IN: %s\n", lookup_symbol(db->pc_first));
> +        log_target_disas(cpu, db->pc_first, db->pc_next - db->pc_first, flags);
> +        qemu_log("\n");
> +        qemu_log_unlock();
> +    }
> +#endif
> +
> +    db->tb->size = db->pc_next - db->pc_first;
> +    db->tb->icount = db->num_insns;
> +}


--
Alex Bennée

  reply	other threads:[~2017-06-26 10:13 UTC|newest]

Thread overview: 72+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-06-25  8:43 [Qemu-devel] [RFC PATCH v9 00/26] translate: [tcg] Generic translation framework Lluís Vilanova
2017-06-25  8:47 ` [PATCH v9 01/26] Pass generic CPUState to gen_intermediate_code() Lluís Vilanova
2017-06-25  8:47   ` [Qemu-devel] " Lluís Vilanova
2017-06-26 10:04   ` [Qemu-devel] [PATCH] fixup! " Alex Bennée
2017-06-26 12:37     ` Lluís Vilanova
2017-06-26 17:50   ` [Qemu-devel] [PATCH v9 01/26] " Emilio G. Cota
2017-06-25  8:51 ` [Qemu-devel] [PATCH v9 02/26] queue: Add macro for incremental traversal Lluís Vilanova
2017-06-25  8:55 ` [PATCH v9 03/26] cpu-exec: Avoid global variables in icount-related functions Lluís Vilanova
2017-06-25  8:55   ` [Qemu-devel] " Lluís Vilanova
2017-06-26 17:53   ` Emilio G. Cota
2017-06-25  8:59 ` [Qemu-devel] [PATCH v9 04/26] target: [tcg] Add generic translation framework Lluís Vilanova
2017-06-26 10:14   ` Alex Bennée [this message]
2017-06-26 12:50     ` Lluís Vilanova
2017-06-26 18:21       ` Peter Maydell
2017-06-27  3:22         ` Richard Henderson
2017-06-27  9:23           ` Peter Maydell
2017-06-27  2:47     ` Richard Henderson
2017-06-26 17:57   ` Emilio G. Cota
2017-06-26 18:12   ` Emilio G. Cota
2017-06-27 11:32     ` Lluís Vilanova
2017-06-27  2:39   ` Richard Henderson
2017-06-27 15:41     ` Lluís Vilanova
2017-06-25  9:03 ` [PATCH v9 05/26] target: [tcg] Redefine DISAS_* onto the generic translation framework (DJ_*) Lluís Vilanova
2017-06-25  9:03   ` [Qemu-devel] " Lluís Vilanova
2017-06-26 11:28   ` [Qemu-devel] [PATCH] maybe fixup! " Alex Bennée
2017-06-26 18:05   ` [Qemu-devel] [PATCH v9 05/26] " Emilio G. Cota
2017-06-25  9:07 ` [Qemu-devel] [PATCH v9 06/26] target: [tcg, i386] Port to DisasContextBase Lluís Vilanova
2017-06-26 18:14   ` Emilio G. Cota
2017-06-28 11:23     ` Lluís Vilanova
2017-06-29 21:50       ` Emilio G. Cota
2017-06-25  9:12 ` [Qemu-devel] [PATCH v9 07/26] target: [tcg, i386] Refactor init_disas_context Lluís Vilanova
2017-06-27  2:57   ` Richard Henderson
2017-06-27  6:07     ` Lluís Vilanova
2017-06-25  9:16 ` [Qemu-devel] [PATCH v9 08/26] target: [tcg, i386] Refactor init_globals Lluís Vilanova
2017-06-25  9:20 ` [Qemu-devel] [PATCH v9 09/26] target: [tcg, i386] Refactor insn_start Lluís Vilanova
2017-06-25  9:24 ` [Qemu-devel] [PATCH v9 10/26] target: [tcg, i386] Refactor breakpoint_check Lluís Vilanova
2017-06-25  9:28 ` [Qemu-devel] [PATCH v9 11/26] target: [tcg, i386] Refactor disas_insn Lluís Vilanova
2017-06-25  9:32 ` [Qemu-devel] [PATCH v9 12/26] target: [tcg,i386] Refactor tb_stop Lluís Vilanova
2017-06-25  9:36 ` [Qemu-devel] [PATCH v9 13/26] target: [tcg, i386] Refactor disas_flags Lluís Vilanova
2017-06-25  9:40 ` [Qemu-devel] [PATCH v9 14/26] target: [tcg, i386] Replace DISAS_* with DJ_* Lluís Vilanova
2017-06-25  9:48 ` [PATCH v9 16/26] target: [tcg,arm] " Lluís Vilanova
2017-06-25  9:48   ` [Qemu-devel] [PATCH v9 16/26] target: [tcg, arm] " Lluís Vilanova
2017-06-26 18:08   ` Emilio G. Cota
2017-06-25  9:52 ` [PATCH v9 17/26] target: [tcg,arm] Port to DisasContextBase Lluís Vilanova
2017-06-25  9:52   ` [Qemu-devel] [PATCH v9 17/26] target: [tcg, arm] " Lluís Vilanova
2017-06-25  9:56 ` [PATCH v9 18/26] target: [tcg,arm] Port to init_disas_context Lluís Vilanova
2017-06-25  9:56   ` [Qemu-devel] [PATCH v9 18/26] target: [tcg, arm] " Lluís Vilanova
2017-06-25 10:00 ` [PATCH v9 19/26] target: [tcg,arm] Port to init_globals Lluís Vilanova
2017-06-25 10:00   ` [Qemu-devel] [PATCH v9 19/26] target: [tcg, arm] " Lluís Vilanova
2017-06-25 10:04 ` [PATCH v9 20/26] target: [tcg,arm] Port to tb_start Lluís Vilanova
2017-06-25 10:04   ` [Qemu-devel] " Lluís Vilanova
2017-06-25 10:08 ` [PATCH v9 21/26] target: [tcg,arm] Port to insn_start Lluís Vilanova
2017-06-25 10:08   ` [Qemu-devel] [PATCH v9 21/26] target: [tcg, arm] " Lluís Vilanova
2017-06-26 11:31   ` [PATCH v9 21/26] target: [tcg,arm] " Alex Bennée
2017-06-26 11:31     ` [Qemu-devel] [PATCH v9 21/26] target: [tcg, arm] " Alex Bennée
2017-06-27  3:33   ` Richard Henderson
2017-06-28 11:48     ` Lluís Vilanova
2017-06-25 10:12 ` [PATCH v9 22/26] target: [tcg,arm] Port to breakpoint_check Lluís Vilanova
2017-06-25 10:12   ` [Qemu-devel] [PATCH v9 22/26] target: [tcg, arm] " Lluís Vilanova
2017-06-25 10:16 ` [PATCH v9 23/26] target: [tcg,arm] Port to disas_insn Lluís Vilanova
2017-06-25 10:16   ` [Qemu-devel] [PATCH v9 23/26] target: [tcg, arm] " Lluís Vilanova
2017-06-25 10:20 ` [PATCH v9 24/26] target: [tcg,arm] Port to tb_stop Lluís Vilanova
2017-06-25 10:20   ` [Qemu-devel] " Lluís Vilanova
2017-06-25 10:24 ` [PATCH v9 25/26] target: [tcg,arm] Port to disas_flags Lluís Vilanova
2017-06-25 10:24   ` [Qemu-devel] [PATCH v9 25/26] target: [tcg, arm] " Lluís Vilanova
2017-06-25 10:28 ` [PATCH v9 26/26] target: [tcg, arm] Port to generic translation framework Lluís Vilanova
2017-06-25 10:28   ` [Qemu-devel] " Lluís Vilanova
2017-06-27  3:47   ` Richard Henderson
2017-06-26 11:34 ` [Qemu-devel] [RFC PATCH v9 00/26] translate: [tcg] Generic " Alex Bennée
2017-06-26 13:02   ` Lluís Vilanova
2017-06-27  3:00 ` Eric Blake
2017-06-27 12:23   ` Lluís Vilanova

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87fuenxdh2.fsf@linaro.org \
    --to=alex.bennee@linaro.org \
    --cc=crosthwaite.peter@gmail.com \
    --cc=pbonzini@redhat.com \
    --cc=qemu-devel@nongnu.org \
    --cc=rth@twiddle.net \
    --cc=vilanova@ac.upc.edu \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.