1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <atomic.h>
18 
atomicAddByte(volatile uint8_t * byte,uint32_t addend)19 uint32_t atomicAddByte(volatile uint8_t *byte, uint32_t addend)
20 {
21     uint32_t prevVal, storeFailed, tmp;
22 
23     do {
24         asm volatile(
25             "ldrexb %0,     [%4] \n"
26             "add    %2, %0, %3   \n"
27             "strexb %1, %2, [%4] \n"
28             :"=r"(prevVal), "=r"(storeFailed), "=r"(tmp), "=r"(addend), "=r"(byte)
29             :"3"(addend), "4"(byte)
30             :"memory"
31         );
32     } while (storeFailed);
33 
34     return prevVal;
35 }
36 
atomicAdd32bits(volatile uint32_t * word,uint32_t addend)37 uint32_t atomicAdd32bits(volatile uint32_t *word, uint32_t addend)
38 {
39     uint32_t prevVal, storeFailed, tmp;
40 
41     do {
42         asm volatile(
43             "ldrex  %0,     [%4] \n"
44             "add    %2, %0, %3   \n"
45             "strex  %1, %2, [%4] \n"
46             :"=r"(prevVal), "=r"(storeFailed), "=r"(tmp), "=r"(addend), "=r"(word)
47             :"3"(addend), "4"(word)
48             :"memory"
49         );
50     } while (storeFailed);
51 
52     return prevVal;
53 }
54 
atomicXchgByte(volatile uint8_t * byte,uint32_t newVal)55 uint32_t atomicXchgByte(volatile uint8_t *byte, uint32_t newVal)
56 {
57     uint32_t prevVal, storeFailed;
58 
59     do {
60         asm volatile(
61             "ldrexb %0,     [%3] \n"
62             "strexb %1, %2, [%3] \n"
63             :"=r"(prevVal), "=r"(storeFailed), "=r"(newVal), "=r"(byte)
64             :"2"(newVal), "3"(byte)
65             :"memory"
66         );
67     } while (storeFailed);
68 
69     return prevVal;
70 }
71 
atomicXchg32bits(volatile uint32_t * word,uint32_t newVal)72 uint32_t atomicXchg32bits(volatile uint32_t *word, uint32_t newVal)
73 {
74     uint32_t prevVal, storeFailed;
75 
76     do {
77         asm volatile(
78             "ldrex %0,     [%3] \n"
79             "strex %1, %2, [%3] \n"
80             :"=r"(prevVal), "=r"(storeFailed), "=r"(newVal), "=r"(word)
81             :"2"(newVal), "3"(word)
82             :"memory"
83         );
84     } while (storeFailed);
85 
86     return prevVal;
87 }
88 
atomicCmpXchgByte(volatile uint8_t * byte,uint32_t prevVal,uint32_t newVal)89 bool atomicCmpXchgByte(volatile uint8_t *byte, uint32_t prevVal, uint32_t newVal)
90 {
91     uint32_t currVal, storeFailed;
92 
93     do {
94         asm volatile(
95             "ldrexb %0,     [%1] \n"
96             :"=r"(currVal), "=r"(byte)
97             :"1"(byte)
98             :"memory"
99         );
100 
101         if (currVal != prevVal)
102             return false;
103 
104         asm volatile(
105             "strexb %0, %1, [%2] \n"
106             :"=r"(storeFailed), "=r"(newVal), "=r"(byte)
107             :"1"(newVal), "2"(byte)
108             :"memory"
109         );
110     } while (storeFailed);
111 
112     return true;
113 }
114 
atomicCmpXchg32bits(volatile uint32_t * word,uint32_t prevVal,uint32_t newVal)115 bool atomicCmpXchg32bits(volatile uint32_t *word, uint32_t prevVal, uint32_t newVal)
116 {
117     uint32_t currVal, storeFailed;
118 
119     do {
120         asm volatile(
121             "ldrex %0,     [%1] \n"
122             :"=r"(currVal), "=r"(word)
123             :"1"(word)
124             :"memory"
125         );
126 
127         if (currVal != prevVal)
128             return false;
129 
130         asm volatile(
131             "strex %0, %1, [%2] \n"
132             :"=r"(storeFailed), "=r"(newVal), "=r"(word)
133             :"1"(newVal), "2"(word)
134             :"memory"
135         );
136     } while (storeFailed);
137 
138     return true;
139 }
140