From 858acfd44a367a693ea803f1bbddb11cdcaf0362 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Juha=20Riihim=C3=A4ki?= Date: Wed, 21 Jan 2009 14:47:51 +0200 Subject: [PATCH] Add ARM TrustZone feature flag and security control registers in CP15 Add dummy implementation for security control registers in ARM CP15 c1. Also introduced ARM_FEATURE_TRUSTZONE flag which controls access to the new registers. Further, added dummy implementation for SMI/SMC ARM instruction; for the time being it is simply ignored when encountered. --- target-arm/cpu.h | 6 +- target-arm/helper.c | 284 +++++++++++++++++++++++++++++------------------- target-arm/machine.c | 6 + target-arm/translate.c | 20 +++- 4 files changed, 197 insertions(+), 119 deletions(-) diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 54c2c2e..6af633c 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -108,6 +108,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. */ @@ -337,7 +340,8 @@ enum arm_features { ARM_FEATURE_DIV, ARM_FEATURE_M, /* Microcontroller profile. */ ARM_FEATURE_OMAPCP, /* OMAP specific CP15 ops handling. */ - ARM_FEATURE_THUMB2EE + ARM_FEATURE_THUMB2EE, + 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 301c5f1..a5a1ea1 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -89,6 +89,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; @@ -1337,30 +1338,60 @@ 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)) - op2 = 0; - switch (op2) { + switch (crm) { case 0: - if (!arm_feature(env, ARM_FEATURE_XSCALE) || crm == 0) - 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 cotrol register. */ - if (arm_feature(env, ARM_FEATURE_XSCALE)) { - env->cp15.c1_xscaleauxcr = val; + if (arm_feature(env, ARM_FEATURE_OMAPCP)) + op2 = 0; + switch (op2) { + case 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 cotrol register. */ + if (arm_feature(env, ARM_FEATURE_XSCALE)) { + env->cp15.c1_xscaleauxcr = val; + break; + } + /* Not implemented. */ + break; + case 2: + 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? */ + tb_flush(env); + } + break; + default: + goto bad_reg; } - /* Not implemented. */ break; - case 2: - if (arm_feature(env, ARM_FEATURE_XSCALE)) + 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_register; + env->cp15.c1_nseac = val; + break; + default: goto bad_reg; - if (env->cp15.c1_coproc != val) { - env->cp15.c1_coproc = val; - /* ??? Is this safe when called from within a TB? */ - tb_flush(env); } break; default: @@ -1380,22 +1411,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. */ @@ -1494,26 +1525,26 @@ void HELPER(set_cp15)(CPUState *env, uint32_t insn, uint32_t val) break; 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; @@ -1623,7 +1654,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. */ @@ -1646,6 +1677,7 @@ 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. */ @@ -1672,37 +1704,65 @@ uint32_t HELPER(get_cp15)(CPUState *env, uint32_t insn) 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: - return 7; - case ARM_CPUID_ARM11MPCORE: - return 1; - case ARM_CPUID_CORTEXA8: - return 2; + 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; + 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; - return env->cp15.c1_coproc; + 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; + } + break; default: goto bad_reg; } + break; case 2: /* MMU Page table control / MPU cache control. */ if (arm_feature(env, ARM_FEATURE_MPU)) { switch (op2) { @@ -1716,17 +1776,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. */ @@ -1762,41 +1822,39 @@ uint32_t HELPER(get_cp15)(CPUState *env, uint32_t insn) } 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. */ - /* FIXME: Should only clear Z flag if destination is r15. */ - env->ZF = 0; + if ((insn >> 12) & 0xf) == 0xf) /* clear ZF only if destination is r15 */ + env->ZF = 0; return 0; case 8: /* MMU TLB control. */ goto bad_reg; case 9: /* Cache lockdown. */ switch (op1) { case 0: /* L1 cache. */ - if (arm_feature(env, ARM_FEATURE_OMAPCP)) - return 0; + if (arm_feature(env, ARM_FEATURE_OMAPCP)) + return 0; switch (op2) { case 0: return env->cp15.c9_data; diff --git a/target-arm/machine.c b/target-arm/machine.c index 323bace..36ca287 100644 --- a/target-arm/machine.c +++ b/target-arm/machine.c @@ -49,6 +49,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_mask); @@ -144,6 +147,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_mask = qemu_get_be32(f); diff --git a/target-arm/translate.c b/target-arm/translate.c index c36a91f..fa3351b 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -6015,11 +6015,21 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) dead_tmp(tmp2); store_reg(s, rd, tmp); break; - case 7: /* bkpt */ - gen_set_condexec(s); - gen_set_pc_im(s->pc - 4); - gen_exception(EXCP_BKPT); - s->is_jmp = DISAS_JUMP; + case 7: + if (op1 == 1) { + /* bkpt */ + gen_set_condexec(s); + gen_set_pc_im(s->pc - 4); + gen_exception(EXCP_BKPT); + s->is_jmp = DISAS_JUMP; + } else if (op1 == 3) { + /* smi/smc */ + if (!(env->cp15.c0_c2[4] & 0xf000)) + goto illegal_op; + /* unsupported at the moment, ignore. */ + } else { + goto illegal_op; + } break; case 0x8: /* signed multiply */ case 0xa: -- 1.7.9.5