diff mbox

[01/11] S/390 CPU fake emulation

Message ID 1259241800-2810-2-git-send-email-agraf@suse.de
State New
Headers show

Commit Message

Alexander Graf Nov. 26, 2009, 1:23 p.m. UTC
Because Qemu currently requires a TCG target to exist and there are quite some
useful helpers here to lay the groundwork for out KVM target, let's create a
stub TCG emulation target for S390X CPUs.

This is required to make tcg happy. The emulation target itself won't work
though.

Signed-off-by: Alexander Graf <agraf@suse.de>
---
 cpu-exec.c               |    2 +
 target-s390x/cpu.h       |  119 ++++++++++++++++++++++++++++++++++++++++++++++
 target-s390x/exec.h      |   51 ++++++++++++++++++++
 target-s390x/helper.c    |   57 ++++++++++++++++++++++
 target-s390x/op_helper.c |   74 ++++++++++++++++++++++++++++
 target-s390x/translate.c |   57 ++++++++++++++++++++++
 6 files changed, 360 insertions(+), 0 deletions(-)
 create mode 100644 target-s390x/cpu.h
 create mode 100644 target-s390x/exec.h
 create mode 100644 target-s390x/helper.c
 create mode 100644 target-s390x/op_helper.c
 create mode 100644 target-s390x/translate.c

Comments

Aurelien Jarno Nov. 30, 2009, 6:18 p.m. UTC | #1
On Thu, Nov 26, 2009 at 02:23:10PM +0100, Alexander Graf wrote:
> Because Qemu currently requires a TCG target to exist and there are quite some
> useful helpers here to lay the groundwork for out KVM target, let's create a
> stub TCG emulation target for S390X CPUs.
> 
> This is required to make tcg happy. The emulation target itself won't work
> though.

Please find the comments below.

