diff --git a/arch/arm64/include/arch.h b/arch/arm64/include/arch.h index f3b29fd6f81c3..f8a78b38d035e 100644 --- a/arch/arm64/include/arch.h +++ b/arch/arm64/include/arch.h @@ -55,7 +55,7 @@ /**************************************************************************** * Name: - * read_/write_/zero_ sysreg + * read_/write_/zero_/modify_ sysreg * * Description: * @@ -84,6 +84,10 @@ ::: "memory"); \ }) +#define modify_sysreg(v,m,a) \ + write_sysreg((read_sysreg(a) & ~(m)) | \ + ((uintptr_t)(v) & (m)), a) + /**************************************************************************** * Inline functions ****************************************************************************/ diff --git a/arch/arm64/include/irq.h b/arch/arm64/include/irq.h index 42a00c2066494..7830505067205 100644 --- a/arch/arm64/include/irq.h +++ b/arch/arm64/include/irq.h @@ -382,31 +382,17 @@ static inline void up_irq_restore(irqstate_t flags) #endif /* CONFIG_ARCH_HAVE_MULTICPU */ /**************************************************************************** - * Name: - * up_current_regs/up_set_current_regs - * - * Description: - * We use the following code to manipulate the tpidr_el1 register, - * which exists uniquely for each CPU and is primarily designed to store - * current thread information. Currently, we leverage it to store interrupt - * information, with plans to further optimize its use for storing both - * thread and interrupt information in the future. + * Schedule acceleration macros * + * The lsbit of tpidr_el1 stores information about whether the current + * execution is in an interrupt context, where 1 indicates being in an + * interrupt context and 0 indicates being in a thread context. ****************************************************************************/ -noinstrument_function -static inline_function uint64_t *up_current_regs(void) -{ - uint64_t *regs; - __asm__ volatile ("mrs %0, " "tpidr_el1" : "=r" (regs)); - return regs; -} - -noinstrument_function -static inline_function void up_set_current_regs(uint64_t *regs) -{ - __asm__ volatile ("msr " "tpidr_el1" ", %0" : : "r" (regs)); -} +#define up_current_regs() (this_task()->xcp.regs) +#define up_this_task() ((struct tcb_s *)(read_sysreg(tpidr_el1) & ~1ul)) +#define up_update_task(t) modify_sysreg(t, ~1ul, tpidr_el1) +#define up_interrupt_context() (read_sysreg(tpidr_el1) & 1) #define up_switch_context(tcb, rtcb) \ do { \ @@ -417,19 +403,6 @@ static inline_function void up_set_current_regs(uint64_t *regs) } \ } while (0) -/**************************************************************************** - * Name: up_interrupt_context - * - * Description: Return true is we are currently executing in - * the interrupt handler context. - * - ****************************************************************************/ - -static inline bool up_interrupt_context(void) -{ - return up_current_regs() != NULL; -} - /**************************************************************************** * Name: up_getusrpc ****************************************************************************/ diff --git a/arch/arm64/src/common/arm64_cpustart.c b/arch/arm64/src/common/arm64_cpustart.c index 46f9b72151c55..5aeb600944f78 100644 --- a/arch/arm64/src/common/arm64_cpustart.c +++ b/arch/arm64/src/common/arm64_cpustart.c @@ -113,7 +113,7 @@ static inline void local_delay(void) static void arm64_smp_init_top(void) { - struct tcb_s *tcb = this_task(); + struct tcb_s *tcb = current_task(this_cpu()); #ifndef CONFIG_SUPPRESS_INTERRUPTS /* And finally, enable interrupts */ @@ -222,6 +222,12 @@ int up_cpu_start(int cpu) void arm64_boot_secondary_c_routine(void) { + struct tcb_s *tcb = current_task(this_cpu()); + + /* Init idle task to percpu reg */ + + up_update_task(tcb); + #ifdef CONFIG_ARCH_HAVE_MPU arm64_mpu_init(false); #endif diff --git a/arch/arm64/src/common/arm64_doirq.c b/arch/arm64/src/common/arm64_doirq.c index 9806c2c41c043..499b2ab3e4f42 100644 --- a/arch/arm64/src/common/arm64_doirq.c +++ b/arch/arm64/src/common/arm64_doirq.c @@ -61,13 +61,12 @@ uint64_t *arm64_doirq(int irq, uint64_t * regs) /* Nested interrupts are not supported */ - DEBUGASSERT(up_current_regs() == NULL); + DEBUGASSERT(!up_interrupt_context()); - /* Current regs non-zero indicates that we are processing an interrupt; - * current_regs is also used to manage interrupt level context switches. - */ + /* Set irq flag */ + + write_sysreg((uintptr_t)tcb | 1, tpidr_el1); - up_set_current_regs(regs); tcb->xcp.regs = regs; /* Deliver the IRQ */ @@ -110,11 +109,9 @@ uint64_t *arm64_doirq(int irq, uint64_t * regs) regs = tcb->xcp.regs; } - /* Set current_regs to NULL to indicate that we are no longer in an - * interrupt handler. - */ + /* Clear irq flag */ - up_set_current_regs(NULL); + write_sysreg((uintptr_t)tcb & ~1ul, tpidr_el1); return regs; } diff --git a/arch/arm64/src/common/arm64_fatal.c b/arch/arm64/src/common/arm64_fatal.c index 202af3b707fc3..7f4cd2d7d33f9 100644 --- a/arch/arm64/src/common/arm64_fatal.c +++ b/arch/arm64/src/common/arm64_fatal.c @@ -544,13 +544,18 @@ static int arm64_exception_handler(struct regs_context *regs) void arm64_fatal_handler(struct regs_context *regs) { + struct tcb_s *tcb = this_task(); int ret; /* Nested exception are not supported */ - DEBUGASSERT(up_current_regs() == NULL); + DEBUGASSERT(!up_interrupt_context()); - up_set_current_regs((uint64_t *)regs); + tcb->xcp.regs = (uint64_t *)regs; + + /* Set irq flag */ + + write_sysreg((uintptr_t)tcb | 1, tpidr_el1); ret = arm64_exception_handler(regs); @@ -561,11 +566,9 @@ void arm64_fatal_handler(struct regs_context *regs) PANIC_WITH_REGS("panic", regs); } - /* Set CURRENT_REGS to NULL to indicate that we are no longer in an - * Exception handler. - */ + /* Clear irq flag */ - up_set_current_regs(NULL); + write_sysreg((uintptr_t)tcb & ~1ul, tpidr_el1); } void arm64_register_debug_hook(int nr, fatal_handle_func_t fn) diff --git a/arch/arm64/src/common/arm64_registerdump.c b/arch/arm64/src/common/arm64_registerdump.c index 692d275681c6a..d04e173b6fe0a 100644 --- a/arch/arm64/src/common/arm64_registerdump.c +++ b/arch/arm64/src/common/arm64_registerdump.c @@ -31,6 +31,7 @@ #include #include +#include "sched/sched.h" #include "arm64_arch.h" #include "arm64_internal.h" #include "chip.h" diff --git a/fs/procfs/fs_procfstcbinfo.c b/fs/procfs/fs_procfstcbinfo.c index 7aa1f4745938e..23cc918a3d7ff 100644 --- a/fs/procfs/fs_procfstcbinfo.c +++ b/fs/procfs/fs_procfstcbinfo.c @@ -41,6 +41,7 @@ #include #include "fs_heap.h" +#include "sched/sched.h" #if !defined(CONFIG_DISABLE_MOUNTPOINT) && defined(CONFIG_FS_PROCFS) && \ defined(CONFIG_ARCH_HAVE_TCBINFO) && !defined(CONFIG_FS_PROCFS_EXCLUDE_TCBINFO) diff --git a/include/nuttx/arch.h b/include/nuttx/arch.h index e6c9199a7fd3f..e2d5381655dfa 100644 --- a/include/nuttx/arch.h +++ b/include/nuttx/arch.h @@ -943,6 +943,43 @@ int up_copy_section(FAR void *dest, FAR const void *src, size_t n); # define up_getpicbase(ppicbase) #endif +/**************************************************************************** + * Percpu support + ****************************************************************************/ + +/**************************************************************************** + * Name: up_update_task + * + * Description: + * We can utilize percpu storage to hold information about the + * current running task. If we intend to implement this feature, we would + * need to define two macros that help us manage this percpu information + * effectively. + * + * up_this_task: This macro is designed to read the contents of the percpu + * register to retrieve information about the current + * running task.This allows us to quickly access + * task-specific data without having to disable interrupts, + * access global variables and obtain the current cpu index. + * + * up_update_task: This macro is responsible for updating the contents of + * the percpu register.It is typically called during + * initialization or when a context switch occurs to ensure + * that the percpu register reflects the information of the + * newly running task. + * + * Input Parameters: + * current tcb + * + * Returned Value: + * current tcb + * + ****************************************************************************/ + +#ifndef up_update_task +# define up_update_task(t) +#endif + /**************************************************************************** * Address Environment Interfaces * diff --git a/libs/libc/time/lib_localtime.c b/libs/libc/time/lib_localtime.c index 64e79f2b06d27..8be9d17258be4 100644 --- a/libs/libc/time/lib_localtime.c +++ b/libs/libc/time/lib_localtime.c @@ -53,6 +53,7 @@ #include +#include #include #include #include diff --git a/net/utils/net_snoop.c b/net/utils/net_snoop.c index bdbca71291be8..38c16c9ff43da 100644 --- a/net/utils/net_snoop.c +++ b/net/utils/net_snoop.c @@ -34,6 +34,7 @@ #include +#include #include /**************************************************************************** diff --git a/sched/init/nx_start.c b/sched/init/nx_start.c index 2cdf6f5a1a84d..8f88e2b6c1ba7 100644 --- a/sched/init/nx_start.c +++ b/sched/init/nx_start.c @@ -429,6 +429,11 @@ static void idle_task_initialize(void) /* Mark the idle task as the running task */ g_running_tasks[i] = tcb; + + if (i == 0) + { + up_update_task(&g_idletcb[0]); /* Init idle task to percpu reg */ + } } } diff --git a/sched/sched/sched.h b/sched/sched/sched.h index a17dfcd5a29ed..92a441cb04cf3 100644 --- a/sched/sched/sched.h +++ b/sched/sched/sched.h @@ -69,7 +69,6 @@ # define current_task(cpu) ((FAR struct tcb_s *)list_assignedtasks(cpu)->head) #else # define current_task(cpu) ((FAR struct tcb_s *)list_readytorun()->head) -# define this_task() (current_task(this_cpu())) #endif #define is_idle_task(t) ((t)->pid < CONFIG_SMP_NCPUS) @@ -375,7 +374,11 @@ void nxsched_sporadic_lowpriority(FAR struct tcb_s *tcb); void nxsched_suspend(FAR struct tcb_s *tcb); #endif -#ifdef CONFIG_SMP +#if defined(up_this_task) +# define this_task() up_this_task() +#elif !defined(CONFIG_SMP) +# define this_task() ((FAR struct tcb_s *)g_readytorun.head) +#else noinstrument_function static inline_function FAR struct tcb_s *this_task(void) { @@ -389,7 +392,7 @@ static inline_function FAR struct tcb_s *this_task(void) flags = up_irq_save(); - /* Obtain the TCB which is currently running on this CPU */ + /* Obtain the TCB which is current running on this CPU */ tcb = current_task(this_cpu()); @@ -398,7 +401,9 @@ static inline_function FAR struct tcb_s *this_task(void) up_irq_restore(flags); return tcb; } +#endif +#ifdef CONFIG_SMP void nxsched_process_delivered(int cpu); #else # define nxsched_select_cpu(a) (0) diff --git a/sched/sched/sched_addreadytorun.c b/sched/sched/sched_addreadytorun.c index 18032dc9b4aab..fd5ccc1f2f6b5 100644 --- a/sched/sched/sched_addreadytorun.c +++ b/sched/sched/sched_addreadytorun.c @@ -100,6 +100,7 @@ bool nxsched_add_readytorun(FAR struct tcb_s *btcb) btcb->task_state = TSTATE_TASK_RUNNING; btcb->flink->task_state = TSTATE_TASK_READYTORUN; + up_update_task(btcb); ret = true; } else @@ -269,6 +270,7 @@ bool nxsched_add_readytorun(FAR struct tcb_s *btcb) */ dq_addfirst_nonempty((FAR dq_entry_t *)btcb, tasklist); + up_update_task(btcb); DEBUGASSERT(task_state == TSTATE_TASK_RUNNING); btcb->cpu = cpu; diff --git a/sched/sched/sched_mergepending.c b/sched/sched/sched_mergepending.c index 2aa515458c979..a577932957eb1 100644 --- a/sched/sched/sched_mergepending.c +++ b/sched/sched/sched_mergepending.c @@ -134,6 +134,7 @@ bool nxsched_merge_pending(void) = (FAR dq_entry_t *)ptcb; rtcb->task_state = TSTATE_TASK_READYTORUN; ptcb->task_state = TSTATE_TASK_RUNNING; + up_update_task(ptcb); ret = true; } else diff --git a/sched/sched/sched_process_delivered.c b/sched/sched/sched_process_delivered.c index b0394354431a8..016f7307129b5 100644 --- a/sched/sched/sched_process_delivered.c +++ b/sched/sched/sched_process_delivered.c @@ -120,6 +120,7 @@ void nxsched_process_delivered(int cpu) dq_addfirst_nonempty((FAR dq_entry_t *)btcb, tasklist); btcb->cpu = cpu; btcb->task_state = TSTATE_TASK_RUNNING; + up_update_task(btcb); DEBUGASSERT(btcb->flink != NULL); DEBUGASSERT(next == btcb->flink); diff --git a/sched/sched/sched_profil.c b/sched/sched/sched_profil.c index de77d4e60ffbd..21294f6205ab7 100644 --- a/sched/sched/sched_profil.c +++ b/sched/sched/sched_profil.c @@ -28,6 +28,7 @@ #include #include #include +#include "sched/sched.h" /**************************************************************************** * Pre-processor Definitions diff --git a/sched/sched/sched_removereadytorun.c b/sched/sched/sched_removereadytorun.c index abfff839bd520..be7ebac2e2961 100644 --- a/sched/sched/sched_removereadytorun.c +++ b/sched/sched/sched_removereadytorun.c @@ -85,6 +85,7 @@ bool nxsched_remove_readytorun(FAR struct tcb_s *rtcb) DEBUGASSERT(nxttcb != NULL); nxttcb->task_state = TSTATE_TASK_RUNNING; + up_update_task(nxttcb); doswitch = true; } @@ -270,6 +271,8 @@ void nxsched_remove_running(FAR struct tcb_s *tcb) /* Since the TCB is no longer in any list, it is now invalid */ tcb->task_state = TSTATE_TASK_INVALID; + + up_update_task(nxttcb); } void nxsched_remove_self(FAR struct tcb_s *tcb)