From 8132c01830c9e71e75e6bc1e365326cf07c5b00f Mon Sep 17 00:00:00 2001
From: Kevin Hartman <kevin@hart.mn>
Date: Mon, 5 Jan 2015 02:17:00 -0500
Subject: [PATCH] Added exclusive reservation granule from ARMv7 spec to dyncom
 to protect LDR/STREX.

---
 .../arm/dyncom/arm_dyncom_interpreter.cpp     | 12 +++++-----
 src/core/arm/skyeye_common/armdefs.h          | 22 +++++++++----------
 2 files changed, 18 insertions(+), 16 deletions(-)

diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
index 64335b9c20..ba23ef3838 100644
--- a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
+++ b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
@@ -63,16 +63,21 @@ extern void switch_mode(arm_core_t *core, uint32_t mode);
 typedef arm_core_t arm_processor;
 typedef unsigned int (*shtop_fp_t)(arm_processor *cpu, unsigned int sht_oper);
 
+// Defines a reservation granule of 2 words, which protects the first 2 words starting at the tag.
+// This is the smallest granule allowed by the v7 spec, and is coincidentally just large enough to
+// support LDR/STREXD.
+static const ARMword RESERVATION_GRANULE_MASK = 0xFFFFFFF8;
+
 // Exclusive memory access
 static int exclusive_detect(ARMul_State* state, ARMword addr){
-    if(state->exclusive_tag == addr)
+    if(state->exclusive_tag == (addr & RESERVATION_GRANULE_MASK))
         return 0;
     else
         return -1;
 }
 
 static void add_exclusive_addr(ARMul_State* state, ARMword addr){
-    state->exclusive_tag = addr;
+    state->exclusive_tag = addr & RESERVATION_GRANULE_MASK;
     return;
 }
 
@@ -80,7 +85,6 @@ static void remove_exclusive(ARMul_State* state, ARMword addr){
     state->exclusive_tag = 0xFFFFFFFF;
 }
 
-
 unsigned int DPO(Immediate)(arm_processor *cpu, unsigned int sht_oper) {
     unsigned int immed_8 = BITS(sht_oper, 0, 7);
     unsigned int rotate_imm = BITS(sht_oper, 8, 11);
@@ -4551,7 +4555,6 @@ unsigned InterpreterMainLoop(ARMul_State* state) {
 
             add_exclusive_addr(cpu, read_addr);
             cpu->exclusive_state = 1;
-            // TODO(bunnei): Do we need to also make [read_addr + 4] exclusive?
 
             RD = Memory::Read32(read_addr);
             RD2 = Memory::Read32(read_addr + 4);
@@ -5978,7 +5981,6 @@ unsigned InterpreterMainLoop(ARMul_State* state) {
             if ((exclusive_detect(cpu, write_addr) == 0) && (cpu->exclusive_state == 1)) {
                 remove_exclusive(cpu, write_addr);
                 cpu->exclusive_state = 0;
-                // TODO(bunnei): Remove exclusive from [write_addr + 4] if we implement this in LDREXD
 
                 Memory::Write32(write_addr, cpu->Reg[inst_cream->Rm]);
                 Memory::Write32(write_addr + 4, cpu->Reg[inst_cream->Rm + 1]);
diff --git a/src/core/arm/skyeye_common/armdefs.h b/src/core/arm/skyeye_common/armdefs.h
index c2c78cd5ab..4592c5808b 100644
--- a/src/core/arm/skyeye_common/armdefs.h
+++ b/src/core/arm/skyeye_common/armdefs.h
@@ -162,20 +162,20 @@ struct ARMul_State
     unsigned ErrorCode;    /* type of illegal instruction */
 
     /* Order of the following register should not be modified */
-    ARMword Reg[16];      /* the current register file */
-    ARMword Cpsr;         /* the current psr */
+    ARMword Reg[16];            /* the current register file */
+    ARMword Cpsr;               /* the current psr */
     ARMword Spsr_copy;
     ARMword phys_pc;
     ARMword Reg_usr[2];
-    ARMword Reg_svc[2];   /* R13_SVC R14_SVC */
-    ARMword Reg_abort[2]; /* R13_ABORT R14_ABORT */
-    ARMword Reg_undef[2]; /* R13 UNDEF R14 UNDEF */
-    ARMword Reg_irq[2];   /* R13_IRQ R14_IRQ */
-    ARMword Reg_firq[7];  /* R8---R14 FIRQ */
-    ARMword Spsr[7];      /* the exception psr's */
-    ARMword Mode;         /* the current mode */
-    ARMword Bank;         /* the current register bank */
-    ARMword exclusive_tag;
+    ARMword Reg_svc[2];         /* R13_SVC R14_SVC */
+    ARMword Reg_abort[2];       /* R13_ABORT R14_ABORT */
+    ARMword Reg_undef[2];       /* R13 UNDEF R14 UNDEF */
+    ARMword Reg_irq[2];         /* R13_IRQ R14_IRQ */
+    ARMword Reg_firq[7];        /* R8---R14 FIRQ */
+    ARMword Spsr[7];            /* the exception psr's */
+    ARMword Mode;               /* the current mode */
+    ARMword Bank;               /* the current register bank */
+    ARMword exclusive_tag;      /* the address for which the local monitor is in exclusive access mode */
     ARMword exclusive_state;
     ARMword exclusive_result;
     ARMword CP15[VFP_BASE - CP15_BASE];