diff mbox

[2/9] Add trustzone support.

Message ID 4EF0DDAE.50706@calxeda.com
State New
Headers show

Commit Message

Mark Langsdorf Dec. 20, 2011, 7:10 p.m. UTC
From: juha.riihimaki@nokia.com

Conflicts:

         target-arm/cpu.h
         target-arm/helper.c

Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
---
  target-arm/cpu.h     |    4 +
  target-arm/helper.c  |  556 
+++++++++++++++++++++++++++++---------------------
  target-arm/machine.c |    6 +
  3 files changed, 335 insertions(+), 231 deletions(-)

Comments

Peter Maydell Dec. 20, 2011, 7:38 p.m. UTC | #1
On 20 December 2011 19:10, Mark Langsdorf <mark.langsdorf@calxeda.com> wrote:
> From: juha.riihimaki@nokia.com
>
> Conflicts:
>
>        target-arm/cpu.h
>        target-arm/helper.c
>
> Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>

All sorts of problems here, I'm afraid.
 * you can't submit a patch written by somebody else and without
   their sign-off
 * no git 'conflicts' messages in commit messages!
 * lots of irrelevant changes (like the brace changes)
 * it's clearly not actually an implementation of trustzone
   (just for a start, no register banking, and no monitor mode)

This is a long way from being acceptable upstream.

I have a variant on this patch in qemu-linaro
(http://git.linaro.org/gitweb?p=qemu/qemu-linaro.git;a=commitdiff;h=52bca16c339bebfc8d0a359886c0a63988ec6735)
which at least has fewer irrelevant bits in it but is still
in need of attention. More promisingly,
  https://github.com/jowinter/qemu-trustzone
is a much more complete trustzone implementation, and Johannes
has said he hopes to get it into shape for upstream.

-- PMM
diff mbox

Patch

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);