zephyr/kernel/include/kswap.h

266 lines
7.6 KiB
C
Raw Permalink Normal View History

/*
* Copyright (c) 2018 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_KERNEL_INCLUDE_KSWAP_H_
#define ZEPHYR_KERNEL_INCLUDE_KSWAP_H_
#include <ksched.h>
#include <zephyr/spinlock.h>
#include <zephyr/sys/barrier.h>
#include <kernel_arch_func.h>
#ifdef CONFIG_STACK_SENTINEL
extern void z_check_stack_sentinel(void);
#else
#define z_check_stack_sentinel() /**/
#endif /* CONFIG_STACK_SENTINEL */
extern struct k_spinlock _sched_spinlock;
kernel: Rework SMP irq_lock() compatibility layer This was wrong in two ways, one subtle and one awful. The subtle problem was that the IRQ lock isn't actually globally recursive, it gets reset when you context switch (i.e. a _Swap() implicitly releases and reacquires it). So the recursive count I was keeping needs to be per-thread or else we risk deadlock any time we swap away from a thread holding the lock. And because part of my brain apparently knew this, there was an "optimization" in the code that tested the current count vs. zero outside the lock, on the argument that if it was non-zero we must already hold the lock. Which would be true of a per-thread counter, but NOT a global one: the other CPU may be holding that lock, and this test will tell you *you* do. The upshot is that a recursive irq_lock() would almost always SUCCEED INCORRECTLY when there was lock contention. That this didn't break more things is amazing to me. The rework is actually simpler than the original, thankfully. Though there are some further subtleties: * The lock state implied by irq_lock() allows the lock to be implicitly released on context switch (i.e. you can _Swap() with the lock held at a recursion level higher than 1, which needs to allow other processes to run). So return paths into threads from _Swap() and interrupt/exception exit need to check and restore the global lock state, spinning as needed. * The idle loop design specifies a k_cpu_idle() function that is on common architectures expected to enable interrupts (for obvious reasons), but there is no place to put non-arch code to wire it into the global lock accounting. So on SMP, even CPU0 needs to use the "dumb" spinning idle loop. Finally this patch contains a simple bugfix too, found by inspection: the interrupt return code used when CONFIG_SWITCH is enabled wasn't correctly setting the active flag on the threads, opening up the potential for a race that might result in a thread being scheduled on two CPUs simultaneously. Signed-off-by: Andy Ross <andrew.j.ross@intel.com>
2018-04-12 21:50:05 +02:00
/* In SMP, the irq_lock() is a spinlock which is implicitly released
* and reacquired on context switch to preserve the existing
* semantics. This means that whenever we are about to return to a
* thread (via either z_swap() or interrupt/exception return!) we need
kernel: Rework SMP irq_lock() compatibility layer This was wrong in two ways, one subtle and one awful. The subtle problem was that the IRQ lock isn't actually globally recursive, it gets reset when you context switch (i.e. a _Swap() implicitly releases and reacquires it). So the recursive count I was keeping needs to be per-thread or else we risk deadlock any time we swap away from a thread holding the lock. And because part of my brain apparently knew this, there was an "optimization" in the code that tested the current count vs. zero outside the lock, on the argument that if it was non-zero we must already hold the lock. Which would be true of a per-thread counter, but NOT a global one: the other CPU may be holding that lock, and this test will tell you *you* do. The upshot is that a recursive irq_lock() would almost always SUCCEED INCORRECTLY when there was lock contention. That this didn't break more things is amazing to me. The rework is actually simpler than the original, thankfully. Though there are some further subtleties: * The lock state implied by irq_lock() allows the lock to be implicitly released on context switch (i.e. you can _Swap() with the lock held at a recursion level higher than 1, which needs to allow other processes to run). So return paths into threads from _Swap() and interrupt/exception exit need to check and restore the global lock state, spinning as needed. * The idle loop design specifies a k_cpu_idle() function that is on common architectures expected to enable interrupts (for obvious reasons), but there is no place to put non-arch code to wire it into the global lock accounting. So on SMP, even CPU0 needs to use the "dumb" spinning idle loop. Finally this patch contains a simple bugfix too, found by inspection: the interrupt return code used when CONFIG_SWITCH is enabled wasn't correctly setting the active flag on the threads, opening up the potential for a race that might result in a thread being scheduled on two CPUs simultaneously. Signed-off-by: Andy Ross <andrew.j.ross@intel.com>
2018-04-12 21:50:05 +02:00
* to restore the lock state to whatever the thread's counter
* expects.
*/
void z_smp_release_global_lock(struct k_thread *thread);
kernel: Rework SMP irq_lock() compatibility layer This was wrong in two ways, one subtle and one awful. The subtle problem was that the IRQ lock isn't actually globally recursive, it gets reset when you context switch (i.e. a _Swap() implicitly releases and reacquires it). So the recursive count I was keeping needs to be per-thread or else we risk deadlock any time we swap away from a thread holding the lock. And because part of my brain apparently knew this, there was an "optimization" in the code that tested the current count vs. zero outside the lock, on the argument that if it was non-zero we must already hold the lock. Which would be true of a per-thread counter, but NOT a global one: the other CPU may be holding that lock, and this test will tell you *you* do. The upshot is that a recursive irq_lock() would almost always SUCCEED INCORRECTLY when there was lock contention. That this didn't break more things is amazing to me. The rework is actually simpler than the original, thankfully. Though there are some further subtleties: * The lock state implied by irq_lock() allows the lock to be implicitly released on context switch (i.e. you can _Swap() with the lock held at a recursion level higher than 1, which needs to allow other processes to run). So return paths into threads from _Swap() and interrupt/exception exit need to check and restore the global lock state, spinning as needed. * The idle loop design specifies a k_cpu_idle() function that is on common architectures expected to enable interrupts (for obvious reasons), but there is no place to put non-arch code to wire it into the global lock accounting. So on SMP, even CPU0 needs to use the "dumb" spinning idle loop. Finally this patch contains a simple bugfix too, found by inspection: the interrupt return code used when CONFIG_SWITCH is enabled wasn't correctly setting the active flag on the threads, opening up the potential for a race that might result in a thread being scheduled on two CPUs simultaneously. Signed-off-by: Andy Ross <andrew.j.ross@intel.com>
2018-04-12 21:50:05 +02:00
/* context switching and scheduling-related routines */
#ifdef CONFIG_USE_SWITCH
/* Spin, with the scheduler lock held (!), on a thread that is known
* (!!) to have released the lock and be on a path where it will
* deterministically (!!!) reach arch_switch() in very small constant
* time.
*
* This exists to treat an unavoidable SMP race when threads swap --
* their thread record is in the queue (and visible to other CPUs)
* before arch_switch() finishes saving state. We must spin for the
* switch handle before entering a new thread. See docs on
* arch_switch().
*
* Stated differently: there's a chicken and egg bug with the question
* of "is a thread running or not?". The thread needs to mark itself
* "not running" from its own context, but at that moment it obviously
* is still running until it reaches arch_switch()! Locking can't
* treat this because the scheduler lock can't be released by the
* switched-to thread, which is going to (obviously) be running its
* own code and doesn't know it was switched out.
*/
static inline void z_sched_switch_spin(struct k_thread *thread)
{
#ifdef CONFIG_SMP
volatile void **shp = (void *)&thread->switch_handle;
while (*shp == NULL) {
arch_spin_relax();
}
/* Read barrier: don't allow any subsequent loads in the
* calling code to reorder before we saw switch_handle go
* non-null.
*/
barrier_dmem_fence_full();
#endif /* CONFIG_SMP */
}
/* New style context switching. arch_switch() is a lower level
* primitive that doesn't know about the scheduler or return value.
* Needed for SMP, where the scheduler requires spinlocking that we
* don't want to have to do in per-architecture assembly.
*
* Note that is_spinlock is a compile-time construct which will be
* optimized out when this function is expanded.
*/
static ALWAYS_INLINE unsigned int do_swap(unsigned int key,
struct k_spinlock *lock,
bool is_spinlock)
{
ARG_UNUSED(lock);
struct k_thread *new_thread, *old_thread;
#ifdef CONFIG_SPIN_VALIDATE
/* Make sure the key acts to unmask interrupts, if it doesn't,
* then we are context switching out of a nested lock
* (i.e. breaking the lock of someone up the stack) which is
* forbidden! The sole exception are dummy threads used
* during initialization (where we start with interrupts
* masked and switch away to begin scheduling) and the case of
* a dead current thread that was just aborted (where the
* damage was already done by the abort anyway).
*
* (Note that this is disabled on ARM64, where system calls
* can sometimes run with interrupts masked in ways that don't
* represent lock state. See #35307)
*/
# ifndef CONFIG_ARM64
__ASSERT(arch_irq_unlocked(key) ||
_current->base.thread_state & (_THREAD_DUMMY | _THREAD_DEAD),
"Context switching while holding lock!");
# endif /* CONFIG_ARM64 */
#endif /* CONFIG_SPIN_VALIDATE */
old_thread = _current;
z_check_stack_sentinel();
old_thread->swap_retval = -EAGAIN;
/* We always take the scheduler spinlock if we don't already
* have it. We "release" other spinlocks here. But we never
* drop the interrupt lock.
*/
if (is_spinlock && lock != NULL && lock != &_sched_spinlock) {
k_spin_release(lock);
}
if (!is_spinlock || lock != &_sched_spinlock) {
(void) k_spin_lock(&_sched_spinlock);
}
new_thread = z_swap_next_thread();
if (new_thread != old_thread) {
z_sched_usage_switch(new_thread);
#ifdef CONFIG_SMP
_current_cpu->swap_ok = 0;
new_thread->base.cpu = arch_curr_cpu()->id;
kernel: Rework SMP irq_lock() compatibility layer This was wrong in two ways, one subtle and one awful. The subtle problem was that the IRQ lock isn't actually globally recursive, it gets reset when you context switch (i.e. a _Swap() implicitly releases and reacquires it). So the recursive count I was keeping needs to be per-thread or else we risk deadlock any time we swap away from a thread holding the lock. And because part of my brain apparently knew this, there was an "optimization" in the code that tested the current count vs. zero outside the lock, on the argument that if it was non-zero we must already hold the lock. Which would be true of a per-thread counter, but NOT a global one: the other CPU may be holding that lock, and this test will tell you *you* do. The upshot is that a recursive irq_lock() would almost always SUCCEED INCORRECTLY when there was lock contention. That this didn't break more things is amazing to me. The rework is actually simpler than the original, thankfully. Though there are some further subtleties: * The lock state implied by irq_lock() allows the lock to be implicitly released on context switch (i.e. you can _Swap() with the lock held at a recursion level higher than 1, which needs to allow other processes to run). So return paths into threads from _Swap() and interrupt/exception exit need to check and restore the global lock state, spinning as needed. * The idle loop design specifies a k_cpu_idle() function that is on common architectures expected to enable interrupts (for obvious reasons), but there is no place to put non-arch code to wire it into the global lock accounting. So on SMP, even CPU0 needs to use the "dumb" spinning idle loop. Finally this patch contains a simple bugfix too, found by inspection: the interrupt return code used when CONFIG_SWITCH is enabled wasn't correctly setting the active flag on the threads, opening up the potential for a race that might result in a thread being scheduled on two CPUs simultaneously. Signed-off-by: Andy Ross <andrew.j.ross@intel.com>
2018-04-12 21:50:05 +02:00
if (!is_spinlock) {
z_smp_release_global_lock(new_thread);
}
#endif /* CONFIG_SMP */
z_thread_mark_switched_out();
z_sched_switch_spin(new_thread);
_current_cpu->current = new_thread;
#ifdef CONFIG_TIMESLICING
z_reset_time_slice(new_thread);
#endif /* CONFIG_TIMESLICING */
#ifdef CONFIG_SPIN_VALIDATE
z_spin_lock_set_owner(&_sched_spinlock);
#endif /* CONFIG_SPIN_VALIDATE */
arch_cohere_stacks(old_thread, NULL, new_thread);
kernel/sched: Fix rare SMP deadlock It was possible with pathological timing (see below) for the scheduler to pick a cycle of threads on each CPU and enter the context switch path on all of them simultaneously. Example: * CPU0 is idle, CPU1 is running thread A * CPU1 makes high priority thread B runnable * CPU1 reaches a schedule point (or returns from an interrupt) and decides to run thread B instead * CPU0 simultaneously takes its IPI and returns, selecting thread A Now both CPUs enter wait_for_switch() to spin, waiting for the context switch code on the other thread to finish and mark the thread runnable. So we have a deadlock, each CPU is spinning waiting for the other! Actually, in practice this seems not to happen on existing hardware platforms, it's only exercisable in emulation. The reason is that the hardware IPI time is much faster than the software paths required to reach a schedule point or interrupt exit, so CPU1 always selects the newly scheduled thread and no deadlock appears. I tried for a bit to make this happen with a cycle of three threads, but it's complicated to get right and I still couldn't get the timing to hit correctly. In qemu, though, the IPI is implemented as a Unix signal sent to the thread running the other CPU, which is far slower and opens the window to see this happen. The solution is simple enough: don't store the _current thread in the run queue until we are on the tail end of the context switch path, after wait_for_switch() and going to reach the end in guaranteed time. Note that this requires changing a little logic to handle the yield case: because we can no longer rely on _current's position in the run queue to suppress it, we need to do the priority comparison directly based on the existing "swap_ok" flag (which has always meant "yielded", and maybe should be renamed). Signed-off-by: Andy Ross <andrew.j.ross@intel.com>
2021-02-08 17:28:54 +01:00
#ifdef CONFIG_SMP
/* Now add _current back to the run queue, once we are
* guaranteed to reach the context switch in finite
* time. See z_sched_switch_spin().
kernel/sched: Fix rare SMP deadlock It was possible with pathological timing (see below) for the scheduler to pick a cycle of threads on each CPU and enter the context switch path on all of them simultaneously. Example: * CPU0 is idle, CPU1 is running thread A * CPU1 makes high priority thread B runnable * CPU1 reaches a schedule point (or returns from an interrupt) and decides to run thread B instead * CPU0 simultaneously takes its IPI and returns, selecting thread A Now both CPUs enter wait_for_switch() to spin, waiting for the context switch code on the other thread to finish and mark the thread runnable. So we have a deadlock, each CPU is spinning waiting for the other! Actually, in practice this seems not to happen on existing hardware platforms, it's only exercisable in emulation. The reason is that the hardware IPI time is much faster than the software paths required to reach a schedule point or interrupt exit, so CPU1 always selects the newly scheduled thread and no deadlock appears. I tried for a bit to make this happen with a cycle of three threads, but it's complicated to get right and I still couldn't get the timing to hit correctly. In qemu, though, the IPI is implemented as a Unix signal sent to the thread running the other CPU, which is far slower and opens the window to see this happen. The solution is simple enough: don't store the _current thread in the run queue until we are on the tail end of the context switch path, after wait_for_switch() and going to reach the end in guaranteed time. Note that this requires changing a little logic to handle the yield case: because we can no longer rely on _current's position in the run queue to suppress it, we need to do the priority comparison directly based on the existing "swap_ok" flag (which has always meant "yielded", and maybe should be renamed). Signed-off-by: Andy Ross <andrew.j.ross@intel.com>
2021-02-08 17:28:54 +01:00
*/
z_requeue_current(old_thread);
#endif /* CONFIG_SMP */
void *newsh = new_thread->switch_handle;
kernel/sched: Fix rare SMP deadlock It was possible with pathological timing (see below) for the scheduler to pick a cycle of threads on each CPU and enter the context switch path on all of them simultaneously. Example: * CPU0 is idle, CPU1 is running thread A * CPU1 makes high priority thread B runnable * CPU1 reaches a schedule point (or returns from an interrupt) and decides to run thread B instead * CPU0 simultaneously takes its IPI and returns, selecting thread A Now both CPUs enter wait_for_switch() to spin, waiting for the context switch code on the other thread to finish and mark the thread runnable. So we have a deadlock, each CPU is spinning waiting for the other! Actually, in practice this seems not to happen on existing hardware platforms, it's only exercisable in emulation. The reason is that the hardware IPI time is much faster than the software paths required to reach a schedule point or interrupt exit, so CPU1 always selects the newly scheduled thread and no deadlock appears. I tried for a bit to make this happen with a cycle of three threads, but it's complicated to get right and I still couldn't get the timing to hit correctly. In qemu, though, the IPI is implemented as a Unix signal sent to the thread running the other CPU, which is far slower and opens the window to see this happen. The solution is simple enough: don't store the _current thread in the run queue until we are on the tail end of the context switch path, after wait_for_switch() and going to reach the end in guaranteed time. Note that this requires changing a little logic to handle the yield case: because we can no longer rely on _current's position in the run queue to suppress it, we need to do the priority comparison directly based on the existing "swap_ok" flag (which has always meant "yielded", and maybe should be renamed). Signed-off-by: Andy Ross <andrew.j.ross@intel.com>
2021-02-08 17:28:54 +01:00
if (IS_ENABLED(CONFIG_SMP)) {
/* Active threads must have a null here. And
* it must be seen before the scheduler lock
* is released!
*/
kernel/sched: Fix rare SMP deadlock It was possible with pathological timing (see below) for the scheduler to pick a cycle of threads on each CPU and enter the context switch path on all of them simultaneously. Example: * CPU0 is idle, CPU1 is running thread A * CPU1 makes high priority thread B runnable * CPU1 reaches a schedule point (or returns from an interrupt) and decides to run thread B instead * CPU0 simultaneously takes its IPI and returns, selecting thread A Now both CPUs enter wait_for_switch() to spin, waiting for the context switch code on the other thread to finish and mark the thread runnable. So we have a deadlock, each CPU is spinning waiting for the other! Actually, in practice this seems not to happen on existing hardware platforms, it's only exercisable in emulation. The reason is that the hardware IPI time is much faster than the software paths required to reach a schedule point or interrupt exit, so CPU1 always selects the newly scheduled thread and no deadlock appears. I tried for a bit to make this happen with a cycle of three threads, but it's complicated to get right and I still couldn't get the timing to hit correctly. In qemu, though, the IPI is implemented as a Unix signal sent to the thread running the other CPU, which is far slower and opens the window to see this happen. The solution is simple enough: don't store the _current thread in the run queue until we are on the tail end of the context switch path, after wait_for_switch() and going to reach the end in guaranteed time. Note that this requires changing a little logic to handle the yield case: because we can no longer rely on _current's position in the run queue to suppress it, we need to do the priority comparison directly based on the existing "swap_ok" flag (which has always meant "yielded", and maybe should be renamed). Signed-off-by: Andy Ross <andrew.j.ross@intel.com>
2021-02-08 17:28:54 +01:00
new_thread->switch_handle = NULL;
barrier_dmem_fence_full(); /* write barrier */
kernel/sched: Fix rare SMP deadlock It was possible with pathological timing (see below) for the scheduler to pick a cycle of threads on each CPU and enter the context switch path on all of them simultaneously. Example: * CPU0 is idle, CPU1 is running thread A * CPU1 makes high priority thread B runnable * CPU1 reaches a schedule point (or returns from an interrupt) and decides to run thread B instead * CPU0 simultaneously takes its IPI and returns, selecting thread A Now both CPUs enter wait_for_switch() to spin, waiting for the context switch code on the other thread to finish and mark the thread runnable. So we have a deadlock, each CPU is spinning waiting for the other! Actually, in practice this seems not to happen on existing hardware platforms, it's only exercisable in emulation. The reason is that the hardware IPI time is much faster than the software paths required to reach a schedule point or interrupt exit, so CPU1 always selects the newly scheduled thread and no deadlock appears. I tried for a bit to make this happen with a cycle of three threads, but it's complicated to get right and I still couldn't get the timing to hit correctly. In qemu, though, the IPI is implemented as a Unix signal sent to the thread running the other CPU, which is far slower and opens the window to see this happen. The solution is simple enough: don't store the _current thread in the run queue until we are on the tail end of the context switch path, after wait_for_switch() and going to reach the end in guaranteed time. Note that this requires changing a little logic to handle the yield case: because we can no longer rely on _current's position in the run queue to suppress it, we need to do the priority comparison directly based on the existing "swap_ok" flag (which has always meant "yielded", and maybe should be renamed). Signed-off-by: Andy Ross <andrew.j.ross@intel.com>
2021-02-08 17:28:54 +01:00
}
k_spin_release(&_sched_spinlock);
arch_switch(newsh, &old_thread->switch_handle);
} else {
k_spin_release(&_sched_spinlock);
}
if (is_spinlock) {
arch_irq_unlock(key);
} else {
irq_unlock(key);
}
return _current->swap_retval;
}
static inline int z_swap_irqlock(unsigned int key)
{
return do_swap(key, NULL, false);
}
static inline int z_swap(struct k_spinlock *lock, k_spinlock_key_t key)
{
return do_swap(key.key, lock, true);
}
static inline void z_swap_unlocked(void)
{
(void) do_swap(arch_irq_lock(), NULL, true);
}
#else /* !CONFIG_USE_SWITCH */
extern int arch_swap(unsigned int key);
static inline void z_sched_switch_spin(struct k_thread *thread)
{
ARG_UNUSED(thread);
}
static inline int z_swap_irqlock(unsigned int key)
{
int ret;
z_check_stack_sentinel();
ret = arch_swap(key);
return ret;
}
/* If !USE_SWITCH, then spinlocks are guaranteed degenerate as we
* can't be in SMP. The k_spin_release() call is just for validation
* handling.
*/
static ALWAYS_INLINE int z_swap(struct k_spinlock *lock, k_spinlock_key_t key)
{
k_spin_release(lock);
return z_swap_irqlock(key.key);
}
static inline void z_swap_unlocked(void)
{
(void) z_swap_irqlock(arch_irq_lock());
}
#endif /* !CONFIG_USE_SWITCH */
/**
* Set up a "dummy" thread, used at early initialization to launch the
* first thread on a CPU.
*
* Needs to set enough fields such that the context switching code can
* use it to properly store state, which will just be discarded.
*
* The memory of the dummy thread can be completely uninitialized.
*/
static inline void z_dummy_thread_init(struct k_thread *dummy_thread)
{
dummy_thread->base.thread_state = _THREAD_DUMMY;
#ifdef CONFIG_SCHED_CPU_MASK
dummy_thread->base.cpu_mask = -1;
#endif /* CONFIG_SCHED_CPU_MASK */
dummy_thread->base.user_options = K_ESSENTIAL;
#ifdef CONFIG_THREAD_STACK_INFO
dummy_thread->stack_info.start = 0U;
dummy_thread->stack_info.size = 0U;
#endif /* CONFIG_THREAD_STACK_INFO */
#ifdef CONFIG_USERSPACE
dummy_thread->mem_domain_info.mem_domain = &k_mem_domain_default;
#endif /* CONFIG_USERSPACE */
kernel: Introduce a way to specify minimum system heap size There are several subsystems and boards which require a relatively large system heap (used by k_malloc()) to function properly. This became even more notable with the recent introduction of the ACPICA library, which causes ACPI-using boards to require a system heap of up to several megabytes in size. Until now, subsystems and boards have tried to solve this by having Kconfig overlays which modify the default value of HEAP_MEM_POOL_SIZE. This works ok, except when applications start explicitly setting values in their prj.conf files: $ git grep CONFIG_HEAP_MEM_POOL_SIZE= tests samples|wc -l 157 The vast majority of values set by current sample or test applications is much too small for subsystems like ACPI, which results in the application not being able to run on such boards. To solve this situation, we introduce support for subsystems to specify their own custom system heap size requirement. Subsystems do this by defining Kconfig options with the prefix HEAP_MEM_POOL_ADD_SIZE_. The final value of the system heap is the sum of the custom minimum requirements, or the value existing HEAP_MEM_POOL_SIZE option, whichever is greater. We also introduce a new HEAP_MEM_POOL_IGNORE_MIN Kconfig option which applications can use to force a lower value than what subsystems have specficied, however this behavior is disabled by default. Whenever the minimum is greater than the requested value a CMake warning will be issued in the build output. This patch ends up modifying several places outside of kernel code, since the presence of the system heap is no longer detected using a non-zero CONFIG_HEAP_MEM_POOL_SIZE value, rather it's now detected using a new K_HEAP_MEM_POOL_SIZE value that's evaluated at build. Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
2023-11-29 10:22:39 +01:00
#if (K_HEAP_MEM_POOL_SIZE > 0)
k_thread_system_pool_assign(dummy_thread);
#else
dummy_thread->resource_pool = NULL;
#endif /* K_HEAP_MEM_POOL_SIZE */
#ifdef CONFIG_TIMESLICE_PER_THREAD
dummy_thread->base.slice_ticks = 0;
#endif /* CONFIG_TIMESLICE_PER_THREAD */
_current_cpu->current = dummy_thread;
}
#endif /* ZEPHYR_KERNEL_INCLUDE_KSWAP_H_ */