source: mainline/uspace/lib/c/arch/arm32/src/atomic.c@ eec201d

Last change on this file since eec201d was 09ab0a9a, checked in by Jiri Svoboda <jiri@…>, 7 years ago

Fix vertical spacing with new Ccheck revision.

  • Property mode set to 100644
File size: 5.0 KB
RevLine 
[d630139]1/*
[6b781c0]2 * Copyright (c) 2007 Michal Kebrt
[ffa73c6]3 * Copyright (c) 2018 CZ.NIC, z.s.p.o.
[d630139]4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
[ffa73c6]30/*
31 * Older ARMs don't have atomic instructions, so we need to define a bunch
32 * of symbols for GCC to use.
[d630139]33 */
34
[3e6a98c5]35#include <stdbool.h>
[8d04f709]36
[ffa73c6]37extern volatile unsigned *ras_page;
[8d04f709]38
[ffa73c6]39bool __atomic_compare_exchange_4(volatile unsigned *mem, unsigned *expected, unsigned desired, bool weak, int success, int failure)
[8d04f709]40{
[ffa73c6]41 (void) success;
42 (void) failure;
43 (void) weak;
44
45 unsigned ov = *expected;
46 unsigned ret;
[a35b458]47
[cd769305]48 /*
49 * The following instructions between labels 1 and 2 constitute a
[7137f74c]50 * Restartable Atomic Sequence. Should the sequence be non-atomic,
[cd769305]51 * the kernel will restart it.
52 */
53 asm volatile (
[1433ecda]54 "1:\n"
55 " adr %[ret], 1b\n"
56 " str %[ret], %[rp0]\n"
57 " adr %[ret], 2f\n"
58 " str %[ret], %[rp1]\n"
[ffa73c6]59
[1433ecda]60 " ldr %[ret], %[addr]\n"
61 " cmp %[ret], %[ov]\n"
62 " streq %[nv], %[addr]\n"
63 "2:\n"
[ffa73c6]64 : [ret] "=&r" (ret),
[1433ecda]65 [rp0] "=m" (ras_page[0]),
66 [rp1] "=m" (ras_page[1]),
[ffa73c6]67 [addr] "+m" (*mem)
[1433ecda]68 : [ov] "r" (ov),
[ffa73c6]69 [nv] "r" (desired)
[1433ecda]70 : "memory"
[cd769305]71 );
[a35b458]72
[cd769305]73 ras_page[0] = 0;
74 ras_page[1] = 0xffffffff;
[a35b458]75
[ffa73c6]76 if (ret == ov)
77 return true;
78
79 *expected = ret;
80 return false;
[8d04f709]81}
82
[508b0df1]83unsigned short __atomic_fetch_add_2(volatile unsigned short *mem, unsigned short val, int model)
84{
85 (void) model;
86
87 unsigned short ret;
88
89 /*
90 * The following instructions between labels 1 and 2 constitute a
91 * Restartable Atomic Seqeunce. Should the sequence be non-atomic,
92 * the kernel will restart it.
93 */
94 asm volatile (
95 "1:\n"
96 " adr %[ret], 1b\n"
97 " str %[ret], %[rp0]\n"
98 " adr %[ret], 2f\n"
99 " str %[ret], %[rp1]\n"
100 " ldrh %[ret], %[addr]\n"
101 " add %[ret], %[ret], %[imm]\n"
102 " strh %[ret], %[addr]\n"
103 "2:\n"
104 : [ret] "=&r" (ret),
105 [rp0] "=m" (ras_page[0]),
106 [rp1] "=m" (ras_page[1]),
107 [addr] "+m" (*mem)
108 : [imm] "r" (val)
109 );
110
111 ras_page[0] = 0;
112 ras_page[1] = 0xffffffff;
113
114 return ret - val;
115}
116
[ffa73c6]117unsigned __atomic_fetch_add_4(volatile unsigned *mem, unsigned val, int model)
[d630139]118{
[ffa73c6]119 (void) model;
120
121 unsigned ret;
[a35b458]122
[cd769305]123 /*
124 * The following instructions between labels 1 and 2 constitute a
125 * Restartable Atomic Seqeunce. Should the sequence be non-atomic,
126 * the kernel will restart it.
127 */
[6b781c0]128 asm volatile (
[1433ecda]129 "1:\n"
130 " adr %[ret], 1b\n"
131 " str %[ret], %[rp0]\n"
132 " adr %[ret], 2f\n"
133 " str %[ret], %[rp1]\n"
134 " ldr %[ret], %[addr]\n"
135 " add %[ret], %[ret], %[imm]\n"
136 " str %[ret], %[addr]\n"
137 "2:\n"
[ffa73c6]138 : [ret] "=&r" (ret),
[1433ecda]139 [rp0] "=m" (ras_page[0]),
140 [rp1] "=m" (ras_page[1]),
[ffa73c6]141 [addr] "+m" (*mem)
142 : [imm] "r" (val)
[6b781c0]143 );
[a35b458]144
[cd769305]145 ras_page[0] = 0;
146 ras_page[1] = 0xffffffff;
[a35b458]147
[ffa73c6]148 return ret - val;
[d630139]149}
150
[ffa73c6]151unsigned __atomic_fetch_sub_4(volatile unsigned *mem, unsigned val, int model)
[de7663f]152{
[ffa73c6]153 return __atomic_fetch_add_4(mem, -val, model);
[de7663f]154}
[6b781c0]155
[ffa73c6]156void __sync_synchronize(void)
[de7663f]157{
[ffa73c6]158 // FIXME: Full memory barrier. We might need a syscall for this.
[de7663f]159}
[d630139]160
[ffa73c6]161unsigned __sync_add_and_fetch_4(volatile void *vptr, unsigned val)
[de7663f]162{
[ffa73c6]163 return __atomic_fetch_add_4(vptr, val, __ATOMIC_SEQ_CST) + val;
[de7663f]164}
[6b781c0]165
[ffa73c6]166unsigned __sync_sub_and_fetch_4(volatile void *vptr, unsigned val)
[de7663f]167{
[ffa73c6]168 return __atomic_fetch_sub_4(vptr, val, __ATOMIC_SEQ_CST) - val;
[de7663f]169}
[6b781c0]170
[ffa73c6]171bool __sync_bool_compare_and_swap_4(volatile void *ptr, unsigned old_val, unsigned new_val)
[de7663f]172{
[ffa73c6]173 return __atomic_compare_exchange_4(ptr, &old_val, new_val, false,
174 __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
[de7663f]175}
[6b781c0]176
[ffa73c6]177unsigned __sync_val_compare_and_swap_4(volatile void *ptr, unsigned old_val, unsigned new_val)
[de7663f]178{
[ffa73c6]179 __atomic_compare_exchange_4(ptr, &old_val, new_val, false,
180 __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
181 return old_val;
[de7663f]182}
Note: See TracBrowser for help on using the repository browser.