Merge remote-tracking branch 'upstream/master' into dev

This commit is contained in:
shchmue 2020-04-17 11:29:07 -06:00
commit a06e062928
58 changed files with 3694 additions and 425 deletions

View File

@ -1,5 +1,67 @@
# Changelog
## Version 3.1.0
#### system
* **Deleted the old and deprecated IPC system**.
* **Added wrappers for all missing system calls**.
* Corrected signatures of many system calls.
* Removed `arm/atomics.h` (use C `<stdatomic.h>` or C++ `<atomic>` instead).
* Removed `U64_MAX` define (use `UINT64_MAX` instead).
* Added UtilFloat3 struct.
#### applet
* Fixed `__nx_applet_exit_mode` handling.
* `apm` is now only used/initialized for `AppletType_Application`.
* Simplified `appletGetAppletResourceUserId` to return the aruid directly, or 0 on "failure" (which is not really a failure condition).
* Changed `appletSetFocusHandlingMode` to return error if the applet type is not `AppletType_Application`.
* Added more fields to `SwkbdType` enum.
#### filesystem
* RomFS code now properly supports reading to uncached buffers.
* Added fsdev commands: fsdevMountDeviceSaveData, fsdevMountBcatSaveData, fsdevMountSystemBcatSaveData, fsdevMountTemporaryStorage, fsdevMountCacheStorage, fsdevMountSaveDataReadOnly.
* Added commands: fsOpenImageDirectoryFileSystem, fsOpenReadOnlySaveDataFileSystem, fsIsSignedSystemPartitionOnSdCardValid, fsOpen_DeviceSaveData, fsOpen_BcatSaveData, fsOpen_SystemBcatSaveData, fsOpen_TemporaryStorage, fsOpen_CacheStorage, fsOpen_SaveDataReadOnly.
* Added enum: FsImageDirectoryId.
* Removed path stack copy logic from fsFsQueryEntry.
#### graphics
* Removed bqDetachBuffer calls from nwindowReleaseBuffers as it does nothing in the place it's called.
* Fixed nvFence/nvGpu/nvMap to use service guard instead of unsafe reference counting.
#### hid
* **Fixed vibration handling**.
* **Added Ring-Con™ support**.
* Added hidbus service wrappers.
* Added commands: hidSetSixAxisSensorFusionParameters, hidGetSixAxisSensorFusionParameters, hidResetSixAxisSensorFusionParameters, hidSetGyroscopeZeroDriftMode, hidGetGyroscopeZeroDriftMode, hidResetGyroscopeZeroDriftMode.
* Majorly overhauled irs service support (infrared camera), with support for features introduced in later system versions.
* Added enum: HidGyroscopeZeroDriftMode.
* Corrected internal console six-axis sensor initialization function to actually use the right command.
* Corrected values of `JOYSTICK_MIN` and `JOYSTICK_MAX`.
#### other services
* Added apm command: apmGetPerformanceMode.
* Added caps:a service wrappers.
* Added caps:c service wrappers.
* Added caps:dc service wrappers.
* Added fan service wrappers.
* Added many missing lbl commands.
* Added nifm commands: nifmGetClientId (with corresponding NifmClientId struct), nifmIsAnyInternetRequestAccepted.
* Added nim service wrappers (only nimListSystemUpdateTask/nimDestroySystemUpdateTask for now).
* Majorly overhauled ns service support, with countless commands and structures.
* Added set:cal service wrappers.
* Completed and corrected all set:sys commands.
* Added tc service wrappers.
* Actually expose ldrShellFlushArguments, ldrDmntFlushArguments, spl\*GetServiceSession.
* Corrected minimum sysver for setsysGetHomeMenuScheme.
* Corrected minimum sysver for nsListApplicationContentMetaStatus.
* Fixed splSslLoadSecureExpModKey/splEsLoadSecureExpModKey/splRsaDecryptPrivateKey/splSslLoadSecureExpModKey/splEsLoadRsaOaepKey/splEsLoadSecureExpModKey/splFsLoadSecureExpModKey on 5.0+.
* Fixed plInitialize failure handling.
* Removed non-existent fsldrSetCurrentProcess.
#### miscellaneous
* Changed timezone support code to always report `NX` as the timezone name, fixing certain issues.
* Further improvements to overall system stability and other minor adjustments have been made to enhance the user experience.
## Version 3.0.0
#### system

View File

@ -9,7 +9,7 @@ endif
include $(DEVKITPRO)/devkitA64/base_rules
export LIBNX_MAJOR := 3
export LIBNX_MINOR := 0
export LIBNX_MINOR := 1
export LIBNX_PATCH := 0

View File

