diff mbox

[v2,15/25] target-arm: A64: Implement minimal set of EL0-visible sysregs

Message ID 1387752607-23755-16-git-send-email-peter.maydell@linaro.org
State New
Headers show

Commit Message

Peter Maydell Dec. 22, 2013, 10:49 p.m. UTC
Implement an initial minimal set of EL0-visible system registers:
 * NZCV
 * FPCR
 * FPSR
 * CTR_EL0
 * DCZID_EL0

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
 target-arm/cpu.h           |  3 ++-
 target-arm/helper.c        | 61 ++++++++++++++++++++++++++++++++++++++++++++++
 target-arm/translate-a64.c | 52 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 115 insertions(+), 1 deletion(-)

Comments

Peter Crosthwaite Jan. 4, 2014, 2:34 a.m. UTC | #1
On Mon, Dec 23, 2013 at 8:49 AM, Peter Maydell <peter.maydell@linaro.org> wrote:
> Implement an initial minimal set of EL0-visible system registers:
>  * NZCV
>  * FPCR
>  * FPSR
>  * CTR_EL0
>  * DCZID_EL0
>
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> Reviewed-by: Richard Henderson <rth@twiddle.net>
> ---
>  target-arm/cpu.h           |  3 ++-
>  target-arm/helper.c        | 61 ++++++++++++++++++++++++++++++++++++++++++++++
>  target-arm/translate-a64.c | 52 +++++++++++++++++++++++++++++++++++++++
>  3 files changed, 115 insertions(+), 1 deletion(-)
>
> diff --git a/target-arm/cpu.h b/target-arm/cpu.h
> index 66490ce..1e0800e 100644
> --- a/target-arm/cpu.h
> +++ b/target-arm/cpu.h
> @@ -660,7 +660,8 @@ static inline uint64_t cpreg_to_kvm_id(uint32_t cpregid)
>  #define ARM_CP_IO 64
>  #define ARM_CP_NOP (ARM_CP_SPECIAL | (1 << 8))
>  #define ARM_CP_WFI (ARM_CP_SPECIAL | (2 << 8))
> -#define ARM_LAST_SPECIAL ARM_CP_WFI
> +#define ARM_CP_NZCV (ARM_CP_SPECIAL | (3 << 8))
> +#define ARM_LAST_SPECIAL ARM_CP_NZCV
>  /* Used only as a terminator for ARMCPRegInfo lists */
>  #define ARM_CP_SENTINEL 0xffff
>  /* Mask of only the flag bits in a type field */
> diff --git a/target-arm/helper.c b/target-arm/helper.c
> index 66214293..ca27c8e 100644
> --- a/target-arm/helper.c
> +++ b/target-arm/helper.c
> @@ -1560,6 +1560,64 @@ static const ARMCPRegInfo lpae_cp_reginfo[] = {
>      REGINFO_SENTINEL
>  };
>
> +static int aa64_fpcr_read(CPUARMState *env, const ARMCPRegInfo *ri,
> +                          uint64_t *value)
> +{
> +    *value = vfp_get_fpcr(env);
> +    return 0;
> +}
> +
> +static int aa64_fpcr_write(CPUARMState *env, const ARMCPRegInfo *ri,
> +                           uint64_t value)
> +{
> +    vfp_set_fpcr(env, value);
> +    return 0;
> +}
> +
> +static int aa64_fpsr_read(CPUARMState *env, const ARMCPRegInfo *ri,
> +                          uint64_t *value)
> +{
> +    *value = vfp_get_fpsr(env);
> +    return 0;
> +}
> +
> +static int aa64_fpsr_write(CPUARMState *env, const ARMCPRegInfo *ri,
> +                           uint64_t value)
> +{
> +    vfp_set_fpsr(env, value);
> +    return 0;
> +}
> +
> +static const ARMCPRegInfo v8_cp_reginfo[] = {
> +    /* Minimal set of EL0-visible registers. This will need to be expanded
> +     * significantly for system emulation of AArch64 CPUs.
> +     */
> +    { .name = "NZCV", .state = ARM_CP_STATE_AA64,
> +      .opc0 = 3, .opc1 = 3, .opc2 = 0, .crn = 4, .crm = 2,
> +      .access = PL0_RW, .type = ARM_CP_NZCV },
> +    {. name = "FPCR", .state = ARM_CP_STATE_AA64,
> +     .opc0 = 3, .opc1 = 3, .opc2 = 0, .crn = 4, .crm = 4,
> +     .access = PL0_RW, .readfn = aa64_fpcr_read, .writefn = aa64_fpcr_write },

Indentation and spacing looks inconsistent.

Regards,
Peter

> +    {. name = "FPSR", .state = ARM_CP_STATE_AA64,
> +     .opc0 = 3, .opc1 = 3, .opc2 = 1, .crn = 4, .crm = 4,
> +     .access = PL0_RW, .readfn = aa64_fpsr_read, .writefn = aa64_fpsr_write },
> +    /* This claims a 32 byte cacheline size for icache and dcache, VIPT icache.
> +     * It will eventually need to have a CPU-specified reset value.
> +     */
> +    { .name = "CTR_EL0", .state = ARM_CP_STATE_AA64,
> +      .opc0 = 3, .opc1 = 3, .opc2 = 1, .crn = 0, .crm = 0,
> +      .access = PL0_R, .type = ARM_CP_CONST,
> +      .resetvalue = 0x80030003 },
> +    /* Prohibit use of DC ZVA. OPTME: implement DC ZVA and allow its use.
> +     * For system mode the DZP bit here will need to be computed, not constant.
> +     */
> +    { .name = "DCZID_EL0", .state = ARM_CP_STATE_AA64,
> +      .opc0 = 3, .opc1 = 3, .opc2 = 7, .crn = 0, .crm = 0,
> +      .access = PL0_R, .type = ARM_CP_CONST,
> +      .resetvalue = 0x10 },
> +    REGINFO_SENTINEL
> +};
> +
>  static int sctlr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
>  {
>      env->cp15.c1_sys = value;
> @@ -1662,6 +1720,9 @@ void register_cp_regs_for_features(ARMCPU *cpu)
>      } else {
>          define_arm_cp_regs(cpu, not_v7_cp_reginfo);
>      }
> +    if (arm_feature(env, ARM_FEATURE_V8)) {
> +        define_arm_cp_regs(cpu, v8_cp_reginfo);
> +    }
>      if (arm_feature(env, ARM_FEATURE_MPU)) {
>          /* These are the MPU registers prior to PMSAv6. Any new
>           * PMSA core later than the ARM946 will require that we
> diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
> index 7a9ee82..c8ed799 100644
> --- a/target-arm/translate-a64.c
> +++ b/target-arm/translate-a64.c
> @@ -733,6 +733,50 @@ static void handle_msr_i(DisasContext *s, uint32_t insn,
>      unsupported_encoding(s, insn);
>  }
>
> +static void gen_get_nzcv(TCGv_i64 tcg_rt)
> +{
> +    TCGv_i32 tmp = tcg_temp_new_i32();
> +    TCGv_i32 nzcv = tcg_temp_new_i32();
> +
> +    /* build bit 31, N */
> +    tcg_gen_andi_i32(nzcv, cpu_NF, (1 << 31));
> +    /* build bit 30, Z */
> +    tcg_gen_setcondi_i32(TCG_COND_EQ, tmp, cpu_ZF, 0);
> +    tcg_gen_deposit_i32(nzcv, nzcv, tmp, 30, 1);
> +    /* build bit 29, C */
> +    tcg_gen_deposit_i32(nzcv, nzcv, cpu_CF, 29, 1);
> +    /* build bit 28, V */
> +    tcg_gen_shri_i32(tmp, cpu_VF, 31);
> +    tcg_gen_deposit_i32(nzcv, nzcv, tmp, 28, 1);
> +    /* generate result */
> +    tcg_gen_extu_i32_i64(tcg_rt, nzcv);
> +
> +    tcg_temp_free_i32(nzcv);
> +    tcg_temp_free_i32(tmp);
> +}
> +
> +static void gen_set_nzcv(TCGv_i64 tcg_rt)
> +
> +{
> +    TCGv_i32 nzcv = tcg_temp_new_i32();
> +
> +    /* take NZCV from R[t] */
> +    tcg_gen_trunc_i64_i32(nzcv, tcg_rt);
> +
> +    /* bit 31, N */
> +    tcg_gen_andi_i32(cpu_NF, nzcv, (1 << 31));
> +    /* bit 30, Z */
> +    tcg_gen_andi_i32(cpu_ZF, nzcv, (1 << 30));
> +    tcg_gen_setcondi_i32(TCG_COND_EQ, cpu_ZF, cpu_ZF, 0);
> +    /* bit 29, C */
> +    tcg_gen_andi_i32(cpu_CF, nzcv, (1 << 29));
> +    tcg_gen_shri_i32(cpu_CF, cpu_CF, 29);
> +    /* bit 28, V */
> +    tcg_gen_andi_i32(cpu_VF, nzcv, (1 << 28));
> +    tcg_gen_shli_i32(cpu_VF, cpu_VF, 3);
> +    tcg_temp_free_i32(nzcv);
> +}
> +
>  /* C5.6.129 MRS - move from system register
>   * C5.6.131 MSR (register) - move to system register
>   * C5.6.204 SYS
> @@ -767,6 +811,14 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread,
>      switch (ri->type & ~(ARM_CP_FLAG_MASK & ~ARM_CP_SPECIAL)) {
>      case ARM_CP_NOP:
>          return;
> +    case ARM_CP_NZCV:
> +        tcg_rt = cpu_reg(s, rt);
> +        if (isread) {
> +            gen_get_nzcv(tcg_rt);
> +        } else {
> +            gen_set_nzcv(tcg_rt);
> +        }
> +        return;
>      default:
>          break;
>      }
> --
> 1.8.5
>
>
Peter Maydell Jan. 4, 2014, 11:35 a.m. UTC | #2
On 4 January 2014 02:34, Peter Crosthwaite <peter.crosthwaite@xilinx.com> wrote:
> On Mon, Dec 23, 2013 at 8:49 AM, Peter Maydell <peter.maydell@linaro.org> wrote:
>> +static const ARMCPRegInfo v8_cp_reginfo[] = {
>> +    /* Minimal set of EL0-visible registers. This will need to be expanded
>> +     * significantly for system emulation of AArch64 CPUs.
>> +     */
>> +    { .name = "NZCV", .state = ARM_CP_STATE_AA64,
>> +      .opc0 = 3, .opc1 = 3, .opc2 = 0, .crn = 4, .crm = 2,
>> +      .access = PL0_RW, .type = ARM_CP_NZCV },
>> +    {. name = "FPCR", .state = ARM_CP_STATE_AA64,
>> +     .opc0 = 3, .opc1 = 3, .opc2 = 0, .crn = 4, .crm = 4,
>> +     .access = PL0_RW, .readfn = aa64_fpcr_read, .writefn = aa64_fpcr_write },
>
> Indentation and spacing looks inconsistent.