> Signed-off-by: Alexander Graf <agraf@suse.de>
> ---
>  cpu-exec.c               |    2 +
>  target-s390x/cpu.h       |  119 ++++++++++++++++++++++++++++++++++++++++++++++
>  target-s390x/exec.h      |   51 ++++++++++++++++++++
>  target-s390x/helper.c    |   57 ++++++++++++++++++++++
>  target-s390x/op_helper.c |   74 ++++++++++++++++++++++++++++
>  target-s390x/translate.c |   57 ++++++++++++++++++++++
>  6 files changed, 360 insertions(+), 0 deletions(-)
>  create mode 100644 target-s390x/cpu.h
>  create mode 100644 target-s390x/exec.h
>  create mode 100644 target-s390x/helper.c
>  create mode 100644 target-s390x/op_helper.c
>  create mode 100644 target-s390x/translate.c
> 
> diff --git a/cpu-exec.c b/cpu-exec.c
> index 2c0765c..af4595b 100644
> --- a/cpu-exec.c
> +++ b/cpu-exec.c
> @@ -249,6 +249,7 @@ int cpu_exec(CPUState *env1)
>  #elif defined(TARGET_MIPS)
>  #elif defined(TARGET_SH4)
>  #elif defined(TARGET_CRIS)
> +#elif defined(TARGET_S390X)
>      /* XXXXX */
>  #else
>  #error unsupported target CPU
> @@ -673,6 +674,7 @@ int cpu_exec(CPUState *env1)
>  #elif defined(TARGET_SH4)
>  #elif defined(TARGET_ALPHA)
>  #elif defined(TARGET_CRIS)
> +#elif defined(TARGET_S390X)
>      /* XXXXX */
>  #else
>  #error unsupported target CPU
> diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h
> new file mode 100644
> index 0000000..f45b00c
> --- /dev/null
> +++ b/target-s390x/cpu.h
> @@ -0,0 +1,119 @@
> +/*
> + * S/390 virtual CPU header
> + *
> + *  Copyright (c) 2009 Ulrich Hecht
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA  02110-1301 USA
> + */
> +#ifndef CPU_S390X_H
> +#define CPU_S390X_H
> +
> +#define TARGET_LONG_BITS 64
> +
> +#define ELF_MACHINE	EM_S390
> +
> +#define CPUState struct CPUS390XState
> +
> +#include "cpu-defs.h"
> +
> +#include "softfloat.h"
> +
> +#define NB_MMU_MODES 2 // guess
> +#define MMU_USER_IDX 0 // guess
> +
> +typedef union FPReg {
> +    struct {
> +#ifdef WORDS_BIGENDIAN
> +        float32 e;
> +        int32_t __pad;
> +#else
> +        int32_t __pad;
> +        float32 e;
> +#endif
> +    };
> +    float64 d;
> +    uint64_t i;
> +} FPReg;
> +
> +typedef struct CPUS390XState {
> +    uint64_t regs[16];	/* GP registers */
> +    
> +    uint32_t aregs[16];	/* access registers */
> +    
> +    uint32_t fpc;	/* floating-point control register */
> +    FPReg fregs[16]; /* FP registers */
> +    float_status fpu_status; /* passed to softfloat lib */
> +    
> +    struct {
> +        uint64_t mask;
> +        uint64_t addr;
> +    } psw;
> +    
> +    int cc; /* condition code (0-3) */
> +    
> +    uint64_t __excp_addr;
> +    
> +    CPU_COMMON
> +} CPUS390XState;
> +
> +#if defined(CONFIG_USER_ONLY)
> +static inline void cpu_clone_regs(CPUState *env, target_ulong newsp)
> +{
> +    if (newsp)
> +        env->regs[15] = newsp;

Coding style.

> +    env->regs[0] = 0;
> +}
> +#endif
> +
> +CPUS390XState *cpu_s390x_init(const char *cpu_model);
> +int cpu_s390x_exec(CPUS390XState *s);
> +void cpu_s390x_close(CPUS390XState *s);
> +
> +/* you can call this signal handler from your SIGBUS and SIGSEGV
> +   signal handlers to inform the virtual CPU of exceptions. non zero
> +   is returned if the signal was handled by the virtual CPU.  */
> +int cpu_s390x_signal_handler(int host_signum, void *pinfo,
> +                           void *puc);
> +int cpu_s390x_handle_mmu_fault (CPUS390XState *env, target_ulong address, int rw,
> +                              int mmu_idx, int is_softmuu);
> +#define cpu_handle_mmu_fault cpu_s390x_handle_mmu_fault
> +
> +#define TARGET_PAGE_BITS 12
> +
> +#define cpu_init cpu_s390x_init
> +#define cpu_exec cpu_s390x_exec
> +#define cpu_gen_code cpu_s390x_gen_code
> +
> +#include "cpu-all.h"
> +#include "exec-all.h"
> +
> +#define EXCP_OPEX 1 /* operation exception (sigill) */
> +#define EXCP_SVC 2 /* supervisor call (syscall) */
> +#define EXCP_ADDR 5 /* addressing exception */
> +#define EXCP_EXECUTE_SVC 0xff00000 /* supervisor call via execute insn */
> +
> +static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock* tb)
> +{
> +    env->psw.addr = tb->pc;
> +}
> +
> +static inline void cpu_get_tb_cpu_state(CPUState* env, target_ulong *pc,
> +                                        target_ulong *cs_base, int *flags)
> +{
> +    *pc = env->psw.addr;
> +    *cs_base = 0;
> +    *flags = env->psw.mask; // guess

I don't know what psw.mask represent, but it may be wrong. It should be
a way to identify which TB can be reused, that is they have been
generated in the same CPU mode.

> +}
> +#endif
> diff --git a/target-s390x/exec.h b/target-s390x/exec.h
> new file mode 100644
> index 0000000..5198359
> --- /dev/null
> +++ b/target-s390x/exec.h
> @@ -0,0 +1,51 @@
> +/*
> + *  S/390 execution defines
> + *
> + *  Copyright (c) 2009 Ulrich Hecht
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA  02110-1301 USA
> + */
> +
> +#include "dyngen-exec.h"
> +
> +register struct CPUS390XState *env asm(AREG0);
> +
> +#include "cpu.h"
> +#include "exec-all.h"
> +
> +static inline int cpu_has_work(CPUState *env)
> +{
> +    return env->interrupt_request & CPU_INTERRUPT_HARD; // guess
> +}
> +
> +static inline void regs_to_env(void)
> +{
> +}
> +
> +static inline void env_to_regs(void)
> +{
> +}
> +
> +static inline int cpu_halted(CPUState *env)
> +{
> +    if (!env->halted) {
> +       return 0;
> +    }
> +    if (cpu_has_work(env)) {
> +        env->halted = 0;
> +        return 0;
> +    }
> +    return EXCP_HALTED;
> +}
> diff --git a/target-s390x/helper.c b/target-s390x/helper.c
> new file mode 100644
> index 0000000..4e23b4a
> --- /dev/null
> +++ b/target-s390x/helper.c
> @@ -0,0 +1,57 @@
> +/*
> + *  S/390 helpers
> + *
> + *  Copyright (c) 2009 Ulrich Hecht
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA  02110-1301 USA
> + */
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +
> +#include "cpu.h"
> +#include "exec-all.h"
> +#include "gdbstub.h"
> +#include "qemu-common.h"
> +
> +CPUS390XState *cpu_s390x_init(const char *cpu_model)
> +{
> +    CPUS390XState *env;
> +    static int inited = 0;
> +    
> +    env = qemu_mallocz(sizeof(CPUS390XState));
> +    cpu_exec_init(env);
> +    if (!inited) {
> +        inited = 1;
> +    }
> +    
> +    env->cpu_model_str = cpu_model;
> +    cpu_reset(env);
> +    qemu_init_vcpu(env);
> +    return env;
> +}
> +
> +void cpu_reset(CPUS390XState *env)
> +{
> +    if (qemu_loglevel_mask(CPU_LOG_RESET)) {
> +        qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
> +        log_cpu_state(env, 0);
> +    }
> +    
> +    memset(env, 0, offsetof(CPUS390XState, breakpoints));
> +    /* FIXME: reset vector? */

Isn't it also needed by kvm to make reset working?

> +    tlb_flush(env, 1);
> +}
> diff --git a/target-s390x/op_helper.c b/target-s390x/op_helper.c
> new file mode 100644
> index 0000000..e623de9
> --- /dev/null
> +++ b/target-s390x/op_helper.c
> @@ -0,0 +1,74 @@
> +/*
> + *  S/390 helper routines
> + *
> + *  Copyright (c) 2009 Alexander Graf
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA  02110-1301 USA
> + */
> +
> +#include "exec.h"
> +
> +/*****************************************************************************/
> +/* Softmmu support */
> +#if !defined (CONFIG_USER_ONLY)
> +
> +#define MMUSUFFIX _mmu
> +
> +#define SHIFT 0
> +#include "softmmu_template.h"
> +
> +#define SHIFT 1
> +#include "softmmu_template.h"
> +
> +#define SHIFT 2
> +#include "softmmu_template.h"
> +
> +#define SHIFT 3
> +#include "softmmu_template.h"
> +
> +/* try to fill the TLB and return an exception if error. If retaddr is
> +   NULL, it means that the function was called in C code (i.e. not
> +   from generated code or from helper.c) */
> +/* XXX: fix it to restore all registers */
> +void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
> +{
> +    TranslationBlock *tb;
> +    CPUState *saved_env;
> +    unsigned long pc;
> +    int ret;
> +
> +    /* XXX: hack to restore env in all cases, even if not called from
> +       generated code */
> +    saved_env = env;
> +    env = cpu_single_env;
> +    ret = cpu_s390x_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
> +    if (unlikely(ret != 0)) {
> +        if (likely(retaddr)) {
> +            /* now we have a real cpu fault */
> +            pc = (unsigned long)retaddr;
> +            tb = tb_find_pc(pc);
> +            if (likely(tb)) {
> +                /* the PC is inside the translated code. It means that we have
> +                   a virtual CPU fault */
> +                cpu_restore_state(tb, env, pc, NULL);
> +            }
> +        }
> +        /* XXX */
> +        /* helper_raise_exception_err(env->exception_index, env->error_code); */
> +    }
> +    env = saved_env;
> +}
> +
> +#endif
> diff --git a/target-s390x/translate.c b/target-s390x/translate.c
> new file mode 100644
> index 0000000..f304411
> --- /dev/null
> +++ b/target-s390x/translate.c
> @@ -0,0 +1,57 @@
> +/*
> + *  S/390 translation
> + *
> + *  Copyright (c) 2009 Ulrich Hecht
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA  02110-1301 USA
> + */
> +
> +#include "cpu.h"
> +#include "exec-all.h"
> +#include "disas.h"
> +#include "tcg-op.h"
> +#include "qemu-log.h"
> +
> +void cpu_dump_state(CPUState *env, FILE *f,
> +                    int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
> +                    int flags)
> +{
> +    int i;
> +    for (i = 0; i < 16; i++) {
> +        cpu_fprintf(f, "R%02d=%016lx", i, env->regs[i]);
> +        if ((i % 4) == 3) cpu_fprintf(f, "\n");
> +        else cpu_fprintf(f, " ");
> +    }
> +    for (i = 0; i < 16; i++) {
> +        cpu_fprintf(f, "F%02d=%016lx", i, env->fregs[i]);
> +        if ((i % 4) == 3) cpu_fprintf(f, "\n");
> +        else cpu_fprintf(f, " ");
> +    }
> +    cpu_fprintf(f, "PSW=mask %016lx addr %016lx cc %02x\n", env->psw.mask, env->psw.addr, env->cc);
> +}
> +
> +void gen_intermediate_code (CPUState *env, struct TranslationBlock *tb)
> +{
> +}
> +
> +void gen_intermediate_code_pc (CPUState *env, struct TranslationBlock *tb)
> +{
> +}
> +
> +void gen_pc_load(CPUState *env, TranslationBlock *tb,
> +                unsigned long searched_pc, int pc_pos, void *puc)
> +{
> +    env->psw.addr = gen_opc_pc[pc_pos];
> +}
> -- 
> 1.6.0.2
> 
> 
> 
>
Alexander Graf Nov. 30, 2009, 10:30 p.m. UTC | #2
On 30.11.2009, at 19:18, Aurelien Jarno wrote:

