From patchwork Mon May 14 19:03:11 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Maydell X-Patchwork-Id: 8630 Return-Path: X-Original-To: patchwork@peony.canonical.com Delivered-To: patchwork@peony.canonical.com Received: from fiordland.canonical.com (fiordland.canonical.com [91.189.94.145]) by peony.canonical.com (Postfix) with ESMTP id D287A23EAB for ; Mon, 14 May 2012 19:27:08 +0000 (UTC) Received: from mail-yx0-f180.google.com (mail-yx0-f180.google.com [209.85.213.180]) by fiordland.canonical.com (Postfix) with ESMTP id 8D548A1880D for ; Mon, 14 May 2012 19:27:08 +0000 (UTC) Received: by mail-yx0-f180.google.com with SMTP id q6so5822442yen.11 for ; Mon, 14 May 2012 12:27:08 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=x-forwarded-to:x-forwarded-for:delivered-to:received-spf:from:to:cc :subject:date:message-id:x-mailer:in-reply-to:references :x-gm-message-state; bh=agnrHcY6hdeTaTAQqX0HJT4AtkQvCehvddOF63DH12U=; b=EvSRKEhGsO7tnYVMBmMDgwSXOHTFlwvEGygmzRh38iMrGu7H6MfdxE3ySDsr0kDCWT 4Te0phNqsoXAs4zOSFFNLTok4NwSjipRlw5C2PpLDuWI+92SPGl7rVX3ycAwlGXya4+z uhdfpf/n0HMafYh1BbQMJf+pL/J0Xa0b/u4kyCb6IIzbN5JTDRTRLeTOOYaZV6XP9irU 4/H7F/A783iNuKGOshAZdNiiA6ryFYwx76a3gd0lUr3+B8nF4WRL64to/0xN9AuIyU9h txcEt9PR5wutpW0q1eSYaI3NZosRkOi8uhzCrS5vpSS87ooDzloMyi8nCIu/Hs8GhCtI uOzQ== Received: by 10.42.89.72 with SMTP id f8mr2660149icm.33.1337023628265; Mon, 14 May 2012 12:27:08 -0700 (PDT) X-Forwarded-To: linaro-patchwork@canonical.com X-Forwarded-For: patch@linaro.org linaro-patchwork@canonical.com Delivered-To: patches@linaro.org Received: by 10.231.35.72 with SMTP id o8csp367249ibd; Mon, 14 May 2012 12:27:05 -0700 (PDT) Received: by 10.204.153.15 with SMTP id i15mr3554978bkw.74.1337023624599; Mon, 14 May 2012 12:27:04 -0700 (PDT) Received: from mnementh.archaic.org.uk (mnementh.archaic.org.uk. [81.2.115.146]) by mx.google.com with ESMTPS id hw3si13879686bkc.18.2012.05.14.12.27.03 (version=TLSv1/SSLv3 cipher=OTHER); Mon, 14 May 2012 12:27:04 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 81.2.115.146 as permitted sender) client-ip=81.2.115.146; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 81.2.115.146 as permitted sender) smtp.mail=pm215@archaic.org.uk Received: from pm215 by mnementh.archaic.org.uk with local (Exim 4.72) (envelope-from ) id 1SU0YP-0005nC-64; Mon, 14 May 2012 20:03:33 +0100 From: Peter Maydell To: qemu-devel@nongnu.org Cc: patches@linaro.org, Paul Brook , =?UTF-8?q?Andreas=20F=C3=A4rber?= , Rusty Russell Subject: [PATCH qom-next v2 12/33] target-arm: Convert performance monitor registers Date: Mon, 14 May 2012 20:03:11 +0100 Message-Id: <1337022212-22219-13-git-send-email-peter.maydell@linaro.org> X-Mailer: git-send-email 1.7.2.5 In-Reply-To: <1337022212-22219-1-git-send-email-peter.maydell@linaro.org> References: <1337022212-22219-1-git-send-email-peter.maydell@linaro.org> X-Gm-Message-State: ALoCoQk34tq7u64j6vX1tCiZp9WZ4143c0WTI2T4EfmK9b3B2iscY23tHpM+gWM0eShO2qkVuqzs Convert the v7 performance monitor cp15 registers to the new scheme. Signed-off-by: Peter Maydell --- target-arm/cpu.c | 4 - target-arm/helper.c | 277 +++++++++++++++++++++++++++--------------------- target-arm/translate.c | 26 +----- 3 files changed, 158 insertions(+), 149 deletions(-) diff --git a/target-arm/cpu.c b/target-arm/cpu.c index 1aff266..0098787 100644 --- a/target-arm/cpu.c +++ b/target-arm/cpu.c @@ -132,10 +132,6 @@ static void arm_cpu_reset(CPUState *s) } env->vfp.xregs[ARM_VFP_FPEXC] = 0; env->cp15.c2_base_mask = 0xffffc000u; - /* v7 performance monitor control register: same implementor - * field as main ID register, and we implement no event counters. - */ - env->cp15.c9_pmcr = (cpu->midr & 0xff000000); #endif set_flush_to_zero(1, &env->vfp.standard_fp_status); set_flush_inputs_to_zero(1, &env->vfp.standard_fp_status); diff --git a/target-arm/helper.c b/target-arm/helper.c index 60bf03c..88f7ca7 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -103,6 +103,97 @@ static const ARMCPRegInfo v6_cp_reginfo[] = { REGINFO_SENTINEL }; +static int pmreg_read(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t *value) +{ + /* Generic performance monitor register read function for where + * user access may be allowed by PMUSERENR. + */ + if (arm_current_pl(env) == 0 && !env->cp15.c9_pmuserenr) { + return EXCP_UDEF; + } + *value = CPREG_FIELD32(env, ri); + return 0; +} + +static int pmcr_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + if (arm_current_pl(env) == 0 && !env->cp15.c9_pmuserenr) { + return EXCP_UDEF; + } + /* only the DP, X, D and E bits are writable */ + env->cp15.c9_pmcr &= ~0x39; + env->cp15.c9_pmcr |= (value & 0x39); + return 0; +} + +static int pmcntenset_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + if (arm_current_pl(env) == 0 && !env->cp15.c9_pmuserenr) { + return EXCP_UDEF; + } + value &= (1 << 31); + env->cp15.c9_pmcnten |= value; + return 0; +} + +static int pmcntenclr_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + if (arm_current_pl(env) == 0 && !env->cp15.c9_pmuserenr) { + return EXCP_UDEF; + } + value &= (1 << 31); + env->cp15.c9_pmcnten &= ~value; + return 0; +} + +static int pmovsr_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + if (arm_current_pl(env) == 0 && !env->cp15.c9_pmuserenr) { + return EXCP_UDEF; + } + env->cp15.c9_pmovsr &= ~value; + return 0; +} + +static int pmxevtyper_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + if (arm_current_pl(env) == 0 && !env->cp15.c9_pmuserenr) { + return EXCP_UDEF; + } + env->cp15.c9_pmxevtyper = value & 0xff; + return 0; +} + +static int pmuserenr_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + env->cp15.c9_pmuserenr = value & 1; + return 0; +} + +static int pmintenset_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + /* We have no event counters so only the C bit can be changed */ + value &= (1 << 31); + env->cp15.c9_pminten |= value; + return 0; +} + +static int pmintenclr_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + value &= (1 << 31); + env->cp15.c9_pminten &= ~value; + return 0; +} + static const ARMCPRegInfo v7_cp_reginfo[] = { /* DBGDRAR, DBGDSAR: always RAZ since we don't implement memory mapped * debug components @@ -114,6 +205,62 @@ static const ARMCPRegInfo v7_cp_reginfo[] = { /* the old v6 WFI, UNPREDICTABLE in v7 but we choose to NOP */ { .name = "NOP", .cp = 15, .crn = 7, .crm = 0, .opc1 = 0, .opc2 = 4, .access = PL1_W, .type = ARM_CP_NOP }, + /* Performance monitors are implementation defined in v7, + * but with an ARM recommended set of registers, which we + * follow (although we don't actually implement any counters) + * + * Performance registers fall into three categories: + * (a) always UNDEF in PL0, RW in PL1 (PMINTENSET, PMINTENCLR) + * (b) RO in PL0 (ie UNDEF on write), RW in PL1 (PMUSERENR) + * (c) UNDEF in PL0 if PMUSERENR.EN==0, otherwise accessible (all others) + * For the cases controlled by PMUSERENR we must set .access to PL0_RW + * or PL0_RO as appropriate and then check PMUSERENR in the helper fn. + */ + { .name = "PMCNTENSET", .cp = 15, .crn = 9, .crm = 12, .opc1 = 0, .opc2 = 1, + .access = PL0_RW, .resetvalue = 0, + .fieldoffset = offsetof(CPUARMState, cp15.c9_pmcnten), + .readfn = pmreg_read, .writefn = pmcntenset_write }, + { .name = "PMCNTENCLR", .cp = 15, .crn = 9, .crm = 12, .opc1 = 0, .opc2 = 2, + .access = PL0_RW, .fieldoffset = offsetof(CPUARMState, cp15.c9_pmcnten), + .readfn = pmreg_read, .writefn = pmcntenclr_write }, + { .name = "PMOVSR", .cp = 15, .crn = 9, .crm = 12, .opc1 = 0, .opc2 = 3, + .access = PL0_RW, .fieldoffset = offsetof(CPUARMState, cp15.c9_pmovsr), + .readfn = pmreg_read, .writefn = pmovsr_write }, + /* Unimplemented so WI. Strictly speaking write accesses in PL0 should + * respect PMUSERENR. + */ + { .name = "PMSWINC", .cp = 15, .crn = 9, .crm = 12, .opc1 = 0, .opc2 = 4, + .access = PL0_W, .type = ARM_CP_NOP }, + /* Since we don't implement any events, writing to PMSELR is UNPREDICTABLE. + * We choose to RAZ/WI. XXX should respect PMUSERENR. + */ + { .name = "PMSELR", .cp = 15, .crn = 9, .crm = 12, .opc1 = 0, .opc2 = 5, + .access = PL0_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + /* Unimplemented, RAZ/WI. XXX PMUSERENR */ + { .name = "PMCCNTR", .cp = 15, .crn = 9, .crm = 13, .opc1 = 0, .opc2 = 0, + .access = PL0_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "PMXEVTYPER", .cp = 15, .crn = 9, .crm = 13, .opc1 = 0, .opc2 = 1, + .access = PL0_RW, + .fieldoffset = offsetof(CPUARMState, cp15.c9_pmxevtyper), + .readfn = pmreg_read, .writefn = pmxevtyper_write }, + /* Unimplemented, RAZ/WI. XXX PMUSERENR */ + { .name = "PMXEVCNTR", .cp = 15, .crn = 9, .crm = 13, .opc1 = 0, .opc2 = 2, + .access = PL0_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "PMUSERENR", .cp = 15, .crn = 9, .crm = 14, .opc1 = 0, .opc2 = 0, + .access = PL0_R | PL1_RW, + .fieldoffset = offsetof(CPUARMState, cp15.c9_pmuserenr), + .resetvalue = 0, + .writefn = pmuserenr_write }, + { .name = "PMINTENSET", .cp = 15, .crn = 9, .crm = 14, .opc1 = 0, .opc2 = 1, + .access = PL1_RW, + .fieldoffset = offsetof(CPUARMState, cp15.c9_pminten), + .resetvalue = 0, + .writefn = pmintenset_write }, + { .name = "PMINTENCLR", .cp = 15, .crn = 9, .crm = 14, .opc1 = 0, .opc2 = 2, + .access = PL1_RW, + .fieldoffset = offsetof(CPUARMState, cp15.c9_pminten), + .resetvalue = 0, + .writefn = pmintenclr_write }, REGINFO_SENTINEL }; @@ -194,6 +341,16 @@ void register_cp_regs_for_features(ARMCPU *cpu) define_arm_cp_regs(cpu, v6k_cp_reginfo); } if (arm_feature(env, ARM_FEATURE_V7)) { + /* v7 performance monitor control register: same implementor + * field as main ID register, and we implement no event counters. + */ + ARMCPRegInfo pmcr = { + .name = "PMCR", .cp = 15, .crn = 9, .crm = 12, .opc1 = 0, .opc2 = 0, + .access = PL0_RW, .resetvalue = cpu->midr & 0xff000000, + .fieldoffset = offsetof(CPUARMState, cp15.c9_pmcr), + .readfn = pmreg_read, .writefn = pmcr_write + }; + define_one_arm_cp_reg(cpu, &pmcr); define_arm_cp_regs(cpu, v7_cp_reginfo); } else { define_arm_cp_regs(cpu, not_v7_cp_reginfo); @@ -1538,81 +1695,6 @@ void HELPER(set_cp15)(CPUARMState *env, uint32_t insn, uint32_t val) case 1: /* TCM memory region registers. */ /* Not implemented. */ goto bad_reg; - case 12: /* Performance monitor control */ - /* Performance monitors are implementation defined in v7, - * but with an ARM recommended set of registers, which we - * follow (although we don't actually implement any counters) - */ - if (!arm_feature(env, ARM_FEATURE_V7)) { - goto bad_reg; - } - switch (op2) { - case 0: /* performance monitor control register */ - /* only the DP, X, D and E bits are writable */ - env->cp15.c9_pmcr &= ~0x39; - env->cp15.c9_pmcr |= (val & 0x39); - break; - case 1: /* Count enable set register */ - val &= (1 << 31); - env->cp15.c9_pmcnten |= val; - break; - case 2: /* Count enable clear */ - val &= (1 << 31); - env->cp15.c9_pmcnten &= ~val; - break; - case 3: /* Overflow flag status */ - env->cp15.c9_pmovsr &= ~val; - break; - case 4: /* Software increment */ - /* RAZ/WI since we don't implement the software-count event */ - break; - case 5: /* Event counter selection register */ - /* Since we don't implement any events, writing to this register - * is actually UNPREDICTABLE. So we choose to RAZ/WI. - */ - break; - default: - goto bad_reg; - } - break; - case 13: /* Performance counters */ - if (!arm_feature(env, ARM_FEATURE_V7)) { - goto bad_reg; - } - switch (op2) { - case 0: /* Cycle count register: not implemented, so RAZ/WI */ - break; - case 1: /* Event type select */ - env->cp15.c9_pmxevtyper = val & 0xff; - break; - case 2: /* Event count register */ - /* Unimplemented (we have no events), RAZ/WI */ - break; - default: - goto bad_reg; - } - break; - case 14: /* Performance monitor control */ - if (!arm_feature(env, ARM_FEATURE_V7)) { - goto bad_reg; - } - switch (op2) { - case 0: /* user enable */ - env->cp15.c9_pmuserenr = val & 1; - /* changes access rights for cp registers, so flush tbs */ - tb_flush(env); - break; - case 1: /* interrupt enable set */ - /* We have no event counters so only the C bit can be changed */ - val &= (1 << 31); - env->cp15.c9_pminten |= val; - break; - case 2: /* interrupt enable clear */ - val &= (1 << 31); - env->cp15.c9_pminten &= ~val; - break; - } - break; default: goto bad_reg; } @@ -1969,51 +2051,6 @@ uint32_t HELPER(get_cp15)(CPUARMState *env, uint32_t insn) goto bad_reg; } break; - case 12: /* Performance monitor control */ - if (!arm_feature(env, ARM_FEATURE_V7)) { - goto bad_reg; - } - switch (op2) { - case 0: /* performance monitor control register */ - return env->cp15.c9_pmcr; - case 1: /* count enable set */ - case 2: /* count enable clear */ - return env->cp15.c9_pmcnten; - case 3: /* overflow flag status */ - return env->cp15.c9_pmovsr; - case 4: /* software increment */ - case 5: /* event counter selection register */ - return 0; /* Unimplemented, RAZ/WI */ - default: - goto bad_reg; - } - case 13: /* Performance counters */ - if (!arm_feature(env, ARM_FEATURE_V7)) { - goto bad_reg; - } - switch (op2) { - case 1: /* Event type select */ - return env->cp15.c9_pmxevtyper; - case 0: /* Cycle count register */ - case 2: /* Event count register */ - /* Unimplemented, so RAZ/WI */ - return 0; - default: - goto bad_reg; - } - case 14: /* Performance monitor control */ - if (!arm_feature(env, ARM_FEATURE_V7)) { - goto bad_reg; - } - switch (op2) { - case 0: /* user enable */ - return env->cp15.c9_pmuserenr; - case 1: /* interrupt enable set */ - case 2: /* interrupt enable clear */ - return env->cp15.c9_pminten; - default: - goto bad_reg; - } default: goto bad_reg; } diff --git a/target-arm/translate.c b/target-arm/translate.c index e6b0d87..f4e9435 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -2439,30 +2439,6 @@ static int disas_dsp_insn(CPUARMState *env, DisasContext *s, uint32_t insn) return 1; } -static int cp15_user_ok(CPUARMState *env, uint32_t insn) -{ - int cpn = (insn >> 16) & 0xf; - int cpm = insn & 0xf; - int op = ((insn >> 5) & 7) | ((insn >> 18) & 0x38); - - if (arm_feature(env, ARM_FEATURE_V7) && cpn == 9) { - /* Performance monitor registers fall into three categories: - * (a) always UNDEF in usermode - * (b) UNDEF only if PMUSERENR.EN is 0 - * (c) always read OK and UNDEF on write (PMUSERENR only) - */ - if ((cpm == 12 && (op < 6)) || - (cpm == 13 && (op < 3))) { - return env->cp15.c9_pmuserenr; - } else if (cpm == 14 && op == 0 && (insn & ARM_CP_RW_BIT)) { - /* PMUSERENR, read only */ - return 1; - } - return 0; - } - return 0; -} - /* Disassemble system coprocessor (cp15) instruction. Return nonzero if instruction is not defined. */ static int disas_cp15_insn(CPUARMState *env, DisasContext *s, uint32_t insn) @@ -2487,7 +2463,7 @@ static int disas_cp15_insn(CPUARMState *env, DisasContext *s, uint32_t insn) return 1; } - if (IS_USER(s) && !cp15_user_ok(env, insn)) { + if (IS_USER(s)) { return 1; }