Skip to content

Commit 51625cb

Browse files
duda-patrykCommit Bot
authored andcommitted
cortex-m/task: Check if interrupts are enabled before switching task
Switching task with disabled interrupts leads to Forced Hard Fault on Cortex-M3/M4/M7 because: - SVCall exception have configurable priority (full list can be found at 2.4.2 Exception types PM0253 Rev 5 p.40) - We are using 'cpsid i' to disable interrupts. This instruction sets PRIMASK bit (3.12.2 CPS PM0253 Rev 5 p.176) - When PRIMASK bit is set, all exceptions with configurable priority are disabled (PM0253 Rev 5 p.25), so SVCall is masked too - SVCall is escalated to Forced Hard Fault because "A fault occurs and the handler for that fault is not enabled" (PM0253 Rev 5 p.48) If Hard Fault is inevitable, it will be a good idea to catch this earlier. It will save time spent debugging why Forced Hard Fault happens. In functions responsible for enabling, disabling or making task ready we postpone task switch when interrupts are disabled BUG=b:190597666 BRANCH=none TEST=Compile and flash EC on boards with Cortex-M3/M4/M7 and make sure that it works properly. Signed-off-by: Patryk Duda <[email protected]> Change-Id: I50976154b0cf0307c5334f6f03e4b3bc137a4ffc Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2953228 Commit-Queue: Marcin Wojtas <[email protected]> Tested-by: Patryk Duda <[email protected]> Reviewed-by: Aseda Aboagye <[email protected]>
1 parent b7b266b commit 51625cb

File tree

1 file changed

+14
-3
lines changed

1 file changed

+14
-3
lines changed

core/cortex-m/task.c

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,15 @@ static uint32_t __wait_evt(int timeout_us, task_id_t resched)
415415
uint32_t evt;
416416
int ret __attribute__((unused));
417417

418+
/*
419+
* Scheduling task when interrupts are disabled will result in Forced
420+
* Hard Fault because:
421+
* - Disabling interrupt using 'cpsid i' also disables SVCall handler
422+
* (because it has configurable priority)
423+
* - Escalation to Hard Fault (also known as 'priority escalation')
424+
* occurs when handler for that fault is not enabled
425+
*/
426+
ASSERT(is_interrupt_enabled());
418427
ASSERT(!in_interrupt_context());
419428

420429
if (timeout_us > 0) {
@@ -445,7 +454,7 @@ uint32_t task_set_event(task_id_t tskid, uint32_t event)
445454
atomic_or(&receiver->events, event);
446455

447456
/* Re-schedule if priorities have changed */
448-
if (in_interrupt_context()) {
457+
if (in_interrupt_context() || !is_interrupt_enabled()) {
449458
/* The receiver might run again */
450459
atomic_or(&tasks_ready, 1 << tskid);
451460
#ifndef CONFIG_TASK_PROFILING
@@ -497,7 +506,8 @@ void task_enable_all_tasks(void)
497506
/* Mark all tasks as ready and able to run. */
498507
tasks_ready = tasks_enabled = BIT(TASK_ID_COUNT) - 1;
499508
/* Reschedule the highest priority task. */
500-
__schedule(0, 0);
509+
if (is_interrupt_enabled())
510+
__schedule(0, 0);
501511
}
502512

503513
void task_enable_task(task_id_t tskid)
@@ -509,7 +519,8 @@ void task_disable_task(task_id_t tskid)
509519
{
510520
atomic_clear_bits(&tasks_enabled, BIT(tskid));
511521

512-
if (!in_interrupt_context() && tskid == task_get_current())
522+
if (!in_interrupt_context() && is_interrupt_enabled() &&
523+
tskid == task_get_current())
513524
__schedule(0, 0);
514525
}
515526

0 commit comments

Comments
 (0)