diff --git a/libctru/Doxyfile b/libctru/Doxyfile index 3a3be9f..f109dd9 100644 --- a/libctru/Doxyfile +++ b/libctru/Doxyfile @@ -743,7 +743,7 @@ WARN_LOGFILE = # spaces. # Note: If this tag is empty the current directory is searched. -INPUT = +INPUT = source include # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses @@ -763,7 +763,7 @@ INPUT_ENCODING = UTF-8 # *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, # *.qsf, *.as and *.js. -FILE_PATTERNS = +FILE_PATTERNS = *.h *.c *.cpp *.s # The RECURSIVE tag can be used to specify whether or not subdirectories should # be searched for input files as well. @@ -811,7 +811,7 @@ EXCLUDE_SYMBOLS = # that contain example code fragments that are included (see the \include # command). -EXAMPLE_PATH = +EXAMPLE_PATH = ../examples # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and diff --git a/libctru/include/3ds.h b/libctru/include/3ds.h index 4b213a5..d43bfe5 100644 --- a/libctru/include/3ds.h +++ b/libctru/include/3ds.h @@ -49,3 +49,24 @@ extern "C" { #ifdef __cplusplus } #endif +/** + * @example app_launch/source/main.c + * @example audio/mic/source/main.c + * @example get_system_language/source/main.c + * @example gpu/source/main.c + * @example graphics/bitmap/24bit-color/source/main.c + * @example graphics/printing/hello-world/source/main.c + * @example graphics/printing/both-screen-text/source/main.c + * @example graphics/printing/colored-text/source/main.c + * @example graphics/printing/multiple-windows-text/source/main.c + * @example http/source/main.c + * @example input/read-controls/source/main.c + * @example input/touch-screen/source/main.c + * @example libapplet_launch/source/main.c + * @example mvd/source/main.c + * @example qtm/source/main.c + * @example sdmc/source/main.c + * @example threads/event/source/main.c + * @example time/rtc/source/main.c + */ + \ No newline at end of file diff --git a/libctru/include/3ds/gfx.h b/libctru/include/3ds/gfx.h index 1d0e545..4d7a660 100644 --- a/libctru/include/3ds/gfx.h +++ b/libctru/include/3ds/gfx.h @@ -1,3 +1,11 @@ +/** + * @file gfx.h + * @brief LCD Screens manipulation + * + * This header provides functions to configure and manipulate the two screens, including double buffering and 3D activation. + * It is mainly an abstraction over the gsp service. + */ + #pragma once #include <3ds/types.h> #include <3ds/services/gsp.h> @@ -11,29 +19,129 @@ typedef enum GFX_BOTTOM = 1 }gfxScreen_t; +/** + * @brief Side of top screen framebuffer. + * + * This is to be used only when the 3D is enabled. + * Use only GFX_LEFT if this concerns the bottom screen or if 3D is disabled. + */ typedef enum { - GFX_LEFT = 0, - GFX_RIGHT = 1, + GFX_LEFT = 0, ///< Left eye framebuffer + GFX_RIGHT = 1,///< Right eye framebuffer // GFX_BOTTOM = 0 }gfx3dSide_t; -//system stuff -void gfxInitDefault(); -void gfxInit(GSP_FramebufferFormats topFormat, GSP_FramebufferFormats bottomFormat, bool vrambuffers); -void gfxExit(); -//control stuff +///@name System related +///@{ + +/** + * @brief Initializes the LCD framebuffers with default parameters + * + * By default ctrulib will configure the LCD framebuffers with the @ref GSP_BGR8_OES format in linear memory. + * This is the same as calling : @code gfxInit(GSP_BGR8_OES,GSP_BGR8_OES,false); @endcode + * + * @note You should always call @ref gfxExit once done to free the memory and services + */ +void gfxInitDefault(); + +/** + * @brief Initializes the LCD framebuffers + * @brief topFormat The format of the top screen framebuffers + * @brief bottomFormat The format of the bottom screen framebuffers + * + * This function will allocate the memory for the framebuffers and open a gsp service session. + * It will also bind the newly allocated framebuffers to the LCD screen and setup the VBlank event. + * + * The 3D stereoscopic display is will be disabled. + * + * @note Even if the double buffering is disabled, it will allocate two buffer per screen. + * @note You should always call @ref gfxExit once done to free the memory and services + */ +void gfxInit(GSP_FramebufferFormats topFormat, GSP_FramebufferFormats bottomFormat, bool vrambuffers); + +/** + * @brief Closes the gsp service and frees the framebuffers. + * + * Just call it when you're done. + */ +void gfxExit(); +///@} + +///@name Control +///@{ +/** + * @brief Enables the 3D stereoscopic effect. + * @param enable Enables the 3D effect if true, disables it if false. + */ void gfxSet3D(bool enable); + +/** + * @brief Changes the color format of a screen + * @param screen The screen of which format should be changed + * @param format One of the gsp pixel formats. + */ void gfxSetScreenFormat(gfxScreen_t screen, GSP_FramebufferFormats format); + +/** + * @brief Gets a screen pixel format. + * @return the pixel format of the chosen screen set by ctrulib. + */ GSP_FramebufferFormats gfxGetScreenFormat(gfxScreen_t screen); + +/** + * @brief Enables the ctrulib double buffering + * + * ctrulib is by default using a double buffering scheme. + * If you do not want to swap one of the screen framebuffers when @ref gfxSwapBuffers or @ref gfxSwapBuffers is called, + * then you have to disable double buffering. + * + * It is however recommended to call @ref gfxSwapBuffers even if double buffering is disabled + * for both screens if you want to keep the gsp configuration up to date. + */ void gfxSetDoubleBuffering(gfxScreen_t screen, bool doubleBuffering); + +/** + * @brief Flushes the current framebuffers + * + * Use this if the data within your framebuffers changes a lot and that you want to make sure everything was updated correctly. + * This shouldn't be needed and has a significant overhead. + */ void gfxFlushBuffers(); + +/** + * @brief Swaps the buffers and sets the gsp state + * + * This is to be called to update the gsp state and swap the framebuffers. + * LCD rendering should start as soon as the gsp state is set. + * When using the GPU, call @ref gfxSwapBuffers instead. + */ void gfxSwapBuffers(); + +/** + * @brief Swaps the framebuffers + * + * This is the version to be used with the GPU since the GPU will use the gsp shared memory, + * so the gsp state mustn't be set directly by the user. + */ void gfxSwapBuffersGpu(); -//helper stuff +///@} + + +///@name Helper +///@{ +/** + * @brief Retrieves a framebuffer information + * @param width Pointer that will hold the width of the framebuffer in pixels + * @param height Pointer that will hold the height of the framebuffer in pixels + * @return a pointer to the current framebuffer of the choosen screen + * + * Please remember that the returned pointer will change after each call to gfxSwapBuffers if double buffering is enabled. + */ u8* gfxGetFramebuffer(gfxScreen_t screen, gfx3dSide_t side, u16* width, u16* height); +///@} //global variables extern u8* gfxTopLeftFramebuffers[2]; diff --git a/libctru/include/3ds/os.h b/libctru/include/3ds/os.h index 78eaa4a..ec9c1d0 100644 --- a/libctru/include/3ds/os.h +++ b/libctru/include/3ds/os.h @@ -1,3 +1,8 @@ +/** + * @file os.h + * + * OS related stuff. + */ #pragma once #define SYSTEM_VERSION(major, minor, revision) \ @@ -7,14 +12,52 @@ #define GET_VERSION_MINOR(version) (((version)>>16)&0xFF) #define GET_VERSION_REVISION(version) (((version)>> 8)&0xFF) +/** + * Converts an address from virtual (process) memory to physical memory. + * It is sometimes required by services or when using the GPU command buffer. + */ u32 osConvertVirtToPhys(u32 vaddr); -u32 osConvertOldLINEARMemToNew(u32 addr);//Converts 0x14* vmem to 0x30*. Returns the input addr when it's already within the new vmem. Returns 0 when outside of either LINEAR mem areas. + +/** + * Converts 0x14* vmem to 0x30*. + * @return The input address when it's already within the new vmem. + * @return 0 when outside of either LINEAR mem areas. + */ +u32 osConvertOldLINEARMemToNew(u32 addr); + +/** + * @brief Basic information about a service error. + * @return A string of the summary of an error. + * + * This can be used to get some details about an error returned by a service call. + */ const char* osStrError(u32 error); + +/** + * @return the Firm version + * + * This can be used to compare system versions easily with @ref SYSTEM_VERSION. + */ u32 osGetFirmVersion(); + +/** + * @return the kernel version + * + * This can be used to compare system versions easily with @ref SYSTEM_VERSION. + * + * @code + * if(osGetKernelVersion() > SYSTEM_VERSION(2,46,0)) printf("You are running 9.0 or higher\n"); + * @endcode + */ u32 osGetKernelVersion(); + +/** + * @return number of milliseconds since 1st Jan 1900 00:00. + */ u64 osGetTime(); -/* @brief Returns the Wifi signal strength. +/** + * @brief Returns the Wifi signal strength. * * Valid values are 0-3: * - 0 means the singal strength is terrible or the 3DS is disconnected from diff --git a/libctru/include/3ds/services/y2r.h b/libctru/include/3ds/services/y2r.h index 40b284b..62cf3bf 100644 --- a/libctru/include/3ds/services/y2r.h +++ b/libctru/include/3ds/services/y2r.h @@ -1,5 +1,6 @@ /** * @file y2r.h + * @brief Y2R service for hardware YUV->RGB conversions */ #pragma once #include <3ds/types.h> diff --git a/libctru/include/3ds/svc.h b/libctru/include/3ds/svc.h index c865f61..7593939 100644 --- a/libctru/include/3ds/svc.h +++ b/libctru/include/3ds/svc.h @@ -1,17 +1,39 @@ -/* - svc.h _ Syscall wrappers. -*/ +/** + * @file svc.h + * @brief Syscall wrappers. + */ #pragma once -typedef enum { - MEMOP_FREE =1, // Free heap - MEMOP_ALLOC=3, // Allocate heap - MEMOP_MAP =4, // Mirror mapping - MEMOP_UNMAP=5, // Mirror unmapping - MEMOP_PROT =6, // Change protection +#include "types.h" + + +///@name Memory management +///@{ + +/** + * @brief @ref svcControlMemory operation flags + * + * The lowest 8 bits are the operation + */ +typedef enum { + MEMOP_FREE = 1, ///< Memory un-mapping + MEMOP_RESERVE = 2, ///< Reserve memory + MEMOP_ALLOC = 3, ///< Memory mapping + MEMOP_MAP = 4, ///< Mirror mapping + MEMOP_UNMAP = 5, ///< Mirror unmapping + MEMOP_PROT = 6, ///< Change protection + + MEMOP_REGION_APP = 0x100, + MEMOP_REGION_SYSTEM = 0x200, + MEMOP_REGION_BASE = 0x300, + + MEMOP_OP_MASK = 0xFF, + MEMOP_REGION_MASK = 0xF00, + MEMOP_LINEAR_FLAG = 0x10000, ///< Flag for linear memory operations + + MEMOP_ALLOC_LINEAR = MEMOP_LINEAR_FLAG | MEMOP_ALLOC, - MEMOP_ALLOC_LINEAR=0x10003 // Allocate linear heap } MemOp; typedef enum { @@ -29,19 +51,21 @@ typedef enum { MEMSTATE_LOCKED = 11 } MemState; +/** + * @brief Memory permission flags + */ typedef enum { MEMPERM_READ = 1, MEMPERM_WRITE = 2, MEMPERM_EXECUTE = 4, - MEMPERM_DONTCARE = 0x10000000, - MEMPERM_MAX = 0xFFFFFFFF //force 4-byte + MEMPERM_DONTCARE = 0x10000000 } MemPerm; typedef struct { u32 base_addr; u32 size; - u32 perm; - u32 state; + u32 perm; ///< See @ref MemPerm + u32 state; ///< See @ref MemState } MemInfo; typedef struct { @@ -49,41 +73,49 @@ typedef struct { } PageInfo; typedef enum { - ARBITER_FREE =0, - ARBITER_ACQUIRE =1, - ARBITER_KERNEL2 =2, - ARBITER_ACQUIRE_TIMEOUT=3, - ARBITER_KERNEL4 =4, + ARBITER_FREE = 0, + ARBITER_ACQUIRE = 1, + ARBITER_KERNEL2 = 2, + ARBITER_ACQUIRE_TIMEOUT = 3, + ARBITER_KERNEL4 = 4, } ArbitrationType; -typedef enum { - DBG_EVENT_PROCESS = 0, - DBG_EVENT_CREATE_THREAD = 1, - DBG_EVENT_EXIT_THREAD = 2, - DBG_EVENT_EXIT_PROCESS = 3, - DBG_EVENT_EXCEPTION = 4, - DBG_EVENT_DLL_LOAD = 5, - DBG_EVENT_DLL_UNLOAD = 6, - DBG_EVENT_SCHEDULE_IN = 7, - DBG_EVENT_SCHEDULE_OUT = 8, - DBG_EVENT_SYSCALL_IN = 9, - DBG_EVENT_SYSCALL_OUT = 10, - DBG_EVENT_OUTPUT_STRING = 11, - DBG_EVENT_MAP = 12 -} DebugEventType; +///@} +///@name Multithreading +///@{ + +typedef enum { + THREADINFO_TYPE_UNKNOWN +} ThreadInfoType; + +///@} + + +///@name Debugging +///@{ typedef enum { REASON_CREATE = 1, REASON_ATTACH = 2 } ProcessEventReason; - + typedef struct { u64 program_id; u8 process_name[8]; u32 process_id; - u32 reason; + u32 reason; ///< See @ref ProcessEventReason } ProcessEvent; +typedef enum { + EXITPROCESS_EVENT_NONE = 0, + EXITPROCESS_EVENT_TERMINATE = 1, + EXITPROCESS_EVENT_UNHANDLED_EXCEPTION = 2 +} ExitProcessEventReason; + +typedef struct { + u32 reason; ///< See @ref ExitProcessEventReason +} ExitProcessEvent; + typedef struct { u32 creator_thread_id; u32 base_addr; @@ -97,50 +129,33 @@ typedef enum { EXITTHREAD_EVENT_TERMINATE_PROCESS = 3 } ExitThreadEventReason; -typedef enum { - EXITPROCESS_EVENT_NONE = 0, - EXITPROCESS_EVENT_TERMINATE = 1, - EXITPROCESS_EVENT_UNHANDLED_EXCEPTION = 2 -} ExitProcessEventReason; - typedef struct { - u32 reason; -} ExitProcessEvent; - -typedef struct { - u32 reason; + u32 reason; ///< See @ref ExitThreadEventReason } ExitThreadEvent; -typedef struct { - u32 type; - u32 address; - u32 argument; -} ExceptionEvent; - -typedef enum { - EXC_EVENT_UNDEFINED_INSTRUCTION = 0, // arg: (None) - EXC_EVENT_UNKNOWN1 = 1, // arg: (None) - EXC_EVENT_UNKNOWN2 = 2, // arg: address - EXC_EVENT_UNKNOWN3 = 3, // arg: address - EXC_EVENT_ATTACH_BREAK = 4, // arg: (None) - EXC_EVENT_BREAKPOINT = 5, // arg: (None) - EXC_EVENT_USER_BREAK = 6, // arg: user break type - EXC_EVENT_DEBUGGER_BREAK = 7, // arg: (None) - EXC_EVENT_UNDEFINED_SYSCALL = 8 // arg: attempted syscall -} ExceptionEventType; - typedef enum { USERBREAK_PANIC = 0, USERBREAK_ASSERT = 1, USERBREAK_USER = 2 } UserBreakType; -/** -* Type of the query for svcGetThreadInfo -*/ typedef enum { - THREADINFO_TYPE_UNKNOWN -} ThreadInfoType; + EXC_EVENT_UNDEFINED_INSTRUCTION = 0, ///< arg: (None) + EXC_EVENT_UNKNOWN1 = 1, ///< arg: (None) + EXC_EVENT_UNKNOWN2 = 2, ///< arg: address + EXC_EVENT_UNKNOWN3 = 3, ///< arg: address + EXC_EVENT_ATTACH_BREAK = 4, ///< arg: (None) + EXC_EVENT_BREAKPOINT = 5, ///< arg: (None) + EXC_EVENT_USER_BREAK = 6, ///< arg: @ref UserBreakType + EXC_EVENT_DEBUGGER_BREAK = 7, ///< arg: (None) + EXC_EVENT_UNDEFINED_SYSCALL = 8 ///< arg: attempted syscall +} ExceptionEventType; + +typedef struct { + u32 type; ///< See @ref ExceptionEventType + u32 address; + u32 argument; ///< See @ref ExceptionEventType +} ExceptionEvent; typedef struct { u64 clock_tick; @@ -163,8 +178,24 @@ typedef struct { u32 memstate; } MapEvent; +typedef enum { + DBG_EVENT_PROCESS = 0, + DBG_EVENT_CREATE_THREAD = 1, + DBG_EVENT_EXIT_THREAD = 2, + DBG_EVENT_EXIT_PROCESS = 3, + DBG_EVENT_EXCEPTION = 4, + DBG_EVENT_DLL_LOAD = 5, + DBG_EVENT_DLL_UNLOAD = 6, + DBG_EVENT_SCHEDULE_IN = 7, + DBG_EVENT_SCHEDULE_OUT = 8, + DBG_EVENT_SYSCALL_IN = 9, + DBG_EVENT_SYSCALL_OUT = 10, + DBG_EVENT_OUTPUT_STRING = 11, + DBG_EVENT_MAP = 12 +} DebugEventType; + typedef struct { - u32 type; + u32 type; ///< See @ref DebugEventType u32 thread_id; u32 unknown[2]; union { @@ -178,10 +209,12 @@ typedef struct { SchedulerInOutEvent scheduler; SyscallInOutEvent syscall; OutputStringEvent output_string; - MapEvent map; + MapEvent map; }; } DebugEventInfo; +///@} + static inline void* getThreadLocalStorage(void) { void* ret; @@ -194,62 +227,212 @@ static inline u32* getThreadCommandBuffer(void) return (u32*)((u8*)getThreadLocalStorage() + 0x80); } -s32 svcControlMemory(u32* addr_out, u32 addr0, u32 addr1, u32 size, MemOp op, MemPerm perm); -s32 svcQueryMemory(MemInfo* info, PageInfo* out, u32 addr); -void __attribute__((noreturn)) svcExitProcess(); -s32 svcCreateThread(Handle* thread, ThreadFunc entrypoint, u32 arg, u32* stack_top, s32 thread_priority, s32 processor_id); -void __attribute__((noreturn)) svcExitThread(); -void svcSleepThread(s64 ns); -s32 svcGetThreadPriority(s32 *out, Handle handle); -s32 svcSetThreadPriority(Handle thread, s32 prio); -s32 svcGetThreadAffinityMask(u8* affinitymask, Handle thread, s32 processorcount); -s32 svcSetThreadAffinityMask(Handle thread, u8* affinitymask, s32 processorcount); -s32 svcGetThreadIdealProcessor(s32* processorid, Handle thread); -s32 svcSetThreadIdealProcessor(Handle thread, s32 processorid); -s32 svcGetProcessorID(); -s32 svcCreateMutex(Handle* mutex, bool initially_locked); -s32 svcReleaseMutex(Handle handle); -s32 svcCreateSemaphore(Handle* semaphore, s32 initial_count, s32 max_count); -s32 svcReleaseSemaphore(s32* count, Handle semaphore, s32 release_count); -s32 svcCreateEvent(Handle* event, u8 reset_type); -s32 svcSignalEvent(Handle handle); -s32 svcClearEvent(Handle handle); -s32 svcCreateTimer(Handle* timer, u8 reset_type); -s32 svcSetTimer(Handle timer, s64 initial, s64 interval); -s32 svcCancelTimer(Handle timer); -s32 svcClearTimer(Handle timer); -s32 svcCreateMemoryBlock(Handle* memblock, u32 addr, u32 size, MemPerm my_perm, MemPerm other_perm); -s32 svcMapMemoryBlock(Handle memblock, u32 addr, MemPerm my_perm, MemPerm other_perm); -s32 svcUnmapMemoryBlock(Handle memblock, u32 addr); -s32 svcCreateAddressArbiter(Handle *arbiter); -s32 svcArbitrateAddress(Handle arbiter, u32 addr, ArbitrationType type, s32 value, s64 nanoseconds); -s32 svcWaitSynchronization(Handle handle, s64 nanoseconds); -s32 svcWaitSynchronizationN(s32* out, Handle* handles, s32 handles_num, bool wait_all, s64 nanoseconds); -s32 svcCloseHandle(Handle handle); -s32 svcDuplicateHandle(Handle* out, Handle original); -u64 svcGetSystemTick(); -s32 svcGetSystemInfo(s64* out, u32 type, s32 param); -s32 svcGetProcessInfo(s64* out, Handle process, u32 type); -s32 svcGetThreadInfo(s64* out, Handle thread, ThreadInfoType type); -s32 svcConnectToPort(volatile Handle* out, const char* portName); -s32 svcSendSyncRequest(Handle session); +///@name Memory management +///@{ + +/** + * @brief Controls memory mapping + * @param[out] addr_out The virtual address resulting from the operation. Usually the same as addr0. + * @param addr0 The virtual address to be used for the operation. + * @param addr1 The virtual address to be (un)mirrored by @p addr0 when using @ref MEMOP_MAP or @ref MEMOP_UNMAP. + * It has to be pointing to a RW memory. + * Use NULL if the operation is @ref MEMOP_FREE or @ref MEMOP_ALLOC. + * @param size The requested size for @ref MEMOP_ALLOC and @ref MEMOP_ALLOC_LINEAR. + * @param op Operation flags. See @ref MemOp. + * @param perm A combination of @ref MEMPERM_READ and @ref MEMPERM_WRITE. Using MEMPERM_EXECUTE will return an error. + * Value 0 is used when unmapping memory. + * + * If a memory is mapped for two or more addresses, you have to use MEMOP_UNMAP before being able to MEMOP_FREE it. + * MEMOP_MAP will fail if @p addr1 was already mapped to another address. + * + * More information is available at http://3dbrew.org/wiki/SVC#Memory_Mapping. + * + * @sa svcControlProcessMemory + */ +Result svcControlMemory(u32* addr_out, u32 addr0, u32 addr1, u32 size, MemOp op, MemPerm perm); + +/** + * @brief Controls the memory mapping of a process + * @param addr0 The virtual address to map + * @param addr1 The virtual address to be mapped by @p addr0 + * @param type Only operations @ref MEMOP_MAP, @ref MEMOP_UNMAP and @ref MEMOP_PROT are allowed. + * + * This is the only SVC which allows mapping executable memory. + * Using @ref MEMOP_PROT will change the memory permissions of an already mapped memory. + * + * @note The pseudo handle for the current process is not supported by this service call. + * @sa svcControlProcess + */ +Result svcControlProcessMemory(Handle process, u32 addr0, u32 addr1, u32 size, u32 type, u32 perm); + +Result svcCreateMemoryBlock(Handle* memblock, u32 addr, u32 size, MemPerm my_perm, MemPerm other_perm); +Result svcMapMemoryBlock(Handle memblock, u32 addr, MemPerm my_perm, MemPerm other_perm); +Result svcMapProcessMemory(Handle process, u32 startAddr, u32 endAddr); +Result svcUnmapProcessMemory(Handle process, u32 startAddr, u32 endAddr); +Result svcUnmapMemoryBlock(Handle memblock, u32 addr); +/** + * @brief Memory information query + * @param addr Virtual memory address + */ +Result svcQueryMemory(MemInfo* info, PageInfo* out, u32 addr); +Result svcQueryProcessMemory(MemInfo* info, PageInfo* out, Handle process, u32 addr); + +Result svcCreateAddressArbiter(Handle *arbiter); +Result svcArbitrateAddress(Handle arbiter, u32 addr, ArbitrationType type, s32 value, s64 nanoseconds); + +Result svcReadProcessMemory(void* buffer, Handle debug, u32 addr, u32 size); +Result svcWriteProcessMemory(Handle debug, const void* buffer, u32 addr, u32 size); +///@} + + +///@name Process management +///@{ + +/** + * @brief Gets the handle of a process. + * @param[out] process The handle of the process + * @param processId The ID of the process to open + */ Result svcOpenProcess(Handle* process, u32 processId); -Result svcOpenThread(Handle* thread,Handle process, u32 threadId); -s32 svcGetProcessId(u32 *out, Handle handle); -s32 svcGetProcessIdOfThread(u32 *out, Handle handle); -s32 svcGetThreadId(u32 *out, Handle handle); -s32 svcOutputDebugString(const char* str, int length); +void svcExitProcess() __attribute__((noreturn)); + +Result svcGetProcessInfo(s64* out, Handle process, u32 type); +Result svcGetProcessId(u32 *out, Handle handle); +Result svcGetProcessList(s32* processCount, u32* processIds, s32 processIdMaxCount); Result svcCreatePort(Handle* portServer, Handle* portClient, const char* name, s32 maxSessions); +Result svcConnectToPort(volatile Handle* out, const char* portName); +///@} + +///@name Multithreading +///@{ +/** + * @brief Creates a new thread. + * @param[out] thread The thread handle + * @param entrypoint The function that will be called first upon thread creation + * @param arg The argument passed to @p entrypoint + * @param stack_top The top of the thread's stack. Must be 0x8 bytes mem-aligned. + * @param thread_priority Low values gives the thread higher priority. + * For userland app, this has to be withing the range [0x18;0x3F] + * @param processor_id The id of the processor the thread should be ran on. Those are labelled starting from 0. + * For old 3ds it has to be <2, and for new 3DS <4. + * Value -1 means all CPUs and -2 read from the Exheader. + * + * The processor with ID 1 is the system processor. + * To enable multi-threading on this core you need to call APT_SetAppCpuTimeLimit at least once with a non-zero value. + * + * Since a thread is considered as a waitable object, you can use @ref svcWaitSynchronization + * and @ref svcWaitSynchronizationN to join with it. + * + * @note The kernel will clear the @p stack_top's address low 3 bits to make sure it is 0x8-bytes aligned. + */ +Result svcCreateThread(Handle* thread, ThreadFunc entrypoint, u32 arg, u32* stack_top, s32 thread_priority, s32 processor_id); + +/** + * @brief Gets the handle of a thread. + * @param[out] thread The handle of the thread + * @param process The ID of the process linked to the thread + */ +Result svcOpenThread(Handle* thread,Handle process, u32 threadId); + +/** + * @brief Exits the current thread. + * + * This will trigger a state change and hence release all @ref svcWaitSynchronization operations. + * It means that you can join a thread by calling @code svcWaitSynchronization(threadHandle,yourtimeout); @endcode + */ +void svcExitThread(void) __attribute__((noreturn)); + +/** + * @brief Puts the current thread to sleep. + * @param ns The minimum number of nanoseconds to sleep for. + */ +void svcSleepThread(s64 ns); + +/** + * @brief Retrieves the priority of a thread. + */ +Result svcGetThreadPriority(s32 *out, Handle handle); + +/** + * @brief Changes the priority of a thread + * @param prio For userland apps, this has to be withing the range [0x18;0x3F] + * + * Low values gives the thread higher priority. + */ +Result svcSetThreadPriority(Handle thread, s32 prio); +Result svcGetThreadAffinityMask(u8* affinitymask, Handle thread, s32 processorcount); +Result svcSetThreadAffinityMask(Handle thread, u8* affinitymask, s32 processorcount); +Result svcGetThreadIdealProcessor(s32* processorid, Handle thread); +Result svcSetThreadIdealProcessor(Handle thread, s32 processorid); + +/** + * @brief Returns the ID of the processor the current thread is running on. + * @sa svcCreateThread + */ +s32 svcGetProcessorID(); + +/** + * @param out The thread ID of the thread @p handle. + */ +Result svcGetThreadId(u32 *out, Handle handle); + +/** + * @param out The process ID of the thread @p handle. + * @sa svcOpenProcess + */ +Result svcGetProcessIdOfThread(u32 *out, Handle handle); + +/** + * @brief Checks if a thread handle is valid. + * This requests always return an error when called, it only checks if the handle is a thread or not. + * @return 0xD8E007ED (BAD_ENUM) if the Handle is a Thread Handle + * @return 0xD8E007F7 (BAD_HANDLE) if it isn't. + */ +Result svcGetThreadInfo(s64* out, Handle thread, ThreadInfoType type); +///@} + + +///@name Synchronization +///@{ +Result svcCreateMutex(Handle* mutex, bool initially_locked); +Result svcReleaseMutex(Handle handle); +Result svcCreateSemaphore(Handle* semaphore, s32 initial_count, s32 max_count); +Result svcReleaseSemaphore(s32* count, Handle semaphore, s32 release_count); +Result svcCreateEvent(Handle* event, u8 reset_type); +Result svcSignalEvent(Handle handle); +Result svcClearEvent(Handle handle); +Result svcWaitSynchronization(Handle handle, s64 nanoseconds); +Result svcWaitSynchronizationN(s32* out, Handle* handles, s32 handles_num, bool wait_all, s64 nanoseconds); +Result svcSendSyncRequest(Handle session); +///@} + +///@name Time +///@{ +Result svcCreateTimer(Handle* timer, u8 reset_type); +Result svcSetTimer(Handle timer, s64 initial, s64 interval); +Result svcCancelTimer(Handle timer); +Result svcClearTimer(Handle timer); +u64 svcGetSystemTick(); +///@} + +///@name System +///@{ +Result svcCloseHandle(Handle handle); +Result svcDuplicateHandle(Handle* out, Handle original); +Result svcGetSystemInfo(s64* out, u32 type, s32 param); +///@} + + +///@name Debugging +///@{ +Result svcOutputDebugString(const char* str, int length); Result svcDebugActiveProcess(Handle* debug, u32 processId); Result svcBreakDebugProcess(Handle debug); Result svcTerminateDebugProcess(Handle debug); Result svcGetProcessDebugEvent(DebugEventInfo* info, Handle debug); Result svcContinueDebugEvent(Handle debug, u32 flags); -Result svcGetProcessList(s32* processCount, u32* processIds, s32 processIdMaxCount); -Result svcReadProcessMemory(void* buffer, Handle debug, u32 addr, u32 size); -Result svcWriteProcessMemory(Handle debug, const void* buffer, u32 addr, u32 size); -Result svcControlProcessMemory(Handle process, u32 addr0, u32 addr1, u32 size, u32 type, u32 perm); -Result svcMapProcessMemory(Handle process, u32 startAddr, u32 endAddr); -Result svcUnmapProcessMemory(Handle process, u32 startAddr, u32 endAddr); +///@} + Result svcBackdoor(s32 (*callback)(void)); -Result svcQueryProcessMemory(MemInfo* info, PageInfo* out, Handle process, u32 addr); + +