Skip to content

Commit 671c2d7

Browse files
authored
Merge pull request #5346 from scartmell-arm/feature-hal-spec-critical-section
Add Critical Section HAL API specification
2 parents 7be79f9 + 643c892 commit 671c2d7

File tree

7 files changed

+310
-131
lines changed

7 files changed

+310
-131
lines changed
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/*
2+
* Copyright (c) 2015-2017, ARM Limited, All Rights Reserved
3+
* SPDX-License-Identifier: Apache-2.0
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License"); you may
6+
* not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
#include "cmsis.h"
18+
#include "nrf_error.h"
19+
#include "nrf_sdm.h"
20+
#include "nrf_soc.h"
21+
22+
#include <stdbool.h>
23+
#include <stdint.h>
24+
25+
static union {
26+
uint32_t _PRIMASK_state;
27+
uint8_t _sd_state;
28+
} _state = {0};
29+
30+
static bool _use_softdevice_routine = false;
31+
static bool _state_saved = false;
32+
33+
void hal_critical_section_enter(void)
34+
{
35+
// Fetch the current state of interrupts
36+
uint32_t primask = __get_PRIMASK();
37+
uint8_t temp_state = 0;
38+
39+
// If interrupts are enabled, try to use the soft device
40+
uint8_t sd_enabled;
41+
if ((primask == 0) &&
42+
(sd_softdevice_is_enabled(&sd_enabled) == NRF_SUCCESS) &&
43+
(sd_enabled == 1)) {
44+
// If the softdevice can be used, use it.
45+
sd_nvic_critical_region_enter(&temp_state);
46+
_use_softdevice_routine = true;
47+
48+
if (_state_saved == false) {
49+
_state._sd_state = temp_state;
50+
}
51+
} else {
52+
// If interrupts are enabled, disable them.
53+
if (primask == 0) {
54+
__disable_irq();
55+
}
56+
57+
// Store PRIMASK state, it will be restored when exiting critical
58+
// section.
59+
_use_softdevice_routine = false;
60+
61+
if (_state_saved == false) {
62+
_state._PRIMASK_state = primask;
63+
}
64+
}
65+
66+
_state_saved = true;
67+
}
68+
69+
void hal_critical_section_exit(void)
70+
{
71+
_state_saved = false;
72+
73+
// Restore the state as it was prior to entering the critical section.
74+
if (_use_softdevice_routine) {
75+
sd_nvic_critical_region_exit(_state._sd_state)
76+
} else {
77+
__set_PRIMASK(_state._PRIMASK_state);
78+
}
79+
}
80+
81+
bool hal_in_critical_section(void)
82+
{
83+
return (_state_saved == true);
84+
}

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

Lines changed: 0 additions & 80 deletions
This file was deleted.

hal/critical_section_api.h

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
/** \addtogroup hal */
2+
/** @{*/
3+
/* mbed Microcontroller Library
4+
* Copyright (c) 2006-2017 ARM Limited
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
#ifndef MBED_CRITICAL_SECTION_API_H
19+
#define MBED_CRITICAL_SECTION_API_H
20+
21+
#include <stdbool.h>
22+
23+
#ifdef __cplusplus
24+
extern "C" {
25+
#endif
26+
27+
/**
28+
* \defgroup hal_critical Critical Section HAL functions
29+
* @{
30+
*/
31+
32+
/**
33+
* Mark the start of a critical section
34+
*
35+
* This function will be called by core_util_critical_section_enter() each time
36+
* the application requests to enter a critical section. The purpose of the
37+
* critical section is to ensure mutual-exclusion synchronisation of the
38+
* processor by preventing any change in processor control, the default
39+
* behaviour requires storing the state of interrupts in the system before
40+
* disabling them.
41+
*
42+
* The critical section code supports nesting. When a thread has entered a
43+
* critical section it can make additional calls to
44+
* core_util_critical_section_enter() without deadlocking itself. The critical
45+
* section driver API tracks the number of nested calls to the critical section.
46+
* The critical section will only be exited when
47+
* core_util_critical_section_exit() has been called once for each time it
48+
* entered the critical section.
49+
*
50+
* On the first call to enter a critical section this function MUST store the
51+
* state of any interrupts or other application settings it will modify to
52+
* facilitate the critical section.
53+
*
54+
* Each successive call to enter the critical section MUST ignore storing or
55+
* modifying any application state.
56+
*
57+
* The default implementation of this function which will save the current state
58+
* of interrupts before disabling them. This implementation can be found in
59+
* mbed_critical_section_api.c. This behaviour is can be overridden on a per
60+
* platform basis by providing a different implementation within the correct
61+
* targets directory.
62+
*/
63+
void hal_critical_section_enter(void);
64+
65+
66+
/** Mark the end of a critical section.
67+
*
68+
* The purpose of this function is to restore any state that was modified upon
69+
* entering the critical section, allowing other threads or interrupts to change
70+
* the processor control.
71+
*
72+
* This function will be called once by core_util_critical_section_exit() per
73+
* critical section on last call to exit. When called, the application MUST
74+
* restore the saved interrupt/application state that was saved when entering
75+
* the critical section.
76+
*
77+
* There is a default implementation of this function, it will restore the state
78+
* of interrupts that were previously saved when hal_critical_section_enter was
79+
* first called, this implementation can be found in
80+
* mbed_critical_section_api.c. This behaviour is overridable by providing a
81+
* different function implementation within the correct targets directory.
82+
*/
83+
void hal_critical_section_exit(void);
84+
85+
86+
/** Determine if the application is currently running in a critical section
87+
*
88+
* The purpose of this function is to inform the caller whether or not the
89+
* application is running in a critical section. This is done by checking if
90+
* the current interrupt state has been saved in the underlying implementation,
91+
* this could also be done by checking the state of the interrupts at the time
92+
* of calling.
93+
*
94+
* @return True if running in a critical section, false if not.
95+
*/
96+
bool hal_in_critical_section(void);
97+
98+
99+
/**@}*/
100+
101+
#ifdef __cplusplus
102+
}
103+
#endif
104+
105+
#endif // MBED_CRITICAL_SECTION_API_H
106+
107+
/** @}*/

