forked

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers mbed_critical.c Source File

mbed_critical.c

00001 /*
00002  * Copyright (c) 2015-2016, ARM Limited, All Rights Reserved
00003  * SPDX-License-Identifier: Apache-2.0
00004  *
00005  * Licensed under the Apache License, Version 2.0 (the "License"); you may
00006  * not use this file except in compliance with the License.
00007  * You may obtain a copy of the License at
00008  *
00009  * http://www.apache.org/licenses/LICENSE-2.0
00010  *
00011  * Unless required by applicable law or agreed to in writing, software
00012  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
00013  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00014  * See the License for the specific language governing permissions and
00015  * limitations under the License.
00016  */
00017 
00018 /* Declare __STDC_LIMIT_MACROS so stdint.h defines UINT32_MAX when using C++ */
00019 #define __STDC_LIMIT_MACROS
00020 #include "platform/mbed_critical.h"
00021 
00022 #include "cmsis.h"
00023 #include "platform/mbed_assert.h"
00024 #include "platform/mbed_toolchain.h"
00025 
00026 #if !defined (__CORTEX_M0) && !defined (__CORTEX_M0PLUS)
00027 #define EXCLUSIVE_ACCESS 1
00028 #else
00029 #define EXCLUSIVE_ACCESS 0
00030 #endif
00031 
00032 static volatile uint32_t interrupt_enable_counter = 0;
00033 static volatile bool critical_interrupts_disabled = false;
00034 
00035 bool core_util_are_interrupts_enabled(void)
00036 {
00037 #if defined(__CORTEX_A9)
00038     return ((__get_CPSR() & 0x80) == 0);
00039 #else
00040     return ((__get_PRIMASK() & 0x1) == 0);
00041 #endif
00042 }
00043 
00044 bool core_util_is_isr_active(void)
00045 {
00046 #if defined(__CORTEX_A9)
00047     switch(__get_CPSR() & 0x1FU) {
00048         case MODE_USR:
00049         case MODE_SYS:
00050             return false;
00051         case MODE_SVC:
00052         default:
00053             return true;
00054     }
00055 #else
00056     return (__get_IPSR() != 0U);
00057 #endif
00058 }
00059 
00060 MBED_WEAK void core_util_critical_section_enter(void)
00061 {
00062     bool interrupts_disabled = !core_util_are_interrupts_enabled();
00063     __disable_irq();
00064 
00065     /* Save the interrupt disabled state as it was prior to any nested critical section lock use */
00066     if (!interrupt_enable_counter) {
00067         critical_interrupts_disabled = interrupts_disabled;
00068     }
00069 
00070     /* If the interrupt_enable_counter overflows or we are in a nested critical section and interrupts
00071        are enabled, then something has gone badly wrong thus assert an error.
00072     */
00073     MBED_ASSERT(interrupt_enable_counter < UINT32_MAX); 
00074 // FIXME
00075 #ifndef   FEATURE_UVISOR
00076     if (interrupt_enable_counter > 0) {
00077         MBED_ASSERT(interrupts_disabled);
00078     }
00079 #else
00080 #warning "core_util_critical_section_enter needs fixing to work from unprivileged code"
00081 #endif /* FEATURE_UVISOR */
00082     interrupt_enable_counter++;
00083 }
00084 
00085 MBED_WEAK void core_util_critical_section_exit(void)
00086 {
00087     /* If critical_section_enter has not previously been called, do nothing */
00088     if (interrupt_enable_counter) {
00089 
00090 // FIXME
00091 #ifndef   FEATURE_UVISOR
00092         bool interrupts_disabled = !core_util_are_interrupts_enabled(); /* get the current interrupt disabled state */
00093 
00094         MBED_ASSERT(interrupts_disabled); /* Interrupts must be disabled on invoking an exit from a critical section */
00095 #else
00096 #warning "core_util_critical_section_exit needs fixing to work from unprivileged code"
00097 #endif /* FEATURE_UVISOR */
00098 
00099         interrupt_enable_counter--;
00100 
00101         /* Only re-enable interrupts if we are exiting the last of the nested critical sections and
00102            interrupts were enabled on entry to the first critical section.
00103         */
00104         if (!interrupt_enable_counter && !critical_interrupts_disabled) {
00105             __enable_irq();
00106         }
00107     }
00108 }
00109 
00110 #if EXCLUSIVE_ACCESS
00111 
00112 /* Supress __ldrex and __strex deprecated warnings - "#3731-D: intrinsic is deprecated" */
00113 #if defined (__CC_ARM) 
00114 #pragma diag_suppress 3731
00115 #endif
00116 
00117 bool core_util_atomic_cas_u8(uint8_t *ptr, uint8_t *expectedCurrentValue, uint8_t desiredValue)
00118 {
00119     uint8_t currentValue = __LDREXB((volatile uint8_t*)ptr);
00120     if (currentValue != *expectedCurrentValue) {
00121         *expectedCurrentValue = currentValue;
00122         __CLREX();
00123         return false;
00124     }
00125 
00126     return !__STREXB(desiredValue, (volatile uint8_t*)ptr);
00127 }
00128 
00129 bool core_util_atomic_cas_u16(uint16_t *ptr, uint16_t *expectedCurrentValue, uint16_t desiredValue)
00130 {
00131     uint16_t currentValue = __LDREXH((volatile uint16_t*)ptr);
00132     if (currentValue != *expectedCurrentValue) {
00133         *expectedCurrentValue = currentValue;
00134         __CLREX();
00135         return false;
00136     }
00137 
00138     return !__STREXH(desiredValue, (volatile uint16_t*)ptr);
00139 }
00140 
00141 
00142 bool core_util_atomic_cas_u32(uint32_t *ptr, uint32_t *expectedCurrentValue, uint32_t desiredValue)
00143 {
00144     uint32_t currentValue = __LDREXW((volatile uint32_t*)ptr);
00145     if (currentValue != *expectedCurrentValue) {
00146         *expectedCurrentValue = currentValue;
00147         __CLREX();
00148         return false;
00149     }
00150 
00151     return !__STREXW(desiredValue, (volatile uint32_t*)ptr);
00152 }
00153 
00154 uint8_t core_util_atomic_incr_u8(uint8_t *valuePtr, uint8_t delta)
00155 {
00156     uint8_t newValue;
00157     do {
00158         newValue = __LDREXB((volatile uint8_t*)valuePtr) + delta;
00159     } while (__STREXB(newValue, (volatile uint8_t*)valuePtr));
00160     return newValue;
00161 }
00162 
00163 uint16_t core_util_atomic_incr_u16(uint16_t *valuePtr, uint16_t delta)
00164 {
00165     uint16_t newValue;
00166     do {
00167         newValue = __LDREXH((volatile uint16_t*)valuePtr) + delta;
00168     } while (__STREXH(newValue, (volatile uint16_t*)valuePtr));
00169     return newValue;
00170 }
00171 
00172 uint32_t core_util_atomic_incr_u32(uint32_t *valuePtr, uint32_t delta)
00173 {
00174     uint32_t newValue;
00175     do {
00176         newValue = __LDREXW((volatile uint32_t*)valuePtr) + delta;
00177     } while (__STREXW(newValue, (volatile uint32_t*)valuePtr));
00178     return newValue;
00179 }
00180 
00181 
00182 uint8_t core_util_atomic_decr_u8(uint8_t *valuePtr, uint8_t delta)
00183 {
00184     uint8_t newValue;
00185     do {
00186         newValue = __LDREXB((volatile uint8_t*)valuePtr) - delta;
00187     } while (__STREXB(newValue, (volatile uint8_t*)valuePtr));
00188     return newValue;
00189 }
00190 
00191 uint16_t core_util_atomic_decr_u16(uint16_t *valuePtr, uint16_t delta)
00192 {
00193     uint16_t newValue;
00194     do {
00195         newValue = __LDREXH((volatile uint16_t*)valuePtr) - delta;
00196     } while (__STREXH(newValue, (volatile uint16_t*)valuePtr));
00197     return newValue;
00198 }
00199 
00200 uint32_t core_util_atomic_decr_u32(uint32_t *valuePtr, uint32_t delta)
00201 {
00202     uint32_t newValue;
00203     do {
00204         newValue = __LDREXW((volatile uint32_t*)valuePtr) - delta;
00205     } while (__STREXW(newValue, (volatile uint32_t*)valuePtr));
00206     return newValue;
00207 }
00208 
00209 #else
00210 
00211 bool core_util_atomic_cas_u8(uint8_t *ptr, uint8_t *expectedCurrentValue, uint8_t desiredValue)
00212 {
00213     bool success;
00214     uint8_t currentValue;
00215     core_util_critical_section_enter();
00216     currentValue = *ptr;
00217     if (currentValue == *expectedCurrentValue) {
00218         *ptr = desiredValue;
00219         success = true;
00220     } else {
00221         *expectedCurrentValue = currentValue;
00222         success = false;
00223     }
00224     core_util_critical_section_exit();
00225     return success;
00226 }
00227 
00228 bool core_util_atomic_cas_u16(uint16_t *ptr, uint16_t *expectedCurrentValue, uint16_t desiredValue)
00229 {
00230     bool success;
00231     uint16_t currentValue;
00232     core_util_critical_section_enter();
00233     currentValue = *ptr;
00234     if (currentValue == *expectedCurrentValue) {
00235         *ptr = desiredValue;
00236         success = true;
00237     } else {
00238         *expectedCurrentValue = currentValue;
00239         success = false;
00240     }
00241     core_util_critical_section_exit();
00242     return success;
00243 }
00244 
00245 
00246 bool core_util_atomic_cas_u32(uint32_t *ptr, uint32_t *expectedCurrentValue, uint32_t desiredValue)
00247 {
00248     bool success;
00249     uint32_t currentValue;
00250     core_util_critical_section_enter();
00251     currentValue = *ptr;
00252     if (currentValue == *expectedCurrentValue) {
00253         *ptr = desiredValue;
00254         success = true;
00255     } else {
00256         *expectedCurrentValue = currentValue;
00257         success = false;
00258     }
00259     core_util_critical_section_exit();
00260     return success;
00261 }
00262 
00263 
00264 uint8_t core_util_atomic_incr_u8(uint8_t *valuePtr, uint8_t delta)
00265 {
00266     uint8_t newValue;
00267     core_util_critical_section_enter();
00268     newValue = *valuePtr + delta;
00269     *valuePtr = newValue;
00270     core_util_critical_section_exit();
00271     return newValue;
00272 }
00273 
00274 uint16_t core_util_atomic_incr_u16(uint16_t *valuePtr, uint16_t delta)
00275 {
00276     uint16_t newValue;
00277     core_util_critical_section_enter();
00278     newValue = *valuePtr + delta;
00279     *valuePtr = newValue;
00280     core_util_critical_section_exit();
00281     return newValue;
00282 }
00283 
00284 uint32_t core_util_atomic_incr_u32(uint32_t *valuePtr, uint32_t delta)
00285 {
00286     uint32_t newValue;
00287     core_util_critical_section_enter();
00288     newValue = *valuePtr + delta;
00289     *valuePtr = newValue;
00290     core_util_critical_section_exit();
00291     return newValue;
00292 }
00293 
00294 
00295 uint8_t core_util_atomic_decr_u8(uint8_t *valuePtr, uint8_t delta)
00296 {
00297     uint8_t newValue;
00298     core_util_critical_section_enter();
00299     newValue = *valuePtr - delta;
00300     *valuePtr = newValue;
00301     core_util_critical_section_exit();
00302     return newValue;
00303 }
00304 
00305 uint16_t core_util_atomic_decr_u16(uint16_t *valuePtr, uint16_t delta)
00306 {
00307     uint16_t newValue;
00308     core_util_critical_section_enter();
00309     newValue = *valuePtr - delta;
00310     *valuePtr = newValue;
00311     core_util_critical_section_exit();
00312     return newValue;
00313 }
00314 
00315 uint32_t core_util_atomic_decr_u32(uint32_t *valuePtr, uint32_t delta)
00316 {
00317     uint32_t newValue;
00318     core_util_critical_section_enter();
00319     newValue = *valuePtr - delta;
00320     *valuePtr = newValue;
00321     core_util_critical_section_exit();
00322     return newValue;
00323 }
00324 
00325 #endif
00326 
00327 
00328 bool core_util_atomic_cas_ptr(void **ptr, void **expectedCurrentValue, void *desiredValue) {
00329     return core_util_atomic_cas_u32(
00330             (uint32_t *)ptr,
00331             (uint32_t *)expectedCurrentValue,
00332             (uint32_t)desiredValue);
00333 }
00334 
00335 void *core_util_atomic_incr_ptr(void **valuePtr, ptrdiff_t delta) {
00336     return (void *)core_util_atomic_incr_u32((uint32_t *)valuePtr, (uint32_t)delta);
00337 }
00338 
00339 void *core_util_atomic_decr_ptr(void **valuePtr, ptrdiff_t delta) {
00340     return (void *)core_util_atomic_decr_u32((uint32_t *)valuePtr, (uint32_t)delta);
00341 }
00342