/** * @file os.h * @brief Operating System implementations. */ #pragma once #include #include #include namespace nn { namespace os { namespace detail { struct InternalCriticalSection { u32 Image; }; struct InternalConditionVariable { u32 Image; }; } // namespace detail typedef u64 Tick; struct LightEventType { std::aligned_storage_t<0xc, 4> storage; }; // https://github.com/misson20000/nn-types/blob/master/nn_os.h struct EventType { nn::os::EventType* _x0; nn::os::EventType* _x8; bool isSignaled; bool initiallySignaled; bool shouldAutoClear; bool isInit; u32 signalCounter; u32 signalCounter2; nn::os::detail::InternalCriticalSection crit; nn::os::detail::InternalConditionVariable condvar; }; typedef EventType Event; // https://github.com/misson20000/nn-types/blob/master/nn_os.h struct ThreadType { u64 field_8; u64 field_10; u64 field_18; char field_20[32]; uint32_t thread_status; char field_41; u16 field_42; uint32_t thread_prio_shift; uint64_t thread_stack_base_addr; uint64_t thread_stack_base_addr_mirror; uint64_t thread_stack_size; uint64_t thread_param; uint64_t thread_func; u64 field_70; u64 field_78; u64 field_80; char field_88[0x100]; char thread_name[0x20]; const char* thread_name_addr; nn::os::detail::InternalCriticalSection crit; nn::os::detail::InternalConditionVariable condvar; u32 thread_handle; }; #ifdef SWITCH static_assert(sizeof(ThreadType) == 0x1C0, "Wrong size"); #endif struct MessageQueueType { u64 _x0; u64 _x8; u64 _x10; u64 _x18; void* Buffer; u32 MaxCount; u32 Count; u32 Offset; bool Initialized; detail::InternalCriticalSection _x38; detail::InternalConditionVariable _x3C; detail::InternalConditionVariable _x40; }; struct ConditionVariableType {}; struct SemaphoreType { std::aligned_storage_t<0x28, 8> storage; }; struct SystemEvent; struct SystemEventType; // ARG void SetHostArgc(s32); s32 GetHostArgc(); void SetHostArgv(char**); char** GetHostArgv(); // MEMORY void InitializeVirtualAddressMemory(); Result AllocateAddressRegion(u64*, u64); Result AllocateMemory(u64*, u64); Result AllocateMemoryPages(u64, u64); void AllocateMemoryBlock(u64*, u64); void FreeMemoryBlock(u64, u64); void SetMemoryHeapSize(u64); // MUTEX struct MutexType { u8 curState; // _0 bool isRecursiveMutex; // _1 s32 lockLevel; // _2 u8 _6[0x20 - 0xE]; }; void InitializeMutex(nn::os::MutexType*, bool, s32); void FinalizeMutex(nn::os::MutexType*); void LockMutex(nn::os::MutexType*); bool TryLockMutex(nn::os::MutexType*); void UnlockMutex(nn::os::MutexType*); bool IsMutexLockedByCurrentThread(nn::os::MutexType const*); // QUEUE void InitializeMessageQueue(nn::os::MessageQueueType*, u64* buf, u64 queueCount); void FinalizeMessageQueue(nn::os::MessageQueueType*); bool TrySendMessageQueue(MessageQueueType*, u64); void SendMessageQueue(MessageQueueType*, u64); bool TimedSendMessageQueue(MessageQueueType*, u64, nn::TimeSpan); bool TryReceiveMessageQueue(u64* out, MessageQueueType*); void ReceiveMessageQueue(u64* out, MessageQueueType*); bool TimedReceiveMessageQueue(u64* out, MessageQueueType*, nn::TimeSpan); bool TryPeekMessageQueue(u64*, MessageQueueType const*); void PeekMessageQueue(u64*, MessageQueueType const*); bool TimedPeekMessageQueue(u64*, MessageQueueType const*); bool TryJamMessageQueue(nn::os::MessageQueueType*, u64); void JamMessageQueue(nn::os::MessageQueueType*, u64); bool TimedJamMessageQueue(nn::os::MessageQueueType*, u64, nn::TimeSpan); // CONDITION VARIABLE void InitializeConditionVariable(ConditionVariableType*); void FinalizeConditionVariable(ConditionVariableType*); void SignalConditionVariable(ConditionVariableType*); void BroadcastConditionVariable(ConditionVariableType*); void WaitConditionVariable(ConditionVariableType*); u8 TimedWaitConditionVariable(ConditionVariableType*, MutexType*, nn::TimeSpan); // THREAD Result CreateThread(nn::os::ThreadType*, void (*)(void*), void* arg, void* srcStack, u64 stackSize, s32 priority, s32 coreNum); Result CreateThread(nn::os::ThreadType*, void (*)(void*), void* arg, void* srcStack, u64 stackSize, s32 priority); void DestroyThread(nn::os::ThreadType*); void StartThread(nn::os::ThreadType*); void SetThreadName(nn::os::ThreadType*, char const* threadName); void SetThreadNamePointer(nn::os::ThreadType*, char const*); char* GetThreadNamePointer(nn::os::ThreadType const*); nn::os::ThreadType* GetCurrentThread(); void GetCurrentStackInfo(uintptr_t* stack_addr, size_t* stack_size); s32 ChangeThreadPriority(nn::os::ThreadType* thread, s32 priority); s32 GetThreadPriority(nn::os::ThreadType const* thread); u64 GetThreadId(const nn::os::ThreadType* thread); void YieldThread(); void SuspendThread(nn::os::ThreadType*); void ResumeThread(nn::os::ThreadType*); void SleepThread(nn::TimeSpan); void WaitThread(nn::os::ThreadType*); void SetThreadCoreMask(nn::os::ThreadType*, int, u64 mask); // EVENTS void InitializeEvent(EventType*, bool initiallySignaled, bool autoclear); void FinalizeEvent(EventType*); void SignalEvent(EventType*); void WaitEvent(EventType*); bool TryWaitEvent(EventType*); bool TimedWaitEvent(EventType*, nn::TimeSpan); void ClearEvent(EventType*); // LIGHT EVENTS void InitializeLightEvent(LightEventType*, bool initiallySignaled, bool autoclear); void FinalizeLightEvent(LightEventType*); void SignalLightEvent(LightEventType*); void WaitLightEvent(LightEventType*); bool TimedWaitLightEvent(LightEventType*, nn::TimeSpan); void ClearLightEvent(LightEventType*); TimeSpan ConvertToTimeSpan(Tick ticks); // SEMAPHORES void InitializeSemaphore(SemaphoreType* semaphore, s32 initial_count, s32 max_count); void FinalizeSemaphore(SemaphoreType* semaphore); void AcquireSemaphore(SemaphoreType* semaphore); bool TryAcquireSemaphore(SemaphoreType* semaphore); void ReleaseSemaphore(SemaphoreType* semaphore); // EXCEPTION HANDLING typedef union { u64 x; ///< 64-bit AArch64 register view. u32 w; ///< 32-bit AArch64 register view. u32 r; ///< AArch32 register view. } CpuRegister; /// Armv8 NEON register. typedef union { u128 v; ///< 128-bit vector view. double d; ///< 64-bit double-precision view. float s; ///< 32-bit single-precision view. } FpuRegister; struct UserExceptionInfo { u32 ErrorDescription; ///< See \ref ThreadExceptionDesc. u32 pad[3]; CpuRegister CpuRegisters[29]; ///< GPRs 0..28. Note: also contains AArch32 registers. CpuRegister FP; ///< Frame pointer. CpuRegister LR; ///< Link register. CpuRegister SP; ///< Stack pointer. CpuRegister PC; ///< Program counter (elr_el1). u64 padding; FpuRegister FpuRegisters[32]; ///< 32 general-purpose NEON registers. u32 PState; ///< pstate & 0xFF0FFE20 u32 AFSR0; u32 AFSR1; u32 ESR; CpuRegister FAR; ///< Fault Address Register. }; void SetUserExceptionHandler(void (*)(UserExceptionInfo*), void*, ulong, UserExceptionInfo*); // OTHER void GenerateRandomBytes(void*, u64); nn::os::Tick GetSystemTick(); nn::os::Tick GetSystemTickFrequency(); u64 GetThreadAvailableCoreMask(); void SetMemoryHeapSize(u64 size); // Thread-local storage struct TlsSlot { u32 slot; }; Result AllocateTlsSlot(TlsSlot* slot_out, void (*)(u64)); void FreeTlsSlot(TlsSlot slot); u64 GetTlsValue(TlsSlot slot); void SetTlsValue(TlsSlot slot, u64 value); u32 GetCurrentCoreNumber(); namespace detail { extern s32 g_CommandLineParameter; extern char** g_CommandLineParameterArgv; }; // namespace detail }; // namespace os }; // namespace nn