Skip to content

Commit e14bee5

Browse files
author
Steven Cartmell
committed
Fix potential race condition in critical section HAL API
Call underlying HAL implementation to enter critical section/disable interrupts before incrementing the global critical section counter. Modify HAL implementations to track first entrances to the critical section and only update the saved state on first enter.
1 parent a07c07f commit e14bee5

File tree

4 files changed

+42
-10
lines changed

4 files changed

+42
-10
lines changed

features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/hal_patch/critical_section_api.c

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,20 +28,26 @@ static union {
2828
} _state = {0};
2929

3030
static bool _use_softdevice_routine = false;
31+
static bool _state_saved = false;
3132

3233
void hal_critical_section_enter(void)
3334
{
3435
// Fetch the current state of interrupts
3536
uint32_t primask = __get_PRIMASK();
37+
uint8_t temp_state = 0;
3638

3739
// If interrupts are enabled, try to use the soft device
3840
uint8_t sd_enabled;
3941
if ((primask == 0) &&
4042
(sd_softdevice_is_enabled(&sd_enabled) == NRF_SUCCESS) &&
4143
(sd_enabled == 1)) {
4244
// If the softdevice can be used, use it.
43-
sd_nvic_critical_region_enter(&_state._sd_state);
45+
sd_nvic_critical_region_enter(&temp_state);
4446
_use_softdevice_routine = true;
47+
48+
if (_state_saved == false) {
49+
_state._sd_state = temp_state;
50+
}
4551
} else {
4652
// If interrupts are enabled, disable them.
4753
if (primask == 0) {
@@ -50,13 +56,20 @@ void hal_critical_section_enter(void)
5056

5157
// Store PRIMASK state, it will be restored when exiting critical
5258
// section.
53-
_state._PRIMASK_state = primask;
5459
_use_softdevice_routine = false;
60+
61+
if (_state_saved == false) {
62+
_state._PRIMASK_state = primask;
63+
}
5564
}
65+
66+
_state_saved = true;
5667
}
5768

5869
void hal_critical_section_exit(void)
5970
{
71+
_state_saved = false;
72+
6073
// Restore the state as it was prior to entering the critical section.
6174
if (_use_softdevice_routine) {
6275
sd_nvic_critical_region_exit(_state._sd_state)

hal/mbed_critical_section_api.c

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include <stdbool.h>
2222

2323
static volatile bool critical_interrupts_enabled = false;
24+
static volatile bool state_saved = false;
2425

2526
static bool are_interrupts_enabled(void)
2627
{
@@ -34,17 +35,25 @@ static bool are_interrupts_enabled(void)
3435

3536
MBED_WEAK void hal_critical_section_enter(void)
3637
{
37-
critical_interrupts_enabled = are_interrupts_enabled();
38+
const bool interrupt_state = are_interrupts_enabled();
3839

3940
__disable_irq();
40-
}
4141

42+
if (state_saved == true) {
43+
return;
44+
}
45+
46+
critical_interrupts_enabled = interrupt_state;
47+
state_saved = true;
48+
}
4249

4350
MBED_WEAK void hal_critical_section_exit()
4451
{
4552
// Interrupts must be disabled on invoking an exit from a critical section
4653
MBED_ASSERT(!are_interrupts_enabled());
4754

55+
state_saved = false;
56+
4857
// Restore the IRQs to their state prior to entering the critical section
4958
if (critical_interrupts_enabled == true) {
5059
__enable_irq();

platform/mbed_critical.c

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -66,11 +66,9 @@ void core_util_critical_section_enter(void)
6666
MBED_ASSERT(critical_section_reentrancy_counter < UINT32_MAX);
6767
#endif /* FEATURE_UVISOR */
6868

69-
if (critical_section_reentrancy_counter == 0) {
70-
hal_critical_section_enter();
71-
}
69+
hal_critical_section_enter();
7270

73-
critical_section_reentrancy_counter++;
71+
++critical_section_reentrancy_counter;
7472
}
7573

7674
void core_util_critical_section_exit(void)
@@ -85,7 +83,7 @@ void core_util_critical_section_exit(void)
8583
return;
8684
}
8785

88-
critical_section_reentrancy_counter--;
86+
--critical_section_reentrancy_counter;
8987

9088
if (critical_section_reentrancy_counter == 0) {
9189
hal_critical_section_exit();

targets/TARGET_NORDIC/TARGET_NRF5/critical_section_api.c

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,28 @@
1616
*/
1717
#include "nrf_nvic.h"
1818

19+
#include <stdbool.h>
1920
#include <stdint.h> // uint32_t, UINT32_MAX
2021

2122
static uint8_t _sd_state = 0;
23+
static volatile bool _state_saved = false;
2224

2325
void hal_critical_section_enter(void)
2426
{
25-
sd_nvic_critical_region_enter(&_sd_state);
27+
uint8_t temp_state = 0;
28+
sd_nvic_critical_region_enter(&temp_state);
29+
30+
if (_state_saved == true) {
31+
return;
32+
}
33+
34+
_sd_state = temp_state;
35+
_state_saved = true;
2636
}
2737

2838
void hal_critical_section_exit(void)
2939
{
40+
_state_saved = false;
41+
3042
sd_nvic_critical_region_exit(_sd_state);
3143
}

0 commit comments

Comments
 (0)