Commit graph zephyr/kernel
Author SHA1 Message Date
Aaron Wisner
4d042d3103 kernel: add configurable striped semaphore locking
Replace the system-wide semaphore spinlock with a configurable array
of naturally aligned lock stripes. Hash each semaphore by its natural
alignment without changing the semaphore object ABI.

Default CONFIG_SEM_LOCK_STRIPES to one so SMP and uniprocessor builds
preserve existing global-lock behavior and static memory use. Use a
scalar lock unless SMP striping is explicitly enabled, so UP builds
retain zero-sized spinlocks and avoid non-portable empty-struct arrays.

Require a power-of-two stripe count so the compiler reduces stripe
selection to a bitmask. Divide by the alignment of struct k_sem before
hashing to discard redundant address bits.

Do not impose cache-line alignment or padding. Explain how spinlock
and cache-line sizes affect the stripe count needed to reduce cache
contention.

Validate upstream semaphore regressions with zero-sized uniprocessor
spinlocks and SMP configurations using one, 16, and 32 stripes.
Reject non-power-of-two stripe counts at compile time.

An internal throughput microbenchmark on a quad-core ARM Cortex-A53
SMP system observed an improvement of approximately 3.1%.

Assisted-by: Codex:GPT-5
Signed-off-by: Aaron Wisner <awiz@openai.com>
2026-08-27 22:11:20 -04:00
Fin Maaß
84e82eae4c kernel: Kconfig: remove prompts from SoC and Board Hooks
The SoC and board hooks are selected by the
SoC or the board. They also implemt them.
Remove the ability to enable them regularly
by the user as the build would then fail, because
the board or SoC has not implemented them.

Signed-off-by: Fin Maaß <f.maass@vogl-electronic.com>
2026-08-27 21:26:07 +01:00
Måns Ansgariusson
839c682963 sys: __assert: migrate users away from __ASSERT_ON
Remove remaining uses of the internal __ASSERT_ON macro. Let __ASSERT()
handle disabled assertions, mark assert-only values as unused where needed,
and use CONFIG_ASSERT for assertion-only state.

Signed-off-by: Måns Ansgariusson <mansgariusson@gmail.com>
2026-08-27 12:12:11 +01:00
Fin Maaß
befb09db72 kernel: init: remove reference to legacy api
Remove reference to legacy api, where the delay
is fixed to K_FOREVER, as that, since quite some time,
no longer exists.

Signed-off-by: Fin Maaß <f.maass@vogl-electronic.com>
2026-08-26 18:14:02 -07:00
Lokesh Gundu
60d6e9ac24 kernel: mmu: use overflow-free inclusive-end form for address range asserts
Replace the unsigned-arithmetic range checks in k_mem_map_phys_bare()
and k_mem_unmap_phys_bare() with the equivalent overflow-free form:

    __ASSERT(aligned_size - 1 <= (UINTPTR_MAX - aligned_addr), ...)

The original checks were correct, but the explicit form avoids
relying on unsigned wraparound behavior and is consistent across
all assert sites in mmu.c.

Signed-off-by: Lokesh Gundu <lgundu@qti.qualcomm.com>
2026-08-26 15:14:44 -04:00
Magnus Strømme
3ac8ef05fc kernel: queue: skip blocking trace for no-wait get
An empty k_queue_get() emits the blocking trace before checking
K_NO_WAIT. This records a block that never occurs and invokes the
tracing backend on a non-blocking fast path.

Move the trace below the no-wait return so only calls that can pend
emit it. Add CTF coverage for an empty no-wait get.

Signed-off-by: Magnus Strømme <magnus.henrik@hotmail.com>
2026-08-24 14:06:45 -07:00
Hui Su
374352fef2 kernel: stack: fix allocation size overflow
k_stack_alloc_init() calculates the allocation size as
num_entries * sizeof(stack_data_t). On targets where size_t is 32 bits,
a sufficiently large entry count can overflow the multiplication and
result in an allocation much smaller than the capacity recorded in the
stack object.

The userspace verifier already checks this multiplication, but supervisor
callers invoke z_impl_k_stack_alloc_init() directly and bypass that check.

Check the multiplication in the implementation before allocating the
buffer. Treat an overflowing request as an allocation failure and return
-ENOMEM.

Add regression coverage for the supervisor allocation path. The complete
qemu_cortex_m3 stack validation passed after the fix:

    16 tests passed, 0 failed
    PROJECT EXECUTION SUCCESSFUL

Fixes: be3d4232c2 ("kernel: fix k_stack_alloc_init()")
Signed-off-by: Hui Su <3164683437@qq.com>
2026-08-22 19:20:09 -04:00
Hui Su
6468c07692 kernel: dynamic: fix kernel stack size overflow
k_thread_stack_alloc() passed K_KERNEL_STACK_LEN(size) directly to the
allocator. The alignment and reserved-size arithmetic could wrap for an
oversized request, causing it to be turned into a much smaller allocation
instead of being rejected.

