SuperTinyKernel™ RTOS 1.08.x
Lightweight, high-performance, deterministic, bare-metal C++ RTOS for resource-constrained embedded systems. MIT Open Source License.
Loading...
Searching...
No Matches
stk_arch_x86-win32.cpp
Go to the documentation of this file.
1/*
2 * SuperTinyKernel(TM) RTOS: Lightweight High-Performance Deterministic C++ RTOS for Embedded Systems.
3 *
4 * Source: https://github.com/SuperTinyKernel-RTOS
5 *
6 * Copyright (c) 2022-2026 Neutron Code Limited <stk@neutroncode.com>. All Rights Reserved.
7 * License: MIT License, see LICENSE for a full text.
8 */
9
10// note: If missing, this header must be customized (get it in the root of the source folder) and
11// copied to the /include folder manually.
12#include "stk_config.h"
13
14#ifdef _STK_ARCH_X86_WIN32
15
16#include "stk_arch.h"
18
19using namespace stk;
20
21#define WIN32_LEAN_AND_MEAN
22#include <windows.h>
23#include <stdlib.h>
24#include <stdio.h>
25#include <assert.h>
26#include <list>
27#include <vector>
28
29using namespace stk;
30
31#ifndef WINAPI
32#define WINAPI __stdcall
33#endif
34
35typedef UINT MMRESULT;
36typedef MMRESULT (WINAPI * timeBeginPeriodF)(UINT uPeriod);
37static timeBeginPeriodF timeBeginPeriod = nullptr;
38
39#define STK_X86_WIN32_CRITICAL_SECTION CRITICAL_SECTION
40#define STK_X86_WIN32_CRITICAL_SECTION_INIT(SES) ::InitializeCriticalSection(SES)
41#define STK_X86_WIN32_CRITICAL_SECTION_START(SES) ::EnterCriticalSection(SES)
42#define STK_X86_WIN32_CRITICAL_SECTION_END(SES) ::LeaveCriticalSection(SES)
43#define STK_X86_WIN32_MIN_RESOLUTION (1000)
44#define STK_X86_WIN32_GET_SP(STACK) (STACK + 2) // +2 to overcome stack filler check inside Kernel (adjusting to +2 preserves 8-byte alignment)
45#define SLK_UNLOCKED hw::SpinLock::UNLOCKED
46#define SLK_LOCKED hw::SpinLock::LOCKED
47
50static __stk_forceinline bool HW_SpinLockTryLock(volatile LONG &lock)
51{
52 return (InterlockedCompareExchange(
53 reinterpret_cast<volatile LONG *>(&lock), SLK_LOCKED, SLK_UNLOCKED) == SLK_UNLOCKED);
54}
55
58static __stk_forceinline void HW_SpinLockLock(volatile LONG &lock)
59{
60 uint8_t sleep_time = 0;
61 uint32_t timeout = 0xFFFFFF;
62
63test:
64 while (!HW_SpinLockTryLock(lock))
65 {
66 if (--timeout == 0)
67 {
68 // invariant violated: the lock owner exited without releasing
70 }
71
72 for (volatile int32_t spin = 100; (spin != 0); spin--)
73 {
74 __stk_relax_cpu();
75
76 // check if became unlocked then try locking atomically again
77 if (lock == SLK_UNLOCKED)
78 goto test;
79 }
80
81 // avoid priority inversion
82 ::Sleep(sleep_time);
83 sleep_time ^= 1;
84 }
85}
86
89static __stk_forceinline void HW_SpinLockUnlock(volatile LONG &lock)
90{
91 InterlockedExchange(reinterpret_cast<volatile LONG *>(&lock), SLK_UNLOCKED);
92}
93
94struct Win32ScopedCriticalSection
95{
96 STK_X86_WIN32_CRITICAL_SECTION &m_sec;
97
98 explicit Win32ScopedCriticalSection(STK_X86_WIN32_CRITICAL_SECTION &sec) : m_sec(sec)
99 {
100 STK_X86_WIN32_CRITICAL_SECTION_START(&sec);
101 }
102 ~Win32ScopedCriticalSection()
103 {
104 STK_X86_WIN32_CRITICAL_SECTION_END(&m_sec);
105 }
106};
107
108class HiResClockQPC
109{
110 LARGE_INTEGER m_freq;
111 LARGE_INTEGER m_start;
112
113public:
114 explicit HiResClockQPC()
115 {
116 QueryPerformanceFrequency(&m_freq);
117 QueryPerformanceCounter(&m_start);
118 }
119
120 static HiResClockQPC *GetInstance()
121 {
122 // keep declaration function-local to allow compiler stripping it from the binary if
123 // it is unused by the user code
124 static HiResClockQPC clock;
125 return &clock;
126 }
127
128 Cycles GetCycles()
129 {
130 LARGE_INTEGER current;
131 QueryPerformanceCounter(&current);
132
133 // relative cycles since simulation start
134 return static_cast<Cycles>(current.QuadPart - m_start.QuadPart);
135 }
136
137 uint32_t GetFrequency()
138 {
139 return static_cast<uint32_t>(m_freq.QuadPart);
140 }
141};
142
144static struct Context final : public PlatformContext
145{
146 Context()
147 : m_overrider(nullptr),
148 m_sleep_trap(nullptr),
149 m_exit_trap(nullptr),
150 m_winmm_dll(nullptr),
151 m_timer_thread(nullptr),
152 m_switch_event(nullptr),
153 m_pending_switch_id(TID_NONE),
154 m_tls(TLS_OUT_OF_INDEXES),
155 m_tasks(),
156 m_task_threads(),
157 m_timer_tid(0),
158 #if STK_TICKLESS_IDLE
159 m_sleep_ticks(0),
160 #endif
161 m_cs(),
162 m_csu_nesting(0),
163 m_started(false),
164 m_stop_signal(false)
165 {}
166
167 void Initialize(IPlatform::IEventHandler *handler, IKernelService *service, Stack *exit_trap,
168 uint32_t resolution_us)
169 {
170 InitializeBase(handler, service, exit_trap, resolution_us);
171
172 m_sleep_trap = nullptr; // set by Context::InitStack
173 m_exit_trap = nullptr; // set by Context::InitStack
174 m_winmm_dll = nullptr;
175 m_timer_thread = nullptr;
176 m_started = false;
177 m_stop_signal = false;
178 m_csu_nesting = 0;
179 m_timer_tid = 0;
180 m_pending_switch_id = TID_NONE;
181 #if STK_TICKLESS_IDLE
182 m_sleep_ticks = 0;
183 #endif
184
185 // auto-reset: used by a task's own thread to hand a forced context
186 // switch off to TimerThread, since only TimerThread (or a thread other
187 // than the one being switched) may safely call SwitchContext()
188 m_switch_event = CreateEventA(nullptr, FALSE, FALSE, nullptr);
189 STK_ASSERT(m_switch_event != nullptr);
190
191 #if STK_TLS
192 if ((m_tls = TlsAlloc()) == TLS_OUT_OF_INDEXES)
193 {
194 STK_ASSERT(false);
195 return;
196 }
197 #endif
198
199 STK_X86_WIN32_CRITICAL_SECTION_INIT(&m_cs);
200
201 LoadWindowsAPI();
202 }
203
204 virtual ~Context()
205 {
206 #if STK_TLS
207 if (m_tls != TLS_OUT_OF_INDEXES)
208 TlsFree(m_tls);
209 #endif
210
211 if (m_switch_event != nullptr)
212 {
213 CloseHandle(m_switch_event);
214 m_switch_event = nullptr;
215 }
216
217 UnloadWindowsAPI();
218 }
219
220 void LoadWindowsAPI()
221 {
222 HMODULE winmm = GetModuleHandleA("Winmm");
223 if (winmm == nullptr)
224 {
225 m_winmm_dll = winmm = LoadLibraryA("Winmm.dll");
226 }
227 STK_ASSERT(winmm != nullptr);
228
229 timeBeginPeriod = (timeBeginPeriodF)GetProcAddress(winmm, "timeBeginPeriod");
230 STK_ASSERT(timeBeginPeriod != nullptr);
231
232 timeBeginPeriod(1);
233 }
234
235 void UnloadWindowsAPI()
236 {
237 if (m_winmm_dll != nullptr)
238 {
239 FreeLibrary(m_winmm_dll);
240 m_winmm_dll = nullptr;
241 }
242 }
243
244 struct TaskContext
245 {
246 TaskContext() : m_task(nullptr), m_stack(nullptr), m_thread(nullptr), m_thread_id(0)
247 {}
248
249 void Initialize(ITask *task, Stack *stack)
250 {
251 m_task = task;
252 m_stack = stack;
253 m_thread = nullptr;
254 m_thread_id = 0;
255
256 InitThread();
257 }
258
259 void InitThread()
260 {
261 // simulate stack size limitation
262 const size_t stack_size = m_task->GetStackSize() * sizeof(Word);
263
264 m_thread = CreateThread(nullptr, stack_size, &OnTaskRun, this, CREATE_SUSPENDED, &m_thread_id);
265 }
266
267 static DWORD WINAPI OnTaskRun(LPVOID param)
268 {
269 ((TaskContext *)param)->m_task->Run();
270 return 0;
271 }
272
273 ITask *m_task;
274 Stack *m_stack;
275 HANDLE m_thread;
276 DWORD m_thread_id;
277 };
278
279 void InitStack(EStackType stack_type, Stack *stack, IStackMemory *stack_memory, ITask *user_task);
280 void ConfigureTime();
281 void StartActiveTask();
282 void CreateTimerThreadAndJoin();
283 void Cleanup();
284 void ProcessTick();
285 void SwitchContext();
286 void SwitchToNext();
287 void ForceContextSwitch(TId id);
288 void OnForceContextSwitch();
289 void Sleep(Timeout ticks);
290 bool SleepUntil(Ticks timestamp);
291 EWaitResult Wait(ISyncObject *sync_obj, IMutex *mutex, Timeout timeout);
292 void Stop();
293 Word GetCallerSP() const;
294 TId GetTid() const;
295
296#if STK_TLS
297 __stk_forceinline Word GetTls()
298 {
299 return hw::PtrToWord(TlsGetValue(m_tls));
300 }
301
302 __stk_forceinline void SetTls(Word tp)
303 {
304 TlsSetValue(m_tls, hw::WordToPtr<void>(tp));
305 }
306#endif
307
308 __stk_forceinline void EnterCriticalSection()
309 {
310 STK_X86_WIN32_CRITICAL_SECTION_START(&m_cs);
311
312 if (m_csu_nesting == 0)
313 {
314 // avoid suspending self
315 if (GetCurrentThreadId() != m_timer_tid)
316 {
317 SuspendThread(m_timer_thread);
318 }
319 }
320
321 // increase nesting count within a limit
322 if (++m_csu_nesting > STK_CS_NESTINGS_MAX)
323 {
324 // invariant violated: exceeded max allowed number of recursions
325 STK_KERNEL_PANIC(KERNEL_PANIC_CS_NESTING_OVERFLOW);
326 }
327 }
328
329 __stk_forceinline void ExitCriticalSection()
330 {
331 STK_ASSERT(m_csu_nesting != 0);
332
333 --m_csu_nesting;
334
335 if (m_csu_nesting == 0)
336 {
337 // suspending self is not supported
338 if (GetCurrentThreadId() != m_timer_tid)
339 {
340 ResumeThread(m_timer_thread);
341 }
342 }
343
344 STK_X86_WIN32_CRITICAL_SECTION_END(&m_cs);
345 }
346
347 IPlatform::IEventOverrider *m_overrider;
348 Stack *m_sleep_trap;
349 Stack *m_exit_trap;
350 HMODULE m_winmm_dll;
351 HANDLE m_timer_thread;
352 HANDLE m_switch_event;
353 TId m_pending_switch_id;
354 DWORD m_tls;
355 std::list<TaskContext *> m_tasks;
356 std::vector<HANDLE> m_task_threads;
357 DWORD m_timer_tid;
358#if STK_TICKLESS_IDLE
359 Timeout m_sleep_ticks;
360#endif
361 STK_X86_WIN32_CRITICAL_SECTION m_cs;
362 uint8_t m_csu_nesting;
363 bool m_started;
364 volatile bool m_stop_signal;
365}
366s_StkPlatformContext[1];
367
369static volatile EKernelPanicId g_LastPanicId = KERNEL_PANIC_NONE;
370
371__stk_attr_noinline // keep out of inlining to preserve stack frame
372__stk_attr_noreturn // never returns - a trap
374{
375 g_LastPanicId = id;
376
377 // spin forever: without a watchdog, a debugger can attach and inspect 'id'
378 for (;;)
379 {
380 __stk_relax_cpu();
381 }
382}
383
384static __stk_forceinline DWORD TicksToMs(uint64_t ticks)
385{
386 return static_cast<DWORD>((ticks * GetContext().m_tick_resolution) / 1000U);
387}
388
389static DWORD WINAPI TimerThread(LPVOID param)
390{
391 (void)param;
392
393 Context &ctx = GetContext();
394 DWORD wait_ms = TicksToMs(1U);
395 ctx.m_timer_tid = GetCurrentThreadId();
396
397 // wait_handles[0] is TimerThread's own handle: since it can only become
398 // signaled once this very thread exits, waiting on it can never actually
399 // be satisfied from inside itself - it's used purely so the call below
400 // behaves like a precise timed sleep (kept as in the original code).
401 // wait_handles[1] lets a task thread wake TimerThread early to request a
402 // forced context switch be serviced (see Context::ForceContextSwitch()).
403 HANDLE wait_handles[] = { ctx.m_timer_thread, ctx.m_switch_event };
404
405 for (;;)
406 {
407 DWORD result = WaitForMultipleObjects(STK_STATIC_ARRAY_SIZE(wait_handles), wait_handles, FALSE, wait_ms);
408
409 if (ctx.m_stop_signal)
410 {
411 break;
412 }
413
414 if (result == (WAIT_OBJECT_0 + 1))
415 {
416 // a task requested a forced context switch: SwitchContext() must
417 // never be invoked by the task thread that might itself need to
418 // be suspended, so it's serviced here instead.
419 ctx.OnForceContextSwitch();
420 continue;
421 }
422
423 STK_ASSERT(result == WAIT_TIMEOUT);
424
425 ctx.ProcessTick();
426
427 #if STK_TICKLESS_IDLE
428 wait_ms = TicksToMs(ctx.m_sleep_ticks);
429 #endif
430 }
431
432 return 0;
433}
434
435void Context::ConfigureTime()
436{
437 // Windows timers are jittery, so make resolution more coarse
438 if (m_tick_resolution < STK_X86_WIN32_MIN_RESOLUTION)
439 {
440 m_tick_resolution = STK_X86_WIN32_MIN_RESOLUTION;
441 }
442
443 // increase precision of ticks to at least 1 ms (although Windows timers will still be quite coarse and have jitter of +1 ms)
444 timeBeginPeriod(1);
445}
446
447void Context::StartActiveTask()
448{
449 STK_ASSERT(m_stack_active != nullptr);
450 TaskContext *active_task = hw::WordToPtr<TaskContext>(m_stack_active->SP);
451 STK_ASSERT(active_task != nullptr);
452
453 ResumeThread(active_task->m_thread);
454}
455
456void Context::CreateTimerThreadAndJoin()
457{
458 m_started = true;
459
460#if STK_TICKLESS_IDLE
461 m_sleep_ticks = 1;
462#endif
463
464 m_handler->OnStart(m_stack_active);
465
466 StartActiveTask();
467
468 // create tick thread with highest priority
469 m_timer_thread = CreateThread(nullptr, 0, &TimerThread, nullptr, 0, nullptr);
470 STK_ASSERT(m_timer_thread != nullptr);
471 SetThreadPriority(m_timer_thread, THREAD_PRIORITY_TIME_CRITICAL);
472
473 while (!m_task_threads.empty())
474 {
475 DWORD result = WaitForMultipleObjects((DWORD)m_task_threads.size(), m_task_threads.data(), FALSE, INFINITE);
476 STK_ASSERT(result != WAIT_TIMEOUT);
477 STK_ASSERT(result != WAIT_ABANDONED);
478 STK_ASSERT(result != WAIT_FAILED);
479
480 Win32ScopedCriticalSection __cs(m_cs);
481
482 uint32_t i = 0;
483 for (std::vector<HANDLE>::iterator itr = m_task_threads.begin(); itr != m_task_threads.end(); ++itr)
484 {
485 if (result == (WAIT_OBJECT_0 + i))
486 {
487 TaskContext *exiting_task = nullptr;
488 for (std::list<TaskContext *>::iterator titr = m_tasks.begin(); titr != m_tasks.end(); ++titr)
489 {
490 if ((*titr)->m_thread == (*itr))
491 {
492 exiting_task = (*titr);
493 break;
494 }
495 }
496 STK_ASSERT(exiting_task != nullptr);
497
498 if (exiting_task != nullptr)
499 {
500 m_handler->OnTaskExit(exiting_task->m_stack);
501 }
502
503 m_task_threads.erase(itr);
504 break;
505 }
506
507 ++i;
508 }
509 }
510
511 // join (never returns to the caller from here unless thread is terminated, see KERNEL_DYNAMIC),
512 // a stop signal is sent by IPlatform::Stop() by the last exiting task
513 if (m_timer_thread != nullptr)
514 {
515 WaitForSingleObject(m_timer_thread, INFINITE);
516 }
517}
518
519void Context::Cleanup()
520{
521 // close thread handles of all tasks
522 for (std::list<TaskContext *>::iterator itr = m_tasks.begin(); itr != m_tasks.end(); ++itr)
523 {
524 if ((*itr)->m_thread != nullptr)
525 {
526 CloseHandle((*itr)->m_thread);
527 (*itr)->m_thread = nullptr;
528 }
529 }
530 m_tasks.clear();
531
532 // close timer thread
533 if (m_timer_thread != nullptr)
534 {
535 CloseHandle(m_timer_thread);
536 m_timer_thread = nullptr;
537 }
538
539 // reset stop signal
540 m_stop_signal = false;
541
542 // notify kernel about a full stop
543 m_handler->OnStop();
544}
545
546void Context::ProcessTick()
547{
548 Win32ScopedCriticalSection __cs(m_cs);
549
550#if STK_TICKLESS_IDLE
551 Timeout ticks = m_sleep_ticks;
552#endif
553
554 if (m_handler->OnTick(m_stack_idle, m_stack_active
555 #if STK_TICKLESS_IDLE
556 , ticks
557 #endif
558 ))
559 {
560 SwitchContext();
561 }
562
563#if STK_TICKLESS_IDLE
564 m_sleep_ticks = ticks;
565#endif
566}
567
568void Context::SwitchContext()
569{
570 // suspend Idle thread
571 if ((m_stack_idle != m_sleep_trap) && (m_stack_idle != m_exit_trap))
572 {
573 TaskContext *idle_task = hw::WordToPtr<TaskContext>(m_stack_idle->SP);
574 STK_ASSERT(idle_task != nullptr);
575
576 SuspendThread(idle_task->m_thread);
577 }
578
579 // resume Active thread
580 if (m_stack_active == m_sleep_trap)
581 {
582 #if STK_TICKLESS_IDLE
583 const Timeout sleep_ticks = m_sleep_ticks;
584 #else
585 const Timeout sleep_ticks = 1;
586 #endif
587
588 if ((m_overrider == nullptr) || !m_overrider->OnSleep(sleep_ticks))
589 {
590 // pass
591 }
592 }
593 else
594 if (m_stack_active == m_exit_trap)
595 {
596 // pass
597 }
598 else
599 {
600 TaskContext *active_task = hw::WordToPtr<TaskContext>(m_stack_active->SP);
601 STK_ASSERT(active_task != nullptr);
602
603 ResumeThread(active_task->m_thread);
604 }
605}
606
607Word Context::GetCallerSP() const
608{
609 Word caller_sp = 0;
610 DWORD calling_tid = GetCurrentThreadId();
611
612 Win32ScopedCriticalSection __cs(const_cast<STK_X86_WIN32_CRITICAL_SECTION &>(m_cs));
613
614 for (std::list<TaskContext *>::const_iterator itr = m_tasks.begin(), end = m_tasks.end(); itr != end; ++itr)
615 {
616 if ((*itr)->m_thread_id == calling_tid)
617 {
618 caller_sp = hw::PtrToWord(STK_X86_WIN32_GET_SP((*itr)->m_task->GetStack()));
619 break;
620 }
621 }
622
623 // expect to find the calling task inside m_tasks
624 STK_ASSERT(caller_sp != 0);
625
626 return caller_sp;
627}
628
629TId Context::GetTid() const
630{
631 TId result;
632
633 if (m_started)
634 {
635 result = m_handler->OnGetTid(GetCallerSP());
636 }
637 else
638 {
639 result = TID_NONE;
640 }
641
642 return result;
643}
644
645void Context::SwitchToNext()
646{
647 m_handler->OnTaskSwitch(GetCallerSP());
648}
649
650void Context::ForceContextSwitch(TId id)
651{
652 if (GetCurrentThreadId() == m_timer_tid)
653 {
654 // running on TimerThread: execute forced context switch
655 if (m_handler->OnForceContextSwitch(id, m_stack_idle, m_stack_active))
656 {
657 SwitchContext();
658 }
659 }
660 else
661 {
662 // notify TimerThread to cause a context switch
663 m_pending_switch_id = id;
664 SetEvent(m_switch_event);
665 }
666}
667
668void Context::OnForceContextSwitch()
669{
670 Win32ScopedCriticalSection __cs(m_cs);
671
672 if (m_handler->OnForceContextSwitch(m_pending_switch_id, m_stack_idle, m_stack_active))
673 {
674 SwitchContext();
675 }
676}
677
678void Context::Sleep(Timeout ticks)
679{
680 m_handler->OnTaskSleep(GetCallerSP(), ticks);
681}
682
683bool Context::SleepUntil(Ticks timestamp)
684{
685 return m_handler->OnTaskSleepUntil(GetCallerSP(), timestamp);
686}
687
688EWaitResult Context::Wait(ISyncObject *sync_obj, IMutex *mutex, Timeout timeout)
689{
690 return m_handler->OnTaskWait(GetCallerSP(), sync_obj, mutex, timeout);
691}
692
693void Context::Stop()
694{
695 m_stop_signal = true;
696 m_started = false;
697}
698
699void Context::InitStack(EStackType stack_type, Stack *stack, IStackMemory *stack_memory, ITask *user_task)
700{
701 InitStackMemory(stack_memory);
702
703 Word *const stack_mem = const_cast<Word *>(stack_memory->GetStack());
704 TaskContext *const ctx = reinterpret_cast<TaskContext *>(STK_X86_WIN32_GET_SP(stack_mem));
705
706 switch (stack_type)
707 {
708 case STACK_USER_TASK: {
709 ctx->Initialize(user_task, stack);
710
711 m_tasks.push_back(ctx);
712 m_task_threads.push_back(ctx->m_thread);
713 break; }
714
715 case STACK_SLEEP_TRAP: {
716 GetContext().m_sleep_trap = stack;
717 break; }
718
719 case STACK_EXIT_TRAP: {
720 GetContext().m_exit_trap = stack;
721 break; }
722
723 default: {
724 STK_ASSERT(false);
725 break; }
726 }
727
728 stack->SP = hw::PtrToWord(ctx);
729}
730
731void PlatformX86Win32::Initialize(IEventHandler *event_handler, IKernelService *service, uint32_t resolution_us,
732 Stack *exit_trap)
733{
734 GetContext().Initialize(event_handler, service, exit_trap, resolution_us);
735}
736
738{
739 GetContext().ConfigureTime();
740 GetContext().CreateTimerThreadAndJoin();
741 GetContext().Cleanup();
742}
743
745{
746 GetContext().Stop();
747}
748
750{
751 STK_ASSERT(false); // unsupported
752 return 0;
753}
754
755void PlatformX86Win32::Resume(Timeout elapsed_ticks)
756{
757 STK_ASSERT(false); // unsupported
758}
759
760void PlatformX86Win32::SetCpuFrequency(uint8_t core_id, uint32_t frequency)
761{
762 STK_ASSERT(false); // unsupported
763}
764
765void PlatformX86Win32::InitStack(EStackType stack_type, Stack *stack, IStackMemory *stack_memory, ITask *user_task)
766{
767 GetContext().InitStack(stack_type, stack, stack_memory, user_task);
768}
769
771{
772 return GetContext().m_tick_resolution;
773}
774
776{
777 return HiResClockQPC::GetInstance()->GetCycles();
778}
779
781{
782 return HiResClockQPC::GetInstance()->GetFrequency();
783}
784
786{
787 GetContext().SwitchToNext();
788}
789
791{
792 GetContext().ForceContextSwitch(id);
793}
794
796{
797 GetContext().Sleep(ticks);
798}
799
801{
802 return GetContext().SleepUntil(timestamp);
803}
804
806{
807 return GetContext().Wait(sync_obj, mutex, timeout);
808}
809
811{
812 GetContext().ProcessTick();
813}
814
816{
817 if ((GetContext().m_overrider == nullptr) || !GetContext().m_overrider->OnHardFault())
818 {
820 }
821}
822
823void PlatformX86Win32::SetEventOverrider(IEventOverrider *overrider, bool non_secure)
824{
825 STK_UNUSED(non_secure);
826
827 STK_ASSERT(!GetContext().m_started);
828 GetContext().m_overrider = overrider;
829}
830
832{
833 return GetContext().GetCallerSP();
834}
835
837{
838 return GetContext().GetTid();
839}
840
841#if STK_TLS
842Word stk::hw::GetTls()
843{
844 return GetContext().GetTls();
845}
846
847void stk::hw::SetTls(Word tp)
848{
849 return GetContext().SetTls(tp);
850}
851#endif
852
854{
855 return GetContext().m_service;
856}
857
859{
860 STK_UNUSED(is_npriv);
861 GetContext().EnterCriticalSection();
862 return DEFAULT_SESSION;
863}
864
866{
867 STK_UNUSED(is_npriv);
868 GetContext().ExitCriticalSection();
869}
870
872{
873 HW_SpinLockLock(m_lock);
874}
875
877{
878 HW_SpinLockUnlock(m_lock);
879}
880
882{
883 return HW_SpinLockTryLock(m_lock);
884}
885
887{
888 return false;
889}
890
892{
893 return true;
894}
895
897{
898 return HiResClockQPC::GetInstance()->GetCycles();
899}
900
902{
903 return HiResClockQPC::GetInstance()->GetFrequency();
904}
905
906#endif // _STK_ARCH_X86_WIN32
Contains common inventory for platform implementation.
#define GetContext()
Get platform's context.
Hardware Abstraction Layer (HAL) declarations for the stk::hw namespace.
void STK_PANIC_HANDLER_DEFAULT(stk::EKernelPanicId id)
Default panic handler: disable interrupts, record the id, and spin in a tight loop - a defined,...
#define STK_UNUSED(X)
Explicitly marks a variable as unused to suppress compiler warnings.
Definition stk_defs.h:715
#define __stk_forceinline
Forces compiler to always inline the decorated function, regardless of optimisation level.
Definition stk_defs.h:277
#define STK_CS_NESTINGS_MAX
Maximum allowable recursion depth for critical section entry (default: 16).
Definition stk_defs.h:590
#define STK_ASSERT(e)
Runtime assertion. Halts execution if the expression e evaluates to false.
Definition stk_defs.h:516
#define __stk_attr_noinline
Prevents compiler from inlining the decorated function (function prefix).
Definition stk_defs.h:357
#define __stk_attr_noreturn
Declares that function never returns to its caller (function prefix).
Definition stk_defs.h:324
#define STK_STATIC_ARRAY_SIZE(ARRAY)
Get size of the static array.
Definition stk_defs.h:742
Namespace of STK package.
uintptr_t Word
Native processor word type.
Definition stk_common.h:143
static void Sleep(Timeout tick_count)
Put calling process into a sleep state.
Definition stk_helper.h:479
EWaitResult
Wait result (see IKernelService::Wait).
Definition stk_common.h:121
int64_t Ticks
Ticks value.
Definition stk_common.h:158
EKernelPanicId
Identifies the source of a kernel panic.
Definition stk_common.h:58
@ KERNEL_PANIC_HRT_HARD_FAULT
Kernel running in KERNEL_HRT mode reported deadline failure of the task.
Definition stk_common.h:63
@ KERNEL_PANIC_NONE
Panic is absent (no fault).
Definition stk_common.h:59
@ KERNEL_PANIC_SPINLOCK_DEADLOCK
Spin-lock timeout expired: lock owner never released.
Definition stk_common.h:60
int32_t Timeout
Timeout time (ticks).
Definition stk_common.h:153
static void STK_KERNEL_PANIC(stk::EKernelPanicId id)
Called when the kernel detects an unrecoverable internal fault.
Definition stk_arch.h:183
static constexpr TId TID_NONE
Reserved task/thread id representing zero/none thread id.
Definition stk_common.h:205
EStackType
Stack type.
Definition stk_common.h:79
@ STACK_SLEEP_TRAP
Stack of the Sleep trap.
Definition stk_common.h:81
@ STACK_USER_TASK
Stack of the user task.
Definition stk_common.h:80
@ STACK_EXIT_TRAP
Stack of the Exit trap.
Definition stk_common.h:82
uint64_t Cycles
Cycles value.
Definition stk_common.h:168
Word TId
Task (thread) id.
Definition stk_common.h:148
bool IsPrivilegedContext()
Check if caller context is Privileged.
static constexpr T * WordToPtr(Word value) noexcept
Cast a CPU register-width integer back to a pointer.
Definition stk_arch.h:231
static constexpr Word PtrToWord(T *const ptr) noexcept
Cast a pointer to a CPU register-width integer.
Definition stk_arch.h:214
bool IsInsideISR()
Check whether the CPU is currently executing inside a hardware interrupt service routine (ISR).
Base platform context for all platform implementations.
EWaitResult Wait(ISyncObject *sync_obj, IMutex *mutex, Timeout timeout) override
Put calling process into a waiting state until synchronization object is signaled or timeout occurs.
void Sleep(Timeout ticks) override
Put calling process into a sleep state.
void Resume(Timeout elapsed_ticks) override
Resume scheduling after a prior Suspend() call.
void Stop() override
Stop scheduling.
void Initialize(IEventHandler *event_handler, IKernelService *service, uint32_t resolution_us, Stack *exit_trap) override
Initialize scheduler's context.
Word GetCallerSP() const override
Get caller's Stack Pointer (SP).
void Start() override
Start scheduling.
uint32_t GetSysTimerFrequency() const override
Get system timer frequency.
uint32_t GetTickResolution() const override
Get resolution of the system tick timer in microseconds. Resolution means a number of microseconds be...
void SetCpuFrequency(uint8_t core_id, uint32_t frequency) override
Notify the scheduler of a CPU core's operating frequency.
void InitStack(EStackType stack_type, Stack *stack, IStackMemory *stack_memory, ITask *user_task) override
Initialize stack memory of the user task.
void ProcessHardFault() override
Cause a hard fault of the system.
void ProcessTick() override
Process one tick.
Cycles GetSysTimerCount() const override
Get system timer count value.
void SetEventOverrider(IEventOverrider *overrider, bool non_secure) override
Set platform event overrider.
bool SleepUntil(Ticks timestamp) override
Put calling process into a sleep state until the specified timestamp.
void ForceContextSwitch(TId id) override
Force context switch.
TId GetTid() const override
Get thread Id.
void SwitchToNext() override
Switch to a next task.
Timeout Suspend() override
Suspend scheduling.
static constexpr Session DEFAULT_SESSION
Default session value passed to Enter()/Exit() when the caller does not need to force a specific hand...
Definition stk_arch.h:478
static Session Enter(const Session ses=DEFAULT_SESSION)
Enter a critical section.
uint8_t Session
Opaque session token returned by Enter() and consumed by Exit().
Definition stk_arch.h:471
static void Exit(const Session ses=DEFAULT_SESSION)
Exit a critical section.
bool TryLock()
Attempt to acquire SpinLock in a single non-blocking attempt.
void Lock()
Acquire SpinLock, blocking until it is available.
void Unlock()
Release SpinLock, allowing another thread or core to acquire it.
static uint32_t GetFrequency()
Get clock frequency.
static Cycles GetCycles()
Get number of clock cycles elapsed.
Stack descriptor.
Definition stk_common.h:392
Word SP
Offset 0: Stack Pointer (SP) register (note: must always be at offset 0).
Definition stk_common.h:393
Interface for a stack memory region.
Definition stk_common.h:413
virtual const Word * GetStack() const =0
Get pointer to the stack memory.
Synchronization object interface.
Definition stk_common.h:564
Interface for mutex synchronization primitive.
Definition stk_common.h:697
Interface for a user task.
Definition stk_common.h:755
Interface for the kernel services exposed to the user processes during run-time when Kernel started s...
static IKernelService * GetInstance()
Get CPU-local instance of the kernel service.
RISC-V specific event handler.