1 /***************************************************************************
2 * Copyright (c) 2024 Microsoft Corporation
3 *
4 * This program and the accompanying materials are made available under the
5 * terms of the MIT License which is available at
6 * https://opensource.org/licenses/MIT.
7 *
8 * SPDX-License-Identifier: MIT
9 **************************************************************************/
10
11
12 /**************************************************************************/
13 /**************************************************************************/
14 /** */
15 /** ThreadX Component */
16 /** */
17 /** Initialize */
18 /** */
19 /**************************************************************************/
20 /**************************************************************************/
21
22
23 #define TX_SOURCE_CODE
24
25
26 /* Include necessary system files. */
27
28 #include "tx_api.h"
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <windows.h>
32 #pragma comment (lib, "Winmm.lib")
33
34 /* Define various Win32 objects used by the ThreadX port. */
35
36 TX_WIN32_CRITICAL_SECTION _tx_win32_critical_section;
37 HANDLE _tx_win32_scheduler_semaphore;
38 DWORD _tx_win32_scheduler_id;
39 ULONG _tx_win32_global_int_disabled_flag;
40 LARGE_INTEGER _tx_win32_time_stamp;
41 ULONG _tx_win32_system_error;
42 extern TX_THREAD *_tx_thread_current_ptr;
43
44
45 /* Define simulated timer interrupt. This is done inside a thread, which is
46 how other interrupts may be defined as well. See code below for an
47 example. */
48
49 UINT _tx_win32_timer_id;
50 VOID CALLBACK _tx_win32_timer_interrupt(UINT wTimerID, UINT msg, DWORD dwUser, DWORD dw1, DWORD dw2);
51
52
53 #ifdef TX_WIN32_DEBUG_ENABLE
54
55 extern ULONG _tx_thread_system_state;
56 extern UINT _tx_thread_preempt_disable;
57 extern TX_THREAD *_tx_thread_current_ptr;
58 extern TX_THREAD *_tx_thread_execute_ptr;
59
60
61 /* Define the maximum size of the Win32 debug array. */
62
63 #ifndef TX_WIN32_DEBUG_EVENT_SIZE
64 #define TX_WIN32_DEBUG_EVENT_SIZE 400
65 #endif
66
67
68 /* Define debug log in order to debug Win32 issues with this port. */
69
70 typedef struct TX_WIN32_DEBUG_ENTRY_STRUCT
71 {
72 char *tx_win32_debug_entry_action;
73 LARGE_INTEGER tx_win32_debug_entry_timestamp;
74 char *tx_win32_debug_entry_file;
75 unsigned long tx_win32_debug_entry_line;
76 TX_WIN32_CRITICAL_SECTION tx_win32_debug_entry_critical_section;
77 unsigned long tx_win32_debug_entry_int_disabled_flag;
78 ULONG tx_win32_debug_entry_system_state;
79 UINT tx_win32_debug_entry_preempt_disable;
80 TX_THREAD *tx_win32_debug_entry_current_thread;
81 DWORD tx_win32_debug_entry_current_thread_id;
82 TX_THREAD *tx_win32_debug_entry_execute_thread;
83 DWORD tx_win32_debug_entry_execute_thread_id;
84 DWORD tx_win32_debug_entry_running_id;
85 } TX_WIN32_DEBUG_ENTRY;
86
87
88 /* Define the circular array of Win32 debug entries. */
89
90 TX_WIN32_DEBUG_ENTRY _tx_win32_debug_entry_array[TX_WIN32_DEBUG_EVENT_SIZE];
91
92
93 /* Define the Win32 debug index. */
94
95 unsigned long _tx_win32_debug_entry_index = 0;
96
97
98 /* Now define the debug entry function. */
_tx_win32_debug_entry_insert(char * action,char * file,unsigned long line)99 void _tx_win32_debug_entry_insert(char *action, char *file, unsigned long line)
100 {
101
102
103 /* Get the time stamp. */
104 QueryPerformanceCounter((LARGE_INTEGER *)&_tx_win32_time_stamp);
105
106 /* Setup the debug entry. */
107 _tx_win32_debug_entry_array[_tx_win32_debug_entry_index].tx_win32_debug_entry_action = action;
108 _tx_win32_debug_entry_array[_tx_win32_debug_entry_index].tx_win32_debug_entry_timestamp = _tx_win32_time_stamp;
109 _tx_win32_debug_entry_array[_tx_win32_debug_entry_index].tx_win32_debug_entry_file = file;
110 _tx_win32_debug_entry_array[_tx_win32_debug_entry_index].tx_win32_debug_entry_line = line;
111 _tx_win32_debug_entry_array[_tx_win32_debug_entry_index].tx_win32_debug_entry_critical_section = _tx_win32_critical_section;
112 _tx_win32_debug_entry_array[_tx_win32_debug_entry_index].tx_win32_debug_entry_int_disabled_flag = _tx_win32_global_int_disabled_flag;
113 _tx_win32_debug_entry_array[_tx_win32_debug_entry_index].tx_win32_debug_entry_system_state = _tx_thread_system_state;
114 _tx_win32_debug_entry_array[_tx_win32_debug_entry_index].tx_win32_debug_entry_preempt_disable = _tx_thread_preempt_disable;
115 _tx_win32_debug_entry_array[_tx_win32_debug_entry_index].tx_win32_debug_entry_current_thread = _tx_thread_current_ptr;
116 if (_tx_thread_current_ptr)
117 _tx_win32_debug_entry_array[_tx_win32_debug_entry_index].tx_win32_debug_entry_current_thread_id = _tx_thread_current_ptr -> tx_thread_win32_thread_id;
118 else
119 _tx_win32_debug_entry_array[_tx_win32_debug_entry_index].tx_win32_debug_entry_current_thread_id = 0;
120 _tx_win32_debug_entry_array[_tx_win32_debug_entry_index].tx_win32_debug_entry_execute_thread = _tx_thread_execute_ptr;
121 if (_tx_thread_execute_ptr)
122 _tx_win32_debug_entry_array[_tx_win32_debug_entry_index].tx_win32_debug_entry_execute_thread_id = _tx_thread_execute_ptr -> tx_thread_win32_thread_id;
123 else
124 _tx_win32_debug_entry_array[_tx_win32_debug_entry_index].tx_win32_debug_entry_execute_thread_id = 0;
125 _tx_win32_debug_entry_array[_tx_win32_debug_entry_index].tx_win32_debug_entry_running_id = GetCurrentThreadId();
126
127 /* Now move to the next entry. */
128 _tx_win32_debug_entry_index++;
129
130 /* Determine if we need to wrap the list. */
131 if (_tx_win32_debug_entry_index >= TX_WIN32_DEBUG_EVENT_SIZE)
132 {
133
134 /* Yes, wrap the list! */
135 _tx_win32_debug_entry_index = 0;
136 }
137 }
138
139 #endif
140
141
142 /* Define the ThreadX timer interrupt handler. */
143
144 void _tx_timer_interrupt(void);
145
146
147 /* Define other external function references. */
148
149 VOID _tx_initialize_low_level(VOID);
150 VOID _tx_thread_context_save(VOID);
151 VOID _tx_thread_context_restore(VOID);
152
153
154 /* Define other external variable references. */
155
156 extern VOID *_tx_initialize_unused_memory;
157
158
159 /**************************************************************************/
160 /* */
161 /* FUNCTION RELEASE */
162 /* */
163 /* _tx_initialize_low_level Win32/Visual */
164 /* 6.1 */
165 /* AUTHOR */
166 /* */
167 /* William E. Lamie, Microsoft Corporation */
168 /* */
169 /* DESCRIPTION */
170 /* */
171 /* This function is responsible for any low-level processor */
172 /* initialization, including setting up interrupt vectors, setting */
173 /* up a periodic timer interrupt source, saving the system stack */
174 /* pointer for use in ISR processing later, and finding the first */
175 /* available RAM memory address for tx_application_define. */
176 /* */
177 /* INPUT */
178 /* */
179 /* None */
180 /* */
181 /* OUTPUT */
182 /* */
183 /* None */
184 /* */
185 /* CALLS */
186 /* */
187 /* CreateMutex Win32 create mutex */
188 /* CreateThread Win32 create thread */
189 /* CreateSemaphore Win32 create semaphore */
190 /* GetCurrentThreadId Win32 get current thread ID */
191 /* SetProcessAffinityMask Win32 process affinity set */
192 /* SetThreadPriority Win32 set thread priority */
193 /* */
194 /* CALLED BY */
195 /* */
196 /* _tx_initialize_kernel_enter ThreadX entry function */
197 /* */
198 /* RELEASE HISTORY */
199 /* */
200 /* DATE NAME DESCRIPTION */
201 /* */
202 /* 09-30-2020 William E. Lamie Initial Version 6.1 */
203 /* */
204 /**************************************************************************/
_tx_initialize_low_level(VOID)205 VOID _tx_initialize_low_level(VOID)
206 {
207
208 /* Deprecate TX_WIN32_MULTI_CORE build option and default to restricting
209 execution to one core. */
210
211 #ifndef TX_WIN32_BYPASS_AFFINITY_SETUP
212
213 /* Limit this ThreadX simulation on Win32 to a single core. */
214 if (SetProcessAffinityMask( GetCurrentProcess(), 1 ) == 0)
215 {
216
217 /* Error restricting the process to one core. */
218 printf("ThreadX Win32 error restricting the process to one core!\n");
219 while(1)
220 {
221 }
222 }
223 #endif
224
225 /* Pickup the first available memory address. */
226
227 /* Save the first available memory address. */
228 _tx_initialize_unused_memory = malloc(TX_WIN32_MEMORY_SIZE);
229
230 /* Pickup the unique Id of the current thread, which will also be the Id of the scheduler. */
231 _tx_win32_scheduler_id = GetCurrentThreadId();
232
233 /* Create the system critical section mutex. This is used by the system to block all other access,
234 analogous to an interrupt lockout on an embedded target. */
235 _tx_win32_critical_section.tx_win32_critical_section_mutex_handle = CreateMutex(NULL, FALSE, NULL);
236 _tx_win32_critical_section.tx_win32_critical_section_nested_count = 0;
237 _tx_win32_critical_section.tx_win32_critical_section_owner = 0;
238
239 /* Create the semaphore that regulates when the scheduler executes. */
240 _tx_win32_scheduler_semaphore = CreateSemaphore(NULL, 0, 1, NULL);
241
242 /* Initialize the global interrupt disabled flag. */
243 _tx_win32_global_int_disabled_flag = TX_FALSE;
244
245 /* Done, return to caller. */
246 }
247
248
249 /* This routine is called after initialization is complete in order to start
250 all interrupt threads. Interrupt threads in addition to the timer may
251 be added to this routine as well. */
252
_tx_initialize_start_interrupts(void)253 void _tx_initialize_start_interrupts(void)
254 {
255 TIMECAPS tc;
256 UINT wTimerRes;
257
258 /* Queries the timer device to determine its resolution. */
259 if (timeGetDevCaps(&tc, sizeof(TIMECAPS)) != TIMERR_NOERROR)
260 {
261 /* Error; application can't continue. */
262 printf("Query timer device error.");
263 while (1)
264 {
265 }
266 }
267
268 wTimerRes = min(max(tc.wPeriodMin, TX_TIMER_PERIODIC), tc.wPeriodMax);
269
270 /* Start a specified timer event. The timer runs in its own thread.
271 It calls the specified callback function when the event is activated. */
272 _tx_win32_timer_id = timeSetEvent(TX_TIMER_PERIODIC, wTimerRes, _tx_win32_timer_interrupt, 0, TIME_PERIODIC);
273 }
274
275 /* Define the ThreadX system timer interrupt. Other interrupts may be simulated
276 in a similar way. */
277
_tx_win32_timer_interrupt(UINT wTimerID,UINT msg,DWORD dwUser,DWORD dw1,DWORD dw2)278 VOID CALLBACK _tx_win32_timer_interrupt(UINT wTimerID, UINT msg, DWORD dwUser, DWORD dw1, DWORD dw2)
279 {
280 /* Call ThreadX context save for interrupt preparation. */
281 _tx_thread_context_save();
282
283 /* Call the ThreadX system timer interrupt processing. */
284 _tx_timer_interrupt();
285
286 /* Call ThreadX context restore for interrupt completion. */
287 _tx_thread_context_restore();
288 }