Before the fix, the regression test accepted SIZE_MAX and reported:

    Assertion failed ... (stack is not NULL)
    overflowing stack size must be rejected
    FAIL - test_dynamic_thread_stack_size_overflow

Reject the allocation when K_KERNEL_STACK_LEN(size) is smaller than the
requested size, which indicates that the size calculation wrapped. The
existing userspace dynamic-object overflow check remains unchanged.

Fixes: 7b1b2576ac ("kernel: support dynamic thread stack allocation")
Signed-off-by: Hui Su <3164683437@qq.com>
2026-08-21 16:20:34 +02:00
Hui Su
0ea1a26fed kernel: queue: remove alloc nodes by payload
k_queue_alloc_append() and k_queue_alloc_prepend() wrap the caller's data
in an internal alloc_node before inserting it into the queue. The old
k_queue_remove() implementation searched for the caller data pointer as
if it were the linked-list node, so removal returned false and left the
allocated queue item in place.

Walk the queue and compare the unwrapped payload pointer instead. Free
the alloc_node wrapper after removing a matching item, while preserving
the existing behavior for directly inserted queue nodes.

Add coverage for removing items inserted through both alloc APIs.

Tested:
- ZEPHYR_TOOLCHAIN_VARIANT=gnuarmemb GNUARMEMB_TOOLCHAIN_PATH=/usr
  west build -d /tmp/zephyr-queue-gnuarmemb
- qemu_cortex_m3: queue_api 15/15 and queue_api_1cpu 7/7

Signed-off-by: Hui Su <3164683437@qq.com>
2026-08-21 16:20:05 +02:00
Peter Mitsis
a9b21fb354 kernel: userspace: Add z_waitq_head_locked()
Splits z_waitq_head() into two versions: z_waitq_head_locked() and
z_waitq_head(). When the scheduler's spinlock is known to be already
held, z_waitq_head_locked() should be used--otherwise, z_waitq_head()
is to be used.

However, this approach uncovered a path where the scheduler spinlock
could be recursively taken when a thread is aborted. To work around the
recursion (see k_thread_perms_all_clear), knowledge of the scheduler's
spinlock state must be passed to the lower layers for use in the
cleanup routines for message queues, stacks and timers.

Fixes #115756

Signed-off-by: Peter Mitsis <peter.mitsis@intel.com>
2026-08-21 16:17:54 +02:00
Peter Mitsis
b4ac294bf5 kernel: k_free() no longer calls z_waitq_head()
As k_malloc(), k_calloc(), k_realloc() are non-blocking calls,
k_free() should not be calling z_waitq_head() to look for blocked
threads. Developers that want the blocking/waking capabilities
should use the k_heap_xxx() routines instead.

Signed-off-by: Peter Mitsis <peter.mitsis@intel.com>
2026-08-21 16:17:54 +02:00
Peter Mitsis
13d8b5eb23 kernel: Apply lock in stack and msgq cleanup routines
Updates the k_stack_cleanup() and k_msgq_cleanup() routines
to lock the appropriate lock to prevent two execution contexts
from trying to clean up the same object at the same time.

Signed-off-by: Peter Mitsis <peter.mitsis@intel.com>
2026-08-21 16:17:54 +02:00
Peter Mitsis
36f1a8515a kernel: Update _sched_spinlock comment references
Updates the comments that reference _sched_spinlock to refer instead
to the scheduler's spinlock.

Signed-off-by: Peter Mitsis <peter.mitsis@intel.com>
2026-08-21 16:17:54 +02:00
Peter Mitsis
52301ff761 kernel: Add and use z_reschedule_locked()
As part of an effort to abstract away the use of _sched_spinlock in
the kernel, this commit introduces z_reschedule_locked(). Callers
must already have _sched_spinlock held.

Signed-off-by: Peter Mitsis <peter.mitsis@intel.com>
2026-08-21 16:17:54 +02:00
Peter Mitsis
285361130e kernel: Add and use z_swap_locked()
As part of an effort to abstract away the use of _sched_spinlock in
the kernel, this commit introduces z_swap_locked(). Callers must
already have _sched_spinlock held.

Signed-off-by: Peter Mitsis <peter.mitsis@intel.com>
2026-08-21 16:17:54 +02:00
Peter Mitsis
772e73c8aa kernel: Add private kernel header file kspinlock.h
The scheduler's spinlock was originally confined to sched.c. However,
as the kernel has evolved and functionality has been moved around,
not only have its references proliferated, but the header files that
reference it have become somewhat brittle. This commits adds a new
private header that will abstract away most of the scheduler's
spinlock references to help keep things cleaner and applies them to
the kernel.

Signed-off-by: Peter Mitsis <peter.mitsis@intel.com>
2026-08-21 16:17:54 +02:00
Nicolas Pitre
a672a717ca tracing: give k_sleep_ticks() its own trace point
The sleep trace hooks were attached to k_sleep(), k_msleep() and
k_usleep().  Those are inline wrappers now, and the only function left to
instrument is the k_sleep_ticks() primitive underneath them, so the three
hook families no longer have anything emitting them.  The msleep pair had
in fact been unused for some time already.

