1 /*
2 * Copyright (c) 2010-2015 Wind River Systems, Inc.
3 * Copyright (c) 2017 Oticon A/S
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 /**
9 * @file
10 * @brief Kernel swapper code for POSIX
11 *
12 * This module implements the arch_swap() routine for the POSIX architecture.
13 *
14 */
15
16 #include "kernel.h"
17 #include <kernel_structs.h>
18 #include "posix_core.h"
19 #include "irq.h"
20 #include "kswap.h"
21 #include <pm/pm.h>
22
arch_swap(unsigned int key)23 int arch_swap(unsigned int key)
24 {
25 /*
26 * struct k_thread * _current is the currently runnig thread
27 * struct k_thread * _kernel.ready_q.cache contains the next thread to
28 * run (cannot be NULL)
29 *
30 * Here a "real" arch would save all processor registers, stack pointer
31 * and so forth. But we do not need to do so because we use posix
32 * threads => those are all nicely kept by the native OS kernel
33 */
34 #if CONFIG_INSTRUMENT_THREAD_SWITCHING
35 z_thread_mark_switched_out();
36 #endif
37 _current->callee_saved.key = key;
38 _current->callee_saved.retval = -EAGAIN;
39
40 /* retval may be modified with a call to
41 * arch_thread_return_value_set()
42 */
43
44 posix_thread_status_t *ready_thread_ptr =
45 (posix_thread_status_t *)
46 _kernel.ready_q.cache->callee_saved.thread_status;
47
48 posix_thread_status_t *this_thread_ptr =
49 (posix_thread_status_t *)
50 _current->callee_saved.thread_status;
51
52
53 _current = _kernel.ready_q.cache;
54 #if CONFIG_INSTRUMENT_THREAD_SWITCHING
55 z_thread_mark_switched_in();
56 #endif
57
58 /*
59 * Here a "real" arch would load all processor registers for the thread
60 * to run. In this arch case, we just block this thread until allowed
61 * to run later, and signal to whomever is allowed to run to
62 * continue.
63 */
64 posix_swap(ready_thread_ptr->thread_idx,
65 this_thread_ptr->thread_idx);
66
67 /* When we continue, _kernel->current points back to this thread */
68
69 irq_unlock(_current->callee_saved.key);
70
71 return _current->callee_saved.retval;
72 }
73
74
75
76 #ifdef CONFIG_ARCH_HAS_CUSTOM_SWAP_TO_MAIN
77 /* This is just a version of arch_swap() in which we do not save anything
78 * about the current thread.
79 *
80 * Note that we will never come back to this thread: posix_main_thread_start()
81 * does never return.
82 */
arch_switch_to_main_thread(struct k_thread * main_thread,char * stack_ptr,k_thread_entry_t _main)83 void arch_switch_to_main_thread(struct k_thread *main_thread, char *stack_ptr,
84 k_thread_entry_t _main)
85 {
86 ARG_UNUSED(stack_ptr);
87 ARG_UNUSED(_main);
88
89 posix_thread_status_t *ready_thread_ptr =
90 (posix_thread_status_t *)
91 _kernel.ready_q.cache->callee_saved.thread_status;
92
93 #ifdef CONFIG_INSTRUMENT_THREAD_SWITCHING
94 z_thread_mark_switched_out();
95 #endif
96
97 _current = _kernel.ready_q.cache;
98
99 #ifdef CONFIG_INSTRUMENT_THREAD_SWITCHING
100 z_thread_mark_switched_in();
101 #endif
102
103 posix_main_thread_start(ready_thread_ptr->thread_idx);
104 } /* LCOV_EXCL_LINE */
105 #endif
106
107 #ifdef CONFIG_PM
108 /**
109 * If the kernel is in idle mode, take it out
110 */
posix_irq_check_idle_exit(void)111 void posix_irq_check_idle_exit(void)
112 {
113 if (_kernel.idle) {
114 int32_t idle_val = _kernel.idle;
115
116 _kernel.idle = 0;
117 z_pm_save_idle_exit(idle_val);
118 }
119 }
120 #endif
121