/*************************************************************************** * Copyright (C) 2026 Eclipse ThreadX contributors * * This program and the accompanying materials are made available under the * terms of the MIT License which is available at * https://opensource.org/licenses/MIT. * * AI Disclosure: This file was largely AI-generated by Codex (gpt 5.4). * The AI-generated portions may be considered public domain (CC0-1.0) * and not subject to the project's licence. The human contributor has * reviewed and verified that the code is correct. * * SPDX-License-Identifier: MIT and CC0-1.0 **************************************************************************/ // Some portions generated by Codex (gpt 5.4). /**************************************************************************/ /**************************************************************************/ /** */ /** ThreadX Component */ /** */ /** Initialize */ /** */ /**************************************************************************/ /**************************************************************************/ #define TX_SOURCE_CODE /* Include necessary system files. */ #include "tx_api.h" #include #include #include #pragma comment (lib, "Winmm.lib") /* Define various Win32 objects used by the ThreadX port. */ TX_WIN32_CRITICAL_SECTION _tx_win32_critical_section; HANDLE _tx_win32_scheduler_semaphore; HANDLE _tx_win32_scheduler_wake_event; DWORD _tx_win32_scheduler_id; ULONG _tx_win32_global_int_disabled_flag; LARGE_INTEGER _tx_win32_time_stamp; ULONG _tx_win32_system_error; HANDLE _tx_win32_timer_handle; HANDLE _tx_win32_timer_thread_handle; HANDLE _tx_win32_isr_semaphore; UINT _tx_win32_timer_waiting; extern TX_THREAD *_tx_thread_current_ptr; /* Define simulated timer interrupt. This is done inside a thread, which is how other interrupts may be defined as well. See code below for an example. */ UINT _tx_win32_timer_id; VOID CALLBACK _tx_win32_timer_interrupt(UINT wTimerID, UINT msg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2); static VOID _tx_win32_timer_start(VOID); static DWORD WINAPI _tx_win32_timer_thread_entry(LPVOID thread_input); #ifdef TX_WIN32_DEBUG_ENABLE extern ULONG _tx_thread_system_state; extern UINT _tx_thread_preempt_disable; extern TX_THREAD *_tx_thread_current_ptr; extern TX_THREAD *_tx_thread_execute_ptr; /* Define the maximum size of the Win32 debug array. */ #ifndef TX_WIN32_DEBUG_EVENT_SIZE #define TX_WIN32_DEBUG_EVENT_SIZE 400 #endif /* Define debug log in order to debug Win32 issues with this port. */ typedef struct TX_WIN32_DEBUG_ENTRY_STRUCT { char *tx_win32_debug_entry_action; LARGE_INTEGER tx_win32_debug_entry_timestamp; char *tx_win32_debug_entry_file; unsigned long tx_win32_debug_entry_line; TX_WIN32_CRITICAL_SECTION tx_win32_debug_entry_critical_section; unsigned long tx_win32_debug_entry_int_disabled_flag; ULONG tx_win32_debug_entry_system_state; UINT tx_win32_debug_entry_preempt_disable; TX_THREAD *tx_win32_debug_entry_current_thread; DWORD tx_win32_debug_entry_current_thread_id; TX_THREAD *tx_win32_debug_entry_execute_thread; DWORD tx_win32_debug_entry_execute_thread_id; DWORD tx_win32_debug_entry_running_id; } TX_WIN32_DEBUG_ENTRY; /* Define the circular array of Win32 debug entries. */ TX_WIN32_DEBUG_ENTRY _tx_win32_debug_entry_array[TX_WIN32_DEBUG_EVENT_SIZE]; /* Define the Win32 debug index. */ unsigned long _tx_win32_debug_entry_index = 0; /* Now define the debug entry function. */ void _tx_win32_debug_entry_insert(char *action, char *file, unsigned long line) { /* Get the time stamp. */ QueryPerformanceCounter((LARGE_INTEGER *)&_tx_win32_time_stamp); /* Setup the debug entry. */ _tx_win32_debug_entry_array[_tx_win32_debug_entry_index].tx_win32_debug_entry_action = action; _tx_win32_debug_entry_array[_tx_win32_debug_entry_index].tx_win32_debug_entry_timestamp = _tx_win32_time_stamp; _tx_win32_debug_entry_array[_tx_win32_debug_entry_index].tx_win32_debug_entry_file = file; _tx_win32_debug_entry_array[_tx_win32_debug_entry_index].tx_win32_debug_entry_line = line; _tx_win32_debug_entry_array[_tx_win32_debug_entry_index].tx_win32_debug_entry_critical_section = _tx_win32_critical_section; _tx_win32_debug_entry_array[_tx_win32_debug_entry_index].tx_win32_debug_entry_int_disabled_flag = _tx_win32_global_int_disabled_flag; _tx_win32_debug_entry_array[_tx_win32_debug_entry_index].tx_win32_debug_entry_system_state = _tx_thread_system_state; _tx_win32_debug_entry_array[_tx_win32_debug_entry_index].tx_win32_debug_entry_preempt_disable = _tx_thread_preempt_disable; _tx_win32_debug_entry_array[_tx_win32_debug_entry_index].tx_win32_debug_entry_current_thread = _tx_thread_current_ptr; if (_tx_thread_current_ptr) _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; else _tx_win32_debug_entry_array[_tx_win32_debug_entry_index].tx_win32_debug_entry_current_thread_id = 0; _tx_win32_debug_entry_array[_tx_win32_debug_entry_index].tx_win32_debug_entry_execute_thread = _tx_thread_execute_ptr; if (_tx_thread_execute_ptr) _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; else _tx_win32_debug_entry_array[_tx_win32_debug_entry_index].tx_win32_debug_entry_execute_thread_id = 0; _tx_win32_debug_entry_array[_tx_win32_debug_entry_index].tx_win32_debug_entry_running_id = GetCurrentThreadId(); /* Now move to the next entry. */ _tx_win32_debug_entry_index++; /* Determine if we need to wrap the list. */ if (_tx_win32_debug_entry_index >= TX_WIN32_DEBUG_EVENT_SIZE) { /* Yes, wrap the list! */ _tx_win32_debug_entry_index = 0; } } #endif /* Define the ThreadX timer interrupt handler. */ void _tx_timer_interrupt(void); /* Define other external function references. */ VOID _tx_initialize_low_level(VOID); VOID _tx_thread_context_save(VOID); VOID _tx_thread_context_restore(VOID); VOID _tx_win32_scheduler_wake(VOID); /* Define other external variable references. */ extern VOID *_tx_initialize_unused_memory; /**************************************************************************/ /* */ /* FUNCTION RELEASE */ /* */ /* _tx_initialize_low_level Win64/MSVC */ /* 6.1 */ /* AUTHOR */ /* */ /* William E. Lamie, Microsoft Corporation */ /* */ /* DESCRIPTION */ /* */ /* This function is responsible for any low-level processor */ /* initialization, including setting up interrupt vectors, setting */ /* up a periodic timer interrupt source, saving the system stack */ /* pointer for use in ISR processing later, and finding the first */ /* available RAM memory address for tx_application_define. */ /* */ /* INPUT */ /* */ /* None */ /* */ /* OUTPUT */ /* */ /* None */ /* */ /* CALLS */ /* */ /* CreateMutex Win32 create mutex */ /* CreateThread Win32 create thread */ /* CreateSemaphore Win32 create semaphore */ /* GetCurrentThreadId Win32 get current thread ID */ /* SetProcessAffinityMask Win32 process affinity set */ /* SetThreadPriority Win32 set thread priority */ /* */ /* CALLED BY */ /* */ /* _tx_initialize_kernel_enter ThreadX entry function */ /* */ /**************************************************************************/ VOID _tx_initialize_low_level(VOID) { /* Deprecate TX_WIN32_MULTI_CORE build option and default to restricting execution to one core. */ #ifndef TX_WIN32_BYPASS_AFFINITY_SETUP /* Limit this ThreadX simulation on Win64 to a single core. */ if (SetProcessAffinityMask(GetCurrentProcess(), ((DWORD_PTR) 1)) == 0) { /* Error restricting the process to one core. */ printf("ThreadX Win64 error restricting the process to one core!\n"); while(1) { } } #endif /* Pickup the first available memory address. */ /* Save the first available memory address. */ _tx_initialize_unused_memory = malloc(TX_WIN32_MEMORY_SIZE); /* Pickup the unique Id of the current thread, which will also be the Id of the scheduler. */ _tx_win32_scheduler_id = GetCurrentThreadId(); /* Create the system critical section mutex. This is used by the system to block all other access, analogous to an interrupt lockout on an embedded target. */ _tx_win32_critical_section.tx_win32_critical_section_mutex_handle = CreateMutex(NULL, FALSE, NULL); _tx_win32_critical_section.tx_win32_critical_section_nested_count = 0; _tx_win32_critical_section.tx_win32_critical_section_owner = 0; if (_tx_win32_critical_section.tx_win32_critical_section_mutex_handle == NULL) { printf("ThreadX Win64 error creating critical section mutex!\n"); while(1) { } } /* Create the semaphore that regulates when the scheduler executes. */ _tx_win32_scheduler_semaphore = CreateSemaphore(NULL, 0, 1, NULL); _tx_win32_isr_semaphore = CreateSemaphore(NULL, 0, 1, NULL); if ((_tx_win32_scheduler_semaphore == NULL) || (_tx_win32_isr_semaphore == NULL)) { printf("ThreadX Win64 error creating semaphores!\n"); while(1) { } } /* Create the event that wakes the scheduler whenever the ready state changes. */ _tx_win32_scheduler_wake_event = CreateEvent(NULL, FALSE, FALSE, NULL); if (_tx_win32_scheduler_wake_event == NULL) { printf("ThreadX Win64 error creating scheduler wake event!\n"); while(1) { } } /* Initialize the global interrupt disabled flag. */ _tx_win32_global_int_disabled_flag = TX_FALSE; _tx_win32_timer_waiting = TX_FALSE; /* Done, return to caller. */ } /* This routine is called after initialization is complete in order to start all interrupt threads. Interrupt threads in addition to the timer may be added to this routine as well. */ void _tx_initialize_start_interrupts(void) { TIMECAPS tc; UINT wTimerRes; /* Queries the timer device to determine its resolution. */ if (timeGetDevCaps(&tc, sizeof(TIMECAPS)) != TIMERR_NOERROR) { /* Error; application can't continue. */ printf("Query timer device error."); while (1) { } } wTimerRes = min(max(tc.wPeriodMin, TX_TIMER_PERIODIC), tc.wPeriodMax); /* Request the best available timer resolution for the simulation. */ if (timeBeginPeriod(wTimerRes) != TIMERR_NOERROR) { printf("ThreadX Win64 error configuring timer resolution!\n"); while (1) { } } /* Create the periodic waitable timer used to drive simulated interrupts. */ #if (TX_WIN32_USE_HIGH_RESOLUTION_TIMER != 0) _tx_win32_timer_handle = CreateWaitableTimerEx(NULL, NULL, CREATE_WAITABLE_TIMER_HIGH_RESOLUTION, TIMER_ALL_ACCESS); if (_tx_win32_timer_handle == NULL) #endif { _tx_win32_timer_handle = CreateWaitableTimer(NULL, FALSE, NULL); } if (_tx_win32_timer_handle == NULL) { printf("ThreadX Win64 error creating timer handle!\n"); while (1) { } } /* Create the timer thread so interrupts are serialized through one execution context. */ _tx_win32_timer_thread_handle = CreateThread(NULL, 0, _tx_win32_timer_thread_entry, NULL, 0, NULL); if (_tx_win32_timer_thread_handle == NULL) { printf("ThreadX Win64 error creating timer thread!\n"); while (1) { } } SetThreadPriority(_tx_win32_timer_thread_handle, THREAD_PRIORITY_HIGHEST); _tx_win32_timer_id = 1; /* Start the first simulated tick. */ _tx_win32_timer_start(); } /* Define the ThreadX system timer interrupt. Other interrupts may be simulated in a similar way. */ VOID CALLBACK _tx_win32_timer_interrupt(UINT wTimerID, UINT msg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2) { TX_PARAMETER_NOT_USED(wTimerID); TX_PARAMETER_NOT_USED(msg); TX_PARAMETER_NOT_USED(dwUser); TX_PARAMETER_NOT_USED(dw1); TX_PARAMETER_NOT_USED(dw2); /* Call ThreadX context save for interrupt preparation. */ _tx_thread_context_save(); /* Call the ThreadX system timer interrupt processing. */ _tx_timer_interrupt(); /* Call ThreadX context restore for interrupt completion. */ _tx_thread_context_restore(); /* Wake the scheduler so it can promptly observe timer-driven work. */ _tx_win32_scheduler_wake(); } static DWORD WINAPI _tx_win32_timer_thread_entry(LPVOID thread_input) { TX_PARAMETER_NOT_USED(thread_input); /* Drive periodic simulated interrupts from a single thread. */ while (1) { WaitForSingleObject(_tx_win32_timer_handle, INFINITE); _tx_win32_timer_interrupt(0, 0, 0, 0, 0); _tx_win32_timer_start(); } } VOID _tx_win32_scheduler_wake(VOID) { /* Wake the scheduler if it is waiting for a state change. */ if (_tx_win32_scheduler_wake_event != NULL) { SetEvent(_tx_win32_scheduler_wake_event); } } static VOID _tx_win32_timer_start(VOID) { LARGE_INTEGER due_time; /* Rearm the host timer relative to "now" to avoid burst catch-up ticks. */ due_time.QuadPart = -(((LONGLONG) TX_TIMER_PERIODIC) * 10000LL); #if (TX_WIN32_USE_HIGH_RESOLUTION_TIMER != 0) if (SetWaitableTimerEx(_tx_win32_timer_handle, &due_time, 0, NULL, NULL, NULL, 0) == 0) #else if (SetWaitableTimer(_tx_win32_timer_handle, &due_time, 0, NULL, NULL, FALSE) == 0) #endif { printf("ThreadX Win64 error starting timer!\n"); while (1) { } } }