Replace all three with one k_thread_sleep_ticks pair reporting the timeout
and the time left to sleep in ticks, and drop what is left behind in each
backend: the CTF events and their top level helpers, the entry in
SYSVIEW_Zephyr.txt, and the user and test hooks.  The new CTF and
SystemView ids are fresh rather than reused, so a recording made by an
older build cannot be misread by a newer decoder.  The retired SystemView
ids stay defined, since out of tree code may refer to them.

The profiling example in the instrumentation documentation named two
symbols that no longer exist, and is updated to the ones that replace
them.

Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
2026-08-20 08:52:31 +02:00
Nicolas Pitre
1d32fe9153 kernel: inline k_sleep() and k_usleep() over a tick primitive
k_sleep() and k_usleep() resolve to an out of line implementation living in
another translation unit, a system call under CONFIG_USERSPACE and a plain
call otherwise.  Either way the compiler sees neither whether the requested
duration is a constant nor whether the caller cares about the returned
value, so it always emits the tick to millisecond and microsecond
conversions.  Those conversions are the only thing that drags the 64 bit
division helper into many small builds: CONFIG_SYS_CLOCK_TICKS_PER_SEC
defaults to 10000 on tickless platforms, which lands in the integer
division path and divides a 64 bit value by ten, something GCC will not
strength reduce on a 32 bit target.

Promote the former z_tick_sleep() helper to a k_sleep_ticks() system call
that reports the remaining time in ticks, and rebuild k_sleep() and
k_usleep() as inlines on top of it.  The conversions now live at the call
site where the compiler can fold or discard them.  Nearly every caller
discards them: of the 4036 sleep call sites in the tree, exactly six use
the returned value, and only three of those are outside of tests.

What this removes is best seen in the two out of line entry points that
disappear, which on a nucleo_f030r8 (Cortex-M0, 10000 ticks/s) were the
only two callers of the 64 bit division helper in the whole image:

  08002594 <z_impl_k_sleep>:
        bl      8001... <z_tick_sleep>
        ...
        movs    r0, #9            /* the ceil() bias, 10 - 1 */
        adds    r0, r0, r2
        adcs    r1, r3
        movs    r2, #10           /* ticks / 10 -> milliseconds */
        bl      8000180 <__aeabi_uldivmod>

  080025c0 <z_impl_k_usleep>:
        movs    r0, #99           /* the ceil() bias, 100 - 1 */
        ...
        movs    r2, #100          /* microseconds / 100 -> ticks */
        bl      8000180 <__aeabi_uldivmod>
        bl      8001... <z_tick_sleep>

Both are gone, and so are __aeabi_uldivmod and __udivmoddi4, which are no
longer referenced anywhere.  A k_usleep(250) call site now passes the
literal 3 ticks the compiler worked out on its own, where it used to pass
250 microseconds to a helper that divided by 100 at runtime.  For a loop
calling k_msleep(100), k_sleep(K_SECONDS(1)) and k_usleep(250) without
using the results, FLASH drops from 11028 to 10600 bytes.

No trace point is emitted here.  The existing sleep hooks take a duration
in milliseconds or microseconds, which no longer describes what this
function is handed, and tracing cannot live in the inlines either: every
tracing backend header includes kernel.h, so a translation unit reaching a
backend header first would expand SYS_PORT_TRACING_* before those macros
exist.  The following commit gives k_sleep_ticks() a hook of its own.

The duration goes through Z_TIMEOUT_US() rather than an open coded
conversion.  That clamps a negative argument to zero, which k_usleep()
never did: it used to truncate the 64 bit conversion into an int32_t
first, which hid the worst of it, and passing it through whole would turn a
negative duration into a sleep of roughly 1.8e17 ticks rather than a bogus
absolute deadline.  The macro also carries the cast to k_ticks_t that C++
needs, since Z_TIMEOUT_TICKS_INIT() is a braced initializer there and an
unsigned to signed conversion inside one is a narrowing error.

This also removes a potential link error.  k_usleep() had no
implementation at all with CONFIG_MULTITHREADING=n, since nothread.c only
ever provided z_impl_k_sleep(), so any caller failed to link.  Nothing in
the tree happens to call it in that configuration, which is presumably why
it went unnoticed; a single z_impl_k_sleep_ticks() now serves both.

Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
2026-08-20 08:52:31 +02:00
Nicolas Pitre
6484418a3a kernel: move the sleep API declarations to their own header
k_sleep(), k_msleep() and k_usleep() are declared in kernel.h today.
Later commits grow that API with a tick based primitive plus inline unit
conversions, which is more than kernel.h ought to carry for a single
service.

Move the three declarations verbatim into a new include/zephyr/sleep.h
and have kernel.h include it, so existing users need no change. The new
header has to be registered with zephyr_syscall_header(), otherwise the
marshalling stubs for k_sleep() and k_usleep() stop being generated and
CONFIG_USERSPACE builds fail to find k_sleep_mrsh.c.

The unit_testing platform fabricates empty stand ins for the generated
syscall headers rather than running the generator, so sleep.h has to be
added to that list too.  Without it any unit test reaching kernel.h fails
to find zephyr/syscalls/sleep.h.