So it does (I didn't even know it was syntactically valid to leave
a space after the '.' like that...) . Will fix.

Do you mind if I don't do a respin just for this?

thanks
-- PMM
Peter Crosthwaite Jan. 4, 2014, 1:32 p.m. UTC | #3
On Mon, Dec 23, 2013 at 8:49 AM, Peter Maydell <peter.maydell@linaro.org> wrote:
> Implement an initial minimal set of EL0-visible system registers:
>  * NZCV
>  * FPCR
>  * FPSR
>  * CTR_EL0
>  * DCZID_EL0
>
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> Reviewed-by: Richard Henderson <rth@twiddle.net>
> ---
>  target-arm/cpu.h           |  3 ++-
>  target-arm/helper.c        | 61 ++++++++++++++++++++++++++++++++++++++++++++++
>  target-arm/translate-a64.c | 52 +++++++++++++++++++++++++++++++++++++++
>  3 files changed, 115 insertions(+), 1 deletion(-)
>
> diff --git a/target-arm/cpu.h b/target-arm/cpu.h
> index 66490ce..1e0800e 100644
> --- a/target-arm/cpu.h
> +++ b/target-arm/cpu.h
> @@ -660,7 +660,8 @@ static inline uint64_t cpreg_to_kvm_id(uint32_t cpregid)
>  #define ARM_CP_IO 64
>  #define ARM_CP_NOP (ARM_CP_SPECIAL | (1 << 8))
>  #define ARM_CP_WFI (ARM_CP_SPECIAL | (2 << 8))
> -#define ARM_LAST_SPECIAL ARM_CP_WFI
> +#define ARM_CP_NZCV (ARM_CP_SPECIAL | (3 << 8))
> +#define ARM_LAST_SPECIAL ARM_CP_NZCV
>  /* Used only as a terminator for ARMCPRegInfo lists */
>  #define ARM_CP_SENTINEL 0xffff
>  /* Mask of only the flag bits in a type field */
> diff --git a/target-arm/helper.c b/target-arm/helper.c
> index 66214293..ca27c8e 100644
> --- a/target-arm/helper.c
> +++ b/target-arm/helper.c
> @@ -1560,6 +1560,64 @@ static const ARMCPRegInfo lpae_cp_reginfo[] = {
>      REGINFO_SENTINEL
>  };
>
> +static int aa64_fpcr_read(CPUARMState *env, const ARMCPRegInfo *ri,
> +                          uint64_t *value)
> +{
> +    *value = vfp_get_fpcr(env);
> +    return 0;
> +}
> +
> +static int aa64_fpcr_write(CPUARMState *env, const ARMCPRegInfo *ri,
> +                           uint64_t value)
> +{
> +    vfp_set_fpcr(env, value);
> +    return 0;
> +}
> +
> +static int aa64_fpsr_read(CPUARMState *env, const ARMCPRegInfo *ri,
> +                          uint64_t *value)
> +{
> +    *value = vfp_get_fpsr(env);
> +    return 0;
> +}
> +
> +static int aa64_fpsr_write(CPUARMState *env, const ARMCPRegInfo *ri,
> +                           uint64_t value)
> +{
> +    vfp_set_fpsr(env, value);
> +    return 0;
> +}
> +
> +static const ARMCPRegInfo v8_cp_reginfo[] = {
> +    /* Minimal set of EL0-visible registers. This will need to be expanded
> +     * significantly for system emulation of AArch64 CPUs.
> +     */
> +    { .name = "NZCV", .state = ARM_CP_STATE_AA64,
> +      .opc0 = 3, .opc1 = 3, .opc2 = 0, .crn = 4, .crm = 2,
> +      .access = PL0_RW, .type = ARM_CP_NZCV },
> +    {. name = "FPCR", .state = ARM_CP_STATE_AA64,
> +     .opc0 = 3, .opc1 = 3, .opc2 = 0, .crn = 4, .crm = 4,
> +     .access = PL0_RW, .readfn = aa64_fpcr_read, .writefn = aa64_fpcr_write },
> +    {. name = "FPSR", .state = ARM_CP_STATE_AA64,
> +     .opc0 = 3, .opc1 = 3, .opc2 = 1, .crn = 4, .crm = 4,
> +     .access = PL0_RW, .readfn = aa64_fpsr_read, .writefn = aa64_fpsr_write },
> +    /* This claims a 32 byte cacheline size for icache and dcache, VIPT icache.
> +     * It will eventually need to have a CPU-specified reset value.
> +     */

Not sure why this can't be solved short term as there is already the
ctr field in cpu state struct as used by 32.

> +    { .name = "CTR_EL0", .state = ARM_CP_STATE_AA64,
> +      .opc0 = 3, .opc1 = 3, .opc2 = 1, .crn = 0, .crm = 0,
> +      .access = PL0_R, .type = ARM_CP_CONST,
> +      .resetvalue = 0x80030003 },
> +    /* Prohibit use of DC ZVA. OPTME: implement DC ZVA and allow its use.
> +     * For system mode the DZP bit here will need to be computed, not constant.
> +     */
> +    { .name = "DCZID_EL0", .state = ARM_CP_STATE_AA64,
> +      .opc0 = 3, .opc1 = 3, .opc2 = 7, .crn = 0, .crm = 0,
> +      .access = PL0_R, .type = ARM_CP_CONST,
> +      .resetvalue = 0x10 },
> +    REGINFO_SENTINEL
> +};
> +
>  static int sctlr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
>  {
>      env->cp15.c1_sys = value;
> @@ -1662,6 +1720,9 @@ void register_cp_regs_for_features(ARMCPU *cpu)
>      } else {
>          define_arm_cp_regs(cpu, not_v7_cp_reginfo);
>      }
> +    if (arm_feature(env, ARM_FEATURE_V8)) {
> +        define_arm_cp_regs(cpu, v8_cp_reginfo);
> +    }

