sched/sem_waitirq: Move kmm_map() call to sem_wait()

The kernel mapping should be performed in sem_wait (thread level) as
virtual memory mappings cannot be added from interrupt, at least for now.

The reason?

kmm_map() depends on mm_map_add(), which in turn uses a mutex for mutual
exclusion. Using mutexes from interrupt level is not permitted.

Mapping tcb->waitobj into kernel virtual memory directly in sem_wait()
makes sense, since accessing tcb->waitobj via a user virtual address can
lead to unexpected results (the wrong mappings can be in place).
This commit is contained in:
Ville Juven
2025-03-12 15:05:34 +02:00
committed by archer
parent ac3b0adb42
commit 4959e269d6
3 changed files with 14 additions and 9 deletions

View File

@@ -31,6 +31,7 @@
#include <nuttx/irq.h>
#include <nuttx/arch.h>
#include <nuttx/sched.h>
#include <nuttx/mm/kmap.h>
#include "semaphore/semaphore.h"
@@ -100,6 +101,10 @@ void nxsem_recover(FAR struct tcb_s *tcb)
*/
atomic_fetch_add(NXSEM_COUNT(sem), 1);
#ifdef CONFIG_MM_KMAP
kmm_unmap(sem);
#endif
}
/* Release all semphore holders for the task */

View File

@@ -33,6 +33,7 @@
#include <nuttx/init.h>
#include <nuttx/irq.h>
#include <nuttx/arch.h>
#include <nuttx/mm/kmap.h>
#include "sched/sched.h"
#include "semaphore/semaphore.h"
@@ -117,6 +118,10 @@ static int nxsem_wait_slow(FAR sem_t *sem)
DEBUGASSERT(rtcb->waitobj == NULL);
#ifdef CONFIG_MM_KMAP
sem = kmm_map_user(rtcb, sem, sizeof(*sem));
#endif
/* Save the waited on semaphore in the TCB */
rtcb->waitobj = sem;
@@ -201,6 +206,10 @@ static int nxsem_wait_slow(FAR sem_t *sem)
ret = rtcb->errcode != OK ? -rtcb->errcode : OK;
#ifdef CONFIG_MM_KMAP
kmm_unmap(sem);
#endif
#ifdef CONFIG_PRIORITY_INHERITANCE
if (prioinherit != 0)
{

View File

@@ -32,7 +32,6 @@
#include <nuttx/irq.h>
#include <nuttx/arch.h>
#include <nuttx/mm/kmap.h>
#include "sched/sched.h"
#include "semaphore/semaphore.h"
@@ -74,10 +73,6 @@ void nxsem_wait_irq(FAR struct tcb_s *wtcb, int errcode)
FAR struct tcb_s *rtcb = this_task();
FAR sem_t *sem = wtcb->waitobj;
#ifdef CONFIG_MM_KMAP
sem = kmm_map_user(wtcb, sem, sizeof(*sem));
#endif
/* It is possible that an interrupt/context switch beat us to the punch
* and already changed the task's state.
*/
@@ -102,10 +97,6 @@ void nxsem_wait_irq(FAR struct tcb_s *wtcb, int errcode)
dq_rem((FAR dq_entry_t *)wtcb, SEM_WAITLIST(sem));
#ifdef CONFIG_MM_KMAP
kmm_unmap(sem);
#endif
/* Indicate that the wait is over. */
wtcb->waitobj = NULL;