The sleep syscalls also have to be excluded from the automatic syscall
tracing in gen_syscalls.py, as kernel.h already is.  They carry hand
written trace points in kernel/sleep.c, and without the exclusion the
generated wrapper would wrap every call in a second set.

No functional change. A test application built for nucleo_f030r8 comes
out byte identical, at 10952 bytes of FLASH before and after.

Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
2026-08-20 08:52:31 +02:00
Yiren Guo
470f468760 kernel: thread_entry: fix include for TLS stack canaries
sys_rand_get() is used to initialize __stack_chk_guard under
CONFIG_STACK_CANARIES_TLS, but <zephyr/random/random.h> was included
under CONFIG_CURRENT_THREAD_USE_TLS. Builds fail when
STACK_CANARIES_TLS=y and CURRENT_THREAD_USE_TLS=n. Also fix the
mismatched endif comment.

Signed-off-by: Yiren Guo <guoyr_2013@hotmail.com>
2026-08-19 18:41:05 -04:00
Yiren Guo
279f7fc171 kernel: usage: fix unused-variable warning when THREAD_USAGE_ALL=n
With CONFIG_SCHED_THREAD_USAGE_ANALYSIS=y and
CONFIG_SCHED_THREAD_USAGE_ALL=n, sched_cpu_update_usage() is a no-op
macro, so the cycles local in k_thread_runtime_stats_enable() and
z_thread_stats_reset() is set but never read, triggering a compiler
warning. Pass the expression straight to the macro to keep
that configuration warning-free.

Signed-off-by: Yiren Guo <guoyr_2013@hotmail.com>
2026-08-19 17:12:24 +01:00
Nicolas Pitre
46f25cffc5 sys: printk: stop locking once a fatal error is being reported
printk_unlocked() serves callers that know they cannot lock, not the ones
that find out too late. A fault taken inside printk() leaves the spinlock
held by a context about to die, so every later printk() blocks and the
crash report is lost along with everything after it. CONFIG_SPIN_VALIDATE
makes it louder rather than better: validation fails, the assertion is
reported through printk, and the system spins there repeating itself.
That happens on a uniprocessor too, where the lock is uncontended but
still recorded as held.

Converting call sites cannot fix it, because code reached after the
failure does not know it is in a crash. So make printk() itself aware:
printk_panic() switches it to the unlocked path and the reporting paths
call it before emitting anything.

The switch is one way. Clearing it would also require releasing the
orphaned lock, and telling "orphaned" from "held by a CPU that is still
running" needs the owner, which only CONFIG_SPIN_VALIDATE records. So a
system that has reported a fatal error keeps unserialized output for the
rest of its life, which costs interleaving and no content.

Linux does the same: bust_spinlocks(), called from its oops and panic
paths, raises oops_in_progress so printk skips console locking. This
mechanism is narrower, printk simply stops locking, but the reasoning is
identical.

Because it cannot be undone, it must only be thrown once the fault is
terminal, which rules out the architecture entry points: several return.
z_arm64_fatal_error() resumes once demand paging has serviced the fault,
so switching there would cost a paging system its printk locking on the
first page fault. EXCEPTION_DUMP() runs only after the recoverable cases
are ruled out and also covers arch-specific dumps such as the Cortex-M
one behind PR_FAULT_INFO, and z_fatal_error() covers reports with no
dump, like k_panic() from a failed assertion. OpenRISC switches at entry
because it reports with LOG_ERR(), which is safe there since its handler
never returns.

k_str_out() shares the lock and honours the switch, so crashes reported
through printf() or puts() are covered too.

Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
2026-08-19 17:09:07 +01:00
Peter Mitsis
4395894020 kernel: Fix race in mbox_message_dispose()
The internal kernel routine mbox_message_dispose() was non-atomically
modifying the internal thread fields 'thread_state'. To correct this,
_sched_spinlock must be held to prevent corruption of this field from
either an ISR or another CPU acting upon the thread.

Signed-off-by: Peter Mitsis <peter.mitsis@intel.com>
2026-08-18 20:22:32 -04:00
Peter Mitsis
cbc956aa64 kernel: mailbox code to use z_sched_waitq_walk()
The mailbox code must search the waiting threads for a matching
message. Prior to this, it was doing so the using _WAIT_Q_FOR_EACH()
macro while holding the mailbox' spinlock. That pattern, however,
does not provide sufficient protection on an SMP system as another
CPU could process a timer that expires one of those waiting threads
thereby unexpectedly mutating the wait queue during the search. This
in turn could cause corruption and a crash.

To work around this, z_sched_waitq_walk() must be used to iterate
through the wait queue to search for and subsequently act upon
a matching message.

Note: z_sched_waitq_walk() locks _sched_spinlock for the duration of
the search. Consequently, if a thread expiration were to occur during
the search, it would spin in z_thread_timeout() until it wins
_sched_spinlock (after the search is complete).

Fixes #111643