But I guess this exact approach wouldn't work. v8_cp_reginfo
declaration would have to be brought inline here (like it is for the
existing A32 MIDR/CTR/friends RegInfo decl.).

Regards,
Peter

>      if (arm_feature(env, ARM_FEATURE_MPU)) {
>          /* These are the MPU registers prior to PMSAv6. Any new
>           * PMSA core later than the ARM946 will require that we
> diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
> index 7a9ee82..c8ed799 100644
> --- a/target-arm/translate-a64.c
> +++ b/target-arm/translate-a64.c,
> @@ -733,6 +733,50 @@ static void handle_msr_i(DisasContext *s, uint32_t insn,
>      unsupported_encoding(s, insn);
>  }
>
> +static void gen_get_nzcv(TCGv_i64 tcg_rt)
> +{
> +    TCGv_i32 tmp = tcg_temp_new_i32();
> +    TCGv_i32 nzcv = tcg_temp_new_i32();
> +
> +    /* build bit 31, N */
> +    tcg_gen_andi_i32(nzcv, cpu_NF, (1 << 31));
> +    /* build bit 30, Z */
> +    tcg_gen_setcondi_i32(TCG_COND_EQ, tmp, cpu_ZF, 0);
> +    tcg_gen_deposit_i32(nzcv, nzcv, tmp, 30, 1);
> +    /* build bit 29, C */
> +    tcg_gen_deposit_i32(nzcv, nzcv, cpu_CF, 29, 1);
> +    /* build bit 28, V */
> +    tcg_gen_shri_i32(tmp, cpu_VF, 31);
> +    tcg_gen_deposit_i32(nzcv, nzcv, tmp, 28, 1);
> +    /* generate result */
> +    tcg_gen_extu_i32_i64(tcg_rt, nzcv);
> +
> +    tcg_temp_free_i32(nzcv);
> +    tcg_temp_free_i32(tmp);
> +}
> +
> +static void gen_set_nzcv(TCGv_i64 tcg_rt)
> +
> +{
> +    TCGv_i32 nzcv = tcg_temp_new_i32();
> +
> +    /* take NZCV from R[t] */
> +    tcg_gen_trunc_i64_i32(nzcv, tcg_rt);
> +
> +    /* bit 31, N */
> +    tcg_gen_andi_i32(cpu_NF, nzcv, (1 << 31));
> +    /* bit 30, Z */
> +    tcg_gen_andi_i32(cpu_ZF, nzcv, (1 << 30));
> +    tcg_gen_setcondi_i32(TCG_COND_EQ, cpu_ZF, cpu_ZF, 0);
> +    /* bit 29, C */
> +    tcg_gen_andi_i32(cpu_CF, nzcv, (1 << 29));
> +    tcg_gen_shri_i32(cpu_CF, cpu_CF, 29);
> +    /* bit 28, V */
> +    tcg_gen_andi_i32(cpu_VF, nzcv, (1 << 28));
> +    tcg_gen_shli_i32(cpu_VF, cpu_VF, 3);
> +    tcg_temp_free_i32(nzcv);
> +}
> +
>  /* C5.6.129 MRS - move from system register
>   * C5.6.131 MSR (register) - move to system register
>   * C5.6.204 SYS
> @@ -767,6 +811,14 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread,
>      switch (ri->type & ~(ARM_CP_FLAG_MASK & ~ARM_CP_SPECIAL)) {
>      case ARM_CP_NOP:
>          return;
> +    case ARM_CP_NZCV:
> +        tcg_rt = cpu_reg(s, rt);
> +        if (isread) {
> +            gen_get_nzcv(tcg_rt);
> +        } else {
> +            gen_set_nzcv(tcg_rt);
> +        }
> +        return;
>      default:
>          break;
>      }
> --
> 1.8.5
>
>
Peter Crosthwaite Jan. 4, 2014, 1:39 p.m. UTC | #4
On Sat, Jan 4, 2014 at 9:35 PM, Peter Maydell <peter.maydell@linaro.org> wrote:
> On 4 January 2014 02:34, Peter Crosthwaite <peter.crosthwaite@xilinx.com> wrote:
>> On Mon, Dec 23, 2013 at 8:49 AM, Peter Maydell <peter.maydell@linaro.org> wrote:
>>> +static const ARMCPRegInfo v8_cp_reginfo[] = {
>>> +    /* Minimal set of EL0-visible registers. This will need to be expanded
>>> +     * significantly for system emulation of AArch64 CPUs.
>>> +     */
>>> +    { .name = "NZCV", .state = ARM_CP_STATE_AA64,
>>> +      .opc0 = 3, .opc1 = 3, .opc2 = 0, .crn = 4, .crm = 2,
>>> +      .access = PL0_RW, .type = ARM_CP_NZCV },
>>> +    {. name = "FPCR", .state = ARM_CP_STATE_AA64,
>>> +     .opc0 = 3, .opc1 = 3, .opc2 = 0, .crn = 4, .crm = 4,
>>> +     .access = PL0_RW, .readfn = aa64_fpcr_read, .writefn = aa64_fpcr_write },
>>
>> Indentation and spacing looks inconsistent.
>
> So it does (I didn't even know it was syntactically valid to leave
> a space after the '.' like that...) . Will fix.
>

