From patchwork Sun Apr 15 13:46:14 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Maydell X-Patchwork-Id: 7846 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 00C6723E47 for ; Sun, 15 Apr 2012 13:46:43 +0000 (UTC) Received: from mail-iy0-f180.google.com (mail-iy0-f180.google.com [209.85.210.180]) by fiordland.canonical.com (Postfix) with ESMTP id B9EAFA18189 for ; Sun, 15 Apr 2012 13:46:42 +0000 (UTC) Received: by mail-iy0-f180.google.com with SMTP id e36so8543068iag.11 for ; Sun, 15 Apr 2012 06:46:42 -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=AFakpE3mzKDH4XjAotiaxgjPIYAnC08RddiacdF4j5w=; b=XyFHPbqsrypAEVI/vqTMjbfpqmjfh7TKJI1IcyMhFbS3US3vKEZUA7LOAiBMrSOr2c 0g5F04R8moLv9BZrhQI6ZHyh3ZccL8hwWQSWEQE/5LOkxmu47hWUkyDL6UATqiTTmXcN T8d5WScAFmhzKGCxKPzdL0h5i/dF/pVK5cF2ngBUUfkZ77EgDstECMR33RE4nW7JSiIh 87ImA9VTWxPNwMhzvOAbRzsf4HTBwHkMzHdYOGVpdjJqqNrqCzWlPqQq4X5M+dGGe6CW TtjjJ+qD3GQM0dTfzTqmzNSob1o0iJ0KzTe8ii3BZYFXDagP4XYbPMI5kCm+oPsDe2Qg E9cg== Received: by 10.42.152.134 with SMTP id i6mr4886920icw.27.1334497602530; Sun, 15 Apr 2012 06:46:42 -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.70.69 with SMTP id c5csp22225ibj; Sun, 15 Apr 2012 06:46:41 -0700 (PDT) Received: by 10.204.129.196 with SMTP id p4mr2621737bks.21.1334497600951; Sun, 15 Apr 2012 06:46:40 -0700 (PDT) Received: from mnementh.archaic.org.uk (mnementh.archaic.org.uk. [81.2.115.146]) by mx.google.com with ESMTPS id t8si5692748bkd.142.2012.04.15.06.46.39 (version=TLSv1/SSLv3 cipher=OTHER); Sun, 15 Apr 2012 06:46:40 -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 1SJPmd-0000FB-Cm; Sun, 15 Apr 2012 14:46:27 +0100 From: Peter Maydell To: qemu-devel@nongnu.org Cc: patches@linaro.org, =?UTF-8?q?Andreas=20F=C3=A4rber?= , Paul Brook Subject: [PATCH 21/32] target-arm: convert cp15 crn=7 registers Date: Sun, 15 Apr 2012 14:46:14 +0100 Message-Id: <1334497585-867-22-git-send-email-peter.maydell@linaro.org> X-Mailer: git-send-email 1.7.2.5 In-Reply-To: <1334497585-867-1-git-send-email-peter.maydell@linaro.org> References: <1334497585-867-1-git-send-email-peter.maydell@linaro.org> X-Gm-Message-State: ALoCoQlUI1bwte7fvmshhsaRcdRytyfuSZDUoTUDVDuSV9YJRyLV6nTs9P1hkzhrBfN9ZxAk1kOd Convert the cp15 crn=7 registers to the new scheme. Note that to do this we have to distinguish some registers used on the ARM9 and ARM10 from some which are ARM1176 only. This is because the old code returned a value of 0 but always set the Z flag (by clearing env->ZF, since we store the Z flag in CPUState inverted). This is inconsistent with actual ARM CPU behaviour, which only sets flags for reads to r15 and sets them based on the top bits of the result. However it happened to work for the two common use cases for cp15 crn=7 reads: * On ARM9 and ARM10 the cache clean-and-test operations are typically done with a destination of r15 so that you can do a "loop: mrc ... ; bne loop" to keep cleaning until the cache is finally clean; always setting the Z flag means this loop terminates immediately * on ARM1176 the Cache Dirty Status Register reads as zero if the cache is dirty; returning 0 means this is correctly implemented for QEMU Since the new coprocessor register framework does the right thing of always setting flags based on the returned result for reads to r15, we need to split these up so that we can return (1<<30) for the ARM9/ARM10 registers but 0 for the ARM1176 one. This allows us to remove the nasty hack which always sets Z. Signed-off-by: Peter Maydell --- target-arm/cpu.c | 18 ++++++++++++++ target-arm/cpu.h | 3 ++ target-arm/helper.c | 62 +++++++++++++++++++++++++++++++++++++++++--------- 3 files changed, 72 insertions(+), 11 deletions(-) diff --git a/target-arm/cpu.c b/target-arm/cpu.c index cf59e08..01de653 100644 --- a/target-arm/cpu.c +++ b/target-arm/cpu.c @@ -214,6 +214,8 @@ static void arm926_initfn(Object *obj) ARMCPU *cpu = ARM_CPU(obj); set_feature(&cpu->env, ARM_FEATURE_V5); set_feature(&cpu->env, ARM_FEATURE_VFP); + set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); + set_feature(&cpu->env, ARM_FEATURE_CACHE_TEST_CLEAN); cpu->midr = ARM_CPUID_ARM926; cpu->reset_fpsid = 0x41011090; cpu->ctr = 0x1dd20d2; @@ -225,6 +227,7 @@ static void arm946_initfn(Object *obj) ARMCPU *cpu = ARM_CPU(obj); set_feature(&cpu->env, ARM_FEATURE_V5); set_feature(&cpu->env, ARM_FEATURE_MPU); + set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); cpu->midr = ARM_CPUID_ARM946; cpu->ctr = 0x0f004006; cpu->reset_sctlr = 0x00000078; @@ -236,6 +239,8 @@ static void arm1026_initfn(Object *obj) set_feature(&cpu->env, ARM_FEATURE_V5); set_feature(&cpu->env, ARM_FEATURE_VFP); set_feature(&cpu->env, ARM_FEATURE_AUXCR); + set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); + set_feature(&cpu->env, ARM_FEATURE_CACHE_TEST_CLEAN); cpu->midr = ARM_CPUID_ARM1026; cpu->reset_fpsid = 0x410110a0; cpu->ctr = 0x1dd20d2; @@ -254,6 +259,9 @@ static void arm1136_r2_initfn(Object *obj) */ set_feature(&cpu->env, ARM_FEATURE_V6); set_feature(&cpu->env, ARM_FEATURE_VFP); + set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); + set_feature(&cpu->env, ARM_FEATURE_CACHE_DIRTY_REG); + set_feature(&cpu->env, ARM_FEATURE_CACHE_BLOCK_OPS); cpu->midr = ARM_CPUID_ARM1136_R2; cpu->reset_fpsid = 0x410120b4; cpu->mvfr0 = 0x11111111; @@ -280,6 +288,9 @@ static void arm1136_initfn(Object *obj) set_feature(&cpu->env, ARM_FEATURE_V6K); set_feature(&cpu->env, ARM_FEATURE_V6); set_feature(&cpu->env, ARM_FEATURE_VFP); + set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); + set_feature(&cpu->env, ARM_FEATURE_CACHE_DIRTY_REG); + set_feature(&cpu->env, ARM_FEATURE_CACHE_BLOCK_OPS); cpu->midr = ARM_CPUID_ARM1136; cpu->reset_fpsid = 0x410120b4; cpu->mvfr0 = 0x11111111; @@ -306,6 +317,8 @@ static void arm1176_initfn(Object *obj) set_feature(&cpu->env, ARM_FEATURE_V6K); set_feature(&cpu->env, ARM_FEATURE_VFP); set_feature(&cpu->env, ARM_FEATURE_VAPA); + set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); + set_feature(&cpu->env, ARM_FEATURE_CACHE_DIRTY_REG); cpu->midr = ARM_CPUID_ARM1176; cpu->reset_fpsid = 0x410120b5; cpu->mvfr0 = 0x11111111; @@ -332,6 +345,7 @@ static void arm11mpcore_initfn(Object *obj) set_feature(&cpu->env, ARM_FEATURE_V6K); set_feature(&cpu->env, ARM_FEATURE_VFP); set_feature(&cpu->env, ARM_FEATURE_VAPA); + set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); cpu->midr = ARM_CPUID_ARM11MPCORE; cpu->reset_fpsid = 0x410120b4; cpu->mvfr0 = 0x11111111; @@ -366,6 +380,7 @@ static void cortex_a8_initfn(Object *obj) set_feature(&cpu->env, ARM_FEATURE_VFP3); set_feature(&cpu->env, ARM_FEATURE_NEON); set_feature(&cpu->env, ARM_FEATURE_THUMB2EE); + set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); cpu->midr = ARM_CPUID_CORTEXA8; cpu->reset_fpsid = 0x410330c0; cpu->mvfr0 = 0x11110222; @@ -475,6 +490,7 @@ static void cortex_a15_initfn(Object *obj) set_feature(&cpu->env, ARM_FEATURE_ARM_DIV); set_feature(&cpu->env, ARM_FEATURE_V7MP); set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER); + set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); cpu->midr = ARM_CPUID_CORTEXA15; cpu->reset_fpsid = 0x410430f0; cpu->mvfr0 = 0x10110222; @@ -513,6 +529,7 @@ static void sa1100_initfn(Object *obj) { ARMCPU *cpu = ARM_CPU(obj); set_feature(&cpu->env, ARM_FEATURE_STRONGARM); + set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); cpu->midr = ARM_CPUID_SA1100; cpu->reset_sctlr = 0x00000070; } @@ -521,6 +538,7 @@ static void sa1110_initfn(Object *obj) { ARMCPU *cpu = ARM_CPU(obj); set_feature(&cpu->env, ARM_FEATURE_STRONGARM); + set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); cpu->midr = ARM_CPUID_SA1110; cpu->reset_sctlr = 0x00000070; } diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 4df35e2..50976d1 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -384,6 +384,9 @@ enum arm_features { ARM_FEATURE_GENERIC_TIMER, ARM_FEATURE_MVFR, /* Media and VFP Feature Registers 0 and 1 */ ARM_FEATURE_DUMMY_C15_REGS, /* RAZ/WI all of cp15 crn=15 */ + ARM_FEATURE_CACHE_TEST_CLEAN, /* 926/1026 style test-and-clean ops */ + ARM_FEATURE_CACHE_DIRTY_REG, /* 1136/1176 cache dirty status register */ + ARM_FEATURE_CACHE_BLOCK_OPS, /* v6 optional cache block operations */ }; static inline int arm_feature(CPUARMState *env, int feature) diff --git a/target-arm/helper.c b/target-arm/helper.c index 58923db..46b1205 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -166,6 +166,9 @@ static const ARMCPRegInfo cp_reginfo[] = { .opc1 = CP_ANY, .opc2 = 2, .access = PL1_W, .writefn = tlbiasid_write, }, { .name = "TLBIMVAA", .cp = 15, .crn = 8, .crm = CP_ANY, .opc1 = CP_ANY, .opc2 = 3, .access = PL1_W, .writefn = tlbimvaa_write, }, + /* Cache maintenance ops; some of this space may be overridden later. */ + { .name = "CACHEMAINT", .cp = 15, .crn = 7, .crm = CP_ANY, + .opc1 = 0, .opc2 = CP_ANY, .access = PL1_W, .type = ARM_CP_NOP }, REGINFO_SENTINEL }; @@ -628,6 +631,17 @@ static int omap_wfi_write(CPUARMState *env, const ARMCPRegInfo *ri, return 0; } +static int omap_cachemaint_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + /* On OMAP there are registers indicating the max/min index of dcache lines + * containing a dirty line; cache flush operations have to reset these. + */ + env->cp15.c15_i_max = 0x000; + env->cp15.c15_i_min = 0xff0; + return 0; +} + static const ARMCPRegInfo omap_cp_reginfo[] = { { .name = "DFSR", .cp = 15, .crn = 5, .crm = CP_ANY, .opc1 = CP_ANY, .opc2 = CP_ANY, .access = PL1_RW, @@ -656,6 +670,9 @@ static const ARMCPRegInfo omap_cp_reginfo[] = { * base address at $rn & ~0xfff and map size of 0x200 << ($rn & 0xfff), * when MMU is off. */ + { .name = "OMAP_CACHEMAINT", .cp = 15, .crn = 7, .crm = CP_ANY, + .opc1 = 0, .opc2 = CP_ANY, .access = PL1_W, + .writefn = omap_cachemaint_write }, REGINFO_SENTINEL }; @@ -691,6 +708,31 @@ static const ARMCPRegInfo dummy_c15_cp_reginfo[] = { REGINFO_SENTINEL }; +static const ARMCPRegInfo cache_dirty_status_cp_reginfo[] = { + /* Cache status: RAZ because we have no cache so it's always clean */ + { .name = "CDSR", .cp = 15, .crn = 7, .crm = 10, .opc1 = 0, .opc2 = 6, + .access = PL1_R, .type = ARM_CP_CONST, .resetvalue = 0 }, + REGINFO_SENTINEL +}; + +static const ARMCPRegInfo cache_block_ops_cp_reginfo[] = { + /* We never have a a block transfer operation in progress */ + { .name = "BXSR", .cp = 15, .crn = 7, .crm = 12, .opc1 = 0, .opc2 = 4, + .access = PL0_R, .type = ARM_CP_CONST, .resetvalue = 0 }, + REGINFO_SENTINEL +}; + +static const ARMCPRegInfo cache_test_clean_cp_reginfo[] = { + /* The cache test-and-clean instructions always return (1 << 30) + * to indicate that there are no dirty cache lines. + */ + { .name = "TC_DCACHE", .cp = 15, .crn = 7, .crm = 10, .opc1 = 0, .opc2 = 3, + .access = PL0_R, .type = ARM_CP_CONST, .resetvalue = (1 << 30) }, + { .name = "TCI_DCACHE", .cp = 15, .crn = 7, .crm = 14, .opc1 = 0, .opc2 = 3, + .access = PL0_R, .type = ARM_CP_CONST, .resetvalue = (1 << 30) }, + REGINFO_SENTINEL +}; + void register_cp_regs_for_features(ARMCPU *cpu) { /* Register all the coprocessor registers based on feature bits */ @@ -744,6 +786,15 @@ void register_cp_regs_for_features(ARMCPU *cpu) if (arm_feature(env, ARM_FEATURE_VAPA)) { define_arm_cp_regs(env, vapa_cp_reginfo); } + if (arm_feature(env, ARM_FEATURE_CACHE_TEST_CLEAN)) { + define_arm_cp_regs(env, cache_test_clean_cp_reginfo); + } + if (arm_feature(env, ARM_FEATURE_CACHE_DIRTY_REG)) { + define_arm_cp_regs(env, cache_dirty_status_cp_reginfo); + } + if (arm_feature(env, ARM_FEATURE_CACHE_BLOCK_OPS)) { + define_arm_cp_regs(env, cache_block_ops_cp_reginfo); + } if (arm_feature(env, ARM_FEATURE_OMAPCP)) { define_arm_cp_regs(env, omap_cp_reginfo); } @@ -1884,13 +1935,6 @@ void HELPER(set_cp15)(CPUARMState *env, uint32_t insn, uint32_t val) } } break; - case 7: /* Cache control. */ - env->cp15.c15_i_max = 0x000; - env->cp15.c15_i_min = 0xff0; - if (op1 != 0) { - goto bad_reg; - } - break; case 9: if (arm_feature(env, ARM_FEATURE_OMAPCP)) break; @@ -2096,10 +2140,6 @@ uint32_t HELPER(get_cp15)(CPUARMState *env, uint32_t insn) goto bad_reg; } } - case 7: /* Cache control. */ - /* FIXME: Should only clear Z flag if destination is r15. */ - env->ZF = 0; - return 0; case 9: switch (crm) { case 0: /* Cache lockdown */