Signed-off-by: Peter Mitsis <peter.mitsis@intel.com>
2026-08-18 20:22:32 -04:00
Peter Mitsis
4a767996eb kernel: mailbox code to use is_thread_dummy()
The mailbox code no longer reaches deep into the thread structure
to determine if a thread is a dummy thread. The kernel has an
existing helper routine called 'is_thread_dummy()'. Use that instead.

Signed-off-by: Peter Mitsis <peter.mitsis@intel.com>
2026-08-18 20:22:32 -04:00
Peter Mitsis
b6bfe9fc6a kernel: Update z_sched_waitq_walk() warning
Updates the z_sched_waitq_walk() documentation to indicate that the
the walk_func callback may safefly remove the thread identified by
the callback's argument from the wait queue on the final iteration.

Signed-off-by: Peter Mitsis <peter.mitsis@intel.com>
2026-08-18 20:22:32 -04:00
Mayur Salve
1b60add1ac kernel: mutex: fix priority inheritance with multiple held mutexes
The existing implementation unconditionally restores owner_orig_prio on
unlock, ignoring other held mutexes that still have high-priority waiters.
This causes incorrect priority restoration in nested mutex scenarios and
requires mutexes to be released in strict reverse acquisition order.

Additionally, priority boosts were not propagated through ownership chains
when the mutex owner was itself blocked on another mutex.

This change adds per-thread held_mutexes tracking and mutex_pended_on
pointer to enable:
- Correct priority recalculation on unlock by scanning all remaining held
  mutexes
- Chained priority inheritance through the full ownership chain
- Deadlock detection: assert on K_FOREVER circular ownership where
  every cycle member also waits forever; bounded chain walk prevents
  livelock on cycles not involving the current thread
- Per-thread orig_prio field records true pre-inheritance priority,
  fixing priority floor when mutexes are released in non-LIFO order

struct k_thread grows by three pointers plus a byte in default builds
(held_mutexes, mutex_pended_on, orig_prio).

Signed-off-by: Mayur Salve <msalve@qti.qualcomm.com>
2026-08-18 17:19:28 -04:00
Emil Hammarström
40b8ee1f11 kernel: Remove redundant K_FOREVER timeout check from thread schedule
Calling thread_schedule_new with a timeout not equal to K_NO_WAIT will
result in a z_add_timeout call, in the much common configuration
CONFIG_SYS_CLOCK_EXISTS=y, which returns early on K_FOREVER making the
compare redundant.

When !CONFIG_SYS_CLOCK_EXISTS the behavior is kept such that a timeout
value of K_FOREVER still results in a nop.

Signed-off-by: Emil Hammarström <emil.a.hammarstrom@gmail.com>
2026-08-17 14:16:59 +02:00
Anas Nashif
1583ed5a4b kernel: mmu: name parameter in virt_region_foreach
MISRA C:2012 Rule 8.2 requires every parameter in a function type to be
named.

Signed-off-by: Anas Nashif <anas.nashif@intel.com>
2026-08-17 10:26:20 +02:00
Anas Nashif
f22b738c3b kernel: init: name the main() parameters
MISRA C:2012 Rule 8.2 requires every parameter in a function type to be
named. The local prototype for main() used when CONFIG_BOOTARGS is
enabled declared its two parameters with bare types.

Declaration only, no functional change.

Signed-off-by: Anas Nashif <anas.nashif@intel.com>
2026-08-17 10:26:20 +02:00
Anas Nashif
8742067a7a kernel: obj_core: name the walk callback parameters
MISRA C:2012 Rule 8.2 requires every parameter in a function type to be
named, and that includes definitions, not just declarations. The two
object core walk functions were declared with named callback parameters
but still defined with unnamed ones.

Use the same names as the header so declaration and definition agree.
No functional change.

Signed-off-by: Anas Nashif <anas.nashif@intel.com>
2026-08-17 10:26:20 +02:00
Anas Nashif
5058917ea6 kernel: thread: validate cpu in k_thread_runtime_stats_cpu_get()
The non-SMP branch only asserted that cpu is 0 and silently
returned CPU 0 statistics for any out-of-range value with
CONFIG_ASSERT=n. The SMP branch had no validation at all and
passed the value through to z_sched_cpu_usage(), indexing the
per-CPU array out of bounds.

Validate cpu against arch_num_cpus() with CHECKIF() returning
-EINVAL, consistent with the existing NULL check for stats, and
unify the SMP and non-SMP branches since arch_num_cpus() is 1 in
the latter case.

Assisted-by: Claude:claude-fable-5
Signed-off-by: Anas Nashif <anas.nashif@intel.com>
2026-08-15 15:03:10 -04:00
Anas Nashif
ef674b52f8 kernel: mmu: handle demand paging failures at runtime
Several demand paging failure conditions were only caught by
assertions, although they are reachable at runtime in a correct
program and were silently ignored with CONFIG_ASSERT=n:

- k_mem_paging_eviction_select() returning NULL (all evictable
  page frames pinned or busy) in map_anon_page() and
  do_page_fault() led to a NULL dereference. Return -ENOMEM from
  map_anon_page() and fail the fault in do_page_fault().