@ -64,6 +64,7 @@ extern "C" {
#include "switch/services/pcv.h"
#include "switch/services/clkrst.h"
#include "switch/services/fan.h"
#include "switch/services/pgl.h"
#include "switch/services/psm.h"
#include "switch/services/spsm.h"
//#include "switch/services/bsd.h" Use <sys/socket.h> instead
@ -82,6 +83,7 @@ extern "C" {
#include "switch/services/vi.h"
#include "switch/services/nv.h"
#include "switch/services/nifm.h"
#include "switch/services/nim.h"
#include "switch/services/ns.h"
#include "switch/services/ldr.h"
#include "switch/services/ro.h"
@ -107,6 +109,8 @@ extern "C" {
#include "switch/services/grc.h"
#include "switch/services/friends.h"
#include "switch/services/notif.h"
#include "switch/services/mii.h"
#include "switch/services/miiimg.h"
#include "switch/display/binder.h"
#include "switch/display/parcel.h"

View File

@ -96,6 +96,13 @@ typedef struct {
u32 padding; ///< Padding.
} MemoryInfo;
/// Physical memory information structure.
typedef struct {
u64 physical_address; ///< Physical address.
u64 virtual_address; ///< Virtual address.
u64 size; ///< Size.
} PhysicalMemoryInfo;
/// Secure monitor arguments.
typedef struct {
u64 X[8]; ///< Values of X0 through X7.
@ -118,6 +125,12 @@ typedef enum {
LimitableResource_Sessions=4, ///<How many sessions can a process own.
} LimitableResource;
/// Thread Activity.
typedef enum {
ThreadActivity_Runnable = 0, ///< Thread can run.
ThreadActivity_Paused = 1, ///< Thread is paused.
} ThreadActivity;
/// Process Information.
typedef enum {
ProcessInfoType_ProcessState=0, ///<What state is a process in.
@ -135,6 +148,12 @@ typedef enum {
ProcessState_DebugSuspended=7, ///<Process execution suspended by debugger.
} ProcessState;
/// Process Activity.
typedef enum {
ProcessActivity_Runnable = 0, ///< Process can run.
ProcessActivity_Paused = 1, ///< Process is paused.
} ProcessActivity;
/// Debug Thread Parameters.
typedef enum {
DebugThreadParam_ActualPriority=0,
@ -199,11 +218,11 @@ typedef enum {
/// GetSystemInfo PhysicalMemory Sub IDs.
typedef enum {
PhysicalMemoryInfo_Application = 0, ///< Memory allocated for application usage.
PhysicalMemoryInfo_Applet = 1, ///< Memory allocated for applet usage.
PhysicalMemoryInfo_System = 2, ///< Memory allocated for system usage.
PhysicalMemoryInfo_SystemUnsafe = 3, ///< Memory allocated for unsafe system usage (accessible to devices).
} PhysicalMemoryInfo;
PhysicalMemorySystemInfo_Application = 0, ///< Memory allocated for application usage.
PhysicalMemorySystemInfo_Applet = 1, ///< Memory allocated for applet usage.
PhysicalMemorySystemInfo_System = 2, ///< Memory allocated for system usage.
PhysicalMemorySystemInfo_SystemUnsafe = 3, ///< Memory allocated for unsafe system usage (accessible to devices).
} PhysicalMemorySystemInfo;
/// SleepThread yield types.
typedef enum {
@ -242,7 +261,7 @@ typedef struct {
* @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.
* @note Syscall number 0x01.
*/
Result svcSetHeapSize(void** out_addr, u64 size);
@ -254,7 +273,7 @@ Result svcSetHeapSize(void** out_addr, u64 size);
* @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.
* @note Syscall number 0x02.
*/
Result svcSetMemoryPermission(void* addr, u64 size, u32 perm);
@ -266,7 +285,7 @@ Result svcSetMemoryPermission(void* addr, u64 size, u32 perm);
* @param[in] val1 State1
* @return Result code.
* @remark See <a href="https://switchbrew.org/wiki/SVC#svcSetMemoryAttribute">switchbrew.org Wiki</a> for more details.
* @note Syscall number 0x02.
* @note Syscall number 0x03.
*/
Result svcSetMemoryAttribute(void* addr, u64 size, u32 val0, u32 val1);
@ -345,7 +364,7 @@ void svcSleepThread(s64 nano);
* @return Result code.
* @note Syscall number 0x0C.
*/
Result svcGetThreadPriority(u32* priority, Handle handle);
Result svcGetThreadPriority(s32* priority, Handle handle);
/**
* @brief Sets a thread's priority.
@ -359,7 +378,7 @@ Result svcSetThreadPriority(Handle handle, u32 priority);
* @return Result code.
* @note Syscall number 0x0E.
*/
Result svcGetThreadCoreMask(s32* preferred_core, u32* affinity_mask, Handle handle);
Result svcGetThreadCoreMask(s32* preferred_core, u64* affinity_mask, Handle handle);
/**
* @brief Sets a thread's core mask.
@ -710,7 +729,7 @@ Result svcGetLastThreadInfo(LastThreadContext *out_context, u64 *out_tls_address
* @note Syscall number 0x30.
* @warning This is a privileged syscall. Use \ref envIsSyscallHinted to check if it is available.
*/
Result svcGetResourceLimitLimitValue(u64 *out, Handle reslimit_h, LimitableResource which);
Result svcGetResourceLimitLimitValue(s64 *out, Handle reslimit_h, LimitableResource which);
/**
* @brief Gets the maximum value a LimitableResource can have, for a Resource Limit handle.
@ -718,7 +737,7 @@ Result svcGetResourceLimitLimitValue(u64 *out, Handle reslimit_h, LimitableResou
* @note Syscall number 0x31.
* @warning This is a privileged syscall. Use \ref envIsSyscallHinted to check if it is available.
*/
Result svcGetResourceLimitCurrentValue(u64 *out, Handle reslimit_h, LimitableResource which);
Result svcGetResourceLimitCurrentValue(s64 *out, Handle reslimit_h, LimitableResource which);
///@}
@ -730,7 +749,7 @@ Result svcGetResourceLimitCurrentValue(u64 *out, Handle reslimit_h, LimitableRes
* @return Result code.
* @note Syscall number 0x32.
*/
Result svcSetThreadActivity(Handle thread, bool paused);
Result svcSetThreadActivity(Handle thread, ThreadActivity paused);
/**
* @brief Dumps the registers of a thread paused by @ref svcSetThreadActivity (register groups: all).
@ -958,7 +977,7 @@ Result svcReadWriteRegister(u32* outVal, u64 regAddr, u32 rwMask, u32 inVal);
* @note Syscall number 0x4F.
* @warning This is a privileged syscall. Use \ref envIsSyscallHinted to check if it is available.
*/
Result svcSetProcessActivity(Handle process, bool paused);
Result svcSetProcessActivity(Handle process, ProcessActivity paused);
///@}
@ -1008,15 +1027,25 @@ Result svcCreateInterruptEvent(Handle* handle, u64 irqNum, u32 flag);
* @note Syscall number 0x54.
* @warning This is a privileged syscall. Use \ref envIsSyscallHinted to check if it is available.
*/
Result svcQueryPhysicalAddress(u64 out[3], u64 virtaddr);
Result svcQueryPhysicalAddress(PhysicalMemoryInfo *out, u64 virtaddr);
/**
* @brief Returns a virtual address mapped to a given IO range.
* @return Result code.
* @note Syscall number 0x55.
* @warning This is a privileged syscall. Use \ref envIsSyscallHinted to check if it is available.
* @warning Only exists on [10.0.0+]. For older versions use \ref svcLegacyQueryIoMapping.
*/
Result svcQueryIoMapping(u64* virtaddr, u64 physaddr, u64 size);
Result svcQueryIoMapping(u64* virtaddr, u64* out_size, u64 physaddr, u64 size);
/**
* @brief Returns a virtual address mapped to a given IO range.
* @return Result code.
* @note Syscall number 0x55.
* @warning This is a privileged syscall. Use \ref envIsSyscallHinted to check if it is available.
* @warning Only exists on [1.0.0-9.2.0]. For newer versions use \ref svcQueryIoMapping.
*/
Result svcLegacyQueryIoMapping(u64* virtaddr, u64 physaddr, u64 size);
///@}
@ -1149,7 +1178,7 @@ Result svcTerminateDebugProcess(Handle debug);
* @note Syscall number 0x63.
* @warning This is a privileged syscall. Use \ref envIsSyscallHinted to check if it is available.
*/
Result svcGetDebugEvent(u8* event_out, Handle debug);
Result svcGetDebugEvent(void* event_out, Handle debug);
/**
* @brief Continues a debugging session.
@ -1206,7 +1235,7 @@ Result svcSetDebugThreadContext(Handle debug, u64 threadID, const ThreadContext*
* @note Syscall number 0x65.
* @warning This is a privileged syscall. Use \ref envIsSyscallHinted to check if it is available.
*/
Result svcGetProcessList(u32 *num_out, u64 *pids_out, u32 max_pids);
Result svcGetProcessList(s32 *num_out, u64 *pids_out, u32 max_pids);
/**
* @brief Retrieves a list of all threads for a debug handle (or zero).
@ -1214,7 +1243,7 @@ Result svcGetProcessList(u32 *num_out, u64 *pids_out, u32 max_pids);
* @note Syscall number 0x66.
* @warning This is a privileged syscall. Use \ref envIsSyscallHinted to check if it is available.
*/
Result svcGetThreadList(u32 *num_out, u64 *tids_out, u32 max_tids, Handle debug);
Result svcGetThreadList(s32 *num_out, u64 *tids_out, u32 max_tids, Handle debug);
///@}
@ -1423,7 +1452,7 @@ Result svcTerminateProcess(Handle proc);
* @note Syscall number 0x7C.
* @warning This is a privileged syscall. Use \ref envIsSyscallHinted to check if it is available.
*/
Result svcGetProcessInfo(u64 *out, Handle proc, ProcessInfoType which);
Result svcGetProcessInfo(s64 *out, Handle proc, ProcessInfoType which);
///@}

View File

@ -91,6 +91,12 @@ Result threadResume(Thread* t);
*/
Result threadDumpContext(ThreadContext* ctx, Thread* t);
/**
* @brief Gets a pointer to the current thread structure.
* @return Thread information structure.
*/
Thread *threadGetSelf(void);
/**
* @brief Gets the raw handle to the current thread.
* @return The current thread's handle.

View File

@ -30,15 +30,34 @@ NX_CONSTEXPR FsDirectoryEntry* fsdevDirGetEntries(fsdev_dir_t *dir)
/// Initializes and mounts the sdmc device if accessible.
Result fsdevMountSdmc(void);
/// Mounts the specified save data.
/// Mounts the specified SaveData.
Result fsdevMountSaveData(const char *name, u64 application_id, AccountUid uid);
/// Mounts the specified SaveData as ReadOnly.
/// Only available on [2.0.0+].
Result fsdevMountSaveDataReadOnly(const char *name, u64 application_id, AccountUid uid);
/// Mounts the specified BcatSaveData.
Result fsdevMountBcatSaveData(const char *name, u64 application_id);
/// Mounts the specified DeviceSaveData.
Result fsdevMountDeviceSaveData(const char *name, u64 application_id);
/// Mounts the specified system save data.
/// Mounts the TemporaryStorage for the current process.
/// Only available on [3.0.0+].
Result fsdevMountTemporaryStorage(const char *name);
/// Mounts the specified CacheStorage.
/// Only available on [3.0.0+].
Result fsdevMountCacheStorage(const char *name, u64 application_id, u16 save_data_index);
/// Mounts the specified SystemSaveData.
Result fsdevMountSystemSaveData(const char *name, FsSaveDataSpaceId save_data_space_id, u64 system_save_data_id, AccountUid uid);
/// Mounts the specified SystemBcatSaveData.
/// Only available on [4.0.0+].
Result fsdevMountSystemBcatSaveData(const char *name, u64 system_save_data_id);
/// Mounts the input fs with the specified device name. fsdev will handle closing the fs when required, including when fsdevMountDevice() fails.
/// Returns -1 when any errors occur.
/// Input device name string shouldn't exceed 31 characters, and shouldn't have a trailing colon.

View File

@ -5,6 +5,7 @@
* @copyright libnx Authors
*/
#pragma once
#include "../types.h"
struct in_addr;
@ -15,8 +16,20 @@ extern struct in_addr __nxlink_host;
#define NXLINK_CLIENT_PORT 28771 ///< nxlink TCP client port
/**
* @brief Sets up stdout/stderr redirection to the nxlink host.
* @brief Connects to the nxlink host, setting up an output stream.
* @param[in] redirStdout Whether to redirect stdout to nxlink output.
* @param[in] redirStderr Whether to redirect stderr to nxlink output.
* @return Socket fd on success, negative number on failure.
* @note The socket should be closed with close() during application cleanup.
*/
int nxlinkStdio(void);
int nxlinkConnectToHost(bool redirStdout, bool redirStderr);
/// Same as \ref nxlinkConnectToHost but redirecting both stdout/stderr.
NX_INLINE int nxlinkStdio(void) {
return nxlinkConnectToHost(true, true);
}
/// Same as \ref nxlinkConnectToHost but redirecting only stderr.
NX_INLINE int nxlinkStdioForDebug(void) {
return nxlinkConnectToHost(false, true);
}

View File

@ -2284,6 +2284,7 @@ Result appletGetHomeButtonDoubleClickEnabled(bool *out);
/**
* @brief Open an \ref AppletApplication for the currently running Application.
* @note Should not be used when no Application is running.
* @note Only available on [1.0.0-9.2.0].
* @param[out] a \ref AppletApplication
*/
Result appletOpenMainApplication(AppletApplication *a);

View File

@ -51,6 +51,17 @@ Result audoutAppendAudioOutBuffer(AudioOutBuffer *Buffer);
Result audoutGetReleasedAudioOutBuffer(AudioOutBuffer **Buffer, u32 *ReleasedBuffersCount);
Result audoutContainsAudioOutBuffer(AudioOutBuffer *Buffer, bool *ContainsBuffer);
/// Only available with [4.0.0+].
Result audoutGetAudioOutBufferCount(u32 *count);
/// Only available with [4.0.0+].
Result audoutGetAudioOutPlayedSampleCount(u64 *count);
/// Only available with [4.0.0+].
Result audoutFlushAudioOutBuffers(bool *flushed);
/// Only available with [6.0.0+].
Result audoutSetAudioOutVolume(float volume);
/// Only available with [6.0.0+].
Result audoutGetAudioOutVolume(float *volume);
/**
* @brief Submits an audio sample data buffer for playing and waits for it to finish playing.
* @brief Uses \ref audoutAppendAudioOutBuffer and \ref audoutWaitPlayFinish internally.

View File

@ -24,4 +24,4 @@ Service* bpcGetServiceSession(void);
Result bpcShutdownSystem(void);
Result bpcRebootSystem(void);
Result bpcGetSleepButtonState(BpcSleepButtonState *out);
Result bpcGetSleepButtonState(BpcSleepButtonState *out); ///< [2.0.0+]

View File

@ -75,5 +75,7 @@ ssize_t bsdRead(int fd, void *buf, size_t count);
int bsdClose(int fd);
/// Duplicate a socket (bsd:s).
int bsdDuplicateSocket(int sockfd);
int bsdRecvMMsg(int sockfd, void *buf, size_t size, unsigned int vlen, int flags, struct timespec *timeout);
int bsdSendMMsg(int sockfd, void *buf, size_t size, unsigned int vlen, int flags);
// TODO: Reverse-engineer GetResourceStatistics. Implement sendmmsg/recvmmsg (custom (un)serialization)
// TODO: Reverse-engineer GetResourceStatistics.

View File

@ -323,16 +323,17 @@ Result fsOpenBisStorage(FsStorage* out, FsBisPartitionId partitionId);
Result fsOpenSdCardFileSystem(FsFileSystem* out);
Result fsCreateSaveDataFileSystemBySystemSaveDataId(const FsSaveDataAttribute* attr, const FsSaveDataCreationInfo* creation_info);
Result fsDeleteSaveDataFileSystemBySaveDataSpaceId(FsSaveDataSpaceId save_data_space_id, u64 saveID); /// [2.0.0+]
Result fsDeleteSaveDataFileSystemBySaveDataSpaceId(FsSaveDataSpaceId save_data_space_id, u64 saveID); ///< [2.0.0+]
Result fsIsExFatSupported(bool* out);
Result fsOpenGameCardFileSystem(FsFileSystem* out, const FsGameCardHandle* handle, FsGameCardPartition partition);
Result fsExtendSaveDataFileSystem(FsSaveDataSpaceId save_data_space_id, u64 saveID, s64 dataSize, s64 journalSize); /// [3.0.0+]
Result fsExtendSaveDataFileSystem(FsSaveDataSpaceId save_data_space_id, u64 saveID, s64 dataSize, s64 journalSize); ///< [3.0.0+]
Result fsOpenSaveDataFileSystem(FsFileSystem* out, FsSaveDataSpaceId save_data_space_id, const FsSaveDataAttribute *attr);
Result fsOpenSaveDataFileSystemBySystemSaveDataId(FsFileSystem* out, FsSaveDataSpaceId save_data_space_id, const FsSaveDataAttribute *attr);
Result fsOpenReadOnlySaveDataFileSystem(FsFileSystem* out, FsSaveDataSpaceId save_data_space_id, const FsSaveDataAttribute *attr); ///< [2.0.0+].
Result fsReadSaveDataFileSystemExtraDataBySaveDataSpaceId(void* buf, size_t len, FsSaveDataSpaceId save_data_space_id, u64 saveID);
Result fsReadSaveDataFileSystemExtraData(void* buf, size_t len, u64 saveID);
@ -342,7 +343,7 @@ Result fsOpenSaveDataInfoReader(FsSaveDataInfoReader* out, FsSaveDataSpaceId sav
Result fsOpenImageDirectoryFileSystem(FsFileSystem* out, FsImageDirectoryId image_directory_id);
Result fsOpenContentStorageFileSystem(FsFileSystem* out, FsContentStorageId content_storage_id);
Result fsOpenCustomStorageFileSystem(FsFileSystem* out, FsCustomStorageId custom_storage_id); /// [7.0.0+]
Result fsOpenCustomStorageFileSystem(FsFileSystem* out, FsCustomStorageId custom_storage_id); ///< [7.0.0+]
Result fsOpenDataStorageByCurrentProcess(FsStorage* out);
Result fsOpenDataStorageByDataId(FsStorage* out, u64 dataId, NcmStorageId storageId);
@ -371,14 +372,35 @@ Result fsCreate_SystemSaveData(FsSaveDataSpaceId save_data_space_id, u64 system_
/// See \ref FsSaveDataAttribute for application_id and uid.
Result fsOpen_SaveData(FsFileSystem* out, u64 application_id, AccountUid uid);
/// Wrapper for fsOpenReadOnlySaveDataFileSystem.
/// Only available on [2.0.0+].
/// See \ref FsSaveDataAttribute for application_id and uid.
Result fsOpen_SaveDataReadOnly(FsFileSystem* out, u64 application_id, AccountUid uid);
/// Wrapper for fsOpenSaveDataFileSystem, for opening BcatSaveData.
Result fsOpen_BcatSaveData(FsFileSystem* out, u64 application_id);
/// Wrapper for fsOpenSaveDataFileSystem, for opening DeviceSaveData.
/// See \ref FsSaveDataAttribute for application_id.
Result fsOpen_DeviceSaveData(FsFileSystem* out, u64 application_id);
/// Wrapper for fsOpenSaveDataFileSystemBySystemSaveDataId.
/// Wrapper for fsOpenSaveDataFileSystem, for opening TemporaryStorage.
/// Only available on [3.0.0+].
Result fsOpen_TemporaryStorage(FsFileSystem* out);
/// Wrapper for fsOpenSaveDataFileSystem, for opening CacheStorage.
/// Only available on [3.0.0+].
/// See \ref FsSaveDataAttribute for application_id.
Result fsOpen_CacheStorage(FsFileSystem* out, u64 application_id, u16 save_data_index);
/// Wrapper for fsOpenSaveDataFileSystemBySystemSaveDataId, for opening SystemSaveData.
/// WARNING: You can brick when writing to SystemSaveData, if the data is corrupted etc.
Result fsOpen_SystemSaveData(FsFileSystem* out, FsSaveDataSpaceId save_data_space_id, u64 system_save_data_id, AccountUid uid);
/// Wrapper for fsOpenSaveDataFileSystemBySystemSaveDataId, for opening SystemBcatSaveData.
/// Only available on [4.0.0+].
Result fsOpen_SystemBcatSaveData(FsFileSystem* out, u64 system_save_data_id);
// IFileSystem
Result fsFsCreateFile(FsFileSystem* fs, const char* path, s64 size, u32 option);
Result fsFsDeleteFile(FsFileSystem* fs, const char* path);

View File

@ -8,6 +8,14 @@
#include "../types.h"
#include "../sf/service.h"
#include "../services/fs.h"
#include "../crypto/sha256.h"
typedef struct {
u8 signature[0x100];
u8 hash[SHA256_HASH_SIZE];
bool is_signed;
u8 reserved[3];
} FsCodeInfo;
/// Initialize fsp-ldr.
Result fsldrInitialize(void);
@ -18,5 +26,5 @@ void fsldrExit(void);
/// Gets the Service object for the actual fsp-ldr service session.
Service* fsldrGetServiceSession(void);
Result fsldrOpenCodeFileSystem(u64 tid, const char *path, FsFileSystem* out);
Result fsldrOpenCodeFileSystem(FsCodeInfo* out_code_info, u64 tid, const char *path, FsFileSystem* out);
Result fsldrIsArchivedProgram(u64 pid, bool *out);

View File

@ -10,44 +10,373 @@
#include "../sf/service.h"
#include "../services/hid.h"
typedef struct {
u64 unk_x0;
u8 unk_x8;
u8 unk_x9;
u8 unk_xa;
u8 pad[5];
u16 unk_x10;
u32 unk_x12;
u16 unk_x16;
u32 unk_constant;//offset 0x18
u8 unk_x1c;
u8 unk_x1d;
u8 pad2[2];
} PACKED IrsPackedMomentProcessorConfig;
#define IRS_MAX_CAMERAS 0x9
/// IrCameraStatus
typedef enum {
IrsIrCameraStatus_Available = 0, ///< Available
IrsIrCameraStatus_Unsupported = 1, ///< Unsupported
IrsIrCameraStatus_Unconnected = 2, ///< Unconnected
} IrsIrCameraStatus;
/// IrCameraInternalStatus
typedef enum {
IrsIrCameraInternalStatus_Stopped = 0, ///< Stopped
IrsIrCameraInternalStatus_FirmwareUpdateNeeded = 1, ///< FirmwareUpdateNeeded
IrsIrCameraInternalStatus_Unknown2 = 2, ///< Unknown
IrsIrCameraInternalStatus_Unknown3 = 3, ///< Unknown
IrsIrCameraInternalStatus_Unknown4 = 4, ///< Unknown
IrsIrCameraInternalStatus_FirmwareVersionRequested = 5, ///< FirmwareVersionRequested
IrsIrCameraInternalStatus_FirmwareVersionIsInvalid = 6, ///< FirmwareVersionIsInvalid
IrsIrCameraInternalStatus_Ready = 7, ///< [4.0.0+] Ready
IrsIrCameraInternalStatus_Setting = 8, ///< [4.0.0+] Setting
} IrsIrCameraInternalStatus;
/// IrSensorMode
typedef enum {
IrsIrSensorMode_None = 0, ///< None
IrsIrSensorMode_MomentProcessor = 1, ///< MomentProcessor
IrsIrSensorMode_ClusteringProcessor = 2, ///< ClusteringProcessor
IrsIrSensorMode_ImageTransferProcessor = 3, ///< ImageTransferProcessor
IrsIrSensorMode_PointingProcessor = 4, ///< PointingProcessor
IrsIrSensorMode_TeraPluginProcessor = 5, ///< TeraPluginProcessor
IrsIrSensorMode_IrLedProcessor = 6, ///< IrLedProcessor (doesn't apply to IrsDeviceFormat::ir_sensor_mode)
} IrsIrSensorMode;
/// ImageProcessorStatus
typedef enum {
IrsImageProcessorStatus_Stopped = 0, ///< Stopped
IrsImageProcessorStatus_Running = 1, ///< Running
} IrsImageProcessorStatus;
/// ImageTransferProcessorFormat. IR Sensor image resolution.
typedef enum {
IrsImageTransferProcessorFormat_320x240 = 0, ///< 320x240
IrsImageTransferProcessorFormat_160x120 = 1, ///< 160x120
IrsImageTransferProcessorFormat_80x60 = 2, ///< 80x60
IrsImageTransferProcessorFormat_40x30 = 3, ///< [4.0.0+] 40x30
IrsImageTransferProcessorFormat_20x15 = 4, ///< [4.0.0+] 20x15
} IrsImageTransferProcessorFormat;
/// AdaptiveClusteringMode
typedef enum {
IrsAdaptiveClusteringMode_StaticFov = 0, ///< StaticFov
IrsAdaptiveClusteringMode_DynamicFov = 1, ///< DynamicFov
} IrsAdaptiveClusteringMode;
/// AdaptiveClusteringTargetDistance
typedef enum {
IrsAdaptiveClusteringTargetDistance_Near = 0, ///< Near
IrsAdaptiveClusteringTargetDistance_Middle = 1, ///< Middle
IrsAdaptiveClusteringTargetDistance_Far = 2, ///< Far
} IrsAdaptiveClusteringTargetDistance;
/// HandAnalysisMode
typedef enum {
IrsHandAnalysisMode_Silhouette = 1, ///< Silhouette
IrsHandAnalysisMode_Image = 2, ///< Image
IrsHandAnalysisMode_SilhouetteAndImage = 3, ///< SilhouetteAndImage
IrsHandAnalysisMode_SilhouetteOnly = 4, ///< [4.0.0+] SilhouetteOnly
} IrsHandAnalysisMode;
/// Internal validation callblack.
typedef bool (*IrsValidationCb)(void* userdata, void* arg);
/// IrCameraHandle
typedef struct {
u64 exposure; ///< IR Sensor exposure time in nanoseconds.
u32 ir_leds; ///< Controls the IR leds. 0: All leds, 1: Bright group, 2: Dim group, 3: None.
u32 digital_gain; ///< IR sensor signal's digital gain.
u8 color_invert; ///< Inverts the colors of the captured image. 0: Normal image, 1: Negative image.
u8 pad[7];
u32 sensor_res; ///< IR Sensor resolution. 0: 240x320, 1: 120x160, 2: 60x80.
u8 player_number; ///< PlayerNumber
u8 device_type; ///< DeviceType
u8 reserved[0x2]; ///< Reserved
} IrsIrCameraHandle;
/// PackedMcuVersion
typedef struct {
u16 major_version; ///< MajorVersion
u16 minor_version; ///< MinorVersion
} IrsPackedMcuVersion;
/// PackedFunctionLevel
typedef struct {
u8 ir_sensor_function_level; ///< IrSensorFunctionLevel
u8 reserved[0x3]; ///< Reserved
} IrsPackedFunctionLevel;
/// Rect
typedef struct {
s16 x; ///< X
s16 y; ///< Y
s16 width; ///< Width
s16 height; ///< Height
} IrsRect;
/// IrsMomentProcessorConfig
typedef struct {
u64 exposure_time; ///< IR Sensor exposure time in nanoseconds.
u32 light_target; ///< Controls the IR leds. 0: All leds, 1: Bright group, 2: Dim group, 3: None.
u32 gain; ///< IR sensor signal's digital gain.
u8 is_negative_image_used; ///< Inverts the colors of the captured image. 0: Normal image, 1: Negative image.
u8 reserved[0x7]; ///< Reserved.
IrsRect window_of_interest; ///< WindowOfInterest
u32 preprocess; ///< Preprocess
u32 preprocess_intensity_threshold; ///< PreprocessIntensityThreshold
} IrsMomentProcessorConfig;
/// PackedMomentProcessorConfig
typedef struct {
u64 exposure_time; ///< IR Sensor exposure time in nanoseconds.
u8 light_target; ///< Controls the IR leds. 0: All leds, 1: Bright group, 2: Dim group, 3: None.
u8 gain; ///< IR sensor signal's digital gain.
u8 is_negative_image_used; ///< Inverts the colors of the captured image. 0: Normal image, 1: Negative image.
u8 reserved[0x5]; ///< Reserved.
IrsRect window_of_interest; ///< WindowOfInterest
IrsPackedMcuVersion required_mcu_version; ///< RequiredMcuVersion
u8 preprocess; ///< Preprocess
u8 preprocess_intensity_threshold; ///< PreprocessIntensityThreshold
u8 reserved2[0x2]; ///< Reserved.
} IrsPackedMomentProcessorConfig;
/// ClusteringProcessorConfig
typedef struct {
u64 exposure_time; ///< IR Sensor exposure time in nanoseconds.
u32 light_target; ///< Controls the IR leds. 0: All leds, 1: Bright group, 2: Dim group, 3: None.
u32 gain; ///< IR sensor signal's digital gain.
u8 is_negative_image_used; ///< Inverts the colors of the captured image. 0: Normal image, 1: Negative image.
u8 reserved[0x7]; ///< Reserved.
IrsRect window_of_interest; ///< WindowOfInterest
u32 object_pixel_count_min; ///< ObjectPixelCountMin
u32 object_pixel_count_max; ///< ObjectPixelCountMax
u32 object_intensity_min; ///< ObjectIntensityMin
u8 is_external_light_filter_enabled; ///< IsExternalLightFilterEnabled
} IrsClusteringProcessorConfig;
/// PackedClusteringProcessorConfig
typedef struct {
u64 exposure_time; ///< IR Sensor exposure time in nanoseconds.
u8 light_target; ///< Controls the IR leds. 0: All leds, 1: Bright group, 2: Dim group, 3: None.
u8 gain; ///< IR sensor signal's digital gain.
u8 is_negative_image_used; ///< Inverts the colors of the captured image. 0: Normal image, 1: Negative image.
u8 reserved[0x5]; ///< Reserved.
IrsRect window_of_interest; ///< WindowOfInterest
IrsPackedMcuVersion required_mcu_version; ///< RequiredMcuVersion
u32 object_pixel_count_min; ///< ObjectPixelCountMin
u32 object_pixel_count_max; ///< ObjectPixelCountMax
u8 object_intensity_min; ///< ObjectIntensityMin
u8 is_external_light_filter_enabled; ///< IsExternalLightFilterEnabled
u8 reserved2[0x2]; ///< Reserved.
} IrsPackedClusteringProcessorConfig;
/// ImageTransferProcessorConfig
typedef struct {
u64 exposure_time; ///< IR Sensor exposure time in nanoseconds.
u32 light_target; ///< Controls the IR leds. 0: All leds, 1: Bright group, 2: Dim group, 3: None.
u32 gain; ///< IR sensor signal's digital gain.
u8 is_negative_image_used; ///< Inverts the colors of the captured image. 0: Normal image, 1: Negative image.
u8 reserved[0x7]; ///< Reserved.
u32 format; ///< \ref IrsImageTransferProcessorFormat
} IrsImageTransferProcessorConfig;
/// ImageTransferProcessorExConfig
typedef struct {
u64 exposure; ///< IR Sensor exposure time in nanoseconds.
u8 ir_leds; ///< Controls the IR leds. 0: All leds, 1: Bright group, 2: Dim group, 3: None.
u8 digital_gain; ///< IR sensor signal's digital gain.
u8 color_invert; ///< Inverts the colors of the captured image. 0: Normal image, 1: Negative image.
u8 pad[5];
u32 unk_constant;//offset 0x10
u8 sensor_res; ///< IR Sensor resolution. 0: 240x320, 1: 120x160, 2: 60x80.
u8 pad2[3];
u64 exposure_time; ///< IR Sensor exposure time in nanoseconds.
u32 light_target; ///< Controls the IR leds. 0: All leds, 1: Bright group, 2: Dim group, 3: None.
u32 gain; ///< IR sensor signal's digital gain.
u8 is_negative_image_used; ///< Inverts the colors of the captured image. 0: Normal image, 1: Negative image.
u8 reserved[0x7]; ///< Reserved.
u32 orig_format; ///< OrigFormat \ref IrsImageTransferProcessorFormat
u32 trimming_format; ///< TrimmingFormat \ref IrsImageTransferProcessorFormat
u16 trimming_start_x; ///< TrimmingStartX
u16 trimming_start_y; ///< TrimmingStartY
u8 is_external_light_filter_enabled; ///< IsExternalLightFilterEnabled
} IrsImageTransferProcessorExConfig;
/// PackedImageTransferProcessorConfig
typedef struct {
u64 exposure_time; ///< IR Sensor exposure time in nanoseconds.
u8 light_target; ///< Controls the IR leds. 0: All leds, 1: Bright group, 2: Dim group, 3: None.
u8 gain; ///< IR sensor signal's digital gain.
u8 is_negative_image_used; ///< Inverts the colors of the captured image. 0: Normal image, 1: Negative image.
u8 reserved[0x5]; ///< Reserved.
IrsPackedMcuVersion required_mcu_version; ///< RequiredMcuVersion
u8 format; ///< \ref IrsImageTransferProcessorFormat
u8 reserved2[0x3]; ///< Reserved.
} IrsPackedImageTransferProcessorConfig;
/// PackedImageTransferProcessorExConfig
typedef struct {
u8 unk_x0[0x10];
} PACKED IrsImageTransferProcessorState;
u64 exposure_time; ///< IR Sensor exposure time in nanoseconds.
u8 light_target; ///< Controls the IR leds. 0: All leds, 1: Bright group, 2: Dim group, 3: None.
u8 gain; ///< IR sensor signal's digital gain.
u8 is_negative_image_used; ///< Inverts the colors of the captured image. 0: Normal image, 1: Negative image.
u8 reserved[0x5]; ///< Reserved.
IrsPackedMcuVersion required_mcu_version; ///< RequiredMcuVersion
u8 orig_format; ///< OrigFormat \ref IrsImageTransferProcessorFormat
u8 trimming_format; ///< TrimmingFormat \ref IrsImageTransferProcessorFormat
u16 trimming_start_x; ///< TrimmingStartX
u16 trimming_start_y; ///< TrimmingStartY
u8 is_external_light_filter_enabled; ///< IsExternalLightFilterEnabled
u8 reserved2[0x5]; ///< Reserved.
} IrsPackedImageTransferProcessorExConfig;
/// ImageTransferProcessorState
typedef struct {
u64 sampling_number; ///< SamplingNumber
u32 ambient_noise_level; ///< AmbientNoiseLevel
u8 reserved[0x4]; ///< Reserved
} IrsImageTransferProcessorState;
/// PackedPointingProcessorConfig
typedef struct {
IrsRect window_of_interest; ///< WindowOfInterest
IrsPackedMcuVersion required_mcu_version; ///< RequiredMcuVersion
} IrsPackedPointingProcessorConfig;
/// TeraPluginProcessorConfig
typedef struct {
u8 mode; ///< Mode
u8 unk_x1; ///< [6.0.0+] Unknown
u8 unk_x2; ///< [6.0.0+] Unknown
u8 unk_x3; ///< [6.0.0+] Unknown
} IrsTeraPluginProcessorConfig;
/// PackedTeraPluginProcessorConfig
typedef struct {
IrsPackedMcuVersion required_mcu_version; ///< RequiredMcuVersion
u8 mode; ///< Mode
u8 unk_x5; ///< [6.0.0+] This is set to 0x2 | (IrsTeraPluginProcessorConfig::unk_x1 << 7).
u8 unk_x6; ///< [6.0.0+] IrsTeraPluginProcessorConfig::unk_x2
u8 unk_x7; ///< [6.0.0+] IrsTeraPluginProcessorConfig::unk_x3
} IrsPackedTeraPluginProcessorConfig;
/// IrLedProcessorConfig
typedef struct {
u32 light_target; ///< Controls the IR leds. 0: All leds, 1: Bright group, 2: Dim group, 3: None.
} IrsIrLedProcessorConfig;
/// PackedIrLedProcessorConfig
typedef struct {
IrsPackedMcuVersion required_mcu_version; ///< RequiredMcuVersion
u8 light_target; ///< Controls the IR leds. 0: All leds, 1: Bright group, 2: Dim group, 3: None.
u8 pad[0x3]; ///< Padding
} IrsPackedIrLedProcessorConfig;
/// AdaptiveClusteringProcessorConfig
typedef struct {
u32 mode; ///< \ref IrsAdaptiveClusteringMode
u32 target_distance; ///< [6.0.0+] \ref IrsAdaptiveClusteringTargetDistance
} IrsAdaptiveClusteringProcessorConfig;
/// HandAnalysisConfig
typedef struct {
u32 mode; ///< \ref IrsHandAnalysisMode
} IrsHandAnalysisConfig;
/// MomentStatistic
typedef struct {
float average_intensity; ///< AverageIntensity
float centroid_x; ///< CentroidX
float centroid_y; ///< CentroidY
} IrsMomentStatistic;
/// MomentProcessorState
typedef struct {
s64 sampling_number; ///< SamplingNumber
u64 timestamp; ///< TimeStamp
u32 ambient_noise_level; ///< AmbientNoiseLevel
u8 reserved[0x4]; ///< Reserved
IrsMomentStatistic statistic[0x30]; ///< \ref IrsMomentStatistic
} IrsMomentProcessorState;
/// ClusteringData
typedef struct {
float average_intensity; ///< AverageIntensity
float centroid_x; ///< CentroidX
float centroid_y; ///< CentroidY
u32 pixel_count; ///< PixelCount
u16 bound_x; ///< BoundX
u16 bound_y; ///< BoundY
u16 boundt_width; ///< BoundtWidth
u16 bound_height; ///< BoundHeight
} IrsClusteringData;
/// ClusteringProcessorState
typedef struct {
s64 sampling_number; ///< SamplingNumber
u64 timestamp; ///< TimeStamp
u8 object_count; ///< ObjectCount
u8 reserved[0x3]; ///< Reserved
u32 ambient_noise_level; ///< AmbientNoiseLevel
IrsClusteringData data[0x10]; ///< \ref IrsClusteringData
} IrsClusteringProcessorState;
/// PointingProcessorMarkerState
typedef struct {
s64 sampling_number; ///< SamplingNumber
u64 timestamp; ///< TimeStamp
struct {
u8 pointing_status; ///< PointingStatus
u8 reserved[0x3]; ///< Reserved
u8 unk_x4[0x4]; ///< Unknown
float unk_x8; ///< Unknown
float position_x; ///< PositionX
float position_y; ///< PositionY
float unk_x14; ///< Unknown
IrsRect window_of_interest; ///< WindowOfInterest
} data[3];
} IrsPointingProcessorMarkerState;
/// PointingProcessorState
typedef struct {
s64 sampling_number; ///< SamplingNumber
u64 timestamp; ///< TimeStamp
u32 pointing_status; ///< PointingStatus
float position_x; ///< PositionX
float position_y; ///< PositionY
u8 reserved[0x4]; ///< Reserved
} IrsPointingProcessorState;
/// TeraPluginProcessorState
typedef struct {
s64 sampling_number; ///< SamplingNumber
u64 timestamp; ///< TimeStamp
u32 ambient_noise_level; ///< AmbientNoiseLevel
u8 plugin_data[0x12c]; ///< PluginData
} IrsTeraPluginProcessorState;
/// ProcessorState
typedef struct {
s64 start; ///< Start
u32 count; ///< Count
u32 pad; ///< Padding
u8 data[0xe10]; ///< Contains an array of *ProcessorState, depending on IrsDeviceFormat::ir_sensor_mode.
} IrsProcessorState;
/// DeviceFormat
typedef struct {
u32 ir_camera_status; ///< \ref IrsIrCameraStatus
u32 ir_camera_internal_status; ///< \ref IrsIrCameraInternalStatus
u32 ir_sensor_mode; ///< \ref IrsIrSensorMode
u32 pad; ///< Padding
IrsProcessorState processor_state; ///< \ref IrsProcessorState
} IrsDeviceFormat;
/// AruidFormat
typedef struct {
u64 ir_sensor_aruid; ///< IrSensorAruid
u32 ir_sensor_aruid_status; ///< IrSensorAruidStatus
u32 pad; ///< Padding
} IrsAruidFormat;
/// StatusManager
typedef struct {
IrsDeviceFormat device_format[IRS_MAX_CAMERAS];
IrsAruidFormat aruid_format[0x5];
} IrsStatusManager;
/// Initialize irs.
Result irsInitialize(void);
@ -58,36 +387,188 @@ void irsExit(void);
/// Gets the Service object for the actual irs service session.
Service* irsGetServiceSession(void);
/// Gets the address of the SharedMemory.
/// Gets the address of the SharedMemory (\ref IrsStatusManager).
void* irsGetSharedmemAddr(void);
/// (De)activate the IR sensor, this is automatically used by \ref irsExit. Must be called after irsInitialize() to activate the IR sensor.
Result irsActivateIrsensor(bool activate);
/// Gets the \ref IrsIrCameraHandle for the specified controller.
Result irsGetIrCameraHandle(IrsIrCameraHandle *handle, HidControllerID id);
/// Gets the IrCameraHandle for the specified controller.
Result irsGetIrCameraHandle(u32 *IrCameraHandle, HidControllerID id);
/// GetIrCameraStatus
Result irsGetIrCameraStatus(IrsIrCameraHandle handle, IrsIrCameraStatus *out);
/// CheckFirmwareUpdateNecessity
/// When successful where the output flag is set, the user should use \ref hidLaShowControllerFirmwareUpdate.
/// Only available on [4.0.0+].
Result irsCheckFirmwareUpdateNecessity(IrsIrCameraHandle handle, bool *out);
/// GetImageProcessorStatus
/// Only available on [4.0.0+].
Result irsGetImageProcessorStatus(IrsIrCameraHandle handle, IrsImageProcessorStatus *out);
/// Stop the current Processor.
/// \ref irsExit calls this with all IrCameraHandles which were not already used with \ref irsStopImageProcessor.
Result irsStopImageProcessor(IrsIrCameraHandle handle);
/// Stop the current Processor, async.
/// Only available on [4.0.0+].
Result irsStopImageProcessorAsync(IrsIrCameraHandle handle);
/**
* @brief Start ImageTransferProcessor.
* @param[in] IrCameraHandle Camera handle.
* @brief Run the MomentProcessor.
* @param[in] handle \ref IrsIrCameraHandle
* @param[in] config Input config.
*/
Result irsRunMomentProcessor(IrsIrCameraHandle handle, const IrsMomentProcessorConfig *config);
/**
* @brief Gets the states for MomentProcessor or IrLedProcessor.
* @note The official GetIrLedProcessorState is essentially the same as this, except it uses hard-coded count=1 with output-array on stack, without returning that data. Hence we don't implement a seperate func for that.
* @param[in] handle \ref IrsIrCameraHandle
* @param[out] states Output array of \ref IrsMomentProcessorState.
* @param[in] count Size of the states array in entries. Must be 1-5.
* @param[out] total_out Total output entries.
*/
Result irsGetMomentProcessorStates(IrsIrCameraHandle handle, IrsMomentProcessorState *states, s32 count, s32 *total_out);
/**
* @brief Calculates an \ref IrsMomentStatistic from the specified region in the input \ref IrsMomentProcessorState.
* @param[in] state \ref IrsMomentProcessorState
* @param[in] rect \ref IrsRect, containing the image width and height.
* @param[in] region_x Region x, must be 0-5 (clamped to this range otherwise). region_x = image_x/6.
* @param[in] region_y Region y, must be 0-7 (clamped to this range otherwise). region_y = image_y/8.
* @param[in] region_width Region width. region_x+region_width must be <=6 (clamped to this range otherwise).
* @param[in] region_height Region height. region_y+region_height must be <=8 (clamped to this range otherwise).
*/
IrsMomentStatistic irsCalculateMomentRegionStatistic(const IrsMomentProcessorState *state, IrsRect rect, s32 region_x, s32 region_y, s32 region_width, s32 region_height);
/**
* @brief Run the ClusteringProcessor.
* @param[in] handle \ref IrsIrCameraHandle
* @param[in] config Input config.
*/
Result irsRunClusteringProcessor(IrsIrCameraHandle handle, const IrsClusteringProcessorConfig *config);
/**
* @brief Gets the states for ClusteringProcessor.
* @param[in] handle \ref IrsIrCameraHandle
* @param[out] states Output array of \ref IrsClusteringProcessorState.
* @param[in] count Size of the states array in entries. Must be 1-5.
* @param[out] total_out Total output entries.
*/
Result irsGetClusteringProcessorStates(IrsIrCameraHandle handle, IrsClusteringProcessorState *states, s32 count, s32 *total_out);
/**
* @brief Run the ImageTransferProcessor.
* @param[in] handle \ref IrsIrCameraHandle
* @param[in] config Input config.
* @param[in] size Work-buffer size, must be 0x1000-byte aligned.
* @note Do not use if already started.
*/
Result irsRunImageTransferProcessor(u32 IrCameraHandle, IrsImageTransferProcessorConfig *config, size_t size);
Result irsGetImageTransferProcessorState(u32 IrCameraHandle, void* buffer, size_t size, IrsImageTransferProcessorState *state);
/// Stop ImageTransferProcessor. Do not use if already stopped.
/// \ref irsExit calls this with all IrCameraHandles which were not already used with \ref irsStopImageProcessor.
Result irsStopImageProcessor(u32 IrCameraHandle);
/// "Suspend" ImageTransferProcessor.
/// TODO: What does this really do?
Result irsSuspendImageProcessor(u32 IrCameraHandle);
Result irsRunImageTransferProcessor(IrsIrCameraHandle handle, const IrsImageTransferProcessorConfig *config, size_t size);
/**
* Gets the default configuration for Image Transfer mode.
* Defaults are exposure 300us, IR LEDs all ON, 8x digital gain, normal image and resolution 240 x 320.
* @brief Run the ImageTransferExProcessor.
* @note Only available on [4.0.0+].
* @param[in] handle \ref IrsIrCameraHandle
* @param[in] config Input config.
* @param[in] size Work-buffer size, must be 0x1000-byte aligned.
*/
Result irsRunImageTransferExProcessor(IrsIrCameraHandle handle, const IrsImageTransferProcessorExConfig *config, size_t size);
/// GetImageTransferProcessorState
Result irsGetImageTransferProcessorState(IrsIrCameraHandle handle, void* buffer, size_t size, IrsImageTransferProcessorState *state);
/**
* @brief Run the PointingProcessor.
* @param[in] handle \ref IrsIrCameraHandle
*/
Result irsRunPointingProcessor(IrsIrCameraHandle handle);
/**
* @brief Gets the states for PointingProcessor.
* @param[in] handle \ref IrsIrCameraHandle
* @param[out] states Output array of \ref IrsPointingProcessorMarkerState.
* @param[in] count Size of the states array in entries. Must be 1-6.
* @param[out] total_out Total output entries.
*/
Result irsGetPointingProcessorMarkerStates(IrsIrCameraHandle handle, IrsPointingProcessorMarkerState *states, s32 count, s32 *total_out);
/**
* @brief Gets the states for \ref IrsPointingProcessorState.
* @note This uses \ref irsGetPointingProcessorMarkerStates, then converts the output to \ref IrsPointingProcessorState.
* @param[in] handle \ref IrsIrCameraHandle
* @param[out] states Output array of \ref IrsPointingProcessorState.
* @param[in] count Size of the states array in entries. Must be 1-6.
* @param[out] total_out Total output entries.
*/
Result irsGetPointingProcessorStates(IrsIrCameraHandle handle, IrsPointingProcessorState *states, s32 count, s32 *total_out);
/**
* @brief Run the TeraPluginProcessor.
* @param[in] handle \ref IrsIrCameraHandle
* @param[in] config Input config.
*/
Result irsRunTeraPluginProcessor(IrsIrCameraHandle handle, const IrsTeraPluginProcessorConfig *config);
/**
* @brief Gets the states for TeraPluginProcessor, filtered using the input params.
* @param[in] handle \ref IrsIrCameraHandle
* @param[out] states Output array of \ref IrsTeraPluginProcessorState.
* @param[in] count Size of the states array in entries. Must be 1-5.
* @param[in] sampling_number Minimum value for IrsTeraPluginProcessorState::sampling_number.
* @param[in] prefix_data Only used when prefix_bitcount is not 0. The first prefix_bitcount bits from prefix_data must match the first prefix_bitcount bits in IrsTeraPluginProcessorState::plugin_data.
* @param[in] prefix_bitcount Total bits for prefix_data.
* @param[out] total_out Total output entries.
*/
Result irsGetTeraPluginProcessorStates(IrsIrCameraHandle handle, IrsTeraPluginProcessorState *states, s32 count, s64 sampling_number, u32 prefix_data, u32 prefix_bitcount, s32 *total_out);
/**
* @brief Run the IrLedProcessor.
* @note Only available on [4.0.0+].
* @param[in] handle \ref IrsIrCameraHandle
* @param[in] config Input config.
*/
Result irsRunIrLedProcessor(IrsIrCameraHandle handle, const IrsIrLedProcessorConfig *config);
/**
* @brief Run the AdaptiveClusteringProcessor.
* @note Only available on [5.0.0+].
* @param[in] handle \ref IrsIrCameraHandle
* @param[in] config Input config.
*/
Result irsRunAdaptiveClusteringProcessor(IrsIrCameraHandle handle, const IrsAdaptiveClusteringProcessorConfig *config);
/**
* @brief Run HandAnalysis.
* @param[in] handle \ref IrsIrCameraHandle
* @param[in] config Input config.
*/
Result irsRunHandAnalysis(IrsIrCameraHandle handle, const IrsHandAnalysisConfig *config);
/**
* Gets the default configuration for MomentProcessor.
*/
void irsGetMomentProcessorDefaultConfig(IrsMomentProcessorConfig *config);
/**
* Gets the default configuration for ClusteringProcessor.
*/
void irsGetClusteringProcessorDefaultConfig(IrsClusteringProcessorConfig *config);
/**
* Gets the default configuration for ImageTransferProcessor.
* Defaults are exposure 300us, 8x digital gain, the rest is all-zero. Format is ::IrsImageTransferProcessorFormat_320x240.
*/
void irsGetDefaultImageTransferProcessorConfig(IrsImageTransferProcessorConfig *config);
/**
* Gets the default configuration for ImageTransferProcessorEx.
* Defaults are exposure 300us, 8x digital gain, the rest is all-zero. OrigFormat/TrimmingFormat are ::IrsImageTransferProcessorFormat_320x240.
*/
void irsGetDefaultImageTransferProcessorExConfig(IrsImageTransferProcessorExConfig *config);
/**
* Gets the default configuration for IrLedProcessor.
*/
NX_CONSTEXPR void irsGetIrLedProcessorDefaultConfig(IrsIrLedProcessorConfig *config) {
config->light_target = 0;
}

View File

@ -66,3 +66,4 @@ Result ldrPmCreateProcess(u64 pin_id, u32 flags, Handle reslimit_h, Handle *out_
Result ldrPmGetProgramInfo(const NcmProgramLocation *loc, LoaderProgramInfo *out_program_info);
Result ldrPmPinProgram(const NcmProgramLocation *loc, u64 *out_pin_id);
Result ldrPmUnpinProgram(u64 pin_id);
Result ldrPmSetEnabledProgramVerification(bool enabled); ///< [10.0.0+]

View File

@ -42,6 +42,9 @@ Result lrLrResolveApplicationLegalInformationPath(LrLocationResolver* lr, u64 ti
Result lrLrRedirectApplicationLegalInformationPath(LrLocationResolver* lr, u64 tid, u64 tid2, const char *path);
Result lrLrRefresh(LrLocationResolver* lr);
/// Only available on [5.0.0+].
Result lrLrEraseProgramRedirection(LrLocationResolver* lr, u64 tid);
// IRegisteredLocationResolver
Result lrRegLrResolveProgramPath(LrRegisteredLocationResolver* reg, u64 tid, char *out);
// TODO: Other IRegisteredLocationResolver commands

View File

@ -0,0 +1,176 @@
/**
* @file mii.h
* @brief Mii services (mii:*) IPC wrapper.
* @author XorTroll
* @copyright libnx Authors
*/
#pragma once
#include "../types.h"
#include "../sf/service.h"
typedef enum {
MiiServiceType_System = 0, ///< Initializes mii:e.
MiiServiceType_User = 1, ///< Initializes mii:u.
} MiiServiceType;
/// Mii age.
typedef enum {
MiiAge_Young = 0, ///< Young
MiiAge_Normal = 1, ///< Normal
MiiAge_Old = 2, ///< Old
MiiAge_All = 3, ///< All of them
} MiiAge;
/// Mii gender.
typedef enum {
MiiGender_Male = 0, ///< Male
MiiGender_Female = 1, ///< Female
MiiGender_All = 2, ///< Both of them
} MiiGender;
/// Mii face color.
typedef enum {
MiiFaceColor_Black = 0, ///< Black
MiiFaceColor_White = 1, ///< White
MiiFaceColor_Asian = 2, ///< Asian
MiiFaceColor_All = 3, ///< All of them
} MiiFaceColor;
// Mii source flag.
typedef enum {
MiiSourceFlag_Database = BIT(0), ///< Miis created by the user
MiiSourceFlag_Default = BIT(1), ///< Default console miis
MiiSourceFlag_All = MiiSourceFlag_Database | MiiSourceFlag_Default, ///< All of them
} MiiSourceFlag;
// Mii special key code
typedef enum {
MiiSpecialKeyCode_Normal = 0, ///< Normal miis
MiiSpecialKeyCode_Special = 0xA523B78F, ///< Special miis
} MiiSpecialKeyCode;
typedef struct {
Service s;
} MiiDatabase;
// Mii create ID.
typedef struct {
Uuid uuid;
} MiiCreateId;
// Mii data structure.
typedef struct {
MiiCreateId create_id;
u16 mii_name[10+1]; ///< utf-16be, null-terminated
u8 unk_x26;
u8 mii_color;
u8 mii_sex;
u8 mii_height;
u8 mii_width;
u8 unk_x2b[2];
u8 mii_face_shape;
u8 mii_face_color;
u8 mii_wrinkles_style;
u8 mii_makeup_style;
u8 mii_hair_style;
u8 mii_hair_color;
u8 mii_has_hair_flipped;
u8 mii_eye_style;
u8 mii_eye_color;
u8 mii_eye_size;
u8 mii_eye_thickness;
u8 mii_eye_angle;
u8 mii_eye_pos_x;
u8 mii_eye_pos_y;
u8 mii_eyebrow_style;
u8 mii_eyebrow_color;
u8 mii_eyebrow_size;
u8 mii_eyebrow_thickness;
u8 mii_eyebrow_angle;
u8 mii_eyebrow_pos_x;
u8 mii_eyebrow_pos_y;
u8 mii_nose_style;
u8 mii_nose_size;
u8 mii_nose_pos;
u8 mii_mouth_style;
u8 mii_mouth_color;
u8 mii_mouth_size;
u8 mii_mouth_thickness;
u8 mii_mouth_pos;
u8 mii_facial_hair_color;
u8 mii_beard_style;
u8 mii_mustache_style;
u8 mii_mustache_size;
u8 mii_mustache_pos;
u8 mii_glasses_style;
u8 mii_glasses_color;
u8 mii_glasses_size;
u8 mii_glasses_pos;
u8 mii_has_mole;
u8 mii_mole_size;
u8 mii_mole_pos_x;
u8 mii_mole_pos_y;
u8 unk_x57;
} MiiCharInfo;
/// Initialize mii.
Result miiInitialize(MiiServiceType service_type);
/// Exit mii.
void miiExit(void);
/// Gets the Service object for the actual mii service session.
Service* miiGetServiceSession(void);
/**
* @brief Opens a mii database.
* @param[in] key_code Mii key code filter.
* @param[out] out Database.
*/
Result miiOpenDatabase(MiiDatabase *out, MiiSpecialKeyCode key_code);
/**
* @brief Returns whether the mii database is updated.
* @param[in] db Database.
* @param[in] flag Source flag.
* @param[out] out_updated Whether the mii database is updated.
*/
Result miiDatabaseIsUpdated(MiiDatabase *db, bool *out_updated, MiiSourceFlag flag);
/**
* @brief Returns whether the mii database is full.
* @param[in] db Database.
* @param[out] out_full Whether the mii database is full.
*/
Result miiDatabaseIsFull(MiiDatabase *db, bool *out_full);
/**
* @brief Returns number of miis in the database with the specified source flag.
* @param[in] db Database.
* @param[in] flag Source flag.
* @param[out] out_count Out mii count.
*/
Result miiDatabaseGetCount(MiiDatabase *db, s32 *out_count, MiiSourceFlag flag);
/**
* @brief Reads mii charinfo data from the specified source flag.
* @param[in] db Database.
* @param[in] flag Source flag.
* @param[out] out_infos Output mii charinfo array.
* @param[in] count Number of mii chainfos to read.
* @param[out] total_out Number of mii charinfos which were actually read.
*/
Result miiDatabaseGet1(MiiDatabase *db, MiiSourceFlag flag, MiiCharInfo *out_infos, s32 count, s32 *total_out);
/**
* @brief Generates a random mii charinfo (doesn't register it in the console database).
* @param[in] db Database.
* @param[in] age Mii's age.
* @param[in] gender Mii's gender.
* @param[in] face_color Mii's face color.
* @param[out] out_info Out mii charinfo data.
*/
Result miiDatabaseBuildRandom(MiiDatabase *db, MiiAge age, MiiGender gender, MiiFaceColor face_color, MiiCharInfo *out_info);
/// Closes a mii database.
void miiDatabaseClose(MiiDatabase *db);

View File

@ -0,0 +1,71 @@
/**
* @file miiimg.h
* @brief Mii image (miiimg) service IPC wrapper.
* @author XorTroll
* @copyright libnx Authors
*/
#pragma once
#include "../types.h"
#include "../sf/service.h"
#include "../services/mii.h"
/// Image ID.
typedef struct {
Uuid uuid;
} MiiimgImageId;
/// Image attribute.
typedef struct {
MiiimgImageId image_id; ///< Image ID.
MiiCreateId create_id; ///< Mii's create ID.
u32 unk;
u16 mii_name[10+1]; ///< utf-16be, null-terminated
} PACKED MiiimgImageAttribute;
/// Initialize miiimg.
Result miiimgInitialize(void);
/// Exit miiimg.
void miiimgExit(void);
/// Gets the Service object for the actual miiimg service session.
Service* miiimgGetServiceSession(void);
/**
* @brief Reloads the image database.
*/
Result miiimgReload(void);
/**
* @brief Gets the number of mii images in the database.
* @param[out] out_count Mii image count.
*/
Result miiimgGetCount(s32 *out_count);
/**
* @brief Gets whether the image database is empty.
* @param[out] out_empty Whether the database is empty.
*/
Result miiimgIsEmpty(bool *out_empty);
/**
* @brief Gets whether the image database is full.
* @param[out] out_empty Whether the database is full.
*/
Result miiimgIsFull(bool *out_full);
/**
* @brief Gets the image attribute for the specified image index.
* @param[in] index Image index.
* @param[out] out_attr Out image attribute.
*/
Result miiimgGetAttribute(s32 index, MiiimgImageAttribute *out_attr);
/**
* @brief Loads the image data (raw RGBA8) for the specified image ID.
* @note Server doesn't seem to check the image buffer size, but 0x40000 is the optimal size.
* @param[in] id Input image ID.
* @param[out] out_image Out iamge buffer.
* @param[in] out_image_size Out image buffer size.
*/
Result miiimgLoadImage(MiiimgImageId id, void* out_image, size_t out_image_size);

View File

@ -8,6 +8,7 @@
#pragma once
#include "../types.h"
#include "../sf/service.h"
#include "../services/mii.h"
/// NfpServiceType
typedef enum {
@ -72,61 +73,7 @@ typedef struct {
} PACKED NfpModelInfo;
typedef struct {
u8 unk_x0[0x10]; // Hash?
u16 mii_name[10+1]; ///< utf-16be, null-terminated
u8 unk_x26;
u8 mii_color;
u8 mii_sex;
u8 mii_height;
u8 mii_width;
u8 unk_x2b[2];
u8 mii_face_shape;
u8 mii_face_color;
u8 mii_wrinkles_style;
u8 mii_makeup_style;
u8 mii_hair_style;
u8 mii_hair_color;
u8 mii_has_hair_flipped;
u8 mii_eye_style;
u8 mii_eye_color;
u8 mii_eye_size;
u8 mii_eye_thickness;
u8 mii_eye_angle;
u8 mii_eye_pos_x;
u8 mii_eye_pos_y;
u8 mii_eyebrow_style;
u8 mii_eyebrow_color;
u8 mii_eyebrow_size;
u8 mii_eyebrow_thickness;
u8 mii_eyebrow_angle;
u8 mii_eyebrow_pos_x;
u8 mii_eyebrow_pos_y;
u8 mii_nose_style;
u8 mii_nose_size;
u8 mii_nose_pos;
u8 mii_mouth_style;
u8 mii_mouth_color;
u8 mii_mouth_size;
u8 mii_mouth_thickness;
u8 mii_mouth_pos;
u8 mii_facial_hair_color;
u8 mii_beard_style;
u8 mii_mustache_style;
u8 mii_mustache_size;
u8 mii_mustache_pos;
u8 mii_glasses_style;
u8 mii_glasses_color;
u8 mii_glasses_size;
u8 mii_glasses_pos;
u8 mii_has_mole;
u8 mii_mole_size;
u8 mii_mole_pos_x;
u8 mii_mole_pos_y;
u8 unk_x57;
} PACKED NfpMiiCharInfo;
typedef struct {
NfpMiiCharInfo mii;
MiiCharInfo mii;
u16 first_write_year;
u8 first_write_month;
u8 first_write_day;
@ -175,7 +122,7 @@ Result nfpMount(const NfcDeviceHandle *handle, NfpDeviceType device_type, NfpMou
Result nfpUnmount(const NfcDeviceHandle *handle);
/// Not available with ::NfpServiceType_System.
Result nfpOpenApplicationArea(const NfcDeviceHandle *handle, u32 app_id, u32 *npad_id);
Result nfpOpenApplicationArea(const NfcDeviceHandle *handle, u32 app_id);
/// Not available with ::NfpServiceType_System.
Result nfpGetApplicationArea(const NfcDeviceHandle *handle, void* buf, size_t buf_size);

View File

@ -30,9 +30,99 @@ typedef enum {
/// ClientId
typedef struct {
u32 id; ///< ClientId
u32 id; ///< ClientId
} NifmClientId;
/// IpV4Address
typedef struct {
u8 addr[4]; ///< IPv4 address, aka struct in_addr.
} NifmIpV4Address;
/// IpAddressSetting
typedef struct {
u8 is_automatic; ///< Whether this setting is automatic. Ignored by \ref nifmGetCurrentIpConfigInfo.
NifmIpV4Address current_addr; ///< Current address.
NifmIpV4Address subnet_mask; ///< Subnet Mask.
NifmIpV4Address gateway; ///< Gateway.
} NifmIpAddressSetting;
/// DnsSetting
typedef struct {
u8 is_automatic; ///< Whether this setting is automatic. Ignored by \ref nifmGetCurrentIpConfigInfo.
NifmIpV4Address primary_dns_server; ///< Primary DNS server.
NifmIpV4Address secondary_dns_server; ///< Secondary DNS server.
} NifmDnsSetting;
/// ProxySetting
typedef struct {
u8 enabled; ///< Enables using the proxy when set.
u8 pad; ///< Padding
u16 port; ///< Port
char server[0x64]; ///< Server string, NUL-terminated.
u8 auto_auth_enabled; ///< Enables auto-authentication when set, which uses the following two strings.
char user[0x20]; ///< User string, NUL-terminated.
char password[0x20]; ///< Password string, NUL-terminated.
u8 pad2; ///< Padding
} NifmProxySetting;
/// IpSettingData
typedef struct {
NifmIpAddressSetting ip_address_setting; ///< \ref NifmIpAddressSetting
NifmDnsSetting dns_setting; ///< \ref NifmDnsSetting
NifmProxySetting proxy_setting; ///< \ref NifmProxySetting
u16 mtu; ///< MTU
} NifmIpSettingData;
/// WirelessSettingData
typedef struct {
u8 ssid_len; ///< NifmSfWirelessSettingData::ssid_len
char ssid[0x21]; ///< NifmSfWirelessSettingData::ssid
u8 unk_x22; ///< NifmSfWirelessSettingData::unk_x21
u8 pad; ///< Padding
u32 unk_x24; ///< NifmSfWirelessSettingData::unk_x22
u32 unk_x28; ///< NifmSfWirelessSettingData::unk_x23
u8 passphrase[0x41]; ///< NifmSfWirelessSettingData::passphrase
u8 pad2[0x3]; ///< Padding
} NifmWirelessSettingData;
/// SfWirelessSettingData
typedef struct {
u8 ssid_len; ///< SSID length.
char ssid[0x20]; ///< SSID string.
u8 unk_x21; ///< Unknown
u8 unk_x22; ///< Unknown
u8 unk_x23; ///< Unknown
u8 passphrase[0x41]; ///< Passphrase
} NifmSfWirelessSettingData;
/// SfNetworkProfileData. Converted to/from \ref NifmNetworkProfileData.
typedef struct {
NifmIpSettingData ip_setting_data; ///< \ref NifmIpSettingData
Uuid uuid; ///< Uuid
char network_name[0x40]; ///< NUL-terminated Network Name string.
u8 unk_x112; ///< Unknown
u8 unk_x113; ///< Unknown
u8 unk_x114; ///< Unknown
u8 unk_x115; ///< Unknown
NifmSfWirelessSettingData wireless_setting_data; ///< \ref NifmSfWirelessSettingData
u8 pad; ///< Padding
} NifmSfNetworkProfileData;
/// NetworkProfileData. Converted from/to \ref NifmSfNetworkProfileData.
typedef struct {
Uuid uuid; ///< NifmSfNetworkProfileData::uuid
char network_name[0x40]; ///< NifmSfNetworkProfileData::network_name
u32 unk_x50; ///< NifmSfNetworkProfileData::unk_x112
u32 unk_x54; ///< NifmSfNetworkProfileData::unk_x113
u8 unk_x58; ///< NifmSfNetworkProfileData::unk_x114
u8 unk_x59; ///< NifmSfNetworkProfileData::unk_x115
u8 pad[2]; ///< Padding
NifmWirelessSettingData wireless_setting_data; ///< \ref NifmWirelessSettingData
NifmIpSettingData ip_setting_data; ///< \ref NifmIpSettingData
} NifmNetworkProfileData;
/// Initialize nifm. This is used automatically by gethostid().
Result nifmInitialize(NifmServiceType service_type);
@ -50,8 +140,43 @@ Service* nifmGetServiceSession_GeneralService(void);
*/
NifmClientId nifmGetClientId(void);
/**
* @brief GetCurrentNetworkProfile
* @param[out] profile \ref NifmNetworkProfileData
*/
Result nifmGetCurrentNetworkProfile(NifmNetworkProfileData *profile);
/**
* @brief GetNetworkProfile
* @param[in] uuid Uuid
* @param[out] profile \ref NifmNetworkProfileData
*/
Result nifmGetNetworkProfile(Uuid uuid, NifmNetworkProfileData *profile);
/**
* @brief SetNetworkProfile
* @note Only available with ::NifmServiceType_Admin.
* @param[in] profile \ref NifmNetworkProfileData
* @param[out] uuid Uuid
*/
Result nifmSetNetworkProfile(const NifmNetworkProfileData *profile, Uuid *uuid);
/**
* @brief GetCurrentIpAddress
* @param[out] out IPv4 address (struct in_addr).
*/
Result nifmGetCurrentIpAddress(u32* out);
/**
* @brief GetCurrentIpConfigInfo
* @param[out] current_addr Same as \ref nifmGetCurrentIpAddress output.
* @param[out] subnet_mask Subnet Mask (struct in_addr).
* @param[out] gateway Gateway (struct in_addr).
* @param[out] primary_dns_server Primary DNS server IPv4 address (struct in_addr).
* @param[out] secondary_dns_server Secondary DNS server IPv4 address (struct in_addr).
*/
Result nifmGetCurrentIpConfigInfo(u32 *current_addr, u32 *subnet_mask, u32 *gateway, u32 *primary_dns_server, u32 *secondary_dns_server);
/**
* @note Works only if called from nifm:a or nifm:s.
*/

View File

@ -0,0 +1,26 @@
/**
* @file nim.h
* @brief Network Install Manager (nim) service IPC wrapper.
* @author SciresM
* @copyright libnx Authors
*/
#pragma once
#include "../types.h"
#include "../sf/service.h"
/// SystemUpdateTaskId
typedef struct {
alignas(8) Uuid uuid; ///< UUID
} NimSystemUpdateTaskId;
/// Initialize nim.
Result nimInitialize(void);
/// Exit nim.
void nimExit(void);
/// Gets the Service object for the actual nim service session.
Service* nimGetServiceSession(void);
Result nimListSystemUpdateTask(s32 *out_count, NimSystemUpdateTaskId *out_task_ids, size_t max_task_ids);
Result nimDestroySystemUpdateTask(const NimSystemUpdateTaskId *task_id);

View File

@ -435,6 +435,7 @@ Result nsIsApplicationEntityMovable(u64 application_id, NcmStorageId storage_id,
/**
* @brief MoveApplicationEntity
* @note Only available on [1.0.0-9.2.0].
* @param[in] application_id ApplicationId.
* @param[in] storage_id \ref NcmStorageId
*/
@ -737,7 +738,7 @@ Result nsWithdrawApplicationUpdateRequest(u64 application_id);
/**
* @brief RequestVerifyAddOnContentsRights
* @note Only available on [3.0.0+].
* @note Only available on [3.0.0-9.2.0].
* @param[out] a \ref NsProgressAsyncResult
* @param[in] application_id ApplicationId.
*/
@ -1318,14 +1319,15 @@ void nsdevExit(void);
/// Gets the Service object for ns:dev.
Service* nsdevGetServiceSession(void);
Result nsdevLaunchProgram(u64* out_pid, const NsLaunchProperties* properties, u32 flags);
Result nsdevLaunchProgram(u64* out_pid, const NsLaunchProperties* properties, u32 flags); ///< [1.0.0-9.2.0]
Result nsdevTerminateProcess(u64 pid);
Result nsdevTerminateProgram(u64 tid);
Result nsdevGetShellEvent(Event* out_event); ///< Autoclear for nsdevShellEvent is always true.
Result nsdevGetShellEventInfo(NsShellEventInfo* out);
Result nsdevTerminateProgram(u64 tid); ///< [1.0.0-9.2.0]
Result nsdevGetShellEvent(Event* out_event); ///< Autoclear for nsdevShellEvent is always true. [1.0.0-9.2.0]
Result nsdevGetShellEventInfo(NsShellEventInfo* out); ///< [1.0.0-9.2.0]
Result nsdevTerminateApplication(void);
Result nsdevPrepareLaunchProgramFromHost(NsLaunchProperties* out, const char* path, size_t path_len);
Result nsdevLaunchApplicationForDevelop(u64* out_pid, u64 application_id, u32 flags);
Result nsdevPrepareLaunchProgramFromHost(NsLaunchProperties* out, const char* path, size_t path_len); ///< [1.0.0-9.2.0]
Result nsdevLaunchApplicationForDevelop(u64* out_pid, u64 application_id, u32 flags); ///< [1.0.0-9.2.0]
Result nsdevLaunchApplicationFromHost(u64* out_pid, const char* path, size_t path_len, u32 flags); ///< [10.0.0+]
Result nsdevLaunchApplicationWithStorageIdForDevelop(u64* out_pid, u64 application_id, u32 flags, u8 app_storage_id, u8 patch_storage_id);
Result nsdevIsSystemMemoryResourceLimitBoosted(bool* out); ///< [6.0.0-8.1.0]
Result nsdevGetRunningApplicationProcessIdForDevelop(u64* out_pid); ///< [6.0.0+]

View File

@ -0,0 +1,64 @@
/**
* @file pgl.h
* @brief PGL service IPC wrapper.
* @author SciresM
* @copyright libnx Authors
*/
#pragma once
#include "../types.h"
#include "../sf/service.h"
#include "../services/ncm_types.h"
#include "../services/pm.h"
/// LaunchFlag
typedef enum {
PglLaunchFlag_None = 0,
PglLaunchFlag_EnableDetailedCrashReport = BIT(0),
PglLaunchFlag_EnableCrashReportScreenShotForProduction = BIT(1),
PglLaunchFlag_EnableCrashReportScreenShotForDevelop = BIT(2),
} PglLaunchFlag;
/// SnapShotDumpType
typedef enum {
PglSnapShotDumpType_None = 0,
PglSnapShotDumpType_Auto = 1,
PglSnapShotDumpType_Full = 2,
} PglSnapShotDumpType;
typedef struct {
u64 id; ///< Program Id
u32 version; ///< Version
u8 content_type; ///< NcmContentType
u8 id_offset; ///< Id Offset
u8 reserved_0E[2]; ///< Padding
} PglContentMetaInfo;
typedef struct {
Service s;
} PglEventObserver;
/// Initialize pgl.
Result pglInitialize(void);
/// Exit pgl.
void pglExit(void);
/// Gets the Service object for the actual pgl service session.
Service* pglGetServiceSession(void);
Result pglLaunchProgram(u64 *out_pid, const NcmProgramLocation *loc, u32 pm_launch_flags, u8 pgl_launch_flags);
Result pglTerminateProcess(u64 pid);
Result pglLaunchProgramFromHost(u64 *out_pid, const char *content_path, u32 pm_launch_flags);
Result pglGetHostContentMetaInfo(PglContentMetaInfo *out, const char *content_path);
Result pglGetApplicationProcessId(u64 *out);
Result pglBoostSystemMemoryResourceLimit(u64 size);
Result pglIsProcessTracked(bool *out, u64 pid);
Result pglEnableApplicationCrashReport(bool en);
Result pglIsApplicationCrashReportEnabled(bool *out);
Result pglEnableApplicationAllThreadDumpOnCrash(bool en);
Result pglTriggerApplicationSnapShotDumper(PglSnapShotDumpType dump_type, const char *arg);
Result pglGetEventObserver(PglEventObserver *out);
Result pglEventObserverGetProcessEvent(PglEventObserver *observer, Event *out);
Result pglEventObserverGetProcessEventInfo(PglEventObserver *observer, PmProcessEventInfo *out);
void pglEventObserverClose(PglEventObserver *observer);

View File

@ -8,6 +8,11 @@
#include "../types.h"
#include "../sf/service.h"
typedef enum {
PlServiceType_User = 0, ///< Initializes pl:u.
PlServiceType_System = 1, ///< Initializes pl:s.
} PlServiceType;
/// SharedFontType
typedef enum {
PlSharedFontType_Standard = 0, ///< Japan, US and Europe
@ -28,7 +33,7 @@ typedef struct {
} PlFontData;
/// Initialize pl.
Result plInitialize(void);
Result plInitialize(PlServiceType service_type);
/// Exit pl.
void plExit(void);

View File

@ -124,4 +124,4 @@ Result pmshellClearJitDebugOccured(u64 pid);
Result pmshellNotifyBootFinished(void);
Result pmshellGetApplicationProcessIdForShell(u64* pid_out);
Result pmshellBoostSystemMemoryResourceLimit(u64 boost_size);
Result pmshellBoostSystemThreadResourceLimit(void);
Result pmshellEnableApplicationExtraThread(void);

View File

@ -51,9 +51,8 @@ typedef enum {
SetRegion_USA = 1, ///< The Americas
SetRegion_EUR = 2, ///< Europe
SetRegion_AUS = 3, ///< Australia/New Zealand
SetRegion_CHN = 4, ///< China
SetRegion_KOR = 5, ///< Korea
SetRegion_TWN = 6, ///< Taiwan
SetRegion_HTK = 4, ///< Hong Kong/Taiwan/Korea
SetRegion_CHN = 5, ///< China
} SetRegion;
/// ConnectionFlag
@ -341,6 +340,11 @@ typedef struct {
char digest[0x40];
} SetSysFirmwareVersionDigest;
/// Structure returned by \ref setsysGetSerialNumber.
typedef struct {
char number[0x18];
} SetSysSerialNumber;
/// UserSelectorSettings
typedef struct {
u32 flags; ///< Bitmask with \ref SetSysUserSelectorFlag.
@ -821,9 +825,7 @@ typedef struct {
u32 generation;
} SetCalRsa2048DeviceKey;
typedef struct {
char number[0x18];
} SetCalSerialNumber;
typedef SetSysSerialNumber SetCalSerialNumber;
typedef struct {
u8 parameter[0x5A];
@ -1291,9 +1293,9 @@ Result setsysGetBatteryLot(SetBatteryLot *out);
/**
* @brief Gets the system's serial number.
* @param serial Pointer to output the serial to. (The buffer size needs to be at least 0x19 bytes)
* @param[out] out \ref SetSysSerialNumber
*/
Result setsysGetSerialNumber(char *serial);
Result setsysGetSerialNumber(SetSysSerialNumber *out);
/**
* @brief GetNfcEnableFlag

View File

@ -53,13 +53,18 @@ typedef struct {
} TimeLocationName;
typedef struct {
s64 time_point; ///< A point in time.
s64 time_point; ///< Monotonic count in seconds.
Uuid source_id; ///< An ID representing the clock source.
} TimeSteadyClockTimePoint;
typedef struct {
s64 time_point;
TimeSteadyClockTimePoint steady_clock_time_point;
s64 base_time;
Uuid source_id;
} TimeStandardSteadyClockTimePointType;
typedef struct {
s64 offset;
TimeSteadyClockTimePoint timestamp;
} TimeSystemClockContext;
/// Initialize time. Used automatically during app startup.
@ -74,9 +79,30 @@ Service* timeGetServiceSession(void);
/// Gets the Service object for ISystemClock with the specified \ref TimeType. This will return NULL when the type is invalid.
Service* timeGetServiceSession_SystemClock(TimeType type);
/// Gets the Service object for ISteadyClock.
Service* timeGetServiceSession_SteadyClock(void);
/// Gets the Service object for ITimeZoneService.
Service* timeGetServiceSession_TimeZoneService(void);
/// [6.0.0+] Gets the address of the SharedMemory.
void* timeGetSharedmemAddr(void);
/**
* @brief Gets the timepoint for the standard steady clock.
* @param[out] out Output timepoint (see \ref TimeSteadyClockTimePoint)
* @remark The standard steady clock counts time since the RTC was configured (usually this happens during manufacturing).
* @return Result code.
*/
Result timeGetStandardSteadyClockTimePoint(TimeSteadyClockTimePoint *out);
/**
* @brief [3.0.0+] Gets the internal offset for the standard steady clock.
* @param[out] out Output internal offset.
* @return Result code.
*/
Result timeGetStandardSteadyClockInternalOffset(s64 *out);
/**
* @brief Gets the time for the specified clock.
* @param[in] type Clock to use.

View File

@ -47,6 +47,8 @@ typedef void (*VoidFn)(void); ///< Function without arguments nor return v
typedef struct { u8 uuid[0x10]; } Uuid; ///< Unique identifier.
typedef struct { float value[3]; } UtilFloat3; ///< 3 floats.
/// Creates a bitmask from a bit number.
#ifndef BIT
#define BIT(n) (1U<<(n))

View File

@ -46,7 +46,7 @@ Result shmemMap(SharedMemory* s)
}
}
else {
rc = LibnxError_AlreadyMapped;
rc = MAKERESULT(Module_Libnx, LibnxError_AlreadyMapped);
}
return rc;

View File

@ -93,7 +93,7 @@ SVC_BEGIN svcGetThreadCoreMask
svc 0xE
ldp x3, x4, [sp], #16
str w1, [x3]
str w2, [x4]
str x2, [x4]
ret
SVC_END
@ -481,6 +481,15 @@ SVC_BEGIN svcQueryPhysicalAddress
SVC_END
SVC_BEGIN svcQueryIoMapping
stp x0, x1, [sp, #-16]!
svc 0x55
ldp x3, x4, [sp], #16
str x1, [x3]
str x2, [x4]
ret
SVC_END
SVC_BEGIN svcLegacyQueryIoMapping
str x0, [sp, #-16]!
svc 0x55
ldr x2, [sp], #16

View File

@ -9,6 +9,7 @@
#include "kernel/thread.h"
#include "kernel/wait.h"
#include "services/fatal.h"
#include "runtime/env.h"
#include "../internal.h"
#define USER_TLS_BEGIN 0x108
@ -23,6 +24,8 @@ extern u8 __tls_end[];
static Mutex g_threadMutex;
static Thread* g_threadList;
static Thread g_mainThread;
static u64 g_tlsUsageMask;
static void (* g_tlsDestructors[NUM_TLS_SLOTS])(void*);
@ -60,6 +63,33 @@ static void _EntryWrap(ThreadEntryArgs* args) {
threadExit();
}
void __libnx_init_thread(void) {
g_mainThread.handle = envGetMainThreadHandle();
MemoryInfo mem_info = {0};
u32 page_info;
svcQueryMemory(&mem_info, &page_info, (u64)(&mem_info));
// Set stack.
g_mainThread.owns_stack_mem = false;
g_mainThread.stack_mem = NULL;
g_mainThread.stack_mirror = (void*)mem_info.addr;
g_mainThread.stack_sz = mem_info.size;
// Set the TLS array.
mutexLock(&g_threadMutex);
g_mainThread.tls_array = (void**)((u8*)armGetTls() + USER_TLS_BEGIN);
g_mainThread.prev_next = &g_threadList;
g_mainThread.next = g_threadList;
if (g_threadList)
g_threadList->prev_next = &g_mainThread.next;
g_threadList = &g_mainThread;
mutexUnlock(&g_threadMutex);
// Set thread_ptr.
getThreadVars()->thread_ptr = &g_mainThread;
}
Result threadCreate(
Thread* t, ThreadFunc entry, void* arg, void* stack_mem, size_t stack_sz,
int prio, int cpuid)
@ -219,17 +249,21 @@ Result threadClose(Thread* t) {
}
Result threadPause(Thread* t) {
return svcSetThreadActivity(t->handle, 1);
return svcSetThreadActivity(t->handle, ThreadActivity_Paused);
}
Result threadResume(Thread* t) {
return svcSetThreadActivity(t->handle, 0);
return svcSetThreadActivity(t->handle, ThreadActivity_Runnable);
}
Result threadDumpContext(ThreadContext* ctx, Thread* t) {
return svcGetThreadContext3(ctx, t->handle);
}
Thread *threadGetSelf(void) {
return getThreadVars()->thread_ptr;
}
Handle threadGetCurHandle(void) {
return getThreadVars()->handle;
}

View File

@ -2,7 +2,6 @@
#include <string.h>
#include <sys/iosupport.h>
#include "runtime/devices/console.h"
#include "kernel/svc.h"
#include "default_font_bin.h"
@ -450,62 +449,26 @@ static ssize_t con_write(struct _reent *r,void *fd,const char *ptr, size_t len)
}
static const devoptab_t dotab_stdout = {
"con",
0,
NULL,
NULL,
con_write,
NULL,
NULL,
NULL
.name = "con",
.write_r = con_write,
};
//---------------------------------------------------------------------------------
static ssize_t debug_write(struct _reent *r, void *fd, const char *ptr, size_t len) {
//---------------------------------------------------------------------------------
svcOutputDebugString(ptr,len);
return len;
const devoptab_t* __nx_get_console_dotab(void) {
return &dotab_stdout;
}
static const devoptab_t dotab_svc = {
"svc",
0,
NULL,
NULL,
debug_write,
NULL,
NULL,
NULL
};
static const devoptab_t dotab_null = {
"null",
0,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL
};
ConsoleRenderer* getDefaultConsoleRenderer(void);
//---------------------------------------------------------------------------------
PrintConsole* consoleInit(PrintConsole* console) {
//---------------------------------------------------------------------------------
static bool firstConsoleInit = true;
static bool didFirstConsoleInit = false;
if(firstConsoleInit) {
if(!didFirstConsoleInit) {
devoptab_list[STD_OUT] = &dotab_stdout;
devoptab_list[STD_ERR] = &dotab_stdout;
setvbuf(stdout, NULL , _IONBF, 0);
setvbuf(stderr, NULL , _IONBF, 0);
firstConsoleInit = false;
setvbuf(stdout, NULL, _IONBF, 0);
didFirstConsoleInit = true;
}
if(console) {
@ -551,29 +514,6 @@ void consoleUpdate(PrintConsole* console) {
}
}
//---------------------------------------------------------------------------------
void consoleDebugInit(debugDevice device) {
//---------------------------------------------------------------------------------
int buffertype = _IONBF;
switch(device) {
case debugDevice_SVC:
devoptab_list[STD_ERR] = &dotab_svc;
buffertype = _IOLBF;
break;
case debugDevice_CONSOLE:
devoptab_list[STD_ERR] = &dotab_stdout;
break;
case debugDevice_NULL:
devoptab_list[STD_ERR] = &dotab_null;
break;
}
setvbuf(stderr, NULL , buffertype, 0);
}
//---------------------------------------------------------------------------------
PrintConsole *consoleSelect(PrintConsole* console) {
//---------------------------------------------------------------------------------

View File

@ -0,0 +1,48 @@
#include <stdio.h>
#include <string.h>
#include <sys/iosupport.h>
#include "runtime/devices/console.h"
#include "kernel/svc.h"
//---------------------------------------------------------------------------------
static ssize_t debug_write(struct _reent *r, void *fd, const char *ptr, size_t len) {
//---------------------------------------------------------------------------------
svcOutputDebugString(ptr,len);
return len;
}
static const devoptab_t dotab_svc = {
.name = "svc",
.write_r = debug_write,
};
static const devoptab_t dotab_null = {
.name = "null",
};
__attribute__((weak)) const devoptab_t* __nx_get_console_dotab(void) {
return &dotab_null;
}
//---------------------------------------------------------------------------------
void consoleDebugInit(debugDevice device) {
//---------------------------------------------------------------------------------
int buffertype = _IONBF;
switch(device) {
case debugDevice_SVC:
devoptab_list[STD_ERR] = &dotab_svc;
buffertype = _IOLBF;
break;
case debugDevice_CONSOLE:
devoptab_list[STD_ERR] = __nx_get_console_dotab();
break;
case debugDevice_NULL:
devoptab_list[STD_ERR] = &dotab_null;
break;
}
setvbuf(stderr, NULL, buffertype, 0);
}

View File

@ -465,6 +465,32 @@ Result fsdevMountSaveData(const char *name, u64 application_id, AccountUid uid)
return rc;
}
Result fsdevMountSaveDataReadOnly(const char *name, u64 application_id, AccountUid uid)
{
FsFileSystem fs;
Result rc = fsOpen_SaveDataReadOnly(&fs, application_id, uid);
if(R_SUCCEEDED(rc))
{
int ret = fsdevMountDevice(name, fs);
if(ret==-1)
rc = MAKERESULT(Module_Libnx, LibnxError_OutOfMemory);
}
return rc;
}
Result fsdevMountBcatSaveData(const char *name, u64 application_id)
{
FsFileSystem fs;
Result rc = fsOpen_BcatSaveData(&fs, application_id);
if(R_SUCCEEDED(rc))
{
int ret = fsdevMountDevice(name, fs);
if(ret==-1)
rc = MAKERESULT(Module_Libnx, LibnxError_OutOfMemory);
}
return rc;
}
Result fsdevMountDeviceSaveData(const char *name, u64 application_id)
{
FsFileSystem fs;
@ -478,6 +504,32 @@ Result fsdevMountDeviceSaveData(const char *name, u64 application_id)
return rc;
}
Result fsdevMountTemporaryStorage(const char *name)
{
FsFileSystem fs;
Result rc = fsOpen_TemporaryStorage(&fs);
if(R_SUCCEEDED(rc))
{
int ret = fsdevMountDevice(name, fs);
if(ret==-1)
rc = MAKERESULT(Module_Libnx, LibnxError_OutOfMemory);
}
return rc;
}
Result fsdevMountCacheStorage(const char *name, u64 application_id, u16 save_data_index)
{
FsFileSystem fs;
Result rc = fsOpen_CacheStorage(&fs, application_id, save_data_index);
if(R_SUCCEEDED(rc))
{
int ret = fsdevMountDevice(name, fs);
if(ret==-1)
rc = MAKERESULT(Module_Libnx, LibnxError_OutOfMemory);
}
return rc;
}
Result fsdevMountSystemSaveData(const char *name, FsSaveDataSpaceId save_data_space_id, u64 system_save_data_id, AccountUid uid)
{
FsFileSystem fs;
@ -491,6 +543,19 @@ Result fsdevMountSystemSaveData(const char *name, FsSaveDataSpaceId save_data_sp
return rc;
}
Result fsdevMountSystemBcatSaveData(const char *name, u64 system_save_data_id)
{
FsFileSystem fs;
Result rc = fsOpen_SystemBcatSaveData(&fs, system_save_data_id);
if(R_SUCCEEDED(rc))
{
int ret = fsdevMountDevice(name, fs);
if(ret==-1)
rc = MAKERESULT(Module_Libnx, LibnxError_OutOfMemory);
}
return rc;
}
void __libnx_init_cwd(void)
{
if(envIsNso() || __system_argc==0 || __system_argv[0] == NULL)

View File

@ -4,6 +4,7 @@
#include <errno.h>
#include <alloca.h>
#include <sys/iosupport.h>
#include <malloc.h>
#include <fcntl.h>
#include <poll.h>
@ -16,6 +17,7 @@
#include "result.h"
#include "services/bsd.h"
#include "runtime/devices/socket.h"
#include "runtime/hosversion.h"
__attribute__((weak)) size_t __nx_pollfd_sb_max_fds = 64;
@ -669,39 +671,338 @@ int socketpair(int domain, int type, int protocol, int sv[2]) {
ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags) {
if(msg == NULL) {
errno = EFAULT;
errno = EINVAL;
return -1;
}
struct mmsghdr msgvec = {
.msg_hdr = *msg,
.msg_len = 1,
.msg_len = 0,
};
return recvmmsg(sockfd, &msgvec, 1, flags, NULL);
ssize_t ret = recvmmsg(sockfd, &msgvec, 1, flags, NULL);
if (ret >= 0) {
*msg = msgvec.msg_hdr;
ret = msgvec.msg_len;
}
return ret;
}
ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags) {
if(msg == NULL) {
errno = EFAULT;
errno = EINVAL;
return -1;
}
struct mmsghdr msgvec = {
.msg_hdr = *msg,
.msg_len = 1,
.msg_len = 0,
};
return sendmmsg(sockfd, &msgvec, 1, flags);
ssize_t ret = sendmmsg(sockfd, &msgvec, 1, flags);
if (ret > 0) ret = msgvec.msg_len;
return ret;
}
static int _serializeMmsg(u8 *outbuf, size_t outbuf_size, struct mmsghdr *msgvec, unsigned int vlen, bool is_send) {
void* tmp_ptr = NULL;
u8 *dataptr = outbuf;
*dataptr++ = 0x8;
for (unsigned int i=0; i<vlen; i++) {
socklen_t msg_controllen = msgvec[i].msg_hdr.msg_controllen;
if (msg_controllen >= sizeof(struct cmsghdr)) {
struct cmsghdr *cmsg = msgvec[i].msg_hdr.msg_control;
if (cmsg) {
if (cmsg->cmsg_level == 0xffff && cmsg->cmsg_type == 1) {
errno = EOPNOTSUPP;
return -1;
}
}
}
socklen_t msg_namelen = msgvec[i].msg_hdr.msg_namelen;
*((socklen_t*)dataptr) = msg_namelen;
dataptr+= sizeof(socklen_t);
if (is_send && (tmp_ptr = msgvec[i].msg_hdr.msg_name)) memcpy(dataptr, tmp_ptr, msg_namelen);
dataptr+= msg_namelen;
int msg_iovlen = msgvec[i].msg_hdr.msg_iovlen;
*((int*)dataptr) = msg_iovlen;
dataptr+= sizeof(int);
for (int veci=0; veci<msg_iovlen; veci++) {
struct iovec *vec = &msgvec[i].msg_hdr.msg_iov[veci];
u64 iov_len = vec->iov_len;
*((u64*)dataptr) = iov_len;
dataptr+= sizeof(u64);
if (is_send) memcpy(dataptr, vec->iov_base, iov_len);
dataptr+= iov_len;
}
*((socklen_t*)dataptr) = msg_controllen;
dataptr+= sizeof(socklen_t);
if (is_send && (tmp_ptr = msgvec[i].msg_hdr.msg_control)) memcpy(dataptr, tmp_ptr, msg_controllen);
dataptr+= msg_controllen;
*((int*)dataptr) = msgvec[i].msg_hdr.msg_flags;
dataptr+= sizeof(int);
*((int*)dataptr) = msgvec[i].msg_len;
dataptr+= sizeof(int);
}
// sdknso would verify that dataptr isn't larger than outbuf+outbuf_size (Abort otherwise), but that can't happen anyway since the caller allocates enough space.
return (uintptr_t)dataptr-(uintptr_t)outbuf;
}
static int _deserializeMmsg(struct mmsghdr *msgvec, unsigned int vlen, u8 *inbuf, size_t inbuf_size, bool is_recv) {
bool bounds_flag=0;
void* tmp_ptr = NULL;
u8 *dataptr = &inbuf[0x1];
uintptr_t inbuf_end = (uintptr_t)&inbuf[inbuf_size];
// sdknso verifies that dataptr isn't larger than outbuf+outbuf_size at the end prior to returning (Abort otherwise). We'll also verify it during the loop, and also verify that sizes from the buffer are not larger than the original msgvec values.
for (unsigned int i=0; i<vlen; i++) {
if ((uintptr_t)dataptr > (uintptr_t)inbuf_end || (uintptr_t)dataptr+sizeof(socklen_t) > inbuf_end) {
bounds_flag = 1;
break;
}
socklen_t msg_namelen = *((socklen_t*)dataptr);
dataptr+= sizeof(socklen_t);
if ((uintptr_t)dataptr+msg_namelen > inbuf_end || msg_namelen > msgvec[i].msg_hdr.msg_namelen) {
bounds_flag = 1;
break;
}
msgvec[i].msg_hdr.msg_namelen = msg_namelen;
if (is_recv && (tmp_ptr = msgvec[i].msg_hdr.msg_name)) {
memcpy(tmp_ptr, dataptr, msg_namelen);
}
dataptr+= msg_namelen;
if ((uintptr_t)dataptr+sizeof(int) > inbuf_end) {
bounds_flag = 1;
break;
}
int msg_iovlen = *((int*)dataptr);
dataptr+= sizeof(int);
if (msg_iovlen > msgvec[i].msg_hdr.msg_iovlen) {
bounds_flag = 1;
break;
}
msgvec[i].msg_hdr.msg_iovlen = msg_iovlen;
for (int veci=0; veci<msg_iovlen; veci++) {
struct iovec *vec = &msgvec[i].msg_hdr.msg_iov[veci];
if ((uintptr_t)dataptr+sizeof(u64) > inbuf_end) {
bounds_flag = 1;
break;
}
u64 iov_len = *((u64*)dataptr);
dataptr+= sizeof(u64);
if (iov_len > inbuf_size || (uintptr_t)dataptr+iov_len > inbuf_end || iov_len > vec->iov_len) {
bounds_flag = 1;
break;
}
vec->iov_len = iov_len;
if (is_recv) memcpy(vec->iov_base, dataptr, iov_len);
dataptr+= iov_len;
}
if (bounds_flag) break;
if ((uintptr_t)dataptr+sizeof(socklen_t) > inbuf_end) {
bounds_flag = 1;
break;
}
socklen_t msg_controllen = *((socklen_t*)dataptr);
dataptr+= sizeof(socklen_t);
if ((uintptr_t)dataptr+msg_controllen > inbuf_end || msg_controllen > msgvec[i].msg_hdr.msg_controllen) {
bounds_flag = 1;
break;
}
msgvec[i].msg_hdr.msg_controllen = msg_controllen;
if (is_recv && (tmp_ptr = msgvec[i].msg_hdr.msg_control)) {
memcpy(tmp_ptr, dataptr, msg_controllen);
}
dataptr+= msg_controllen;
if ((uintptr_t)dataptr+sizeof(int) > inbuf_end) {
bounds_flag = 1;
break;
}
msgvec[i].msg_hdr.msg_flags = *((int*)dataptr);
dataptr+= sizeof(int);
if ((uintptr_t)dataptr+sizeof(int) > inbuf_end) {
bounds_flag = 1;
break;
}
msgvec[i].msg_len = *((int*)dataptr);
dataptr+= sizeof(int);
if (msg_controllen >= sizeof(struct cmsghdr)) {
struct cmsghdr *cmsg = msgvec[i].msg_hdr.msg_control;
if (cmsg) {
if (cmsg->cmsg_level == 0xffff && cmsg->cmsg_type == 1) {
errno = EOPNOTSUPP;
return -1;
}
}
}
}
if (bounds_flag || (uintptr_t)dataptr > inbuf_end) {
errno = EFAULT;
return -1;
}
return (uintptr_t)dataptr-(uintptr_t)inbuf;
}
static int _mmsgInitCommon(u8 **buf, size_t *alignsize, struct mmsghdr *msgvec, unsigned int vlen) {
size_t msgdatasize_total = 0;
size_t bufsize = 1;
for (unsigned int i=0; i<vlen; i++) {
bufsize+= sizeof(socklen_t) + msgvec[i].msg_hdr.msg_namelen + sizeof(int);
int msg_iovlen = msgvec[i].msg_hdr.msg_iovlen;
for (int veci=0; veci<msg_iovlen; veci++) {
size_t iov_len = msgvec[i].msg_hdr.msg_iov[veci].iov_len;
bufsize += sizeof(u64) + iov_len;
msgdatasize_total += iov_len;
}
bufsize+= sizeof(socklen_t) + msgvec[i].msg_hdr.msg_controllen + sizeof(int) + sizeof(int);
}
if (msgdatasize_total > 0x80000) {
errno = EMSGSIZE;
return -1;
}
*alignsize = (bufsize+0xfff) & ~0xfff;
*buf = (u8*)memalign(0x1000, *alignsize);
if (*buf == NULL) {
errno = ENOMEM;
return -1;
}
memset(*buf, 0, *alignsize);
return 0;
}
int sendmmsg(int sockfd, struct mmsghdr *msgvec, unsigned int vlen, int flags) {
//TODO: do the necessary RE & implement it
errno = ENOSYS;
return -1;
if (hosversionBefore(7,0,0)) { // This cmd was added with [3.0.0+], but we'll only support the updated [7.0.0+] version of it.
errno = ENOSYS;
return -1;
}
if(msgvec == NULL) {
errno = EINVAL;
return -1;
}
if(vlen < 1 || vlen > 0x20) {
errno = EMSGSIZE;
return -1;
}
sockfd = _socketGetFd(sockfd);
if(sockfd == -1)
return -1;
int ret=0, ret2=0;
u8 *buf = NULL;
size_t alignsize=0;
ret = _mmsgInitCommon(&buf, &alignsize, msgvec, vlen);
if (ret==-1) return ret;
ret = _serializeMmsg(buf, alignsize, msgvec, vlen, 1);
if (ret>=0) ret = _socketParseBsdResult(NULL, bsdSendMMsg(sockfd, buf, alignsize, vlen, flags));
if (ret>=0 && ret>vlen) { // sdknso doesn't check this, but we will.
errno = EFAULT;
ret = -1;
}
if (ret>=0) {
ret2 = _deserializeMmsg(msgvec, ret, buf, alignsize, 0);
if (ret2==-1) ret = ret2;
}
free(buf);
return ret;
}
int recvmmsg(int sockfd, struct mmsghdr *msgvec, unsigned int vlen, int flags, struct timespec *timeout) {
//TODO: do the necessary RE & implement it
errno = ENOSYS;
return -1;
if (hosversionBefore(7,0,0)) { // This cmd was added with [3.0.0+], but we'll only support the updated [7.0.0+] version of it.
errno = ENOSYS;
return -1;
}
if(msgvec == NULL || (vlen < 1 || vlen > 0x20)) {
errno = EINVAL;
return -1;
}
sockfd = _socketGetFd(sockfd);
if(sockfd == -1)
return -1;
int ret=0, ret2=0;
u8 *buf = NULL;
size_t alignsize=0;
ret = _mmsgInitCommon(&buf, &alignsize, msgvec, vlen);
if (ret==-1) return ret;
struct timespec tmp_timeout={0};
if (timeout) tmp_timeout = *timeout;
ret = _serializeMmsg(buf, alignsize, msgvec, vlen, 0);
if (ret>=0) ret = _socketParseBsdResult(NULL, bsdRecvMMsg(sockfd, buf, alignsize, vlen, flags, &tmp_timeout));
if (ret>=0 && ret>vlen) { // sdknso doesn't check this, but we will.
errno = EFAULT;
ret = -1;
}
if (ret>=0) {
ret2 = _deserializeMmsg(msgvec, ret, buf, alignsize, 1);
if (ret2==-1) ret = ret2;
}
free(buf);
return ret;
}

View File

@ -16,6 +16,7 @@ void NORETURN __nx_exit(Result rc, LoaderReturnFn retaddr);
void virtmemSetup(void);
void newlibSetup(void);
void argvSetup(void);
void __libnx_init_thread(void);
void __libnx_init_time(void);
void __libnx_init_cwd(void);
@ -174,6 +175,7 @@ void __attribute__((weak)) __libnx_init(void* ctx, Handle main_thread, void* sav
newlibSetup();
virtmemSetup();
__libnx_initheap();
__libnx_init_thread();
// Build argc/argv if present
argvSetup();

View File

@ -9,7 +9,7 @@
static int sock = -1;
int nxlinkStdio(void)
int nxlinkConnectToHost(bool redirStdout, bool redirStderr)
{
int ret = -1;
struct sockaddr_in srv_addr;
@ -30,12 +30,17 @@ int nxlinkStdio(void)
return -1;
}
// redirect stdout
fflush(stdout);
dup2(sock, STDOUT_FILENO);
// redirect stderr
fflush(stderr);
dup2(sock, STDERR_FILENO);
if (redirStdout) {
// redirect stdout
fflush(stdout);
dup2(sock, STDOUT_FILENO);
}
if (redirStderr) {
// redirect stderr
fflush(stderr);
dup2(sock, STDERR_FILENO);
}
return sock;
}

View File

@ -2726,7 +2726,13 @@ IPC_MAKE_CMD_IMPL_HOSVER(Result appletGetHomeButtonDoubleClickEnabled(bool *out)
// IDebugFunctions
IPC_MAKE_CMD_IMPL(Result appletOpenMainApplication(AppletApplication *a), &g_appletIDebugFunctions, 1, _appletApplicationCreate, a)
Result appletOpenMainApplication(AppletApplication *a) {
if (hosversionAtLeast(10,0,0))
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
return _appletApplicationCreate(&g_appletIDebugFunctions, a, 1);
}
IPC_MAKE_CMD_IMPL(Result appletPerformSystemButtonPressing(AppletSystemButtonType type), &g_appletIDebugFunctions, 10, _appletCmdInU32NoOut, type)
IPC_MAKE_CMD_IMPL(Result appletInvalidateTransitionLayer(void), &g_appletIDebugFunctions, 20, _appletCmdNoIO)

View File

@ -220,3 +220,41 @@ Result audoutContainsAudioOutBuffer(AudioOutBuffer *Buffer, bool *ContainsBuffer
if (R_SUCCEEDED(rc) && ContainsBuffer) *ContainsBuffer = out & 1;
return rc;
}
Result audoutGetAudioOutBufferCount(u32 *count) {
if (hosversionBefore(4,0,0))
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
return serviceDispatchOut(&g_audoutIAudioOut, 9, *count);
}
Result audoutGetAudioOutPlayedSampleCount(u64 *count) {
if (hosversionBefore(4,0,0))
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
return serviceDispatchOut(&g_audoutIAudioOut, 10, *count);
}
Result audoutFlushAudioOutBuffers(bool *flushed) {
if (hosversionBefore(4,0,0))
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
u8 out=0;
Result rc = serviceDispatchOut(&g_audoutIAudioOut, 11, out);
if (R_SUCCEEDED(rc) && flushed) *flushed = out & 1;
return rc;
}
Result audoutSetAudioOutVolume(float volume) {
if (hosversionBefore(6,0,0))
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
return serviceDispatchIn(&g_audoutIAudioOut, 12, volume);
}
Result audoutGetAudioOutVolume(float *volume) {
if (hosversionBefore(6,0,0))
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
return serviceDispatchOut(&g_audoutIAudioOut, 13, *volume);
}

View File

@ -32,6 +32,9 @@ Result bpcRebootSystem(void) {
}
Result bpcGetSleepButtonState(BpcSleepButtonState *out) {
if (hosversionBefore(2,0,0))
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
u8 tmp = 0;
Result rc = serviceDispatchOut(&g_bpcSrv, 6, tmp);

View File

@ -17,6 +17,7 @@
#include "kernel/rwlock.h"
#include "sf/sessionmgr.h"
#include "services/bsd.h"
#include "runtime/hosversion.h"
typedef struct BsdSelectTimeval {
struct timeval tv;
@ -575,3 +576,37 @@ int bsdDuplicateSocket(int sockfd) {
return _bsdDispatchIn(27, in);
}
int bsdRecvMMsg(int sockfd, void *buf, size_t size, unsigned int vlen, int flags, struct timespec *timeout) {
if (hosversionBefore(7,0,0)) // This cmd was added with [3.0.0+], but we'll only support the updated [7.0.0+] version of it.
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
const struct {
int sockfd;
int vlen;
int flags;
u32 _padding;
struct timespec timeout;
} in = { sockfd, vlen, flags, 0, *timeout };
return _bsdDispatchIn(29, in,
.buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out },
.buffers = { { buf, size } },
);
}
int bsdSendMMsg(int sockfd, void *buf, size_t size, unsigned int vlen, int flags) {
if (hosversionBefore(7,0,0)) // This cmd was added with [3.0.0+], but we'll only support the updated [7.0.0+] version of it.
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
const struct {
int sockfd;
int vlen;
int flags;
} in = { sockfd, vlen, flags };
return _bsdDispatchIn(30, in,
.buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out },
.buffers = { { buf, size } },
);
}

View File

@ -293,6 +293,22 @@ Result fsOpenSaveDataFileSystemBySystemSaveDataId(FsFileSystem* out, FsSaveDataS
);
}
Result fsOpenReadOnlySaveDataFileSystem(FsFileSystem* out, FsSaveDataSpaceId save_data_space_id, const FsSaveDataAttribute *attr) {
if (hosversionBefore(2,0,0))
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
const struct {
u8 save_data_space_id;
u8 pad[7];
FsSaveDataAttribute attr;
} in = { (u8)save_data_space_id, {0}, *attr };
return _fsObjectDispatchIn(&g_fsSrv, 53, in,
.out_num_objects = 1,
.out_objects = &out->s,
);
}
Result fsReadSaveDataFileSystemExtraDataBySaveDataSpaceId(void* buf, size_t len, FsSaveDataSpaceId save_data_space_id, u64 saveID) {
if (hosversionBefore(3,0,0))
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
@ -483,10 +499,6 @@ Result fsCreate_SystemSaveData(FsSaveDataSpaceId save_data_space_id, u64 system_
}
// Wrapper(s) for fsOpenSaveDataFileSystem.
static Result _fsOpen_SaveDataFs(FsFileSystem* out, FsSaveDataAttribute *attr) {
return fsOpenSaveDataFileSystem(out, FsSaveDataSpaceId_User, attr);
}
Result fsOpen_SaveData(FsFileSystem* out, u64 application_id, AccountUid uid) {
FsSaveDataAttribute attr;
@ -495,7 +507,28 @@ Result fsOpen_SaveData(FsFileSystem* out, u64 application_id, AccountUid uid) {
attr.uid = uid;
attr.save_data_type = FsSaveDataType_Account;
return _fsOpen_SaveDataFs(out, &attr);
return fsOpenSaveDataFileSystem(out, FsSaveDataSpaceId_User, &attr);
}
Result fsOpen_SaveDataReadOnly(FsFileSystem* out, u64 application_id, AccountUid uid) {
FsSaveDataAttribute attr;
memset(&attr, 0, sizeof(attr));
attr.application_id = application_id;
attr.uid = uid;
attr.save_data_type = FsSaveDataType_Account;
return fsOpenReadOnlySaveDataFileSystem(out, FsSaveDataSpaceId_User, &attr);
}
Result fsOpen_BcatSaveData(FsFileSystem* out, u64 application_id) {
FsSaveDataAttribute attr;
memset(&attr, 0, sizeof(attr));
attr.application_id = application_id;
attr.save_data_type = FsSaveDataType_Bcat;
return fsOpenSaveDataFileSystem(out, FsSaveDataSpaceId_User, &attr);
}
Result fsOpen_DeviceSaveData(FsFileSystem* out, u64 application_id) {
@ -505,7 +538,33 @@ Result fsOpen_DeviceSaveData(FsFileSystem* out, u64 application_id) {
attr.application_id = application_id;
attr.save_data_type = FsSaveDataType_Device;
return _fsOpen_SaveDataFs(out, &attr);
return fsOpenSaveDataFileSystem(out, FsSaveDataSpaceId_User, &attr);
}
Result fsOpen_TemporaryStorage(FsFileSystem* out) {
if (hosversionBefore(3,0,0))
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
FsSaveDataAttribute attr;
memset(&attr, 0, sizeof(attr));
attr.save_data_type = FsSaveDataType_Temporary;
return fsOpenSaveDataFileSystem(out, FsSaveDataType_Temporary, &attr);
}
Result fsOpen_CacheStorage(FsFileSystem* out, u64 application_id, u16 save_data_index) {
if (hosversionBefore(3,0,0))
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
FsSaveDataAttribute attr;
memset(&attr, 0, sizeof(attr));
attr.application_id = application_id;
attr.save_data_type = FsSaveDataType_Cache;
attr.save_data_index = save_data_index;
return fsOpenSaveDataFileSystem(out, FsSaveDataSpaceId_User, &attr);
}
Result fsOpen_SystemSaveData(FsFileSystem* out, FsSaveDataSpaceId save_data_space_id, u64 system_save_data_id, AccountUid uid) {
@ -519,6 +578,19 @@ Result fsOpen_SystemSaveData(FsFileSystem* out, FsSaveDataSpaceId save_data_spac
return fsOpenSaveDataFileSystemBySystemSaveDataId(out, save_data_space_id, &attr);
}
Result fsOpen_SystemBcatSaveData(FsFileSystem* out, u64 system_save_data_id) {
if (hosversionBefore(4,0,0))
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
FsSaveDataAttribute attr;
memset(&attr, 0, sizeof(attr));
attr.system_save_data_id = system_save_data_id;
attr.save_data_type = FsSaveDataType_SystemBcat;
return fsOpenSaveDataFileSystemBySystemSaveDataId(out, FsSaveDataSpaceId_System, &attr);
}
//-----------------------------------------------------------------------------
// IFileSystem
//-----------------------------------------------------------------------------

View File

@ -32,21 +32,40 @@ Service* fsldrGetServiceSession(void) {
return &g_fsldrSrv;
}
Result fsldrOpenCodeFileSystem(u64 tid, const char *path, FsFileSystem* out) {
Result fsldrOpenCodeFileSystem(FsCodeInfo* out_code_info, u64 tid, const char *path, FsFileSystem* out) {
memset(out_code_info, 0, sizeof(*out_code_info));
char send_path[FS_MAX_PATH]={0};
strncpy(send_path, path, FS_MAX_PATH-1);
serviceAssumeDomain(&g_fsldrSrv);
return serviceDispatchIn(&g_fsldrSrv, 0, tid,
.buffer_attrs = {
SfBufferAttr_HipcPointer | SfBufferAttr_In,
},
.buffers = {
{ send_path, FS_MAX_PATH },
},
.out_num_objects = 1,
.out_objects = &out->s,
);
if (hosversionAtLeast(10,0,0)) {
serviceAssumeDomain(&g_fsldrSrv);
return serviceDispatchIn(&g_fsldrSrv, 0, tid,
.buffer_attrs = {
SfBufferAttr_FixedSize | SfBufferAttr_HipcPointer | SfBufferAttr_Out,
SfBufferAttr_FixedSize | SfBufferAttr_HipcPointer | SfBufferAttr_In,
},
.buffers = {
{ out_code_info, sizeof(*out_code_info) },
{ send_path, FS_MAX_PATH },
},
.out_num_objects = 1,
.out_objects = &out->s,
);
} else {
serviceAssumeDomain(&g_fsldrSrv);
return serviceDispatchIn(&g_fsldrSrv, 0, tid,
.buffer_attrs = {
SfBufferAttr_FixedSize | SfBufferAttr_HipcPointer | SfBufferAttr_In,
},
.buffers = {
{ send_path, FS_MAX_PATH },
},
.out_num_objects = 1,
.out_objects = &out->s,
);
}
}
Result fsldrIsArchivedProgram(u64 pid, bool *out) {

View File

@ -69,7 +69,7 @@ Result fsprUnregisterProgram(u64 pid) {
}
Result fsprSetCurrentProcess(void) {
if(hosversionBefore(4,0,0))
if (hosversionBefore(4,0,0))
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
u64 pid_placeholder = 0;
@ -78,6 +78,9 @@ Result fsprSetCurrentProcess(void) {
}
Result fsprSetEnabledProgramVerification(bool enabled) {
if (hosversionAtLeast(10,0,0))
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
const u8 in = enabled != 0;
serviceAssumeDomain(&g_fsprSrv);
return serviceDispatchIn(&g_fsprSrv, 256, in);

File diff suppressed because it is too large Load Diff

View File

@ -92,3 +92,11 @@ Result ldrPmPinProgram(const NcmProgramLocation *loc, u64 *out_pin_id) {
Result ldrPmUnpinProgram(u64 pin_id) {
return serviceDispatchIn(&g_ldrPmSrv, 3, pin_id);
}
Result ldrPmSetEnabledProgramVerification(bool enabled) {
if (hosversionBefore(10,0,0))
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
const u8 in = enabled != 0;
return serviceDispatchIn(&g_ldrPmSrv, 4, in);
}

View File

@ -135,6 +135,13 @@ Result lrLrRefresh(LrLocationResolver* lr) {
return serviceDispatch(&lr->s, 9);
}
Result lrLrEraseProgramRedirection(LrLocationResolver* lr, u64 tid) {
if (hosversionBefore(5,0,0))
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
return serviceDispatchIn(&lr->s, 12, tid);
}
Result lrRegLrResolveProgramPath(LrRegisteredLocationResolver* reg, u64 tid, char *out) {
return _lrResolvePath(&reg->s, tid, out, 0);
}

80
nx/source/services/mii.c Normal file
View File

@ -0,0 +1,80 @@
#define NX_SERVICE_ASSUME_NON_DOMAIN
#include "service_guard.h"
#include "services/mii.h"
static MiiServiceType g_miiServiceType;
static Service g_miiSrv;
NX_GENERATE_SERVICE_GUARD_PARAMS(mii, (MiiServiceType service_type), (service_type));
Result _miiInitialize(MiiServiceType service_type) {
Result rc = MAKERESULT(Module_Libnx, LibnxError_BadInput);
g_miiServiceType = service_type;
switch (g_miiServiceType) {
case MiiServiceType_System:
rc = smGetService(&g_miiSrv, "mii:e");
break;
case MiiServiceType_User:
rc = smGetService(&g_miiSrv, "mii:u");
break;
}
return rc;
}
void _miiCleanup(void) {
serviceClose(&g_miiSrv);
}
Service* miiGetServiceSession(void) {
return &g_miiSrv;
}
Result miiOpenDatabase(MiiDatabase *out, MiiSpecialKeyCode key_code) {
u32 in = (u32)key_code;
return serviceDispatchIn(&g_miiSrv, 0, in,
.out_num_objects = 1,
.out_objects = &out->s,
);
}
Result miiDatabaseIsUpdated(MiiDatabase *db, bool *out_updated, MiiSourceFlag flag) {
u32 in = (u32)flag;
u8 tmp = 0;
Result rc = serviceDispatchInOut(&db->s, 0, in, tmp);
if (R_SUCCEEDED(rc) && out_updated) *out_updated = tmp & 1;
return rc;
}
Result miiDatabaseIsFull(MiiDatabase *db, bool *out_full) {
u8 tmp = 0;
Result rc = serviceDispatchOut(&db->s, 1, tmp);
if (R_SUCCEEDED(rc) && out_full) *out_full = tmp & 1;
return rc;
}
Result miiDatabaseGetCount(MiiDatabase *db, s32 *out_count, MiiSourceFlag flag) {
u32 in = (u32)flag;
return serviceDispatchInOut(&db->s, 2, in, *out_count);
}
Result miiDatabaseGet1(MiiDatabase *db, MiiSourceFlag flag, MiiCharInfo *out_infos, s32 count, s32 *total_out) {
u32 in = (u32)flag;
return serviceDispatchInOut(&db->s, 4, in, *total_out,
.buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out },
.buffers = { { out_infos, count * sizeof(MiiCharInfo) } },
);
}
Result miiDatabaseBuildRandom(MiiDatabase *db, MiiAge age, MiiGender gender, MiiFaceColor face_color, MiiCharInfo *out_info) {
const struct {
u32 age;
u32 gender;
u32 face_color;
} in = { age, gender, face_color };
return serviceDispatchInOut(&db->s, 6, in, *out_info);
}
void miiDatabaseClose(MiiDatabase *db) {
serviceClose(&db->s);
}

View File

@ -0,0 +1,64 @@
#define NX_SERVICE_ASSUME_NON_DOMAIN
#include "service_guard.h"
#include "services/miiimg.h"
#include "runtime/hosversion.h"
static Service g_miiimgSrv;
NX_GENERATE_SERVICE_GUARD(miiimg);
static Result _miiimgInitializeCmd(u8 in, u8 *out) {
return serviceDispatchInOut(&g_miiimgSrv, 0, in, *out);
}
Result _miiimgInitialize(void) {
if (hosversionBefore(5,0,0))
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
Result rc = smGetService(&g_miiimgSrv, "miiimg");
if (R_SUCCEEDED(rc)) {
u8 tmp;
rc = _miiimgInitializeCmd(1, &tmp);
}
return rc;
}
void _miiimgCleanup(void) {
serviceClose(&g_miiimgSrv);
}
Service* miiimgGetServiceSession(void) {
return &g_miiimgSrv;
}
Result miiimgReload(void) {
return serviceDispatch(&g_miiimgSrv, 10);
}
Result miiimgGetCount(s32 *out_count) {
return serviceDispatchOut(&g_miiimgSrv, 11, *out_count);
}
Result miiimgIsEmpty(bool *out_empty) {
u8 tmp = 0;
Result rc = serviceDispatchOut(&g_miiimgSrv, 12, tmp);
if (R_SUCCEEDED(rc) && out_empty) *out_empty = tmp & 1;
return rc;
}
Result miiimgIsFull(bool *out_full) {
u8 tmp = 0;
Result rc = serviceDispatchOut(&g_miiimgSrv, 13, tmp);
if (R_SUCCEEDED(rc) && out_full) *out_full = tmp & 1;
return rc;
}
Result miiimgGetAttribute(s32 index, MiiimgImageAttribute *out_attr) {
return serviceDispatchInOut(&g_miiimgSrv, 14, index, *out_attr);
}
Result miiimgLoadImage(MiiimgImageId id, void* out_image, size_t out_image_size) {
return serviceDispatchIn(&g_miiimgSrv, 15, id,
.buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out },
.buffers = { { out_image, out_image_size } },
);
}

View File

@ -236,7 +236,7 @@ Result nfpUnmount(const NfcDeviceHandle *handle) {
return _nfcCmdInDevhandleNoOut(&g_nfpInterface, handle, 6);
}
Result nfpOpenApplicationArea(const NfcDeviceHandle *handle, u32 app_id, u32 *npad_id) {
Result nfpOpenApplicationArea(const NfcDeviceHandle *handle, u32 app_id) {
if (g_nfpServiceType == NfpServiceType_System)
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
@ -246,7 +246,7 @@ Result nfpOpenApplicationArea(const NfcDeviceHandle *handle, u32 app_id, u32 *np
} in = { *handle, app_id };
serviceAssumeDomain(&g_nfpInterface);
return serviceDispatchInOut(&g_nfpInterface, 7, in, *npad_id);
return serviceDispatchIn(&g_nfpInterface, 7, in);
}
Result nfpGetApplicationArea(const NfcDeviceHandle *handle, void* buf, size_t buf_size) {

View File

@ -1,3 +1,4 @@
#include <string.h>
#include "service_guard.h"
#include "services/nifm.h"
#include "runtime/hosversion.h"
@ -65,10 +66,10 @@ static Result _nifmCmdGetSession(Service* srv, Service* srv_out, u32 cmd_id) {
);
}
static Result _nifmCmdNoInOutU32(Service* srv, u32 *out, u32 cmd_id) {
/*static Result _nifmCmdNoInOutU32(Service* srv, u32 *out, u32 cmd_id) {
serviceAssumeDomain(srv);
return serviceDispatchOut(srv, cmd_id, *out);
}
}*/
static Result _nifmCmdNoInOutU8(Service* srv, u8 *out, u32 cmd_id) {
serviceAssumeDomain(srv);
@ -105,8 +106,54 @@ static Result _nifmCreateGeneralService(Service* srv_out) {
);
}
static void _nifmConvertSfToNetworkProfileData(const NifmSfNetworkProfileData *in, NifmNetworkProfileData *out) {
memset(out, 0, sizeof(*out));
out->uuid = in->uuid;
strncpy(out->network_name, in->network_name, sizeof(in->network_name));
out->network_name[sizeof(out->network_name)-1] = 0;
out->unk_x50 = in->unk_x112;
out->unk_x54 = in->unk_x113;
out->unk_x58 = in->unk_x114;
out->unk_x59 = in->unk_x115;
out->wireless_setting_data.ssid_len = in->wireless_setting_data.ssid_len;
if (out->wireless_setting_data.ssid_len > sizeof(out->wireless_setting_data.ssid)-1) out->wireless_setting_data.ssid_len = sizeof(out->wireless_setting_data.ssid)-1;
if (out->wireless_setting_data.ssid_len) memcpy(out->wireless_setting_data.ssid, in->wireless_setting_data.ssid, out->wireless_setting_data.ssid_len);
out->wireless_setting_data.unk_x22 = in->wireless_setting_data.unk_x21;
out->wireless_setting_data.unk_x24 = in->wireless_setting_data.unk_x22;
out->wireless_setting_data.unk_x28 = in->wireless_setting_data.unk_x23;
memcpy(out->wireless_setting_data.passphrase, in->wireless_setting_data.passphrase, sizeof(out->wireless_setting_data.passphrase));
memcpy(&out->ip_setting_data, &in->ip_setting_data, sizeof(out->ip_setting_data));
}
static void _nifmConvertSfFromNetworkProfileData(const NifmNetworkProfileData *in, NifmSfNetworkProfileData *out) {
memset(out, 0, sizeof(*out));
out->uuid = in->uuid;
strncpy(out->network_name, in->network_name, sizeof(out->network_name));
out->network_name[sizeof(out->network_name)-1] = 0;
out->unk_x112 = in->unk_x50;
out->unk_x113 = in->unk_x54;
out->unk_x114 = in->unk_x58;
out->unk_x115 = in->unk_x59;
out->wireless_setting_data.ssid_len = in->wireless_setting_data.ssid_len;
memcpy(out->wireless_setting_data.ssid, in->wireless_setting_data.ssid, sizeof(out->wireless_setting_data.ssid)-1);
out->wireless_setting_data.unk_x21 = in->wireless_setting_data.unk_x22;
out->wireless_setting_data.unk_x22 = in->wireless_setting_data.unk_x24;
out->wireless_setting_data.unk_x23 = in->wireless_setting_data.unk_x28;
memcpy(out->wireless_setting_data.passphrase, in->wireless_setting_data.passphrase, sizeof(out->wireless_setting_data.passphrase));
memcpy(&out->ip_setting_data, &in->ip_setting_data, sizeof(out->ip_setting_data));
}
NifmClientId nifmGetClientId(void) {
NifmClientId id={0};
serviceAssumeDomain(&g_nifmIGS);
Result rc = serviceDispatch(&g_nifmIGS, 1,
.buffer_attrs = { SfBufferAttr_FixedSize | SfBufferAttr_HipcPointer | SfBufferAttr_Out },
.buffers = { { &id, sizeof(id) } },
@ -115,8 +162,63 @@ NifmClientId nifmGetClientId(void) {
return id;
}
Result nifmGetCurrentNetworkProfile(NifmNetworkProfileData *profile) {
NifmSfNetworkProfileData tmp={0};
serviceAssumeDomain(&g_nifmIGS);
Result rc = serviceDispatch(&g_nifmIGS, 5,
.buffer_attrs = { SfBufferAttr_FixedSize | SfBufferAttr_HipcPointer | SfBufferAttr_Out },
.buffers = { { &tmp, sizeof(tmp) } },
);
if (R_SUCCEEDED(rc)) _nifmConvertSfToNetworkProfileData(&tmp, profile);
return rc;
}
Result nifmGetNetworkProfile(Uuid uuid, NifmNetworkProfileData *profile) {
NifmSfNetworkProfileData tmp={0};
serviceAssumeDomain(&g_nifmIGS);
Result rc = serviceDispatchIn(&g_nifmIGS, 8, uuid,
.buffer_attrs = { SfBufferAttr_FixedSize | SfBufferAttr_HipcPointer | SfBufferAttr_Out },
.buffers = { { &tmp, sizeof(tmp) } },
);
if (R_SUCCEEDED(rc)) _nifmConvertSfToNetworkProfileData(&tmp, profile);
return rc;
}
Result nifmSetNetworkProfile(const NifmNetworkProfileData *profile, Uuid *uuid) {
NifmSfNetworkProfileData tmp={0};
_nifmConvertSfFromNetworkProfileData(profile, &tmp);
serviceAssumeDomain(&g_nifmIGS);
Result rc = serviceDispatchOut(&g_nifmIGS, 9, *uuid,
.buffer_attrs = { SfBufferAttr_FixedSize | SfBufferAttr_HipcPointer | SfBufferAttr_In },
.buffers = { { &tmp, sizeof(tmp) } },
);
return rc;
}
Result nifmGetCurrentIpAddress(u32* out) {
return _nifmCmdNoInOutU32(&g_nifmIGS, out, 12);
NifmIpV4Address tmp={0};
serviceAssumeDomain(&g_nifmIGS);
Result rc = serviceDispatchOut(&g_nifmIGS, 12, tmp);
if (R_SUCCEEDED(rc) && out) *out = *((u32*)tmp.addr);
return rc;
}
Result nifmGetCurrentIpConfigInfo(u32 *current_addr, u32 *subnet_mask, u32 *gateway, u32 *primary_dns_server, u32 *secondary_dns_server) {
struct {
NifmIpAddressSetting ip_setting;
NifmDnsSetting dns_setting;
} out;
serviceAssumeDomain(&g_nifmIGS);
Result rc = serviceDispatchOut(&g_nifmIGS, 15, out);
if (R_SUCCEEDED(rc)) {
if (current_addr) *current_addr = *((u32*)out.ip_setting.current_addr.addr);
if (subnet_mask) *subnet_mask = *((u32*)out.ip_setting.subnet_mask.addr);
if (gateway) *gateway = *((u32*)out.ip_setting.gateway.addr);
if (primary_dns_server) *primary_dns_server = *((u32*)out.dns_setting.primary_dns_server.addr);
if (secondary_dns_server) *secondary_dns_server = *((u32*)out.dns_setting.secondary_dns_server.addr);
}
return rc;
}
Result nifmSetWirelessCommunicationEnabled(bool enable) {
@ -153,6 +255,7 @@ Result nifmIsEthernetCommunicationEnabled(bool* out) {
bool nifmIsAnyInternetRequestAccepted(NifmClientId id) {
u8 tmp=0;
serviceAssumeDomain(&g_nifmIGS);
Result rc = serviceDispatchOut(&g_nifmIGS, 21, tmp,
.buffer_attrs = { SfBufferAttr_FixedSize | SfBufferAttr_HipcPointer | SfBufferAttr_In },
.buffers = { { &id, sizeof(id) } },

36
nx/source/services/nim.c Normal file
View File

@ -0,0 +1,36 @@
#include <string.h>
#include "service_guard.h"
#include "services/nim.h"
#include "runtime/hosversion.h"
static Service g_nimSrv;
NX_GENERATE_SERVICE_GUARD(nim);
Result _nimInitialize(void) {
return smGetService(&g_nimSrv, "nim");
}
void _nimCleanup(void) {
serviceClose(&g_nimSrv);
}
Service* nimGetServiceSession(void) {
return &g_nimSrv;
}
Result nimDestroySystemUpdateTask(const NimSystemUpdateTaskId *task_id) {
return serviceDispatchIn(&g_nimSrv, 1, *task_id);
}
Result nimListSystemUpdateTask(s32 *out_count, NimSystemUpdateTaskId *out_task_ids, size_t max_task_ids) {
return serviceDispatchOut(&g_nimSrv, 2, *out_count,
.buffer_attrs = {
SfBufferAttr_HipcMapAlias | SfBufferAttr_Out,
},
.buffers = {
{ out_task_ids, max_task_ids * sizeof(*out_task_ids) },
},
);
}

View File

@ -729,6 +729,9 @@ Result nsIsApplicationEntityMovable(u64 application_id, NcmStorageId storage_id,
}
Result nsMoveApplicationEntity(u64 application_id, NcmStorageId storage_id) {
if (hosversionAtLeast(10,0,0))
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
return _nsManCmdInU8U64NoOut(storage_id, application_id, 9);
}
@ -1226,7 +1229,7 @@ static Result _nsRequestVerifyApplication(NsProgressAsyncResult *a, u64 applicat
}
Result nsRequestVerifyAddOnContentsRights(NsProgressAsyncResult *a, u64 application_id) {
if (hosversionBefore(3,0,0))
if (!hosversionBetween(3,10))
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
Service srv={0};
@ -2262,6 +2265,9 @@ Service* nsdevGetServiceSession(void) {
}
Result nsdevLaunchProgram(u64* out_pid, const NsLaunchProperties* properties, u32 flags) {
if (hosversionAtLeast(10,0,0))
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
const struct {
u32 flags;
u32 pad;
@ -2276,14 +2282,23 @@ Result nsdevTerminateProcess(u64 pid) {
}
Result nsdevTerminateProgram(u64 tid) {
if (hosversionAtLeast(10,0,0))
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
return _nsCmdInU64(&g_nsdevSrv, tid, 2);
}
Result nsdevGetShellEvent(Event* out_event) {
if (hosversionAtLeast(10,0,0))
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
return _nsCmdGetEvent(&g_nsdevSrv, out_event, true, 4);
}
Result nsdevGetShellEventInfo(NsShellEventInfo* out) {
if (hosversionAtLeast(10,0,0))
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
struct {
u32 event;
u64 process_id;
@ -2302,6 +2317,9 @@ Result nsdevTerminateApplication(void) {
}
Result nsdevPrepareLaunchProgramFromHost(NsLaunchProperties* out, const char* path, size_t path_len) {
if (hosversionAtLeast(10,0,0))
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
return serviceDispatchOut(&g_nsdevSrv, 7, *out,
.buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_In },
.buffers = { { path, path_len } },
@ -2309,6 +2327,9 @@ Result nsdevPrepareLaunchProgramFromHost(NsLaunchProperties* out, const char* pa
}
Result nsdevLaunchApplicationForDevelop(u64* out_pid, u64 application_id, u32 flags) {
if (hosversionAtLeast(10,0,0))
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
const struct {
u32 flags;
u64 application_id;
@ -2317,6 +2338,16 @@ Result nsdevLaunchApplicationForDevelop(u64* out_pid, u64 application_id, u32 fl
return serviceDispatchInOut(&g_nsdevSrv, 8, in, *out_pid);
}
Result nsdevLaunchApplicationFromHost(u64* out_pid, const char* path, size_t path_len, u32 flags) {
if (hosversionBefore(10,0,0))
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
return serviceDispatchInOut(&g_nsdevSrv, 8, flags, *out_pid,
.buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_In },
.buffers = { { path, path_len } },
);
}
Result nsdevLaunchApplicationWithStorageIdForDevelop(u64* out_pid, u64 application_id, u32 flags, u8 app_storage_id, u8 patch_storage_id) {
const struct {
u8 app_storage_id;

134
nx/source/services/pgl.c Normal file
View File

@ -0,0 +1,134 @@
#define NX_SERVICE_ASSUME_NON_DOMAIN
#include <string.h>
#include "service_guard.h"
#include "services/pgl.h"
#include "runtime/hosversion.h"
static Service g_pglSrv;
NX_GENERATE_SERVICE_GUARD(pgl);
Result _pglInitialize(void) {
if (hosversionBefore(10,0,0))
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
return smGetService(&g_pglSrv, "pgl");
}
void _pglCleanup(void) {
serviceClose(&g_pglSrv);
}
Service* pglGetServiceSession(void) {
return &g_pglSrv;
}
static Result _pglCmdInBool(Service* srv, bool inval, u32 cmd_id) {
const u8 in = inval;
return serviceDispatchIn(srv, cmd_id, in);
}
static Result _pglCmdOutBool(Service* srv, bool *out, u32 cmd_id) {
u8 outval = 0;
Result rc = serviceDispatchOut(srv, cmd_id, outval);
if (R_SUCCEEDED(rc)) {
if (out) *out = outval & 1;
}
return rc;
}
static Result _pglCmdInU64(Service* srv, u64 inval, u32 cmd_id) {
return serviceDispatchIn(srv, cmd_id, inval);
}
Result pglLaunchProgram(u64 *out_pid, const NcmProgramLocation *loc, u32 pm_launch_flags, u8 pgl_launch_flags) {
const struct {
u8 pgl_flags;
u32 pm_flags;
NcmProgramLocation loc;
} in = { pgl_launch_flags, pm_launch_flags, *loc };
return serviceDispatchInOut(&g_pglSrv, 0, in, *out_pid);
}
Result pglTerminateProcess(u64 pid) {
return _pglCmdInU64(&g_pglSrv, pid, 1);
}
Result pglLaunchProgramFromHost(u64 *out_pid, const char *content_path, u32 pm_launch_flags) {
return serviceDispatchInOut(&g_pglSrv, 2, pm_launch_flags, *out_pid,
.buffer_attrs = { SfBufferAttr_In | SfBufferAttr_HipcMapAlias },
.buffers = { { content_path, strlen(content_path) + 1 } },
);
}
Result pglGetHostContentMetaInfo(PglContentMetaInfo *out, const char *content_path) {
return serviceDispatchOut(&g_pglSrv, 4, *out,
.buffer_attrs = { SfBufferAttr_In | SfBufferAttr_HipcMapAlias },
.buffers = { { content_path, strlen(content_path) + 1 } },
);
}
Result pglGetApplicationProcessId(u64 *out) {
return serviceDispatchOut(&g_pglSrv, 5, *out);
}
Result pglBoostSystemMemoryResourceLimit(u64 size) {
return _pglCmdInU64(&g_pglSrv, size, 6);
}
Result pglIsProcessTracked(bool *out, u64 pid) {
u8 outval = 0;
Result rc = serviceDispatchInOut(&g_pglSrv, 7, pid, outval);
if (R_SUCCEEDED(rc)) {
if (out) *out = outval & 1;
}
return rc;
}
Result pglEnableApplicationCrashReport(bool en) {
return _pglCmdInBool(&g_pglSrv, en, 8);
}
Result pglIsApplicationCrashReportEnabled(bool *out) {
return _pglCmdOutBool(&g_pglSrv, out, 9);
}
Result pglEnableApplicationAllThreadDumpOnCrash(bool en) {
return _pglCmdInBool(&g_pglSrv, en, 10);
}
Result pglTriggerApplicationSnapShotDumper(PglSnapShotDumpType dump_type, const char *arg) {
_Static_assert(sizeof(dump_type) == sizeof(u32), "PglSnapShotDumpType");
return serviceDispatchIn(&g_pglSrv, 12, dump_type,
.buffer_attrs = { SfBufferAttr_In | SfBufferAttr_HipcMapAlias },
.buffers = { { arg, strlen(arg) + 1 } },
);
}
Result pglGetEventObserver(PglEventObserver *out) {
return serviceDispatch(&g_pglSrv, 20,
.out_num_objects = 1,
.out_objects = &out->s,
);
}
Result pglEventObserverGetProcessEvent(PglEventObserver *observer, Event *out) {
Handle evt_handle;
Result rc = serviceDispatch(&observer->s, 0,
.out_handle_attrs = { SfOutHandleAttr_HipcCopy },
.out_handles = &evt_handle,
);
if (R_SUCCEEDED(rc)) {
eventLoadRemote(out, evt_handle, true);
}
return rc;
}
Result pglEventObserverGetProcessEventInfo(PglEventObserver *observer, PmProcessEventInfo *out) {
return serviceDispatchOut(&observer->s, 1, *out);
}
void pglEventObserverClose(PglEventObserver *observer) {
serviceClose(&observer->s);
}

View File

@ -6,18 +6,27 @@
#define SHAREDMEMFONT_SIZE 0x1100000
static PlServiceType g_plServiceType;
static Service g_plSrv;
static SharedMemory g_plSharedmem;
static Result _plGetSharedMemoryNativeHandle(Handle* handle_out);
NX_GENERATE_SERVICE_GUARD(pl);
NX_GENERATE_SERVICE_GUARD_PARAMS(pl, (PlServiceType service_type), (service_type));
Result _plInitialize(void) {
Result rc=0;
Result _plInitialize(PlServiceType service_type) {
Result rc = MAKERESULT(Module_Libnx, LibnxError_BadInput);
Handle sharedmem_handle=0;
rc = smGetService(&g_plSrv, "pl:u");
g_plServiceType = service_type;
switch (g_plServiceType) {
case PlServiceType_User:
rc = smGetService(&g_plSrv, "pl:u");
break;
case PlServiceType_System:
rc = smGetService(&g_plSrv, "pl:s");
break;
}
if (R_SUCCEEDED(rc)) {
rc = _plGetSharedMemoryNativeHandle(&sharedmem_handle);

View File

@ -162,7 +162,7 @@ Result pmshellBoostSystemMemoryResourceLimit(u64 boost_size) {
return serviceDispatchIn(&g_pmshellSrv, cmd_id, boost_size);
}
Result pmshellBoostSystemThreadResourceLimit(void) {
Result pmshellEnableApplicationExtraThread(void) {
if (hosversionBefore(7,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
return serviceDispatch(&g_pmshellSrv, 8);
}

View File

@ -569,15 +569,8 @@ Result setsysGetBatteryLot(SetBatteryLot *out) {
return serviceDispatchOut(&g_setsysSrv, 67, *out);
}
Result setsysGetSerialNumber(char *serial) {
char out[0x18]={0};
Result rc = serviceDispatchOut(&g_setsysSrv, 68, out);
if (R_SUCCEEDED(rc) && serial) {
memcpy(serial, out, 0x18);
serial[0x18]=0;
}
return rc;
Result setsysGetSerialNumber(SetSysSerialNumber *out) {
return serviceDispatchOut(&g_setsysSrv, 68, *out);
}
Result setsysGetNfcEnableFlag(bool *out) {

View File

@ -1,5 +1,9 @@
#define NX_SERVICE_ASSUME_NON_DOMAIN
#include <string.h>
#include <stdatomic.h>
#include "service_guard.h"
#include "arm/counter.h"
#include "kernel/shmem.h"
#include "services/time.h"
#include "runtime/hosversion.h"
@ -8,10 +12,15 @@ __attribute__((weak)) TimeServiceType __nx_time_service_type = TimeServiceType_U
static Service g_timeSrv;
static Service g_timeUserSystemClock;
static Service g_timeNetworkSystemClock;
static Service g_timeSteadyClock;
static Service g_timeTimeZoneService;
static Service g_timeLocalSystemClock;
static SharedMemory g_timeSharedmem;
static Result _timeCmdGetSession(Service* srv, Service* srv_out, u32 cmd_id);
static Result _timeGetSharedMemoryNativeHandle(Service* srv, Handle* out);
static void _timeReadSharedmemObj(void* out, size_t offset, size_t size);
NX_GENERATE_SERVICE_GUARD(time);
@ -41,26 +50,38 @@ Result _timeInitialize(void) {
break;
}
if (R_FAILED(rc))
return rc;
rc = _timeCmdGetSession(&g_timeSrv, &g_timeUserSystemClock, 0);
if (R_SUCCEEDED(rc))
rc = _timeCmdGetSession(&g_timeSrv, &g_timeUserSystemClock, 0);
if (R_SUCCEEDED(rc))
rc = _timeCmdGetSession(&g_timeSrv, &g_timeNetworkSystemClock, 1);
if (R_SUCCEEDED(rc))
rc = _timeCmdGetSession(&g_timeSrv, &g_timeSteadyClock, 2);
if (R_SUCCEEDED(rc))
rc = _timeCmdGetSession(&g_timeSrv, &g_timeTimeZoneService, 3);
if (R_SUCCEEDED(rc))
rc = _timeCmdGetSession(&g_timeSrv, &g_timeLocalSystemClock, 4);
if (R_SUCCEEDED(rc) && hosversionAtLeast(6,0,0)) {
Handle shmem;
rc = _timeGetSharedMemoryNativeHandle(&g_timeSrv, &shmem);
if (R_SUCCEEDED(rc)) {
shmemLoadRemote(&g_timeSharedmem, shmem, 0x1000, Perm_R);
rc = shmemMap(&g_timeSharedmem);
}
}
return rc;
}
void _timeCleanup(void) {
shmemClose(&g_timeSharedmem);
serviceClose(&g_timeLocalSystemClock);
serviceClose(&g_timeTimeZoneService);
serviceClose(&g_timeSteadyClock);
serviceClose(&g_timeNetworkSystemClock);
serviceClose(&g_timeUserSystemClock);
serviceClose(&g_timeSrv);
@ -85,10 +106,32 @@ Service* timeGetServiceSession_SystemClock(TimeType type) {
}
}
Service* timeGetServiceSession_SteadyClock(void) {
return &g_timeSteadyClock;
}
Service* timeGetServiceSession_TimeZoneService(void) {
return &g_timeTimeZoneService;
}
void* timeGetSharedmemAddr(void) {
return shmemGetAddr(&g_timeSharedmem);
}
void _timeReadSharedmemObj(void* out, size_t offset, size_t size) {
void* addr = (u8*)shmemGetAddr(&g_timeSharedmem) + offset;
vu32* counter = (vu32*)addr;
void* data = (u8*)addr + 8;
u32 cur_counter;
do {
cur_counter = *counter;
memcpy(out, (u8*)data + (cur_counter&1)*size, size);
atomic_thread_fence(memory_order_consume);
} while (cur_counter != *counter);
}
static Result _timeCmdGetSession(Service* srv, Service* srv_out, u32 cmd_id) {
return serviceDispatch(srv, cmd_id,
.out_num_objects = 1,
@ -96,6 +139,13 @@ static Result _timeCmdGetSession(Service* srv, Service* srv_out, u32 cmd_id) {
);
}
static Result _timeGetSharedMemoryNativeHandle(Service* srv, Handle* out) {
return serviceDispatch(srv, 20,
.out_handle_attrs = { SfOutHandleAttr_HipcCopy },
.out_handles = out,
);
}
static Result _timeCmdInU64NoOut(Service* srv, u64 inval, u32 cmd_id) {
return serviceDispatchIn(srv, cmd_id, inval);
}
@ -108,13 +158,57 @@ static Result _appletCmdNoInOutU32(Service* srv, u32 *out, u32 cmd_id) {
return serviceDispatchOut(srv, cmd_id, *out);
}
static s64 _timeComputeSteadyClockTimePoint(const TimeStandardSteadyClockTimePointType *context) {
return (context->base_time + armTicksToNs(armGetSystemTick())) / 1000000000L;
}
Result timeGetStandardSteadyClockTimePoint(TimeSteadyClockTimePoint *out) {
if (!shmemGetAddr(&g_timeSharedmem)) {
return serviceDispatchOut(&g_timeSteadyClock, 0, *out);
}
TimeStandardSteadyClockTimePointType context;
_timeReadSharedmemObj(&context, 0x00, sizeof(context));
out->time_point = _timeComputeSteadyClockTimePoint(&context);
out->source_id = context.source_id;
return 0;
}
Result timeGetStandardSteadyClockInternalOffset(s64 *out) {
if (hosversionBefore(3,0,0))
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
return serviceDispatchOut(&g_timeSteadyClock, 200, *out);
}
static Result _timeReadClockFromSharedMem(size_t offset, u64 *out) {
TimeStandardSteadyClockTimePointType steady;
_timeReadSharedmemObj(&steady, 0x00, sizeof(steady));
TimeSystemClockContext context;
_timeReadSharedmemObj(&context, offset, sizeof(context));
if (memcmp(&context.timestamp.source_id, &steady.source_id, sizeof(Uuid)) != 0)
return MAKERESULT(116,102);
*out = context.offset + _timeComputeSteadyClockTimePoint(&steady);
return 0;
}
Result timeGetCurrentTime(TimeType type, u64 *timestamp) {
Service *srv = timeGetServiceSession_SystemClock(type);
if (!shmemGetAddr(&g_timeSharedmem)) {
Service *srv = timeGetServiceSession_SystemClock(type);
if (srv==NULL)
return MAKERESULT(Module_Libnx, LibnxError_BadInput);
if (srv==NULL)
return MAKERESULT(Module_Libnx, LibnxError_BadInput);
return _timeCmdNoInOutU64(srv, timestamp, 0);
return _timeCmdNoInOutU64(srv, timestamp, 0);
}
if (type != TimeType_NetworkSystemClock)
return _timeReadClockFromSharedMem(0x38, timestamp);
else
return _timeReadClockFromSharedMem(0x80, timestamp);
}
Result timeSetCurrentTime(TimeType type, u64 timestamp) {