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 }