hal/mbed_critical_section_api.c

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/* mbed Microcontroller Library
2+
* Copyright (c) 2017 ARM Limited
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+
#include "cmsis.h"
17+
#include "hal/critical_section_api.h"
18+
#include "platform/mbed_assert.h"
19+
#include "platform/mbed_toolchain.h"
20+
21+
#include <stdbool.h>
22+
23+
static volatile bool critical_interrupts_enabled = false;
24+
static volatile bool state_saved = false;
25+
26+
static bool are_interrupts_enabled(void)
27+
{
28+
#if defined(__CORTEX_A9)
29+
return ((__get_CPSR() & 0x80) == 0);
30+
#else
31+
return ((__get_PRIMASK() & 0x1) == 0);
32+
#endif
33+
}
34+
35+
36+
MBED_WEAK void hal_critical_section_enter(void)
37+
{
38+
const bool interrupt_state = are_interrupts_enabled();
39+
40+
__disable_irq();
41+
42+
if (state_saved == true) {
43+
return;
44+
}
45+
46+
critical_interrupts_enabled = interrupt_state;
47+
state_saved = true;
48+
}
49+
50+
MBED_WEAK void hal_critical_section_exit(void)
51+
{
52+
#ifndef FEATURE_UVISOR
53+
// Interrupts must be disabled on invoking an exit from a critical section
54+
MBED_ASSERT(!are_interrupts_enabled());
55+
#endif
56+
state_saved = false;
57+
58+
// Restore the IRQs to their state prior to entering the critical section
59+
if (critical_interrupts_enabled == true) {
60+
__enable_irq();
61+
}
62+
}
63+
64+
MBED_WEAK bool hal_in_critical_section(void)
65+
{
66+
return (state_saved == true);
67+
}

0 commit comments

Comments
 (0)