- page_frame_prepare_locked() failing with -ENOMEM (backing store
  full) in do_page_fault() continued with an unprepared page frame
  and garbage page-out location. Fail the fault instead, matching
  the handling map_anon_page() and do_mem_evict() already have.

- do_page_in()/do_mem_pin() ignored a false return from
  do_page_fault() (unmapped address, and now also paging resource
  exhaustion). k_mem_page_in()/k_mem_pin() return void, so the
  caller would continue believing memory is resident/pinned and
  the failure would surface at an arbitrary later access, possibly
  from a context that cannot handle a page fault. Log an error and
  panic instead.

Also drop a tautological assertion in do_mem_evict() that was
only reachable when its condition was already true.

Failed page faults are reported as fatal errors by the arch fault
handler, as already done for ARCH_PAGE_LOCATION_BAD.

Assisted-by: Claude:claude-fable-5
Signed-off-by: Anas Nashif <anas.nashif@intel.com>
2026-08-15 15:03:10 -04:00
Yiren Guo
fc7a8936a4 kernel: usage: fix double-count in k_thread_runtime_stats_disable()
Disabling stats on the current thread accounts the in-progress window
into the CPU stats but forgets to update cpu->usage0. The next
z_sched_usage_stop() recomputes the same window and adds it again.

Signed-off-by: Yiren Guo <guoyr_2013@hotmail.com>
2026-08-15 08:11:37 -04:00
Anas Nashif
7170b2dba2 kernel: fatal: use EXCEPTION_DUMP in fatal error handler
If logging is disabled, we want to get the same exception and
information, right now half of the information is being dropped as they
go through LOG_ERR only while the rest go via EXCEPTION_DUMP/printk.

Signed-off-by: Anas Nashif <anas.nashif@intel.com>
2026-08-14 15:13:19 +02:00
Anas Nashif
32c0ba4c7e Revert "kernel: move the sleep API declarations to their own header"
This reverts commit 274d67b107.

Signed-off-by: Anas Nashif <anas.nashif@intel.com>
2026-08-13 17:48:21 -04:00
Anas Nashif
2dd9f5f414 Revert "kernel: inline k_sleep() and k_usleep() over a tick primitive"
This reverts commit d38477cdf6.

Signed-off-by: Anas Nashif <anas.nashif@intel.com>
2026-08-13 17:48:21 -04:00
Nicolas Pitre
d38477cdf6 kernel: inline k_sleep() and k_usleep() over a tick primitive
k_sleep() and k_usleep() resolve to an out of line implementation living in
another translation unit, a system call under CONFIG_USERSPACE and a plain
call otherwise.  Either way the compiler sees neither whether the requested
duration is a constant nor whether the caller cares about the returned
value, so it always emits the tick to millisecond and microsecond
conversions.  Those conversions are the only thing that drags the 64 bit
division helper into many small builds: CONFIG_SYS_CLOCK_TICKS_PER_SEC
defaults to 10000 on tickless platforms, which lands in the integer
division path and divides a 64 bit value by ten, something GCC will not
strength reduce on a 32 bit target.

Promote the former z_tick_sleep() helper to a k_sleep_ticks() system call
that reports the remaining time in ticks, and rebuild k_sleep() and
k_usleep() as inlines on top of it.  The conversions now live at the call
site where the compiler can fold or discard them.  Nearly every caller
discards them: of the 4036 sleep call sites in the tree, exactly six use
the returned value, and only three of those are outside of tests.

What this removes is best seen in the two out of line entry points that
disappear, which on a nucleo_f030r8 (Cortex-M0, 10000 ticks/s) were the
only two callers of the 64 bit division helper in the whole image:

  08002594 <z_impl_k_sleep>:
        bl      8001... <z_tick_sleep>
        ...
        movs    r0, #9            /* the ceil() bias, 10 - 1 */
        adds    r0, r0, r2
        adcs    r1, r3
        movs    r2, #10           /* ticks / 10 -> milliseconds */
        bl      8000180 <__aeabi_uldivmod>

  080025c0 <z_impl_k_usleep>:
        movs    r0, #99           /* the ceil() bias, 100 - 1 */
        ...
        movs    r2, #100          /* microseconds / 100 -> ticks */
        bl      8000180 <__aeabi_uldivmod>
        bl      8001... <z_tick_sleep>

Both are gone, and so are __aeabi_uldivmod and __udivmoddi4, which are no
longer referenced anywhere.  A k_usleep(250) call site now passes the
literal 3 ticks the compiler worked out on its own, where it used to pass
250 microseconds to a helper that divided by 100 at runtime.  For a loop
calling k_msleep(100), k_sleep(K_SECONDS(1)) and k_usleep(250) without
using the results, FLASH drops from 11028 to 10600 bytes.

Tracing stays in the out of line implementation.  It cannot move into the
inlines because every tracing backend header includes kernel.h, so a
translation unit that reaches a backend header first would expand
SYS_PORT_TRACING_* before those macros exist.  A consequence is that the
sleep_exit hook now reports ticks rather than milliseconds and the usleep
hook is no longer emitted; both are covered in a following commit.

