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 }