From 32566006532af14c2d5a466724153ee26f1b5d4e Mon Sep 17 00:00:00 2001 From: Joey Yakimowich-Payne Date: Sun, 24 Jun 2018 11:59:50 +0900 Subject: [PATCH] Fix issues with static inline headers --- src/libnx/ext/integer128.nim | 10 +- src/libnx/wrapper/nx/include/switch/arm/tls.h | 8 +- src/libnx/wrapper/nx/include/switch/gfx/gfx.h | 63 ++- .../wrapper/nx/include/switch/gfx/ioctl.h | 62 +-- .../nx/include/switch/kernel/condvar.h | 25 +- .../wrapper/nx/include/switch/kernel/ipc.h | 472 +++++++++++++++--- .../wrapper/nx/include/switch/kernel/shmem.h | 18 +- .../wrapper/nx/include/switch/kernel/svc.h | 351 ++++++------- .../switch/runtime/devices/romfs_dev.h | 54 +- .../wrapper/nx/include/switch/services/hid.h | 40 +- .../wrapper/nx/include/switch/services/sm.h | 117 +++-- src/libnx/wrapper/sm.nim | 2 +- 12 files changed, 829 insertions(+), 393 deletions(-) diff --git a/src/libnx/ext/integer128.nim b/src/libnx/ext/integer128.nim index c44a9f3..676e653 100644 --- a/src/libnx/ext/integer128.nim +++ b/src/libnx/ext/integer128.nim @@ -1,5 +1,4 @@ -{.emit:"typedef __uint128_t NU128; typedef __int128_t NI128;".} - +import strutils # Capacity of 42 because it seems # reasonable that the number will fit. # If it doesn't, nim will just allocate @@ -7,11 +6,11 @@ const STRING_CAPACITY = 42 type - s128* {.importc: "NI128"} = object + s128* {.importc: "__int128_t"} = object high: int64 low: uint64 - u128* {.importc: "NU128"} = object + u128* {.importc: "__uint128_t"} = object high, low: uint64 helperInt128 = object @@ -327,6 +326,9 @@ proc `$`*(val: s128): string = result = str +proc toHex*(val: u128): string = + result = val.hi.toHex & val.lo.toHex + proc `$`*(val: u128): string = var v = val diff --git a/src/libnx/wrapper/nx/include/switch/arm/tls.h b/src/libnx/wrapper/nx/include/switch/arm/tls.h index 32a7014..e24ac85 100644 --- a/src/libnx/wrapper/nx/include/switch/arm/tls.h +++ b/src/libnx/wrapper/nx/include/switch/arm/tls.h @@ -6,9 +6,13 @@ */ #pragma once #include "../types.h" - + /** * @brief Gets the thread local storage buffer. * @return The thread local storage buffer. */ -static inline void* armGetTls(void); +static inline void* armGetTls(void) { + void* ret; + __asm__ ("mrs %x[data], tpidrro_el0" : [data] "=r" (ret)); + return ret; +} diff --git a/src/libnx/wrapper/nx/include/switch/gfx/gfx.h b/src/libnx/wrapper/nx/include/switch/gfx/gfx.h index d64325f..590f909 100644 --- a/src/libnx/wrapper/nx/include/switch/gfx/gfx.h +++ b/src/libnx/wrapper/nx/include/switch/gfx/gfx.h @@ -7,13 +7,13 @@ */ #pragma once #include "../types.h" - + /// Converts red, green, blue, and alpha components to packed RGBA8. #define RGBA8(r,g,b,a) (((r)&0xff)|(((g)&0xff)<<8)|(((b)&0xff)<<16)|(((a)&0xff)<<24)) - + /// Same as \ref RGBA8 except with alpha=0xff. #define RGBA8_MAXALPHA(r,g,b) RGBA8(r,g,b,0xff) - + /// GfxMode set by \ref gfxSetMode. The default is GfxMode_LinearDouble. Note that the text-console (see console.h) sets this to GfxMode_TiledDouble. typedef enum { @@ -21,21 +21,21 @@ typedef enum GfxMode_TiledDouble, ///< Double-buffering with raw tiled (block-linear) framebuffer. GfxMode_LinearDouble ///< Double-buffering with linear framebuffer, which is transferred to the actual framebuffer by \ref gfxFlushBuffers(). } GfxMode; - + /// Framebuffer pixel-format is RGBA8888, there's no known way to change this. - + /** * @brief Initializes the graphics subsystem. * @warning Do not use \ref viInitialize when using this function. */ void gfxInitDefault(void); - + /** * @brief Uninitializes the graphics subsystem. * @warning Do not use \ref viExit when using this function. */ void gfxExit(void); - + /** * @brief Sets the resolution to be used when initializing the graphics subsystem. * @param[in] width Horizontal resolution, in pixels. @@ -46,10 +46,10 @@ void gfxExit(void); * @note The width and height are aligned to 4. */ void gfxInitResolution(u32 width, u32 height); - + /// Wrapper for \ref gfxInitResolution with resolution=1080p. Use this if you want to support 1080p or >720p in docked-mode. void gfxInitResolutionDefault(void); - + /// Configure framebuffer crop, by default crop is all-zero. Use all-zero input to reset to default. \ref gfxExit resets this to the default. /// When the input is invalid this returns without changing the crop data, this includes the input values being larger than the framebuf width/height. /// This will update the display width/height returned by \ref gfxGetFramebuffer, with that width/height being reset to the default when required. @@ -57,44 +57,61 @@ void gfxInitResolutionDefault(void); /// The new crop config will not take affect with double-buffering disabled. When used during frame-drawing, this should be called before \ref gfxGetFramebuffer. /// The right and bottom params are aligned to 4. void gfxConfigureCrop(s32 left, s32 top, s32 right, s32 bottom); - + /// Wrapper for \ref gfxConfigureCrop. Use this to set the resolution, within the bounds of the maximum resolution. Use all-zero input to reset to default. void gfxConfigureResolution(s32 width, s32 height); - + /// If enabled, \ref gfxConfigureResolution will be used with the input resolution for the current OperationMode. Then \ref gfxConfigureResolution will automatically be used with the specified resolution each time OperationMode changes. void gfxConfigureAutoResolution(bool enable, s32 handheld_width, s32 handheld_height, s32 docked_width, s32 docked_height); - + /// Wrapper for \ref gfxConfigureAutoResolution. handheld_resolution=720p, docked_resolution={all-zero for using current maximum resolution}. void gfxConfigureAutoResolutionDefault(bool enable); - + /// Waits for vertical sync. void gfxWaitForVsync(void); - + /// Swaps the framebuffers (for double-buffering). void gfxSwapBuffers(void); - + /// Get the current framebuffer address, with optional output ptrs for the display framebuffer width/height. The display width/height is adjusted by \ref gfxConfigureCrop and \ref gfxConfigureResolution. u8* gfxGetFramebuffer(u32* width, u32* height); - + /// Get the framebuffer width/height without crop. void gfxGetFramebufferResolution(u32* width, u32* height); - + /// Use this to get the actual byte-size of the framebuffer for use with memset/etc. size_t gfxGetFramebufferSize(void); - + /// Sets the \ref GfxMode. void gfxSetMode(GfxMode mode); - + /// Controls whether a vertical-flip is done when determining the pixel-offset within the actual framebuffer. By default this is enabled. void gfxSetDrawFlip(bool flip); - + /// Configures transform. See the NATIVE_WINDOW_TRANSFORM_* enums in buffer_producer.h. The default is NATIVE_WINDOW_TRANSFORM_FLIP_V. void gfxConfigureTransform(u32 transform); - + /// Flushes the framebuffer in the data cache. When \ref GfxMode is GfxMode_LinearDouble, this also transfers the linear-framebuffer to the actual framebuffer. void gfxFlushBuffers(void); - + /// Use this to get the pixel-offset in the framebuffer. Returned value is in pixels, not bytes. /// This implements tegra blocklinear, with hard-coded constants etc. /// Do not use this when \ref GfxMode is GfxMode_LinearDouble. -static inline u32 gfxGetFramebufferDisplayOffset(u32 x, u32 y); +static inline u32 gfxGetFramebufferDisplayOffset(u32 x, u32 y) { + u32 tmp_pos; + + extern size_t g_gfx_framebuf_aligned_width; + extern size_t g_gfx_framebuf_display_height; + extern bool g_gfx_drawflip; + + //if (x >= g_gfx_framebuf_width || y >= g_gfx_framebuf_display_height) return (gfxGetFramebufferSize()-4)/4;//Return the last pixel-offset in the buffer, the data located here is not displayed due to alignment. (Disabled for perf) + + if (g_gfx_drawflip) y = g_gfx_framebuf_display_height-1-y; + + tmp_pos = ((y & 127) / 16) + (x/16*8) + ((y/16/8)*(g_gfx_framebuf_aligned_width/16*8)); + tmp_pos *= 16*16 * 4; + + tmp_pos += ((y%16)/8)*512 + ((x%16)/8)*256 + ((y%8)/2)*64 + ((x%8)/4)*32 + (y%2)*16 + (x%4)*4;//This line is a modified version of code from the Tegra X1 datasheet. + + return tmp_pos / 4; +} diff --git a/src/libnx/wrapper/nx/include/switch/gfx/ioctl.h b/src/libnx/wrapper/nx/include/switch/gfx/ioctl.h index 0187318..5af6089 100644 --- a/src/libnx/wrapper/nx/include/switch/gfx/ioctl.h +++ b/src/libnx/wrapper/nx/include/switch/gfx/ioctl.h @@ -2,46 +2,46 @@ //The below defines are based on Linux kernel ioctl.h. -#define UNV_IOC_NRBITS 8 -#define UNV_IOC_TYPEBITS 8 -#define UNV_IOC_SIZEBITS 14 -#define UNV_IOC_DIRBITS 2 +#define _NV_IOC_NRBITS 8 +#define _NV_IOC_TYPEBITS 8 +#define _NV_IOC_SIZEBITS 14 +#define _NV_IOC_DIRBITS 2 -#define UNV_IOC_NRMASK ((1 << UNV_IOC_NRBITS)-1) -#define UNV_IOC_TYPEMASK ((1 << UNV_IOC_TYPEBITS)-1) -#define UNV_IOC_SIZEMASK ((1 << UNV_IOC_SIZEBITS)-1) -#define UNV_IOC_DIRMASK ((1 << UNV_IOC_DIRBITS)-1) +#define _NV_IOC_NRMASK ((1 << _NV_IOC_NRBITS)-1) +#define _NV_IOC_TYPEMASK ((1 << _NV_IOC_TYPEBITS)-1) +#define _NV_IOC_SIZEMASK ((1 << _NV_IOC_SIZEBITS)-1) +#define _NV_IOC_DIRMASK ((1 << _NV_IOC_DIRBITS)-1) -#define UNV_IOC_NRSHIFT 0 -#define UNV_IOC_TYPESHIFT (UNV_IOC_NRSHIFT+UNV_IOC_NRBITS) -#define UNV_IOC_SIZESHIFT (UNV_IOC_TYPESHIFT+UNV_IOC_TYPEBITS) -#define UNV_IOC_DIRSHIFT (UNV_IOC_SIZESHIFT+UNV_IOC_SIZEBITS) +#define _NV_IOC_NRSHIFT 0 +#define _NV_IOC_TYPESHIFT (_NV_IOC_NRSHIFT+_NV_IOC_NRBITS) +#define _NV_IOC_SIZESHIFT (_NV_IOC_TYPESHIFT+_NV_IOC_TYPEBITS) +#define _NV_IOC_DIRSHIFT (_NV_IOC_SIZESHIFT+_NV_IOC_SIZEBITS) /* * Direction bits. */ -#define UNV_IOC_NONE 0U -#define UNV_IOC_WRITE 1U -#define UNV_IOC_READ 2U +#define _NV_IOC_NONE 0U +#define _NV_IOC_WRITE 1U +#define _NV_IOC_READ 2U -#define UNV_IOC(dir,type,nr,size) \ - (((dir) << UNV_IOC_DIRSHIFT) | \ - ((type) << UNV_IOC_TYPESHIFT) | \ - ((nr) << UNV_IOC_NRSHIFT) | \ - ((size) << UNV_IOC_SIZESHIFT)) +#define _NV_IOC(dir,type,nr,size) \ + (((dir) << _NV_IOC_DIRSHIFT) | \ + ((type) << _NV_IOC_TYPESHIFT) | \ + ((nr) << _NV_IOC_NRSHIFT) | \ + ((size) << _NV_IOC_SIZESHIFT)) /* used to create numbers */ -#define UNV_IO(type,nr) UNV_IOC(UNV_IOC_NONE,(type),(nr),0) -#define UNV_IOR(type,nr,size) UNV_IOC(UNV_IOC_READ,(type),(nr),sizeof(size)) -#define UNV_IOW(type,nr,size) UNV_IOC(UNV_IOC_WRITE,(type),(nr),sizeof(size)) -#define UNV_IOWR(type,nr,size) UNV_IOC(UNV_IOC_READ|UNV_IOC_WRITE,(type),(nr),sizeof(size)) +#define _NV_IO(type,nr) _NV_IOC(_NV_IOC_NONE,(type),(nr),0) +#define _NV_IOR(type,nr,size) _NV_IOC(_NV_IOC_READ,(type),(nr),sizeof(size)) +#define _NV_IOW(type,nr,size) _NV_IOC(_NV_IOC_WRITE,(type),(nr),sizeof(size)) +#define _NV_IOWR(type,nr,size) _NV_IOC(_NV_IOC_READ|_NV_IOC_WRITE,(type),(nr),sizeof(size)) /* used to decode ioctl numbers.. */ -#define UNV_IOC_DIR(nr) (((nr) >> UNV_IOC_DIRSHIFT) & UNV_IOC_DIRMASK) -#define UNV_IOC_TYPE(nr) (((nr) >> UNV_IOC_TYPESHIFT) & UNV_IOC_TYPEMASK) -#define UNV_IOC_NR(nr) (((nr) >> UNV_IOC_NRSHIFT) & UNV_IOC_NRMASK) -#define UNV_IOC_SIZE(nr) (((nr) >> UNV_IOC_SIZESHIFT) & UNV_IOC_SIZEMASK) +#define _NV_IOC_DIR(nr) (((nr) >> _NV_IOC_DIRSHIFT) & _NV_IOC_DIRMASK) +#define _NV_IOC_TYPE(nr) (((nr) >> _NV_IOC_TYPESHIFT) & _NV_IOC_TYPEMASK) +#define _NV_IOC_NR(nr) (((nr) >> _NV_IOC_NRSHIFT) & _NV_IOC_NRMASK) +#define _NV_IOC_SIZE(nr) (((nr) >> _NV_IOC_SIZESHIFT) & _NV_IOC_SIZEMASK) -#define DUnv_in -#define DUnv_out -#define DUnv_inout +#define __nv_in +#define __nv_out +#define __nv_inout diff --git a/src/libnx/wrapper/nx/include/switch/kernel/condvar.h b/src/libnx/wrapper/nx/include/switch/kernel/condvar.h index 096d094..cd428b7 100644 --- a/src/libnx/wrapper/nx/include/switch/kernel/condvar.h +++ b/src/libnx/wrapper/nx/include/switch/kernel/condvar.h @@ -6,20 +6,20 @@ */ #include "../types.h" #include "../kernel/mutex.h" - + /// Condition variable structure. typedef struct { u32 tag; Mutex* mutex; } CondVar; - + /** * @brief Initializes a condition variable. * @param[in] c Condition variable object. * @param[in] m Mutex object to use inside the condition variable. */ void condvarInit(CondVar* c, Mutex* m); - + /** * @brief Waits on a condition variable with a timeout. * @param[in] c Condition variable object. @@ -28,7 +28,7 @@ void condvarInit(CondVar* c, Mutex* m); * @remark On function return, the underlying mutex is acquired. */ Result condvarWaitTimeout(CondVar* c, u64 timeout); - + /** * @brief Waits on a condition variable. * @param[in] c Condition variable object. @@ -36,7 +36,10 @@ Result condvarWaitTimeout(CondVar* c, u64 timeout); * @remark On function return, the underlying mutex is acquired. */ static inline Result condvarWait(CondVar* c) -; +{ + return condvarWaitTimeout(c, -1ull); +} + /** * @brief Wakes up up to the specified number of threads waiting on a condition variable. * @param[in] c Condition variable object. @@ -44,17 +47,23 @@ static inline Result condvarWait(CondVar* c) * @return Result code. */ Result condvarWake(CondVar* c, int num); - + /** * @brief Wakes up a single thread waiting on a condition variable. * @param[in] c Condition variable object. * @return Result code. */ static inline Result condvarWakeOne(CondVar* c) -; +{ + return condvarWake(c, 1); +} + /** * @brief Wakes up all thread waiting on a condition variable. * @param[in] c Condition variable object. * @return Result code. */ -static inline Result condvarWakeAll(CondVar* c); +static inline Result condvarWakeAll(CondVar* c) +{ + return condvarWake(c, -1); +} diff --git a/src/libnx/wrapper/nx/include/switch/kernel/ipc.h b/src/libnx/wrapper/nx/include/switch/kernel/ipc.h index 77da92f..ce99815 100644 --- a/src/libnx/wrapper/nx/include/switch/kernel/ipc.h +++ b/src/libnx/wrapper/nx/include/switch/kernel/ipc.h @@ -8,35 +8,35 @@ #include "../result.h" #include "../arm/tls.h" #include "../kernel/svc.h" - + /// IPC input header magic #define SFCI_MAGIC 0x49434653 /// IPC output header magic #define SFCO_MAGIC 0x4f434653 - + /// IPC invalid object ID #define IPC_INVALID_OBJECT_ID UINT32_MAX - + ///@name IPC request building ///@{ - + /// IPC command (request) structure. #define IPC_MAX_BUFFERS 8 #define IPC_MAX_OBJECTS 8 - + typedef enum { BufferType_Normal=0, ///< Regular buffer. BufferType_Type1=1, ///< Allows ProcessMemory and shared TransferMemory. BufferType_Invalid=2, BufferType_Type3=3 ///< Same as Type1 except remote process is not allowed to use device-mapping. } BufferType; - + typedef enum { BufferDirection_Send=0, BufferDirection_Recv=1, BufferDirection_Exch=2, } BufferDirection; - + typedef enum { IpcCommandType_Invalid = 0, IpcCommandType_LegacyRequest = 1, @@ -47,7 +47,7 @@ typedef enum { IpcCommandType_RequestWithContext = 6, IpcCommandType_ControlWithContext = 7 } IpcCommandType; - + typedef struct { size_t NumSend; // A size_t NumRecv; // B @@ -55,47 +55,49 @@ typedef struct { const void* Buffers[IPC_MAX_BUFFERS]; size_t BufferSizes[IPC_MAX_BUFFERS]; BufferType BufferTypes[IPC_MAX_BUFFERS]; - + size_t NumStaticIn; // X size_t NumStaticOut; // C const void* Statics[IPC_MAX_BUFFERS]; size_t StaticSizes[IPC_MAX_BUFFERS]; u8 StaticIndices[IPC_MAX_BUFFERS]; - + bool SendPid; size_t NumHandlesCopy; size_t NumHandlesMove; Handle Handles[IPC_MAX_OBJECTS]; - + size_t NumObjectIds; u32 ObjectIds[IPC_MAX_OBJECTS]; } IpcCommand; - + /** * @brief Initializes an IPC command structure. * @param cmd IPC command structure. */ -static inline void ipcInitialize(IpcCommand* cmd); - +static inline void ipcInitialize(IpcCommand* cmd) { + *cmd = (IpcCommand){0}; +} + /// IPC buffer descriptor. typedef struct { u32 Size; ///< Size of the buffer. u32 Addr; ///< Lower 32-bits of the address of the buffer u32 Packed; ///< Packed data (including higher bits of the address) } IpcBufferDescriptor; - + /// IPC static send-buffer descriptor. typedef struct { u32 Packed; ///< Packed data (including higher bits of the address) u32 Addr; ///< Lower 32-bits of the address } IpcStaticSendDescriptor; - + /// IPC static receive-buffer descriptor. typedef struct { u32 Addr; ///< Lower 32-bits of the address of the buffer u32 Packed; ///< Packed data (including higher bits of the address) } IpcStaticRecvDescriptor; - + /** * @brief Adds a buffer to an IPC command structure. * @param cmd IPC command structure. @@ -103,8 +105,14 @@ typedef struct { * @param size Size of the buffer. * @param type Buffer type. */ -static inline void ipcAddSendBuffer(IpcCommand* cmd, const void* buffer, size_t size, BufferType type); - +static inline void ipcAddSendBuffer(IpcCommand* cmd, const void* buffer, size_t size, BufferType type) { + size_t off = cmd->NumSend; + cmd->Buffers[off] = buffer; + cmd->BufferSizes[off] = size; + cmd->BufferTypes[off] = type; + cmd->NumSend++; +} + /** * @brief Adds a receive-buffer to an IPC command structure. * @param cmd IPC command structure. @@ -112,8 +120,14 @@ static inline void ipcAddSendBuffer(IpcCommand* cmd, const void* buffer, size_t * @param size Size of the buffer. * @param type Buffer type. */ -static inline void ipcAddRecvBuffer(IpcCommand* cmd, void* buffer, size_t size, BufferType type); - +static inline void ipcAddRecvBuffer(IpcCommand* cmd, void* buffer, size_t size, BufferType type) { + size_t off = cmd->NumSend + cmd->NumRecv; + cmd->Buffers[off] = buffer; + cmd->BufferSizes[off] = size; + cmd->BufferTypes[off] = type; + cmd->NumRecv++; +} + /** * @brief Adds an exchange-buffer to an IPC command structure. * @param cmd IPC command structure. @@ -121,8 +135,14 @@ static inline void ipcAddRecvBuffer(IpcCommand* cmd, void* buffer, size_t size, * @param size Size of the buffer. * @param type Buffer type. */ -static inline void ipcAddExchBuffer(IpcCommand* cmd, void* buffer, size_t size, BufferType type); - +static inline void ipcAddExchBuffer(IpcCommand* cmd, void* buffer, size_t size, BufferType type) { + size_t off = cmd->NumSend + cmd->NumRecv + cmd->NumExch; + cmd->Buffers[off] = buffer; + cmd->BufferSizes[off] = size; + cmd->BufferTypes[off] = type; + cmd->NumExch++; +} + /** * @brief Adds a static-buffer to an IPC command structure. * @param cmd IPC command structure. @@ -130,8 +150,14 @@ static inline void ipcAddExchBuffer(IpcCommand* cmd, void* buffer, size_t size, * @param size Size of the buffer. * @param index Index of buffer. */ -static inline void ipcAddSendStatic(IpcCommand* cmd, const void* buffer, size_t size, u8 index); - +static inline void ipcAddSendStatic(IpcCommand* cmd, const void* buffer, size_t size, u8 index) { + size_t off = cmd->NumStaticIn; + cmd->Statics[off] = buffer; + cmd->StaticSizes[off] = size; + cmd->StaticIndices[off] = index; + cmd->NumStaticIn++; +} + /** * @brief Adds a static-receive-buffer to an IPC command structure. * @param cmd IPC command structure. @@ -139,8 +165,14 @@ static inline void ipcAddSendStatic(IpcCommand* cmd, const void* buffer, size_t * @param size Size of the buffer. * @param index Index of buffer. */ -static inline void ipcAddRecvStatic(IpcCommand* cmd, void* buffer, size_t size, u8 index); - +static inline void ipcAddRecvStatic(IpcCommand* cmd, void* buffer, size_t size, u8 index) { + size_t off = cmd->NumStaticIn + cmd->NumStaticOut; + cmd->Statics[off] = buffer; + cmd->StaticSizes[off] = size; + cmd->StaticIndices[off] = index; + cmd->NumStaticOut++; +} + /** * @brief Adds a smart-buffer (buffer + static-buffer pair) to an IPC command structure. * @param cmd IPC command structure. @@ -149,8 +181,16 @@ static inline void ipcAddRecvStatic(IpcCommand* cmd, void* buffer, size_t size, * @param size Size of the buffer. * @param index Index of buffer. */ -static inline void ipcAddSendSmart(IpcCommand* cmd, size_t ipc_buffer_size, const void* buffer, size_t size, u8 index); - +static inline void ipcAddSendSmart(IpcCommand* cmd, size_t ipc_buffer_size, const void* buffer, size_t size, u8 index) { + if (ipc_buffer_size != 0 && size <= ipc_buffer_size) { + ipcAddSendBuffer(cmd, NULL, 0, BufferType_Normal); + ipcAddSendStatic(cmd, buffer, size, index); + } else { + ipcAddSendBuffer(cmd, buffer, size, BufferType_Normal); + ipcAddSendStatic(cmd, NULL, 0, index); + } +} + /** * @brief Adds a smart-receive-buffer (buffer + static-receive-buffer pair) to an IPC command structure. * @param cmd IPC command structure. @@ -159,124 +199,377 @@ static inline void ipcAddSendSmart(IpcCommand* cmd, size_t ipc_buffer_size, cons * @param size Size of the buffer. * @param index Index of buffer. */ -static inline void ipcAddRecvSmart(IpcCommand* cmd, size_t ipc_buffer_size, void* buffer, size_t size, u8 index); - +static inline void ipcAddRecvSmart(IpcCommand* cmd, size_t ipc_buffer_size, void* buffer, size_t size, u8 index) { + if (ipc_buffer_size != 0 && size <= ipc_buffer_size) { + ipcAddRecvBuffer(cmd, NULL, 0, BufferType_Normal); + ipcAddRecvStatic(cmd, buffer, size, index); + } else { + ipcAddRecvBuffer(cmd, buffer, size, BufferType_Normal); + ipcAddRecvStatic(cmd, NULL, 0, index); + } +} + /** * @brief Tags an IPC command structure to send the PID. * @param cmd IPC command structure. */ -static inline void ipcSendPid(IpcCommand* cmd); - +static inline void ipcSendPid(IpcCommand* cmd) { + cmd->SendPid = true; +} + /** * @brief Adds a copy-handle to be sent through an IPC command structure. * @param cmd IPC command structure. * @param h Handle to send. * @remark The receiving process gets a copy of the handle. */ -static inline void ipcSendHandleCopy(IpcCommand* cmd, Handle h); - +static inline void ipcSendHandleCopy(IpcCommand* cmd, Handle h) { + cmd->Handles[cmd->NumHandlesCopy++] = h; +} + /** * @brief Adds a move-handle to be sent through an IPC command structure. * @param cmd IPC command structure. * @param h Handle to send. * @remark The sending process loses ownership of the handle, which is transferred to the receiving process. */ -static inline void ipcSendHandleMove(IpcCommand* cmd, Handle h); - +static inline void ipcSendHandleMove(IpcCommand* cmd, Handle h) { + cmd->Handles[cmd->NumHandlesCopy + cmd->NumHandlesMove++] = h; +} + /** * @brief Prepares the header of an IPC command structure. * @param cmd IPC command structure. * @param sizeof_raw Size in bytes of the raw data structure to embed inside the IPC request * @return Pointer to the raw embedded data structure in the request, ready to be filled out. */ -static inline void* ipcPrepareHeader(IpcCommand* cmd, size_t sizeof_raw); - +static inline void* ipcPrepareHeader(IpcCommand* cmd, size_t sizeof_raw) { + u32* buf = (u32*)armGetTls(); + size_t i; + *buf++ = IpcCommandType_Request | (cmd->NumStaticIn << 16) | (cmd->NumSend << 20) | (cmd->NumRecv << 24) | (cmd->NumExch << 28); + + u32* fill_in_size_later = buf; + + if (cmd->NumStaticOut > 0) { + *buf = (cmd->NumStaticOut + 2) << 10; + } + else { + *buf = 0; + } + + if (cmd->SendPid || cmd->NumHandlesCopy > 0 || cmd->NumHandlesMove > 0) { + *buf++ |= 0x80000000; + *buf++ = (!!cmd->SendPid) | (cmd->NumHandlesCopy << 1) | (cmd->NumHandlesMove << 5); + + if (cmd->SendPid) + buf += 2; + + for (i=0; i<(cmd->NumHandlesCopy + cmd->NumHandlesMove); i++) + *buf++ = cmd->Handles[i]; + } + else { + buf++; + } + + for (i=0; iNumStaticIn; i++, buf+=2) { + IpcStaticSendDescriptor* desc = (IpcStaticSendDescriptor*) buf; + + uintptr_t ptr = (uintptr_t) cmd->Statics[i]; + desc->Addr = ptr; + desc->Packed = cmd->StaticIndices[i] | (cmd->StaticSizes[i] << 16) | + (((ptr >> 32) & 15) << 12) | (((ptr >> 36) & 15) << 6); + } + + for (i=0; i<(cmd->NumSend + cmd->NumRecv + cmd->NumExch); i++, buf+=3) { + IpcBufferDescriptor* desc = (IpcBufferDescriptor*) buf; + desc->Size = cmd->BufferSizes[i]; + + uintptr_t ptr = (uintptr_t) cmd->Buffers[i]; + desc->Addr = ptr; + desc->Packed = cmd->BufferTypes[i] | + (((ptr >> 32) & 15) << 28) | ((ptr >> 36) << 2); + } + + u32 padding = ((16 - (((uintptr_t) buf) & 15)) & 15) / 4; + u32* raw = (u32*) (buf + padding); + + size_t raw_size = (sizeof_raw/4) + 4; + buf += raw_size; + + u16* buf_u16 = (u16*) buf; + + for (i=0; iNumStaticOut; i++) { + size_t off = cmd->NumStaticIn + i; + size_t sz = (uintptr_t) cmd->StaticSizes[off]; + + buf_u16[i] = (sz > 0xFFFF) ? 0 : sz; + } + + size_t u16s_size = ((2*cmd->NumStaticOut) + 3)/4; + buf += u16s_size; + raw_size += u16s_size; + + *fill_in_size_later |= raw_size; + + for (i=0; iNumStaticOut; i++, buf+=2) { + IpcStaticRecvDescriptor* desc = (IpcStaticRecvDescriptor*) buf; + size_t off = cmd->NumStaticIn + i; + + uintptr_t ptr = (uintptr_t) cmd->Statics[off]; + desc->Addr = ptr; + desc->Packed = (ptr >> 32) | (cmd->StaticSizes[off] << 16); + } + + return (void*) raw; +} + /** * @brief Dispatches an IPC request. * @param session IPC session handle. * @return Result code. */ -static inline Result ipcDispatch(Handle session); - +static inline Result ipcDispatch(Handle session) { + return svcSendSyncRequest(session); +} + ///@} - + ///@name IPC response parsing ///@{ - + /// IPC parsed command (response) structure. typedef struct { IpcCommandType CommandType; ///< Type of the command bool HasPid; ///< true if the 'Pid' field is filled out. u64 Pid; ///< PID included in the response (only if HasPid is true) - + size_t NumHandles; ///< Number of handles copied. Handle Handles[IPC_MAX_OBJECTS]; ///< Handles. bool WasHandleCopied[IPC_MAX_OBJECTS]; ///< true if the handle was moved, false if it was copied. - + u32 ThisObjectId; ///< Object ID to call the command on (for domain messages). size_t NumObjectIds; ///< Number of object IDs (for domain messages). u32 ObjectIds[IPC_MAX_OBJECTS]; ///< Object IDs (for domain messages). - + size_t NumBuffers; ///< Number of buffers in the response. void* Buffers[IPC_MAX_BUFFERS]; ///< Pointers to the buffers. size_t BufferSizes[IPC_MAX_BUFFERS]; ///< Sizes of the buffers. BufferType BufferTypes[IPC_MAX_BUFFERS]; ///< Types of the buffers. BufferDirection BufferDirections[IPC_MAX_BUFFERS]; ///< Direction of each buffer. - + size_t NumStatics; ///< Number of statics in the response. void* Statics[IPC_MAX_BUFFERS]; ///< Pointers to the statics. size_t StaticSizes[IPC_MAX_BUFFERS]; ///< Sizes of the statics. u8 StaticIndices[IPC_MAX_BUFFERS]; ///< Indices of the statics. size_t NumStaticsOut; ///< Number of output statics available in the response. - + void* Raw; ///< Pointer to the raw embedded data structure in the response. void* RawWithoutPadding; ///< Pointer to the raw embedded data structure, without padding. size_t RawSize; ///< Size of the raw embedded data. } IpcParsedCommand; - + /** * @brief Parse an IPC command response into an IPC parsed command structure. * @param IPC parsed command structure to fill in. * @return Result code. */ -static inline Result ipcParse(IpcParsedCommand* r); - +static inline Result ipcParse(IpcParsedCommand* r) { + u32* buf = (u32*)armGetTls(); + u32 ctrl0 = *buf++; + u32 ctrl1 = *buf++; + size_t i; + + r->CommandType = (IpcCommandType) (ctrl0 & 0xffff); + r->HasPid = false; + r->RawSize = (ctrl1 & 0x1ff) * 4; + r->NumHandles = 0; + + r->NumStaticsOut = (ctrl1 >> 10) & 15; + if (r->NumStaticsOut >> 1) r->NumStaticsOut--; // Value 2 -> Single descriptor + if (r->NumStaticsOut >> 1) r->NumStaticsOut--; // Value 3+ -> (Value - 2) descriptors + + if (ctrl1 & 0x80000000) { + u32 ctrl2 = *buf++; + + if (ctrl2 & 1) { + r->HasPid = true; + r->Pid = *buf++; + r->Pid |= ((u64)(*buf++)) << 32; + } + + size_t num_handles_copy = ((ctrl2 >> 1) & 15); + size_t num_handles_move = ((ctrl2 >> 5) & 15); + + size_t num_handles = num_handles_copy + num_handles_move; + u32* buf_after_handles = buf + num_handles; + + if (num_handles > IPC_MAX_OBJECTS) + num_handles = IPC_MAX_OBJECTS; + + for (i=0; iHandles[i] = *(buf+i); + r->WasHandleCopied[i] = (i < num_handles_copy); + } + + r->NumHandles = num_handles; + buf = buf_after_handles; + } + + size_t num_statics = (ctrl0 >> 16) & 15; + u32* buf_after_statics = buf + num_statics*2; + + if (num_statics > IPC_MAX_BUFFERS) + num_statics = IPC_MAX_BUFFERS; + + for (i=0; iPacked; + + r->Statics[i] = (void*) (desc->Addr | (((packed >> 12) & 15) << 32) | (((packed >> 6) & 15) << 36)); + r->StaticSizes[i] = packed >> 16; + r->StaticIndices[i] = packed & 63; + } + + r->NumStatics = num_statics; + buf = buf_after_statics; + + size_t num_bufs_send = (ctrl0 >> 20) & 15; + size_t num_bufs_recv = (ctrl0 >> 24) & 15; + size_t num_bufs_exch = (ctrl0 >> 28) & 15; + + size_t num_bufs = num_bufs_send + num_bufs_recv + num_bufs_exch; + r->Raw = (void*)(((uintptr_t)(buf + num_bufs*3) + 15) &~ 15); + r->RawWithoutPadding = (void*)((uintptr_t)(buf + num_bufs*3)); + + if (num_bufs > IPC_MAX_BUFFERS) + num_bufs = IPC_MAX_BUFFERS; + + for (i=0; iPacked; + + r->Buffers[i] = (void*) (desc->Addr | ((packed >> 28) << 32) | (((packed >> 2) & 15) << 36)); + r->BufferSizes[i] = desc->Size; + r->BufferTypes[i] = (BufferType) (packed & 3); + + if (i < num_bufs_send) + r->BufferDirections[i] = BufferDirection_Send; + else if (i < (num_bufs_send + num_bufs_recv)) + r->BufferDirections[i] = BufferDirection_Recv; + else + r->BufferDirections[i] = BufferDirection_Exch; + } + + r->NumBuffers = num_bufs; + return 0; +} + /** * @brief Queries the size of an IPC pointer buffer. * @param session IPC session handle. * @param size Output variable in which to store the size. * @return Result code. */ -static inline Result ipcQueryPointerBufferSize(Handle session, size_t *size); - +static inline Result ipcQueryPointerBufferSize(Handle session, size_t *size) { + u32* buf = (u32*)armGetTls(); + + buf[0] = IpcCommandType_Control; + buf[1] = 8; + buf[2] = 0; + buf[3] = 0; + buf[4] = SFCI_MAGIC; + buf[5] = 0; + buf[6] = 3; + buf[7] = 0; + + Result rc = ipcDispatch(session); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + ipcParse(&r); + + struct ipcQueryPointerBufferSizeResponse { + u64 magic; + u64 result; + u32 size; + } *raw = (struct ipcQueryPointerBufferSizeResponse*)r.Raw; + + rc = raw->result; + + if (R_SUCCEEDED(rc)) { + *size = raw->size & 0xffff; + } + } + + return rc; +} + /** * @brief Closes the IPC session with proper clean up. * @param session IPC session handle. * @return Result code. */ -static inline Result ipcCloseSession(Handle session); +static inline Result ipcCloseSession(Handle session) { + u32* buf = (u32*)armGetTls(); + buf[0] = IpcCommandType_Close; + buf[1] = 0; + return ipcDispatch(session); +} ///@} - + ///@name IPC domain handling ///@{ - + /** * @brief Converts an IPC session handle into a domain. * @param session IPC session handle. * @param object_id_out Output variable in which to store the object ID. * @return Result code. */ -static inline Result ipcConvertSessionToDomain(Handle session, u32* object_id_out); - +static inline Result ipcConvertSessionToDomain(Handle session, u32* object_id_out) { + u32* buf = (u32*)armGetTls(); + + buf[0] = IpcCommandType_Control; + buf[1] = 8; + buf[4] = SFCI_MAGIC; + buf[5] = 0; + buf[6] = 0; + buf[7] = 0; + + Result rc = ipcDispatch(session); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + ipcParse(&r); + + struct ipcConvertSessionToDomainResponse { + u64 magic; + u64 result; + u32 object_id; + } *raw = (struct ipcConvertSessionToDomainResponse*)r.Raw; + + rc = raw->result; + + if (R_SUCCEEDED(rc)) { + *object_id_out = raw->object_id; + } + } + + return rc; +} + /** * @brief Adds an object ID to be sent through an IPC domain command structure. * @param cmd IPC domain command structure. * @param object_id Object ID to send. */ -static inline void ipcSendObjectId(IpcCommand* cmd, u32 object_id); - +static inline void ipcSendObjectId(IpcCommand* cmd, u32 object_id) { + cmd->ObjectIds[cmd->NumObjectIds++] = object_id; +} + /// IPC domain message header. typedef struct { u8 Type; @@ -285,7 +578,7 @@ typedef struct { u32 ThisObjectId; u32 Pad[2]; } DomainMessageHeader; - + /** * @brief Prepares the header of an IPC command structure (domain version). * @param cmd IPC command structure. @@ -293,21 +586,66 @@ typedef struct { * @oaram object_id Domain object ID. * @return Pointer to the raw embedded data structure in the request, ready to be filled out. */ -static inline void* ipcPrepareHeaderForDomain(IpcCommand* cmd, size_t sizeof_raw, u32 object_id); - +static inline void* ipcPrepareHeaderForDomain(IpcCommand* cmd, size_t sizeof_raw, u32 object_id) { + void* raw = ipcPrepareHeader(cmd, sizeof_raw + sizeof(DomainMessageHeader)); + DomainMessageHeader* hdr = (DomainMessageHeader*) raw; + u32 *object_ids = (u32*)(((uintptr_t) raw) + sizeof(DomainMessageHeader) + sizeof_raw); + + hdr->Type = 1; + hdr->NumObjectIds = (u8)cmd->NumObjectIds; + hdr->Length = sizeof_raw; + hdr->ThisObjectId = object_id; + hdr->Pad[0] = hdr->Pad[1] = 0; + + for(size_t i = 0; i < cmd->NumObjectIds; i++) + object_ids[i] = cmd->ObjectIds[i]; + return (void*)(((uintptr_t) raw) + sizeof(DomainMessageHeader)); +} + /** * @brief Parse an IPC command response into an IPC parsed command structure (domain version). * @param IPC parsed command structure to fill in. * @return Result code. */ -static inline Result ipcParseForDomain(IpcParsedCommand* r); - +static inline Result ipcParseForDomain(IpcParsedCommand* r) { + Result rc = ipcParse(r); + DomainMessageHeader* hdr; + u32 *object_ids; + if(R_FAILED(rc)) + return rc; + + hdr = (DomainMessageHeader*) r->Raw; + object_ids = (u32*)(((uintptr_t) hdr) + sizeof(DomainMessageHeader) + hdr->Length); + r->Raw = (void*)(((uintptr_t) r->Raw) + sizeof(DomainMessageHeader)); + + r->ThisObjectId = hdr->ThisObjectId; + r->NumObjectIds = hdr->NumObjectIds > 8 ? 8 : hdr->NumObjectIds; + for(size_t i = 0; i < r->NumObjectIds; i++) + r->ObjectIds[i] = object_ids[i]; + + return rc; +} + /** * @brief Closes a domain object by ID. * @param session IPC session handle. * @param object_id ID of the object to close. * @return Result code. */ -static inline Result ipcCloseObjectById(Handle session, u32 object_id); - +static inline Result ipcCloseObjectById(Handle session, u32 object_id) { + IpcCommand c; + DomainMessageHeader* hdr; + + ipcInitialize(&c); + hdr = (DomainMessageHeader*)ipcPrepareHeader(&c, sizeof(DomainMessageHeader)); + + hdr->Type = 2; + hdr->NumObjectIds = 0; + hdr->Length = 0; + hdr->ThisObjectId = object_id; + hdr->Pad[0] = hdr->Pad[1] = 0; + + return ipcDispatch(session); // this command has no associated response +} + ///@} diff --git a/src/libnx/wrapper/nx/include/switch/kernel/shmem.h b/src/libnx/wrapper/nx/include/switch/kernel/shmem.h index e2d8463..b40af1b 100644 --- a/src/libnx/wrapper/nx/include/switch/kernel/shmem.h +++ b/src/libnx/wrapper/nx/include/switch/kernel/shmem.h @@ -7,7 +7,7 @@ */ #pragma once #include "../types.h" - + /// Shared memory information structure. typedef struct { Handle handle; ///< Kernel object handle. @@ -15,7 +15,7 @@ typedef struct { Permission perm; ///< Permissions. void* map_addr; ///< Address to which the shared memory object is mapped. } SharedMemory; - + /** * @brief Creates a shared memory object. * @param s Shared memory information structure which will be filled in. @@ -26,7 +26,7 @@ typedef struct { * @warning This is a privileged operation; in normal circumstances applications cannot use this function. */ Result shmemCreate(SharedMemory* s, size_t size, Permission local_perm, Permission remote_perm); - + /** * @brief Loads a shared memory object coming from a remote process. * @param s Shared memory information structure which will be filled in. @@ -35,28 +35,30 @@ Result shmemCreate(SharedMemory* s, size_t size, Permission local_perm, Permissi * @param perm Permissions with which the shared memory object will be mapped in the local process. */ void shmemLoadRemote(SharedMemory* s, Handle handle, size_t size, Permission perm); - + /** * @brief Maps a shared memory object. * @param s Shared memory information structure. * @return Result code. */ Result shmemMap(SharedMemory* s); - + /** * @brief Unmaps a shared memory object. * @param s Shared memory information structure. * @return Result code. */ Result shmemUnmap(SharedMemory* s); - + /** * @brief Retrieves the mapped address of a shared memory object. * @param s Shared memory information structure. * @return Mapped address of the shared memory object. */ -static inline void* shmemGetAddr(SharedMemory* s); - +static inline void* shmemGetAddr(SharedMemory* s) { + return s->map_addr; +} + /** * @brief Frees up resources used by a shared memory object, unmapping and closing handles, etc. * @param s Shared memory information structure. diff --git a/src/libnx/wrapper/nx/include/switch/kernel/svc.h b/src/libnx/wrapper/nx/include/switch/kernel/svc.h index f7ffa30..0ae591c 100644 --- a/src/libnx/wrapper/nx/include/switch/kernel/svc.h +++ b/src/libnx/wrapper/nx/include/switch/kernel/svc.h @@ -5,13 +5,13 @@ */ #pragma once #include "../types.h" - + /// Pseudo handle for the current process. #define CUR_PROCESS_HANDLE 0xFFFF8001 - + /// Pseudo handle for the current thread. #define CUR_THREAD_HANDLE 0xFFFF8000 - + /// Memory type enumeration (lower 8 bits of \ref MemoryState) typedef enum { MemType_Unmapped=0x00, ///< Unmapped memory. @@ -37,7 +37,7 @@ typedef enum { MemType_CodeReadOnly=0x14, ///< Mapped in kernel during \ref svcControlCodeMemory. MemType_CodeWritable=0x15, ///< Mapped in kernel during \ref svcControlCodeMemory. } MemoryType; - + /// Memory state bitmasks. typedef enum { MemState_Type=0xFF, ///< Type field (see \ref MemoryType). @@ -60,7 +60,7 @@ typedef enum { MemState_AttrChangeAllowed=BIT(24), ///< Attribute change allowed. MemState_CodeMemAllowed=BIT(25), ///< Code memory allowed. } MemoryState; - + /// Memory attribute bitmasks. typedef enum { MemAttr_IsBorrowed=BIT(0), ///< Is borrowed memory. @@ -68,7 +68,7 @@ typedef enum { MemAttr_IsDeviceMapped=BIT(2), ///< Is device mapped (when DeviceRefCount > 0). MemAttr_IsUncached=BIT(3), ///< Is uncached. } MemoryAttribute; - + /// Memory permission bitmasks. typedef enum { Perm_None = 0, ///< No permissions. @@ -79,7 +79,7 @@ typedef enum { Perm_Rx = Perm_R | Perm_X, ///< Read/execute permissions. Perm_DontCare = BIT(28), ///< Don't care } Permission; - + /// Memory information structure. typedef struct { u64 addr; ///< Base address. @@ -91,12 +91,12 @@ typedef struct { u32 ipc_refcount; ///< IPC reference count. u32 padding; ///< Padding. } MemoryInfo; - + /// Secure monitor arguments. typedef struct { u64 X[8]; ///< Values of X0 through X7. -} SecmonArgs; - +} PACKED SecmonArgs; + /// Code memory mapping operations typedef enum { CodeMapOperation_MapOwner=0, ///< Map owner. @@ -104,7 +104,7 @@ typedef enum { CodeMapOperation_UnmapOwner=2, ///< Unmap owner. CodeMapOperation_UnmapSlave=3, ///< Unmap slave. } CodeMapOperation; - + /// Limitable Resources. typedef enum { LimitableResource_Memory=0, ///type == ServiceType_Override; +} + /** * @brief Returns whether a service has been initialized. * @param[in] s Service object. * @return true if initialized. */ -static inline bool serviceIsActive(Service* s); - +static inline bool serviceIsActive(Service* s) { + return s->type != ServiceType_Uninitialized; +} + /** * @brief Returns whether a service is a domain. * @param[in] s Service object. * @return true if a domain. */ -static inline bool serviceIsDomain(Service* s); - +static inline bool serviceIsDomain(Service* s) { + return s->type == ServiceType_Domain; +} + /** * @brief Returns whether a service is a domain subservice. * @param[in] s Service object. * @return true if a domain subservice. */ -static inline bool serviceIsDomainSubservice(Service* s); - +static inline bool serviceIsDomainSubservice(Service* s) { + return s->type == ServiceType_DomainSubservice; +} + /** * @brief For a domain/domain subservice, return the associated object ID. * @param[in] s Service object, necessarily a domain or domain subservice. * @return The object ID. */ -static inline u32 serviceGetObjectId(Service* s); - +static inline u32 serviceGetObjectId(Service* s) { + return s->object_id; +} + /** * @brief Closes a domain object by ID. * @param[in] s Service object, necessarily a domain or domain subservice. * @param object_id ID of the object to close. * @return Result code. */ -static inline Result serviceCloseObjectById(Service* s, u32 object_id); - +static inline Result serviceCloseObjectById(Service* s, u32 object_id) { + return ipcCloseObjectById(s->handle, object_id); +} + /** * @brief Dispatches an IPC request to a service. * @param[in] s Service object. * @return Result code. */ -static inline Result serviceIpcDispatch(Service* s); - +static inline Result serviceIpcDispatch(Service* s) { + return ipcDispatch(s->handle); +} + /** * @brief Creates a service object from an IPC session handle. * @param[out] s Service object. * @param[in] h IPC session handle. */ -static inline void serviceCreate(Service* s, Handle h); - +static inline void serviceCreate(Service* s, Handle h) { + s->handle = h; + s->type = ServiceType_Normal; + s->object_id = IPC_INVALID_OBJECT_ID; +} + /** * @brief Creates a domain subservice object from a parent service. * @param[out] s Service object. * @param[in] parent Parent service, necessarily a domain or domain subservice. * @param[in] object_id Object ID for this subservice. */ -static inline void serviceCreateDomainSubservice(Service* s, Service* parent, u32 object_id); - +static inline void serviceCreateDomainSubservice(Service* s, Service* parent, u32 object_id) { + s->handle = parent->handle; + s->type = ServiceType_DomainSubservice; + s->object_id = object_id; +} + /** * @brief Converts a regular service to a domain. * @param[in] s Service object. * @return Result code. */ -static inline Result serviceConvertToDomain(Service* s); - +static inline Result serviceConvertToDomain(Service* s) { + Result rc = ipcConvertSessionToDomain(s->handle, &s->object_id); + if(R_SUCCEEDED(rc)) + s->type = ServiceType_Domain; + return rc; +} + /** * @brief Closes a service. * @param[in] s Service object. */ -static inline void serviceClose(Service* s); - +static inline void serviceClose(Service* s) { + switch (s->type) { + + case ServiceType_Normal: + case ServiceType_Domain: + ipcCloseSession(s->handle); + svcCloseHandle(s->handle); + break; + + case ServiceType_DomainSubservice: + serviceCloseObjectById(s, s->object_id); + break; + + case ServiceType_Override: + // Don't close because we don't own the overridden handle. + break; + + case ServiceType_Uninitialized: + break; + } + + s->type = ServiceType_Uninitialized; +} + /** * @brief Initializes SM. * @return Result code. * @note This function is already called in the default application startup code (before main() is called). */ Result smInitialize(void); - + /** * @brief Uninitializes SM. * @return Result code. * @note This function is already handled in the default application exit code (after main() returns). */ void smExit(void); - + /** * @brief Requests a service from SM. * @param[out] service_out Service structure which will be filled in. @@ -125,7 +174,7 @@ void smExit(void); * @return Result code. */ Result smGetService(Service* service_out, const char* name); - + /** * @brief Requests a service from SM, as an IPC session handle directly * @param[out] handle_out Variable containing IPC session handle. @@ -133,14 +182,14 @@ Result smGetService(Service* service_out, const char* name); * @return Result code. */ Result smGetServiceOriginal(Handle* handle_out, u64 name); - + /** * @brief Retrieves an overriden service in the homebrew environment. * @param[in] name Name of the service to request (as 64-bit integer). * @return IPC session handle. */ Handle smGetServiceOverride(u64 name); - + /** * @brief Creates and registers a new service within SM. * @param[out] handle_out Variable containing IPC port handle. @@ -150,27 +199,27 @@ Handle smGetServiceOverride(u64 name); * @return Result code. */ Result smRegisterService(Handle* handle_out, const char* name, bool is_light, int max_sessions); - + /** * @brief Unregisters a previously registered service in SM. * @param[in] name Name of the service. * @return Result code. */ Result smUnregisterService(const char* name); - + /** * @brief Check whether SM is initialized. * @return true if initialized. */ bool smHasInitialized(void); - + /** * @brief Encodes a service name as a 64-bit integer. * @param[in] name Name of the service. * @return Encoded name. */ u64 smEncodeName(const char* name); - + /** * @brief Overrides a service with a custom IPC service handle. * @param[in] name Name of the service (as 64-bit integer). diff --git a/src/libnx/wrapper/sm.nim b/src/libnx/wrapper/sm.nim index 8b8d2d1..39936b3 100644 --- a/src/libnx/wrapper/sm.nim +++ b/src/libnx/wrapper/sm.nim @@ -203,4 +203,4 @@ proc smEncodeName*(name: cstring): uint64 {.cdecl, importc: "smEncodeName", ## proc smAddOverrideHandle*(name: uint64; handle: Handle) {.cdecl, - importc: "smAddOverrideHandle", header: headersm.} \ No newline at end of file + importc: "smAddOverrideHandle", header: headersm.}