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 <zephyr/kernel.h>
17 #include <zephyr/kernel_structs.h>
18 #include "posix_core.h"
19 #include <zephyr/irq.h>
20 #include "kswap.h"
21 #include <zephyr/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 running 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 		_kernel.idle = 0;
115 		z_pm_save_idle_exit();
116 	}
117 }
118 #endif
119