> On Thu, Nov 26, 2009 at 02:23:10PM +0100, Alexander Graf wrote:
>> Because Qemu currently requires a TCG target to exist and there are quite some
>> useful helpers here to lay the groundwork for out KVM target, let's create a
>> stub TCG emulation target for S390X CPUs.
>> 
>> This is required to make tcg happy. The emulation target itself won't work
>> though.
> 
> Please find the comments below.
> 
>> Signed-off-by: Alexander Graf <agraf@suse.de>
>> ---
>> cpu-exec.c               |    2 +
>> target-s390x/cpu.h       |  119 ++++++++++++++++++++++++++++++++++++++++++++++
>> target-s390x/exec.h      |   51 ++++++++++++++++++++
>> target-s390x/helper.c    |   57 ++++++++++++++++++++++
>> target-s390x/op_helper.c |   74 ++++++++++++++++++++++++++++
>> target-s390x/translate.c |   57 ++++++++++++++++++++++
>> 6 files changed, 360 insertions(+), 0 deletions(-)
>> create mode 100644 target-s390x/cpu.h
>> create mode 100644 target-s390x/exec.h
>> create mode 100644 target-s390x/helper.c
>> create mode 100644 target-s390x/op_helper.c
>> create mode 100644 target-s390x/translate.c
>> 
>> diff --git a/cpu-exec.c b/cpu-exec.c
>> index 2c0765c..af4595b 100644
>> --- a/cpu-exec.c
>> +++ b/cpu-exec.c
>> @@ -249,6 +249,7 @@ int cpu_exec(CPUState *env1)
>> #elif defined(TARGET_MIPS)
>> #elif defined(TARGET_SH4)
>> #elif defined(TARGET_CRIS)
>> +#elif defined(TARGET_S390X)
>>     /* XXXXX */
>> #else
>> #error unsupported target CPU
>> @@ -673,6 +674,7 @@ int cpu_exec(CPUState *env1)
>> #elif defined(TARGET_SH4)
>> #elif defined(TARGET_ALPHA)
>> #elif defined(TARGET_CRIS)
>> +#elif defined(TARGET_S390X)
>>     /* XXXXX */
>> #else
>> #error unsupported target CPU
>> diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h
>> new file mode 100644
>> index 0000000..f45b00c
>> --- /dev/null
>> +++ b/target-s390x/cpu.h
>> @@ -0,0 +1,119 @@
>> +/*
>> + * S/390 virtual CPU header
>> + *
>> + *  Copyright (c) 2009 Ulrich Hecht
>> + *
>> + * This library is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU Lesser General Public
>> + * License as published by the Free Software Foundation; either
>> + * version 2 of the License, or (at your option) any later version.
>> + *
>> + * This library is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>> + * Lesser General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU Lesser General Public
>> + * License along with this library; if not, write to the Free Software
>> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA  02110-1301 USA
>> + */
>> +#ifndef CPU_S390X_H
>> +#define CPU_S390X_H
>> +
>> +#define TARGET_LONG_BITS 64
>> +
>> +#define ELF_MACHINE	EM_S390
>> +
>> +#define CPUState struct CPUS390XState
>> +
>> +#include "cpu-defs.h"
>> +
>> +#include "softfloat.h"
>> +
>> +#define NB_MMU_MODES 2 // guess
>> +#define MMU_USER_IDX 0 // guess
>> +
>> +typedef union FPReg {
>> +    struct {
>> +#ifdef WORDS_BIGENDIAN
>> +        float32 e;
>> +        int32_t __pad;
>> +#else
>> +        int32_t __pad;
>> +        float32 e;
>> +#endif
>> +    };
>> +    float64 d;
>> +    uint64_t i;
>> +} FPReg;
>> +
>> +typedef struct CPUS390XState {
>> +    uint64_t regs[16];	/* GP registers */
>> +    
>> +    uint32_t aregs[16];	/* access registers */
>> +    
>> +    uint32_t fpc;	/* floating-point control register */
>> +    FPReg fregs[16]; /* FP registers */
>> +    float_status fpu_status; /* passed to softfloat lib */
>> +    
>> +    struct {
>> +        uint64_t mask;
>> +        uint64_t addr;
>> +    } psw;
>> +    
>> +    int cc; /* condition code (0-3) */
>> +    
>> +    uint64_t __excp_addr;
>> +    
>> +    CPU_COMMON
>> +} CPUS390XState;
>> +
>> +#if defined(CONFIG_USER_ONLY)
>> +static inline void cpu_clone_regs(CPUState *env, target_ulong newsp)
>> +{
>> +    if (newsp)
>> +        env->regs[15] = newsp;
> 
> Coding style.
> 
>> +    env->regs[0] = 0;
>> +}
>> +#endif
>> +
>> +CPUS390XState *cpu_s390x_init(const char *cpu_model);
>> +int cpu_s390x_exec(CPUS390XState *s);
>> +void cpu_s390x_close(CPUS390XState *s);
>> +
>> +/* you can call this signal handler from your SIGBUS and SIGSEGV
>> +   signal handlers to inform the virtual CPU of exceptions. non zero
>> +   is returned if the signal was handled by the virtual CPU.  */
>> +int cpu_s390x_signal_handler(int host_signum, void *pinfo,
>> +                           void *puc);
>> +int cpu_s390x_handle_mmu_fault (CPUS390XState *env, target_ulong address, int rw,
>> +                              int mmu_idx, int is_softmuu);
>> +#define cpu_handle_mmu_fault cpu_s390x_handle_mmu_fault
>> +
>> +#define TARGET_PAGE_BITS 12
>> +
>> +#define cpu_init cpu_s390x_init
>> +#define cpu_exec cpu_s390x_exec
>> +#define cpu_gen_code cpu_s390x_gen_code
>> +
>> +#include "cpu-all.h"
>> +#include "exec-all.h"
>> +
>> +#define EXCP_OPEX 1 /* operation exception (sigill) */
>> +#define EXCP_SVC 2 /* supervisor call (syscall) */
>> +#define EXCP_ADDR 5 /* addressing exception */
>> +#define EXCP_EXECUTE_SVC 0xff00000 /* supervisor call via execute insn */
>> +
>> +static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock* tb)
>> +{
>> +    env->psw.addr = tb->pc;
>> +}
>> +
>> +static inline void cpu_get_tb_cpu_state(CPUState* env, target_ulong *pc,
>> +                                        target_ulong *cs_base, int *flags)
>> +{
>> +    *pc = env->psw.addr;
>> +    *cs_base = 0;
>> +    *flags = env->psw.mask; // guess
> 
> I don't know what psw.mask represent, but it may be wrong. It should be
> a way to identify which TB can be reused, that is they have been
> generated in the same CPU mode.

psw.mask is rougly the same as RFLAGS, cr0 and cr4 on x86_64 combined. So IMHO it looked like a pretty good identifier for TB uniqueness.

Alex
Carsten Otte Dec. 1, 2009, 9:46 a.m. UTC | #3
Alexander Graf wrote:
>> I don't know what psw.mask represent, but it may be wrong. It should be
>> a way to identify which TB can be reused, that is they have been
>> generated in the same CPU mode.
> 
> psw.mask is rougly the same as RFLAGS, cr0 and cr4 on x86_64 combined. So IMHO it looked like a pretty good identifier for TB uniqueness.
I am not familar with qemu at all here, therefore the following 
explanation may not fit here. I assume the translation block refers to 
guest virtual to guest physical memory translations. In that case this 
is not the right indicator on it's own. The right indicator which 
translation the cpu would do would be pretty complex:
Our cpu keeps multiple seperate address spaces open at the same time 
(similar to x86 with a bunch of cr0s), defined by address space control 
elements in various control registers. Linux uses primary, secondary and 
home space to address user space and kernel space. The third one is user 
space once again for exec-type access (to implement stack execute 
protection). PSW.mask selects which one is to be used for address 
translation by _default_. Even worse, the cpu may load instructions and 
data from different adddress spaces (secondary space mdoe). Yet more 
worse some instructions use "access register mode" where a general 
purpose register points to yet another address space. A detailed 
documentation can be found here: 
http://publibfp.boulder.ibm.com/cgi-bin/bookmgr/BOOKS/dz9zr002/3.0?DT=20030424140649

That said, I think it's best to keep out softmmu for now. It's not 
needed for kvm operation and very complex to do right.
Alexander Graf Dec. 1, 2009, 10:11 a.m. UTC | #4
On 01.12.2009, at 10:46, Carsten Otte wrote:

> Alexander Graf wrote:
>>> I don't know what psw.mask represent, but it may be wrong. It should be
>>> a way to identify which TB can be reused, that is they have been
>>> generated in the same CPU mode.
>> psw.mask is rougly the same as RFLAGS, cr0 and cr4 on x86_64 combined. So IMHO it looked like a pretty good identifier for TB uniqueness.
> I am not familar with qemu at all here, therefore the following explanation may not fit here. I assume the translation block refers to guest virtual to guest physical memory translations. In that case this is not the right indicator on it's own. The right indicator which translation the cpu would do would be pretty complex:
> Our cpu keeps multiple seperate address spaces open at the same time (similar to x86 with a bunch of cr0s), defined by address space control elements in various control registers. Linux uses primary, secondary and home space to address user space and kernel space. The third one is user space once again for exec-type access (to implement stack execute protection). PSW.mask selects which one is to be used for address translation by _default_. Even worse, the cpu may load instructions and data from different adddress spaces (secondary space mdoe). Yet more worse some instructions use "access register mode" where a general purpose register points to yet another address space. A detailed documentation can be found here: http://publibfp.boulder.ibm.com/cgi-bin/bookmgr/BOOKS/dz9zr002/3.0?DT=20030424140649
> 
> That said, I think it's best to keep out softmmu for now. It's not needed for kvm operation and very complex to do right.

Ah ok, so we're missing the asce register information for softmmu uniqueness. Well - I guess I should put a comment there that tells anyone who feels like implementing a softmmu target that this is a pitfall.

Alex
Blue Swirl Dec. 1, 2009, 6:45 p.m. UTC | #5
2009/12/1 Carsten Otte <carsteno@de.ibm.com>:
> Alexander Graf wrote:
>>>
>>> I don't know what psw.mask represent, but it may be wrong. It should be
>>> a way to identify which TB can be reused, that is they have been
>>> generated in the same CPU mode.
>>
>> psw.mask is rougly the same as RFLAGS, cr0 and cr4 on x86_64 combined. So
>> IMHO it looked like a pretty good identifier for TB uniqueness.
>
> I am not familar with qemu at all here, therefore the following explanation
> may not fit here. I assume the translation block refers to guest virtual to
> guest physical memory translations. In that case this is not the right
> indicator on it's own. The right indicator which translation the cpu would
> do would be pretty complex:

The translation block (TB) refers to a block of host instructions,
translated from some block of target instructions under some
assumptions. The assumptions used when translating (for example, user
vs supervisor mode in the CPU state) are recorded to TB flags. If the
CPU state changes, the old TBs with different flags will not be used
and new TBs will be generated.

> Our cpu keeps multiple seperate address spaces open at the same time
> (similar to x86 with a bunch of cr0s), defined by address space control
> elements in various control registers. Linux uses primary, secondary and
> home space to address user space and kernel space. The third one is user
> space once again for exec-type access (to implement stack execute
> protection). PSW.mask selects which one is to be used for address
> translation by _default_. Even worse, the cpu may load instructions and data
> from different adddress spaces (secondary space mdoe). Yet more worse some
> instructions use "access register mode" where a general purpose register
> points to yet another address space. A detailed documentation can be found
> here:
> http://publibfp.boulder.ibm.com/cgi-bin/bookmgr/BOOKS/dz9zr002/3.0?DT=20030424140649

Actually Sparc64 address spaces and ASIs are very similar. There are
nucleus, primary and secondary address spaces (not fully implemented
yet in QEMU). Instructions can encode the ASI or %asi register can be
used. Some ASIs are restricted for supervisor or hypervisor modes.
Sparc32 ASIs are simpler (physical address space extension to 36 bits,
basically) and for supervisor only.

For S/390, I think the TB flags do not need to contain the address
space control registers if the generated instructions fetch the state
from CPU state and do not rely on translation time information. If the
address spaces do not change very often, it may alternatively be
possible to rely on the CPU state during translation, but then it must
be ensured that all generated TBs are always flushed when the
registers change.
Carsten Otte Dec. 2, 2009, 7:55 a.m. UTC | #6
Blue Swirl wrote:
> The translation block (TB) refers to a block of host instructions,
> translated from some block of target instructions under some
> assumptions. The assumptions used when translating (for example, user
> vs supervisor mode in the CPU state) are recorded to TB flags. If the
> CPU state changes, the old TBs with different flags will not be used
> and new TBs will be generated.
Thanks for the explanation, Alex did explain it too on irc.

> Actually Sparc64 address spaces and ASIs are very similar. There are
> nucleus, primary and secondary address spaces (not fully implemented
> yet in QEMU). Instructions can encode the ASI or %asi register can be
> used. Some ASIs are restricted for supervisor or hypervisor modes.
> Sparc32 ASIs are simpler (physical address space extension to 36 bits,
> basically) and for supervisor only.
Oh, I though we were the only odd bird on this one.

> For S/390, I think the TB flags do not need to contain the address
> space control registers if the generated instructions fetch the state
> from CPU state and do not rely on translation time information. If the
> address spaces do not change very often, it may alternatively be
> possible to rely on the CPU state during translation, but then it must
> be ensured that all generated TBs are always flushed when the
> registers change.
Yes, that would work as far as I can tell. The registers change whenever 
$guest decides to schedule a different task, but not on every syscall.

cheers,
Carsten
Aurelien Jarno Dec. 2, 2009, 8:17 a.m. UTC | #7
On Mon, Nov 30, 2009 at 11:30:04PM +0100, Alexander Graf wrote:
> 
> On 30.11.2009, at 19:18, Aurelien Jarno wrote:
> 
> > On Thu, Nov 26, 2009 at 02:23:10PM +0100, Alexander Graf wrote:
> >> Because Qemu currently requires a TCG target to exist and there are quite some
> >> useful helpers here to lay the groundwork for out KVM target, let's create a
> >> stub TCG emulation target for S390X CPUs.
> >> 
> >> This is required to make tcg happy. The emulation target itself won't work
> >> though.
> > 
> > Please find the comments below.
> > 
> >> Signed-off-by: Alexander Graf <agraf@suse.de>
> >> ---
> >> cpu-exec.c               |    2 +
> >> target-s390x/cpu.h       |  119 ++++++++++++++++++++++++++++++++++++++++++++++
> >> target-s390x/exec.h      |   51 ++++++++++++++++++++
> >> target-s390x/helper.c    |   57 ++++++++++++++++++++++
> >> target-s390x/op_helper.c |   74 ++++++++++++++++++++++++++++
> >> target-s390x/translate.c |   57 ++++++++++++++++++++++
> >> 6 files changed, 360 insertions(+), 0 deletions(-)
> >> create mode 100644 target-s390x/cpu.h
> >> create mode 100644 target-s390x/exec.h
> >> create mode 100644 target-s390x/helper.c
> >> create mode 100644 target-s390x/op_helper.c
> >> create mode 100644 target-s390x/translate.c
> >> 
> >> diff --git a/cpu-exec.c b/cpu-exec.c
> >> index 2c0765c..af4595b 100644
> >> --- a/cpu-exec.c
> >> +++ b/cpu-exec.c
> >> @@ -249,6 +249,7 @@ int cpu_exec(CPUState *env1)
> >> #elif defined(TARGET_MIPS)
> >> #elif defined(TARGET_SH4)
> >> #elif defined(TARGET_CRIS)
> >> +#elif defined(TARGET_S390X)
> >>     /* XXXXX */
> >> #else
> >> #error unsupported target CPU
> >> @@ -673,6 +674,7 @@ int cpu_exec(CPUState *env1)
> >> #elif defined(TARGET_SH4)
> >> #elif defined(TARGET_ALPHA)
> >> #elif defined(TARGET_CRIS)
> >> +#elif defined(TARGET_S390X)
> >>     /* XXXXX */
> >> #else
> >> #error unsupported target CPU
> >> diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h
> >> new file mode 100644
> >> index 0000000..f45b00c
> >> --- /dev/null
> >> +++ b/target-s390x/cpu.h
> >> @@ -0,0 +1,119 @@
> >> +/*
> >> + * S/390 virtual CPU header
> >> + *
> >> + *  Copyright (c) 2009 Ulrich Hecht
> >> + *
> >> + * This library is free software; you can redistribute it and/or
> >> + * modify it under the terms of the GNU Lesser General Public
> >> + * License as published by the Free Software Foundation; either
> >> + * version 2 of the License, or (at your option) any later version.
> >> + *
> >> + * This library is distributed in the hope that it will be useful,
> >> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> >> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> >> + * Lesser General Public License for more details.
> >> + *
> >> + * You should have received a copy of the GNU Lesser General Public
> >> + * License along with this library; if not, write to the Free Software
> >> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA  02110-1301 USA
> >> + */
> >> +#ifndef CPU_S390X_H
> >> +#define CPU_S390X_H
> >> +
> >> +#define TARGET_LONG_BITS 64
> >> +
> >> +#define ELF_MACHINE	EM_S390
> >> +
> >> +#define CPUState struct CPUS390XState
> >> +
> >> +#include "cpu-defs.h"
> >> +
> >> +#include "softfloat.h"
> >> +
> >> +#define NB_MMU_MODES 2 // guess
> >> +#define MMU_USER_IDX 0 // guess
> >> +
> >> +typedef union FPReg {
> >> +    struct {
> >> +#ifdef WORDS_BIGENDIAN
> >> +        float32 e;
> >> +        int32_t __pad;
> >> +#else
> >> +        int32_t __pad;
> >> +        float32 e;
> >> +#endif
> >> +    };
> >> +    float64 d;
> >> +    uint64_t i;
> >> +} FPReg;
> >> +
> >> +typedef struct CPUS390XState {
> >> +    uint64_t regs[16];	/* GP registers */
> >> +    
> >> +    uint32_t aregs[16];	/* access registers */
> >> +    
> >> +    uint32_t fpc;	/* floating-point control register */
> >> +    FPReg fregs[16]; /* FP registers */
> >> +    float_status fpu_status; /* passed to softfloat lib */
> >> +    
> >> +    struct {
> >> +        uint64_t mask;
> >> +        uint64_t addr;
> >> +    } psw;
> >> +    
> >> +    int cc; /* condition code (0-3) */
> >> +    
> >> +    uint64_t __excp_addr;
> >> +    
> >> +    CPU_COMMON
> >> +} CPUS390XState;
> >> +
> >> +#if defined(CONFIG_USER_ONLY)
> >> +static inline void cpu_clone_regs(CPUState *env, target_ulong newsp)
> >> +{
> >> +    if (newsp)
> >> +        env->regs[15] = newsp;
> > 
> > Coding style.
> > 
> >> +    env->regs[0] = 0;
> >> +}
> >> +#endif
> >> +
> >> +CPUS390XState *cpu_s390x_init(const char *cpu_model);
> >> +int cpu_s390x_exec(CPUS390XState *s);
> >> +void cpu_s390x_close(CPUS390XState *s);
> >> +
> >> +/* you can call this signal handler from your SIGBUS and SIGSEGV
> >> +   signal handlers to inform the virtual CPU of exceptions. non zero
> >> +   is returned if the signal was handled by the virtual CPU.  */
> >> +int cpu_s390x_signal_handler(int host_signum, void *pinfo,
> >> +                           void *puc);
> >> +int cpu_s390x_handle_mmu_fault (CPUS390XState *env, target_ulong address, int rw,
> >> +                              int mmu_idx, int is_softmuu);
> >> +#define cpu_handle_mmu_fault cpu_s390x_handle_mmu_fault
> >> +
> >> +#define TARGET_PAGE_BITS 12
> >> +
> >> +#define cpu_init cpu_s390x_init
> >> +#define cpu_exec cpu_s390x_exec
> >> +#define cpu_gen_code cpu_s390x_gen_code
> >> +
> >> +#include "cpu-all.h"
> >> +#include "exec-all.h"
> >> +
> >> +#define EXCP_OPEX 1 /* operation exception (sigill) */
> >> +#define EXCP_SVC 2 /* supervisor call (syscall) */
> >> +#define EXCP_ADDR 5 /* addressing exception */
> >> +#define EXCP_EXECUTE_SVC 0xff00000 /* supervisor call via execute insn */
> >> +
> >> +static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock* tb)
> >> +{
> >> +    env->psw.addr = tb->pc;
> >> +}
> >> +
> >> +static inline void cpu_get_tb_cpu_state(CPUState* env, target_ulong *pc,
> >> +                                        target_ulong *cs_base, int *flags)
> >> +{
> >> +    *pc = env->psw.addr;
> >> +    *cs_base = 0;
> >> +    *flags = env->psw.mask; // guess
> > 
> > I don't know what psw.mask represent, but it may be wrong. It should be
> > a way to identify which TB can be reused, that is they have been
> > generated in the same CPU mode.
> 
> psw.mask is rougly the same as RFLAGS, cr0 and cr4 on x86_64 combined. So IMHO it looked like a pretty good identifier for TB uniqueness.
> 

Then it's most probably correct, except some bits may have to be
ignored. Can you update the comment explaining that?
Alexander Graf Dec. 2, 2009, 8:30 a.m. UTC | #8
On 02.12.2009, at 09:17, Aurelien Jarno wrote:

> On Mon, Nov 30, 2009 at 11:30:04PM +0100, Alexander Graf wrote:
>> 
>> On 30.11.2009, at 19:18, Aurelien Jarno wrote:
>> 
>>> On Thu, Nov 26, 2009 at 02:23:10PM +0100, Alexander Graf wrote:
>>>> Because Qemu currently requires a TCG target to exist and there are quite some
>>>> useful helpers here to lay the groundwork for out KVM target, let's create a
>>>> stub TCG emulation target for S390X CPUs.
>>>> 
>>>> This is required to make tcg happy. The emulation target itself won't work
>>>> though.
>>> 
>>> Please find the comments below.
>>> 
>>>> Signed-off-by: Alexander Graf <agraf@suse.de>
>>>> ---
>>>> cpu-exec.c               |    2 +
>>>> target-s390x/cpu.h       |  119 ++++++++++++++++++++++++++++++++++++++++++++++
>>>> target-s390x/exec.h      |   51 ++++++++++++++++++++
>>>> target-s390x/helper.c    |   57 ++++++++++++++++++++++
>>>> target-s390x/op_helper.c |   74 ++++++++++++++++++++++++++++
>>>> target-s390x/translate.c |   57 ++++++++++++++++++++++
>>>> 6 files changed, 360 insertions(+), 0 deletions(-)
>>>> create mode 100644 target-s390x/cpu.h
>>>> create mode 100644 target-s390x/exec.h
>>>> create mode 100644 target-s390x/helper.c
>>>> create mode 100644 target-s390x/op_helper.c
>>>> create mode 100644 target-s390x/translate.c
>>>> 
>>>> diff --git a/cpu-exec.c b/cpu-exec.c
>>>> index 2c0765c..af4595b 100644
>>>> --- a/cpu-exec.c
>>>> +++ b/cpu-exec.c
>>>> @@ -249,6 +249,7 @@ int cpu_exec(CPUState *env1)
>>>> #elif defined(TARGET_MIPS)
>>>> #elif defined(TARGET_SH4)
>>>> #elif defined(TARGET_CRIS)
>>>> +#elif defined(TARGET_S390X)
>>>>    /* XXXXX */
>>>> #else
>>>> #error unsupported target CPU
>>>> @@ -673,6 +674,7 @@ int cpu_exec(CPUState *env1)
>>>> #elif defined(TARGET_SH4)
>>>> #elif defined(TARGET_ALPHA)
>>>> #elif defined(TARGET_CRIS)
>>>> +#elif defined(TARGET_S390X)
>>>>    /* XXXXX */
>>>> #else
>>>> #error unsupported target CPU
>>>> diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h
>>>> new file mode 100644
>>>> index 0000000..f45b00c
>>>> --- /dev/null
>>>> +++ b/target-s390x/cpu.h
>>>> @@ -0,0 +1,119 @@
>>>> +/*
>>>> + * S/390 virtual CPU header
>>>> + *
>>>> + *  Copyright (c) 2009 Ulrich Hecht
>>>> + *
>>>> + * This library is free software; you can redistribute it and/or
>>>> + * modify it under the terms of the GNU Lesser General Public
>>>> + * License as published by the Free Software Foundation; either
>>>> + * version 2 of the License, or (at your option) any later version.
>>>> + *
>>>> + * This library is distributed in the hope that it will be useful,
>>>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>>>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>>>> + * Lesser General Public License for more details.
>>>> + *
>>>> + * You should have received a copy of the GNU Lesser General Public
>>>> + * License along with this library; if not, write to the Free Software
>>>> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA  02110-1301 USA
>>>> + */
>>>> +#ifndef CPU_S390X_H
>>>> +#define CPU_S390X_H
>>>> +
>>>> +#define TARGET_LONG_BITS 64
>>>> +
>>>> +#define ELF_MACHINE	EM_S390
>>>> +
>>>> +#define CPUState struct CPUS390XState
>>>> +
>>>> +#include "cpu-defs.h"
>>>> +
>>>> +#include "softfloat.h"
>>>> +
>>>> +#define NB_MMU_MODES 2 // guess
>>>> +#define MMU_USER_IDX 0 // guess
>>>> +
>>>> +typedef union FPReg {
>>>> +    struct {
>>>> +#ifdef WORDS_BIGENDIAN
>>>> +        float32 e;
>>>> +        int32_t __pad;
>>>> +#else
>>>> +        int32_t __pad;
>>>> +        float32 e;
>>>> +#endif
>>>> +    };
>>>> +    float64 d;
>>>> +    uint64_t i;
>>>> +} FPReg;
>>>> +
>>>> +typedef struct CPUS390XState {
>>>> +    uint64_t regs[16];	/* GP registers */
>>>> +    
>>>> +    uint32_t aregs[16];	/* access registers */
>>>> +    
>>>> +    uint32_t fpc;	/* floating-point control register */
>>>> +    FPReg fregs[16]; /* FP registers */
>>>> +    float_status fpu_status; /* passed to softfloat lib */
>>>> +    
>>>> +    struct {
>>>> +        uint64_t mask;
>>>> +        uint64_t addr;
>>>> +    } psw;
>>>> +    
>>>> +    int cc; /* condition code (0-3) */
>>>> +    
>>>> +    uint64_t __excp_addr;
>>>> +    
>>>> +    CPU_COMMON
>>>> +} CPUS390XState;
>>>> +
>>>> +#if defined(CONFIG_USER_ONLY)
>>>> +static inline void cpu_clone_regs(CPUState *env, target_ulong newsp)
>>>> +{
>>>> +    if (newsp)
>>>> +        env->regs[15] = newsp;
>>> 
>>> Coding style.
>>> 
>>>> +    env->regs[0] = 0;
>>>> +}
>>>> +#endif
>>>> +
>>>> +CPUS390XState *cpu_s390x_init(const char *cpu_model);
>>>> +int cpu_s390x_exec(CPUS390XState *s);
>>>> +void cpu_s390x_close(CPUS390XState *s);
>>>> +
>>>> +/* you can call this signal handler from your SIGBUS and SIGSEGV
>>>> +   signal handlers to inform the virtual CPU of exceptions. non zero
>>>> +   is returned if the signal was handled by the virtual CPU.  */
>>>> +int cpu_s390x_signal_handler(int host_signum, void *pinfo,
>>>> +                           void *puc);
>>>> +int cpu_s390x_handle_mmu_fault (CPUS390XState *env, target_ulong address, int rw,
>>>> +                              int mmu_idx, int is_softmuu);
>>>> +#define cpu_handle_mmu_fault cpu_s390x_handle_mmu_fault
>>>> +
>>>> +#define TARGET_PAGE_BITS 12
>>>> +
>>>> +#define cpu_init cpu_s390x_init
>>>> +#define cpu_exec cpu_s390x_exec
>>>> +#define cpu_gen_code cpu_s390x_gen_code
>>>> +
>>>> +#include "cpu-all.h"
>>>> +#include "exec-all.h"
>>>> +
>>>> +#define EXCP_OPEX 1 /* operation exception (sigill) */
>>>> +#define EXCP_SVC 2 /* supervisor call (syscall) */
>>>> +#define EXCP_ADDR 5 /* addressing exception */
>>>> +#define EXCP_EXECUTE_SVC 0xff00000 /* supervisor call via execute insn */
>>>> +
>>>> +static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock* tb)
>>>> +{
>>>> +    env->psw.addr = tb->pc;
>>>> +}
>>>> +
>>>> +static inline void cpu_get_tb_cpu_state(CPUState* env, target_ulong *pc,
>>>> +                                        target_ulong *cs_base, int *flags)
>>>> +{
>>>> +    *pc = env->psw.addr;
>>>> +    *cs_base = 0;
>>>> +    *flags = env->psw.mask; // guess
>>> 
>>> I don't know what psw.mask represent, but it may be wrong. It should be
>>> a way to identify which TB can be reused, that is they have been
>>> generated in the same CPU mode.
>> 
>> psw.mask is rougly the same as RFLAGS, cr0 and cr4 on x86_64 combined. So IMHO it looked like a pretty good identifier for TB uniqueness.
>> 
> 
> Then it's most probably correct, except some bits may have to be
> ignored. Can you update the comment explaining that?

Yep.

Alex
Paul Brook Dec. 2, 2009, 2:41 p.m. UTC | #9
> > Our cpu keeps multiple seperate address spaces open at the same time
> > (similar to x86 with a bunch of cr0s), defined by address space control
> > elements in various control registers. Linux uses primary, secondary and
> > home space to address user space and kernel space. The third one is user
> > space once again for exec-type access (to implement stack execute
> > protection). PSW.mask selects which one is to be used for address
> > translation by _default_. Even worse, the cpu may load instructions and
> > data from different adddress spaces (secondary space mdoe). Yet more
> > worse some instructions use "access register mode" where a general
> > purpose register points to yet another address space. A detailed
> > documentation can be found here:
> > http://publibfp.boulder.ibm.com/cgi-bin/bookmgr/BOOKS/dz9zr002/3.0?DT=200
> >30424140649
> 
> Actually Sparc64 address spaces and ASIs are very similar. There are
> nucleus, primary and secondary address spaces (not fully implemented
> yet in QEMU). Instructions can encode the ASI or %asi register can be
> used. Some ASIs are restricted for supervisor or hypervisor modes.
> Sparc32 ASIs are simpler (physical address space extension to 36 bits,
> basically) and for supervisor only.
> 
> For S/390, I think the TB flags do not need to contain the address
> space control registers if the generated instructions fetch the state
> from CPU state and do not rely on translation time information. If the
> address spaces do not change very often, it may alternatively be
> possible to rely on the CPU state during translation, but then it must
> be ensured that all generated TBs are always flushed when the
> registers change.

It sounds like there's some confusion between virtual address translation and 
state that effects instruction semantics. The TB flags should include the 
latter. The former isn't particularly well supported in qemu. If you have more 
than a couple of different address spaces (i.e. kernel and userspace) then you 
basically have to flush the TLB every time the current address space changes. 
If the address space an be selected per-instruction then you're pretty much 
screwed.

Paul
diff mbox

Patch

diff --git a/cpu-exec.c b/cpu-exec.c
index 2c0765c..af4595b 100644
--- a/cpu-exec.c
+++ b/cpu-exec.c
@@ -249,6 +249,7 @@  int cpu_exec(CPUState *env1)
 #elif defined(TARGET_MIPS)
 #elif defined(TARGET_SH4)
 #elif defined(TARGET_CRIS)
+#elif defined(TARGET_S390X)
     /* XXXXX */
 #else
 #error unsupported target CPU
@@ -673,6 +674,7 @@  int cpu_exec(CPUState *env1)
 #elif defined(TARGET_SH4)
 #elif defined(TARGET_ALPHA)
 #elif defined(TARGET_CRIS)
+#elif defined(TARGET_S390X)
     /* XXXXX */
 #else
 #error unsupported target CPU
diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h
new file mode 100644
index 0000000..f45b00c
--- /dev/null
+++ b/target-s390x/cpu.h
@@ -0,0 +1,119 @@ 
+/*
+ * S/390 virtual CPU header
+ *
+ *  Copyright (c) 2009 Ulrich Hecht
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA  02110-1301 USA
+ */
+#ifndef CPU_S390X_H
+#define CPU_S390X_H
+
+#define TARGET_LONG_BITS 64
+
+#define ELF_MACHINE	EM_S390
+
+#define CPUState struct CPUS390XState
+
+#include "cpu-defs.h"
+
+#include "softfloat.h"
+
+#define NB_MMU_MODES 2 // guess
+#define MMU_USER_IDX 0 // guess
+
+typedef union FPReg {
+    struct {
+#ifdef WORDS_BIGENDIAN
+        float32 e;
+        int32_t __pad;
+#else
+        int32_t __pad;
+        float32 e;
+#endif
+    };
+    float64 d;
+    uint64_t i;
+} FPReg;
+
+typedef struct CPUS390XState {
+    uint64_t regs[16];	/* GP registers */
+    
+    uint32_t aregs[16];	/* access registers */
+    
+    uint32_t fpc;	/* floating-point control register */
+    FPReg fregs[16]; /* FP registers */
+    float_status fpu_status; /* passed to softfloat lib */
+    
+    struct {
+        uint64_t mask;
+        uint64_t addr;
+    } psw;
+    
+    int cc; /* condition code (0-3) */
+    
+    uint64_t __excp_addr;
+    
+    CPU_COMMON
+} CPUS390XState;
+
+#if defined(CONFIG_USER_ONLY)
+static inline void cpu_clone_regs(CPUState *env, target_ulong newsp)
+{
+    if (newsp)
+        env->regs[15] = newsp;
+    env->regs[0] = 0;
+}
+#endif
+
+CPUS390XState *cpu_s390x_init(const char *cpu_model);
+int cpu_s390x_exec(CPUS390XState *s);
+void cpu_s390x_close(CPUS390XState *s);
+
+/* you can call this signal handler from your SIGBUS and SIGSEGV
+   signal handlers to inform the virtual CPU of exceptions. non zero
+   is returned if the signal was handled by the virtual CPU.  */
+int cpu_s390x_signal_handler(int host_signum, void *pinfo,
+                           void *puc);
+int cpu_s390x_handle_mmu_fault (CPUS390XState *env, target_ulong address, int rw,
+                              int mmu_idx, int is_softmuu);
+#define cpu_handle_mmu_fault cpu_s390x_handle_mmu_fault
+
+#define TARGET_PAGE_BITS 12
+
+#define cpu_init cpu_s390x_init
+#define cpu_exec cpu_s390x_exec
+#define cpu_gen_code cpu_s390x_gen_code
+
+#include "cpu-all.h"
+#include "exec-all.h"
+
+#define EXCP_OPEX 1 /* operation exception (sigill) */
+#define EXCP_SVC 2 /* supervisor call (syscall) */
+#define EXCP_ADDR 5 /* addressing exception */
+#define EXCP_EXECUTE_SVC 0xff00000 /* supervisor call via execute insn */
+
+static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock* tb)
+{
+    env->psw.addr = tb->pc;
+}
+
+static inline void cpu_get_tb_cpu_state(CPUState* env, target_ulong *pc,
+                                        target_ulong *cs_base, int *flags)
+{
+    *pc = env->psw.addr;
+    *cs_base = 0;
+    *flags = env->psw.mask; // guess
+}
+#endif
diff --git a/target-s390x/exec.h b/target-s390x/exec.h
new file mode 100644
index 0000000..5198359
--- /dev/null
+++ b/target-s390x/exec.h
@@ -0,0 +1,51 @@ 
+/*
+ *  S/390 execution defines
+ *
+ *  Copyright (c) 2009 Ulrich Hecht
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA  02110-1301 USA
+ */
+
+#include "dyngen-exec.h"
+
+register struct CPUS390XState *env asm(AREG0);
+
+#include "cpu.h"
+#include "exec-all.h"
+
+static inline int cpu_has_work(CPUState *env)
+{
+    return env->interrupt_request & CPU_INTERRUPT_HARD; // guess
+}
+
+static inline void regs_to_env(void)
+{
+}
+
+static inline void env_to_regs(void)
+{
+}
+
+static inline int cpu_halted(CPUState *env)
+{
+    if (!env->halted) {
+       return 0;
+    }
+    if (cpu_has_work(env)) {
+        env->halted = 0;
+        return 0;
+    }
+    return EXCP_HALTED;
+}
diff --git a/target-s390x/helper.c b/target-s390x/helper.c
new file mode 100644
index 0000000..4e23b4a
--- /dev/null
+++ b/target-s390x/helper.c
@@ -0,0 +1,57 @@ 
+/*
+ *  S/390 helpers
+ *
+ *  Copyright (c) 2009 Ulrich Hecht
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA  02110-1301 USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "cpu.h"
+#include "exec-all.h"
+#include "gdbstub.h"
+#include "qemu-common.h"
+
+CPUS390XState *cpu_s390x_init(const char *cpu_model)
+{
+    CPUS390XState *env;
+    static int inited = 0;
+    
+    env = qemu_mallocz(sizeof(CPUS390XState));
+    cpu_exec_init(env);
+    if (!inited) {
+        inited = 1;
+    }
+    
+    env->cpu_model_str = cpu_model;
+    cpu_reset(env);
+    qemu_init_vcpu(env);
+    return env;
+}
+
+void cpu_reset(CPUS390XState *env)
+{
+    if (qemu_loglevel_mask(CPU_LOG_RESET)) {
+        qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
+        log_cpu_state(env, 0);
+    }
+    
+    memset(env, 0, offsetof(CPUS390XState, breakpoints));
+    /* FIXME: reset vector? */
+    tlb_flush(env, 1);
+}
diff --git a/target-s390x/op_helper.c b/target-s390x/op_helper.c
new file mode 100644
index 0000000..e623de9
--- /dev/null
+++ b/target-s390x/op_helper.c
@@ -0,0 +1,74 @@ 
+/*
+ *  S/390 helper routines
+ *
+ *  Copyright (c) 2009 Alexander Graf
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA  02110-1301 USA
+ */
+
+#include "exec.h"
+
+/*****************************************************************************/
+/* Softmmu support */
+#if !defined (CONFIG_USER_ONLY)
+
+#define MMUSUFFIX _mmu
+
+#define SHIFT 0
+#include "softmmu_template.h"
+
+#define SHIFT 1
+#include "softmmu_template.h"
+
+#define SHIFT 2
+#include "softmmu_template.h"
+
+#define SHIFT 3
+#include "softmmu_template.h"
+
+/* try to fill the TLB and return an exception if error. If retaddr is
+   NULL, it means that the function was called in C code (i.e. not
+   from generated code or from helper.c) */
+/* XXX: fix it to restore all registers */
+void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
+{
+    TranslationBlock *tb;
+    CPUState *saved_env;
+    unsigned long pc;
+    int ret;
+
+    /* XXX: hack to restore env in all cases, even if not called from
+       generated code */
+    saved_env = env;
+    env = cpu_single_env;
+    ret = cpu_s390x_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
+    if (unlikely(ret != 0)) {
+        if (likely(retaddr)) {
+            /* now we have a real cpu fault */
+            pc = (unsigned long)retaddr;
+            tb = tb_find_pc(pc);
+            if (likely(tb)) {
+                /* the PC is inside the translated code. It means that we have
+                   a virtual CPU fault */
+                cpu_restore_state(tb, env, pc, NULL);
+            }
+        }
+        /* XXX */
+        /* helper_raise_exception_err(env->exception_index, env->error_code); */
+    }
+    env = saved_env;
+}
+
+#endif
diff --git a/target-s390x/translate.c b/target-s390x/translate.c
new file mode 100644
index 0000000..f304411
--- /dev/null
+++ b/target-s390x/translate.c
@@ -0,0 +1,57 @@ 
+/*
+ *  S/390 translation
+ *
+ *  Copyright (c) 2009 Ulrich Hecht
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA  02110-1301 USA
+ */
+
+#include "cpu.h"
+#include "exec-all.h"
+#include "disas.h"
+#include "tcg-op.h"
+#include "qemu-log.h"
+
+void cpu_dump_state(CPUState *env, FILE *f,
+                    int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
+                    int flags)
+{
+    int i;
+    for (i = 0; i < 16; i++) {
+        cpu_fprintf(f, "R%02d=%016lx", i, env->regs[i]);
+        if ((i % 4) == 3) cpu_fprintf(f, "\n");
+        else cpu_fprintf(f, " ");
+    }
+    for (i = 0; i < 16; i++) {
+        cpu_fprintf(f, "F%02d=%016lx", i, env->fregs[i]);
+        if ((i % 4) == 3) cpu_fprintf(f, "\n");
+        else cpu_fprintf(f, " ");
+    }
+    cpu_fprintf(f, "PSW=mask %016lx addr %016lx cc %02x\n", env->psw.mask, env->psw.addr, env->cc);
+}
+
+void gen_intermediate_code (CPUState *env, struct TranslationBlock *tb)
+{
+}
+
+void gen_intermediate_code_pc (CPUState *env, struct TranslationBlock *tb)
+{
+}
+
+void gen_pc_load(CPUState *env, TranslationBlock *tb,
+                unsigned long searched_pc, int pc_pos, void *puc)
+{
+    env->psw.addr = gen_opc_pc[pc_pos];
+}