diff mbox

[03/12] ARM: Prepare translation for AArch64 code

Message ID 1362535280-5068-4-git-send-email-agraf@suse.de
State New
Headers show

Commit Message

Alexander Graf March 6, 2013, 2:01 a.m. UTC
This patch adds all the prerequisites for AArch64 support that didn't
fit into split up patches. It extends important bits in the core cpu
headers to also take AArch64 mode into account.

Signed-off-by: Alexander Graf <agraf@suse.de>
---
 include/elf.h          |    2 +
 target-arm/cpu.h       |  103 ++++++++++++++++++++++++++++++++++++------------
 target-arm/translate.c |   42 +++++++++++--------
 3 files changed, 103 insertions(+), 44 deletions(-)

Comments

Laurent Desnogues March 6, 2013, 7:11 a.m. UTC | #1
On Wed, Mar 6, 2013 at 3:01 AM, Alexander Graf <agraf@suse.de> wrote:
> This patch adds all the prerequisites for AArch64 support that didn't
> fit into split up patches. It extends important bits in the core cpu
> headers to also take AArch64 mode into account.
>
> Signed-off-by: Alexander Graf <agraf@suse.de>
> ---
>  include/elf.h          |    2 +
>  target-arm/cpu.h       |  103 ++++++++++++++++++++++++++++++++++++------------
>  target-arm/translate.c |   42 +++++++++++--------
>  3 files changed, 103 insertions(+), 44 deletions(-)
>
> diff --git a/include/elf.h b/include/elf.h
> index a21ea53..0ff0ea6 100644
> --- a/include/elf.h
> +++ b/include/elf.h
> @@ -109,6 +109,8 @@ typedef int64_t  Elf64_Sxword;
>  #define EM_OPENRISC     92        /* OpenCores OpenRISC */
>
>  #define EM_UNICORE32    110     /* UniCore32 */
> +#define EM_AARCH64      183     /* ARM 64-bit architecture */
> +
>
>  /*
>   * This is an interim value that we will use until the committee comes
> diff --git a/target-arm/cpu.h b/target-arm/cpu.h
> index c28a0d9..ec292c9 100644
> --- a/target-arm/cpu.h
> +++ b/target-arm/cpu.h
> @@ -19,13 +19,19 @@
>  #ifndef CPU_ARM_H
>  #define CPU_ARM_H
>
> -#define TARGET_LONG_BITS 32
> +#include "config.h"
>
> -#define ELF_MACHINE    EM_ARM
> +#if defined (TARGET_ARM64)
> +  /* AArch64 definitions */
> +#  define TARGET_LONG_BITS 64
> +#  define ELF_MACHINE  EM_AARCH64
> +#else
> +#  define TARGET_LONG_BITS 32
> +#  define ELF_MACHINE  EM_ARM
> +#endif
>
>  #define CPUArchState struct CPUARMState
>
> -#include "config.h"
>  #include "qemu-common.h"
>  #include "exec/cpu-defs.h"
>
> @@ -79,6 +85,13 @@ struct arm_boot_info;
>  typedef struct CPUARMState {
>      /* Regs for current mode.  */
>      uint32_t regs[16];
> +
> +    /* Regs for A64 mode.  */
> +    uint64_t xregs[32];

I'm not sure it makes sense to allocate space for xregs[31].
If it is the zero register then you would anyway have special
cases in translation code to discard writes to reg 31 and so
it could be argued you could also special case reads from
reg 31 (and you should so that the optimizer knows it's zero).

Perhaps you could use xregs[31] as SP, which after all is
a more "regular" register than xzr.


Laurent

> +    uint64_t pc;
> +    uint64_t sp;
> +    uint32_t pstate;
> +
>      /* Frequently accessed CPSR bits are stored separately for efficiency.
>         This contains all the other bits.  Use cpsr_{read,write} to access
>         the whole CPSR.  */
> @@ -154,6 +167,11 @@ typedef struct CPUARMState {
>          uint32_t c15_power_control; /* power control */
>      } cp15;
>
> +    /* System registers (AArch64) */
> +    struct {
> +        uint64_t tpidr_el0;
> +    } sr;
> +
>      struct {
>          uint32_t other_sp;
>          uint32_t vecbase;
> @@ -170,7 +188,7 @@ typedef struct CPUARMState {
>
>      /* VFP coprocessor state.  */
>      struct {
> -        float64 regs[32];
> +        float64 regs[64];
>
>          uint32_t xregs[16];
>          /* We store these fpcsr fields separately for convenience.  */
> @@ -241,6 +259,24 @@ int bank_number(int mode);
>  void switch_mode(CPUARMState *, int);
>  uint32_t do_arm_semihosting(CPUARMState *env);
>
> +static inline bool is_a64(CPUARMState *env)
> +{
> +#ifdef TARGET_ARM64
> +    return true;
> +#else
> +    return false;
> +#endif
> +}
> +
> +#define PSTATE_N_SHIFT 3
> +#define PSTATE_N  (1 << PSTATE_N_SHIFT)
> +#define PSTATE_Z_SHIFT 2
> +#define PSTATE_Z  (1 << PSTATE_Z_SHIFT)
> +#define PSTATE_C_SHIFT 1
> +#define PSTATE_C  (1 << PSTATE_C_SHIFT)
> +#define PSTATE_V_SHIFT 0
> +#define PSTATE_V  (1 << PSTATE_V_SHIFT)
> +
>  /* 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.  */
> @@ -624,8 +660,13 @@ static inline bool cp_access_ok(CPUARMState *env,
>  #define TARGET_PAGE_BITS 10
>  #endif
>
> -#define TARGET_PHYS_ADDR_SPACE_BITS 40
> -#define TARGET_VIRT_ADDR_SPACE_BITS 32
> +#if defined (TARGET_ARM64)
> +#  define TARGET_PHYS_ADDR_SPACE_BITS 64
> +#  define TARGET_VIRT_ADDR_SPACE_BITS 64
> +#else
> +#  define TARGET_PHYS_ADDR_SPACE_BITS 40
> +#  define TARGET_VIRT_ADDR_SPACE_BITS 32
> +#endif
>
>  static inline CPUARMState *cpu_init(const char *cpu_model)
>  {
> @@ -699,25 +740,31 @@ static inline void cpu_clone_regs(CPUARMState *env, target_ulong newsp)
>  static inline void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc,
>                                          target_ulong *cs_base, int *flags)
>  {
> -    int privmode;
> -    *pc = env->regs[15];
> -    *cs_base = 0;
> -    *flags = (env->thumb << ARM_TBFLAG_THUMB_SHIFT)
> -        | (env->vfp.vec_len << ARM_TBFLAG_VECLEN_SHIFT)
> -        | (env->vfp.vec_stride << ARM_TBFLAG_VECSTRIDE_SHIFT)
> -        | (env->condexec_bits << ARM_TBFLAG_CONDEXEC_SHIFT)
> -        | (env->bswap_code << ARM_TBFLAG_BSWAP_CODE_SHIFT);
> -    if (arm_feature(env, ARM_FEATURE_M)) {
> -        privmode = !((env->v7m.exception == 0) && (env->v7m.control & 1));
> +    if (is_a64(env)) {
> +        *pc = env->pc;
> +        *flags = 0;
>      } else {
> -        privmode = (env->uncached_cpsr & CPSR_M) != ARM_CPU_MODE_USR;
> -    }
> -    if (privmode) {
> -        *flags |= ARM_TBFLAG_PRIV_MASK;
> -    }
> -    if (env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30)) {
> -        *flags |= ARM_TBFLAG_VFPEN_MASK;
> +        int privmode;
> +        *pc = env->regs[15];
> +        *flags = (env->thumb << ARM_TBFLAG_THUMB_SHIFT)
> +            | (env->vfp.vec_len << ARM_TBFLAG_VECLEN_SHIFT)
> +            | (env->vfp.vec_stride << ARM_TBFLAG_VECSTRIDE_SHIFT)
> +            | (env->condexec_bits << ARM_TBFLAG_CONDEXEC_SHIFT)
> +            | (env->bswap_code << ARM_TBFLAG_BSWAP_CODE_SHIFT);
> +        if (arm_feature(env, ARM_FEATURE_M)) {
> +            privmode = !((env->v7m.exception == 0) && (env->v7m.control & 1));
> +        } else {
> +            privmode = (env->uncached_cpsr & CPSR_M) != ARM_CPU_MODE_USR;
> +        }
> +        if (privmode) {
> +            *flags |= ARM_TBFLAG_PRIV_MASK;
> +        }
> +        if (env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30)) {
> +            *flags |= ARM_TBFLAG_VFPEN_MASK;
> +        }
>      }
> +
> +    *cs_base = 0;
>  }
>
>  static inline bool cpu_has_work(CPUState *cpu)
> @@ -732,11 +779,15 @@ static inline bool cpu_has_work(CPUState *cpu)
>
>  static inline void cpu_pc_from_tb(CPUARMState *env, TranslationBlock *tb)
>  {
> -    env->regs[15] = tb->pc;
> +    if (is_a64(env)) {
> +        env->pc = tb->pc;
> +    } else {
> +        env->regs[15] = tb->pc;
> +    }
>  }
>
>  /* Load an instruction and return it in the standard little-endian order */
> -static inline uint32_t arm_ldl_code(CPUARMState *env, uint32_t addr,
> +static inline uint32_t arm_ldl_code(CPUARMState *env, target_ulong addr,
>                                      bool do_swap)
>  {
>      uint32_t insn = cpu_ldl_code(env, addr);
> @@ -747,7 +798,7 @@ static inline uint32_t arm_ldl_code(CPUARMState *env, uint32_t addr,
>  }
>
>  /* Ditto, for a halfword (Thumb) instruction */
> -static inline uint16_t arm_lduw_code(CPUARMState *env, uint32_t addr,
> +static inline uint16_t arm_lduw_code(CPUARMState *env, target_ulong addr,
>                                       bool do_swap)
>  {
>      uint16_t insn = cpu_lduw_code(env, addr);
> diff --git a/target-arm/translate.c b/target-arm/translate.c
> index f8838f3..de04a0c 100644
> --- a/target-arm/translate.c
> +++ b/target-arm/translate.c
> @@ -9749,7 +9749,7 @@ static inline void gen_intermediate_code_internal(CPUARMState *env,
>      uint16_t *gen_opc_end;
>      int j, lj;
>      target_ulong pc_start;
> -    uint32_t next_page_start;
> +    target_ulong next_page_start;
>      int num_insns;
>      int max_insns;
>
> @@ -9833,24 +9833,26 @@ static inline void gen_intermediate_code_internal(CPUARMState *env,
>          store_cpu_field(tmp, condexec_bits);
>        }
>      do {
> +        if (!is_a64(env)) {
>  #ifdef CONFIG_USER_ONLY
> -        /* Intercept jump to the magic kernel page.  */
> -        if (dc->pc >= 0xffff0000) {
> -            /* We always get here via a jump, so know we are not in a
> -               conditional execution block.  */
> -            gen_exception(EXCP_KERNEL_TRAP);
> -            dc->is_jmp = DISAS_UPDATE;
> -            break;
> -        }
> +            /* Intercept jump to the magic kernel page.  */
> +            if (dc->pc >= 0xffff0000) {
> +                /* We always get here via a jump, so know we are not in a
> +                   conditional execution block.  */
> +                gen_exception(EXCP_KERNEL_TRAP);
> +                dc->is_jmp = DISAS_UPDATE;
> +                break;
> +            }
>  #else
> -        if (dc->pc >= 0xfffffff0 && IS_M(env)) {
> -            /* We always get here via a jump, so know we are not in a
> -               conditional execution block.  */
> -            gen_exception(EXCP_EXCEPTION_EXIT);
> -            dc->is_jmp = DISAS_UPDATE;
> -            break;
> -        }
> +            if (dc->pc >= 0xfffffff0 && IS_M(env)) {
> +                /* We always get here via a jump, so know we are not in a
> +                   conditional execution block.  */
> +                gen_exception(EXCP_EXCEPTION_EXIT);
> +                dc->is_jmp = DISAS_UPDATE;
> +                break;
> +            }
>  #endif
> +        }
>
>          if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) {
>              QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
> @@ -9904,7 +9906,7 @@ static inline void gen_intermediate_code_internal(CPUARMState *env,
>          }
>
>          if (tcg_check_temp_count()) {
> -            fprintf(stderr, "TCG temporary leak before %08x\n", dc->pc);
> +            fprintf(stderr, "TCG temporary leak before "TARGET_FMT_lx"\n", dc->pc);
>          }
>
>          /* Translation stops when a conditional branch is encountered.
> @@ -10074,6 +10076,10 @@ void cpu_dump_state(CPUARMState *env, FILE *f, fprintf_function cpu_fprintf,
>
>  void restore_state_to_opc(CPUARMState *env, TranslationBlock *tb, int pc_pos)
>  {
> -    env->regs[15] = tcg_ctx.gen_opc_pc[pc_pos];
> +    if (is_a64(env)) {
> +        env->pc = tcg_ctx.gen_opc_pc[pc_pos];
> +    } else {
> +        env->regs[15] = tcg_ctx.gen_opc_pc[pc_pos];
> +    }
>      env->condexec_bits = gen_opc_condexec_bits[pc_pos];
>  }
> --
> 1.6.0.2
>
>
Alexander Graf March 6, 2013, 9:36 a.m. UTC | #2
Am 06.03.2013 um 08:11 schrieb Laurent Desnogues <laurent.desnogues@gmail.com>:

> On Wed, Mar 6, 2013 at 3:01 AM, Alexander Graf <agraf@suse.de> wrote:
>> This patch adds all the prerequisites for AArch64 support that didn't
>> fit into split up patches. It extends important bits in the core cpu
>> headers to also take AArch64 mode into account.
>> 
>> Signed-off-by: Alexander Graf <agraf@suse.de>
>> ---
>> include/elf.h          |    2 +
>> target-arm/cpu.h       |  103 ++++++++++++++++++++++++++++++++++++------------
>> target-arm/translate.c |   42 +++++++++++--------
>> 3 files changed, 103 insertions(+), 44 deletions(-)
>> 
>> diff --git a/include/elf.h b/include/elf.h
>> index a21ea53..0ff0ea6 100644
>> --- a/include/elf.h
>> +++ b/include/elf.h
>> @@ -109,6 +109,8 @@ typedef int64_t  Elf64_Sxword;
>> #define EM_OPENRISC     92        /* OpenCores OpenRISC */
>> 
>> #define EM_UNICORE32    110     /* UniCore32 */
>> +#define EM_AARCH64      183     /* ARM 64-bit architecture */
>> +
>> 
>> /*
>>  * This is an interim value that we will use until the committee comes
>> diff --git a/target-arm/cpu.h b/target-arm/cpu.h
>> index c28a0d9..ec292c9 100644
>> --- a/target-arm/cpu.h
>> +++ b/target-arm/cpu.h
>> @@ -19,13 +19,19 @@
>> #ifndef CPU_ARM_H
>> #define CPU_ARM_H
>> 
>> -#define TARGET_LONG_BITS 32
>> +#include "config.h"
>> 
>> -#define ELF_MACHINE    EM_ARM
>> +#if defined (TARGET_ARM64)
>> +  /* AArch64 definitions */
>> +#  define TARGET_LONG_BITS 64
>> +#  define ELF_MACHINE  EM_AARCH64
>> +#else
>> +#  define TARGET_LONG_BITS 32
>> +#  define ELF_MACHINE  EM_ARM
>> +#endif
>> 
>> #define CPUArchState struct CPUARMState
>> 
>> -#include "config.h"
>> #include "qemu-common.h"
>> #include "exec/cpu-defs.h"
>> 
>> @@ -79,6 +85,13 @@ struct arm_boot_info;
>> typedef struct CPUARMState {
>>     /* Regs for current mode.  */
>>     uint32_t regs[16];
>> +
>> +    /* Regs for A64 mode.  */
>> +    uint64_t xregs[32];
> 
> I'm not sure it makes sense to allocate space for xregs[31].
> If it is the zero register then you would anyway have special
> cases in translation code to discard writes to reg 31 and so
> it could be argued you could also special case reads from
> reg 31 (and you should so that the optimizer knows it's zero).
> 
> Perhaps you could use xregs[31] as SP, which after all is
> a more "regular" register than xzr.

Sp is a separate env field in my patch set. So yeah, I should just drop xregs[31] and always special case it I suppose. That's the best way to avoid accidents I hope :)

Alex

> 
> 
> Laurent
> 
>> +    uint64_t pc;
>> +    uint64_t sp;
>> +    uint32_t pstate;
>> +
>>     /* Frequently accessed CPSR bits are stored separately for efficiency.
>>        This contains all the other bits.  Use cpsr_{read,write} to access
>>        the whole CPSR.  */
>> @@ -154,6 +167,11 @@ typedef struct CPUARMState {
>>         uint32_t c15_power_control; /* power control */
>>     } cp15;
>> 
>> +    /* System registers (AArch64) */
>> +    struct {
>> +        uint64_t tpidr_el0;
>> +    } sr;
>> +
>>     struct {
>>         uint32_t other_sp;
>>         uint32_t vecbase;
>> @@ -170,7 +188,7 @@ typedef struct CPUARMState {
>> 
>>     /* VFP coprocessor state.  */
>>     struct {
>> -        float64 regs[32];
>> +        float64 regs[64];
>> 
>>         uint32_t xregs[16];
>>         /* We store these fpcsr fields separately for convenience.  */
>> @@ -241,6 +259,24 @@ int bank_number(int mode);
>> void switch_mode(CPUARMState *, int);
>> uint32_t do_arm_semihosting(CPUARMState *env);
>> 
>> +static inline bool is_a64(CPUARMState *env)
>> +{
>> +#ifdef TARGET_ARM64
>> +    return true;
>> +#else
>> +    return false;
>> +#endif
>> +}
>> +
>> +#define PSTATE_N_SHIFT 3
>> +#define PSTATE_N  (1 << PSTATE_N_SHIFT)
>> +#define PSTATE_Z_SHIFT 2
>> +#define PSTATE_Z  (1 << PSTATE_Z_SHIFT)
>> +#define PSTATE_C_SHIFT 1
>> +#define PSTATE_C  (1 << PSTATE_C_SHIFT)
>> +#define PSTATE_V_SHIFT 0
>> +#define PSTATE_V  (1 << PSTATE_V_SHIFT)
>> +
>> /* 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.  */
>> @@ -624,8 +660,13 @@ static inline bool cp_access_ok(CPUARMState *env,
>> #define TARGET_PAGE_BITS 10
>> #endif
>> 
>> -#define TARGET_PHYS_ADDR_SPACE_BITS 40
>> -#define TARGET_VIRT_ADDR_SPACE_BITS 32
>> +#if defined (TARGET_ARM64)
>> +#  define TARGET_PHYS_ADDR_SPACE_BITS 64
>> +#  define TARGET_VIRT_ADDR_SPACE_BITS 64
>> +#else
>> +#  define TARGET_PHYS_ADDR_SPACE_BITS 40
>> +#  define TARGET_VIRT_ADDR_SPACE_BITS 32
>> +#endif
>> 
>> static inline CPUARMState *cpu_init(const char *cpu_model)
>> {
>> @@ -699,25 +740,31 @@ static inline void cpu_clone_regs(CPUARMState *env, target_ulong newsp)
>> static inline void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc,
>>                                         target_ulong *cs_base, int *flags)
>> {
>> -    int privmode;
>> -    *pc = env->regs[15];
>> -    *cs_base = 0;
>> -    *flags = (env->thumb << ARM_TBFLAG_THUMB_SHIFT)
>> -        | (env->vfp.vec_len << ARM_TBFLAG_VECLEN_SHIFT)
>> -        | (env->vfp.vec_stride << ARM_TBFLAG_VECSTRIDE_SHIFT)
>> -        | (env->condexec_bits << ARM_TBFLAG_CONDEXEC_SHIFT)
>> -        | (env->bswap_code << ARM_TBFLAG_BSWAP_CODE_SHIFT);
>> -    if (arm_feature(env, ARM_FEATURE_M)) {
>> -        privmode = !((env->v7m.exception == 0) && (env->v7m.control & 1));
>> +    if (is_a64(env)) {
>> +        *pc = env->pc;
>> +        *flags = 0;
>>     } else {
>> -        privmode = (env->uncached_cpsr & CPSR_M) != ARM_CPU_MODE_USR;
>> -    }
>> -    if (privmode) {
>> -        *flags |= ARM_TBFLAG_PRIV_MASK;
>> -    }
>> -    if (env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30)) {
>> -        *flags |= ARM_TBFLAG_VFPEN_MASK;
>> +        int privmode;
>> +        *pc = env->regs[15];
>> +        *flags = (env->thumb << ARM_TBFLAG_THUMB_SHIFT)
>> +            | (env->vfp.vec_len << ARM_TBFLAG_VECLEN_SHIFT)
>> +            | (env->vfp.vec_stride << ARM_TBFLAG_VECSTRIDE_SHIFT)
>> +            | (env->condexec_bits << ARM_TBFLAG_CONDEXEC_SHIFT)
>> +            | (env->bswap_code << ARM_TBFLAG_BSWAP_CODE_SHIFT);
>> +        if (arm_feature(env, ARM_FEATURE_M)) {
>> +            privmode = !((env->v7m.exception == 0) && (env->v7m.control & 1));
>> +        } else {
>> +            privmode = (env->uncached_cpsr & CPSR_M) != ARM_CPU_MODE_USR;
>> +        }
>> +        if (privmode) {
>> +            *flags |= ARM_TBFLAG_PRIV_MASK;
>> +        }
>> +        if (env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30)) {
>> +            *flags |= ARM_TBFLAG_VFPEN_MASK;
>> +        }
>>     }
>> +
>> +    *cs_base = 0;
>> }
>> 
>> static inline bool cpu_has_work(CPUState *cpu)
>> @@ -732,11 +779,15 @@ static inline bool cpu_has_work(CPUState *cpu)
>> 
>> static inline void cpu_pc_from_tb(CPUARMState *env, TranslationBlock *tb)
>> {
>> -    env->regs[15] = tb->pc;
>> +    if (is_a64(env)) {
>> +        env->pc = tb->pc;
>> +    } else {
>> +        env->regs[15] = tb->pc;
>> +    }
>> }
>> 
>> /* Load an instruction and return it in the standard little-endian order */
>> -static inline uint32_t arm_ldl_code(CPUARMState *env, uint32_t addr,
>> +static inline uint32_t arm_ldl_code(CPUARMState *env, target_ulong addr,
>>                                     bool do_swap)
>> {
>>     uint32_t insn = cpu_ldl_code(env, addr);
>> @@ -747,7 +798,7 @@ static inline uint32_t arm_ldl_code(CPUARMState *env, uint32_t addr,
>> }
>> 
>> /* Ditto, for a halfword (Thumb) instruction */
>> -static inline uint16_t arm_lduw_code(CPUARMState *env, uint32_t addr,
>> +static inline uint16_t arm_lduw_code(CPUARMState *env, target_ulong addr,
>>                                      bool do_swap)
>> {
>>     uint16_t insn = cpu_lduw_code(env, addr);
>> diff --git a/target-arm/translate.c b/target-arm/translate.c
>> index f8838f3..de04a0c 100644
>> --- a/target-arm/translate.c
>> +++ b/target-arm/translate.c
>> @@ -9749,7 +9749,7 @@ static inline void gen_intermediate_code_internal(CPUARMState *env,
>>     uint16_t *gen_opc_end;
>>     int j, lj;
>>     target_ulong pc_start;
>> -    uint32_t next_page_start;
>> +    target_ulong next_page_start;
>>     int num_insns;
>>     int max_insns;
>> 
>> @@ -9833,24 +9833,26 @@ static inline void gen_intermediate_code_internal(CPUARMState *env,
>>         store_cpu_field(tmp, condexec_bits);
>>       }
>>     do {
>> +        if (!is_a64(env)) {
>> #ifdef CONFIG_USER_ONLY
>> -        /* Intercept jump to the magic kernel page.  */
>> -        if (dc->pc >= 0xffff0000) {
>> -            /* We always get here via a jump, so know we are not in a
>> -               conditional execution block.  */
>> -            gen_exception(EXCP_KERNEL_TRAP);
>> -            dc->is_jmp = DISAS_UPDATE;
>> -            break;
>> -        }
>> +            /* Intercept jump to the magic kernel page.  */
>> +            if (dc->pc >= 0xffff0000) {
>> +                /* We always get here via a jump, so know we are not in a
>> +                   conditional execution block.  */
>> +                gen_exception(EXCP_KERNEL_TRAP);
>> +                dc->is_jmp = DISAS_UPDATE;
>> +                break;
>> +            }
>> #else
>> -        if (dc->pc >= 0xfffffff0 && IS_M(env)) {
>> -            /* We always get here via a jump, so know we are not in a
>> -               conditional execution block.  */
>> -            gen_exception(EXCP_EXCEPTION_EXIT);
>> -            dc->is_jmp = DISAS_UPDATE;
>> -            break;
>> -        }
>> +            if (dc->pc >= 0xfffffff0 && IS_M(env)) {
>> +                /* We always get here via a jump, so know we are not in a
>> +                   conditional execution block.  */
>> +                gen_exception(EXCP_EXCEPTION_EXIT);
>> +                dc->is_jmp = DISAS_UPDATE;
>> +                break;
>> +            }
>> #endif
>> +        }
>> 
>>         if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) {
>>             QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
>> @@ -9904,7 +9906,7 @@ static inline void gen_intermediate_code_internal(CPUARMState *env,
>>         }
>> 
>>         if (tcg_check_temp_count()) {
>> -            fprintf(stderr, "TCG temporary leak before %08x\n", dc->pc);
>> +            fprintf(stderr, "TCG temporary leak before "TARGET_FMT_lx"\n", dc->pc);
>>         }
>> 
>>         /* Translation stops when a conditional branch is encountered.
>> @@ -10074,6 +10076,10 @@ void cpu_dump_state(CPUARMState *env, FILE *f, fprintf_function cpu_fprintf,
>> 
>> void restore_state_to_opc(CPUARMState *env, TranslationBlock *tb, int pc_pos)
>> {
>> -    env->regs[15] = tcg_ctx.gen_opc_pc[pc_pos];
>> +    if (is_a64(env)) {
>> +        env->pc = tcg_ctx.gen_opc_pc[pc_pos];
>> +    } else {
>> +        env->regs[15] = tcg_ctx.gen_opc_pc[pc_pos];
>> +    }
>>     env->condexec_bits = gen_opc_condexec_bits[pc_pos];
>> }
>> --
>> 1.6.0.2
>> 
>>
Laurent Desnogues March 6, 2013, 9:46 a.m. UTC | #3
On Wed, Mar 6, 2013 at 10:36 AM, Alexander Graf <agraf@suse.de> wrote:
>
>
> Am 06.03.2013 um 08:11 schrieb Laurent Desnogues <laurent.desnogues@gmail.com>:
>
>> On Wed, Mar 6, 2013 at 3:01 AM, Alexander Graf <agraf@suse.de> wrote:
>>> This patch adds all the prerequisites for AArch64 support that didn't
>>> fit into split up patches. It extends important bits in the core cpu
>>> headers to also take AArch64 mode into account.
>>>
>>> Signed-off-by: Alexander Graf <agraf@suse.de>
>>> ---
>>> include/elf.h          |    2 +
>>> target-arm/cpu.h       |  103 ++++++++++++++++++++++++++++++++++++------------
>>> target-arm/translate.c |   42 +++++++++++--------
>>> 3 files changed, 103 insertions(+), 44 deletions(-)
>>>
>>> diff --git a/include/elf.h b/include/elf.h
>>> index a21ea53..0ff0ea6 100644
>>> --- a/include/elf.h
>>> +++ b/include/elf.h
>>> @@ -109,6 +109,8 @@ typedef int64_t  Elf64_Sxword;
>>> #define EM_OPENRISC     92        /* OpenCores OpenRISC */
>>>
>>> #define EM_UNICORE32    110     /* UniCore32 */
>>> +#define EM_AARCH64      183     /* ARM 64-bit architecture */
>>> +
>>>
>>> /*
>>>  * This is an interim value that we will use until the committee comes
>>> diff --git a/target-arm/cpu.h b/target-arm/cpu.h
>>> index c28a0d9..ec292c9 100644
>>> --- a/target-arm/cpu.h
>>> +++ b/target-arm/cpu.h
>>> @@ -19,13 +19,19 @@
>>> #ifndef CPU_ARM_H
>>> #define CPU_ARM_H
>>>
>>> -#define TARGET_LONG_BITS 32
>>> +#include "config.h"
>>>
>>> -#define ELF_MACHINE    EM_ARM
>>> +#if defined (TARGET_ARM64)
>>> +  /* AArch64 definitions */
>>> +#  define TARGET_LONG_BITS 64
>>> +#  define ELF_MACHINE  EM_AARCH64
>>> +#else
>>> +#  define TARGET_LONG_BITS 32
>>> +#  define ELF_MACHINE  EM_ARM
>>> +#endif
>>>
>>> #define CPUArchState struct CPUARMState
>>>
>>> -#include "config.h"
>>> #include "qemu-common.h"
>>> #include "exec/cpu-defs.h"
>>>
>>> @@ -79,6 +85,13 @@ struct arm_boot_info;
>>> typedef struct CPUARMState {
>>>     /* Regs for current mode.  */
>>>     uint32_t regs[16];
>>> +
>>> +    /* Regs for A64 mode.  */
>>> +    uint64_t xregs[32];
>>
>> I'm not sure it makes sense to allocate space for xregs[31].
>> If it is the zero register then you would anyway have special
>> cases in translation code to discard writes to reg 31 and so
>> it could be argued you could also special case reads from
>> reg 31 (and you should so that the optimizer knows it's zero).
>>
>> Perhaps you could use xregs[31] as SP, which after all is
>> a more "regular" register than xzr.
>
> Sp is a separate env field in my patch set. So yeah, I should just drop xregs[31] and always special case it I suppose. That's the best way to avoid accidents I hope :)

I think that using xregs[31] as sp would ease code generation.
No need to special case both xzr and sp.

OTOH if you only declare 31 regs and you access xregs[31]
by accident you'd read/write pc which might help uncover
bugs faster, though I wouldn't want to use that "feature" to
ease development :-)


Laurent

> Alex
>
>>
>>
>> Laurent
>>
>>> +    uint64_t pc;
>>> +    uint64_t sp;
>>> +    uint32_t pstate;
>>> +
>>>     /* Frequently accessed CPSR bits are stored separately for efficiency.
>>>        This contains all the other bits.  Use cpsr_{read,write} to access
>>>        the whole CPSR.  */
>>> @@ -154,6 +167,11 @@ typedef struct CPUARMState {
>>>         uint32_t c15_power_control; /* power control */
>>>     } cp15;
>>>
>>> +    /* System registers (AArch64) */
>>> +    struct {
>>> +        uint64_t tpidr_el0;
>>> +    } sr;
>>> +
>>>     struct {
>>>         uint32_t other_sp;
>>>         uint32_t vecbase;
>>> @@ -170,7 +188,7 @@ typedef struct CPUARMState {
>>>
>>>     /* VFP coprocessor state.  */
>>>     struct {
>>> -        float64 regs[32];
>>> +        float64 regs[64];
>>>
>>>         uint32_t xregs[16];
>>>         /* We store these fpcsr fields separately for convenience.  */
>>> @@ -241,6 +259,24 @@ int bank_number(int mode);
>>> void switch_mode(CPUARMState *, int);
>>> uint32_t do_arm_semihosting(CPUARMState *env);
>>>
>>> +static inline bool is_a64(CPUARMState *env)
>>> +{
>>> +#ifdef TARGET_ARM64
>>> +    return true;
>>> +#else
>>> +    return false;
>>> +#endif
>>> +}
>>> +
>>> +#define PSTATE_N_SHIFT 3
>>> +#define PSTATE_N  (1 << PSTATE_N_SHIFT)
>>> +#define PSTATE_Z_SHIFT 2
>>> +#define PSTATE_Z  (1 << PSTATE_Z_SHIFT)
>>> +#define PSTATE_C_SHIFT 1
>>> +#define PSTATE_C  (1 << PSTATE_C_SHIFT)
>>> +#define PSTATE_V_SHIFT 0
>>> +#define PSTATE_V  (1 << PSTATE_V_SHIFT)
>>> +
>>> /* 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.  */
>>> @@ -624,8 +660,13 @@ static inline bool cp_access_ok(CPUARMState *env,
>>> #define TARGET_PAGE_BITS 10
>>> #endif
>>>
>>> -#define TARGET_PHYS_ADDR_SPACE_BITS 40
>>> -#define TARGET_VIRT_ADDR_SPACE_BITS 32
>>> +#if defined (TARGET_ARM64)
>>> +#  define TARGET_PHYS_ADDR_SPACE_BITS 64
>>> +#  define TARGET_VIRT_ADDR_SPACE_BITS 64
>>> +#else
>>> +#  define TARGET_PHYS_ADDR_SPACE_BITS 40
>>> +#  define TARGET_VIRT_ADDR_SPACE_BITS 32
>>> +#endif
>>>
>>> static inline CPUARMState *cpu_init(const char *cpu_model)
>>> {
>>> @@ -699,25 +740,31 @@ static inline void cpu_clone_regs(CPUARMState *env, target_ulong newsp)
>>> static inline void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc,
>>>                                         target_ulong *cs_base, int *flags)
>>> {
>>> -    int privmode;
>>> -    *pc = env->regs[15];
>>> -    *cs_base = 0;
>>> -    *flags = (env->thumb << ARM_TBFLAG_THUMB_SHIFT)
>>> -        | (env->vfp.vec_len << ARM_TBFLAG_VECLEN_SHIFT)
>>> -        | (env->vfp.vec_stride << ARM_TBFLAG_VECSTRIDE_SHIFT)
>>> -        | (env->condexec_bits << ARM_TBFLAG_CONDEXEC_SHIFT)
>>> -        | (env->bswap_code << ARM_TBFLAG_BSWAP_CODE_SHIFT);
>>> -    if (arm_feature(env, ARM_FEATURE_M)) {
>>> -        privmode = !((env->v7m.exception == 0) && (env->v7m.control & 1));
>>> +    if (is_a64(env)) {
>>> +        *pc = env->pc;
>>> +        *flags = 0;
>>>     } else {
>>> -        privmode = (env->uncached_cpsr & CPSR_M) != ARM_CPU_MODE_USR;
>>> -    }
>>> -    if (privmode) {
>>> -        *flags |= ARM_TBFLAG_PRIV_MASK;
>>> -    }
>>> -    if (env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30)) {
>>> -        *flags |= ARM_TBFLAG_VFPEN_MASK;
>>> +        int privmode;
>>> +        *pc = env->regs[15];
>>> +        *flags = (env->thumb << ARM_TBFLAG_THUMB_SHIFT)
>>> +            | (env->vfp.vec_len << ARM_TBFLAG_VECLEN_SHIFT)
>>> +            | (env->vfp.vec_stride << ARM_TBFLAG_VECSTRIDE_SHIFT)
>>> +            | (env->condexec_bits << ARM_TBFLAG_CONDEXEC_SHIFT)
>>> +            | (env->bswap_code << ARM_TBFLAG_BSWAP_CODE_SHIFT);
>>> +        if (arm_feature(env, ARM_FEATURE_M)) {
>>> +            privmode = !((env->v7m.exception == 0) && (env->v7m.control & 1));
>>> +        } else {
>>> +            privmode = (env->uncached_cpsr & CPSR_M) != ARM_CPU_MODE_USR;
>>> +        }
>>> +        if (privmode) {
>>> +            *flags |= ARM_TBFLAG_PRIV_MASK;
>>> +        }
>>> +        if (env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30)) {
>>> +            *flags |= ARM_TBFLAG_VFPEN_MASK;
>>> +        }
>>>     }
>>> +
>>> +    *cs_base = 0;
>>> }
>>>
>>> static inline bool cpu_has_work(CPUState *cpu)
>>> @@ -732,11 +779,15 @@ static inline bool cpu_has_work(CPUState *cpu)
>>>
>>> static inline void cpu_pc_from_tb(CPUARMState *env, TranslationBlock *tb)
>>> {
>>> -    env->regs[15] = tb->pc;
>>> +    if (is_a64(env)) {
>>> +        env->pc = tb->pc;
>>> +    } else {
>>> +        env->regs[15] = tb->pc;
>>> +    }
>>> }
>>>
>>> /* Load an instruction and return it in the standard little-endian order */
>>> -static inline uint32_t arm_ldl_code(CPUARMState *env, uint32_t addr,
>>> +static inline uint32_t arm_ldl_code(CPUARMState *env, target_ulong addr,
>>>                                     bool do_swap)
>>> {
>>>     uint32_t insn = cpu_ldl_code(env, addr);
>>> @@ -747,7 +798,7 @@ static inline uint32_t arm_ldl_code(CPUARMState *env, uint32_t addr,
>>> }
>>>
>>> /* Ditto, for a halfword (Thumb) instruction */
>>> -static inline uint16_t arm_lduw_code(CPUARMState *env, uint32_t addr,
>>> +static inline uint16_t arm_lduw_code(CPUARMState *env, target_ulong addr,
>>>                                      bool do_swap)
>>> {
>>>     uint16_t insn = cpu_lduw_code(env, addr);
>>> diff --git a/target-arm/translate.c b/target-arm/translate.c
>>> index f8838f3..de04a0c 100644
>>> --- a/target-arm/translate.c
>>> +++ b/target-arm/translate.c
>>> @@ -9749,7 +9749,7 @@ static inline void gen_intermediate_code_internal(CPUARMState *env,
>>>     uint16_t *gen_opc_end;
>>>     int j, lj;
>>>     target_ulong pc_start;
>>> -    uint32_t next_page_start;
>>> +    target_ulong next_page_start;
>>>     int num_insns;
>>>     int max_insns;
>>>
>>> @@ -9833,24 +9833,26 @@ static inline void gen_intermediate_code_internal(CPUARMState *env,
>>>         store_cpu_field(tmp, condexec_bits);
>>>       }
>>>     do {
>>> +        if (!is_a64(env)) {
>>> #ifdef CONFIG_USER_ONLY
>>> -        /* Intercept jump to the magic kernel page.  */
>>> -        if (dc->pc >= 0xffff0000) {
>>> -            /* We always get here via a jump, so know we are not in a
>>> -               conditional execution block.  */
>>> -            gen_exception(EXCP_KERNEL_TRAP);
>>> -            dc->is_jmp = DISAS_UPDATE;
>>> -            break;
>>> -        }
>>> +            /* Intercept jump to the magic kernel page.  */
>>> +            if (dc->pc >= 0xffff0000) {
>>> +                /* We always get here via a jump, so know we are not in a
>>> +                   conditional execution block.  */
>>> +                gen_exception(EXCP_KERNEL_TRAP);
>>> +                dc->is_jmp = DISAS_UPDATE;
>>> +                break;
>>> +            }
>>> #else
>>> -        if (dc->pc >= 0xfffffff0 && IS_M(env)) {
>>> -            /* We always get here via a jump, so know we are not in a
>>> -               conditional execution block.  */
>>> -            gen_exception(EXCP_EXCEPTION_EXIT);
>>> -            dc->is_jmp = DISAS_UPDATE;
>>> -            break;
>>> -        }
>>> +            if (dc->pc >= 0xfffffff0 && IS_M(env)) {
>>> +                /* We always get here via a jump, so know we are not in a
>>> +                   conditional execution block.  */
>>> +                gen_exception(EXCP_EXCEPTION_EXIT);
>>> +                dc->is_jmp = DISAS_UPDATE;
>>> +                break;
>>> +            }
>>> #endif
>>> +        }
>>>
>>>         if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) {
>>>             QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
>>> @@ -9904,7 +9906,7 @@ static inline void gen_intermediate_code_internal(CPUARMState *env,
>>>         }
>>>
>>>         if (tcg_check_temp_count()) {
>>> -            fprintf(stderr, "TCG temporary leak before %08x\n", dc->pc);
>>> +            fprintf(stderr, "TCG temporary leak before "TARGET_FMT_lx"\n", dc->pc);
>>>         }
>>>
>>>         /* Translation stops when a conditional branch is encountered.
>>> @@ -10074,6 +10076,10 @@ void cpu_dump_state(CPUARMState *env, FILE *f, fprintf_function cpu_fprintf,
>>>
>>> void restore_state_to_opc(CPUARMState *env, TranslationBlock *tb, int pc_pos)
>>> {
>>> -    env->regs[15] = tcg_ctx.gen_opc_pc[pc_pos];
>>> +    if (is_a64(env)) {
>>> +        env->pc = tcg_ctx.gen_opc_pc[pc_pos];
>>> +    } else {
>>> +        env->regs[15] = tcg_ctx.gen_opc_pc[pc_pos];
>>> +    }
>>>     env->condexec_bits = gen_opc_condexec_bits[pc_pos];
>>> }
>>> --
>>> 1.6.0.2
>>>
>>>
Peter Maydell March 8, 2013, 2:27 a.m. UTC | #4
On 6 March 2013 10:01, Alexander Graf <agraf@suse.de> wrote:
> @@ -699,25 +740,31 @@ static inline void cpu_clone_regs(CPUARMState *env, target_ulong newsp)
>  static inline void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc,
>                                          target_ulong *cs_base, int *flags)
>  {
> -    int privmode;
> -    *pc = env->regs[15];
> -    *cs_base = 0;
> -    *flags = (env->thumb << ARM_TBFLAG_THUMB_SHIFT)
> -        | (env->vfp.vec_len << ARM_TBFLAG_VECLEN_SHIFT)
> -        | (env->vfp.vec_stride << ARM_TBFLAG_VECSTRIDE_SHIFT)
> -        | (env->condexec_bits << ARM_TBFLAG_CONDEXEC_SHIFT)
> -        | (env->bswap_code << ARM_TBFLAG_BSWAP_CODE_SHIFT);
> -    if (arm_feature(env, ARM_FEATURE_M)) {
> -        privmode = !((env->v7m.exception == 0) && (env->v7m.control & 1));
> +    if (is_a64(env)) {
> +        *pc = env->pc;
> +        *flags = 0;
>      } else {

This isn't going to work for system emulation mode. We need a bit in the
tb->flags which is "CPU is in AArch64 state". I think most of the existing
TB flag bits will end up zero when in AArch64, but for simplicity I
think we should just define that the flag word layout is the same in
both cases.

> -        privmode = (env->uncached_cpsr & CPSR_M) != ARM_CPU_MODE_USR;
> -    }
> -    if (privmode) {
> -        *flags |= ARM_TBFLAG_PRIV_MASK;
> -    }
> -    if (env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30)) {
> -        *flags |= ARM_TBFLAG_VFPEN_MASK;
> +        int privmode;
> +        *pc = env->regs[15];
> +        *flags = (env->thumb << ARM_TBFLAG_THUMB_SHIFT)
> +            | (env->vfp.vec_len << ARM_TBFLAG_VECLEN_SHIFT)
> +            | (env->vfp.vec_stride << ARM_TBFLAG_VECSTRIDE_SHIFT)
> +            | (env->condexec_bits << ARM_TBFLAG_CONDEXEC_SHIFT)
> +            | (env->bswap_code << ARM_TBFLAG_BSWAP_CODE_SHIFT);
> +        if (arm_feature(env, ARM_FEATURE_M)) {
> +            privmode = !((env->v7m.exception == 0) && (env->v7m.control & 1));
> +        } else {
> +            privmode = (env->uncached_cpsr & CPSR_M) != ARM_CPU_MODE_USR;
> +        }
> +        if (privmode) {
> +            *flags |= ARM_TBFLAG_PRIV_MASK;
> +        }
> +        if (env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30)) {
> +            *flags |= ARM_TBFLAG_VFPEN_MASK;
> +        }
>      }
> +
> +    *cs_base = 0;
>  }
>
>  static inline bool cpu_has_work(CPUState *cpu)
> @@ -732,11 +779,15 @@ static inline bool cpu_has_work(CPUState *cpu)
>
>  static inline void cpu_pc_from_tb(CPUARMState *env, TranslationBlock *tb)
>  {
> -    env->regs[15] = tb->pc;
> +    if (is_a64(env)) {
> +        env->pc = tb->pc;
> +    } else {
> +        env->regs[15] = tb->pc;
> +    }

This should be based on the "is AArch64" tb->flags bit rather than the env
field I guess. (Though I think it is not going to be possible to get here
with tb->flags and is_a64(env) giving different answers.)

>  }
>
>  /* Load an instruction and return it in the standard little-endian order */
> -static inline uint32_t arm_ldl_code(CPUARMState *env, uint32_t addr,
> +static inline uint32_t arm_ldl_code(CPUARMState *env, target_ulong addr,
>                                      bool do_swap)
>  {
>      uint32_t insn = cpu_ldl_code(env, addr);
> @@ -747,7 +798,7 @@ static inline uint32_t arm_ldl_code(CPUARMState *env, uint32_t addr,
>  }
>
>  /* Ditto, for a halfword (Thumb) instruction */
> -static inline uint16_t arm_lduw_code(CPUARMState *env, uint32_t addr,
> +static inline uint16_t arm_lduw_code(CPUARMState *env, target_ulong addr,
>                                       bool do_swap)
>  {
>      uint16_t insn = cpu_lduw_code(env, addr);
> diff --git a/target-arm/translate.c b/target-arm/translate.c
> index f8838f3..de04a0c 100644
> --- a/target-arm/translate.c
> +++ b/target-arm/translate.c
> @@ -9749,7 +9749,7 @@ static inline void gen_intermediate_code_internal(CPUARMState *env,
>      uint16_t *gen_opc_end;
>      int j, lj;
>      target_ulong pc_start;
> -    uint32_t next_page_start;
> +    target_ulong next_page_start;
>      int num_insns;
>      int max_insns;
>
> @@ -9833,24 +9833,26 @@ static inline void gen_intermediate_code_internal(CPUARMState *env,
>          store_cpu_field(tmp, condexec_bits);
>        }
>      do {
> +        if (!is_a64(env)) {

Since we can only flip between AArch64 and AArch32 at exception boundaries
I think that the right place to do the 'if is_a64() { translate_a64_stuff() }'
check is outside the 'for each insn in the block' loop, not inside it.
At that point this code path is only executed for AArch32 and you don't need
this check.

>  #ifdef CONFIG_USER_ONLY
> -        /* Intercept jump to the magic kernel page.  */
> -        if (dc->pc >= 0xffff0000) {
> -            /* We always get here via a jump, so know we are not in a
> -               conditional execution block.  */
> -            gen_exception(EXCP_KERNEL_TRAP);
> -            dc->is_jmp = DISAS_UPDATE;
> -            break;
> -        }
> +            /* Intercept jump to the magic kernel page.  */
> +            if (dc->pc >= 0xffff0000) {
> +                /* We always get here via a jump, so know we are not in a
> +                   conditional execution block.  */
> +                gen_exception(EXCP_KERNEL_TRAP);
> +                dc->is_jmp = DISAS_UPDATE;
> +                break;
> +            }
>  #else
> -        if (dc->pc >= 0xfffffff0 && IS_M(env)) {
> -            /* We always get here via a jump, so know we are not in a
> -               conditional execution block.  */
> -            gen_exception(EXCP_EXCEPTION_EXIT);
> -            dc->is_jmp = DISAS_UPDATE;
> -            break;
> -        }
> +            if (dc->pc >= 0xfffffff0 && IS_M(env)) {
> +                /* We always get here via a jump, so know we are not in a
> +                   conditional execution block.  */
> +                gen_exception(EXCP_EXCEPTION_EXIT);
> +                dc->is_jmp = DISAS_UPDATE;
> +                break;
> +            }
>  #endif
> +        }
>
>          if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) {
>              QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
> @@ -9904,7 +9906,7 @@ static inline void gen_intermediate_code_internal(CPUARMState *env,
>          }
>
>          if (tcg_check_temp_count()) {
> -            fprintf(stderr, "TCG temporary leak before %08x\n", dc->pc);
> +            fprintf(stderr, "TCG temporary leak before "TARGET_FMT_lx"\n", dc->pc);
>          }
>
>          /* Translation stops when a conditional branch is encountered.
> @@ -10074,6 +10076,10 @@ void cpu_dump_state(CPUARMState *env, FILE *f, fprintf_function cpu_fprintf,
>
>  void restore_state_to_opc(CPUARMState *env, TranslationBlock *tb, int pc_pos)
>  {
> -    env->regs[15] = tcg_ctx.gen_opc_pc[pc_pos];
> +    if (is_a64(env)) {
> +        env->pc = tcg_ctx.gen_opc_pc[pc_pos];
> +    } else {
> +        env->regs[15] = tcg_ctx.gen_opc_pc[pc_pos];
> +    }
>      env->condexec_bits = gen_opc_condexec_bits[pc_pos];
>  }
> --
> 1.6.0.2
>

-- PMM
diff mbox

Patch

diff --git a/include/elf.h b/include/elf.h
index a21ea53..0ff0ea6 100644
--- a/include/elf.h
+++ b/include/elf.h
@@ -109,6 +109,8 @@  typedef int64_t  Elf64_Sxword;
 #define EM_OPENRISC     92        /* OpenCores OpenRISC */
 
 #define EM_UNICORE32    110     /* UniCore32 */
+#define EM_AARCH64      183     /* ARM 64-bit architecture */
+
 
 /*
  * This is an interim value that we will use until the committee comes
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index c28a0d9..ec292c9 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -19,13 +19,19 @@ 
 #ifndef CPU_ARM_H
 #define CPU_ARM_H
 
-#define TARGET_LONG_BITS 32
+#include "config.h"
 
-#define ELF_MACHINE	EM_ARM
+#if defined (TARGET_ARM64)
+  /* AArch64 definitions */
+#  define TARGET_LONG_BITS 64
+#  define ELF_MACHINE	EM_AARCH64
+#else
+#  define TARGET_LONG_BITS 32
+#  define ELF_MACHINE	EM_ARM
+#endif
 
 #define CPUArchState struct CPUARMState
 
-#include "config.h"
 #include "qemu-common.h"
 #include "exec/cpu-defs.h"
 
@@ -79,6 +85,13 @@  struct arm_boot_info;
 typedef struct CPUARMState {
     /* Regs for current mode.  */
     uint32_t regs[16];
+
+    /* Regs for A64 mode.  */
+    uint64_t xregs[32];
+    uint64_t pc;
+    uint64_t sp;
+    uint32_t pstate;
+
     /* Frequently accessed CPSR bits are stored separately for efficiency.
        This contains all the other bits.  Use cpsr_{read,write} to access
        the whole CPSR.  */
@@ -154,6 +167,11 @@  typedef struct CPUARMState {
         uint32_t c15_power_control; /* power control */
     } cp15;
 
+    /* System registers (AArch64) */
+    struct {
+        uint64_t tpidr_el0;
+    } sr;
+
     struct {
         uint32_t other_sp;
         uint32_t vecbase;
@@ -170,7 +188,7 @@  typedef struct CPUARMState {
 
     /* VFP coprocessor state.  */
     struct {
-        float64 regs[32];
+        float64 regs[64];
 
         uint32_t xregs[16];
         /* We store these fpcsr fields separately for convenience.  */
@@ -241,6 +259,24 @@  int bank_number(int mode);
 void switch_mode(CPUARMState *, int);
 uint32_t do_arm_semihosting(CPUARMState *env);
 
+static inline bool is_a64(CPUARMState *env)
+{
+#ifdef TARGET_ARM64
+    return true;
+#else
+    return false;
+#endif
+}
+
+#define PSTATE_N_SHIFT 3
+#define PSTATE_N  (1 << PSTATE_N_SHIFT)
+#define PSTATE_Z_SHIFT 2
+#define PSTATE_Z  (1 << PSTATE_Z_SHIFT)
+#define PSTATE_C_SHIFT 1
+#define PSTATE_C  (1 << PSTATE_C_SHIFT)
+#define PSTATE_V_SHIFT 0
+#define PSTATE_V  (1 << PSTATE_V_SHIFT)
+
 /* 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.  */
@@ -624,8 +660,13 @@  static inline bool cp_access_ok(CPUARMState *env,
 #define TARGET_PAGE_BITS 10
 #endif
 
-#define TARGET_PHYS_ADDR_SPACE_BITS 40
-#define TARGET_VIRT_ADDR_SPACE_BITS 32
+#if defined (TARGET_ARM64)
+#  define TARGET_PHYS_ADDR_SPACE_BITS 64
+#  define TARGET_VIRT_ADDR_SPACE_BITS 64
+#else
+#  define TARGET_PHYS_ADDR_SPACE_BITS 40
+#  define TARGET_VIRT_ADDR_SPACE_BITS 32
+#endif
 
 static inline CPUARMState *cpu_init(const char *cpu_model)
 {
@@ -699,25 +740,31 @@  static inline void cpu_clone_regs(CPUARMState *env, target_ulong newsp)
 static inline void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc,
                                         target_ulong *cs_base, int *flags)
 {
-    int privmode;
-    *pc = env->regs[15];
-    *cs_base = 0;
-    *flags = (env->thumb << ARM_TBFLAG_THUMB_SHIFT)
-        | (env->vfp.vec_len << ARM_TBFLAG_VECLEN_SHIFT)
-        | (env->vfp.vec_stride << ARM_TBFLAG_VECSTRIDE_SHIFT)
-        | (env->condexec_bits << ARM_TBFLAG_CONDEXEC_SHIFT)
-        | (env->bswap_code << ARM_TBFLAG_BSWAP_CODE_SHIFT);
-    if (arm_feature(env, ARM_FEATURE_M)) {
-        privmode = !((env->v7m.exception == 0) && (env->v7m.control & 1));
+    if (is_a64(env)) {
+        *pc = env->pc;
+        *flags = 0;
     } else {
-        privmode = (env->uncached_cpsr & CPSR_M) != ARM_CPU_MODE_USR;
-    }
-    if (privmode) {
-        *flags |= ARM_TBFLAG_PRIV_MASK;
-    }
-    if (env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30)) {
-        *flags |= ARM_TBFLAG_VFPEN_MASK;
+        int privmode;
+        *pc = env->regs[15];
+        *flags = (env->thumb << ARM_TBFLAG_THUMB_SHIFT)
+            | (env->vfp.vec_len << ARM_TBFLAG_VECLEN_SHIFT)
+            | (env->vfp.vec_stride << ARM_TBFLAG_VECSTRIDE_SHIFT)
+            | (env->condexec_bits << ARM_TBFLAG_CONDEXEC_SHIFT)
+            | (env->bswap_code << ARM_TBFLAG_BSWAP_CODE_SHIFT);
+        if (arm_feature(env, ARM_FEATURE_M)) {
+            privmode = !((env->v7m.exception == 0) && (env->v7m.control & 1));
+        } else {
+            privmode = (env->uncached_cpsr & CPSR_M) != ARM_CPU_MODE_USR;
+        }
+        if (privmode) {
+            *flags |= ARM_TBFLAG_PRIV_MASK;
+        }
+        if (env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30)) {
+            *flags |= ARM_TBFLAG_VFPEN_MASK;
+        }
     }
+
+    *cs_base = 0;
 }
 
 static inline bool cpu_has_work(CPUState *cpu)
@@ -732,11 +779,15 @@  static inline bool cpu_has_work(CPUState *cpu)
 
 static inline void cpu_pc_from_tb(CPUARMState *env, TranslationBlock *tb)
 {
-    env->regs[15] = tb->pc;
+    if (is_a64(env)) {
+        env->pc = tb->pc;
+    } else {
+        env->regs[15] = tb->pc;
+    }
 }
 
 /* Load an instruction and return it in the standard little-endian order */
-static inline uint32_t arm_ldl_code(CPUARMState *env, uint32_t addr,
+static inline uint32_t arm_ldl_code(CPUARMState *env, target_ulong addr,
                                     bool do_swap)
 {
     uint32_t insn = cpu_ldl_code(env, addr);
@@ -747,7 +798,7 @@  static inline uint32_t arm_ldl_code(CPUARMState *env, uint32_t addr,
 }
 
 /* Ditto, for a halfword (Thumb) instruction */
-static inline uint16_t arm_lduw_code(CPUARMState *env, uint32_t addr,
+static inline uint16_t arm_lduw_code(CPUARMState *env, target_ulong addr,
                                      bool do_swap)
 {
     uint16_t insn = cpu_lduw_code(env, addr);
diff --git a/target-arm/translate.c b/target-arm/translate.c
index f8838f3..de04a0c 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -9749,7 +9749,7 @@  static inline void gen_intermediate_code_internal(CPUARMState *env,
     uint16_t *gen_opc_end;
     int j, lj;
     target_ulong pc_start;
-    uint32_t next_page_start;
+    target_ulong next_page_start;
     int num_insns;
     int max_insns;
 
@@ -9833,24 +9833,26 @@  static inline void gen_intermediate_code_internal(CPUARMState *env,
         store_cpu_field(tmp, condexec_bits);
       }
     do {
+        if (!is_a64(env)) {
 #ifdef CONFIG_USER_ONLY
-        /* Intercept jump to the magic kernel page.  */
-        if (dc->pc >= 0xffff0000) {
-            /* We always get here via a jump, so know we are not in a
-               conditional execution block.  */
-            gen_exception(EXCP_KERNEL_TRAP);
-            dc->is_jmp = DISAS_UPDATE;
-            break;
-        }
+            /* Intercept jump to the magic kernel page.  */
+            if (dc->pc >= 0xffff0000) {
+                /* We always get here via a jump, so know we are not in a
+                   conditional execution block.  */
+                gen_exception(EXCP_KERNEL_TRAP);
+                dc->is_jmp = DISAS_UPDATE;
+                break;
+            }
 #else
-        if (dc->pc >= 0xfffffff0 && IS_M(env)) {
-            /* We always get here via a jump, so know we are not in a
-               conditional execution block.  */
-            gen_exception(EXCP_EXCEPTION_EXIT);
-            dc->is_jmp = DISAS_UPDATE;
-            break;
-        }
+            if (dc->pc >= 0xfffffff0 && IS_M(env)) {
+                /* We always get here via a jump, so know we are not in a
+                   conditional execution block.  */
+                gen_exception(EXCP_EXCEPTION_EXIT);
+                dc->is_jmp = DISAS_UPDATE;
+                break;
+            }
 #endif
+        }
 
         if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) {
             QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
@@ -9904,7 +9906,7 @@  static inline void gen_intermediate_code_internal(CPUARMState *env,
         }
 
         if (tcg_check_temp_count()) {
-            fprintf(stderr, "TCG temporary leak before %08x\n", dc->pc);
+            fprintf(stderr, "TCG temporary leak before "TARGET_FMT_lx"\n", dc->pc);
         }
 
         /* Translation stops when a conditional branch is encountered.
@@ -10074,6 +10076,10 @@  void cpu_dump_state(CPUARMState *env, FILE *f, fprintf_function cpu_fprintf,
 
 void restore_state_to_opc(CPUARMState *env, TranslationBlock *tb, int pc_pos)
 {
-    env->regs[15] = tcg_ctx.gen_opc_pc[pc_pos];
+    if (is_a64(env)) {
+        env->pc = tcg_ctx.gen_opc_pc[pc_pos];
+    } else {
+        env->regs[15] = tcg_ctx.gen_opc_pc[pc_pos];
+    }
     env->condexec_bits = gen_opc_condexec_bits[pc_pos];
 }