target-arm: Exit cpu loop on wfe

Improves performance of spinlocks.

Change-Id: I449bd348a28814a445b27244e07f9d1f25503e4c
Signed-off-by: Arve Hjønnevåg <arve@android.com>
diff --git a/target-arm/helper.h b/target-arm/helper.h
index 63ae13a..40dea37 100644
--- a/target-arm/helper.h
+++ b/target-arm/helper.h
@@ -50,6 +50,7 @@
                    i32, i32, i32, i32)
 DEF_HELPER_2(exception, void, env, i32)
 DEF_HELPER_1(wfi, void, env)
+DEF_HELPER_1(wfe, void, env)
 
 DEF_HELPER_3(cpsr_write, void, env, i32, i32)
 DEF_HELPER_1(cpsr_read, i32, env)
diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c
index a918e5b..ca6eb5a 100644
--- a/target-arm/op_helper.c
+++ b/target-arm/op_helper.c
@@ -225,6 +225,14 @@
     cpu_loop_exit(env);
 }
 
+void HELPER(wfe)(CPUARMState *env)
+{
+    /* TODO: Implement WFE to actually wait for an event. For now, just give
+     * the next cpu a chance to run right away. */
+    env->exception_index = EXCP_HLT;
+    cpu_loop_exit(env);
+}
+
 void HELPER(exception)(CPUARMState *env, uint32_t excp)
 {
     env->exception_index = excp;
diff --git a/target-arm/translate.c b/target-arm/translate.c
index b164996..f3dcdf4 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -80,6 +80,7 @@
 #define DISAS_WFI 4
 #define DISAS_SWI 5
 #define DISAS_SMC 6
+#define DISAS_WFE 7
 
 TCGv_ptr cpu_env;
 /* We reuse the same 64-bit temporaries for efficiency.  */
@@ -3597,9 +3598,12 @@
         s->is_jmp = DISAS_WFI;
         break;
     case 2: /* wfe */
+        gen_set_pc_im(s, s->pc);
+        s->is_jmp = DISAS_WFE;
+        break;
     case 4: /* sev */
     case 5: /* sevl */
-        /* TODO: Implement SEV, SEVL and WFE.  May help SMP performance.  */
+        /* TODO: Implement SEV and SEVL.  May help SMP performance.  */
     default: /* nop */
         break;
     }
@@ -10300,6 +10304,9 @@
         case DISAS_WFI:
             gen_helper_wfi(cpu_env);
             break;
+        case DISAS_WFE:
+            gen_helper_wfe(cpu_env);
+            break;
         case DISAS_SWI:
             gen_exception(EXCP_SWI);
             break;