diff --git a/nx/include/switch/kernel/svc.h b/nx/include/switch/kernel/svc.h index 930d524f..d2fdd73b 100644 --- a/nx/include/switch/kernel/svc.h +++ b/nx/include/switch/kernel/svc.h @@ -6,13 +6,13 @@ #pragma once #include "../types.h" -/// Pseudo handle for the current process +/// Pseudo handle for the current process. #define CUR_PROCESS_HANDLE 0xFFFF8001 -/// Pseudo handle for the current thread +/// Pseudo handle for the current thread. #define CUR_THREAD_HANDLE 0xFFFF8000 -/// Memory type enumeration (lower 8 bits of MemoryState) +/// Memory type enumeration (lower 8 bits of \ref MemoryState) typedef enum { MemType_Unmapped=0x00, ///< Unmapped memory. MemType_Io=0x01, ///< Mapped by kernel capability parsing in \ref svcCreateProcess. @@ -21,7 +21,7 @@ typedef enum { MemType_CodeMutable=0x04, ///< Transition from MemType_CodeStatic performed by \ref svcSetProcessMemoryPermission. MemType_Heap=0x05, ///< Mapped using \ref svcSetHeapSize. MemType_SharedMem=0x06, ///< Mapped using \ref svcMapSharedMemory. - MemType_WeirdSharedMem=0x07, ///< Mapped using \ref svcMapMemory. + MemType_WeirdMappedMem=0x07, ///< Mapped using \ref svcMapMemory. MemType_ModuleCodeStatic=0x08, ///< Mapped using \ref svcMapProcessCodeMemory. MemType_ModuleCodeMutable=0x09, ///< Transition from \ref MemType_ModuleCodeStatic performed by \ref svcSetProcessMemoryPermission. MemType_IpcBuffer0=0x0A, ///< IPC buffers with descriptor flags=0. @@ -92,82 +92,379 @@ typedef struct { u32 padding; ///< Padding. } MemoryInfo; +/// Secure monitor arguments. typedef struct { - u64 X[8]; + u64 X[8]; ///< Values of X0 through X7. } PACKED SecmonArgs; +/// JIT mapping operations typedef enum { - JitMapOperation_MapOwner=0, - JitMapOperation_MapSlave=1, - JitMapOperation_UnmapOwner=2, - JitMapOperation_UnmapSlave=3 + JitMapOperation_MapOwner=0, ///< Map owner. + JitMapOperation_MapSlave=1, ///< Map slave. + JitMapOperation_UnmapOwner=2, ///< Unmap owner. + JitMapOperation_UnmapSlave=3, ///< Unmap slave. } JitMapOperation; +///@name Memory management +///@{ + +/** + * @brief Set the process heap to a given size. It can both extend and shrink the heap. + * @param[out] out_addr Variable to which write the address of the heap (which is randomized and fixed by the kernel) + * @param[in] size Size of the heap, must be a multiple of 0x2000000 and [2.0.0+] less than 0x18000000. + * @return Result code. + * @note Syscall number 0x00. + */ Result svcSetHeapSize(void** out_addr, u64 size); + +/** + * @brief Set the memory permissions of a (page-aligned) range of memory. + * @param[in] addr Start address of the range. + * @param[in] size Size of the range, in bytes. + * @param[in] perm Permissions (see \ref Permission). + * @return Result code. + * @remark Perm_X is not allowed. Setting write-only is not allowed either (Perm_W). + * This can be used to move back and forth between Perm_None, Perm_R and Perm_Rw. + * @note Syscall number 0x01. + */ Result svcSetMemoryPermission(void* addr, u64 size, u32 perm); + +/** + * @brief Set the memory attributes of a (page-aligned) range of memory. + * @param[in] addr Start address of the range. + * @param[in] size Size of the range, in bytes. + * @param[in] val0 State0 + * @param[in] val1 State1 + * @return Result code. + * @remark See switchbrew.org Wiki for more details. + * @note Syscall number 0x02. + */ Result svcSetMemoryAttribute(void* addr, u64 size, u32 val0, u32 val1); + +/** + * @brief Maps a memory range into a different range. Mainly used for adding guard pages around stack. + * Source range gets reprotected to Perm_None (it can no longer be accessed), and \ref MemAttr_IsBorrowed is set in the source \ref MemoryAttribute. + * @param[in] dst_addr Destination address. + * @param[in] src_addr Source address. + * @param[in] size Size of the range. + * @return Result code. + * @note Syscall number 0x04. + */ Result svcMapMemory(void* dst_addr, void* src_addr, u64 size); + +/** + * @brief Unmaps a region that was previously mapped with \ref svcMapMemory. + * @param[in] dst_addr Destination address. + * @param[in] src_addr Source address. + * @param[in] size Size of the range. + * @return Result code. + * @note Syscall number 0x05. + */ Result svcUnmapMemory(void* dst_addr, void* src_addr, u64 size); + +/** + * @brief Query information about an address. Will always fetch the lowest page-aligned mapping that contains the provided address. + * @param[out] meminfo_ptr \ref MemoryInfo structure which will be filled in. + * @param[out] page_info Page information which will be filled in. + * @param[in] addr Address to query. + * @return Result code. + * @note Syscall number 0x06. + */ Result svcQueryMemory(MemoryInfo* meminfo_ptr, u32 *pageinfo, u64 addr); + +///@} + +///@name Process and thread management +///@{ + void NORETURN svcExitProcess(void); Result svcCreateThread(Handle* out, void* entry, void* arg, void* stack_top, int prio, int cpuid); Result svcStartThread(Handle handle); void NORETURN svcExitThread(void); Result svcSleepThread(u64 nano); + +///@} + +///@name Synchronization +///@{ + Result svcClearEvent(Handle handle); -Result svcCloseHandle(Handle handle); -Result svcResetSignal(Handle handle); + +///@} + +///@name Inter-process memory sharing +///@{ + Result svcMapSharedMemory(Handle handle, void* addr, size_t size, u32 perm); Result svcUnmapSharedMemory(Handle handle, void* addr, size_t size); Result svcCreateTransferMemory(Handle* out, void* addr, size_t size, u32 perm); + +///@} + +///@name Miscellaneous +///@{ + +/** + * @brief Closes a handle, decrementing the reference count of the corresponding kernel object. + * This might result in the kernel freeing the object. + * @param handle Handle to close. + * @return Result code. + * @note Syscall number 0x16. + */ +Result svcCloseHandle(Handle handle); + +///@} + +///@name Synchronization +///@{ + +Result svcResetSignal(Handle handle); + +///@} + +///@name Synchronization +///@{ + Result svcWaitSynchronization(s32* index, const Handle* handles, s32 handleCount, u64 timeout); -Result svcCancelSynchronization(Handle thread); -Result svcArbitrateLock(u32 wait_tag, u32* tag_location, u32 self_tag); -Result svcArbitrateUnlock(u32* tag_location); -Result svcWaitProcessWideKeyAtomic(u32* key, u32* tag_location, u32 self_tag, u64 timeout); -Result svcSignalProcessWideKey(u32* key, s32 num); -Result svcConnectToNamedPort(Handle* session, const char* name); -u64 svcGetSystemTick(void); -Result svcSendSyncRequest(Handle session); -Result svcGetProcessId(u64 *processID, Handle handle); -Result svcBreak(u32 breakReason, u64 inval1, u64 inval2); -Result svcOutputDebugString(const char *str, u64 size); -Result svcGetInfo(u64* out, u64 id0, Handle handle, u64 id1); -Result svcSetThreadActivity(Handle thread, bool paused); -Result svcCreateSession(Handle *server_handle, Handle *client_handle, u32 unk0, u64 unk1);//unk* are normally 0? -Result svcAcceptSession(Handle *session_handle, Handle port_handle); -Result svcReplyAndReceive(s32* index, const Handle* handles, s32 handleCount, Handle replyTarget, u64 timeout); -Result svcCreateJitMemory(Handle* jit_handle, void* src_addr, u64 size); -Result svcMapJitMemory(Handle jit_handle, JitMapOperation op, void* dst_addr, u64 size, u64 perm); -Result svcCreateSharedMemory(Handle* out, size_t size, u32 local_perm, u32 other_perm); -Result svcMapTransferMemory(Handle tmem_handle, void* addr, size_t size, u32 perm); -Result svcUnmapTransferMemory(Handle tmem_handle, void* addr, size_t size); -Result svcQueryPhysicalAddress(u64 out[3], u64 virtaddr); -Result svcQueryIoMapping(u64* virtaddr, u64 physaddr, u64 size); -Result svcCreateDeviceAddressSpace(Handle *handle, u64 dev_addr, u64 dev_size); -Result svcAttachDeviceAddressSpace(u64 device, Handle handle); -Result svcDetachDeviceAddressSpace(u64 device, Handle handle); -Result svcMapDeviceAddressSpaceAligned(Handle handle, Handle proc_handle, u64 dev_addr, u64 dev_size, u64 map_addr, u64 perm); -Result svcUnmapDeviceAddressSpace(Handle handle, Handle proc_handle, u64 map_addr, u64 map_size, u64 perm); -Result svcDebugActiveProcess(Handle* debug, u64 processID); -Result svcBreakDebugProcess(Handle debug); -Result svcGetDebugEvent(u8* event_out, Handle* debug); -Result svcContinueDebugEvent(Handle debug, u32 flags, u64 unk); -Result svcGetDebugThreadContext(u8* out, Handle debug, u64 threadID, u32 flags); -Result svcGetProcessList(u32 *num_out, u64 *pids_out, u32 max_pids); -Result svcQueryDebugProcessMemory(MemoryInfo* meminfo_ptr, u32* pageinfo, Handle debug, u64 addr); -Result svcReadDebugProcessMemory(void* buffer, Handle debug, u64 addr, u64 size); -Result svcWriteDebugProcessMemory(Handle debug, void* buffer, u64 addr, u64 size); -Result svcManageNamedPort(Handle* portServer, const char* name, s32 maxSessions); -Result svcSetProcessMemoryPermission(Handle proc, u64 addr, u64 size, u32 perm); -Result svcMapProcessMemory(void* dst, Handle proc, u64 src, u64 size); -Result svcMapProcessCodeMemory(Handle proc, u64 dst, u64 src, u64 size); -Result svcUnmapProcessCodeMemory(Handle proc, u64 dst, u64 src, u64 size); -Result svcCreateProcess(Handle* out, void* proc_info, u32* caps, u64 cap_num); -Result svcStartProcess(Handle proc, s32 main_prio, s32 default_cpu, u32 stack_size); -u64 svcCallSecureMonitor(SecmonArgs* regs); static inline Result svcWaitSynchronizationSingle(Handle handle, u64 timeout) { s32 tmp; return svcWaitSynchronization(&tmp, &handle, 1, timeout); } + +Result svcCancelSynchronization(Handle thread); +Result svcArbitrateLock(u32 wait_tag, u32* tag_location, u32 self_tag); +Result svcArbitrateUnlock(u32* tag_location); +Result svcWaitProcessWideKeyAtomic(u32* key, u32* tag_location, u32 self_tag, u64 timeout); +Result svcSignalProcessWideKey(u32* key, s32 num); + +///@} + +///@name Miscellaneous +///@{ + +/** + * @brief Gets the current system tick. + * @return The current system tick. + * @note Syscall number 0x1E. + */ +u64 svcGetSystemTick(void); + +///@} + +///@name Inter-process communication (IPC) +///@{ + +Result svcConnectToNamedPort(Handle* session, const char* name); +Result svcSendSyncRequest(Handle session); + +///@} + +///@name Process and thread management +///@{ + +Result svcGetProcessId(u64 *processID, Handle handle); + +///@} + +///@name Miscellaneous +///@{ + +/** + * @brief Breaks execution. Panic. + * @param[in] breakReason Break reason. + * @param[in] inval1 First break parameter. + * @param[in] inval2 Second break parameter. + * @return Result code. + * @note Syscall number 0x26. + */ +Result svcBreak(u32 breakReason, u64 inval1, u64 inval2); + +///@} + +///@name Debugging +///@{ + +Result svcOutputDebugString(const char *str, u64 size); + +///@} + +///@name Miscellaneous +///@{ + +/** + * @brief Retrieves information about the system, or a certain kernel object. + * @param[out] out Variable to which store the information. + * @param[in] id0 First ID of the property to retrieve. + * @param[in] handle Handle of the object to retrieve information from, or \ref INVALID_HANDLE to retrieve information about the system. + * @param[in] id1 Second ID of the property to retrieve. + * @return Result code. + * @remark The full list of property IDs can be found on the switchbrew.org wiki. + * @note Syscall number 0x29. + */ +Result svcGetInfo(u64* out, u64 id0, Handle handle, u64 id1); + +///@} + +///@name Process and thread management +///@{ + +Result svcSetThreadActivity(Handle thread, bool paused); + +///@} + +///@name Inter-process communication (IPC) +///@{ + +Result svcCreateSession(Handle *server_handle, Handle *client_handle, u32 unk0, u64 unk1);//unk* are normally 0? +Result svcAcceptSession(Handle *session_handle, Handle port_handle); +Result svcReplyAndReceive(s32* index, const Handle* handles, s32 handleCount, Handle replyTarget, u64 timeout); + +///@} + +///@name Just-in-time (JIT) compilation support +///@{ + +Result svcCreateJitMemory(Handle* jit_handle, void* src_addr, u64 size); +Result svcMapJitMemory(Handle jit_handle, JitMapOperation op, void* dst_addr, u64 size, u64 perm); + +///@} + +///@name Inter-process memory sharing +///@{ + +Result svcCreateSharedMemory(Handle* out, size_t size, u32 local_perm, u32 other_perm); +Result svcMapTransferMemory(Handle tmem_handle, void* addr, size_t size, u32 perm); +Result svcUnmapTransferMemory(Handle tmem_handle, void* addr, size_t size); + +///@} + +///@name Device memory-mapped I/O (MMIO) +///@{ + +Result svcQueryPhysicalAddress(u64 out[3], u64 virtaddr); +Result svcQueryIoMapping(u64* virtaddr, u64 physaddr, u64 size); + +///@} + +///@name I/O memory management unit (IOMMU) +///@{ + +Result svcCreateDeviceAddressSpace(Handle *handle, u64 dev_addr, u64 dev_size); +Result svcAttachDeviceAddressSpace(u64 device, Handle handle); +Result svcDetachDeviceAddressSpace(u64 device, Handle handle); +Result svcMapDeviceAddressSpaceAligned(Handle handle, Handle proc_handle, u64 dev_addr, u64 dev_size, u64 map_addr, u64 perm); +Result svcUnmapDeviceAddressSpace(Handle handle, Handle proc_handle, u64 map_addr, u64 map_size, u64 perm); + +///@} + +///@name Debugging +///@{ + +Result svcDebugActiveProcess(Handle* debug, u64 processID); +Result svcBreakDebugProcess(Handle debug); +Result svcGetDebugEvent(u8* event_out, Handle* debug); +Result svcContinueDebugEvent(Handle debug, u32 flags, u64 unk); +Result svcGetDebugThreadContext(u8* out, Handle debug, u64 threadID, u32 flags); + +///@} + +///@name Process and thread management +///@{ + +Result svcGetProcessList(u32 *num_out, u64 *pids_out, u32 max_pids); + +///@} + +///@name Debugging +///@{ + +Result svcQueryDebugProcessMemory(MemoryInfo* meminfo_ptr, u32* pageinfo, Handle debug, u64 addr); +Result svcReadDebugProcessMemory(void* buffer, Handle debug, u64 addr, u64 size); +Result svcWriteDebugProcessMemory(Handle debug, void* buffer, u64 addr, u64 size); + +///@} + +///@name Inter-process communication (IPC) +///@{ + +Result svcManageNamedPort(Handle* portServer, const char* name, s32 maxSessions); + +///@} + +///@name Memory management +///@{ + +/** + * @brief Sets the memory permissions for the specified memory with the supplied process handle. + * @param[in] proc Process handle. + * @param[in] addr Address of the memory. + * @param[in] size Size of the memory. + * @param[in] perm Permissions (see \ref Permission). + * @return Result code. + * @remark This returns an error (0xD801) when \p perm is >0x5, hence -WX and RWX are not allowed. + * @note Syscall number 0x73. + * @warning This is a privileged syscall. Use \ref envIsSyscallHinted to check if it is available. + */ +Result svcSetProcessMemoryPermission(Handle proc, u64 addr, u64 size, u32 perm); + +/** + * @brief Maps the src address from the supplied process handle into the current process. + * @param[in] dst Address to which map the memory in the current process. + * @param[in] proc Process handle. + * @param[in] src Address of the memory in the process. + * @param[in] size Size of the memory. + * @return Result code. + * @remark This allows mapping code and rodata with RW- permission. + * @note Syscall number 0x74. + * @warning This is a privileged syscall. Use \ref envIsSyscallHinted to check if it is available. + */ +Result svcMapProcessMemory(void* dst, Handle proc, u64 src, u64 size); + +/** + * @brief Maps normal heap in a certain process as executable code (used when loading NROs). + * @param[in] proc Process handle (cannot be \ref CUR_PROCESS_HANDLE). + * @param[in] dst Destination mapping address. + * @param[in] src Source mapping address. + * @param[in] size Size of the mapping. + * @return Result code. + * @note Syscall number 0x77. + * @warning This is a privileged syscall. Use \ref envIsSyscallHinted to check if it is available. + */ +Result svcMapProcessCodeMemory(Handle proc, u64 dst, u64 src, u64 size); + +/** + * @brief Undoes the effects of \ref svcMapProcessCodeMemory. + * @param[in] proc Process handle (cannot be \ref CUR_PROCESS_HANDLE). + * @param[in] dst Destination mapping address. + * @param[in] src Source mapping address. + * @param[in] size Size of the mapping. + * @return Result code. + * @note Syscall number 0x78. + * @warning This is a privileged syscall. Use \ref envIsSyscallHinted to check if it is available. + */ +Result svcUnmapProcessCodeMemory(Handle proc, u64 dst, u64 src, u64 size); + +///@} + +///@name Process and thread management +///@{ + +Result svcCreateProcess(Handle* out, void* proc_info, u32* caps, u64 cap_num); +Result svcStartProcess(Handle proc, s32 main_prio, s32 default_cpu, u32 stack_size); + +///@} + +///@name ( ͡° ͜ʖ ͡°) +///@{ + +/** + * @brief Calls a secure monitor function (TrustZone, EL3). + * @param regs Arguments to pass to the secure monitor. + * @return Return value from the secure monitor. + * @note Syscall number 0x7F. + * @warning This is a privileged syscall. Use \ref envIsSyscallHinted to check if it is available. + */ +u64 svcCallSecureMonitor(SecmonArgs* regs); + +///@}