The microsecond duration is clamped to zero the way Z_TIMEOUT_US() already
does.  k_usleep() never did that, but it used to truncate the 64 bit
conversion into an int32_t before handing it over, which hid the worst of
it.
Passing the conversion through whole would turn a negative duration into a
sleep of roughly 1.8e17 ticks rather than a bogus absolute deadline.

This also removes a potential link error.  k_usleep() had no
implementation at all with CONFIG_MULTITHREADING=n, since nothread.c only
ever provided z_impl_k_sleep(), so any caller failed to link.  Nothing in
the tree happens to call it in that configuration, which is presumably why
it went unnoticed; a single z_impl_k_sleep_ticks() now serves both.

Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
2026-08-13 16:37:05 -04:00
Nicolas Pitre
274d67b107 kernel: move the sleep API declarations to their own header
k_sleep(), k_msleep() and k_usleep() are declared in kernel.h today.
Later commits grow that API with a tick based primitive plus inline unit
conversions, which is more than kernel.h ought to carry for a single
service.

Move the three declarations verbatim into a new include/zephyr/sleep.h
and have kernel.h include it, so existing users need no change. The new
header has to be registered with zephyr_syscall_header(), otherwise the
marshalling stubs for k_sleep() and k_usleep() stop being generated and
CONFIG_USERSPACE builds fail to find k_sleep_mrsh.c.

No functional change. A test application built for nucleo_f030r8 comes
out byte identical, at 11028 bytes of FLASH before and after.

Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
2026-08-13 16:37:05 -04:00
Nicolas Pitre
51b33f884a kernel: timeout: report the no-deadline case from the idle path
The idle path asks this for the time until the next wakeup, and gets a
tick count that never says "there is nothing to wake up for": an empty
timeout list is reported as the capped announce budget, exactly like a
deadline further out than can be programmed in one step. The power
management code cannot then tell the two apart, so it arms the timer in
both cases and a system with sloppy idle enabled keeps waking up for
nothing.

Make the same decision reprogram_next() makes. With
CONFIG_SYSTEM_CLOCK_SLOPPY_IDLE allowing the uptime to drift, an empty
list is reported as K_TICKS_FOREVER; anything else is a wait, whether a
real deadline or the synthetic one that keeps the announce range
covered. Without sloppy idle the empty case stays a wait, so the timer
remains armed and timekeeping is unaffected.

The return type becomes unsigned to match the tick type used throughout
the timer interface. The conversion at the only caller, in the idle
path, is value preserving in both directions: every wait is capped at
SYS_CLOCK_MAX_WAIT, which is INT32_MAX, and K_TICKS_FOREVER is the same
value read either way. Nothing outside the kernel sees the change; the
power management API keeps its signed tick counts.

Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
2026-08-12 19:27:28 -04:00
Nicolas Pitre
360f4fb1fd kernel: timeout: add sys_clock_no_timeout() for the empty timeout list
An empty timeout list normally still gets the driver a wakeup request.
That is a synthetic timeout: nothing is waiting for it, it is there to
keep the announce baseline moving so uptime stays correct.
CONFIG_SYSTEM_CLOCK_SLOPPY_IDLE is the permission to skip it, which is
why an empty list only becomes visible to a driver when that option is
set, and today it becomes visible as a tick value the driver has to
recognise rather than as a condition of its own.

Add a weak sys_clock_no_timeout() hook, called in place of
sys_clock_set_timeout() when the list is empty and sloppy idle allows the
uptime to drift. Its default asks sys_clock_set_timeout() for UINT32_MAX
ticks, which is what K_TICKS_FOREVER is in the unsigned tick domain this
interface now uses, so an out-of-tree driver that has not migrated still
sees the "no deadline" value it always did. What gets deprecated is the
special meaning, not the call.

next_timeout() no longer decides sloppy idle, so its empty-list and
far-timeout arms collapse into one capped budget. The far-timeout arm no
longer stops a tick short of the cap either: it only did so to stay
distinguishable from the empty case, which now travels out of band.

Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
2026-08-12 19:27:28 -04:00
Gustav Holmberg
8483d28b42 toolchain: fix deprecation warning for iar
In commit 4f9df472fc1d06a6deeb7dddf6ab167c7cba984f
TOOLCHAIN_DISABLE_WARNING with a hard coded argument in work.c. This
created warnings when using the iar toolchain. Fix it by using a
preprocessor macro.

Signed-off-by: Gustav Holmberg <gustav.holmberg@qt.io>
2026-08-12 13:11:27 -04:00
Anas Nashif
5c12262de7 kernel: kernel_offsets: put the include guard before the includes
kernel_offsets.h pulls in three headers before defining its own
include guard, so the guard is not the first thing in the file as
MISRA C:2012 Directive 4.10 requires.

Move the guard above the includes.  The header is still only used by
the offsets generator, and the includes stay inside the guard.