FWIW, I think in ".foo" the "." and "foo" will still be lexed as two
tokens by compilers so the standard rule of "whitespace doesn't
matter" applies and the parser has to sort it out.

Checkpatch could probably use a rule though.

> Do you mind if I don't do a respin just for this?
>

Not just for this, although I had a second read through and have a
comment on the CTR (separate mail). But i'd rather see it go through
considering the issue is flagged fixme, so just pending the
whitespace:

Reviewed-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>

(I haven't gone line by line on the TCG stuff, but Richard has RB'd it
so I'm assuming thats covered).

Regards,
Peter

> thanks
> -- PMM
>
Peter Maydell Jan. 4, 2014, 2:11 p.m. UTC | #5
On 4 January 2014 13:32, Peter Crosthwaite <peter.crosthwaite@xilinx.com> wrote:
> On Mon, Dec 23, 2013 at 8:49 AM, Peter Maydell <peter.maydell@linaro.org> wrote:
>> +static const ARMCPRegInfo v8_cp_reginfo[] = {
>> +    /* Minimal set of EL0-visible registers. This will need to be expanded
>> +     * significantly for system emulation of AArch64 CPUs.
>> +     */
>> +    { .name = "NZCV", .state = ARM_CP_STATE_AA64,
>> +      .opc0 = 3, .opc1 = 3, .opc2 = 0, .crn = 4, .crm = 2,
>> +      .access = PL0_RW, .type = ARM_CP_NZCV },
>> +    {. name = "FPCR", .state = ARM_CP_STATE_AA64,
>> +     .opc0 = 3, .opc1 = 3, .opc2 = 0, .crn = 4, .crm = 4,
>> +     .access = PL0_RW, .readfn = aa64_fpcr_read, .writefn = aa64_fpcr_write },
>> +    {. name = "FPSR", .state = ARM_CP_STATE_AA64,
>> +     .opc0 = 3, .opc1 = 3, .opc2 = 1, .crn = 4, .crm = 4,
>> +     .access = PL0_RW, .readfn = aa64_fpsr_read, .writefn = aa64_fpsr_write },
>> +    /* This claims a 32 byte cacheline size for icache and dcache, VIPT icache.
>> +     * It will eventually need to have a CPU-specified reset value.
>> +     */
>
> Not sure why this can't be solved short term as there is already the
> ctr field in cpu state struct as used by 32.

I hadn't noticed that the register was aliased to the CTR AArch32 register.
NB that we can't just share a single reginfo for AArch64 and AArch32
though -- the permissions are different since in AArch32 this is accessible
only in EL1 and above.

My aim here was mostly to set out a framework for how the system
register integration will work with system emulation, but just to
provide low-effort implementations of the EL0-visible regs for
the initial user-emulation patchset. (In the SuSE patchset these are
actually just all implemented as special cases inline in translate-a64.c,
so to some extent this array is just those special cases converted over
to reginfo.)

thanks
-- PMM
diff mbox

Patch

diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index 66490ce..1e0800e 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -660,7 +660,8 @@  static inline uint64_t cpreg_to_kvm_id(uint32_t cpregid)
 #define ARM_CP_IO 64
 #define ARM_CP_NOP (ARM_CP_SPECIAL | (1 << 8))
 #define ARM_CP_WFI (ARM_CP_SPECIAL | (2 << 8))
-#define ARM_LAST_SPECIAL ARM_CP_WFI
+#define ARM_CP_NZCV (ARM_CP_SPECIAL | (3 << 8))
+#define ARM_LAST_SPECIAL ARM_CP_NZCV
 /* Used only as a terminator for ARMCPRegInfo lists */
 #define ARM_CP_SENTINEL 0xffff
 /* Mask of only the flag bits in a type field */
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 66214293..ca27c8e 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -1560,6 +1560,64 @@  static const ARMCPRegInfo lpae_cp_reginfo[] = {
     REGINFO_SENTINEL
 };
 
+static int aa64_fpcr_read(CPUARMState *env, const ARMCPRegInfo *ri,
+                          uint64_t *value)
+{
+    *value = vfp_get_fpcr(env);
+    return 0;
+}
+
+static int aa64_fpcr_write(CPUARMState *env, const ARMCPRegInfo *ri,
+                           uint64_t value)
+{
+    vfp_set_fpcr(env, value);
+    return 0;
+}
+
+static int aa64_fpsr_read(CPUARMState *env, const ARMCPRegInfo *ri,
+                          uint64_t *value)
+{
+    *value = vfp_get_fpsr(env);
+    return 0;
+}
+
+static int aa64_fpsr_write(CPUARMState *env, const ARMCPRegInfo *ri,
+                           uint64_t value)
+{
+    vfp_set_fpsr(env, value);
+    return 0;
+}
+
+static const ARMCPRegInfo v8_cp_reginfo[] = {
+    /* Minimal set of EL0-visible registers. This will need to be expanded
+     * significantly for system emulation of AArch64 CPUs.
+     */
+    { .name = "NZCV", .state = ARM_CP_STATE_AA64,
+      .opc0 = 3, .opc1 = 3, .opc2 = 0, .crn = 4, .crm = 2,
+      .access = PL0_RW, .type = ARM_CP_NZCV },
+    {. name = "FPCR", .state = ARM_CP_STATE_AA64,
+     .opc0 = 3, .opc1 = 3, .opc2 = 0, .crn = 4, .crm = 4,
+     .access = PL0_RW, .readfn = aa64_fpcr_read, .writefn = aa64_fpcr_write },
+    {. name = "FPSR", .state = ARM_CP_STATE_AA64,
+     .opc0 = 3, .opc1 = 3, .opc2 = 1, .crn = 4, .crm = 4,
+     .access = PL0_RW, .readfn = aa64_fpsr_read, .writefn = aa64_fpsr_write },
+    /* This claims a 32 byte cacheline size for icache and dcache, VIPT icache.
+     * It will eventually need to have a CPU-specified reset value.
+     */
+    { .name = "CTR_EL0", .state = ARM_CP_STATE_AA64,
+      .opc0 = 3, .opc1 = 3, .opc2 = 1, .crn = 0, .crm = 0,
+      .access = PL0_R, .type = ARM_CP_CONST,
+      .resetvalue = 0x80030003 },
+    /* Prohibit use of DC ZVA. OPTME: implement DC ZVA and allow its use.
+     * For system mode the DZP bit here will need to be computed, not constant.
+     */
+    { .name = "DCZID_EL0", .state = ARM_CP_STATE_AA64,
+      .opc0 = 3, .opc1 = 3, .opc2 = 7, .crn = 0, .crm = 0,
+      .access = PL0_R, .type = ARM_CP_CONST,
+      .resetvalue = 0x10 },
+    REGINFO_SENTINEL
+};
+
 static int sctlr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
 {
     env->cp15.c1_sys = value;
@@ -1662,6 +1720,9 @@  void register_cp_regs_for_features(ARMCPU *cpu)
     } else {
         define_arm_cp_regs(cpu, not_v7_cp_reginfo);
     }
+    if (arm_feature(env, ARM_FEATURE_V8)) {
+        define_arm_cp_regs(cpu, v8_cp_reginfo);
+    }
     if (arm_feature(env, ARM_FEATURE_MPU)) {
         /* These are the MPU registers prior to PMSAv6. Any new
          * PMSA core later than the ARM946 will require that we
diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index 7a9ee82..c8ed799 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -733,6 +733,50 @@  static void handle_msr_i(DisasContext *s, uint32_t insn,
     unsupported_encoding(s, insn);
 }
 
+static void gen_get_nzcv(TCGv_i64 tcg_rt)
+{
+    TCGv_i32 tmp = tcg_temp_new_i32();
+    TCGv_i32 nzcv = tcg_temp_new_i32();
+
+    /* build bit 31, N */
+    tcg_gen_andi_i32(nzcv, cpu_NF, (1 << 31));
+    /* build bit 30, Z */
+    tcg_gen_setcondi_i32(TCG_COND_EQ, tmp, cpu_ZF, 0);
+    tcg_gen_deposit_i32(nzcv, nzcv, tmp, 30, 1);
+    /* build bit 29, C */
+    tcg_gen_deposit_i32(nzcv, nzcv, cpu_CF, 29, 1);
+    /* build bit 28, V */
+    tcg_gen_shri_i32(tmp, cpu_VF, 31);
+    tcg_gen_deposit_i32(nzcv, nzcv, tmp, 28, 1);
+    /* generate result */
+    tcg_gen_extu_i32_i64(tcg_rt, nzcv);
+
+    tcg_temp_free_i32(nzcv);
+    tcg_temp_free_i32(tmp);
+}
+
+static void gen_set_nzcv(TCGv_i64 tcg_rt)
+
+{
+    TCGv_i32 nzcv = tcg_temp_new_i32();
+
+    /* take NZCV from R[t] */
+    tcg_gen_trunc_i64_i32(nzcv, tcg_rt);
+
+    /* bit 31, N */
+    tcg_gen_andi_i32(cpu_NF, nzcv, (1 << 31));
+    /* bit 30, Z */
+    tcg_gen_andi_i32(cpu_ZF, nzcv, (1 << 30));
+    tcg_gen_setcondi_i32(TCG_COND_EQ, cpu_ZF, cpu_ZF, 0);
+    /* bit 29, C */
+    tcg_gen_andi_i32(cpu_CF, nzcv, (1 << 29));
+    tcg_gen_shri_i32(cpu_CF, cpu_CF, 29);
+    /* bit 28, V */
+    tcg_gen_andi_i32(cpu_VF, nzcv, (1 << 28));
+    tcg_gen_shli_i32(cpu_VF, cpu_VF, 3);
+    tcg_temp_free_i32(nzcv);
+}
+
 /* C5.6.129 MRS - move from system register
  * C5.6.131 MSR (register) - move to system register
  * C5.6.204 SYS
@@ -767,6 +811,14 @@  static void handle_sys(DisasContext *s, uint32_t insn, bool isread,
     switch (ri->type & ~(ARM_CP_FLAG_MASK & ~ARM_CP_SPECIAL)) {
     case ARM_CP_NOP:
         return;
+    case ARM_CP_NZCV:
+        tcg_rt = cpu_reg(s, rt);
+        if (isread) {
+            gen_get_nzcv(tcg_rt);
+        } else {
+            gen_set_nzcv(tcg_rt);
+        }
+        return;
     default:
         break;
     }