From cbfc4ff14e350e11f8f0e712a9497bb4251eab0b Mon Sep 17 00:00:00 2001
From: Jeffrey Lee <jlee@gitlab.riscosopen.org>
Date: Tue, 11 Aug 2015 19:52:12 +0000
Subject: [PATCH] Fix some re-entrancy issues. Minor optimisations.

Detail:
  s/TickEvents:
  - Change initial TickNodeLeft check in ProcessTickEventChain to exit on HI rather than NE. This fixes a case where the ticker event chain can become corrupted if ProcessTickEventChain is re-entered while in the middle of processing multiple nodes which are due to fire at the same time (after initial node is removed from the list, head node will be left with a TickNodeLeft value of 0)
  - Move "IRQ's off again" PSR write to be after the 10 label, to ensure that IRQs are off before we examine/process the next node (naughty CallEvery may have exited with IRQs enabled)
  - Stop using crusty old WritePSRc macro (currently generates 4 instructions for something that should be 1)
  - Also get rid of ARM2-era NOPs
  - Optimise CallEvery check to be MOVS rather than LDR + CMP
Admin:
  Tested on Pandaboard
  Should fix problem reported on forums with apparent wrap-around of TickNodeLeft value of first node: https://www.riscosopen.org/forum/forums/5/topics/3544
  May also fix other ticker corruption problems: https://www.riscosopen.org/forum/forums/4/topics/2708


Version 5.35, 4.79.2.278. Tagged as 'Kernel-5_35-4_79_2_278'
---
 VersionASM   | 10 +++++-----
 VersionNum   | 14 +++++++-------
 s/TickEvents | 18 ++++++++----------
 3 files changed, 20 insertions(+), 22 deletions(-)

diff --git a/VersionASM b/VersionASM
index 5c7bc82..407b672 100644
--- a/VersionASM
+++ b/VersionASM
@@ -13,11 +13,11 @@
                         GBLS    Module_ComponentPath
 Module_MajorVersion     SETS    "5.35"
 Module_Version          SETA    535
-Module_MinorVersion     SETS    "4.79.2.277"
-Module_Date             SETS    "10 Aug 2015"
-Module_ApplicationDate  SETS    "10-Aug-15"
+Module_MinorVersion     SETS    "4.79.2.278"
+Module_Date             SETS    "11 Aug 2015"
+Module_ApplicationDate  SETS    "11-Aug-15"
 Module_ComponentName    SETS    "Kernel"
 Module_ComponentPath    SETS    "castle/RiscOS/Sources/Kernel"
-Module_FullVersion      SETS    "5.35 (4.79.2.277)"
-Module_HelpVersion      SETS    "5.35 (10 Aug 2015) 4.79.2.277"
+Module_FullVersion      SETS    "5.35 (4.79.2.278)"
+Module_HelpVersion      SETS    "5.35 (11 Aug 2015) 4.79.2.278"
                         END
diff --git a/VersionNum b/VersionNum
index 5b4df7d..dd5c882 100644
--- a/VersionNum
+++ b/VersionNum
@@ -5,19 +5,19 @@
  *
  */
 #define Module_MajorVersion_CMHG        5.35
-#define Module_MinorVersion_CMHG        4.79.2.277
-#define Module_Date_CMHG                10 Aug 2015
+#define Module_MinorVersion_CMHG        4.79.2.278
+#define Module_Date_CMHG                11 Aug 2015
 
 #define Module_MajorVersion             "5.35"
 #define Module_Version                  535
-#define Module_MinorVersion             "4.79.2.277"
-#define Module_Date                     "10 Aug 2015"
+#define Module_MinorVersion             "4.79.2.278"
+#define Module_Date                     "11 Aug 2015"
 
-#define Module_ApplicationDate          "10-Aug-15"
+#define Module_ApplicationDate          "11-Aug-15"
 
 #define Module_ComponentName            "Kernel"
 #define Module_ComponentPath            "castle/RiscOS/Sources/Kernel"
 
