From patchwork Tue Dec 20 19:10:38 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mark Langsdorf X-Patchwork-Id: 132503 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [140.186.70.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 01E14B7054 for ; Wed, 21 Dec 2011 06:11:08 +1100 (EST) Received: from localhost ([::1]:60095 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Rd55X-0003f7-JT for incoming@patchwork.ozlabs.org; Tue, 20 Dec 2011 14:10:59 -0500 Received: from eggs.gnu.org ([140.186.70.92]:47076) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Rd55F-0003Es-23 for qemu-devel@nongnu.org; Tue, 20 Dec 2011 14:10:46 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Rd55B-0005t7-2T for qemu-devel@nongnu.org; Tue, 20 Dec 2011 14:10:40 -0500 Received: from smtp191.dfw.emailsrvr.com ([67.192.241.191]:43727) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Rd55A-0005t0-Ik for qemu-devel@nongnu.org; Tue, 20 Dec 2011 14:10:37 -0500 Received: from localhost (localhost.localdomain [127.0.0.1]) by smtp19.relay.dfw1a.emailsrvr.com (SMTP Server) with ESMTP id 42AF03C86CF; Tue, 20 Dec 2011 14:10:36 -0500 (EST) X-Virus-Scanned: OK Received: by smtp19.relay.dfw1a.emailsrvr.com (Authenticated sender: mark.langsdorf-AT-calxeda.com) with ESMTPSA id 12F4E3C86C9; Tue, 20 Dec 2011 14:10:36 -0500 (EST) Message-ID: <4EF0DDAE.50706@calxeda.com> Date: Tue, 20 Dec 2011 13:10:38 -0600 From: Mark Langsdorf User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:8.0) Gecko/20111124 Thunderbird/8.0 MIME-Version: 1.0 To: qemu-devel@nongnu.org, paul@codesourcery.com, peter.maydell@linaro.org X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6 (newer, 3) X-Received-From: 67.192.241.191 Subject: [Qemu-devel] [PATCH 2/9] Add trustzone support. X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org From: juha.riihimaki@nokia.com Conflicts: target-arm/cpu.h target-arm/helper.c Signed-off-by: Mark Langsdorf --- target-arm/cpu.h | 4 + target-arm/helper.c | 556 +++++++++++++++++++++++++++++--------------------- target-arm/machine.c | 6 + 3 files changed, 335 insertions(+), 231 deletions(-) diff --git a/target-arm/cpu.h b/target-arm/cpu.h index c4d742f..129edbb 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -116,6 +116,9 @@ typedef struct CPUARMState { uint32_t c1_sys; /* System control register. */ uint32_t c1_coproc; /* Coprocessor access register. */ uint32_t c1_xscaleauxcr; /* XScale auxiliary control register. */ + uint32_t c1_secfg; /* Secure configuration register. */ + uint32_t c1_sedbg; /* Secure debug enable register. */ + uint32_t c1_nseac; /* Non-secure access control register. */ uint32_t c2_base0; /* MMU translation table base 0. */ uint32_t c2_base1; /* MMU translation table base 1. */ uint32_t c2_control; /* MMU translation table base control. */ @@ -377,6 +380,7 @@ enum arm_features { ARM_FEATURE_VAPA, /* cp15 VA to PA lookups */ ARM_FEATURE_ARM_DIV, /* divide supported in ARM encoding */ ARM_FEATURE_VFP4, /* VFPv4 (implies that NEON is v2) */ + ARM_FEATURE_TRUSTZONE /* TrustZone Security Extensions. */ }; static inline int arm_feature(CPUARMState *env, int feature) diff --git a/target-arm/helper.c b/target-arm/helper.c index 65f4fbf..816c4c4 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -124,6 +124,7 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id) set_feature(env, ARM_FEATURE_VFP3); set_feature(env, ARM_FEATURE_NEON); set_feature(env, ARM_FEATURE_THUMB2EE); + set_feature(env, ARM_FEATURE_TRUSTZONE); env->vfp.xregs[ARM_VFP_FPSID] = 0x410330c0; env->vfp.xregs[ARM_VFP_MVFR0] = 0x11110222; env->vfp.xregs[ARM_VFP_MVFR1] = 0x00011100; @@ -147,6 +148,7 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id) * and valid configurations; we don't model A9UP). */ set_feature(env, ARM_FEATURE_V7MP); + set_feature(env, ARM_FEATURE_TRUSTZONE); env->vfp.xregs[ARM_VFP_FPSID] = 0x41034000; /* Guess */ env->vfp.xregs[ARM_VFP_MVFR0] = 0x11110222; env->vfp.xregs[ARM_VFP_MVFR1] = 0x01111111; @@ -1000,7 +1002,7 @@ static uint32_t get_level1_table_address(CPUState *env, uint32_t address) } static int get_phys_addr_v5(CPUState *env, uint32_t address, int access_type, - int is_user, uint32_t *phys_ptr, int *prot, + int is_user, uint32_t *phys_ptr, int *prot, target_ulong *page_size) { int code; @@ -1039,13 +1041,13 @@ static int get_phys_addr_v5(CPUState *env, uint32_t address, int access_type, *page_size = 1024 * 1024; } else { /* Lookup l2 entry. */ - if (type == 1) { - /* Coarse pagetable. */ - table = (desc & 0xfffffc00) | ((address >> 10) & 0x3fc); - } else { - /* Fine pagetable. */ - table = (desc & 0xfffff000) | ((address >> 8) & 0xffc); - } + if (type == 1) { + /* Coarse pagetable. */ + table = (desc & 0xfffffc00) | ((address >> 10) & 0x3fc); + } else { + /* Fine pagetable. */ + table = (desc & 0xfffff000) | ((address >> 8) & 0xffc); + } desc = ldl_phys(table); switch (desc & 3) { case 0: /* Page translation fault. */ @@ -1062,17 +1064,17 @@ static int get_phys_addr_v5(CPUState *env, uint32_t address, int access_type, *page_size = 0x1000; break; case 3: /* 1k page. */ - if (type == 1) { - if (arm_feature(env, ARM_FEATURE_XSCALE)) { - phys_addr = (desc & 0xfffff000) | (address & 0xfff); - } else { - /* Page translation fault. */ - code = 7; - goto do_fault; - } - } else { - phys_addr = (desc & 0xfffffc00) | (address & 0x3ff); - } + if (type == 1) { + if (arm_feature(env, ARM_FEATURE_XSCALE)) { + phys_addr = (desc & 0xfffff000) | (address & 0xfff); + } else { + /* Page translation fault. */ + code = 7; + goto do_fault; + } + } else { + phys_addr = (desc & 0xfffffc00) | (address & 0x3ff); + } ap = (desc >> 4) & 3; *page_size = 0x400; break; @@ -1095,7 +1097,7 @@ do_fault: } static int get_phys_addr_v6(CPUState *env, uint32_t address, int access_type, - int is_user, uint32_t *phys_ptr, int *prot, + int is_user, uint32_t *phys_ptr, int *prot, target_ulong *page_size) { int code; @@ -1113,7 +1115,7 @@ static int get_phys_addr_v6(CPUState *env, uint32_t address, int access_type, table = get_level1_table_address(env, address); desc = ldl_phys(table); type = (desc & 3); - if (type == 0) { + if (type == 0 || type == 3) { /* Section translation fault. */ code = 5; domain = 0; @@ -1199,7 +1201,7 @@ do_fault: } static int get_phys_addr_mpu(CPUState *env, uint32_t address, int access_type, - int is_user, uint32_t *phys_ptr, int *prot) + int is_user, uint32_t *phys_ptr, int *prot) { int n; uint32_t mask; @@ -1207,52 +1209,58 @@ static int get_phys_addr_mpu(CPUState *env, uint32_t address, int access_type, *phys_ptr = address; for (n = 7; n >= 0; n--) { - base = env->cp15.c6_region[n]; - if ((base & 1) == 0) - continue; - mask = 1 << ((base >> 1) & 0x1f); - /* Keep this shift separate from the above to avoid an - (undefined) << 32. */ - mask = (mask << 1) - 1; - if (((base ^ address) & ~mask) == 0) - break; - } - if (n < 0) - return 2; + base = env->cp15.c6_region[n]; + if ((base & 1) == 0) { + continue; + } + mask = 1 << ((base >> 1) & 0x1f); + /* Keep this shift separate from the above to avoid an + (undefined) << 32. */ + mask = (mask << 1) - 1; + if (((base ^ address) & ~mask) == 0) { + break; + } + } + if (n < 0) { + return 2; + } if (access_type == 2) { - mask = env->cp15.c5_insn; + mask = env->cp15.c5_insn; } else { - mask = env->cp15.c5_data; + mask = env->cp15.c5_data; } mask = (mask >> (n * 4)) & 0xf; switch (mask) { case 0: - return 1; + return 1; case 1: - if (is_user) - return 1; - *prot = PAGE_READ | PAGE_WRITE; - break; + if (is_user) { + return 1; + } + *prot = PAGE_READ | PAGE_WRITE; + break; case 2: - *prot = PAGE_READ; - if (!is_user) - *prot |= PAGE_WRITE; - break; + *prot = PAGE_READ; + if (!is_user) { + *prot |= PAGE_WRITE; + } + break; case 3: - *prot = PAGE_READ | PAGE_WRITE; - break; + *prot = PAGE_READ | PAGE_WRITE; + break; case 5: - if (is_user) - return 1; - *prot = PAGE_READ; - break; + if (is_user) { + return 1; + } + *prot = PAGE_READ; + break; case 6: - *prot = PAGE_READ; - break; + *prot = PAGE_READ; + break; default: - /* Bad permission. */ - return 1; + /* Bad permission. */ + return 1; } *prot |= PAGE_EXEC; return 0; @@ -1264,8 +1272,9 @@ static inline int get_phys_addr(CPUState *env, uint32_t address, target_ulong *page_size) { /* Fast Context Switch Extension. */ - if (address < 0x02000000) + if (address < 0x02000000) { address += env->cp15.c13_fcse; + } if ((env->cp15.c1_sys & 1) == 0) { /* MMU/MPU disabled. */ @@ -1275,8 +1284,8 @@ static inline int get_phys_addr(CPUState *env, uint32_t address, return 0; } else if (arm_feature(env, ARM_FEATURE_MPU)) { *page_size = TARGET_PAGE_SIZE; - return get_phys_addr_mpu(env, address, access_type, is_user, phys_ptr, - prot); + return get_phys_addr_mpu(env, address, access_type, is_user, phys_ptr, + prot); } else if (env->cp15.c1_sys & (1 << 23)) { return get_phys_addr_v6(env, address, access_type, is_user, phys_ptr, prot, page_size); @@ -1328,9 +1337,9 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) ret = get_phys_addr(env, addr, 0, 0, &phys_addr, &prot, &page_size); - if (ret != 0) + if (ret != 0) { return -1; - + } return phys_addr; } @@ -1341,9 +1350,10 @@ void HELPER(set_cp)(CPUState *env, uint32_t insn, uint32_t val) int src = (insn >> 16) & 0xf; int operand = insn & 0xf; - if (env->cp[cp_num].cp_write) + if (env->cp[cp_num].cp_write) { env->cp[cp_num].cp_write(env->cp[cp_num].opaque, cp_info, src, operand, val); + } } uint32_t HELPER(get_cp)(CPUState *env, uint32_t insn) @@ -1353,9 +1363,10 @@ uint32_t HELPER(get_cp)(CPUState *env, uint32_t insn) int dest = (insn >> 16) & 0xf; int operand = insn & 0xf; - if (env->cp[cp_num].cp_read) + if (env->cp[cp_num].cp_read) { return env->cp[cp_num].cp_read(env->cp[cp_num].opaque, cp_info, dest, operand); + } return 0; } @@ -1401,10 +1412,12 @@ void HELPER(set_cp15)(CPUState *env, uint32_t insn, uint32_t val) switch ((insn >> 16) & 0xf) { case 0: /* ID codes. */ - if (arm_feature(env, ARM_FEATURE_XSCALE)) + if (arm_feature(env, ARM_FEATURE_XSCALE)) { break; - if (arm_feature(env, ARM_FEATURE_OMAPCP)) + } + if (arm_feature(env, ARM_FEATURE_OMAPCP)) { break; + } if (arm_feature(env, ARM_FEATURE_V7) && op1 == 2 && crm == 0 && op2 == 0) { env->cp15.c0_cssel = val & 0xf; @@ -1412,17 +1425,21 @@ void HELPER(set_cp15)(CPUState *env, uint32_t insn, uint32_t val) } goto bad_reg; case 1: /* System configuration. */ - if (arm_feature(env, ARM_FEATURE_OMAPCP)) + switch (crm) { + case 0: + if (arm_feature(env, ARM_FEATURE_OMAPCP)) { op2 = 0; + } switch (op2) { case 0: - if (!arm_feature(env, ARM_FEATURE_XSCALE) || crm == 0) + if (!arm_feature(env, ARM_FEATURE_XSCALE)) { env->cp15.c1_sys = val; + } /* ??? Lots of these bits are not implemented. */ /* This may enable/disable the MMU, so do a TLB flush. */ tlb_flush(env, 1); break; - case 1: /* Auxiliary control register. */ + case 1: /* Auxiliary cotrol register. */ if (arm_feature(env, ARM_FEATURE_XSCALE)) { env->cp15.c1_xscaleauxcr = val; break; @@ -1430,8 +1447,9 @@ void HELPER(set_cp15)(CPUState *env, uint32_t insn, uint32_t val) /* Not implemented. */ break; case 2: - if (arm_feature(env, ARM_FEATURE_XSCALE)) + if (arm_feature(env, ARM_FEATURE_XSCALE)) { goto bad_reg; + } if (env->cp15.c1_coproc != val) { env->cp15.c1_coproc = val; /* ??? Is this safe when called from within a TB? */ @@ -1442,6 +1460,38 @@ void HELPER(set_cp15)(CPUState *env, uint32_t insn, uint32_t val) goto bad_reg; } break; + case 1: + if (!arm_feature(env, ARM_FEATURE_TRUSTZONE) + || (env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_USR) { + goto bad_reg; + } + switch (op2) { + case 0: /* Secure configuration register. */ + if (env->cp15.c1_secfg & 1) { + goto bad_reg; + } + env->cp15.c1_secfg = val; + break; + case 1: /* Secure debug enable register. */ + if (env->cp15.c1_secfg & 1) { + goto bad_reg; + } + env->cp15.c1_sedbg = val; + break; + case 2: /* Nonsecure access control register. */ + if (env->cp15.c1_secfg & 1) { + goto bad_reg; + } + env->cp15.c1_nseac = val; + break; + default: + goto bad_reg; + } + break; + default: + goto bad_reg; + } + break; case 2: /* MMU Page table control / MPU cache control. */ if (arm_feature(env, ARM_FEATURE_MPU)) { switch (op2) { @@ -1455,22 +1505,22 @@ void HELPER(set_cp15)(CPUState *env, uint32_t insn, uint32_t val) goto bad_reg; } } else { - switch (op2) { - case 0: - env->cp15.c2_base0 = val; - break; - case 1: - env->cp15.c2_base1 = val; - break; - case 2: + switch (op2) { + case 0: + env->cp15.c2_base0 = val; + break; + case 1: + env->cp15.c2_base1 = val; + break; + case 2: val &= 7; env->cp15.c2_control = val; - env->cp15.c2_mask = ~(((uint32_t)0xffffffffu) >> val); + env->cp15.c2_mask = ~(((uint32_t)0xffffffffu) >> val); env->cp15.c2_base_mask = ~((uint32_t)0x3fffu >> val); - break; - default: - goto bad_reg; - } + break; + default: + goto bad_reg; + } } break; case 3: /* MMU Domain access control / MPU write buffer control. */ @@ -1509,8 +1559,9 @@ void HELPER(set_cp15)(CPUState *env, uint32_t insn, uint32_t val) break; case 6: /* MMU Fault address / MPU base/size. */ if (arm_feature(env, ARM_FEATURE_MPU)) { - if (crm >= 8) + if (crm >= 8) { goto bad_reg; + } env->cp15.c6_region[crm] = val; } else { if (arm_feature(env, ARM_FEATURE_OMAPCP)) @@ -1544,7 +1595,7 @@ void HELPER(set_cp15)(CPUState *env, uint32_t insn, uint32_t val) env->cp15.c7_par = val & 0xfffff1ff; } break; - case 8: { + case 8: uint32_t phys_addr; target_ulong page_size; int prot; @@ -1572,7 +1623,6 @@ void HELPER(set_cp15)(CPUState *env, uint32_t insn, uint32_t val) } break; } - } } break; case 8: /* MMU TLB control. */ @@ -1595,32 +1645,34 @@ void HELPER(set_cp15)(CPUState *env, uint32_t insn, uint32_t val) } break; case 9: - if (arm_feature(env, ARM_FEATURE_OMAPCP)) + if (arm_feature(env, ARM_FEATURE_OMAPCP)) { break; - if (arm_feature(env, ARM_FEATURE_STRONGARM)) + } + if (arm_feature(env, ARM_FEATURE_STRONGARM)) { break; /* Ignore ReadBuffer access */ + } switch (crm) { case 0: /* Cache lockdown. */ - switch (op1) { - case 0: /* L1 cache. */ - switch (op2) { - case 0: - env->cp15.c9_data = val; - break; - case 1: - env->cp15.c9_insn = val; - break; - default: - goto bad_reg; - } - break; - case 1: /* L2 cache. */ - /* Ignore writes to L2 lockdown/auxiliary registers. */ - break; - default: - goto bad_reg; - } - break; + switch (op1) { + case 0: /* L1 cache. */ + switch (op2) { + case 0: + env->cp15.c9_data = val; + break; + case 1: + env->cp15.c9_insn = val; + break; + default: + goto bad_reg; + } + break; + case 1: /* L2 cache. */ + /* Ignore writes to L2 lockdown/auxiliary registers. */ + break; + default: + goto bad_reg; + } + break; case 1: /* TCM memory region registers. */ /* Not implemented. */ goto bad_reg; @@ -1714,15 +1766,17 @@ void HELPER(set_cp15)(CPUState *env, uint32_t insn, uint32_t val) /* Unlike real hardware the qemu TLB uses virtual addresses, not modified virtual addresses, so this causes a TLB flush. */ - if (env->cp15.c13_fcse != val) - tlb_flush(env, 1); + if (env->cp15.c13_fcse != val) { + tlb_flush(env, 1); + } env->cp15.c13_fcse = val; break; case 1: /* This changes the ASID, so do a TLB flush. */ if (env->cp15.c13_context != val - && !arm_feature(env, ARM_FEATURE_MPU)) - tlb_flush(env, 0); + && !arm_feature(env, ARM_FEATURE_MPU)) { + tlb_flush(env, 0); + } env->cp15.c13_context = val; break; default: @@ -1796,7 +1850,7 @@ uint32_t HELPER(get_cp15)(CPUState *env, uint32_t insn) case 0: /* Device ID. */ return env->cp15.c0_cpuid; case 1: /* Cache Type. */ - return env->cp15.c0_cachetype; + return env->cp15.c0_cachetype; case 2: /* TCM status. */ return 0; case 3: /* TLB type register. */ @@ -1839,15 +1893,19 @@ uint32_t HELPER(get_cp15)(CPUState *env, uint32_t insn) default: goto bad_reg; } + break; case 1: /* These registers aren't documented on arm11 cores. However Linux looks at them anyway. */ - if (!arm_feature(env, ARM_FEATURE_V6)) + if (!arm_feature(env, ARM_FEATURE_V6)) { goto bad_reg; - if (crm != 0) + } + if (crm != 0) { goto bad_reg; - if (!arm_feature(env, ARM_FEATURE_V7)) + } + if (!arm_feature(env, ARM_FEATURE_V7)) { return 0; + } switch (op2) { case 0: @@ -1859,46 +1917,81 @@ uint32_t HELPER(get_cp15)(CPUState *env, uint32_t insn) } goto bad_reg; case 2: - if (op2 != 0 || crm != 0) + if (op2 != 0 || crm != 0) { goto bad_reg; + } return env->cp15.c0_cssel; default: goto bad_reg; } + break; case 1: /* System configuration. */ - if (arm_feature(env, ARM_FEATURE_OMAPCP)) - op2 = 0; - switch (op2) { - case 0: /* Control register. */ - return env->cp15.c1_sys; - case 1: /* Auxiliary control register. */ - if (arm_feature(env, ARM_FEATURE_XSCALE)) - return env->cp15.c1_xscaleauxcr; - if (!arm_feature(env, ARM_FEATURE_AUXCR)) - goto bad_reg; - switch (ARM_CPUID(env)) { - case ARM_CPUID_ARM1026: - return 1; - case ARM_CPUID_ARM1136: - case ARM_CPUID_ARM1136_R2: - case ARM_CPUID_ARM1176: - return 7; - case ARM_CPUID_ARM11MPCORE: - return 1; - case ARM_CPUID_CORTEXA8: - return 2; - case ARM_CPUID_CORTEXA9: - return 0; + switch (crm) { + case 0: + if (arm_feature(env, ARM_FEATURE_OMAPCP)) { + op2 = 0; + } + switch (op2) { + case 0: /* Control register. */ + return env->cp15.c1_sys; + case 1: /* Auxiliary control register. */ + if (arm_feature(env, ARM_FEATURE_XSCALE)) { + return env->cp15.c1_xscaleauxcr; + } + if (!arm_feature(env, ARM_FEATURE_AUXCR)) { + goto bad_reg; + } + switch (ARM_CPUID(env)) { + case ARM_CPUID_ARM1026: + return 1; + case ARM_CPUID_ARM1136: + case ARM_CPUID_ARM1136_R2: + return 7; + case ARM_CPUID_ARM11MPCORE: + return 1; + case ARM_CPUID_CORTEXA8: + return 2; + case ARM_CPUID_CORTEXA9: + return 0; + default: + goto bad_reg; + } + break; + case 2: /* Coprocessor access register. */ + if (arm_feature(env, ARM_FEATURE_XSCALE)) { + goto bad_reg; + } + return env->cp15.c1_coproc; default: goto bad_reg; } - case 2: /* Coprocessor access register. */ - if (arm_feature(env, ARM_FEATURE_XSCALE)) + break; + case 1: + if (!arm_feature(env, ARM_FEATURE_TRUSTZONE) + || (env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_USR) { + goto bad_reg; + } + switch (op2) { + case 0: /* Secure configuration register. */ + if (env->cp15.c1_secfg & 1) { + goto bad_reg; + } + return env->cp15.c1_secfg; + case 1: /* Secure debug enable register. */ + if (env->cp15.c1_secfg & 1) { + goto bad_reg; + } + return env->cp15.c1_sedbg; + case 2: /* Nonsecure access control register. */ + return env->cp15.c1_nseac; + default: goto bad_reg; - return env->cp15.c1_coproc; + } + break; default: goto bad_reg; } + break; case 2: /* MMU Page table control / MPU cache control. */ if (arm_feature(env, ARM_FEATURE_MPU)) { switch (op2) { @@ -1912,17 +2005,17 @@ uint32_t HELPER(get_cp15)(CPUState *env, uint32_t insn) goto bad_reg; } } else { - switch (op2) { - case 0: - return env->cp15.c2_base0; - case 1: - return env->cp15.c2_base1; - case 2: + switch (op2) { + case 0: + return env->cp15.c2_base0; + case 1: + return env->cp15.c2_base1; + case 2: return env->cp15.c2_control; - default: - goto bad_reg; - } - } + default: + goto bad_reg; + } + } case 3: /* MMU Domain access control / MPU write buffer control. */ return env->cp15.c3; case 4: /* Reserved. */ @@ -1932,95 +2025,76 @@ uint32_t HELPER(get_cp15)(CPUState *env, uint32_t insn) op2 = 0; switch (op2) { case 0: - if (arm_feature(env, ARM_FEATURE_MPU)) + if (arm_feature(env, ARM_FEATURE_MPU)) { return simple_mpu_ap_bits(env->cp15.c5_data); + } return env->cp15.c5_data; case 1: - if (arm_feature(env, ARM_FEATURE_MPU)) + if (arm_feature(env, ARM_FEATURE_MPU)) { return simple_mpu_ap_bits(env->cp15.c5_data); + } return env->cp15.c5_insn; case 2: - if (!arm_feature(env, ARM_FEATURE_MPU)) + if (!arm_feature(env, ARM_FEATURE_MPU)) { goto bad_reg; + } return env->cp15.c5_data; case 3: - if (!arm_feature(env, ARM_FEATURE_MPU)) + if (!arm_feature(env, ARM_FEATURE_MPU)) { goto bad_reg; + } return env->cp15.c5_insn; default: goto bad_reg; } case 6: /* MMU Fault address. */ if (arm_feature(env, ARM_FEATURE_MPU)) { - if (crm >= 8) + if (crm >= 8) { goto bad_reg; + } return env->cp15.c6_region[crm]; } else { if (arm_feature(env, ARM_FEATURE_OMAPCP)) op2 = 0; - switch (op2) { - case 0: - return env->cp15.c6_data; - case 1: - if (arm_feature(env, ARM_FEATURE_V6)) { - /* Watchpoint Fault Adrress. */ - return 0; /* Not implemented. */ - } else { - /* Instruction Fault Adrress. */ - /* Arm9 doesn't have an IFAR, but implementing it anyway - shouldn't do any harm. */ - return env->cp15.c6_insn; - } - case 2: - if (arm_feature(env, ARM_FEATURE_V6)) { - /* Instruction Fault Adrress. */ - return env->cp15.c6_insn; - } else { - goto bad_reg; - } - default: - goto bad_reg; - } + switch (op2) { + case 0: + return env->cp15.c6_data; + case 1: + if (arm_feature(env, ARM_FEATURE_V6)) { + /* Watchpoint Fault Adrress. */ + return 0; /* Not implemented. */ + } + /* Instruction Fault Adrress. */ + /* Arm9 doesn't have an IFAR, but implementing it anyway + shouldn't do any harm. */ + return env->cp15.c6_insn; + case 2: + if (arm_feature(env, ARM_FEATURE_V6)) { + /* Instruction Fault Adrress. */ + return env->cp15.c6_insn; + } + goto bad_reg; + default: + goto bad_reg; + } } case 7: /* Cache control. */ if (crm == 4 && op1 == 0 && op2 == 0) { return env->cp15.c7_par; } - /* FIXME: Should only clear Z flag if destination is r15. */ - env->ZF = 0; + /* FIXME this is still totally in the wrong place! */ + /* clear ZF only if destination is r15 */ + if (((insn >> 12) & 0xf) == 0xf) { + env->ZF = 0; + } return 0; case 8: /* MMU TLB control. */ goto bad_reg; - case 9: - switch (crm) { - case 0: /* Cache lockdown */ - switch (op1) { - case 0: /* L1 cache. */ - if (arm_feature(env, ARM_FEATURE_OMAPCP)) { - return 0; - } - switch (op2) { - case 0: - return env->cp15.c9_data; - case 1: - return env->cp15.c9_insn; - default: - goto bad_reg; - } - case 1: /* L2 cache */ - if (crm != 0) { - goto bad_reg; - } - /* L2 Lockdown and Auxiliary control. */ + case 9: /* Cache lockdown. */ + switch (op1) { + case 0: /* L1 cache. */ + if (arm_feature(env, ARM_FEATURE_OMAPCP)) return 0; - default: - 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; @@ -2071,6 +2145,18 @@ uint32_t HELPER(get_cp15)(CPUState *env, uint32_t insn) return 0; case 11: /* TCM DMA control. */ case 12: /* Reserved. */ + if (!op1) { + switch (crm) { + case 0: /* secure or nonsecure vector base address */ + if (arm_feature(env, ARM_FEATURE_TRUSTZONE)) { + /* FIXME: implement true vector base addressing */ + return 0; /* reset value according to ARM Cortex-A8 TRM */ + } + break; + default: + break; + } + } goto bad_reg; case 13: /* Process ID. */ switch (op2) { @@ -2212,10 +2298,11 @@ void HELPER(v7m_msr)(CPUState *env, uint32_t reg, uint32_t val) env->v7m.other_sp = val; break; case 16: /* PRIMASK */ - if (val & 1) + if (val & 1) { env->uncached_cpsr |= CPSR_I; - else + } else { env->uncached_cpsr &= ~CPSR_I; + } break; case 17: /* BASEPRI */ env->v7m.basepri = val & 0xff; @@ -2226,10 +2313,11 @@ void HELPER(v7m_msr)(CPUState *env, uint32_t reg, uint32_t val) env->v7m.basepri = val; break; case 19: /* FAULTMASK */ - if (val & 1) + if (val & 1) { env->uncached_cpsr |= CPSR_F; - else + } else { env->uncached_cpsr &= ~CPSR_F; + } break; case 20: /* CONTROL */ env->v7m.control = val & 3; @@ -2271,10 +2359,11 @@ static inline uint16_t add16_sat(uint16_t a, uint16_t b) res = a + b; if (((res ^ a) & 0x8000) && !((a ^ b) & 0x8000)) { - if (a & 0x8000) + if (a & 0x8000) { res = 0x8000; - else + } else { res = 0x7fff; + } } return res; } @@ -2286,10 +2375,11 @@ static inline uint8_t add8_sat(uint8_t a, uint8_t b) res = a + b; if (((res ^ a) & 0x80) && !((a ^ b) & 0x80)) { - if (a & 0x80) + if (a & 0x80) { res = 0x80; - else + } else { res = 0x7f; + } } return res; } @@ -2301,10 +2391,11 @@ static inline uint16_t sub16_sat(uint16_t a, uint16_t b) res = a - b; if (((res ^ a) & 0x8000) && ((a ^ b) & 0x8000)) { - if (a & 0x8000) + if (a & 0x8000) { res = 0x8000; - else + } else { res = 0x7fff; + } } return res; } @@ -2316,10 +2407,11 @@ static inline uint8_t sub8_sat(uint8_t a, uint8_t b) res = a - b; if (((res ^ a) & 0x80) && ((a ^ b) & 0x80)) { - if (a & 0x80) + if (a & 0x80) { res = 0x80; - else + } else { res = 0x7f; + } } return res; } @@ -2344,10 +2436,11 @@ static inline uint16_t add16_usat(uint16_t a, uint16_t b) static inline uint16_t sub16_usat(uint16_t a, uint16_t b) { - if (a > b) + if (a > b) { return a - b; - else + } else { return 0; + } } static inline uint8_t add8_usat(uint8_t a, uint8_t b) @@ -2361,10 +2454,11 @@ static inline uint8_t add8_usat(uint8_t a, uint8_t b) static inline uint8_t sub8_usat(uint8_t a, uint8_t b) { - if (a > b) + if (a > b) { return a - b; - else + } else { return 0; + } } #define ADD16(a, b, n) RESULT(add16_usat(a, b), n, 16); @@ -2468,10 +2562,11 @@ static inline uint8_t sub8_usat(uint8_t a, uint8_t b) static inline uint8_t do_usad(uint8_t a, uint8_t b) { - if (a > b) + if (a > b) { return a - b; - else + } else { return b - a; + } } /* Unsigned sum of absolute byte differences. */ @@ -2925,9 +3020,8 @@ float32 HELPER(recpe_f32)(float32 a, CPUState *env) f64 = recip_estimate(f64, env); - val32 = sign - | ((result_exp & 0xff) << 23) - | ((float64_val(f64) >> 29) & 0x7fffff); + val32 = sign | ((result_exp & 0xff) << 23) | + ((float64_val(f64) >> 29) & 0x7fffff); return make_float32(val32); } diff --git a/target-arm/machine.c b/target-arm/machine.c index aaee9b9..975b522 100644 --- a/target-arm/machine.c +++ b/target-arm/machine.c @@ -26,6 +26,9 @@ void cpu_save(QEMUFile *f, void *opaque) qemu_put_be32(f, env->cp15.c1_sys); qemu_put_be32(f, env->cp15.c1_coproc); qemu_put_be32(f, env->cp15.c1_xscaleauxcr); + qemu_put_be32(f, env->cp15.c1_secfg); + qemu_put_be32(f, env->cp15.c1_sedbg); + qemu_put_be32(f, env->cp15.c1_nseac); qemu_put_be32(f, env->cp15.c2_base0); qemu_put_be32(f, env->cp15.c2_base1); qemu_put_be32(f, env->cp15.c2_control); @@ -140,6 +143,9 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) env->cp15.c1_sys = qemu_get_be32(f); env->cp15.c1_coproc = qemu_get_be32(f); env->cp15.c1_xscaleauxcr = qemu_get_be32(f); + env->cp15.c1_secfg = qemu_get_be32(f); + env->cp15.c1_sedbg = qemu_get_be32(f); + env->cp15.c1_nseac = qemu_get_be32(f); env->cp15.c2_base0 = qemu_get_be32(f); env->cp15.c2_base1 = qemu_get_be32(f); env->cp15.c2_control = qemu_get_be32(f);