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