1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
|
Backport r7043 from upstream: partially replaces use of SWP with LDREX/STREX
on systems where SWP is no longer available. This fix is incomplete,
but sufficient for our purposes.
Fri Mar 11 14:51:54 GMT 2016 Lee Noar <leenoar@sky.com>
* sys/_cpucaps.s: New file. Provide functions to probe the
OS for details of the CPU (currently SWP, LDREX/STREX
availability).
* Makefile.am: Add above file.
* include/unixlib/local.h: Add declarations for user facing
functions provided above.
* incl-local/internal/asm_dec.s(__ul_global): Add entry to
record CPU flags.
* incl-local/internal/unix.h: Likewise.
* pthread/_ints.s(__pthread_disable_ints,__pthread_protect_unsafe):
Use CPU flags to determine whether to use the SWP instruction or
LRDEX/STREX.
* sys/_syslib.s(__main): Add call to __probe_cpu_caps.
(__unixlib_fatal): Use CPU flags to determine whether to use the
SWP instruction or LRDEX/STREX.
Index: gcc4/recipe/files/gcc/libunixlib/pthread/_ints.s
===================================================================
--- gcc4/recipe/files/gcc/libunixlib/pthread/_ints.s (revision 7042)
+++ gcc4/recipe/files/gcc/libunixlib/pthread/_ints.s (revision 7043)
@@ -2,7 +2,7 @@
@ disable_ints can be called multiple times, provided enable_ints is
@ subsequently called an equal number of times
@ Written by Martin Piper and Alex Waugh
-@ Copyright (c) 2002-2008 UnixLib Developers
+@ Copyright (c) 2002-2016 UnixLib Developers
#include "internal/asm_dec.s"
@@ -20,15 +20,26 @@
PICEQ "LDR a2, [a2, #0]"
PICEQ "LDR a2, [a2, #__GOTT_INDEX__]" @ a2 = GOT ptr
- LDR a1, .L0 @=__ul_global
+ LDR a1, .L0 @ =__ul_global
PICEQ "LDR a1, [a2, a1]"
+ LDR a4, [a1, #GBL_CPU_FLAGS]
ADD a1, a1, #GBL_PTH_WORKSEMAPHORE
+ TST a4, #__CPUCAP_HAVE_SWP
+ @ From this point onwards we will not be interrupted by the callback
+ BEQ 0f
+
MOV a3, #1
SWP a2, a3, [a1]
- @ From this point onwards we will not be interrupted by the callback
ADD a2, a2, #1
STR a2, [a1]
MOV pc, lr
+0:
+ LDREX a2, [a1]
+ ADD a2, a2, #1
+ STREX a3, a2, [a1]
+ TEQ a3, #1
+ BEQ 0b
+ MOV pc, lr
.L0:
WORD __ul_global
DECLARE_FUNCTION __pthread_disable_ints
@@ -78,18 +89,32 @@
PICEQ "LDR a1, [a1, #0]"
PICEQ "LDR a1, [a1, #__GOTT_INDEX__]" @ a1 = GOT ptr
- LDR a4, .L2 @=__ul_global
+ LDR a4, .L2 @ =__ul_global
PICEQ "LDR a4, [a1, a4]"
+ LDR a2, [a4, #GBL_CPU_FLAGS]
ADD a1, a4, #GBL_PTH_WORKSEMAPHORE
+ TST a2, #__CPUCAP_HAVE_SWP
+ @ From this point onwards we cannot be interrupted by the callback
+ BEQ 0f
+
MOV a2, #1
SWP a3, a2, [a1]
- @ From this point onwards we cannot be interrupted by the callback
CMP a3, #0
- STRNE a3, [a1, #0] @ Restore original value
+ BEQ 1f
+ STR a3, [a1, #0] @ Restore original value
@ Return, as if ints are disabled on entry to the
@ calling function then they should not be reenabled
@ until the calling function has returned
+ MOV pc, lr
+0:
+ LDREX a3, [a1]
+ MOV ip, #1
+ STREX a2, ip, [a1]
+ TEQ a2, #1
+ BEQ 0b
+ TEQ a3, #0
MOVNE pc, lr
+1:
#if __UNIXLIB_PARANOID
LDR a3, [a4, #GBL_PTH_RETURN_ADDRESS]
Index: gcc4/recipe/files/gcc/libunixlib/include/unixlib/local.h
===================================================================
--- gcc4/recipe/files/gcc/libunixlib/include/unixlib/local.h (revision 7042)
+++ gcc4/recipe/files/gcc/libunixlib/include/unixlib/local.h (revision 7043)
@@ -133,6 +133,16 @@
socket. Is -1 when socket handle is not valid. */
extern int __get_ro_socket (int __sockfd);
+/* Return 1 if the SWP instruction is available, otherwise 0. */
+extern unsigned int __cpucap_have_swp (void);
+
+/* Return 1 if the LDREX/STREX instructions are available, otherwise 0. */
+extern unsigned int __cpucap_have_rex (void);
+
+/* Return 1 if the LDREX/STREX instructions that operate on bytes, half-words
+ and double words are available, otherwise 0. */
+extern unsigned int __cpucap_have_rexbhd (void);
+
__END_DECLS
#endif
* incl-local/internal/asm_dec.s(XSOM_DeregisterClient): Add
Index: gcc4/recipe/files/gcc/libunixlib/Makefile.am
===================================================================
--- gcc4/recipe/files/gcc/libunixlib/Makefile.am (revision 7042)
+++ gcc4/recipe/files/gcc/libunixlib/Makefile.am (revision 7043)
@@ -1027,6 +1027,7 @@
sys/sigsetjmp.c \
sys/stackalloc.c \
sys/vfork.c \
+ sys/_cpucaps.s \
sys/_getcpuarch.s \
sys/_jmp.s \
sys/_mman.s \
Index: gcc4/recipe/files/gcc/libunixlib/incl-local/internal/asm_dec.s
===================================================================
--- gcc4/recipe/files/gcc/libunixlib/incl-local/internal/asm_dec.s (revision 7042)
+++ gcc4/recipe/files/gcc/libunixlib/incl-local/internal/asm_dec.s (revision 7043)
@@ -269,8 +269,10 @@
.set GBL_FLS_LBSTM_ON_RD, 108 @ = __ul_global.fls_lbstm_on_rd
.set GBL_PTH_CALLEVERY_RMA, 112 @ = __ul_global.pthread_callevery_rma
+.set GBL_CPU_FLAGS, 116 @ = __ul_global.cpu_flags
+
#if !defined(__SOFTFP__) && defined(__VFP_FP__)
-.set GBL_VFP_REGCOUNT, 116 @ = __ul_global.vfp_regcount
+.set GBL_VFP_REGCOUNT, 120 @ = __ul_global.vfp_regcount
#endif
@ Entries in the __ul_memory table. Must be kept in sync with
@@ -322,3 +324,7 @@
.set CRT1_LIB_FINI, 32 @ Ptr to function to finalise shared libraries
@ at program exit - can be NULL.
#endif
+
+#define __CPUCAP_HAVE_SWP 0x1
+#define __CPUCAP_HAVE_REX 0x2
+#define __CPUCAP_HAVE_REXBHD 0x4
Index: gcc4/recipe/files/gcc/libunixlib/incl-local/internal/unix.h
===================================================================
--- gcc4/recipe/files/gcc/libunixlib/incl-local/internal/unix.h (revision 7042)
+++ gcc4/recipe/files/gcc/libunixlib/incl-local/internal/unix.h (revision 7043)
@@ -197,6 +197,8 @@
the life of the program. This block is passed to the call_every handler in
r12. */
+ unsigned int cpu_flags; /* Flags indicating the capabilities of the CPU. */
+
#if !defined(__SOFTFP__) && defined(__VFP_FP__)
int vfp_regcount; /* Number of doubleword registers we should request for
VFP contexts */
Index: gcc4/recipe/files/gcc/libunixlib/sys/_cpucaps.s
===================================================================
--- gcc4/recipe/files/gcc/libunixlib/sys/_cpucaps.s (revision 0)
+++ gcc4/recipe/files/gcc/libunixlib/sys/_cpucaps.s (revision 7043)
@@ -0,0 +1,91 @@
+@ Determine the capabilities of the CPU and allow callers to enquire
+@ what they are.
+@ Copyright (c) 2016 UnixLib Developers.
+@ Written by Lee Noar.
+
+#include "internal/asm_dec.s"
+
+ .text
+
+@ Determine what the CPU capabilities are, and record them.
+@ Called early on during program initialisation in _syslib.s.
+ .global __probe_cpu_caps
+ NAME __probe_cpu_caps
+__probe_cpu_caps:
+ MOV r0, #0
+ SWI XOS_PlatformFeatures
+ MOVVS r0, #0
+
+ MOV r2, #0
+ @ The OS flag is set to 1 to indicate _no_ SWP instruction available (for
+ @ backwards compatibility). We reverse it here and set our flag to 1 to
+ @ indicate that SWP _is_ available.
+ TST r0, #1<<11 @ SWP{B} not available
+ ORREQ r2, r2, #__CPUCAP_HAVE_SWP
+ TST r0, #1<<12 @ LDREX/STREX available
+ ORRNE r2, r2, #__CPUCAP_HAVE_REX
+ TST r0, #1<<13 @ LDREX/STREX{B/H/D} available
+ ORRNE r2, r2, #__CPUCAP_HAVE_REXBHD
+
+ PICEQ "LDR r0, =__GOTT_BASE__"
+ PICEQ "LDR r0, [r0, #0]"
+ PICEQ "LDR r0, [r0, #__GOTT_INDEX__]" @ r0 = GOT ptr
+ LDR r1, .L0 @ =__ul_global
+ PICEQ "LDR r1, [r0, r1]"
+ STR r2, [r1, #GBL_CPU_FLAGS]
+
+ MOV pc, lr
+.L0:
+ WORD __ul_global
+ DECLARE_FUNCTION __probe_cpu_caps
+
+ .global __cpucap_have_swp
+ NAME __cpucap_have_swp
+__cpucap_have_swp:
+ PICEQ "LDR r0, =__GOTT_BASE__"
+ PICEQ "LDR r0, [r0, #0]"
+ PICEQ "LDR r0, [r0, #__GOTT_INDEX__]" @ r0 = GOT ptr
+ LDR r1, .L0 @ =__ul_global
+ PICEQ "LDR r1, [r0, r1]"
+ LDR r0, [r1, #GBL_CPU_FLAGS]
+ TST r0, #__CPUCAP_HAVE_SWP
+ MOVEQ r0, #0
+ MOVNE r0, #1
+
+ MOV pc, lr
+ DECLARE_FUNCTION __cpucap_have_swp
+
+@ Return 1 if LDREX/STREX instructions are available on the CPU, otherwise 0.
+ .global __cpucap_have_rex
+ NAME __cpucap_have_rex
+__cpucap_have_rex:
+ PICEQ "LDR r0, =__GOTT_BASE__"
+ PICEQ "LDR r0, [r0, #0]"
+ PICEQ "LDR r0, [r0, #__GOTT_INDEX__]" @ r0 = GOT ptr
+ LDR r1, .L0 @ =__ul_global
+ PICEQ "LDR r1, [r0, r1]"
+ LDR r0, [r1, #GBL_CPU_FLAGS]
+ TST r0, #__CPUCAP_HAVE_REX
+ MOVEQ r0, #0
+ MOVNE r0, #1
+
+ MOV pc, lr
+ DECLARE_FUNCTION __cpucap_have_rex
+
+@ Return 1 if LDREX/STREX instructions that work on non-32 bit data sizes
+@ are available on the CPU, otherwise 0.
+ .global __cpucap_have_rexbhd
+ NAME __cpucap_have_rexbhd
+__cpucap_have_rexbhd:
+ PICEQ "LDR r0, =__GOTT_BASE__"
+ PICEQ "LDR r0, [r0, #0]"
+ PICEQ "LDR r0, [r0, #__GOTT_INDEX__]" @ r0 = GOT ptr
+ LDR r1, .L0 @ =__ul_global
+ PICEQ "LDR r1, [r0, r1]"
+ LDR r0, [r1, #GBL_CPU_FLAGS]
+ TST r0, #__CPUCAP_HAVE_REXBHD
+ MOVEQ r0, #0
+ MOVNE r0, #1
+
+ MOV pc, lr
+ DECLARE_FUNCTION __cpucap_have_rexbhd
Index: gcc4/recipe/files/gcc/libunixlib/sys/_syslib.s
===================================================================
--- gcc4/recipe/files/gcc/libunixlib/sys/_syslib.s (revision 7042)
+++ gcc4/recipe/files/gcc/libunixlib/sys/_syslib.s (revision 7043)
@@ -255,6 +255,8 @@
BCC __exit_with_error_num
unknown_cpu_arch:
+ BL __probe_cpu_caps
+
@ Use of DAs explicitly overridden if __dynamic_no_da is declared
MOV lr, #-1
STR lr, [ip, #GBL_DYNAMIC_NUM]
@@ -1286,9 +1288,21 @@
@ error handling. As last resort to avoid an infinite loop
@ we go for a straight OS_Exit scenario. Anything better we
@ can do ?
+ ADD a3, a4, #GBL_PANIC_MODE
+ LDR a2, [a4, #GBL_CPU_FLAGS]
+ TST a2, #__CPUCAP_HAVE_SWP
+ BEQ 0f
+
MOV a2, #1
- ADD a3, a4, #GBL_PANIC_MODE
SWP a2, a2, [a3]
+ B 1f
+0:
+ LDREX a2, [a3]
+ MOV ip, #1
+ STREX lr, ip, [a3]
+ TEQ lr, #1
+ BEQ 0b
+1:
TEQ a2, #0
BEQ __unixlib_fatal_cont1
|