-#define Module_FullVersion              "5.35 (4.79.2.277)"
-#define Module_HelpVersion              "5.35 (10 Aug 2015) 4.79.2.277"
+#define Module_FullVersion              "5.35 (4.79.2.278)"
+#define Module_HelpVersion              "5.35 (11 Aug 2015) 4.79.2.278"
 #define Module_LibraryVersionInfo       "5:35"
diff --git a/s/TickEvents b/s/TickEvents
index c7a5c63..47a9a95 100644
--- a/s/TickEvents
+++ b/s/TickEvents
@@ -145,11 +145,10 @@ ProcessTickEventChain  ROUT
         LDR     r2, [r1, #TickNodeLeft]
         SUBS    r2, r2, #1
         STR     r2, [r1, #TickNodeLeft]
-        MOVNE   pc, lr                          ; nothing to call yet (was MOVPL)
+        MOVHI   pc, lr                          ; nothing to call yet (HI to cope with ordinary 1 -> 0 transition, and 0 -> -1 transition if re-entered while processing two or more events which are due to fire at the same time)
 
         Push    "lr"                            ; save IRQ_lr
-        WritePSRc SVC_mode+I_bit, r10           ; switch to SVC mode, IRQ's off
-        NOP
+        MSR     CPSR_c, #SVC32_mode+I32_bit     ; switch to SVC mode, IRQ's off
         Push    "lr"                            ; save SVC_lr
 01
         LDMIA   r1, {r2, r10, r11, r12}         ; load next ptr, redo state,
@@ -162,8 +161,7 @@ ProcessTickEventChain  ROUT
         BLX     r11                             ; call event handler
       ]
 
-        LDR     r0, [r1, #TickNodeRedo]
-        CMP     r0, #0                          ; CallEvery?
+        MOVS    r0, r10                         ; CallEvery?
         BEQ     %FT05
 
         BL      InsertTickerEvent               ; yes, then re-insert timer
@@ -172,7 +170,7 @@ ProcessTickEventChain  ROUT
 05
 ; Return spent ticker node to heap
 
-        WritePSRc SVC_mode, r2                  ; IRQ's ON for the  S L O W  bit
+        MSR     CPSR_c, #SVC32_mode             ; IRQ's ON for the  S L O W  bit
         MOV     r2, r1                          ; R2->node to free
   [ ChocolateSysHeap
         ASSERT  ChocolateTKBlocks = ChocolateBlockArrays + 8
@@ -187,10 +185,11 @@ ProcessTickEventChain  ROUT
         MOV     r0, #HeapReason_Free
         SWI     XOS_Heap
   ]
-        WritePSRc SVC_mode+I_bit, r1            ; IRQ's off again
 
 ; Check for more events at the same level in the list
 10
+        MSR     CPSR_c, #SVC32_mode+I32_bit     ; IRQ's off again (after returning node to heap, or after naughty CallEvery exits with IRQs on)
+
         LDR     r1, [r3, #TickNodeLink]         ; get top of list
         CMP     r1, #0                          ; list empty?
         BEQ     %FT02                           ; yes then exit
@@ -200,13 +199,12 @@ ProcessTickEventChain  ROUT
         BEQ     %BT01                           ; yes then jump
 02
         Pull    "lr"                            ; restore SVC_lr
-        WritePSRc IRQ_mode+I_bit, r10           ; back to IRQ mode
-        NOP
+        MSR     CPSR_c, #IRQ32_mode+I32_bit     ; back to IRQ mode
         Pull    "pc"                            ; pull IRQ_lr from IRQ stack
 
 RemoveTickerEvent_Code
 ; R0 is address of code to remove, R1 the R12 value
-        WritePSRc SVC_mode+I_bit, r10
+        MSR     CPSR_c, #SVC32_mode+I32_bit
         LDR     r10, =ZeroPage+TickNodeChain
 01
         LDR     r11, [r10]
-- 
GitLab