Signed-off-by: Anas Nashif <anas.nashif@intel.com>
2026-08-11 17:09:37 -04:00
Anas Nashif
e84e2f7955 kernel: rename the reserved 'exit' labels to 'out'
'exit' is reserved by the C standard for any use, so using it as a
label violates MISRA C:2012 Rule 21.2.  Rename the labels in the
message queue and pipe implementations to 'out', which is the spelling
already used elsewhere in the kernel.

Pure rename, no functional change.

Signed-off-by: Anas Nashif <anas.nashif@intel.com>
2026-08-11 17:08:24 -04:00
Anas Nashif
7a72151634 kernel: smp: replace SMP_BOOT_DELAY with per-CPU devicetree deferral
CONFIG_SMP_BOOT_DELAY was a global, application-level switch that made
the kernel skip starting every secondary CPU at boot, used in-tree only
by two tests and in practice by one platform class (intel_adsp, where
the host or PM policy brings DSP cores up on demand). Boot topology is
a hardware/platform property, and all-or-nothing is needlessly coarse.

Replace it with a per-CPU devicetree flag, zephyr,deferred-start, on
the /cpus children (mirroring zephyr,deferred-init for devices):
z_smp_init() now always runs and simply skips flagged CPUs, which are
brought up at run time with the existing k_smp_cpu_start() (or
k_smp_cpu_resume()). Deferral is per CPU, so asymmetric bring-up
(start some cores at boot, defer others) is now expressible, and the
special-case branch disappears from the boot path.

The flag is declared in the common cpu.yaml binding. The lookup uses
DT_PROP_OR() so cpu nodes whose binding does not cover the property
simply cannot be deferred rather than breaking the build; a binding
for the intel,x86_64 compatible used by qemu_x86_64's cpu nodes was
missing entirely and is added.

The two users are converted: tests/kernel/multiprocessing/
smp_boot_delay marks the secondary CPUs in per-board overlays (both
tests pass on qemu_x86_64) and tests/boards/intel_adsp/smoke gains
overlays for its four platforms (all build). Normal SMP boot is
unaffected (verified on qemu_x86_64, all CPUs online).

Out-of-tree users migrate by dropping CONFIG_SMP_BOOT_DELAY=y and
adding zephyr,deferred-start to the deferred cpu nodes in their board
overlay.

Assisted-by: Claude:claude-fable-5
Signed-off-by: Anas Nashif <anas.nashif@intel.com>
2026-08-11 17:01:49 -04:00
Tim Pambor
e1b4cf8615 kernel: Update CONFIG_SWITCH workaround for clang
Clang (pre-v20) enables frame pointers at all optimization levels,
unlike gcc which only enables them only at -O0. This causes the
same r7 clobber issue in arch_switch inline assembly as for GCC,
if CONFIG_SWITCH=y.

Extend the -fomit-frame-pointer workaround to apply unconditionally
for clang and also add sleep.c and thread.c which also started to
need the flag since the workaround was added.

Signed-off-by: Tim Pambor <tim.pambor@codewrights.de>
2026-08-11 13:45:59 -04:00
Tim Pambor
6527ead56b kernel: format CMakeLists.txt
Format CMakeLists.txt according to CMake Style Guidelines.

Signed-off-by: Tim Pambor <tim.pambor@codewrights.de>
2026-08-11 13:45:59 -04:00
Anas Nashif
1036694889 kernel: device: restrict the device_deinit syscall to driver objects
z_vrfy_device_deinit() validated its argument with K_OBJ_ANY, so any kernel
object the calling thread has access to could be passed as a struct device.
z_impl_device_deinit() then calls dev->ops.deinit(dev), an indirect call
through a function pointer read out of the confused object, giving user
mode an arbitrary call primitive when CONFIG_DEVICE_DEINIT_SUPPORT=y.

Use K_OBJ_DRIVER_ANY, matching z_vrfy_device_init() and
z_vrfy_device_is_ready().

Signed-off-by: Anas Nashif <anas.nashif@intel.com>
2026-08-10 09:14:56 -07:00
Anas Nashif
85c1c4c219 kernel: userspace: reject size overflow in dynamic object allocation
dynamic_object_create() computed the allocation size as
obj_size_get(otype) + size, where size comes straight from user mode via
the k_object_alloc_size() syscall - the verifier is a bare pass-through and
z_object_alloc() only range-checks otype. A size close to SIZE_MAX wraps,
so the allocation is small while the object is tagged with the requested
type; the matching init syscall then writes a full object over it. The
K_OBJ_THREAD_STACK_ELEMENT branch has the same problem through
STACK_ELEMENT_DATA_SIZE(), which rounds up and adds overhead.

Reject both overflows and free the descriptor.

Signed-off-by: Anas Nashif <anas.nashif@intel.com>
2026-08-10 09:14:40 -07:00
Peter Mitsis
7d4140aee7 kernel: Streamline k_work_submit() tracing
Updates k_work_submit() to use z_work_submit_to_queue() instead of
k_work_submit_to_queue() to remove superfluous tracing calls.

Signed-off-by: Peter Mitsis <peter.mitsis@intel.com>
2026-08-04 06:53:32 -04:00